Coverage Report

Created: 2026-03-12 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/text/qtextobject.cpp
Line
Count
Source
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
#include "qtextobject.h"
5
#include "qtextobject_p.h"
6
#include "qtextcursor_p.h"
7
#include "qtextdocument.h"
8
#include "qtextformat_p.h"
9
#include "qtextdocument_p.h"
10
#include "qtextcursor.h"
11
#include "qtextlist.h"
12
#include "qabstracttextdocumentlayout.h"
13
#include "qtextengine_p.h"
14
#include "qdebug.h"
15
16
#include <algorithm>
17
18
QT_BEGIN_NAMESPACE
19
20
// ### DOC: We ought to explain the CONCEPT of objectIndexes if
21
// relevant to the public API
22
/*!
23
    \class QTextObject
24
    \reentrant
25
26
    \brief The QTextObject class is a base class for different kinds
27
    of objects that can group parts of a QTextDocument together.
28
    \inmodule QtGui
29
30
    \ingroup richtext-processing
31
32
    The common grouping text objects are lists (QTextList), frames
33
    (QTextFrame), and tables (QTextTable). A text object has an
34
    associated format() and document().
35
36
    There are essentially two kinds of text objects: those that are used
37
    with blocks (block formats), and those that are used with characters
38
    (character formats). The first kind are derived from QTextBlockGroup,
39
    and the second kind from QTextFrame.
40
41
    You rarely need to use this class directly. When creating custom text
42
    objects, you will also need to reimplement QTextDocument::createObject()
43
    which acts as a factory method for creating text objects.
44
45
    \sa QTextDocument
46
*/
47
48
/*!
49
    \fn QTextObject::QTextObject(QTextDocument *document)
50
51
    Creates a new QTextObject for the given \a document.
52
53
    \warning This function should never be called directly, but only
54
    from QTextDocument::createObject().
55
*/
56
QTextObject::QTextObject(QTextDocument *doc)
57
0
    : QObject(*new QTextObjectPrivate(doc), doc)
58
0
{
59
0
}
60
61
/*!
62
  \fn QTextObject::QTextObject(QTextObjectPrivate &p, QTextDocument *document)
63
64
  \internal
65
*/
66
QTextObject::QTextObject(QTextObjectPrivate &p, QTextDocument *doc)
67
17.4k
    : QObject(p, doc)
68
17.4k
{
69
17.4k
}
70
71
/*!
72
    Destroys the text object.
73
74
    \warning Text objects are owned by the document, so you should
75
    never destroy them yourself.
76
*/
77
QTextObject::~QTextObject()
78
17.4k
{
79
17.4k
}
80
81
/*!
82
    Returns the text object's format.
83
84
    \sa setFormat(), document()
85
*/
86
QTextFormat QTextObject::format() const
87
104k
{
88
104k
    Q_D(const QTextObject);
89
104k
    return d->pieceTable->formatCollection()->objectFormat(d->objectIndex);
90
104k
}
91
92
/*!
93
    Returns the index of the object's format in the document's internal
94
    list of formats.
95
96
    \sa QTextDocument::allFormats()
97
*/
98
int QTextObject::formatIndex() const
99
0
{
100
0
    Q_D(const QTextObject);
101
0
    return d->pieceTable->formatCollection()->objectFormatIndex(d->objectIndex);
102
0
}
103
104
105
/*!
106
    Sets the text object's \a format.
107
108
    \sa format()
109
*/
110
void QTextObject::setFormat(const QTextFormat &format)
111
17.4k
{
112
17.4k
    Q_D(QTextObject);
113
17.4k
    int idx = d->pieceTable->formatCollection()->indexForFormat(format);
114
17.4k
    d->pieceTable->changeObjectFormat(this, idx);
115
17.4k
}
116
117
/*!
118
    Returns the object index of this object. This can be used together with
119
    QTextFormat::setObjectIndex().
120
*/
121
int QTextObject::objectIndex() const
122
17.4k
{
123
17.4k
    Q_D(const QTextObject);
124
17.4k
    return d->objectIndex;
125
17.4k
}
126
127
/*!
128
    Returns the document this object belongs to.
129
130
    \sa format()
131
*/
132
QTextDocument *QTextObject::document() const
133
4.72M
{
134
4.72M
    return static_cast<QTextDocument *>(parent());
135
4.72M
}
136
137
/*!
138
    \class QTextBlockGroup
139
    \reentrant
140
141
    \brief The QTextBlockGroup class provides a container for text blocks within
142
    a QTextDocument.
143
    \inmodule QtGui
144
145
    \ingroup richtext-processing
146
147
    Block groups can be used to organize blocks of text within a document.
148
    They maintain an up-to-date list of the text blocks that belong to
149
    them, even when text blocks are being edited.
150
151
    Each group has a parent document which is specified when the group is
152
    constructed.
153
154
    Text blocks can be inserted into a group with blockInserted(), and removed
155
    with blockRemoved(). If a block's format is changed, blockFormatChanged()
156
    is called.
157
158
    The list of blocks in the group is returned by blockList(). Note that the
159
    blocks in the list are not necessarily adjacent elements in the document;
160
    for example, the top-level items in a multi-level list will be separated
161
    by the items in lower levels of the list.
162
163
    \sa QTextBlock, QTextDocument
164
*/
165
166
void QTextBlockGroupPrivate::markBlocksDirty()
167
0
{
168
0
    for (int i = 0; i < blocks.size(); ++i) {
169
0
        const QTextBlock &block = blocks.at(i);
170
0
        pieceTable->documentChange(block.position(), block.length());
171
0
    }
172
0
}
173
174
/*!
175
    \fn QTextBlockGroup::QTextBlockGroup(QTextDocument *document)
176
177
    Creates a new block group for the given \a document.
178
179
    \warning This function should only be called from
180
    QTextDocument::createObject().
181
*/
182
QTextBlockGroup::QTextBlockGroup(QTextDocument *doc)
183
0
    : QTextObject(*new QTextBlockGroupPrivate(doc), doc)
184
0
{
185
0
}
186
187
/*!
188
  \internal
189
*/
190
QTextBlockGroup::QTextBlockGroup(QTextBlockGroupPrivate &p, QTextDocument *doc)
191
0
    : QTextObject(p, doc)
