Coverage Report

Created: 2025-11-16 07:45

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