blob: 14fc117b26bbf9425aeee09ed574f8bb45618f4e [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2011 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$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $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<QTextDocument *>(parent());
}
/*!
\internal
*/
QTextDocumentPrivate *QTextObject::docHandle() const
{
return static_cast<const QTextDocument *>(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<QTextBlock> 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 *> 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.
Please see the document \l{STL-style-Iterators} for more information.
\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<QTextFrame *>(this), b, b, e);
}
/*!
Returns an iterator pointing to the position past the last document element inside the frame.
Please see the document \l{STL-Style Iterators} for more information.
\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<QTextFrame *>(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<QTextFrame *>(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<QTextFrame *>(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);
}
/*!
\since 4.7
Returns the resolved text direction.
If the block has no explicit direction set, it will resolve the
direction from the blocks content. Returns either Qt::LeftToRight
or Qt::RightToLeft.
\sa QTextFormat::layoutDirection(), QString::isRightToLeft(), Qt::LayoutDirection
*/
Qt::LayoutDirection QTextBlock::textDirection() const
{
Qt::LayoutDirection dir = blockFormat().layoutDirection();
if (dir != Qt::LayoutDirectionAuto)
return dir;
dir = p->defaultTextOption.textDirection();
if (dir != Qt::LayoutDirectionAuto)
return dir;
const QString buffer = p->buffer();
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();
const QChar *p = buffer.constData() + frag->stringPosition;
const QChar * const end = p + frag->size_array[0];
while (p < end) {
switch(QChar::direction(p->unicode()))
{
case QChar::DirL:
return Qt::LeftToRight;
case QChar::DirR:
case QChar::DirAL:
return Qt::RightToLeft;
default:
break;
}
++p;
}
}
return Qt::LeftToRight;
}
/*!
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<QTextList *>(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 (!isValid() || !p->blockMap().isValid(n))
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