192
0
{
193
0
}
194
195
/*!
196
    Destroys this block group; the blocks are not deleted, they simply
197
    don't belong to this block anymore.
198
*/
199
QTextBlockGroup::~QTextBlockGroup()
200
{
201
}
202
203
// ### DOC: Shouldn't this be insertBlock()?
204
/*!
205
    Appends the given \a block to the end of the group.
206
207
    \warning If you reimplement this function you must call the base
208
    class implementation.
209
*/
210
void QTextBlockGroup::blockInserted(const QTextBlock &block)
211
0
{
212
0
    Q_D(QTextBlockGroup);
213
0
    QTextBlockGroupPrivate::BlockList::Iterator it = std::lower_bound(d->blocks.begin(), d->blocks.end(), block);
214
0
    d->blocks.insert(it, block);
215
0
    d->markBlocksDirty();
216
0
}
217
218
// ### DOC: Shouldn't this be removeBlock()?
219
/*!
220
    Removes the given \a block from the group; the block itself is not
221
    deleted, it simply isn't a member of this group anymore.
222
*/
223
void QTextBlockGroup::blockRemoved(const QTextBlock &block)
224
0
{
225
0
    Q_D(QTextBlockGroup);
226
0
    d->blocks.removeAll(block);
227
0
    d->markBlocksDirty();
228
0
    if (d->blocks.isEmpty()) {
229
0
        QTextDocumentPrivate::get(document())->deleteObject(this);
230
0
        return;
231
0
    }
232
0
}
233
234
/*!
235
    This function is called whenever the specified \a block of text is changed.
236
    The text block is a member of this group.
237
238
    The base class implementation does nothing.
239
*/
240
void QTextBlockGroup::blockFormatChanged(const QTextBlock &)
241
0
{
242
0
}
243
244
/*!
245
    Returns a (possibly empty) list of all the blocks that are part of
246
    the block group.
247
*/
248
QList<QTextBlock> QTextBlockGroup::blockList() const
249
0
{
250
0
    Q_D(const QTextBlockGroup);
251
0
    return d->blocks;
252
0
}
253
254
255
256
QTextFrameLayoutData::~QTextFrameLayoutData()
257
17.4k
{
258
17.4k
}
259
260
261
/*!
262
    \class QTextFrame
263
    \reentrant
264
265
    \brief The QTextFrame class represents a frame in a QTextDocument.
266
    \inmodule QtGui
267
268
    \ingroup richtext-processing
269
270
    Text frames provide structure for the text in a document. They are used
271
    as generic containers for other document elements.
272
    Frames are usually created by using QTextCursor::insertFrame().
273
274
    \omit
275
    Each frame in a document consists of a frame start character,
276
    QChar(0xFDD0), followed by the frame's contents, followed by a
277
    frame end character, QChar(0xFDD1). The character formats of the
278
    start and end character contain a reference to the frame object's
279
    objectIndex.
280
    \endomit
281
282
    Frames can be used to create hierarchical structures in rich text documents.
283
    Each document has a root frame (QTextDocument::rootFrame()), and each frame
284
    beneath the root frame has a parent frame and a (possibly empty) list of
285
    child frames. The parent frame can be found with parentFrame(), and the
286
    childFrames() function provides a list of child frames.
287
288
    Each frame contains at least one text block to enable text cursors to
289
    insert new document elements within. As a result, the QTextFrame::iterator
290
    class is used to traverse both the blocks and child frames within a given
291
    frame. The first and last child elements in the frame can be found with
292
    begin() and end().
293
294
    A frame also has a format (specified using QTextFrameFormat) which can be set
295
    with setFormat() and read with format().
296
297
    Text cursors can be obtained that point to the first and last valid cursor
298
    positions within a frame; use the firstCursorPosition() and
299
    lastCursorPosition() functions for this. The frame's extent in the
300
    document can be found with firstPosition() and lastPosition().
301
302
    You can iterate over a frame's contents using the
303
    QTextFrame::iterator class: this provides read-only access to its
304
    internal list of text blocks and child frames.
305
306
    \sa QTextCursor, QTextDocument
307
*/
308
309
/*!
310
    \typedef QTextFrame::Iterator
311
312
    Qt-style synonym for QTextFrame::iterator.
313
*/
314
315
/*!
316
    \fn QTextFrame *QTextFrame::iterator::parentFrame() const
317
318
    Returns the parent frame of the current frame.
319
320
    \sa currentFrame(), QTextFrame::parentFrame()
321
*/
322
323
/*!
324
    \fn bool QTextFrame::iterator::operator==(const iterator &other) const
325
326
    Returns true if the iterator is the same as the \a other iterator;
327
    otherwise returns \c false.
328
*/
329
330
/*!
331
    \fn bool QTextFrame::iterator::operator!=(const iterator &other) const
332
333
    Returns true if the iterator is different from the \a other iterator;
334
    otherwise returns \c false.
335
*/
336
337
/*!
338
    \fn QTextFrame::iterator QTextFrame::iterator::operator++(int)
339
340
    The postfix \c{++} operator (\c{i++}) advances the iterator to the
341
    next item in the text frame, and returns an iterator to the old item.
342
*/
343
344
/*!
345
    \fn QTextFrame::iterator QTextFrame::iterator::operator--(int)
346
347
    The postfix \c{--} operator (\c{i--}) makes the preceding item in the
348
    current frame, and returns an iterator to the old item.
349
*/
350
351
/*!
352
    \fn void QTextFrame::setFrameFormat(const QTextFrameFormat &format)
353
354
    Sets the frame's \a format.
355
356
    \sa frameFormat()
357
*/
358
359
/*!
360
    \fn QTextFrameFormat QTextFrame::frameFormat() const
361
362
    Returns the frame's format.
363
364
    \sa setFrameFormat()
365
*/
366
367
/*!
368
    \fn QTextFrame::QTextFrame(QTextDocument *document)
369
370
    Creates a new empty frame for the text \a document.
371
*/
372
QTextFrame::QTextFrame(QTextDocument *doc)
373
17.4k
    : QTextObject(*new QTextFramePrivate(doc), doc)
374
17.4k
{
375
17.4k
}
376
377
/*!
378
    Destroys the text frame.
379
380
    \warning Text frames are owned by the document, so you should
381
    never destroy them yourself. In order to remove a frame from
382
    its document, remove its contents using a \c QTextCursor.
383
*/
384
QTextFrame::~QTextFrame()
385
17.4k
{
386
17.4k
    Q_D(QTextFrame);
387
17.4k
    delete d->layoutData;
388
17.4k
}
389
390
/*!
391
    \internal
392
*/
393
QTextFrame::QTextFrame(QTextFramePrivate &p, QTextDocument *doc)
394
0
    : QTextObject(p, doc)
