diff -r 000000000000 -r 1918ee327afb src/gui/text/qtextobject.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/text/qtextobject.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,1701 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtextobject.h" +#include "qtextobject_p.h" +#include "qtextdocument.h" +#include "qtextformat_p.h" +#include "qtextdocument_p.h" +#include "qtextcursor.h" +#include "qtextlist.h" +#include "qabstracttextdocumentlayout.h" +#include "qtextengine_p.h" +#include "qdebug.h" + +QT_BEGIN_NAMESPACE + +// ### DOC: We ought to explain the CONCEPT of objectIndexes if +// relevant to the public API +/*! + \class QTextObject + \reentrant + + \brief The QTextObject class is a base class for different kinds + of objects that can group parts of a QTextDocument together. + + \ingroup richtext-processing + + The common grouping text objects are lists (QTextList), frames + (QTextFrame), and tables (QTextTable). A text object has an + associated format() and document(). + + There are essentially two kinds of text objects: those that are used + with blocks (block formats), and those that are used with characters + (character formats). The first kind are derived from QTextBlockGroup, + and the second kind from QTextFrame. + + You rarely need to use this class directly. When creating custom text + objects, you will also need to reimplement QTextDocument::createObject() + which acts as a factory method for creating text objects. + + \sa QTextDocument, {Text Object Example} +*/ + +/*! + \fn QTextObject::QTextObject(QTextDocument *document) + + Creates a new QTextObject for the given \a document. + + \warning This function should never be called directly, but only + from QTextDocument::createObject(). +*/ +QTextObject::QTextObject(QTextDocument *doc) + : QObject(*new QTextObjectPrivate(doc), doc) +{ +} + +/*! + \fn QTextObject::QTextObject(QTextObjectPrivate &p, QTextDocument *document) + + \internal +*/ +QTextObject::QTextObject(QTextObjectPrivate &p, QTextDocument *doc) + : QObject(p, doc) +{ +} + +/*! + Destroys the text object. + + \warning Text objects are owned by the document, so you should + never destroy them yourself. +*/ +QTextObject::~QTextObject() +{ +} + +/*! + Returns the text object's format. + + \sa setFormat() document() +*/ +QTextFormat QTextObject::format() const +{ + Q_D(const QTextObject); + return d->pieceTable->formatCollection()->objectFormat(d->objectIndex); +} + +/*! + Returns the index of the object's format in the document's internal + list of formats. + + \sa QTextDocument::allFormats() +*/ +int QTextObject::formatIndex() const +{ + Q_D(const QTextObject); + return d->pieceTable->formatCollection()->objectFormatIndex(d->objectIndex); +} + + +/*! + Sets the text object's \a format. + + \sa format() +*/ +void QTextObject::setFormat(const QTextFormat &format) +{ + Q_D(QTextObject); + int idx = d->pieceTable->formatCollection()->indexForFormat(format); + d->pieceTable->changeObjectFormat(this, idx); +} + +/*! + Returns the object index of this object. This can be used together with + QTextFormat::setObjectIndex(). +*/ +int QTextObject::objectIndex() const +{ + Q_D(const QTextObject); + return d->objectIndex; +} + +/*! + Returns the document this object belongs to. + + \sa format() +*/ +QTextDocument *QTextObject::document() const +{ + return static_cast(parent()); +} + +/*! + \internal +*/ +QTextDocumentPrivate *QTextObject::docHandle() const +{ + return static_cast(parent())->docHandle(); +} + +/*! + \class QTextBlockGroup + \reentrant + + \brief The QTextBlockGroup class provides a container for text blocks within + a QTextDocument. + + \ingroup richtext-processing + + Block groups can be used to organize blocks of text within a document. + They maintain an up-to-date list of the text blocks that belong to + them, even when text blocks are being edited. + + Each group has a parent document which is specified when the group is + constructed. + + Text blocks can be inserted into a group with blockInserted(), and removed + with blockRemoved(). If a block's format is changed, blockFormatChanged() + is called. + + The list of blocks in the group is returned by blockList(). Note that the + blocks in the list are not necessarily adjacent elements in the document; + for example, the top-level items in a multi-level list will be separated + by the items in lower levels of the list. + + \sa QTextBlock QTextDocument +*/ + +void QTextBlockGroupPrivate::markBlocksDirty() +{ + for (int i = 0; i < blocks.count(); ++i) { + const QTextBlock &block = blocks.at(i); + pieceTable->documentChange(block.position(), block.length()); + } +} + +/*! + \fn QTextBlockGroup::QTextBlockGroup(QTextDocument *document) + + Creates a new new block group for the given \a document. + + \warning This function should only be called from + QTextDocument::createObject(). +*/ +QTextBlockGroup::QTextBlockGroup(QTextDocument *doc) + : QTextObject(*new QTextBlockGroupPrivate(doc), doc) +{ +} + +/*! + \internal +*/ +QTextBlockGroup::QTextBlockGroup(QTextBlockGroupPrivate &p, QTextDocument *doc) + : QTextObject(p, doc) +{ +} + +/*! + Destroys this block group; the blocks are not deleted, they simply + don't belong to this block anymore. +*/ +QTextBlockGroup::~QTextBlockGroup() +{ +} + +// ### DOC: Shouldn't this be insertBlock()? +/*! + Appends the given \a block to the end of the group. + + \warning If you reimplement this function you must call the base + class implementation. +*/ +void QTextBlockGroup::blockInserted(const QTextBlock &block) +{ + Q_D(QTextBlockGroup); + QTextBlockGroupPrivate::BlockList::Iterator it = qLowerBound(d->blocks.begin(), d->blocks.end(), block); + d->blocks.insert(it, block); + d->markBlocksDirty(); +} + +// ### DOC: Shouldn't this be removeBlock()? +/*! + Removes the given \a block from the group; the block itself is not + deleted, it simply isn't a member of this group anymore. +*/ +void QTextBlockGroup::blockRemoved(const QTextBlock &block) +{ + Q_D(QTextBlockGroup); + d->blocks.removeAll(block); + d->markBlocksDirty(); + if (d->blocks.isEmpty()) { + document()->docHandle()->deleteObject(this); + return; + } +} + +/*! + This function is called whenever the specified \a block of text is changed. + The text block is a member of this group. + + The base class implementation does nothing. +*/ +void QTextBlockGroup::blockFormatChanged(const QTextBlock &) +{ +} + +/*! + Returns a (possibly empty) list of all the blocks that are part of + the block group. +*/ +QList QTextBlockGroup::blockList() const +{ + Q_D(const QTextBlockGroup); + return d->blocks; +} + + + +QTextFrameLayoutData::~QTextFrameLayoutData() +{ +} + + +/*! + \class QTextFrame + \reentrant + + \brief The QTextFrame class represents a frame in a QTextDocument. + + \ingroup richtext-processing + + Text frames provide structure for the text in a document. They are used + as generic containers for other document elements. + Frames are usually created by using QTextCursor::insertFrame(). + + \omit + Each frame in a document consists of a frame start character, + QChar(0xFDD0), followed by the frame's contents, followed by a + frame end character, QChar(0xFDD1). The character formats of the + start and end character contain a reference to the frame object's + objectIndex. + \endomit + + Frames can be used to create hierarchical structures in rich text documents. + Each document has a root frame (QTextDocument::rootFrame()), and each frame + beneath the root frame has a parent frame and a (possibly empty) list of + child frames. The parent frame can be found with parentFrame(), and the + childFrames() function provides a list of child frames. + + Each frame contains at least one text block to enable text cursors to + insert new document elements within. As a result, the QTextFrame::iterator + class is used to traverse both the blocks and child frames within a given + frame. The first and last child elements in the frame can be found with + begin() and end(). + + A frame also has a format (specified using QTextFrameFormat) which can be set + with setFormat() and read with format(). + + Text cursors can be obtained that point to the first and last valid cursor + positions within a frame; use the firstCursorPosition() and + lastCursorPosition() functions for this. The frame's extent in the + document can be found with firstPosition() and lastPosition(). + + You can iterate over a frame's contents using the + QTextFrame::iterator class: this provides read-only access to its + internal list of text blocks and child frames. + + \sa QTextCursor QTextDocument +*/ + +/*! + \typedef QTextFrame::Iterator + + Qt-style synonym for QTextFrame::iterator. +*/ + +/*! + \fn QTextFrame *QTextFrame::iterator::parentFrame() const + + Returns the parent frame of the current frame. + + \sa currentFrame() QTextFrame::parentFrame() +*/ + +/*! + \fn bool QTextFrame::iterator::operator==(const iterator &other) const + + Retuns true if the iterator is the same as the \a other iterator; + otherwise returns false. +*/ + +/*! + \fn bool QTextFrame::iterator::operator!=(const iterator &other) const + + Retuns true if the iterator is different from the \a other iterator; + otherwise returns false. +*/ + +/*! + \fn QTextFrame::iterator QTextFrame::iterator::operator++(int) + + The postfix ++ operator (\c{i++}) advances the iterator to the + next item in the text frame, and returns an iterator to the old item. +*/ + +/*! + \fn QTextFrame::iterator QTextFrame::iterator::operator--(int) + + The postfix -- operator (\c{i--}) makes the preceding item in the + current frame, and returns an iterator to the old item. +*/ + +/*! + \fn void QTextFrame::setFrameFormat(const QTextFrameFormat &format) + + Sets the frame's \a format. + + \sa frameFormat() +*/ + +/*! + \fn QTextFrameFormat QTextFrame::frameFormat() const + + Returns the frame's format. + + \sa setFrameFormat() +*/ + +/*! + \fn QTextFrame::QTextFrame(QTextDocument *document) + + Creates a new empty frame for the text \a document. +*/ +QTextFrame::QTextFrame(QTextDocument *doc) + : QTextObject(*new QTextFramePrivate(doc), doc) +{ +} + +// ### DOC: What does this do to child frames? +/*! + Destroys the frame, and removes it from the document's layout. +*/ +QTextFrame::~QTextFrame() +{ + Q_D(QTextFrame); + delete d->layoutData; +} + +/*! + \internal +*/ +QTextFrame::QTextFrame(QTextFramePrivate &p, QTextDocument *doc) + : QTextObject(p, doc) +{ +} + +/*! + Returns a (possibly empty) list of the frame's child frames. + + \sa parentFrame() +*/ +QList QTextFrame::childFrames() const +{ + Q_D(const QTextFrame); + return d->childFrames; +} + +/*! + Returns the frame's parent frame. If the frame is the root frame of a + document, this will return 0. + + \sa childFrames() QTextDocument::rootFrame() +*/ +QTextFrame *QTextFrame::parentFrame() const +{ + Q_D(const QTextFrame); + return d->parentFrame; +} + + +/*! + Returns the first cursor position inside the frame. + + \sa lastCursorPosition() firstPosition() lastPosition() +*/ +QTextCursor QTextFrame::firstCursorPosition() const +{ + Q_D(const QTextFrame); + return QTextCursor(d->pieceTable, firstPosition()); +} + +/*! + Returns the last cursor position inside the frame. + + \sa firstCursorPosition() firstPosition() lastPosition() +*/ +QTextCursor QTextFrame::lastCursorPosition() const +{ + Q_D(const QTextFrame); + return QTextCursor(d->pieceTable, lastPosition()); +} + +/*! + Returns the first document position inside the frame. + + \sa lastPosition() firstCursorPosition() lastCursorPosition() +*/ +int QTextFrame::firstPosition() const +{ + Q_D(const QTextFrame); + if (!d->fragment_start) + return 0; + return d->pieceTable->fragmentMap().position(d->fragment_start) + 1; +} + +/*! + Returns the last document position inside the frame. + + \sa firstPosition() firstCursorPosition() lastCursorPosition() +*/ +int QTextFrame::lastPosition() const +{ + Q_D(const QTextFrame); + if (!d->fragment_end) + return d->pieceTable->length() - 1; + return d->pieceTable->fragmentMap().position(d->fragment_end); +} + +/*! + \internal +*/ +QTextFrameLayoutData *QTextFrame::layoutData() const +{ + Q_D(const QTextFrame); + return d->layoutData; +} + +/*! + \internal +*/ +void QTextFrame::setLayoutData(QTextFrameLayoutData *data) +{ + Q_D(QTextFrame); + delete d->layoutData; + d->layoutData = data; +} + + + +void QTextFramePrivate::fragmentAdded(const QChar &type, uint fragment) +{ + if (type == QTextBeginningOfFrame) { + Q_ASSERT(!fragment_start); + fragment_start = fragment; + } else if (type == QTextEndOfFrame) { + Q_ASSERT(!fragment_end); + fragment_end = fragment; + } else if (type == QChar::ObjectReplacementCharacter) { + Q_ASSERT(!fragment_start); + Q_ASSERT(!fragment_end); + fragment_start = fragment; + fragment_end = fragment; + } else { + Q_ASSERT(false); + } +} + +void QTextFramePrivate::fragmentRemoved(const QChar &type, uint fragment) +{ + Q_UNUSED(fragment); // --release warning + if (type == QTextBeginningOfFrame) { + Q_ASSERT(fragment_start == fragment); + fragment_start = 0; + } else if (type == QTextEndOfFrame) { + Q_ASSERT(fragment_end == fragment); + fragment_end = 0; + } else if (type == QChar::ObjectReplacementCharacter) { + Q_ASSERT(fragment_start == fragment); + Q_ASSERT(fragment_end == fragment); + fragment_start = 0; + fragment_end = 0; + } else { + Q_ASSERT(false); + } + remove_me(); +} + + +void QTextFramePrivate::remove_me() +{ + Q_Q(QTextFrame); + if (fragment_start == 0 && fragment_end == 0 + && !parentFrame) { + q->document()->docHandle()->deleteObject(q); + return; + } + + if (!parentFrame) + return; + + int index = parentFrame->d_func()->childFrames.indexOf(q); + + // iterator over all children and move them to the parent + for (int i = 0; i < childFrames.size(); ++i) { + QTextFrame *c = childFrames.at(i); + parentFrame->d_func()->childFrames.insert(index, c); + c->d_func()->parentFrame = parentFrame; + ++index; + } + Q_ASSERT(parentFrame->d_func()->childFrames.at(index) == q); + parentFrame->d_func()->childFrames.removeAt(index); + + childFrames.clear(); + parentFrame = 0; +} + +/*! + \class QTextFrame::iterator + \reentrant + + \brief The iterator class provides an iterator for reading + the contents of a QTextFrame. + + \ingroup richtext-processing + + A frame consists of an arbitrary sequence of \l{QTextBlock}s and + child \l{QTextFrame}s. This class provides a way to iterate over the + child objects of a frame, and read their contents. It does not provide + a way to modify the contents of the frame. + +*/ + +/*! + \fn bool QTextFrame::iterator::atEnd() const + + Returns true if the current item is the last item in the text frame. +*/ + +/*! + Returns an iterator pointing to the first document element inside the frame. + + \sa end() +*/ +QTextFrame::iterator QTextFrame::begin() const +{ + const QTextDocumentPrivate *priv = docHandle(); + int b = priv->blockMap().findNode(firstPosition()); + int e = priv->blockMap().findNode(lastPosition()+1); + return iterator(const_cast(this), b, b, e); +} + +/*! + Returns an iterator pointing to the last document element inside the frame. + + \sa begin() +*/ +QTextFrame::iterator QTextFrame::end() const +{ + const QTextDocumentPrivate *priv = docHandle(); + int b = priv->blockMap().findNode(firstPosition()); + int e = priv->blockMap().findNode(lastPosition()+1); + return iterator(const_cast(this), e, b, e); +} + +/*! + Constructs an invalid iterator. +*/ +QTextFrame::iterator::iterator() +{ + f = 0; + b = 0; + e = 0; + cf = 0; + cb = 0; +} + +/*! + \internal +*/ +QTextFrame::iterator::iterator(QTextFrame *frame, int block, int begin, int end) +{ + f = frame; + b = begin; + e = end; + cf = 0; + cb = block; +} + +/*! + Copy constructor. Constructs a copy of the \a other iterator. +*/ +QTextFrame::iterator::iterator(const iterator &other) +{ + f = other.f; + b = other.b; + e = other.e; + cf = other.cf; + cb = other.cb; +} + +/*! + Assigns \a other to this iterator and returns a reference to + this iterator. +*/ +QTextFrame::iterator &QTextFrame::iterator::operator=(const iterator &other) +{ + f = other.f; + b = other.b; + e = other.e; + cf = other.cf; + cb = other.cb; + return *this; +} + +/*! + Returns the current frame pointed to by the iterator, or 0 if the + iterator currently points to a block. + + \sa currentBlock() +*/ +QTextFrame *QTextFrame::iterator::currentFrame() const +{ + return cf; +} + +/*! + Returns the current block the iterator points to. If the iterator + points to a child frame, the returned block is invalid. + + \sa currentFrame() +*/ +QTextBlock QTextFrame::iterator::currentBlock() const +{ + if (!f) + return QTextBlock(); + return QTextBlock(f->docHandle(), cb); +} + +/*! + Moves the iterator to the next frame or block. + + \sa currentBlock() currentFrame() +*/ +QTextFrame::iterator &QTextFrame::iterator::operator++() +{ + const QTextDocumentPrivate *priv = f->docHandle(); + const QTextDocumentPrivate::BlockMap &map = priv->blockMap(); + if (cf) { + int end = cf->lastPosition() + 1; + cb = map.findNode(end); + cf = 0; + } else if (cb) { + cb = map.next(cb); + if (cb == e) + return *this; + + if (!f->d_func()->childFrames.isEmpty()) { + int pos = map.position(cb); + // check if we entered a frame + QTextDocumentPrivate::FragmentIterator frag = priv->find(pos-1); + if (priv->buffer().at(frag->stringPosition) != QChar::ParagraphSeparator) { + QTextFrame *nf = qobject_cast(priv->objectForFormat(frag->format)); + if (nf) { + if (priv->buffer().at(frag->stringPosition) == QTextBeginningOfFrame && nf != f) { + cf = nf; + cb = 0; + } else { + Q_ASSERT(priv->buffer().at(frag->stringPosition) != QTextEndOfFrame); + } + } + } + } + } + return *this; +} + +/*! + Moves the iterator to the previous frame or block. + + \sa currentBlock() currentFrame() +*/ +QTextFrame::iterator &QTextFrame::iterator::operator--() +{ + const QTextDocumentPrivate *priv = f->docHandle(); + const QTextDocumentPrivate::BlockMap &map = priv->blockMap(); + if (cf) { + int start = cf->firstPosition() - 1; + cb = map.findNode(start); + cf = 0; + } else { + if (cb == b) + goto end; + if (cb != e) { + int pos = map.position(cb); + // check if we have to enter a frame + QTextDocumentPrivate::FragmentIterator frag = priv->find(pos-1); + if (priv->buffer().at(frag->stringPosition) != QChar::ParagraphSeparator) { + QTextFrame *pf = qobject_cast(priv->objectForFormat(frag->format)); + if (pf) { + if (priv->buffer().at(frag->stringPosition) == QTextBeginningOfFrame) { + Q_ASSERT(pf == f); + } else if (priv->buffer().at(frag->stringPosition) == QTextEndOfFrame) { + Q_ASSERT(pf != f); + cf = pf; + cb = 0; + goto end; + } + } + } + } + cb = map.previous(cb); + } + end: + return *this; +} + +/*! + \class QTextBlockUserData + \reentrant + + \brief The QTextBlockUserData class is used to associate custom data with blocks of text. + \since 4.1 + + \ingroup richtext-processing + + QTextBlockUserData provides an abstract interface for container classes that are used + to associate application-specific user data with text blocks in a QTextDocument. + + Generally, subclasses of this class provide functions to allow data to be stored + and retrieved, and instances are attached to blocks of text using + QTextBlock::setUserData(). This makes it possible to store additional data per text + block in a way that can be retrieved safely by the application. + + Each subclass should provide a reimplementation of the destructor to ensure that any + private data is automatically cleaned up when user data objects are deleted. + + \sa QTextBlock +*/ + +/*! + Destroys the user data. +*/ +QTextBlockUserData::~QTextBlockUserData() +{ +} + +/*! + \class QTextBlock + \reentrant + + \brief The QTextBlock class provides a container for text fragments in a + QTextDocument. + + \ingroup richtext-processing + + A text block encapsulates a block or paragraph of text in a QTextDocument. + QTextBlock provides read-only access to the block/paragraph structure of + QTextDocuments. It is mainly of use if you want to implement your own + layouts for the visual representation of a QTextDocument, or if you want to + iterate over a document and write out the contents in your own custom + format. + + Text blocks are created by their parent documents. If you need to create + a new text block, or modify the contents of a document while examining its + contents, use the cursor-based interface provided by QTextCursor instead. + + Each text block is located at a specific position() in a document(). + The contents of the block can be obtained by using the text() function. + The length() function determines the block's size within the document + (including formatting characters). + The visual properties of the block are determined by its text layout(), + its charFormat(), and its blockFormat(). + + The next() and previous() functions enable iteration over consecutive + valid blocks in a document under the condition that the document is not + modified by other means during the iteration process. Note that, although + blocks are returned in sequence, adjacent blocks may come from different + places in the document structure. The validity of a block can be determined + by calling isValid(). + + QTextBlock provides comparison operators to make it easier to work with + blocks: \l operator==() compares two block for equality, \l operator!=() + compares two blocks for inequality, and \l operator<() determines whether + a block precedes another in the same document. + + \img qtextblock-sequence.png + + \sa QTextBlockFormat QTextCharFormat QTextFragment + */ + +/*! + \fn QTextBlock::QTextBlock(QTextDocumentPrivate *priv, int b) + + \internal +*/ + +/*! + \fn QTextBlock::QTextBlock() + + \internal +*/ + +/*! + \fn QTextBlock::QTextBlock(const QTextBlock &other) + + Copies the \a other text block's attributes to this text block. +*/ + +/*! + \fn bool QTextBlock::isValid() const + + Returns true if this text block is valid; otherwise returns false. +*/ + +/*! + \fn QTextBlock &QTextBlock::operator=(const QTextBlock &other) + + Assigns the \a other text block to this text block. +*/ + +/*! + \fn bool QTextBlock::operator==(const QTextBlock &other) const + + Returns true if this text block is the same as the \a other text + block. +*/ + +/*! + \fn bool QTextBlock::operator!=(const QTextBlock &other) const + + Returns true if this text block is different from the \a other + text block. +*/ + +/*! + \fn bool QTextBlock::operator<(const QTextBlock &other) const + + Returns true if this text block occurs before the \a other text + block in the document. +*/ + +/*! + \class QTextBlock::iterator + \reentrant + + \brief The QTextBlock::iterator class provides an iterator for reading + the contents of a QTextBlock. + + \ingroup richtext-processing + + A block consists of a sequence of text fragments. This class provides + a way to iterate over these, and read their contents. It does not provide + a way to modify the internal structure or contents of the block. + + An iterator can be constructed and used to access the fragments within + a text block in the following way: + + \snippet doc/src/snippets/textblock-fragments/xmlwriter.cpp 4 + \snippet doc/src/snippets/textblock-fragments/xmlwriter.cpp 7 + + \sa QTextFragment +*/ + +/*! + \typedef QTextBlock::Iterator + + Qt-style synonym for QTextBlock::iterator. +*/ + +/*! + \fn QTextBlock::iterator::iterator() + + Constructs an iterator for this text block. +*/ + +/*! + \fn QTextBlock::iterator::iterator(const iterator &other) + + Copy constructor. Constructs a copy of the \a other iterator. +*/ + +/*! + \fn bool QTextBlock::iterator::atEnd() const + + Returns true if the current item is the last item in the text block. +*/ + +/*! + \fn bool QTextBlock::iterator::operator==(const iterator &other) const + + Retuns true if this iterator is the same as the \a other iterator; + otherwise returns false. +*/ + +/*! + \fn bool QTextBlock::iterator::operator!=(const iterator &other) const + + Retuns true if this iterator is different from the \a other iterator; + otherwise returns false. +*/ + +/*! + \fn QTextBlock::iterator QTextBlock::iterator::operator++(int) + + The postfix ++ operator (\c{i++}) advances the iterator to the + next item in the text block and returns an iterator to the old current + item. +*/ + +/*! + \fn QTextBlock::iterator QTextBlock::iterator::operator--(int) + + The postfix -- operator (\c{i--}) makes the preceding item current and + returns an iterator to the old current item. +*/ + +/*! + \fn QTextDocumentPrivate *QTextBlock::docHandle() const + + \internal +*/ + +/*! + \fn int QTextBlock::fragmentIndex() const + + \internal +*/ + +/*! + Returns the index of the block's first character within the document. + */ +int QTextBlock::position() const +{ + if (!p || !n) + return 0; + + return p->blockMap().position(n); +} + +/*! + Returns the length of the block in characters. + + \note The length returned includes all formatting characters, + for example, newline. + + \sa text() charFormat() blockFormat() + */ +int QTextBlock::length() const +{ + if (!p || !n) + return 0; + + return p->blockMap().size(n); +} + +/*! + Returns true if the given \a position is located within the text + block; otherwise returns false. + */ +bool QTextBlock::contains(int position) const +{ + if (!p || !n) + return false; + + int pos = p->blockMap().position(n); + int len = p->blockMap().size(n); + return position >= pos && position < pos + len; +} + +/*! + Returns the QTextLayout that is used to lay out and display the + block's contents. + + Note that the returned QTextLayout object can only be modified from the + documentChanged implementation of a QAbstractTextDocumentLayout subclass. + Any changes applied from the outside cause undefined behavior. + + \sa clearLayout() + */ +QTextLayout *QTextBlock::layout() const +{ + if (!p || !n) + return 0; + + const QTextBlockData *b = p->blockMap().fragment(n); + if (!b->layout) + b->layout = new QTextLayout(*this); + return b->layout; +} + +/*! + \since 4.4 + Clears the QTextLayout that is used to lay out and display the + block's contents. + + \sa layout() + */ +void QTextBlock::clearLayout() +{ + if (!p || !n) + return; + + const QTextBlockData *b = p->blockMap().fragment(n); + if (b->layout) + b->layout->clearLayout(); +} + +/*! + Returns the QTextBlockFormat that describes block-specific properties. + + \sa charFormat() + */ +QTextBlockFormat QTextBlock::blockFormat() const +{ + if (!p || !n) + return QTextFormat().toBlockFormat(); + + return p->formatCollection()->blockFormat(p->blockMap().fragment(n)->format); +} + +/*! + Returns an index into the document's internal list of block formats + for the text block's format. + + \sa QTextDocument::allFormats() +*/ +int QTextBlock::blockFormatIndex() const +{ + if (!p || !n) + return -1; + + return p->blockMap().fragment(n)->format; +} + +/*! + Returns the QTextCharFormat that describes the block's character + format. The block's character format is used when inserting text into + an empty block. + + \sa blockFormat() + */ +QTextCharFormat QTextBlock::charFormat() const +{ + if (!p || !n) + return QTextFormat().toCharFormat(); + + return p->formatCollection()->charFormat(charFormatIndex()); +} + +/*! + Returns an index into the document's internal list of character formats + for the text block's character format. + + \sa QTextDocument::allFormats() +*/ +int QTextBlock::charFormatIndex() const +{ + if (!p || !n) + return -1; + + return p->blockCharFormatIndex(n); +} + +/*! + Returns the block's contents as plain text. + + \sa length() charFormat() blockFormat() + */ +QString QTextBlock::text() const +{ + if (!p || !n) + return QString(); + + const QString buffer = p->buffer(); + QString text; + text.reserve(length()); + + const int pos = position(); + QTextDocumentPrivate::FragmentIterator it = p->find(pos); + QTextDocumentPrivate::FragmentIterator end = p->find(pos + length() - 1); // -1 to omit the block separator char + for (; it != end; ++it) { + const QTextFragmentData * const frag = it.value(); + text += QString::fromRawData(buffer.constData() + frag->stringPosition, frag->size_array[0]); + } + + return text; +} + + +/*! + Returns the text document this text block belongs to, or 0 if the + text block does not belong to any document. +*/ +const QTextDocument *QTextBlock::document() const +{ + return p ? p->document() : 0; +} + +/*! + If the block represents a list item, returns the list that the item belongs + to; otherwise returns 0. +*/ +QTextList *QTextBlock::textList() const +{ + if (!isValid()) + return 0; + + const QTextBlockFormat fmt = blockFormat(); + QTextObject *obj = p->document()->objectForFormat(fmt); + return qobject_cast(obj); +} + +/*! + \since 4.1 + + Returns a pointer to a QTextBlockUserData object if previously set with + setUserData() or a null pointer. +*/ +QTextBlockUserData *QTextBlock::userData() const +{ + if (!p || !n) + return 0; + + const QTextBlockData *b = p->blockMap().fragment(n); + return b->userData; +} + +/*! + \since 4.1 + + Attaches the given \a data object to the text block. + + QTextBlockUserData can be used to store custom settings. The + ownership is passed to the underlying text document, i.e. the + provided QTextBlockUserData object will be deleted if the + corresponding text block gets deleted. The user data object is + not stored in the undo history, so it will not be available after + undoing the deletion of a text block. + + For example, if you write a programming editor in an IDE, you may + want to let your user set breakpoints visually in your code for an + integrated debugger. In a programming editor a line of text + usually corresponds to one QTextBlock. The QTextBlockUserData + interface allows the developer to store data for each QTextBlock, + like for example in which lines of the source code the user has a + breakpoint set. Of course this could also be stored externally, + but by storing it inside the QTextDocument, it will for example be + automatically deleted when the user deletes the associated + line. It's really just a way to store custom information in the + QTextDocument without using custom properties in QTextFormat which + would affect the undo/redo stack. +*/ +void QTextBlock::setUserData(QTextBlockUserData *data) +{ + if (!p || !n) + return; + + const QTextBlockData *b = p->blockMap().fragment(n); + if (data != b->userData) + delete b->userData; + b->userData = data; +} + +/*! + \since 4.1 + + Returns the integer value previously set with setUserState() or -1. +*/ +int QTextBlock::userState() const +{ + if (!p || !n) + return -1; + + const QTextBlockData *b = p->blockMap().fragment(n); + return b->userState; +} + +/*! + \since 4.1 + + Stores the specified \a state integer value in the text block. This may be + useful for example in a syntax highlighter to store a text parsing state. +*/ +void QTextBlock::setUserState(int state) +{ + if (!p || !n) + return; + + const QTextBlockData *b = p->blockMap().fragment(n); + b->userState = state; +} + +/*! + \since 4.4 + + Returns the blocks revision. + + \sa setRevision(), QTextDocument::revision() +*/ +int QTextBlock::revision() const +{ + if (!p || !n) + return -1; + + const QTextBlockData *b = p->blockMap().fragment(n); + return b->revision; +} + +/*! + \since 4.4 + + Sets a blocks revision to \a rev. + + \sa revision(), QTextDocument::revision() +*/ +void QTextBlock::setRevision(int rev) +{ + if (!p || !n) + return; + + const QTextBlockData *b = p->blockMap().fragment(n); + b->revision = rev; +} + +/*! + \since 4.4 + + Returns true if the block is visible; otherwise returns false. + + \sa setVisible() +*/ +bool QTextBlock::isVisible() const +{ + if (!p || !n) + return true; + + const QTextBlockData *b = p->blockMap().fragment(n); + return !b->hidden; +} + +/*! + \since 4.4 + + Sets the block's visibility to \a visible. + + \sa isVisible() +*/ +void QTextBlock::setVisible(bool visible) +{ + if (!p || !n) + return; + + const QTextBlockData *b = p->blockMap().fragment(n); + b->hidden = !visible; +} + + +/*! +\since 4.4 + + Returns the number of this block, or -1 if the block is invalid. + + \sa QTextCursor::blockNumber() + +*/ +int QTextBlock::blockNumber() const +{ + if (!p || !n) + return -1; + return p->blockMap().position(n, 1); +} + +/*! +\since 4.5 + + Returns the first line number of this block, or -1 if the block is invalid. + Unless the layout supports it, the line number is identical to the block number. + + \sa QTextBlock::blockNumber() + +*/ +int QTextBlock::firstLineNumber() const +{ + if (!p || !n) + return -1; + return p->blockMap().position(n, 2); +} + + +/*! +\since 4.5 + +Sets the line count to \a count. + +\sa lineCount() +*/ +void QTextBlock::setLineCount(int count) +{ + if (!p || !n) + return; + p->blockMap().setSize(n, count, 2); +} +/*! +\since 4.5 + +Returns the line count. Not all document layouts support this feature. + +\sa setLineCount() + */ +int QTextBlock::lineCount() const +{ + if (!p || !n) + return -1; + return p->blockMap().size(n, 2); +} + + +/*! + Returns a text block iterator pointing to the beginning of the + text block. + + \sa end() +*/ +QTextBlock::iterator QTextBlock::begin() const +{ + if (!p || !n) + return iterator(); + + int pos = position(); + int len = length() - 1; // exclude the fragment that holds the paragraph separator + int b = p->fragmentMap().findNode(pos); + int e = p->fragmentMap().findNode(pos+len); + return iterator(p, b, e, b); +} + +/*! + Returns a text block iterator pointing to the end of the text + block. + + \sa begin() next() previous() +*/ +QTextBlock::iterator QTextBlock::end() const +{ + if (!p || !n) + return iterator(); + + int pos = position(); + int len = length() - 1; // exclude the fragment that holds the paragraph separator + int b = p->fragmentMap().findNode(pos); + int e = p->fragmentMap().findNode(pos+len); + return iterator(p, b, e, e); +} + + +/*! + Returns the text block in the document after this block, or an empty + text block if this is the last one. + + Note that the next block may be in a different frame or table to this block. + + \sa previous() begin() end() +*/ +QTextBlock QTextBlock::next() const +{ + if (!p) + return QTextBlock(); + + return QTextBlock(p, p->blockMap().next(n)); +} + +/*! + Returns the text block in the document before this block, or an empty text + block if this is the first one. + + Note that the next block may be in a different frame or table to this block. + + \sa next() begin() end() +*/ +QTextBlock QTextBlock::previous() const +{ + if (!p) + return QTextBlock(); + + return QTextBlock(p, p->blockMap().previous(n)); +} + + +/*! + Returns the text fragment the iterator currently points to. +*/ +QTextFragment QTextBlock::iterator::fragment() const +{ + int ne = n; + int formatIndex = p->fragmentMap().fragment(n)->format; + do { + ne = p->fragmentMap().next(ne); + } while (ne != e && p->fragmentMap().fragment(ne)->format == formatIndex); + return QTextFragment(p, n, ne); +} + +/*! + The prefix ++ operator (\c{++i}) advances the iterator to the + next item in the hash and returns an iterator to the new current + item. +*/ + +QTextBlock::iterator &QTextBlock::iterator::operator++() +{ + int ne = n; + int formatIndex = p->fragmentMap().fragment(n)->format; + do { + ne = p->fragmentMap().next(ne); + } while (ne != e && p->fragmentMap().fragment(ne)->format == formatIndex); + n = ne; + return *this; +} + +/*! + The prefix -- operator (\c{--i}) makes the preceding item + current and returns an iterator pointing to the new current item. +*/ + +QTextBlock::iterator &QTextBlock::iterator::operator--() +{ + n = p->fragmentMap().previous(n); + + if (n == b) + return *this; + + int formatIndex = p->fragmentMap().fragment(n)->format; + int last = n; + + while (n != b && p->fragmentMap().fragment(n)->format != formatIndex) { + last = n; + n = p->fragmentMap().previous(n); + } + + n = last; + return *this; +} + + +/*! + \class QTextFragment + \reentrant + + \brief The QTextFragment class holds a piece of text in a + QTextDocument with a single QTextCharFormat. + + \ingroup richtext-processing + + A text fragment describes a piece of text that is stored with a single + character format. Text in which the character format changes can be + represented by sequences of text fragments with different formats. + + If the user edits the text in a fragment and introduces a different + character format, the fragment's text will be split at each point where + the format changes, and new fragments will be created. + For example, changing the style of some text in the middle of a + sentence will cause the fragment to be broken into three separate fragments: + the first and third with the same format as before, and the second with + the new style. The first fragment will contain the text from the beginning + of the sentence, the second will contain the text from the middle, and the + third takes the text from the end of the sentence. + + \img qtextfragment-split.png + + A fragment's text and character format can be obtained with the text() + and charFormat() functions. The length() function gives the length of + the text in the fragment. position() gives the position in the document + of the start of the fragment. To determine whether the fragment contains + a particular position within the document, use the contains() function. + + \sa QTextDocument, {Rich Text Document Structure} +*/ + +/*! + \fn QTextFragment::QTextFragment(const QTextDocumentPrivate *priv, int f, int fe) + \internal +*/ + +/*! + \fn QTextFragment::QTextFragment() + + Creates a new empty text fragment. +*/ + +/*! + \fn QTextFragment::QTextFragment(const QTextFragment &other) + + Copies the content (text and format) of the \a other text fragment + to this text fragment. +*/ + +/*! + \fn QTextFragment &QTextFragment::operator=(const QTextFragment + &other) + + Assigns the content (text and format) of the \a other text fragment + to this text fragment. +*/ + +/*! + \fn bool QTextFragment::isValid() const + + Returns true if this is a valid text fragment (i.e. has a valid + position in a document); otherwise returns false. +*/ + +/*! + \fn bool QTextFragment::operator==(const QTextFragment &other) const + + Returns true if this text fragment is the same (at the same + position) as the \a other text fragment; otherwise returns false. +*/ + +/*! + \fn bool QTextFragment::operator!=(const QTextFragment &other) const + + Returns true if this text fragment is different (at a different + position) from the \a other text fragment; otherwise returns + false. +*/ + +/*! + \fn bool QTextFragment::operator<(const QTextFragment &other) const + + Returns true if this text fragment appears earlier in the document + than the \a other text fragment; otherwise returns false. +*/ + + +/*! + Returns the position of this text fragment in the document. +*/ +int QTextFragment::position() const +{ + if (!p || !n) + return 0; // ### -1 instead? + + return p->fragmentMap().position(n); +} + +/*! + Returns the number of characters in the text fragment. + + \sa text() +*/ +int QTextFragment::length() const +{ + if (!p || !n) + return 0; + + int len = 0; + int f = n; + while (f != ne) { + len += p->fragmentMap().size(f); + f = p->fragmentMap().next(f); + } + return len; +} + +/*! + Returns true if the text fragment contains the text at the given + \a position in the document; otherwise returns false. +*/ +bool QTextFragment::contains(int position) const +{ + if (!p || !n) + return false; + int pos = this->position(); + return position >= pos && position < pos + length(); +} + +/*! + Returns the text fragment's character format. + + \sa text() +*/ +QTextCharFormat QTextFragment::charFormat() const +{ + if (!p || !n) + return QTextCharFormat(); + const QTextFragmentData *data = p->fragmentMap().fragment(n); + return p->formatCollection()->charFormat(data->format); +} + +/*! + Returns an index into the document's internal list of character formats + for the text fragment's character format. + + \sa QTextDocument::allFormats() +*/ +int QTextFragment::charFormatIndex() const +{ + if (!p || !n) + return -1; + const QTextFragmentData *data = p->fragmentMap().fragment(n); + return data->format; +} + +/*! + Returns the text fragment's as plain text. + + \sa length(), charFormat() +*/ +QString QTextFragment::text() const +{ + if (!p || !n) + return QString(); + + QString result; + QString buffer = p->buffer(); + int f = n; + while (f != ne) { + const QTextFragmentData * const frag = p->fragmentMap().fragment(f); + result += QString(buffer.constData() + frag->stringPosition, frag->size_array[0]); + f = p->fragmentMap().next(f); + } + return result; +} + +QT_END_NAMESPACE