source: trunk/src/gui/text/qtextobject.cpp@ 352

Last change on this file since 352 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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