395
0
{
396
0
}
397
398
/*!
399
    Returns a (possibly empty) list of the frame's child frames.
400
401
    \sa parentFrame()
402
*/
403
QList<QTextFrame *> QTextFrame::childFrames() const
404
229k
{
405
229k
    Q_D(const QTextFrame);
406
229k
    return d->childFrames;
407
229k
}
408
409
/*!
410
    Returns the frame's parent frame. If the frame is the root frame of a
411
    document, this will return 0.
412
413
    \sa childFrames(), QTextDocument::rootFrame()
414
*/
415
QTextFrame *QTextFrame::parentFrame() const
416
156k
{
417
156k
    Q_D(const QTextFrame);
418
156k
    return d->parentFrame;
419
156k
}
420
421
422
/*!
423
    Returns the first cursor position inside the frame.
424
425
    \sa lastCursorPosition(), firstPosition(), lastPosition()
426
*/
427
QTextCursor QTextFrame::firstCursorPosition() const
428
0
{
429
0
    Q_D(const QTextFrame);
430
0
    return QTextCursorPrivate::fromPosition(d->pieceTable, firstPosition());
431
0
}
432
433
/*!
434
    Returns the last cursor position inside the frame.
435
436
    \sa firstCursorPosition(), firstPosition(), lastPosition()
437
*/
438
QTextCursor QTextFrame::lastCursorPosition() const
439
0
{
440
0
    Q_D(const QTextFrame);
441
0
    return QTextCursorPrivate::fromPosition(d->pieceTable, lastPosition());
442
0
}
443
444
/*!
445
    Returns the first document position inside the frame.
446
447
    \sa lastPosition(), firstCursorPosition(), lastCursorPosition()
448
*/
449
int QTextFrame::firstPosition() const
450
264k
{
451
264k
    Q_D(const QTextFrame);
452
264k
    if (!d->fragment_start)
453
264k
        return 0;
454
0
    return d->pieceTable->fragmentMap().position(d->fragment_start) + 1;
455
264k
}
456
457
/*!
458
    Returns the last document position inside the frame.
459
460
    \sa firstPosition(), firstCursorPosition(), lastCursorPosition()
461
*/
462
int QTextFrame::lastPosition() const
463
229k
{
464
229k
    Q_D(const QTextFrame);
465
229k
    if (!d->fragment_end)
466
229k
        return d->pieceTable->length() - 1;
467
0
    return d->pieceTable->fragmentMap().position(d->fragment_end);
468
229k
}
469
470
/*!
471
  \internal
472
*/
473
QTextFrameLayoutData *QTextFrame::layoutData() const
474
3.31M
{
475
3.31M
    Q_D(const QTextFrame);
476
3.31M
    return d->layoutData;
477
3.31M
}
478
479
/*!
480
  \internal
481
*/
482
void QTextFrame::setLayoutData(QTextFrameLayoutData *data)
483
17.4k
{
484
17.4k
    Q_D(QTextFrame);
485
17.4k
    delete d->layoutData;
486
17.4k
    d->layoutData = data;
487
17.4k
}
488
489
490
491
void QTextFramePrivate::fragmentAdded(QChar type, uint fragment)
492
0
{
493
0
    if (type == QTextBeginningOfFrame) {
494
0
        Q_ASSERT(!fragment_start);
495
0
        fragment_start = fragment;
496
0
    } else if (type == QTextEndOfFrame) {
497
0
        Q_ASSERT(!fragment_end);
498
0
        fragment_end = fragment;
499
0
    } else if (type == QChar::ObjectReplacementCharacter) {
500
0
        Q_ASSERT(!fragment_start);
501
0
        Q_ASSERT(!fragment_end);
502
0
        fragment_start = fragment;
503
0
        fragment_end = fragment;
504
0
    } else {
505
0
        Q_ASSERT(false);
506
0
    }
507
0
}
508
509
void QTextFramePrivate::fragmentRemoved(QChar type, uint fragment)
510
0
{
511
0
    Q_UNUSED(fragment); // --release warning
512
0
    if (type == QTextBeginningOfFrame) {
513
0
        Q_ASSERT(fragment_start == fragment);
514
0
        fragment_start = 0;
515
0
    } else if (type == QTextEndOfFrame) {
516
0
        Q_ASSERT(fragment_end == fragment);
517
0
        fragment_end = 0;
518
0
    } else if (type == QChar::ObjectReplacementCharacter) {
519
0
        Q_ASSERT(fragment_start == fragment);
520
0
        Q_ASSERT(fragment_end == fragment);
521
0
        fragment_start = 0;
522
0
        fragment_end = 0;
523
0
    } else {
524
0
        Q_ASSERT(false);
525
0
    }
526
0
    remove_me();
527
0
}
528
529
530
void QTextFramePrivate::remove_me()
531
0
{
532
0
    Q_Q(QTextFrame);
533
0
    if (fragment_start == 0 && fragment_end == 0
534
0
        && !parentFrame) {
535
0
        QTextDocumentPrivate::get(q->document())->deleteObject(q);
536
0
        return;
537
0
    }
538
539
0
    if (!parentFrame)
540
0
        return;
541
542
0
    int index = parentFrame->d_func()->childFrames.indexOf(q);
543
544
    // iterator over all children and move them to the parent
545
0
    for (int i = 0; i < childFrames.size(); ++i) {
546
0
        QTextFrame *c = childFrames.at(i);
547
0
        parentFrame->d_func()->childFrames.insert(index, c);
548
0
        c->d_func()->parentFrame = parentFrame;
549
0
        ++index;
550
0
    }
551
0
    Q_ASSERT(parentFrame->d_func()->childFrames.at(index) == q);
552
0
    parentFrame->d_func()->childFrames.removeAt(index);
553
554
0
    childFrames.clear();
555
0
    parentFrame = nullptr;
556
0
}
557
558
/*!
559
    \class QTextFrame::iterator
560
    \reentrant
561
562
    \brief The iterator class provides an iterator for reading
563
    the contents of a QTextFrame.
564
565
    \inmodule QtGui
566
    \ingroup richtext-processing
567
568
    A frame consists of an arbitrary sequence of \l{QTextBlock}s and
569
    child \l{QTextFrame}s. This class provides a way to iterate over the
570
    child objects of a frame, and read their contents. It does not provide
571
    a way to modify the contents of the frame.
572
573
*/
574
575
/*!
576
    \fn bool QTextFrame::iterator::atEnd() const
577
578
    Returns \c true if the current item is the last item in the text frame.
579
*/
580
581
/*!
582
    Returns an iterator pointing to the first document element inside the frame.
583
    Please see the document \l{STL-style-Iterators} for more information.
584
585
    \sa end()
586
*/
587
QTextFrame::iterator QTextFrame::begin() const
588
52.2k
{
589
52.2k
    const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(this);
590
52.2k
    int b = priv->blockMap().findNode(firstPosition());
591
52.2k
    int e = priv->blockMap().findNode(lastPosition()+1);
592
52.2k
    return iterator(const_cast<QTextFrame *>(this), b, b, e);
593
52.2k
}
594
595
/*!
596
    Returns an iterator pointing to the position past the last document element inside the frame.
597
    Please see the document \l{STL-Style Iterators} for more information.
598
    \sa begin()
599
*/
600
QTextFrame::iterator QTextFrame::end() const
601
0
{
602
0
    const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(this);
603
0
    int b = priv->blockMap().findNode(firstPosition());
604
0
    int e = priv->blockMap().findNode(lastPosition()+1);
605
0
    return iterator(const_cast<QTextFrame *>(this), e, b, e);
606
0
}
607
608
/*!
609
    \fn QTextFrame::iterator::iterator()
610
611
    Constructs an invalid iterator.
612
*/
613
614
/*!
615
    \fn QTextFrame *QTextFrame::iterator::currentFrame() const
616
    Returns the current frame pointed to by the iterator, or \nullptr
617
    if the iterator currently points to a block.
618
619
    \sa currentBlock()
620
*/
621
622
/*!
623
    Returns the current block the iterator points to. If the iterator
624
    points to a child frame, the returned block is invalid.
625
626
    \sa currentFrame()
627
*/
628
QTextBlock QTextFrame::iterator::currentBlock() const
629
3.60M
{
630
3.60M
    if (!f)
631
69.6k
        return QTextBlock();
632
3.53M
    return QTextBlock(QTextDocumentPrivate::get(f), cb);
633
3.60M
}
634
635
/*!
636
    Moves the iterator to the next frame or block.
637
638
    \sa currentBlock(), currentFrame()
639
*/
640
QTextFrame::iterator &QTextFrame::iterator::operator++()
641
1.13M
{
642
1.13M
    const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(f);
643
1.13M
    const QTextDocumentPrivate::BlockMap &map = priv->blockMap();
644
1.13M
    if (cf) {
645
0
        int end = cf->lastPosition() + 1;
646
0
        cb = map.findNode(end);
647
0
        cf = nullptr;
648
1.13M
    } else if (cb) {
649
1.13M
        cb = map.next(cb);
650
1.13M
        if (cb == e)
651
64.4k
            return *this;
652
653
1.07M
        if (!f->d_func()->childFrames.isEmpty()) {
654
0
            int pos = map.position(cb);
655
            // check if we entered a frame
656
0
            QTextDocumentPrivate::FragmentIterator frag = priv->find(pos-1);
657
0
            if (priv->buffer().at(frag->stringPosition) != QChar::ParagraphSeparator) {
658
0
                QTextFrame *nf = qobject_cast<QTextFrame *>(priv->objectForFormat(frag->format));
659
0
                if (nf) {
660
0
                    if (priv->buffer().at(frag->stringPosition) == QTextBeginningOfFrame && nf != f) {
661
0
                        cf = nf;
662
0
                        cb = 0;
663
0
                    } else {
664
0
                        Q_ASSERT(priv->buffer().at(frag->stringPosition) != QTextEndOfFrame);
665
0
                    }
666
0
                }
667
0
            }
668
0
        }
669
1.07M
    }
670
1.07M
    return *this;
671
1.13M
}
672
673
/*!
674
    Moves the iterator to the previous frame or block.
675
676
    \sa currentBlock(), currentFrame()
677
*/
678
QTextFrame::iterator &QTextFrame::iterator::operator--()
679
0
{
680
0
    const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(f);
681
0
    const QTextDocumentPrivate::BlockMap &map = priv->blockMap();
682
0
    if (cf) {
683
0
        int start = cf->firstPosition() - 1;
684
0
        cb = map.findNode(start);
685
0
        cf = nullptr;
686
0
    } else {
687
0
        if (cb == b)
688
0
            goto end;
689
0
        if (cb != e) {
690
0
            int pos = map.position(cb);
691
            // check if we have to enter a frame
692
0
            QTextDocumentPrivate::FragmentIterator frag = priv->find(pos-1);
693
0
            if (priv->buffer().at(frag->stringPosition) != QChar::ParagraphSeparator) {
694
0
                QTextFrame *pf = qobject_cast<QTextFrame *>(priv->objectForFormat(frag->format));
695
0
                if (pf) {
696
0
                    if (priv->buffer().at(frag->stringPosition) == QTextBeginningOfFrame) {
697
0
                        Q_ASSERT(pf == f);
698
0
                    } else if (priv->buffer().at(frag->stringPosition) == QTextEndOfFrame) {
699
0
                        Q_ASSERT(pf != f);
700
0
                        cf = pf;
701
0
                        cb = 0;
702
0
                        goto end;
703
0
                    }
704
0
                }
705
0
            }
706
0
        }
707
0
        cb = map.previous(cb);
708
0
    }
709
0
 end:
710
0
    return *this;
711
0
}
712
713
/*!
714
    \class QTextBlockUserData
715
    \reentrant
716
717
    \brief The QTextBlockUserData class is used to associate custom data with blocks of text.
718
    \inmodule QtGui
719
    \since 4.1
720
721
    \ingroup richtext-processing
722
723
    QTextBlockUserData provides an abstract interface for container classes that are used
724
    to associate application-specific user data with text blocks in a QTextDocument.
725
726
    Generally, subclasses of this class provide functions to allow data to be stored
727
    and retrieved, and instances are attached to blocks of text using
728
    QTextBlock::setUserData(). This makes it possible to store additional data per text
729
    block in a way that can be retrieved safely by the application.
730
731
    Each subclass should provide a reimplementation of the destructor to ensure that any
732
    private data is automatically cleaned up when user data objects are deleted.
733
734
    \sa QTextBlock
735
*/
736
737
/*!
738
    Destroys the user data.
739
*/
740
QTextBlockUserData::~QTextBlockUserData()
741
424k
{
742
424k
}
743
744
/*!
745
    \class QTextBlock
746
    \reentrant
747
748
    \brief The QTextBlock class provides a container for text fragments in a
749
    QTextDocument.
750
    \inmodule QtGui
751
752
    \ingroup richtext-processing
753
754
    A text block encapsulates a block or paragraph of text in a QTextDocument.
755
    QTextBlock provides read-only access to the block/paragraph structure of
756
    QTextDocuments. It is mainly of use if you want to implement your own
757
    layouts for the visual representation of a QTextDocument, or if you want to
758
    iterate over a document and write out the contents in your own custom
759
    format.
760
761
    Text blocks are created by their parent documents. If you need to create
762
    a new text block, or modify the contents of a document while examining its
763
    contents, use the cursor-based interface provided by QTextCursor instead.
764
765
    Each text block is located at a specific position() in a document().
766
    The contents of the block can be obtained by using the text() function.
767
    The length() function determines the block's size within the document
768
    (including formatting characters).
769
    The visual properties of the block are determined by its text layout(),
770
    its charFormat(), and its blockFormat().
771
772
    The next() and previous() functions enable iteration over consecutive
773
    valid blocks in a document under the condition that the document is not
774
    modified by other means during the iteration process. Note that, although
775
    blocks are returned in sequence, adjacent blocks may come from different
776
    places in the document structure. The validity of a block can be determined
777
    by calling isValid().
778
779
    QTextBlock provides comparison operators to make it easier to work with
780
    blocks: \l operator==() compares two block for equality, \l operator!=()
781
    compares two blocks for inequality, and \l operator<() determines whether
782
    a block precedes another in the same document.
783
784
    \image qtextblock-sequence.png {Diagram showing multiple text blocks in
785
           a hierarchy of text frames, and the iteration order between the
786
           text blocks.}
787
788
    \sa QTextBlockFormat, QTextCharFormat, QTextFragment
789
 */
