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
18QT_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, {Text Object Example}
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*/
56QTextObject::QTextObject(QTextDocument *doc)
57 : QObject(*new QTextObjectPrivate(doc), doc)
58{
59}
60
61/*!
62 \fn QTextObject::QTextObject(QTextObjectPrivate &p, QTextDocument *document)
63
64 \internal
65*/
66QTextObject::QTextObject(QTextObjectPrivate &p, QTextDocument *doc)
67 : QObject(p, doc)
68{
69}
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*/
77QTextObject::~QTextObject()
78{
79}
80
81/*!
82 Returns the text object's format.
83
84 \sa setFormat(), document()
85*/
86QTextFormat QTextObject::format() const
87{
88 Q_D(const QTextObject);
89 return d->pieceTable->formatCollection()->objectFormat(objectIndex: d->objectIndex);
90}
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*/
98int QTextObject::formatIndex() const
99{
100 Q_D(const QTextObject);
101 return d->pieceTable->formatCollection()->objectFormatIndex(objectIndex: d->objectIndex);
102}
103
104
105/*!
106 Sets the text object's \a format.
107
108 \sa format()
109*/
110void QTextObject::setFormat(const QTextFormat &format)
111{
112 Q_D(QTextObject);
113 int idx = d->pieceTable->formatCollection()->indexForFormat(f: format);
114 d->pieceTable->changeObjectFormat(group: this, format: idx);
115}
116
117/*!
118 Returns the object index of this object. This can be used together with
119 QTextFormat::setObjectIndex().
120*/
121int QTextObject::objectIndex() const
122{
123 Q_D(const QTextObject);
124 return d->objectIndex;
125}
126
127/*!
128 Returns the document this object belongs to.
129
130 \sa format()
131*/
132QTextDocument *QTextObject::document() const
133{
134 return static_cast<QTextDocument *>(parent());
135}
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
166void QTextBlockGroupPrivate::markBlocksDirty()
167{
168 for (int i = 0; i < blocks.size(); ++i) {
169 const QTextBlock &block = blocks.at(i);
170 pieceTable->documentChange(from: block.position(), length: block.length());
171 }
172}
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*/
182QTextBlockGroup::QTextBlockGroup(QTextDocument *doc)
183 : QTextObject(*new QTextBlockGroupPrivate(doc), doc)
184{
185}
186
187/*!
188 \internal
189*/
190QTextBlockGroup::QTextBlockGroup(QTextBlockGroupPrivate &p, QTextDocument *doc)
191 : QTextObject(p, doc)
192{
193}
194
195/*!
196 Destroys this block group; the blocks are not deleted, they simply
197 don't belong to this block anymore.
198*/
199QTextBlockGroup::~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*/
210void QTextBlockGroup::blockInserted(const QTextBlock &block)
211{
212 Q_D(QTextBlockGroup);
213 QTextBlockGroupPrivate::BlockList::Iterator it = std::lower_bound(d->blocks.begin(), d->blocks.end(), block);
214 d->blocks.insert(before: it, t: block);
215 d->markBlocksDirty();
216}
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*/
223void QTextBlockGroup::blockRemoved(const QTextBlock &block)
224{
225 Q_D(QTextBlockGroup);
226 d->blocks.removeAll(t: block);
227 d->markBlocksDirty();
228 if (d->blocks.isEmpty()) {
229 QTextDocumentPrivate::get(document: document())->deleteObject(object: this);
230 return;
231 }
232}
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*/
240void QTextBlockGroup::blockFormatChanged(const QTextBlock &)
241{
242}
243
244/*!
245 Returns a (possibly empty) list of all the blocks that are part of
246 the block group.
247*/
248QList<QTextBlock> QTextBlockGroup::blockList() const
249{
250 Q_D(const QTextBlockGroup);
251 return d->blocks;
252}
253
254
255
256QTextFrameLayoutData::~QTextFrameLayoutData()
257{
258}
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*/
372QTextFrame::QTextFrame(QTextDocument *doc)
373 : QTextObject(*new QTextFramePrivate(doc), doc)
374{
375}
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*/
384QTextFrame::~QTextFrame()
385{
386 Q_D(QTextFrame);
387 delete d->layoutData;
388}
389
390/*!
391 \internal
392*/
393QTextFrame::QTextFrame(QTextFramePrivate &p, QTextDocument *doc)
394 : QTextObject(p, doc)
395{
396}
397
398/*!
399 Returns a (possibly empty) list of the frame's child frames.
400
401 \sa parentFrame()
402*/
403QList<QTextFrame *> QTextFrame::childFrames() const
404{
405 Q_D(const QTextFrame);
406 return d->childFrames;
407}
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*/
415QTextFrame *QTextFrame::parentFrame() const
416{
417 Q_D(const QTextFrame);
418 return d->parentFrame;
419}
420
421
422/*!
423 Returns the first cursor position inside the frame.
424
425 \sa lastCursorPosition(), firstPosition(), lastPosition()
426*/
427QTextCursor QTextFrame::firstCursorPosition() const
428{
429 Q_D(const QTextFrame);
430 return QTextCursorPrivate::fromPosition(d: d->pieceTable, pos: firstPosition());
431}
432
433/*!
434 Returns the last cursor position inside the frame.
435
436 \sa firstCursorPosition(), firstPosition(), lastPosition()
437*/
438QTextCursor QTextFrame::lastCursorPosition() const
439{
440 Q_D(const QTextFrame);
441 return QTextCursorPrivate::fromPosition(d: d->pieceTable, pos: lastPosition());
442}
443
444/*!
445 Returns the first document position inside the frame.
446
447 \sa lastPosition(), firstCursorPosition(), lastCursorPosition()
448*/
449int QTextFrame::firstPosition() const
450{
451 Q_D(const QTextFrame);
452 if (!d->fragment_start)
453 return 0;
454 return d->pieceTable->fragmentMap().position(node: d->fragment_start) + 1;
455}
456
457/*!
458 Returns the last document position inside the frame.
459
460 \sa firstPosition(), firstCursorPosition(), lastCursorPosition()
461*/
462int QTextFrame::lastPosition() const
463{
464 Q_D(const QTextFrame);
465 if (!d->fragment_end)
466 return d->pieceTable->length() - 1;
467 return d->pieceTable->fragmentMap().position(node: d->fragment_end);
468}
469
470/*!
471 \internal
472*/
473QTextFrameLayoutData *QTextFrame::layoutData() const
474{
475 Q_D(const QTextFrame);
476 return d->layoutData;
477}
478
479/*!
480 \internal
481*/
482void QTextFrame::setLayoutData(QTextFrameLayoutData *data)
483{
484 Q_D(QTextFrame);
485 delete d->layoutData;
486 d->layoutData = data;
487}
488
489
490
491void QTextFramePrivate::fragmentAdded(QChar type, uint fragment)
492{
493 if (type == QTextBeginningOfFrame) {
494 Q_ASSERT(!fragment_start);
495 fragment_start = fragment;
496 } else if (type == QTextEndOfFrame) {
497 Q_ASSERT(!fragment_end);
498 fragment_end = fragment;
499 } else if (type == QChar::ObjectReplacementCharacter) {
500 Q_ASSERT(!fragment_start);
501 Q_ASSERT(!fragment_end);
502 fragment_start = fragment;
503 fragment_end = fragment;
504 } else {
505 Q_ASSERT(false);
506 }
507}
508
509void QTextFramePrivate::fragmentRemoved(QChar type, uint fragment)
510{
511 Q_UNUSED(fragment); // --release warning
512 if (type == QTextBeginningOfFrame) {
513 Q_ASSERT(fragment_start == fragment);
514 fragment_start = 0;
515 } else if (type == QTextEndOfFrame) {
516 Q_ASSERT(fragment_end == fragment);
517 fragment_end = 0;
518 } else if (type == QChar::ObjectReplacementCharacter) {
519 Q_ASSERT(fragment_start == fragment);
520 Q_ASSERT(fragment_end == fragment);
521 fragment_start = 0;
522 fragment_end = 0;
523 } else {
524 Q_ASSERT(false);
525 }
526 remove_me();
527}
528
529
530void QTextFramePrivate::remove_me()
531{
532 Q_Q(QTextFrame);
533 if (fragment_start == 0 && fragment_end == 0
534 && !parentFrame) {
535 QTextDocumentPrivate::get(document: q->document())->deleteObject(object: q);
536 return;
537 }
538
539 if (!parentFrame)
540 return;
541
542 int index = parentFrame->d_func()->childFrames.indexOf(t: q);
543
544 // iterator over all children and move them to the parent
545 for (int i = 0; i < childFrames.size(); ++i) {
546 QTextFrame *c = childFrames.at(i);
547 parentFrame->d_func()->childFrames.insert(i: index, t: c);
548 c->d_func()->parentFrame = parentFrame;
549 ++index;
550 }
551 Q_ASSERT(parentFrame->d_func()->childFrames.at(index) == q);
552 parentFrame->d_func()->childFrames.removeAt(i: index);
553
554 childFrames.clear();
555 parentFrame = nullptr;
556}
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*/
587QTextFrame::iterator QTextFrame::begin() const
588{
589 const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(object: this);
590 int b = priv->blockMap().findNode(k: firstPosition());
591 int e = priv->blockMap().findNode(k: lastPosition()+1);
592 return iterator(const_cast<QTextFrame *>(this), b, b, e);
593}
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*/
600QTextFrame::iterator QTextFrame::end() const
601{
602 const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(object: this);
603 int b = priv->blockMap().findNode(k: firstPosition());
604 int e = priv->blockMap().findNode(k: lastPosition()+1);
605 return iterator(const_cast<QTextFrame *>(this), e, b, e);
606}
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*/
628QTextBlock QTextFrame::iterator::currentBlock() const
629{
630 if (!f)
631 return QTextBlock();
632 return QTextBlock(QTextDocumentPrivate::get(object: f), cb);
633}
634
635/*!
636 Moves the iterator to the next frame or block.
637
638 \sa currentBlock(), currentFrame()
639*/
640QTextFrame::iterator &QTextFrame::iterator::operator++()
641{
642 const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(object: f);
643 const QTextDocumentPrivate::BlockMap &map = priv->blockMap();
644 if (cf) {
645 int end = cf->lastPosition() + 1;
646 cb = map.findNode(k: end);
647 cf = nullptr;
648 } else if (cb) {
649 cb = map.next(n: cb);
650 if (cb == e)
651 return *this;
652
653 if (!f->d_func()->childFrames.isEmpty()) {
654 int pos = map.position(node: cb);
655 // check if we entered a frame
656 QTextDocumentPrivate::FragmentIterator frag = priv->find(pos: pos-1);
657 if (priv->buffer().at(i: frag->stringPosition) != QChar::ParagraphSeparator) {
658 QTextFrame *nf = qobject_cast<QTextFrame *>(object: priv->objectForFormat(formatIndex: frag->format));
659 if (nf) {
660 if (priv->buffer().at(i: frag->stringPosition) == QTextBeginningOfFrame && nf != f) {
661 cf = nf;
662 cb = 0;
663 } else {
664 Q_ASSERT(priv->buffer().at(frag->stringPosition) != QTextEndOfFrame);
665 }
666 }
667 }
668 }
669 }
670 return *this;
671}
672
673/*!
674 Moves the iterator to the previous frame or block.
675
676 \sa currentBlock(), currentFrame()
677*/
678QTextFrame::iterator &QTextFrame::iterator::operator--()
679{
680 const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(object: f);
681 const QTextDocumentPrivate::BlockMap &map = priv->blockMap();
682 if (cf) {
683 int start = cf->firstPosition() - 1;
684 cb = map.findNode(k: start);
685 cf = nullptr;
686 } else {
687 if (cb == b)
688 goto end;
689 if (cb != e) {
690 int pos = map.position(node: cb);
691 // check if we have to enter a frame
692 QTextDocumentPrivate::FragmentIterator frag = priv->find(pos: pos-1);
693 if (priv->buffer().at(i: frag->stringPosition) != QChar::ParagraphSeparator) {
694 QTextFrame *pf = qobject_cast<QTextFrame *>(object: priv->objectForFormat(formatIndex: frag->format));
695 if (pf) {
696 if (priv->buffer().at(i: frag->stringPosition) == QTextBeginningOfFrame) {
697 Q_ASSERT(pf == f);
698 } else if (priv->buffer().at(i: frag->stringPosition) == QTextEndOfFrame) {
699 Q_ASSERT(pf != f);
700 cf = pf;
701 cb = 0;
702 goto end;
703 }
704 }
705 }
706 }
707 cb = map.previous(n: cb);
708 }
709 end:
710 return *this;
711}
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*/
740QTextBlockUserData::~QTextBlockUserData()
741{
742}
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
785
786 \sa QTextBlockFormat, QTextCharFormat, QTextFragment
787 */
788
789/*!
790 \fn QTextBlock::QTextBlock(QTextDocumentPrivate *priv, int b)
791
792 \internal
793*/
794
795/*!
796 \fn QTextBlock::QTextBlock()
797
798 \internal
799*/
800
801/*!
802 \fn QTextBlock::QTextBlock(const QTextBlock &other)
803
804 Copies the \a other text block's attributes to this text block.
805*/
806
807/*!
808 \fn bool QTextBlock::isValid() const
809
810 Returns \c true if this text block is valid; otherwise returns \c false.
811*/
812
813bool QTextBlock::isValid() const
814{
815 return p != nullptr && p->blockMap().isValid(n);
816}
817
818/*!
819 \fn QTextBlock &QTextBlock::operator=(const QTextBlock &other)
820
821 Assigns the \a other text block to this text block.
822*/
823
824/*!
825 \fn bool QTextBlock::operator==(const QTextBlock &other) const
826
827 Returns \c true if this text block is the same as the \a other text
828 block.
829*/
830
831/*!
832 \fn bool QTextBlock::operator!=(const QTextBlock &other) const
833
834 Returns \c true if this text block is different from the \a other
835 text block.
836*/
837
838/*!
839 \fn bool QTextBlock::operator<(const QTextBlock &other) const
840
841 Returns \c true if this text block occurs before the \a other text
842 block in the document.
843*/
844
845/*!
846 \class QTextBlock::iterator
847 \reentrant
848
849 \brief The QTextBlock::iterator class provides an iterator for reading
850 the contents of a QTextBlock.
851 \inmodule QtGui
852
853 \ingroup richtext-processing
854
855 A block consists of a sequence of text fragments. This class provides
856 a way to iterate over these, and read their contents. It does not provide
857 a way to modify the internal structure or contents of the block.
858
859 An iterator can be constructed and used to access the fragments within
860 a text block in the following way:
861
862 \snippet textblock-fragments/xmlwriter.cpp 4
863 \snippet textblock-fragments/xmlwriter.cpp 7
864
865 \sa QTextFragment
866*/
867
868/*!
869 \typedef QTextBlock::Iterator
870
871 Qt-style synonym for QTextBlock::iterator.
872*/
873
874/*!
875 \fn QTextBlock::iterator::iterator()
876
877 Constructs an iterator for this text block.
878*/
879
880/*!
881 \fn bool QTextBlock::iterator::atEnd() const
882
883 Returns \c true if the current item is the last item in the text block.
884*/
885
886/*!
887 \fn bool QTextBlock::iterator::operator==(const iterator &other) const
888
889 Returns true if this iterator is the same as the \a other iterator;
890 otherwise returns \c false.
891*/
892
893/*!
894 \fn bool QTextBlock::iterator::operator!=(const iterator &other) const
895
896 Returns true if this iterator is different from the \a other iterator;
897 otherwise returns \c false.
898*/
899
900/*!
901 \fn QTextBlock::iterator QTextBlock::iterator::operator++(int)
902
903 The postfix ++ operator (\c{i++}) advances the iterator to the
904 next item in the text block and returns an iterator to the old current
905 item.
906*/
907
908/*!
909 \fn QTextBlock::iterator QTextBlock::iterator::operator--(int)
910
911 The postfix -- operator (\c{i--}) makes the preceding item current and
912 returns an iterator to the old current item.
913*/
914
915/*!
916 \fn int QTextBlock::fragmentIndex() const
917
918 \internal
919*/
920
921/*!
922 Returns the index of the block's first character within the document.
923 */
924int QTextBlock::position() const
925{
926 if (!p || !n)
927 return 0;
928
929 return p->blockMap().position(node: n);
930}
931
932/*!
933 Returns the length of the block in characters.
934
935 \note The length returned includes all formatting characters,
936 for example, newline.
937
938 \sa text(), charFormat(), blockFormat()
939 */
940int QTextBlock::length() const
941{
942 if (!p || !n)
943 return 0;
944
945 return p->blockMap().size(node: n);
946}
947
948/*!
949 Returns \c true if the given \a position is located within the text
950 block; otherwise returns \c false.
951 */
952bool QTextBlock::contains(int position) const
953{
954 if (!p || !n)
955 return false;
956
957 int pos = p->blockMap().position(node: n);
958 int len = p->blockMap().size(node: n);
959 return position >= pos && position < pos + len;
960}
961
962/*!
963 Returns the QTextLayout that is used to lay out and display the
964 block's contents.
965
966 Note that the returned QTextLayout object can only be modified from the
967 documentChanged implementation of a QAbstractTextDocumentLayout subclass.
968 Any changes applied from the outside cause undefined behavior.
969
970 \sa clearLayout()
971 */
972QTextLayout *QTextBlock::layout() const
973{
974 if (!p || !n)
975 return nullptr;
976
977 const QTextBlockData *b = p->blockMap().fragment(index: n);
978 if (!b->layout)
979 b->layout = new QTextLayout(*this);
980 return b->layout;
981}
982
983/*!
984 \since 4.4
985 Clears the QTextLayout that is used to lay out and display the
986 block's contents.
987
988 \sa layout()
989 */
990void QTextBlock::clearLayout()
991{
992 if (!p || !n)
993 return;
994
995 const QTextBlockData *b = p->blockMap().fragment(index: n);
996 if (b->layout)
997 b->layout->clearLayout();
998}
999
1000/*!
1001 Returns the QTextBlockFormat that describes block-specific properties.
1002
1003 \sa charFormat()
1004 */
1005QTextBlockFormat QTextBlock::blockFormat() const
1006{
1007 if (!p || !n)
1008 return QTextFormat().toBlockFormat();
1009
1010 return p->formatCollection()->blockFormat(index: p->blockMap().fragment(index: n)->format);
1011}
1012
1013/*!
1014 Returns an index into the document's internal list of block formats
1015 for the text block's format.
1016
1017 \sa QTextDocument::allFormats()
1018*/
1019int QTextBlock::blockFormatIndex() const
1020{
1021 if (!p || !n)
1022 return -1;
1023
1024 return p->blockMap().fragment(index: n)->format;
1025}
1026
1027/*!
1028 Returns the QTextCharFormat that describes the block's character
1029 format. The block's character format is used when inserting text into
1030 an empty block.
1031
1032 \sa blockFormat()
1033 */
1034QTextCharFormat QTextBlock::charFormat() const
1035{
1036 if (!p || !n)
1037 return QTextFormat().toCharFormat();
1038
1039 return p->formatCollection()->charFormat(index: charFormatIndex());
1040}
1041
1042/*!
1043 Returns an index into the document's internal list of character formats
1044 for the text block's character format.
1045
1046 \sa QTextDocument::allFormats()
1047*/
1048int QTextBlock::charFormatIndex() const
1049{
1050 if (!p || !n)
1051 return -1;
1052
1053 return p->blockCharFormatIndex(node: n);
1054}
1055
1056/*!
1057 \since 4.7
1058
1059 Returns the resolved text direction.
1060
1061 If the block has no explicit direction set, it will resolve the
1062 direction from the blocks content. Returns either Qt::LeftToRight
1063 or Qt::RightToLeft.
1064
1065 \sa QTextFormat::layoutDirection(), QString::isRightToLeft(), Qt::LayoutDirection
1066*/
1067Qt::LayoutDirection QTextBlock::textDirection() const
1068{
1069 Qt::LayoutDirection dir = blockFormat().layoutDirection();
1070 if (dir != Qt::LayoutDirectionAuto)
1071 return dir;
1072
1073 dir = p->defaultTextOption.textDirection();
1074 if (dir != Qt::LayoutDirectionAuto)
1075 return dir;
1076
1077 const QString buffer = p->buffer();
1078
1079 const int pos = position();
1080 QTextDocumentPrivate::FragmentIterator it = p->find(pos);
1081 QTextDocumentPrivate::FragmentIterator end = p->find(pos: pos + length() - 1); // -1 to omit the block separator char
1082 for (; it != end; ++it) {
1083 const QTextFragmentData * const frag = it.value();
1084 const QChar *p = buffer.constData() + frag->stringPosition;
1085 const QChar * const end = p + frag->size_array[0];
1086 while (p < end) {
1087 uint ucs4 = p->unicode();
1088 if (QChar::isHighSurrogate(ucs4) && p + 1 < end) {
1089 ushort low = p[1].unicode();
1090 if (QChar::isLowSurrogate(ucs4: low)) {
1091 ucs4 = QChar::surrogateToUcs4(high: ucs4, low);
1092 ++p;
1093 }
1094 }
1095 switch (QChar::direction(ucs4)) {
1096 case QChar::DirL:
1097 return Qt::LeftToRight;
1098 case QChar::DirR:
1099 case QChar::DirAL:
1100 return Qt::RightToLeft;
1101 default:
1102 break;
1103 }
1104 ++p;
1105 }
1106 }
1107 return Qt::LeftToRight;
1108}
1109
1110/*!
1111 Returns the block's contents as plain text.
1112
1113 \sa length(), charFormat(), blockFormat()
1114 */
1115QString QTextBlock::text() const
1116{
1117 if (!p || !n)
1118 return QString();
1119
1120 const QString buffer = p->buffer();
1121 QString text;
1122 text.reserve(asize: length());
1123
1124 const int pos = position();
1125 QTextDocumentPrivate::FragmentIterator it = p->find(pos);
1126 QTextDocumentPrivate::FragmentIterator end = p->find(pos: pos + length() - 1); // -1 to omit the block separator char
1127 for (; it != end; ++it) {
1128 const QTextFragmentData * const frag = it.value();
1129 text += QStringView(buffer.constData() + frag->stringPosition, frag->size_array[0]);
1130 }
1131
1132 return text;
1133}
1134
1135/*!
1136 \since 5.3
1137
1138 Returns the block's text format options as a list of continuous ranges
1139 of QTextCharFormat. The range's character format is used when inserting text
1140 within the range boundaries.
1141
1142 \sa charFormat(), blockFormat()
1143*/
1144QList<QTextLayout::FormatRange> QTextBlock::textFormats() const
1145{
1146 QList<QTextLayout::FormatRange> formats;
1147 if (!p || !n)
1148 return formats;
1149
1150 const QTextFormatCollection *formatCollection = p->formatCollection();
1151
1152 int start = 0;
1153 int cur = start;
1154 int format = -1;
1155
1156 const int pos = position();
1157 QTextDocumentPrivate::FragmentIterator it = p->find(pos);
1158 QTextDocumentPrivate::FragmentIterator end = p->find(pos: pos + length() - 1); // -1 to omit the block separator char
1159 for (; it != end; ++it) {
1160 const QTextFragmentData * const frag = it.value();
1161 if (format != it.value()->format) {
1162 if (cur - start > 0) {
1163 QTextLayout::FormatRange range;
1164 range.start = start;
1165 range.length = cur - start;
1166 range.format = formatCollection->charFormat(index: format);
1167 formats.append(t: range);
1168 }
1169
1170 format = frag->format;
1171 start = cur;
1172 }
1173 cur += frag->size_array[0];
1174 }
1175 if (cur - start > 0) {
1176 QTextLayout::FormatRange range;
1177 range.start = start;
1178 range.length = cur - start;
1179 range.format = formatCollection->charFormat(index: format);
1180 formats.append(t: range);
1181 }
1182
1183 return formats;
1184}
1185
1186/*!
1187 Returns the text document this text block belongs to, or \nullptr
1188 if the text block does not belong to any document.
1189*/
1190const QTextDocument *QTextBlock::document() const
1191{
1192 return p ? p->document() : nullptr;
1193}
1194
1195/*!
1196 If the block represents a list item, returns the list that the item belongs
1197 to; otherwise returns \nullptr.
1198*/
1199QTextList *QTextBlock::textList() const
1200{
1201 if (!isValid())
1202 return nullptr;
1203
1204 const QTextBlockFormat fmt = blockFormat();
1205 QTextObject *obj = p->document()->objectForFormat(fmt);
1206 return qobject_cast<QTextList *>(object: obj);
1207}
1208
1209/*!
1210 \since 4.1
1211
1212 Returns a pointer to a QTextBlockUserData object,
1213 if one has been set with setUserData(), or \nullptr.
1214*/
1215QTextBlockUserData *QTextBlock::userData() const
1216{
1217 if (!p || !n)
1218 return nullptr;
1219
1220 const QTextBlockData *b = p->blockMap().fragment(index: n);
1221 return b->userData;
1222}
1223
1224/*!
1225 \since 4.1
1226
1227 Attaches the given \a data object to the text block.
1228
1229 QTextBlockUserData can be used to store custom settings. The
1230 ownership is passed to the underlying text document, i.e. the
1231 provided QTextBlockUserData object will be deleted if the
1232 corresponding text block gets deleted. The user data object is
1233 not stored in the undo history, so it will not be available after
1234 undoing the deletion of a text block.
1235
1236 For example, if you write a programming editor in an IDE, you may
1237 want to let your user set breakpoints visually in your code for an
1238 integrated debugger. In a programming editor a line of text
1239 usually corresponds to one QTextBlock. The QTextBlockUserData
1240 interface allows the developer to store data for each QTextBlock,
1241 like for example in which lines of the source code the user has a
1242 breakpoint set. Of course this could also be stored externally,
1243 but by storing it inside the QTextDocument, it will for example be
1244 automatically deleted when the user deletes the associated
1245 line. It's really just a way to store custom information in the
1246 QTextDocument without using custom properties in QTextFormat which
1247 would affect the undo/redo stack.
1248*/
1249void QTextBlock::setUserData(QTextBlockUserData *data)
1250{
1251 if (!p || !n)
1252 return;
1253
1254 const QTextBlockData *b = p->blockMap().fragment(index: n);
1255 if (data != b->userData)
1256 delete b->userData;
1257 b->userData = data;
1258}
1259
1260/*!
1261 \since 4.1
1262
1263 Returns the integer value previously set with setUserState() or -1.
1264*/
1265int QTextBlock::userState() const
1266{
1267 if (!p || !n)
1268 return -1;
1269
1270 const QTextBlockData *b = p->blockMap().fragment(index: n);
1271 return b->userState;
1272}
1273
1274/*!
1275 \since 4.1
1276
1277 Stores the specified \a state integer value in the text block. This may be
1278 useful for example in a syntax highlighter to store a text parsing state.
1279*/
1280void QTextBlock::setUserState(int state)
1281{
1282 if (!p || !n)
1283 return;
1284
1285 const QTextBlockData *b = p->blockMap().fragment(index: n);
1286 b->userState = state;
1287}
1288
1289/*!
1290 \since 4.4
1291
1292 Returns the blocks revision.
1293
1294 \sa setRevision(), QTextDocument::revision()
1295*/
1296int QTextBlock::revision() const
1297{
1298 if (!p || !n)
1299 return -1;
1300
1301 const QTextBlockData *b = p->blockMap().fragment(index: n);
1302 return b->revision;
1303}
1304
1305/*!
1306 \since 4.4
1307
1308 Sets a blocks revision to \a rev.
1309
1310 \sa revision(), QTextDocument::revision()
1311*/
1312void QTextBlock::setRevision(int rev)
1313{
1314 if (!p || !n)
1315 return;
1316
1317 const QTextBlockData *b = p->blockMap().fragment(index: n);
1318 b->revision = rev;
1319}
1320
1321/*!
1322 \since 4.4
1323
1324 Returns \c true if the block is visible; otherwise returns \c false.
1325
1326 \sa setVisible()
1327*/
1328bool QTextBlock::isVisible() const
1329{
1330 if (!p || !n)
1331 return true;
1332
1333 const QTextBlockData *b = p->blockMap().fragment(index: n);
1334 return !b->hidden;
1335}
1336
1337/*!
1338 \since 4.4
1339
1340 Sets the block's visibility to \a visible.
1341
1342 \sa isVisible()
1343*/
1344void QTextBlock::setVisible(bool visible)
1345{
1346 if (!p || !n)
1347 return;
1348
1349 const QTextBlockData *b = p->blockMap().fragment(index: n);
1350 b->hidden = !visible;
1351}
1352
1353
1354/*!
1355\since 4.4
1356
1357 Returns the number of this block, or -1 if the block is invalid.
1358
1359 \sa QTextCursor::blockNumber()
1360
1361*/
1362int QTextBlock::blockNumber() const
1363{
1364 if (!p || !n)
1365 return -1;
1366 return p->blockMap().position(node: n, field: 1);
1367}
1368
1369/*!
1370\since 4.5
1371
1372 Returns the first line number of this block, or -1 if the block is invalid.
1373 Unless the layout supports it, the line number is identical to the block number.
1374
1375 \sa QTextBlock::blockNumber()
1376
1377*/
1378int QTextBlock::firstLineNumber() const
1379{
1380 if (!p || !n)
1381 return -1;
1382 return p->blockMap().position(node: n, field: 2);
1383}
1384
1385
1386/*!
1387\since 4.5
1388
1389Sets the line count to \a count.
1390
1391\sa lineCount()
1392*/
1393void QTextBlock::setLineCount(int count)
1394{
1395 if (!p || !n)
1396 return;
1397 p->blockMap().setSize(node: n, new_size: count, field: 2);
1398}
1399/*!
1400\since 4.5
1401
1402Returns the line count. Not all document layouts support this feature.
1403
1404\sa setLineCount()
1405 */
1406int QTextBlock::lineCount() const
1407{
1408 if (!p || !n)
1409 return -1;
1410 return p->blockMap().size(node: n, field: 2);
1411}
1412
1413
1414/*!
1415 Returns a text block iterator pointing to the beginning of the
1416 text block.
1417
1418 \sa end()
1419*/
1420QTextBlock::iterator QTextBlock::begin() const
1421{
1422 if (!p || !n)
1423 return iterator();
1424
1425 int pos = position();
1426 int len = length() - 1; // exclude the fragment that holds the paragraph separator
1427 int b = p->fragmentMap().findNode(k: pos);
1428 int e = p->fragmentMap().findNode(k: pos+len);
1429 return iterator(p, b, e, b);
1430}
1431
1432/*!
1433 Returns a text block iterator pointing to the end of the text
1434 block.
1435
1436 \sa begin(), next(), previous()
1437*/
1438QTextBlock::iterator QTextBlock::end() const
1439{
1440 if (!p || !n)
1441 return iterator();
1442
1443 int pos = position();
1444 int len = length() - 1; // exclude the fragment that holds the paragraph separator
1445 int b = p->fragmentMap().findNode(k: pos);
1446 int e = p->fragmentMap().findNode(k: pos+len);
1447 return iterator(p, b, e, e);
1448}
1449
1450
1451/*!
1452 Returns the text block in the document after this block, or an empty
1453 text block if this is the last one.
1454
1455 Note that the next block may be in a different frame or table to this block.
1456
1457 \sa previous(), begin(), end()
1458*/
1459QTextBlock QTextBlock::next() const
1460{
1461 if (!isValid())
1462 return QTextBlock();
1463
1464 return QTextBlock(p, p->blockMap().next(n));
1465}
1466
1467/*!
1468 Returns the text block in the document before this block, or an empty text
1469 block if this is the first one.
1470
1471 Note that the previous block may be in a different frame or table to this block.
1472
1473 \sa next(), begin(), end()
1474*/
1475QTextBlock QTextBlock::previous() const
1476{
1477 if (!p)
1478 return QTextBlock();
1479
1480 return QTextBlock(p, p->blockMap().previous(n));
1481}
1482
1483
1484/*!
1485 Returns the text fragment the iterator currently points to.
1486*/
1487QTextFragment QTextBlock::iterator::fragment() const
1488{
1489 int ne = n;
1490 int formatIndex = p->fragmentMap().fragment(index: n)->format;
1491 do {
1492 ne = p->fragmentMap().next(n: ne);
1493 } while (ne != e && p->fragmentMap().fragment(index: ne)->format == formatIndex);
1494 return QTextFragment(p, n, ne);
1495}
1496
1497/*!
1498 The prefix ++ operator (\c{++i}) advances the iterator to the
1499 next item in the hash and returns an iterator to the new current
1500 item.
1501*/
1502
1503QTextBlock::iterator &QTextBlock::iterator::operator++()
1504{
1505 int ne = n;
1506 int formatIndex = p->fragmentMap().fragment(index: n)->format;
1507 do {
1508 ne = p->fragmentMap().next(n: ne);
1509 } while (ne != e && p->fragmentMap().fragment(index: ne)->format == formatIndex);
1510 n = ne;
1511 return *this;
1512}
1513
1514/*!
1515 The prefix -- operator (\c{--i}) makes the preceding item
1516 current and returns an iterator pointing to the new current item.
1517*/
1518
1519QTextBlock::iterator &QTextBlock::iterator::operator--()
1520{
1521 n = p->fragmentMap().previous(n);
1522
1523 if (n == b)
1524 return *this;
1525
1526 int formatIndex = p->fragmentMap().fragment(index: n)->format;
1527 int last = n;
1528
1529 while (n != b && p->fragmentMap().fragment(index: n)->format != formatIndex) {
1530 last = n;
1531 n = p->fragmentMap().previous(n);
1532 }
1533
1534 n = last;
1535 return *this;
1536}
1537
1538
1539/*!
1540 \class QTextFragment
1541 \reentrant
1542
1543 \brief The QTextFragment class holds a piece of text in a
1544 QTextDocument with a single QTextCharFormat.
1545 \inmodule QtGui
1546
1547 \ingroup richtext-processing
1548
1549 A text fragment describes a piece of text that is stored with a single
1550 character format. Text in which the character format changes can be
1551 represented by sequences of text fragments with different formats.
1552
1553 If the user edits the text in a fragment and introduces a different
1554 character format, the fragment's text will be split at each point where
1555 the format changes, and new fragments will be created.
1556 For example, changing the style of some text in the middle of a
1557 sentence will cause the fragment to be broken into three separate fragments:
1558 the first and third with the same format as before, and the second with
1559 the new style. The first fragment will contain the text from the beginning
1560 of the sentence, the second will contain the text from the middle, and the
1561 third takes the text from the end of the sentence.
1562
1563 \image qtextfragment-split.png
1564
1565 A fragment's text and character format can be obtained with the text()
1566 and charFormat() functions. The length() function gives the length of
1567 the text in the fragment. position() gives the position in the document
1568 of the start of the fragment. To determine whether the fragment contains
1569 a particular position within the document, use the contains() function.
1570
1571 \sa QTextDocument, {Rich Text Document Structure}
1572*/
1573
1574/*!
1575 \fn QTextFragment::QTextFragment(const QTextDocumentPrivate *priv, int f, int fe)
1576 \internal
1577*/
1578
1579/*!
1580 \fn QTextFragment::QTextFragment()
1581
1582 Creates a new empty text fragment.
1583*/
1584
1585/*!
1586 \fn QTextFragment::QTextFragment(const QTextFragment &other)
1587
1588 Copies the content (text and format) of the \a other text fragment
1589 to this text fragment.
1590*/
1591
1592/*!
1593 \fn QTextFragment &QTextFragment::operator=(const QTextFragment
1594 &other)
1595
1596 Assigns the content (text and format) of the \a other text fragment
1597 to this text fragment.
1598*/
1599
1600/*!
1601 \fn bool QTextFragment::isValid() const
1602
1603 Returns \c true if this is a valid text fragment (i.e. has a valid
1604 position in a document); otherwise returns \c false.
1605*/
1606
1607/*!
1608 \fn bool QTextFragment::operator==(const QTextFragment &other) const
1609
1610 Returns \c true if this text fragment is the same (at the same
1611 position) as the \a other text fragment; otherwise returns \c false.
1612*/
1613
1614/*!
1615 \fn bool QTextFragment::operator!=(const QTextFragment &other) const
1616
1617 Returns \c true if this text fragment is different (at a different
1618 position) from the \a other text fragment; otherwise returns
1619 false.
1620*/
1621
1622/*!
1623 \fn bool QTextFragment::operator<(const QTextFragment &other) const
1624
1625 Returns \c true if this text fragment appears earlier in the document
1626 than the \a other text fragment; otherwise returns \c false.
1627*/
1628
1629/*!
1630 Returns the glyphs corresponding to \a len characters of this text fragment starting at
1631 position \a pos. The positions of the glyphs are relative to the position of the QTextBlock's
1632 layout.
1633
1634 If \a pos is less than zero, it will default to the start of the QTextFragment. If \a len
1635 is less than zero, it will default to the length of the fragment.
1636
1637 \sa QGlyphRun, QTextBlock::layout(), QTextLayout::position(), QPainter::drawGlyphRun()
1638*/
1639#if !defined(QT_NO_RAWFONT)
1640QList<QGlyphRun> QTextFragment::glyphRuns(int pos, int len) const
1641{
1642 if (!p || !n)
1643 return QList<QGlyphRun>();
1644
1645 int blockNode = p->blockMap().findNode(k: position());
1646
1647 const QTextBlockData *blockData = p->blockMap().fragment(index: blockNode);
1648 QTextLayout *layout = blockData->layout;
1649
1650 int blockPosition = p->blockMap().position(node: blockNode);
1651 if (pos < 0)
1652 pos = position() - blockPosition;
1653 if (len < 0)
1654 len = length();
1655 if (len == 0)
1656 return QList<QGlyphRun>();
1657
1658 QList<QGlyphRun> ret;
1659 for (int i=0; i<layout->lineCount(); ++i) {
1660 QTextLine textLine = layout->lineAt(i);
1661 ret += textLine.glyphRuns(from: pos, length: len);
1662 }
1663
1664 return ret;
1665}
1666#endif // QT_NO_RAWFONT
1667
1668/*!
1669 Returns the position of this text fragment in the document.
1670*/
1671int QTextFragment::position() const
1672{
1673 if (!p || !n)
1674 return 0; // ### -1 instead?
1675
1676 return p->fragmentMap().position(node: n);
1677}
1678
1679/*!
1680 Returns the number of characters in the text fragment.
1681
1682 \sa text()
1683*/
1684int QTextFragment::length() const
1685{
1686 if (!p || !n)
1687 return 0;
1688
1689 int len = 0;
1690 int f = n;
1691 while (f != ne) {
1692 len += p->fragmentMap().size(node: f);
1693 f = p->fragmentMap().next(n: f);
1694 }
1695 return len;
1696}
1697
1698/*!
1699 Returns \c true if the text fragment contains the text at the given
1700 \a position in the document; otherwise returns \c false.
1701*/
1702bool QTextFragment::contains(int position) const
1703{
1704 if (!p || !n)
1705 return false;
1706 int pos = this->position();
1707 return position >= pos && position < pos + length();
1708}
1709
1710/*!
1711 Returns the text fragment's character format.
1712
1713 \sa text()
1714*/
1715QTextCharFormat QTextFragment::charFormat() const
1716{
1717 if (!p || !n)
1718 return QTextCharFormat();
1719 const QTextFragmentData *data = p->fragmentMap().fragment(index: n);
1720 return p->formatCollection()->charFormat(index: data->format);
1721}
1722
1723/*!
1724 Returns an index into the document's internal list of character formats
1725 for the text fragment's character format.
1726
1727 \sa QTextDocument::allFormats()
1728*/
1729int QTextFragment::charFormatIndex() const
1730{
1731 if (!p || !n)
1732 return -1;
1733 const QTextFragmentData *data = p->fragmentMap().fragment(index: n);
1734 return data->format;
1735}
1736
1737/*!
1738 Returns the text fragment's as plain text.
1739
1740 \sa length(), charFormat()
1741*/
1742QString QTextFragment::text() const
1743{
1744 if (!p || !n)
1745 return QString();
1746
1747 QString result;
1748 QString buffer = p->buffer();
1749 int f = n;
1750 while (f != ne) {
1751 const QTextFragmentData * const frag = p->fragmentMap().fragment(index: f);
1752 result += QString(buffer.constData() + frag->stringPosition, frag->size_array[0]);
1753 f = p->fragmentMap().next(n: f);
1754 }
1755 return result;
1756}
1757
1758QT_END_NAMESPACE
1759
1760#include "moc_qtextobject.cpp"
1761

source code of qtbase/src/gui/text/qtextobject.cpp