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
54QT_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*/
92QTextObject::QTextObject(QTextDocument *doc)
93 : QObject(*new QTextObjectPrivate(doc), doc)
94{
95}
96
97/*!
98 \fn QTextObject::QTextObject(QTextObjectPrivate &p, QTextDocument *document)
99
100 \internal
101*/
102QTextObject::QTextObject(QTextObjectPrivate &p, QTextDocument *doc)
103 : QObject(p, doc)
104{
105}
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*/
113QTextObject::~QTextObject()
114{
115}
116
117/*!
118 Returns the text object's format.
119
120 \sa setFormat(), document()
121*/
122QTextFormat QTextObject::format() const
123{
124 Q_D(const QTextObject);
125 return d->pieceTable->formatCollection()->objectFormat(objectIndex: d->objectIndex);
126}
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*/
134int QTextObject::formatIndex() const
135{
136 Q_D(const QTextObject);
137 return d->pieceTable->formatCollection()->objectFormatIndex(objectIndex: d->objectIndex);
138}
139
140
141/*!
142 Sets the text object's \a format.
143
144 \sa format()
145*/
146void QTextObject::setFormat(const QTextFormat &format)
147{
148 Q_D(QTextObject);
149 int idx = d->pieceTable->formatCollection()->indexForFormat(f: format);
150 d->pieceTable->changeObjectFormat(group: this, format: idx);
151}
152
153/*!
154 Returns the object index of this object. This can be used together with
155 QTextFormat::setObjectIndex().
156*/
157int QTextObject::objectIndex() const
158{
159 Q_D(const QTextObject);
160 return d->objectIndex;
161}
162
163/*!
164 Returns the document this object belongs to.
165
166 \sa format()
167*/
168QTextDocument *QTextObject::document() const
169{
170 return static_cast<QTextDocument *>(parent());
171}
172
173/*!
174 \internal
175*/
176QTextDocumentPrivate *QTextObject::docHandle() const
177{
178 return static_cast<const QTextDocument *>(parent())->docHandle();
179}
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
210void QTextBlockGroupPrivate::markBlocksDirty()
211{
212 for (int i = 0; i < blocks.count(); ++i) {
213 const QTextBlock &block = blocks.at(i);
214 pieceTable->documentChange(from: block.position(), length: block.length());
215 }
216}
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*/
226QTextBlockGroup::QTextBlockGroup(QTextDocument *doc)
227 : QTextObject(*new QTextBlockGroupPrivate(doc), doc)
228{
229}
230
231/*!
232 \internal
233*/
234QTextBlockGroup::QTextBlockGroup(QTextBlockGroupPrivate &p, QTextDocument *doc)
235 : QTextObject(p, doc)
236{
237}
238
239/*!
240 Destroys this block group; the blocks are not deleted, they simply
241 don't belong to this block anymore.
242*/
243QTextBlockGroup::~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*/
254void QTextBlockGroup::blockInserted(const QTextBlock &block)
255{
256 Q_D(QTextBlockGroup);
257 QTextBlockGroupPrivate::BlockList::Iterator it = std::lower_bound(first: d->blocks.begin(), last: d->blocks.end(), val: block);
258 d->blocks.insert(before: it, t: block);
259 d->markBlocksDirty();
260}
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*/
267void QTextBlockGroup::blockRemoved(const QTextBlock &block)
268{
269 Q_D(QTextBlockGroup);
270 d->blocks.removeAll(t: block);
271 d->markBlocksDirty();
272 if (d->blocks.isEmpty()) {
273 document()->docHandle()->deleteObject(object: this);
274 return;
275 }
276}
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*/
284void QTextBlockGroup::blockFormatChanged(const QTextBlock &)
285{
286}
287
288/*!
289 Returns a (possibly empty) list of all the blocks that are part of
290 the block group.
291*/
292QList<QTextBlock> QTextBlockGroup::blockList() const
293{
294 Q_D(const QTextBlockGroup);
295 return d->blocks;
296}
297
298
299
300QTextFrameLayoutData::~QTextFrameLayoutData()
301{
302}
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*/
416QTextFrame::QTextFrame(QTextDocument *doc)
417 : QTextObject(*new QTextFramePrivate(doc), doc)
418{
419}
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*/
428QTextFrame::~QTextFrame()
429{
430 Q_D(QTextFrame);
431 delete d->layoutData;
432}
433
434/*!
435 \internal
436*/
437QTextFrame::QTextFrame(QTextFramePrivate &p, QTextDocument *doc)
438 : QTextObject(p, doc)
439{
440}
441
442/*!
443 Returns a (possibly empty) list of the frame's child frames.
444
445 \sa parentFrame()
446*/
447QList<QTextFrame *> QTextFrame::childFrames() const
448{
449 Q_D(const QTextFrame);
450 return d->childFrames;
451}
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*/
459QTextFrame *QTextFrame::parentFrame() const
460{
461 Q_D(const QTextFrame);
462 return d->parentFrame;
463}
464
465
466/*!
467 Returns the first cursor position inside the frame.
468
469 \sa lastCursorPosition(), firstPosition(), lastPosition()
470*/
471QTextCursor QTextFrame::firstCursorPosition() const
472{
473 Q_D(const QTextFrame);
474 return QTextCursorPrivate::fromPosition(d: d->pieceTable, pos: firstPosition());
475}
476
477/*!
478 Returns the last cursor position inside the frame.
479
480 \sa firstCursorPosition(), firstPosition(), lastPosition()
481*/
482QTextCursor QTextFrame::lastCursorPosition() const
483{
484 Q_D(const QTextFrame);
485 return QTextCursorPrivate::fromPosition(d: d->pieceTable, pos: lastPosition());
486}
487
488/*!
489 Returns the first document position inside the frame.
490
491 \sa lastPosition(), firstCursorPosition(), lastCursorPosition()
492*/
493int QTextFrame::firstPosition() const
494{
495 Q_D(const QTextFrame);
496 if (!d->fragment_start)
497 return 0;
498 return d->pieceTable->fragmentMap().position(node: d->fragment_start) + 1;
499}
500
501/*!
502 Returns the last document position inside the frame.
503
504 \sa firstPosition(), firstCursorPosition(), lastCursorPosition()
505*/
506int QTextFrame::lastPosition() const
507{
508 Q_D(const QTextFrame);
509 if (!d->fragment_end)
510 return d->pieceTable->length() - 1;
511 return d->pieceTable->fragmentMap().position(node: d->fragment_end);
512}
513
514/*!
515 \internal
516*/
517QTextFrameLayoutData *QTextFrame::layoutData() const
518{
519 Q_D(const QTextFrame);
520 return d->layoutData;
521}
522
523/*!
524 \internal
525*/
526void QTextFrame::setLayoutData(QTextFrameLayoutData *data)
527{
528 Q_D(QTextFrame);
529 delete d->layoutData;
530 d->layoutData = data;
531}
532
533
534
535void 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
553void 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
574void QTextFramePrivate::remove_me()
575{
576 Q_Q(QTextFrame);
577 if (fragment_start == 0 && fragment_end == 0
578 && !parentFrame) {
579 q->document()->docHandle()->deleteObject(object: q);
580 return;
581 }
582
583 if (!parentFrame)
584 return;
585
586 int index = parentFrame->d_func()->childFrames.indexOf(t: q);
587
588 // iterator over all children and move them to the parent
589 for (int i = 0; i < childFrames.size(); ++i) {
590 QTextFrame *c = childFrames.at(i);
591 parentFrame->d_func()->childFrames.insert(i: index, t: c);
592 c->d_func()->parentFrame = parentFrame;
593 ++index;
594 }
595 Q_ASSERT(parentFrame->d_func()->childFrames.at(index) == q);
596 parentFrame->d_func()->childFrames.removeAt(i: index);
597
598 childFrames.clear();
599 parentFrame = nullptr;
600}
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*/
631QTextFrame::iterator QTextFrame::begin() const
632{
633 const QTextDocumentPrivate *priv = docHandle();
634 int b = priv->blockMap().findNode(k: firstPosition());
635 int e = priv->blockMap().findNode(k: lastPosition()+1);
636 return iterator(const_cast<QTextFrame *>(this), b, b, e);
637}
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*/
644QTextFrame::iterator QTextFrame::end() const
645{
646 const QTextDocumentPrivate *priv = docHandle();
647 int b = priv->blockMap().findNode(k: firstPosition());
648 int e = priv->blockMap().findNode(k: lastPosition()+1);
649 return iterator(const_cast<QTextFrame *>(this), e, b, e);
650}
651
652/*!
653 Constructs an invalid iterator.
654*/
655QTextFrame::iterator::iterator()
656{
657 f = nullptr;
658 b = 0;
659 e = 0;
660 cf = nullptr;
661 cb = 0;
662}
663
664/*!
665 \internal
666*/
667QTextFrame::iterator::iterator(QTextFrame *frame, int block, int begin, int end)
668{
669 f = frame;
670 b = begin;
671 e = end;
672 cf = nullptr;
673 cb = block;
674}
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*/
681QTextFrame::iterator::iterator(const iterator &other) noexcept
682{
683 f = other.f;
684 b = other.b;
685 e = other.e;
686 cf = other.cf;
687 cb = other.cb;
688}
689
690/*!
691 Assigns \a other to this iterator and returns a reference to
692 this iterator.
693*/
694QTextFrame::iterator &QTextFrame::iterator::operator=(const iterator &other) noexcept
695{
696 f = other.f;
697 b = other.b;
698 e = other.e;
699 cf = other.cf;
700 cb = other.cb;
701 return *this;
702}
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*/
712QTextFrame *QTextFrame::iterator::currentFrame() const
713{
714 return cf;
715}
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*/
723QTextBlock QTextFrame::iterator::currentBlock() const
724{
725 if (!f)
726 return QTextBlock();
727 return QTextBlock(f->docHandle(), cb);
728}
729
730/*!
731 Moves the iterator to the next frame or block.
732
733 \sa currentBlock(), currentFrame()
734*/
735QTextFrame::iterator &QTextFrame::iterator::operator++()
736{
737 const QTextDocumentPrivate *priv = f->docHandle();
738 const QTextDocumentPrivate::BlockMap &map = priv->blockMap();
739 if (cf) {
740 int end = cf->lastPosition() + 1;
741 cb = map.findNode(k: end);
742 cf = nullptr;
743 } else if (cb) {
744 cb = map.next(n: cb);
745 if (cb == e)
746 return *this;
747
748 if (!f->d_func()->childFrames.isEmpty()) {
749 int pos = map.position(node: cb);
750 // check if we entered a frame
751 QTextDocumentPrivate::FragmentIterator frag = priv->find(pos: pos-1);
752 if (priv->buffer().at(i: frag->stringPosition) != QChar::ParagraphSeparator) {
753 QTextFrame *nf = qobject_cast<QTextFrame *>(object: priv->objectForFormat(formatIndex: frag->format));
754 if (nf) {
755 if (priv->buffer().at(i: frag->stringPosition) == QTextBeginningOfFrame && nf != f) {
756 cf = nf;
757 cb = 0;
758 } else {
759 Q_ASSERT(priv->buffer().at(frag->stringPosition) != QTextEndOfFrame);
760 }
761 }
762 }
763 }
764 }
765 return *this;
766}
767
768/*!
769 Moves the iterator to the previous frame or block.
770
771 \sa currentBlock(), currentFrame()
772*/
773QTextFrame::iterator &QTextFrame::iterator::operator--()
774{
775 const QTextDocumentPrivate *priv = f->docHandle();
776 const QTextDocumentPrivate::BlockMap &map = priv->blockMap();
777 if (cf) {
778 int start = cf->firstPosition() - 1;
779 cb = map.findNode(k: start);
780 cf = nullptr;
781 } else {
782 if (cb == b)
783 goto end;
784 if (cb != e) {
785 int pos = map.position(node: cb);
786 // check if we have to enter a frame
787 QTextDocumentPrivate::FragmentIterator frag = priv->find(pos: pos-1);
788 if (priv->buffer().at(i: frag->stringPosition) != QChar::ParagraphSeparator) {
789 QTextFrame *pf = qobject_cast<QTextFrame *>(object: priv->objectForFormat(formatIndex: frag->format));
790 if (pf) {
791 if (priv->buffer().at(i: frag->stringPosition) == QTextBeginningOfFrame) {
792 Q_ASSERT(pf == f);
793 } else if (priv->buffer().at(i: frag->stringPosition) == QTextEndOfFrame) {
794 Q_ASSERT(pf != f);
795 cf = pf;
796 cb = 0;
797 goto end;
798 }
799 }
800 }
801 }
802 cb = map.previous(n: cb);
803 }
804 end:
805 return *this;
806}
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*/
835QTextBlockUserData::~QTextBlockUserData()
836{
837}
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
908bool QTextBlock::isValid() const
909{
910 return p != nullptr && p->blockMap().isValid(n);
911}
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 */
1031int QTextBlock::position() const
1032{
1033 if (!p || !n)
1034 return 0;
1035
1036 return p->blockMap().position(node: n);
1037}
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 */
1047int QTextBlock::length() const
1048{
1049 if (!p || !n)
1050 return 0;
1051
1052 return p->blockMap().size(node: n);
1053}
1054
1055/*!
1056 Returns \c true if the given \a position is located within the text
1057 block; otherwise returns \c false.
1058 */
1059bool QTextBlock::contains(int position) const
1060{
1061 if (!p || !n)
1062 return false;
1063
1064 int pos = p->blockMap().position(node: n);
1065 int len = p->blockMap().size(node: n);
1066 return position >= pos && position < pos + len;
1067}
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 */
1079QTextLayout *QTextBlock::layout() const
1080{
1081 if (!p || !n)
1082 return nullptr;
1083
1084 const QTextBlockData *b = p->blockMap().fragment(index: n);
1085 if (!b->layout)
1086 b->layout = new QTextLayout(*this);
1087 return b->layout;
1088}
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 */
1097void QTextBlock::clearLayout()
1098{
1099 if (!p || !n)
1100 return;
1101
1102 const QTextBlockData *b = p->blockMap().fragment(index: n);
1103 if (b->layout)
1104 b->layout->clearLayout();
1105}
1106
1107/*!
1108 Returns the QTextBlockFormat that describes block-specific properties.
1109
1110 \sa charFormat()
1111 */
1112QTextBlockFormat QTextBlock::blockFormat() const
1113{
1114 if (!p || !n)
1115 return QTextFormat().toBlockFormat();
1116
1117 return p->formatCollection()->blockFormat(index: p->blockMap().fragment(index: n)->format);
1118}
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*/
1126int QTextBlock::blockFormatIndex() const
1127{
1128 if (!p || !n)
1129 return -1;
1130
1131 return p->blockMap().fragment(index: n)->format;
1132}
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 */
1141QTextCharFormat QTextBlock::charFormat() const
1142{
1143 if (!p || !n)
1144 return QTextFormat().toCharFormat();
1145
1146 return p->formatCollection()->charFormat(index: charFormatIndex());
1147}
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*/
1155int QTextBlock::charFormatIndex() const
1156{
1157 if (!p || !n)
1158 return -1;
1159
1160 return p->blockCharFormatIndex(node: n);
1161}
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*/
1174Qt::LayoutDirection QTextBlock::textDirection() const
1175{
1176 Qt::LayoutDirection dir = blockFormat().layoutDirection();
1177 if (dir != Qt::LayoutDirectionAuto)
1178 return dir;
1179
1180 dir = p->defaultTextOption.textDirection();
1181 if (dir != Qt::LayoutDirectionAuto)
1182 return dir;
1183
1184 const QString buffer = p->buffer();
1185
1186 const int pos = position();
1187 QTextDocumentPrivate::FragmentIterator it = p->find(pos);
1188 QTextDocumentPrivate::FragmentIterator end = p->find(pos: pos + length() - 1); // -1 to omit the block separator char
1189 for (; it != end; ++it) {
1190 const QTextFragmentData * const frag = it.value();
1191 const QChar *p = buffer.constData() + frag->stringPosition;
1192 const QChar * const end = p + frag->size_array[0];
1193 while (p < end) {
1194 uint ucs4 = p->unicode();
1195 if (QChar::isHighSurrogate(ucs4) && p + 1 < end) {
1196 ushort low = p[1].unicode();
1197 if (QChar::isLowSurrogate(ucs4: low)) {
1198 ucs4 = QChar::surrogateToUcs4(high: ucs4, low);
1199 ++p;
1200 }
1201 }
1202 switch (QChar::direction(ucs4)) {
1203 case QChar::DirL:
1204 return Qt::LeftToRight;
1205 case QChar::DirR:
1206 case QChar::DirAL:
1207 return Qt::RightToLeft;
1208 default:
1209 break;
1210 }
1211 ++p;
1212 }
1213 }
1214 return Qt::LeftToRight;
1215}
1216
1217/*!
1218 Returns the block's contents as plain text.
1219
1220 \sa length(), charFormat(), blockFormat()
1221 */
1222QString QTextBlock::text() const
1223{
1224 if (!p || !n)
1225 return QString();
1226
1227 const QString buffer = p->buffer();
1228 QString text;
1229 text.reserve(asize: length());
1230
1231 const int pos = position();
1232 QTextDocumentPrivate::FragmentIterator it = p->find(pos);
1233 QTextDocumentPrivate::FragmentIterator end = p->find(pos: pos + length() - 1); // -1 to omit the block separator char
1234 for (; it != end; ++it) {
1235 const QTextFragmentData * const frag = it.value();
1236 text += QString::fromRawData(buffer.constData() + frag->stringPosition, size: frag->size_array[0]);
1237 }
1238
1239 return text;
1240}
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*/
1251QVector<QTextLayout::FormatRange> QTextBlock::textFormats() const
1252{
1253 QVector<QTextLayout::FormatRange> formats;
1254 if (!p || !n)
1255 return formats;
1256
1257 const QTextFormatCollection *formatCollection = p->formatCollection();
1258
1259 int start = 0;
1260 int cur = start;
1261 int format = -1;
1262
1263 const int pos = position();
1264 QTextDocumentPrivate::FragmentIterator it = p->find(pos);
1265 QTextDocumentPrivate::FragmentIterator end = p->find(pos: pos + length() - 1); // -1 to omit the block separator char
1266 for (; it != end; ++it) {
1267 const QTextFragmentData * const frag = it.value();
1268 if (format != it.value()->format) {
1269 if (cur - start > 0) {
1270 QTextLayout::FormatRange range;
1271 range.start = start;
1272 range.length = cur - start;
1273 range.format = formatCollection->charFormat(index: format);
1274 formats.append(t: range);
1275 }
1276
1277 format = frag->format;
1278 start = cur;
1279 }
1280 cur += frag->size_array[0];
1281 }
1282 if (cur - start > 0) {
1283 QTextLayout::FormatRange range;
1284 range.start = start;
1285 range.length = cur - start;
1286 range.format = formatCollection->charFormat(index: format);
1287 formats.append(t: range);
1288 }
1289
1290 return formats;
1291}
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*/
1297const QTextDocument *QTextBlock::document() const
1298{
1299 return p ? p->document() : nullptr;
1300}
1301
1302/*!
1303 If the block represents a list item, returns the list that the item belongs
1304 to; otherwise returns \nullptr.
1305*/
1306QTextList *QTextBlock::textList() const
1307{
1308 if (!isValid())
1309 return nullptr;
1310
1311 const QTextBlockFormat fmt = blockFormat();
1312 QTextObject *obj = p->document()->objectForFormat(fmt);
1313 return qobject_cast<QTextList *>(object: obj);
1314}
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*/
1322QTextBlockUserData *QTextBlock::userData() const
1323{
1324 if (!p || !n)
1325 return nullptr;
1326
1327 const QTextBlockData *b = p->blockMap().fragment(index: n);
1328 return b->userData;
1329}
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*/
1356void QTextBlock::setUserData(QTextBlockUserData *data)
1357{
1358 if (!p || !n)
1359 return;
1360
1361 const QTextBlockData *b = p->blockMap().fragment(index: n);
1362 if (data != b->userData)
1363 delete b->userData;
1364 b->userData = data;
1365}
1366
1367/*!
1368 \since 4.1
1369
1370 Returns the integer value previously set with setUserState() or -1.
1371*/
1372int QTextBlock::userState() const
1373{
1374 if (!p || !n)
1375 return -1;
1376
1377 const QTextBlockData *b = p->blockMap().fragment(index: n);
1378 return b->userState;
1379}
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*/
1387void QTextBlock::setUserState(int state)
1388{
1389 if (!p || !n)
1390 return;
1391
1392 const QTextBlockData *b = p->blockMap().fragment(index: n);
1393 b->userState = state;
1394}
1395
1396/*!
1397 \since 4.4
1398
1399 Returns the blocks revision.
1400
1401 \sa setRevision(), QTextDocument::revision()
1402*/
1403int QTextBlock::revision() const
1404{
1405 if (!p || !n)
1406 return -1;
1407
1408 const QTextBlockData *b = p->blockMap().fragment(index: n);
1409 return b->revision;
1410}
1411
1412/*!
1413 \since 4.4
1414
1415 Sets a blocks revision to \a rev.
1416
1417 \sa revision(), QTextDocument::revision()
1418*/
1419void QTextBlock::setRevision(int rev)
1420{
1421 if (!p || !n)
1422 return;
1423
1424 const QTextBlockData *b = p->blockMap().fragment(index: n);
1425 b->revision = rev;
1426}
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*/
1435bool QTextBlock::isVisible() const
1436{
1437 if (!p || !n)
1438 return true;
1439
1440 const QTextBlockData *b = p->blockMap().fragment(index: n);
1441 return !b->hidden;
1442}
1443
1444/*!
1445 \since 4.4
1446
1447 Sets the block's visibility to \a visible.
1448
1449 \sa isVisible()
1450*/
1451void QTextBlock::setVisible(bool visible)
1452{
1453 if (!p || !n)
1454 return;
1455
1456 const QTextBlockData *b = p->blockMap().fragment(index: n);
1457 b->hidden = !visible;
1458}
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*/
1469int QTextBlock::blockNumber() const
1470{
1471 if (!p || !n)
1472 return -1;
1473 return p->blockMap().position(node: n, field: 1);
1474}
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*/
1485int QTextBlock::firstLineNumber() const
1486{
1487 if (!p || !n)
1488 return -1;
1489 return p->blockMap().position(node: n, field: 2);
1490}
1491
1492
1493/*!
1494\since 4.5
1495
1496Sets the line count to \a count.
1497
1498\sa lineCount()
1499*/
1500void QTextBlock::setLineCount(int count)
1501{
1502 if (!p || !n)
1503 return;
1504 p->blockMap().setSize(node: n, new_size: count, field: 2);
1505}
1506/*!
1507\since 4.5
1508
1509Returns the line count. Not all document layouts support this feature.
1510
1511\sa setLineCount()
1512 */
1513int QTextBlock::lineCount() const
1514{
1515 if (!p || !n)
1516 return -1;
1517 return p->blockMap().size(node: n, field: 2);
1518}
1519
1520
1521/*!
1522 Returns a text block iterator pointing to the beginning of the
1523 text block.
1524
1525 \sa end()
1526*/
1527QTextBlock::iterator QTextBlock::begin() const
1528{
1529 if (!p || !n)
1530 return iterator();
1531
1532 int pos = position();
1533 int len = length() - 1; // exclude the fragment that holds the paragraph separator
1534 int b = p->fragmentMap().findNode(k: pos);
1535 int e = p->fragmentMap().findNode(k: pos+len);
1536 return iterator(p, b, e, b);
1537}
1538
1539/*!
1540 Returns a text block iterator pointing to the end of the text
1541 block.
1542
1543 \sa begin(), next(), previous()
1544*/
1545QTextBlock::iterator QTextBlock::end() const
1546{
1547 if (!p || !n)
1548 return iterator();
1549
1550 int pos = position();
1551 int len = length() - 1; // exclude the fragment that holds the paragraph separator
1552 int b = p->fragmentMap().findNode(k: pos);
1553 int e = p->fragmentMap().findNode(k: pos+len);
1554 return iterator(p, b, e, e);
1555}
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*/
1566QTextBlock QTextBlock::next() const
1567{
1568 if (!isValid())
1569 return QTextBlock();
1570
1571 return QTextBlock(p, p->blockMap().next(n));
1572}
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*/
1582QTextBlock QTextBlock::previous() const
1583{
1584 if (!p)
1585 return QTextBlock();
1586
1587 return QTextBlock(p, p->blockMap().previous(n));
1588}
1589
1590
1591/*!
1592 Returns the text fragment the iterator currently points to.
1593*/
1594QTextFragment QTextBlock::iterator::fragment() const
1595{
1596 int ne = n;
1597 int formatIndex = p->fragmentMap().fragment(index: n)->format;
1598 do {
1599 ne = p->fragmentMap().next(n: ne);
1600 } while (ne != e && p->fragmentMap().fragment(index: ne)->format == formatIndex);
1601 return QTextFragment(p, n, ne);
1602}
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
1610QTextBlock::iterator &QTextBlock::iterator::operator++()
1611{
1612 int ne = n;
1613 int formatIndex = p->fragmentMap().fragment(index: n)->format;
1614 do {
1615 ne = p->fragmentMap().next(n: ne);
1616 } while (ne != e && p->fragmentMap().fragment(index: ne)->format == formatIndex);
1617 n = ne;
1618 return *this;
1619}
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
1626QTextBlock::iterator &QTextBlock::iterator::operator--()
1627{
1628 n = p->fragmentMap().previous(n);
1629
1630 if (n == b)
1631 return *this;
1632
1633 int formatIndex = p->fragmentMap().fragment(index: n)->format;
1634 int last = n;
1635
1636 while (n != b && p->fragmentMap().fragment(index: n)->format != formatIndex) {
1637 last = n;
1638 n = p->fragmentMap().previous(n);
1639 }
1640
1641 n = last;
1642 return *this;
1643}
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)
1747QList<QGlyphRun> QTextFragment::glyphRuns(int pos, int len) const
1748{
1749 if (!p || !n)
1750 return QList<QGlyphRun>();
1751
1752 int blockNode = p->blockMap().findNode(k: position());
1753
1754 const QTextBlockData *blockData = p->blockMap().fragment(index: blockNode);
1755 QTextLayout *layout = blockData->layout;
1756
1757 int blockPosition = p->blockMap().position(node: blockNode);
1758 if (pos < 0)
1759 pos = position() - blockPosition;
1760 if (len < 0)
1761 len = length();
1762 if (len == 0)
1763 return QList<QGlyphRun>();
1764
1765 QList<QGlyphRun> ret;
1766 for (int i=0; i<layout->lineCount(); ++i) {
1767 QTextLine textLine = layout->lineAt(i);
1768 ret += textLine.glyphRuns(from: pos, length: len);
1769 }
1770
1771 return ret;
1772}
1773#endif // QT_NO_RAWFONT
1774
1775/*!
1776 Returns the position of this text fragment in the document.
1777*/
1778int QTextFragment::position() const
1779{
1780 if (!p || !n)
1781 return 0; // ### -1 instead?
1782
1783 return p->fragmentMap().position(node: n);
1784}
1785
1786/*!
1787 Returns the number of characters in the text fragment.
1788
1789 \sa text()
1790*/
1791int QTextFragment::length() const
1792{
1793 if (!p || !n)
1794 return 0;
1795
1796 int len = 0;
1797 int f = n;
1798 while (f != ne) {
1799 len += p->fragmentMap().size(node: f);
1800 f = p->fragmentMap().next(n: f);
1801 }
1802 return len;
1803}
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*/
1809bool QTextFragment::contains(int position) const
1810{
1811 if (!p || !n)
1812 return false;
1813 int pos = this->position();
1814 return position >= pos && position < pos + length();
1815}
1816
1817/*!
1818 Returns the text fragment's character format.
1819
1820 \sa text()
1821*/
1822QTextCharFormat QTextFragment::charFormat() const
1823{
1824 if (!p || !n)
1825 return QTextCharFormat();
1826 const QTextFragmentData *data = p->fragmentMap().fragment(index: n);
1827 return p->formatCollection()->charFormat(index: data->format);
1828}
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*/
1836int QTextFragment::charFormatIndex() const
1837{
1838 if (!p || !n)
1839 return -1;
1840 const QTextFragmentData *data = p->fragmentMap().fragment(index: n);
1841 return data->format;
1842}
1843
1844/*!
1845 Returns the text fragment's as plain text.
1846
1847 \sa length(), charFormat()
1848*/
1849QString QTextFragment::text() const
1850{
1851 if (!p || !n)
1852 return QString();
1853
1854 QString result;
1855 QString buffer = p->buffer();
1856 int f = n;
1857 while (f != ne) {
1858 const QTextFragmentData * const frag = p->fragmentMap().fragment(index: f);
1859 result += QString(buffer.constData() + frag->stringPosition, frag->size_array[0]);
1860 f = p->fragmentMap().next(n: f);
1861 }
1862 return result;
1863}
1864
1865QT_END_NAMESPACE
1866

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