790
791
/*!
792
    \fn QTextBlock::QTextBlock(QTextDocumentPrivate *priv, int b)
793
794
    \internal
795
*/
796
797
/*!
798
    \fn QTextBlock::QTextBlock()
799
800
    \internal
801
*/
802
803
/*!
804
    \fn QTextBlock::QTextBlock(const QTextBlock &other)
805
806
    Copies the \a other text block's attributes to this text block.
807
*/
808
809
/*!
810
    \fn bool QTextBlock::isValid() const
811
812
    Returns \c true if this text block is valid; otherwise returns \c false.
813
*/
814
815
bool QTextBlock::isValid() const
816
9.22M
{
817
9.22M
    return p != nullptr && p->blockMap().isValid(n);
818
9.22M
}
819
820
/*!
821
    \fn QTextBlock &QTextBlock::operator=(const QTextBlock &other)
822
823
    Assigns the \a other text block to this text block.
824
*/
825
826
/*!
827
    \fn bool QTextBlock::operator==(const QTextBlock &other) const
828
829
    Returns \c true if this text block is the same as the \a other text
830
    block.
831
*/
832
833
/*!
834
    \fn bool QTextBlock::operator!=(const QTextBlock &other) const
835
836
    Returns \c true if this text block is different from the \a other
837
    text block.
838
*/
839
840
/*!
841
    \fn bool QTextBlock::operator<(const QTextBlock &other) const
842
843
    Returns \c true if this text block occurs before the \a other text
844
    block in the document.
845
*/
846
847
/*!
848
    \class QTextBlock::iterator
849
    \reentrant
850
851
    \brief The QTextBlock::iterator class provides an iterator for reading
852
    the contents of a QTextBlock.
853
    \inmodule QtGui
854
855
    \ingroup richtext-processing
856
857
    A block consists of a sequence of text fragments. This class provides
858
    a way to iterate over these, and read their contents. It does not provide
859
    a way to modify the internal structure or contents of the block.
860
861
    An iterator can be constructed and used to access the fragments within
862
    a text block in the following way:
863
864
    \snippet textblock-fragments/xmlwriter.cpp 4
865
    \snippet textblock-fragments/xmlwriter.cpp 7
866
867
    \sa QTextFragment
868
*/
869
870
/*!
871
    \typedef QTextBlock::Iterator
872
873
    Qt-style synonym for QTextBlock::iterator.
874
*/
875
876
/*!
877
    \fn QTextBlock::iterator::iterator()
878
879
    Constructs an iterator for this text block.
880
*/
881
882
/*!
883
    \fn bool QTextBlock::iterator::atEnd() const
884
885
    Returns \c true if the current item is the last item in the text block.
886
*/
887
888
/*!
889
    \fn bool QTextBlock::iterator::operator==(const iterator &other) const
890
891
    Returns true if this iterator is the same as the \a other iterator;
892
    otherwise returns \c false.
893
*/
894
895
/*!
896
    \fn bool QTextBlock::iterator::operator!=(const iterator &other) const
897
898
    Returns true if this iterator is different from the \a other iterator;
899
    otherwise returns \c false.
900
*/
901
902
/*!
903
    \fn QTextBlock::iterator QTextBlock::iterator::operator++(int)
904
905
    The postfix ++ operator (\c{i++}) advances the iterator to the
906
    next item in the text block and returns an iterator to the old current
907
    item.
908
*/
909
910
/*!
911
    \fn QTextBlock::iterator QTextBlock::iterator::operator--(int)
912
913
    The postfix -- operator (\c{i--}) makes the preceding item current and
914
    returns an iterator to the old current item.
915
*/
916
917
/*!
918
    \fn int QTextBlock::fragmentIndex() const
919
920
    \internal
921
*/
922
923
/*!
924
    Returns the index of the block's first character within the document.
925
 */
