1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qtextobject.h"
41 #include "qtextobject_p.h"
42 #include "qtextcursor_p.h"
43 #include "qtextdocument.h"
44 #include "qtextformat_p.h"
45 #include "qtextdocument_p.h"
46 #include "qtextcursor.h"
47 #include "qtextlist.h"
48 #include "qabstracttextdocumentlayout.h"
49 #include "qtextengine_p.h"
50 #include "qdebug.h"
51 
52 #include <algorithm>
53 
54 QT_BEGIN_NAMESPACE
55 
56 // ### DOC: We ought to explain the CONCEPT of objectIndexes if
57 // relevant to the public API
58 /*!
59     \class QTextObject
60     \reentrant
61 
62     \brief The QTextObject class is a base class for different kinds
63     of objects that can group parts of a QTextDocument together.
64     \inmodule QtGui
65 
66     \ingroup richtext-processing
67 
68     The common grouping text objects are lists (QTextList), frames
69     (QTextFrame), and tables (QTextTable). A text object has an
70     associated format() and document().
71 
72     There are essentially two kinds of text objects: those that are used
73     with blocks (block formats), and those that are used with characters
74     (character formats). The first kind are derived from QTextBlockGroup,
75     and the second kind from QTextFrame.
76 
77     You rarely need to use this class directly. When creating custom text
78     objects, you will also need to reimplement QTextDocument::createObject()
79     which acts as a factory method for creating text objects.
80 
81     \sa QTextDocument, {Text Object Example}
82 */
83 
84 /*!
85     \fn QTextObject::QTextObject(QTextDocument *document)
86 
87     Creates a new QTextObject for the given \a document.
88 
89     \warning This function should never be called directly, but only
90     from QTextDocument::createObject().
91 */
QTextObject(QTextDocument * doc)92 QTextObject::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 */
QTextObject(QTextObjectPrivate & p,QTextDocument * doc)102 QTextObject::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 */
~QTextObject()113 QTextObject::~QTextObject()
114 {
115 }
116 
117 /*!
118     Returns the text object's format.
119 
120     \sa setFormat(), document()
121 */
format() const122 QTextFormat QTextObject::format() const
123 {
124     Q_D(const QTextObject);
125     return d->pieceTable->formatCollection()->objectFormat(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 */
formatIndex() const134 int QTextObject::formatIndex() const
135 {
136     Q_D(const QTextObject);
137     return d->pieceTable->formatCollection()->objectFormatIndex(d->objectIndex);
138 }
139 
140 
141 /*!
142     Sets the text object's \a format.
143 
144     \sa format()
145 */
setFormat(const QTextFormat & format)146 void QTextObject::setFormat(const QTextFormat &format)
147 {
148     Q_D(QTextObject);
149     int idx = d->pieceTable->formatCollection()->indexForFormat(format);
150     d->pieceTable->changeObjectFormat(this, idx);
151 }
152 
153 /*!
154     Returns the object index of this object. This can be used together with
155     QTextFormat::setObjectIndex().
156 */
objectIndex() const157 int 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 */
document() const168 QTextDocument *QTextObject::document() const
169 {
170     return static_cast<QTextDocument *>(parent());
171 }
172 
173 /*!
174   \internal
175 */
docHandle() const176 QTextDocumentPrivate *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 
markBlocksDirty()210 void QTextBlockGroupPrivate::markBlocksDirty()
211 {
212     for (int i = 0; i < blocks.count(); ++i) {
213         const QTextBlock &block = blocks.at(i);
214         pieceTable->documentChange(block.position(), 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 */
QTextBlockGroup(QTextDocument * doc)226 QTextBlockGroup::QTextBlockGroup(QTextDocument *doc)
227     : QTextObject(*new QTextBlockGroupPrivate(doc), doc)
228 {
229 }
230 
231 /*!
232   \internal
233 */
QTextBlockGroup(QTextBlockGroupPrivate & p,QTextDocument * doc)234 QTextBlockGroup::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 */
~QTextBlockGroup()243 QTextBlockGroup::~QTextBlockGroup()
244 {
245 }
246 
247 // ### DOC: Shouldn't this be insertBlock()?
248 /*!
249     Appends the given \a block to the end of the group.
250 
251     \warning If you reimplement this function you must call the base
252     class implementation.
253 */
blockInserted(const QTextBlock & block)254 void QTextBlockGroup::blockInserted(const QTextBlock &block)
255 {
256     Q_D(QTextBlockGroup);
257     QTextBlockGroupPrivate::BlockList::Iterator it = std::lower_bound(d->blocks.begin(), d->blocks.end(), block);
258     d->blocks.insert(it, 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 */
blockRemoved(const QTextBlock & block)267 void QTextBlockGroup::blockRemoved(const QTextBlock &block)
268 {
269     Q_D(QTextBlockGroup);
270     d->blocks.removeAll(block);
271     d->markBlocksDirty();
272     if (d->blocks.isEmpty()) {
273         document()->docHandle()->deleteObject(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 */
blockFormatChanged(const QTextBlock &)284 void 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 */
blockList() const292 QList<QTextBlock> QTextBlockGroup::blockList() const
293 {
294     Q_D(const QTextBlockGroup);
295     return d->blocks;
296 }
297 
298 
299 
~QTextFrameLayoutData()300 QTextFrameLayoutData::~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 */
QTextFrame(QTextDocument * doc)416 QTextFrame::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 */
~QTextFrame()428 QTextFrame::~QTextFrame()
429 {
430     Q_D(QTextFrame);
431     delete d->layoutData;
432 }
433 
434 /*!
435     \internal
436 */
QTextFrame(QTextFramePrivate & p,QTextDocument * doc)437 QTextFrame::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 */
childFrames() const447 QList<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 */
parentFrame() const459 QTextFrame *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 */
firstCursorPosition() const471 QTextCursor QTextFrame::firstCursorPosition() const
472 {
473     Q_D(const QTextFrame);
474     return QTextCursorPrivate::fromPosition(d->pieceTable, firstPosition());
475 }
476 
477 /*!
478     Returns the last cursor position inside the frame.
479 
480     \sa firstCursorPosition(), firstPosition(), lastPosition()
481 */
lastCursorPosition() const482 QTextCursor QTextFrame::lastCursorPosition() const
483 {
484     Q_D(const QTextFrame);
485     return QTextCursorPrivate::fromPosition(d->pieceTable, lastPosition());
486 }
487 
488 /*!
489     Returns the first document position inside the frame.
490 
491     \sa lastPosition(), firstCursorPosition(), lastCursorPosition()
492 */
firstPosition() const493 int QTextFrame::firstPosition() const
494 {
495     Q_D(const QTextFrame);
496     if (!d->fragment_start)
497         return 0;
498     return d->pieceTable->fragmentMap().position(d->fragment_start) + 1;
499 }
500 
501 /*!
502     Returns the last document position inside the frame.
503 
504     \sa firstPosition(), firstCursorPosition(), lastCursorPosition()
505 */
lastPosition() const506 int 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(d->fragment_end);
512 }
513 
514 /*!
515   \internal
516 */
layoutData() const517 QTextFrameLayoutData *QTextFrame::layoutData() const
518 {
519     Q_D(const QTextFrame);
520     return d->layoutData;
521 }
522 
523 /*!
524   \internal
525 */
setLayoutData(QTextFrameLayoutData * data)526 void QTextFrame::setLayoutData(QTextFrameLayoutData *data)
527 {
528     Q_D(QTextFrame);
529     delete d->layoutData;
530     d->layoutData = data;
531 }
532 
533 
534 
fragmentAdded(QChar type,uint fragment)535 void QTextFramePrivate::fragmentAdded(QChar type, uint fragment)
536 {
537     if (type == QTextBeginningOfFrame) {
538         Q_ASSERT(!fragment_start);
539         fragment_start = fragment;
540     } else if (type == QTextEndOfFrame) {
541         Q_ASSERT(!fragment_end);
542         fragment_end = fragment;
543     } else if (type == QChar::ObjectReplacementCharacter) {
544         Q_ASSERT(!fragment_start);
545         Q_ASSERT(!fragment_end);
546         fragment_start = fragment;
547         fragment_end = fragment;
548     } else {
549         Q_ASSERT(false);
550     }
551 }
552 
fragmentRemoved(QChar type,uint fragment)553 void QTextFramePrivate::fragmentRemoved(QChar type, uint fragment)
554 {
555     Q_UNUSED(fragment); // --release warning
556     if (type == QTextBeginningOfFrame) {
557         Q_ASSERT(fragment_start == fragment);
558         fragment_start = 0;
559     } else if (type == QTextEndOfFrame) {
560         Q_ASSERT(fragment_end == fragment);
561         fragment_end = 0;
562     } else if (type == QChar::ObjectReplacementCharacter) {
563         Q_ASSERT(fragment_start == fragment);
564         Q_ASSERT(fragment_end == fragment);
565         fragment_start = 0;
566         fragment_end = 0;
567     } else {
568         Q_ASSERT(false);
569     }
570     remove_me();
571 }
572 
573 
remove_me()574 void QTextFramePrivate::remove_me()
575 {
576     Q_Q(QTextFrame);
577     if (fragment_start == 0 && fragment_end == 0
578         && !parentFrame) {
579         q->document()->docHandle()->deleteObject(q);
580         return;
581     }
582 
583     if (!parentFrame)
584         return;
585 
586     int index = parentFrame->d_func()->childFrames.indexOf(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(index, 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(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 */
begin() const631 QTextFrame::iterator QTextFrame::begin() const
632 {
633     const QTextDocumentPrivate *priv = docHandle();
634     int b = priv->blockMap().findNode(firstPosition());
635     int e = priv->blockMap().findNode(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 */
end() const644 QTextFrame::iterator QTextFrame::end() const
645 {
646     const QTextDocumentPrivate *priv = docHandle();
647     int b = priv->blockMap().findNode(firstPosition());
648     int e = priv->blockMap().findNode(lastPosition()+1);
649     return iterator(const_cast<QTextFrame *>(this), e, b, e);
650 }
651 
652 /*!
653     Constructs an invalid iterator.
654 */
iterator()655 QTextFrame::iterator::iterator()
656 {
657     f = nullptr;
658     b = 0;
659     e = 0;
660     cf = nullptr;
661     cb = 0;
662 }
663 
664 /*!
665   \internal
666 */
iterator(QTextFrame * frame,int block,int begin,int end)667 QTextFrame::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 */
iterator(const iterator & other)681 QTextFrame::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 */
operator =(const iterator & other)694 QTextFrame::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 */
currentFrame() const712 QTextFrame *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 */
currentBlock() const723 QTextBlock 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 */
operator ++()735 QTextFrame::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(end);
742         cf = nullptr;
743     } else if (cb) {
744         cb = map.next(cb);
745         if (cb == e)
746             return *this;
747 
748         if (!f->d_func()->childFrames.isEmpty()) {
749             int pos = map.position(cb);
750             // check if we entered a frame
751             QTextDocumentPrivate::FragmentIterator frag = priv->find(pos-1);
752             if (priv->buffer().at(frag->stringPosition) != QChar::ParagraphSeparator) {
753                 QTextFrame *nf = qobject_cast<QTextFrame *>(priv->objectForFormat(frag->format));
754                 if (nf) {
755                     if (priv->buffer().at(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 */
operator --()773 QTextFrame::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(start);
780         cf = nullptr;
781     } else {
782         if (cb == b)
783             goto end;
784         if (cb != e) {
785             int pos = map.position(cb);
786             // check if we have to enter a frame
787             QTextDocumentPrivate::FragmentIterator frag = priv->find(pos-1);
788             if (priv->buffer().at(frag->stringPosition) != QChar::ParagraphSeparator) {
789                 QTextFrame *pf = qobject_cast<QTextFrame *>(priv->objectForFormat(frag->format));
790                 if (pf) {
791                     if (priv->buffer().at(frag->stringPosition) == QTextBeginningOfFrame) {
792                         Q_ASSERT(pf == f);
793                     } else if (priv->buffer().at(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(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 */
~QTextBlockUserData()835 QTextBlockUserData::~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 
isValid() const908 bool 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  */
position() const1031 int QTextBlock::position() const
1032 {
1033     if (!p || !n)
1034         return 0;
1035 
1036     return p->blockMap().position(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  */
length() const1047 int QTextBlock::length() const
1048 {
1049     if (!p || !n)
1050         return 0;
1051 
1052     return p->blockMap().size(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  */
contains(int position) const1059 bool QTextBlock::contains(int position) const
1060 {
1061     if (!p || !n)
1062         return false;
1063 
1064     int pos = p->blockMap().position(n);
1065     int len = p->blockMap().size(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  */
layout() const1079 QTextLayout *QTextBlock::layout() const
1080 {
1081     if (!p || !n)
1082         return nullptr;
1083 
1084     const QTextBlockData *b = p->blockMap().fragment(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  */
clearLayout()1097 void QTextBlock::clearLayout()
1098 {
1099     if (!p || !n)
1100         return;
1101 
1102     const QTextBlockData *b = p->blockMap().fragment(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  */
blockFormat() const1112 QTextBlockFormat QTextBlock::blockFormat() const
1113 {
1114     if (!p || !n)
1115         return QTextFormat().toBlockFormat();
1116 
1117     return p->formatCollection()->blockFormat(p->blockMap().fragment(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 */
blockFormatIndex() const1126 int QTextBlock::blockFormatIndex() const
1127 {
1128     if (!p || !n)
1129         return -1;
1130 
1131     return p->blockMap().fragment(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  */
charFormat() const1141 QTextCharFormat QTextBlock::charFormat() const
1142 {
1143     if (!p || !n)
1144         return QTextFormat().toCharFormat();
1145 
1146     return p->formatCollection()->charFormat(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 */
charFormatIndex() const1155 int QTextBlock::charFormatIndex() const
1156 {
1157     if (!p || !n)
1158         return -1;
1159 
1160     return p->blockCharFormatIndex(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 */
textDirection() const1174 Qt::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 + 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(low)) {
1198                     ucs4 = QChar::surrogateToUcs4(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  */
text() const1222 QString QTextBlock::text() const
1223 {
1224     if (!p || !n)
1225         return QString();
1226 
1227     const QString buffer = p->buffer();
1228     QString text;
1229     text.reserve(length());
1230 
1231     const int pos = position();
1232     QTextDocumentPrivate::FragmentIterator it = p->find(pos);
1233     QTextDocumentPrivate::FragmentIterator end = p->find(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, 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 */
textFormats() const1251 QVector<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 + 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(format);
1274                 formats.append(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(format);
1287         formats.append(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 */
document() const1297 const 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 */
textList() const1306 QTextList *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 *>(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 */
userData() const1322 QTextBlockUserData *QTextBlock::userData() const
1323 {
1324     if (!p || !n)
1325         return nullptr;
1326 
1327     const QTextBlockData *b = p->blockMap().fragment(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 */
setUserData(QTextBlockUserData * data)1356 void QTextBlock::setUserData(QTextBlockUserData *data)
1357 {
1358     if (!p || !n)
1359         return;
1360 
1361     const QTextBlockData *b = p->blockMap().fragment(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 */
userState() const1372 int QTextBlock::userState() const
1373 {
1374     if (!p || !n)
1375         return -1;
1376 
1377     const QTextBlockData *b = p->blockMap().fragment(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 */
setUserState(int state)1387 void QTextBlock::setUserState(int state)
1388 {
1389     if (!p || !n)
1390         return;
1391 
1392     const QTextBlockData *b = p->blockMap().fragment(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 */
revision() const1403 int QTextBlock::revision() const
1404 {
1405     if (!p || !n)
1406         return -1;
1407 
1408     const QTextBlockData *b = p->blockMap().fragment(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 */
setRevision(int rev)1419 void QTextBlock::setRevision(int rev)
1420 {
1421     if (!p || !n)
1422         return;
1423 
1424     const QTextBlockData *b = p->blockMap().fragment(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 */
isVisible() const1435 bool QTextBlock::isVisible() const
1436 {
1437     if (!p || !n)
1438         return true;
1439 
1440     const QTextBlockData *b = p->blockMap().fragment(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 */
setVisible(bool visible)1451 void QTextBlock::setVisible(bool visible)
1452 {
1453     if (!p || !n)
1454         return;
1455 
1456     const QTextBlockData *b = p->blockMap().fragment(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 */
blockNumber() const1469 int QTextBlock::blockNumber() const
1470 {
1471     if (!p || !n)
1472         return -1;
1473     return p->blockMap().position(n, 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 */
firstLineNumber() const1485 int QTextBlock::firstLineNumber() const
1486 {
1487     if (!p || !n)
1488         return -1;
1489     return p->blockMap().position(n, 2);
1490 }
1491 
1492 
1493 /*!
1494 \since 4.5
1495 
1496 Sets the line count to \a count.
1497 
1498 \sa lineCount()
1499 */
setLineCount(int count)1500 void QTextBlock::setLineCount(int count)
1501 {
1502     if (!p || !n)
1503         return;
1504     p->blockMap().setSize(n, count, 2);
1505 }
1506 /*!
1507 \since 4.5
1508 
1509 Returns the line count. Not all document layouts support this feature.
1510 
1511 \sa setLineCount()
1512  */
lineCount() const1513 int QTextBlock::lineCount() const
1514 {
1515     if (!p || !n)
1516         return -1;
1517     return p->blockMap().size(n, 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 */
begin() const1527 QTextBlock::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(pos);
1535     int e = p->fragmentMap().findNode(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 */
end() const1545 QTextBlock::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(pos);
1553     int e = p->fragmentMap().findNode(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 */
next() const1566 QTextBlock 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 */
previous() const1582 QTextBlock 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 */
fragment() const1594 QTextFragment QTextBlock::iterator::fragment() const
1595 {
1596     int ne = n;
1597     int formatIndex = p->fragmentMap().fragment(n)->format;
1598     do {
1599         ne = p->fragmentMap().next(ne);
1600     } while (ne != e && p->fragmentMap().fragment(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 
operator ++()1610 QTextBlock::iterator &QTextBlock::iterator::operator++()
1611 {
1612     int ne = n;
1613     int formatIndex = p->fragmentMap().fragment(n)->format;
1614     do {
1615         ne = p->fragmentMap().next(ne);
1616     } while (ne != e && p->fragmentMap().fragment(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 
operator --()1626 QTextBlock::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(n)->format;
1634     int last = n;
1635 
1636     while (n != b && p->fragmentMap().fragment(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)
glyphRuns(int pos,int len) const1747 QList<QGlyphRun> QTextFragment::glyphRuns(int pos, int len) const
1748 {
1749     if (!p || !n)
1750         return QList<QGlyphRun>();
1751 
1752     int blockNode = p->blockMap().findNode(position());
1753 
1754     const QTextBlockData *blockData = p->blockMap().fragment(blockNode);
1755     QTextLayout *layout = blockData->layout;
1756 
1757     int blockPosition = p->blockMap().position(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(pos, 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 */
position() const1778 int QTextFragment::position() const
1779 {
1780     if (!p || !n)
1781         return 0; // ### -1 instead?
1782 
1783     return p->fragmentMap().position(n);
1784 }
1785 
1786 /*!
1787     Returns the number of characters in the text fragment.
1788 
1789     \sa text()
1790 */
length() const1791 int 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(f);
1800         f = p->fragmentMap().next(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 */
contains(int position) const1809 bool 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 */
charFormat() const1822 QTextCharFormat QTextFragment::charFormat() const
1823 {
1824     if (!p || !n)
1825         return QTextCharFormat();
1826     const QTextFragmentData *data = p->fragmentMap().fragment(n);
1827     return p->formatCollection()->charFormat(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 */
charFormatIndex() const1836 int QTextFragment::charFormatIndex() const
1837 {
1838     if (!p || !n)
1839         return -1;
1840     const QTextFragmentData *data = p->fragmentMap().fragment(n);
1841     return data->format;
1842 }
1843 
1844 /*!
1845     Returns the text fragment's as plain text.
1846 
1847     \sa length(), charFormat()
1848 */
text() const1849 QString 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(f);
1859         result += QString(buffer.constData() + frag->stringPosition, frag->size_array[0]);
1860         f = p->fragmentMap().next(f);
1861     }
1862     return result;
1863 }
1864 
1865 QT_END_NAMESPACE
1866