926
int QTextBlock::position() const
927
9.09M
{
928
9.09M
    if (!p || !n)
929
0
        return 0;
930
931
9.09M
    return p->blockMap().position(n);
932
9.09M
}
933
934
/*!
935
    Returns the length of the block in characters.
936
937
    \note The length returned includes all formatting characters,
938
    for example, newline.
939
940
    \sa text(), charFormat(), blockFormat()
941
 */
942
int QTextBlock::length() const
943
6.39M
{
944
6.39M
    if (!p || !n)
945
0
        return 0;
946
947
6.39M
    return p->blockMap().size(n);
948
6.39M
}
949
950
/*!
951
    Returns \c true if the given \a position is located within the text
952
    block; otherwise returns \c false.
953
 */
954
bool QTextBlock::contains(int position) const
955
0
{
956
0
    if (!p || !n)
957
0
        return false;
958
959
0
    int pos = p->blockMap().position(n);
960
0
    int len = p->blockMap().size(n);
961
0
    return position >= pos && position < pos + len;
962
0
}
963
964
/*!
965
    Returns the QTextLayout that is used to lay out and display the
966
    block's contents.
967
968
    Note that the returned QTextLayout object can only be modified from the
969
    documentChanged implementation of a QAbstractTextDocumentLayout subclass.
970
    Any changes applied from the outside cause undefined behavior.
971
972
    \sa clearLayout()
973
 */
974
QTextLayout *QTextBlock::layout() const
975
3.21M
{
976
3.21M
    if (!p || !n)
977
0
        return nullptr;
978
979
3.21M
    const QTextBlockData *b = p->blockMap().fragment(n);
980
3.21M
    if (!b->layout)
981
424k
        b->layout = new QTextLayout(*this);
982
3.21M
    return b->layout;
983
3.21M
}
984
985
/*!
986
    \since 4.4
987
    Clears the QTextLayout that is used to lay out and display the
988
    block's contents.
989
990
    \sa layout()
991
 */
992
void QTextBlock::clearLayout()
993
848k
{
994
848k
    if (!p || !n)
995
0
        return;
996
997
848k
    const QTextBlockData *b = p->blockMap().fragment(n);
998
848k
    if (b->layout)
999
848k
        b->layout->clearLayout();
1000
848k
}
1001
1002
/*!
1003
    Returns the QTextBlockFormat that describes block-specific properties.
1004
1005
    \sa charFormat()
1006
 */
1007
QTextBlockFormat QTextBlock::blockFormat() const
1008
2.13M
{
1009
2.13M
    if (!p || !n)
1010
52.2k
        return QTextFormat().toBlockFormat();
1011
1012
2.08M
    return p->formatCollection()->blockFormat(p->blockMap().fragment(n)->format);
1013
2.13M
}
1014
1015
/*!
1016
    Returns an index into the document's internal list of block formats
1017
    for the text block's format.
1018
1019
    \sa QTextDocument::allFormats()
1020
*/
1021
int QTextBlock::blockFormatIndex() const
1022
0
{
1023
0
    if (!p || !n)
1024
0
        return -1;
1025
1026
0
    return p->blockMap().fragment(n)->format;
1027
0
}
1028
1029
/*!
1030
    Returns the QTextCharFormat that describes the block's character
1031
    format. The block's character format is used when inserting text into
1032
    an empty block.
1033
1034
    \sa blockFormat()
1035
 */
1036
QTextCharFormat QTextBlock::charFormat() const
1037
598k
{
1038
598k
    if (!p || !n)
1039
0
        return QTextFormat().toCharFormat();
1040
1041
598k
    return p->formatCollection()->charFormat(charFormatIndex());
1042
598k
}
1043
1044
/*!
1045
    Returns an index into the document's internal list of character formats
1046
    for the text block's character format.
1047
1048
    \sa QTextDocument::allFormats()
1049
*/
1050
int QTextBlock::charFormatIndex() const
1051
598k
{
1052
598k
    if (!p || !n)
1053
0
        return -1;
1054
1055
598k
    return p->blockCharFormatIndex(n);
1056
598k
}
1057
1058
/*!
1059
  \since 4.7
1060
1061
  Returns the resolved text direction.
1062
1063
  If the block has no explicit direction set, it will resolve the
1064
  direction from the blocks content. Returns either Qt::LeftToRight
1065
  or Qt::RightToLeft.
1066
1067
  \sa QTextFormat::layoutDirection(), QString::isRightToLeft(), Qt::LayoutDirection
1068
*/
1069
Qt::LayoutDirection QTextBlock::textDirection() const
1070
836k
{
1071
836k
    Qt::LayoutDirection dir = blockFormat().layoutDirection();
1072
836k
    if (dir != Qt::LayoutDirectionAuto)
1073
0
        return dir;
1074
1075
836k
    dir = p->defaultTextOption.textDirection();
1076
836k
    if (dir != Qt::LayoutDirectionAuto)
1077
836k
        return dir;
1078
1079
0
    const QString buffer = p->buffer();
1080
1081
0
    const int pos = position();
1082
0
    QTextDocumentPrivate::FragmentIterator it = p->find(pos);
1083
0
    QTextDocumentPrivate::FragmentIterator end = p->find(pos + length() - 1); // -1 to omit the block separator char
1084
0
    for (; it != end; ++it) {
1085
0
        const QTextFragmentData * const frag = it.value();
1086
0
        const QChar *p = buffer.constData() + frag->stringPosition;
1087
0
        const QChar * const end = p + frag->size_array[0];
1088
0
        while (p < end) {
1089
0
            uint ucs4 = p->unicode();
1090
0
            if (QChar::isHighSurrogate(ucs4) && p + 1 < end) {
1091
0
                ushort low = p[1].unicode();
1092
0
                if (QChar::isLowSurrogate(low)) {
1093
0
                    ucs4 = QChar::surrogateToUcs4(ucs4, low);
1094
0
                    ++p;
1095
0
                }
1096
0
            }
1097
0
            switch (QChar::direction(ucs4)) {
1098
0
            case QChar::DirL:
1099
0
                return Qt::LeftToRight;
1100
0
            case QChar::DirR:
1101
0
            case QChar::DirAL:
1102
0
                return Qt::RightToLeft;
1103
0
            default:
1104
0
                break;
1105
0
            }
1106
0
            ++p;
1107
0
        }
1108
0
    }
1109
0
    return Qt::LeftToRight;
1110
0
}
1111
1112
/*!
1113
    Returns the block's contents as plain text.
1114
1115
    \sa length(), charFormat(), blockFormat()
1116
 */
1117
QString QTextBlock::text() const
1118
1.74M
{
1119
1.74M
    if (!p || !n)
1120
0
        return QString();
1121
1122
1.74M
    const QString buffer = p->buffer();
1123
1.74M
    QString text;
1124
1.74M
    text.reserve(length());
1125
1126
1.74M
    const int pos = position();
1127
1.74M
    QTextDocumentPrivate::FragmentIterator it = p->find(pos);
1128
1.74M
    QTextDocumentPrivate::FragmentIterator end = p->find(pos + length() - 1); // -1 to omit the block separator char
1129
2.24M
    for (; it != end; ++it) {
1130
500k
        const QTextFragmentData * const frag = it.value();
1131
500k
        text += QStringView(buffer.constData() + frag->stringPosition, frag->size_array[0]);
1132
500k
    }
1133
1134
1.74M
    return text;
1135
1.74M
}
1136
1137
/*!
1138
    \since 5.3
1139
1140
    Returns the block's text format options as a list of continuous ranges
1141
    of QTextCharFormat. The range's character format is used when inserting text
1142
    within the range boundaries.
1143
1144
    \sa charFormat(), blockFormat()
1145
*/
1146
QList<QTextLayout::FormatRange> QTextBlock::textFormats() const
1147
0
{
1148
0
    QList<QTextLayout::FormatRange> formats;
1149
0
    if (!p || !n)
1150
0
        return formats;
1151
1152
0
    const QTextFormatCollection *formatCollection = p->formatCollection();
1153
1154
0
    int start = 0;
1155
0
    int cur = start;
1156
0
    int format = -1;
1157
1158
0
    const int pos = position();
1159
0
    QTextDocumentPrivate::FragmentIterator it = p->find(pos);
1160
0
    QTextDocumentPrivate::FragmentIterator end = p->find(pos + length() - 1); // -1 to omit the block separator char
1161
0
    for (; it != end; ++it) {
1162
0
        const QTextFragmentData * const frag = it.value();
1163
0
        if (format != it.value()->format) {
1164
0
            if (cur - start > 0) {
1165
0
                QTextLayout::FormatRange range;
1166
0
                range.start = start;
1167
0
                range.length = cur - start;
1168
0
                range.format = formatCollection->charFormat(format);
1169
0
                formats.append(range);
1170
0
            }
1171
1172
0
            format = frag->format;
1173
0
            start = cur;
1174
0
        }
1175
0
        cur += frag->size_array[0];
1176
0
    }
1177
0
    if (cur - start > 0) {
1178
0
        QTextLayout::FormatRange range;
1179
0
        range.start = start;
1180
0
        range.length = cur - start;
1181
0
        range.format = formatCollection->charFormat(format);
1182
0
        formats.append(range);
1183
0
    }
1184
1185
0
    return formats;
1186
0
}
1187
1188
/*!
1189
    Returns the text document this text block belongs to, or \nullptr
1190
    if the text block does not belong to any document.
1191
*/
1192
const QTextDocument *QTextBlock::document() const
1193
0
{
1194
0
    return p ? p->document() : nullptr;
1195
0
}
1196
1197
/*!
1198
    If the block represents a list item, returns the list that the item belongs
1199
    to; otherwise returns \nullptr.
1200
*/
1201
QTextList *QTextBlock::textList() const
1202
0
{
1203
0
    if (!isValid())
1204
0
        return nullptr;
1205
1206
0
    const QTextBlockFormat fmt = blockFormat();
1207
0
    QTextObject *obj = p->document()->objectForFormat(fmt);
1208
0
    return qobject_cast<QTextList *>(obj);
1209
0
}
1210
1211
/*!
1212
    \since 4.1
1213
1214
    Returns a pointer to a QTextBlockUserData object,
1215
    if one has been set with setUserData(), or \nullptr.
1216
*/
1217
QTextBlockUserData *QTextBlock::userData() const
1218
1.66M
{
1219
1.66M
    if (!p || !n)
1220
0
        return nullptr;
1221
1222
1.66M
    const QTextBlockData *b = p->blockMap().fragment(n);
1223
1.66M
    return b->userData;
1224
1.66M
}
1225
1226
/*!
1227
    \since 4.1
1228
1229
    Attaches the given \a data object to the text block.
1230
1231
    QTextBlockUserData can be used to store custom settings.  The
1232
    ownership is passed to the underlying text document, i.e. the
1233
    provided QTextBlockUserData object will be deleted if the
1234
    corresponding text block gets deleted. The user data object is
1235
    not stored in the undo history, so it will not be available after
1236
    undoing the deletion of a text block.
1237
1238
    For example, if you write a programming editor in an IDE, you may
1239
    want to let your user set breakpoints visually in your code for an
1240
    integrated debugger. In a programming editor a line of text
1241
    usually corresponds to one QTextBlock. The QTextBlockUserData
1242
    interface allows the developer to store data for each QTextBlock,
1243
    like for example in which lines of the source code the user has a
1244
    breakpoint set. Of course this could also be stored externally,
1245
    but by storing it inside the QTextDocument, it will for example be
1246
    automatically deleted when the user deletes the associated
1247
    line. It's really just a way to store custom information in the
1248
    QTextDocument without using custom properties in QTextFormat which
1249
    would affect the undo/redo stack.
1250
*/
1251
void QTextBlock::setUserData(QTextBlockUserData *data)
1252
424k
{
1253
424k
    if (!p || !n)
1254
0
        return;
1255
1256
424k
    const QTextBlockData *b = p->blockMap().fragment(n);
1257
424k
    if (data != b->userData)
1258
424k
        delete b->userData;
1259
424k
    b->userData = data;
1260
424k
}
1261
1262
/*!
1263
    \since 4.1
1264
1265
    Returns the integer value previously set with setUserState() or -1.
1266
*/
1267
int QTextBlock::userState() const
1268
1.69M
{
1269
1.69M
    if (!p || !n)
1270
0
        return -1;
1271
1272
1.69M
    const QTextBlockData *b = p->blockMap().fragment(n);
1273
1.69M
    return b->userState;
1274
1.69M
}
1275
1276
/*!
1277
    \since 4.1
1278
1279
    Stores the specified \a state integer value in the text block. This may be
1280
    useful for example in a syntax highlighter to store a text parsing state.
1281
*/
1282
void QTextBlock::setUserState(int state)
1283
0
{
1284
0
    if (!p || !n)
1285
0
        return;
1286
1287
0
    const QTextBlockData *b = p->blockMap().fragment(n);
1288
0
    b->userState = state;
1289
0
}
1290
1291
/*!
1292
    \since 4.4
1293
1294
    Returns the blocks revision.
1295
1296
    \sa setRevision(), QTextDocument::revision()
1297
*/
1298
int QTextBlock::revision() const
1299
0
{
1300
0
    if (!p || !n)
1301
0
        return -1;
1302
1303
0
    const QTextBlockData *b = p->blockMap().fragment(n);
1304
0
    return b->revision;
1305
0
}
1306
1307
/*!
1308
    \since 4.4
1309
1310
    Sets a blocks revision to \a rev.
1311
1312
    \sa revision(), QTextDocument::revision()
1313
*/
1314
void QTextBlock::setRevision(int rev)
1315
0
{
1316
0
    if (!p || !n)
1317
0
        return;
1318
1319
0
    const QTextBlockData *b = p->blockMap().fragment(n);
1320
0
    b->revision = rev;
1321
0
}
1322
1323
/*!
1324
    \since 4.4
1325
1326
    Returns \c true if the block is visible; otherwise returns \c false.
1327
1328
    \sa setVisible()
1329
*/
1330
bool QTextBlock::isVisible() const
1331
1.08M
{
1332
1.08M
    if (!p || !n)
1333
0
        return true;
1334
1335
1.08M
    const QTextBlockData *b = p->blockMap().fragment(n);
1336
1.08M
    return !b->hidden;
1337
1.08M
}
1338
1339
/*!
1340
    \since 4.4
1341
1342
    Sets the block's visibility to \a visible.
1343
1344
    \sa isVisible()
1345
*/
1346
void QTextBlock::setVisible(bool visible)
1347
0
{
1348
0
    if (!p || !n)
1349
0
        return;
1350
1351
0
    const QTextBlockData *b = p->blockMap().fragment(n);
1352
0
    b->hidden = !visible;
1353
0
}
1354
1355
1356
/*!
1357
\since 4.4
1358
1359
    Returns the number of this block, or -1 if the block is invalid.
1360
1361
    \sa QTextCursor::blockNumber()
1362
1363
*/
1364
int QTextBlock::blockNumber() const
1365
0
{
1366
0
    if (!p || !n)
1367
0
        return -1;
1368
0
    return p->blockMap().position(n, 1);
1369
0
}
1370
1371
/*!
1372
\since 4.5
1373
1374
    Returns the first line number of this block, or -1 if the block is invalid.
1375
    Unless the layout supports it, the line number is identical to the block number.
1376
1377
    \sa QTextBlock::blockNumber()
1378
1379
*/
1380
int QTextBlock::firstLineNumber() const
1381
0
{
1382
0
    if (!p || !n)
1383
0
        return -1;
1384
0
    return p->blockMap().position(n, 2);
1385
0
}
1386
1387
1388
/*!
1389
\since 4.5
1390
1391
Sets the line count to \a count.
1392
1393
\sa lineCount()
1394
*/
1395
void QTextBlock::setLineCount(int count)
1396
0
{
1397
0
    if (!p || !n)
1398
0
        return;
1399
0
    p->blockMap().setSize(n, count, 2);
1400
0
}
1401
/*!
1402
\since 4.5
1403
1404
Returns the line count. Not all document layouts support this feature.
1405
1406
\sa setLineCount()
1407
 */
1408
int QTextBlock::lineCount() const
1409
0
{
1410
0
    if (!p || !n)
1411
0
        return -1;
1412
0
    return p->blockMap().size(n, 2);
1413
0
}
1414
1415
1416
/*!
1417
    Returns a text block iterator pointing to the beginning of the
1418
    text block.
1419
1420
    \sa end()
1421
*/
1422
QTextBlock::iterator QTextBlock::begin() const
1423
0
{
1424
0
    if (!p || !n)
1425
0
        return iterator();
1426
1427
0
    int pos = position();
1428
0
    int len = length() - 1; // exclude the fragment that holds the paragraph separator
1429
0
    int b = p->fragmentMap().findNode(pos);
1430
0
    int e = p->fragmentMap().findNode(pos+len);
1431
0
    return iterator(p, b, e, b);
1432
0
}
1433
1434
/*!
1435
    Returns a text block iterator pointing to the end of the text
1436
    block.
1437
1438
    \sa begin(), next(), previous()
1439
*/
1440
QTextBlock::iterator QTextBlock::end() const
1441
0
{
1442
0
    if (!p || !n)
1443
0
        return iterator();
1444
1445
0
    int pos = position();
1446
0
    int len = length() - 1; // exclude the fragment that holds the paragraph separator
1447
0
    int b = p->fragmentMap().findNode(pos);
1448
0
    int e = p->fragmentMap().findNode(pos+len);
1449
0
    return iterator(p, b, e, e);
1450
0
}
1451
1452
1453
/*!
1454
    Returns the text block in the document after this block, or an empty
1455
    text block if this is the last one.
1456
1457
    Note that the next block may be in a different frame or table to this block.
1458
1459
    \sa previous(), begin(), end()
1460
*/
1461
QTextBlock QTextBlock::next() const
1462
3.04M
{
1463
3.04M
    if (!isValid())
1464
0
        return QTextBlock();
1465
1466
3.04M
    return QTextBlock(p, p->blockMap().next(n));
1467
3.04M
}
1468
1469
/*!
1470
    Returns the text block in the document before this block, or an empty text
1471
    block if this is the first one.
1472
1473
    Note that the previous block may be in a different frame or table to this block.
1474
1475
    \sa next(), begin(), end()
1476
*/
1477
QTextBlock QTextBlock::previous() const
1478
814k
{
1479
814k
    if (!p)
1480
0
        return QTextBlock();
1481
1482
814k
    return QTextBlock(p, p->blockMap().previous(n));
1483
814k
}
1484
1485
1486
/*!
1487
    Returns the text fragment the iterator currently points to.
1488
*/
1489
QTextFragment QTextBlock::iterator::fragment() const
1490
0
{
1491
0
    int ne = n;
1492
0
    int formatIndex = p->fragmentMap().fragment(n)->format;
1493
0
    do {
1494
0
        ne = p->fragmentMap().next(ne);
1495
0
    } while (ne != e && p->fragmentMap().fragment(ne)->format == formatIndex);
1496
0
    return QTextFragment(p, n, ne);
1497
0
}
1498
1499
/*!
1500
    The prefix ++ operator (\c{++i}) advances the iterator to the
1501
    next item in the hash and returns an iterator to the new current
1502
    item.
1503
*/
1504
1505
QTextBlock::iterator &QTextBlock::iterator::operator++()
1506
0
{
1507
0
    int ne = n;
1508
0
    int formatIndex = p->fragmentMap().fragment(n)->format;
1509
0
    do {
1510
0
        ne = p->fragmentMap().next(ne);
1511
0
    } while (ne != e && p->fragmentMap().fragment(ne)->format == formatIndex);
1512
0
    n = ne;
1513
0
    return *this;
1514
0
}
1515
1516
/*!
1517
    The prefix -- operator (\c{--i}) makes the preceding item
1518
    current and returns an iterator pointing to the new current item.
1519
*/
1520
1521
QTextBlock::iterator &QTextBlock::iterator::operator--()
1522
0
{
1523
0
    n = p->fragmentMap().previous(n);
1524
1525
0
    if (n == b)
1526
0
        return *this;
1527
1528
0
    int formatIndex = p->fragmentMap().fragment(n)->format;
1529
0
    int last = n;
1530
1531
0
    while (n != b && p->fragmentMap().fragment(n)->format != formatIndex) {
1532
0
        last = n;
1533
0
        n = p->fragmentMap().previous(n);
1534
0
    }
1535
1536
0
    n = last;
1537
0
    return *this;
1538
0
}
1539
1540
1541
/*!
1542
    \class QTextFragment
1543
    \reentrant
1544
1545
    \brief The QTextFragment class holds a piece of text in a
1546
    QTextDocument with a single QTextCharFormat.
1547
    \inmodule QtGui
1548
1549
    \ingroup richtext-processing
1550
1551
    A text fragment describes a piece of text that is stored with a single
1552
    character format. Text in which the character format changes can be
1553
    represented by sequences of text fragments with different formats.
1554
1555
    If the user edits the text in a fragment and introduces a different
1556
    character format, the fragment's text will be split at each point where
1557
    the format changes, and new fragments will be created.
1558
    For example, changing the style of some text in the middle of a
1559
    sentence will cause the fragment to be broken into three separate fragments:
1560
    the first and third with the same format as before, and the second with
1561
    the new style. The first fragment will contain the text from the beginning
1562
    of the sentence, the second will contain the text from the middle, and the
1563
    third takes the text from the end of the sentence.
1564
1565
    \image qtextfragment-split.png {Screenshot showing how a text is separated
1566
           in three fragments if the middle text is made bold.}
1567
1568
    A fragment's text and character format can be obtained with the text()
1569
    and charFormat() functions. The length() function gives the length of
1570
    the text in the fragment. position() gives the position in the document
1571
    of the start of the fragment. To determine whether the fragment contains
1572
    a particular position within the document, use the contains() function.
1573
1574
    \sa QTextDocument, {Rich Text Document Structure}
1575
*/
1576
1577
/*!
1578
    \fn QTextFragment::QTextFragment(const QTextDocumentPrivate *priv, int f, int fe)
1579
    \internal
1580
*/
1581
1582
/*!
1583
    \fn QTextFragment::QTextFragment()
1584
1585
    Creates a new empty text fragment.
1586
*/
1587
1588
/*!
1589
    \fn QTextFragment::QTextFragment(const QTextFragment &other)
1590
1591
    Copies the content (text and format) of the \a other text fragment
1592
    to this text fragment.
1593
*/
1594
1595
/*!
1596
    \fn QTextFragment &QTextFragment::operator=(const QTextFragment
1597
    &other)
1598
1599
    Assigns the content (text and format) of the \a other text fragment
1600
    to this text fragment.
1601
*/
1602
1603
/*!
1604
    \fn bool QTextFragment::isValid() const
1605
1606
    Returns \c true if this is a valid text fragment (i.e. has a valid
1607
    position in a document); otherwise returns \c false.
1608
*/
1609
1610
/*!
1611
    \fn bool QTextFragment::operator==(const QTextFragment &other) const
1612
1613
    Returns \c true if this text fragment is the same (at the same
1614
    position) as the \a other text fragment; otherwise returns \c false.
1615
*/
1616
1617
/*!
1618
    \fn bool QTextFragment::operator!=(const QTextFragment &other) const
1619
1620
    Returns \c true if this text fragment is different (at a different
1621
    position) from the \a other text fragment; otherwise returns
1622
    false.
1623
*/
1624
1625
/*!
1626
    \fn bool QTextFragment::operator<(const QTextFragment &other) const
1627
1628
    Returns \c true if this text fragment appears earlier in the document
1629
    than the \a other text fragment; otherwise returns \c false.
1630
*/
1631
1632
/*!
1633
    Returns the glyphs corresponding to \a len characters of this text fragment starting at
1634
    position \a pos. The positions of the glyphs are relative to the position of the QTextBlock's
1635
    layout.
1636
1637
    If \a pos is less than zero, it will default to the start of the QTextFragment. If \a len
1638
    is less than zero, it will default to the length of the fragment.
1639
1640
    \sa QGlyphRun, QTextBlock::layout(), QTextLayout::position(), QPainter::drawGlyphRun()
1641
*/
1642
#if !defined(QT_NO_RAWFONT)
1643
QList<QGlyphRun> QTextFragment::glyphRuns(int pos, int len) const
1644
0
{
1645
0
    if (!p || !n)
1646
0
        return QList<QGlyphRun>();
1647
1648
0
    int blockNode = p->blockMap().findNode(position());
1649
1650
0
    const QTextBlockData *blockData = p->blockMap().fragment(blockNode);
1651
0
    QTextLayout *layout = blockData->layout;
1652
1653
0
    int blockPosition = p->blockMap().position(blockNode);
1654
0
    if (pos < 0)
1655
0
        pos = position() - blockPosition;
1656
0
    if (len < 0)
1657
0
        len = length();
1658
0
    if (len == 0)
1659
0
        return QList<QGlyphRun>();
1660
1661
0
    QList<QGlyphRun> ret;
1662
0
    for (int i=0; i<layout->lineCount(); ++i) {
1663
0
        QTextLine textLine = layout->lineAt(i);
1664
0
        ret += textLine.glyphRuns(pos, len);
1665
0
    }
1666
1667
0
    return ret;
1668
0
}
1669
#endif // QT_NO_RAWFONT
1670
1671
/*!
1672
    Returns the position of this text fragment in the document.
1673
*/
1674
int QTextFragment::position() const
1675
0
{
1676
0
    if (!p || !n)
1677
0
        return 0; // ### -1 instead?
1678
1679
0
    return p->fragmentMap().position(n);
1680
0
}
1681
1682
/*!
1683
    Returns the number of characters in the text fragment.
1684
1685
    \sa text()
1686
*/
1687
int QTextFragment::length() const
1688
0
{
1689
0
    if (!p || !n)
1690
0
        return 0;
1691
1692
0
    int len = 0;
1693
0
    int f = n;
1694
0
    while (f != ne) {
1695
0
        len += p->fragmentMap().size(f);
1696
0
        f = p->fragmentMap().next(f);
1697
0
    }
1698
0
    return len;
1699
0
}
1700
1701
/*!
1702
    Returns \c true if the text fragment contains the text at the given
1703
    \a position in the document; otherwise returns \c false.
1704
*/
1705
bool QTextFragment::contains(int position) const
1706
0
{
1707
0
    if (!p || !n)
1708
0
        return false;
1709
0
    int pos = this->position();
1710
0
    return position >= pos && position < pos + length();
1711
0
}
1712
1713
/*!
1714
    Returns the text fragment's character format.
1715
1716
    \sa text()
1717
*/
1718
QTextCharFormat QTextFragment::charFormat() const
1719
0
{
1720
0
    if (!p || !n)
1721
0
        return QTextCharFormat();
1722
0
    const QTextFragmentData *data = p->fragmentMap().fragment(n);
1723
0
    return p->formatCollection()->charFormat(data->format);
1724
0
}
1725
1726
/*!
1727
    Returns an index into the document's internal list of character formats
1728
    for the text fragment's character format.
1729
1730
    \sa QTextDocument::allFormats()
1731
*/
1732
int QTextFragment::charFormatIndex() const
1733
0
{
1734
0
    if (!p || !n)
1735
0
        return -1;
1736
0
    const QTextFragmentData *data = p->fragmentMap().fragment(n);
1737
0
    return data->format;
1738
0
}
1739
1740
/*!
1741
    Returns the text fragment's as plain text.
1742
1743
    \sa length(), charFormat()
1744
*/
1745
QString QTextFragment::text() const
1746
0
{
1747
0
    if (!p || !n)
1748
0
        return QString();
1749
1750
0
    QString result;
1751
0
    QString buffer = p->buffer();
1752
0
    int f = n;
1753
0
    while (f != ne) {
1754
0
        const QTextFragmentData * const frag = p->fragmentMap().fragment(f);
1755
0
        result += QString(buffer.constData() + frag->stringPosition, frag->size_array[0]);
1756
0
        f = p->fragmentMap().next(f);
1757
0
    }
1758
0
    return result;
1759
0
}
1760
1761
QT_END_NAMESPACE
1762
1763
#include "moc_qtextobject.cpp"