1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <qabstracttextdocumentlayout.h>
43 #include <qtextformat.h>
44 #include "qtextdocument_p.h"
45 #include "qtextengine_p.h"
47 #include "qabstracttextdocumentlayout_p.h"
52 \class QAbstractTextDocumentLayout
55 \brief The QAbstractTextDocumentLayout class is an abstract base
56 class used to implement custom layouts for QTextDocuments.
58 \ingroup richtext-processing
60 The standard layout provided by Qt can handle simple word processing
61 including inline images, lists and tables.
63 Some applications, e.g., a word processor or a DTP application might need
64 more features than the ones provided by Qt's layout engine, in which case
65 you can subclass QAbstractTextDocumentLayout to provide custom layout
66 behavior for your text documents.
68 An instance of the QAbstractTextDocumentLayout subclass can be installed
69 on a QTextDocument object with the
70 \l{QTextDocument::}{setDocumentLayout()} function.
72 You can insert custom objects into a QTextDocument; see the
73 QTextObjectInterface class description for details.
75 \sa QTextObjectInterface
79 \class QTextObjectInterface
80 \brief The QTextObjectInterface class allows drawing of
81 custom text objects in \l{QTextDocument}s.
84 A text object describes the structure of one or more elements in a
85 text document; for instance, images imported from HTML are
86 implemented using text objects. A text object knows how to lay out
87 and draw its elements when a document is being rendered.
89 Qt allows custom text objects to be inserted into a document by
90 registering a custom \l{QTextCharFormat::objectType()}{object
91 type} with QTextCharFormat. A QTextObjectInterface must also be
92 implemented for this type and be
93 \l{QAbstractTextDocumentLayout::registerHandler()}{registered}
94 with the QAbstractTextDocumentLayout of the document. When the
95 object type is encountered while rendering a QTextDocument, the
96 intrinsicSize() and drawObject() functions of the interface are
99 The following list explains the required steps of inserting a
100 custom text object into a document:
103 \o Choose an \a objectType. The \a objectType is an integer with a
104 value greater or equal to QTextFormat::UserObject.
105 \o Create a QTextCharFormat object and set the object type to the
106 chosen type using the setObjectType() function.
107 \o Implement the QTextObjectInterface class.
108 \o Call QAbstractTextDocumentLayout::registerHandler() with an instance of your
109 QTextObjectInterface subclass to register your object type.
110 \o Insert QChar::ObjectReplacementCharacter with the aforementioned
111 QTextCharFormat of the chosen object type into the document.
112 As mentioned, the functions of QTextObjectInterface
113 \l{QTextObjectInterface::}{intrinsicSize()} and
114 \l{QTextObjectInterface::}{drawObject()} will then be called with the
115 QTextFormat as parameter whenever the replacement character is
119 A class implementing a text object needs to inherit both QObject
120 and QTextObjectInterface. QObject must be the first class
121 inherited. For instance:
123 \snippet examples/richtext/textobject/svgtextobject.h 1
125 The data of a text object is usually stored in the QTextCharFormat
126 using QTextCharFormat::setProperty(), and then retrieved with
127 QTextCharFormat::property().
129 \warning Copy and Paste operations ignore custom text objects.
131 \sa {Text Object Example}, QTextCharFormat, QTextLayout
135 \fn QTextObjectInterface::~QTextObjectInterface()
137 Destroys this QTextObjectInterface.
141 \fn virtual QSizeF QTextObjectInterface::intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) = 0
143 The intrinsicSize() function returns the size of the text object
144 represented by \a format in the given document (\a doc) at the
145 given position (\a posInDocument).
147 The size calculated will be used for subsequent calls to
148 drawObject() for this \a format.
154 \fn virtual void QTextObjectInterface::drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format) = 0
156 Draws this text object using the specified \a painter.
158 The size of the rectangle, \a rect, to draw in is the size
159 previously calculated by intrinsicSize(). The rectangles position
160 is relative to the \a painter.
162 You also get the document (\a doc) and the position (\a
163 posInDocument) of the \a format in that document.
169 \fn void QAbstractTextDocumentLayout::update(const QRectF &rect)
171 This signal is emitted when the rectangle \a rect has been updated.
173 Subclasses of QAbstractTextDocumentLayout should emit this signal when
174 the layout of the contents change in order to repaint.
178 \fn void QAbstractTextDocumentLayout::updateBlock(const QTextBlock &block)
181 This signal is emitted when the specified \a block has been updated.
183 Subclasses of QAbstractTextDocumentLayout should emit this signal when
184 the layout of \a block has changed in order to repaint.
188 \fn void QAbstractTextDocumentLayout::documentSizeChanged(const QSizeF &newSize)
190 This signal is emitted when the size of the document layout changes to
193 Subclasses of QAbstractTextDocumentLayout should emit this signal when the
194 document's entire layout size changes. This signal is useful for widgets
195 that display text documents since it enables them to update their scroll
202 \fn void QAbstractTextDocumentLayout::pageCountChanged(int newPages)
204 This signal is emitted when the number of pages in the layout changes;
205 \a newPages is the updated page count.
207 Subclasses of QAbstractTextDocumentLayout should emit this signal when
208 the number of pages in the layout has changed. Changes to the page count
209 are caused by changes to the layout or the document content itself.
215 \fn int QAbstractTextDocumentLayout::pageCount() const
217 Returns the number of pages contained in the layout.
219 \sa pageCountChanged()
223 \fn QSizeF QAbstractTextDocumentLayout::documentSize() const
225 Returns the total size of the document's layout.
227 This information can be used by display widgets to update their scroll bars
230 \sa documentSizeChanged(), QTextDocument::pageSize
234 \fn void QAbstractTextDocumentLayout::draw(QPainter *painter, const PaintContext &context)
236 Draws the layout with the given \a painter using the given \a context.
240 \fn int QAbstractTextDocumentLayout::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
242 Returns the cursor postion for the given \a point with the specified
243 \a accuracy. Returns -1 if no valid cursor position was found.
247 \fn void QAbstractTextDocumentLayout::documentChanged(int position, int charsRemoved, int charsAdded)
249 This function is called whenever the contents of the document change. A
250 change occurs when text is inserted, removed, or a combination of these
251 two. The change is specified by \a position, \a charsRemoved, and
252 \a charsAdded corresponding to the starting character position of the
253 change, the number of characters removed from the document, and the
254 number of characters added.
256 For example, when inserting the text "Hello" into an empty document,
257 \a charsRemoved would be 0 and \a charsAdded would be 5 (the length of
260 Replacing text is a combination of removing and inserting. For example, if
261 the text "Hello" gets replaced by "Hi", \a charsRemoved would be 5 and
262 \a charsAdded would be 2.
264 For subclasses of QAbstractTextDocumentLayout, this is the central function
265 where a large portion of the work to lay out and position document contents
268 For example, in a subclass that only arranges blocks of text, an
269 implementation of this function would have to do the following:
272 \o Determine the list of changed \l{QTextBlock}(s) using the parameters
274 \o Each QTextBlock object's corresponding QTextLayout object needs to
275 be processed. You can access the \l{QTextBlock}'s layout using the
276 QTextBlock::layout() function. This processing should take the
277 document's page size into consideration.
278 \o If the total number of pages changed, the pageCountChanged() signal
280 \o If the total size changed, the documentSizeChanged() signal should
282 \o The update() signal should be emitted to schedule a repaint of areas
283 in the layout that require repainting.
290 \class QAbstractTextDocumentLayout::PaintContext
293 \brief The QAbstractTextDocumentLayout::PaintContext class is a convenience
294 class defining the parameters used when painting a document's layout.
296 A paint context is used when rendering custom layouts for QTextDocuments
297 with the QAbstractTextDocumentLayout::draw() function. It is specified by
298 a \l {cursorPosition}{cursor position}, \l {palette}{default text color},
299 \l clip rectangle and a collection of \l selections.
301 \sa QAbstractTextDocumentLayout
305 \fn QAbstractTextDocumentLayout::PaintContext::PaintContext()
310 \variable QAbstractTextDocumentLayout::PaintContext::cursorPosition
312 \brief the position within the document, where the cursor line should be
315 The default value is -1.
319 \variable QAbstractTextDocumentLayout::PaintContext::palette
321 \brief the default color that is used for the text, when no color is
324 The default value is the application's default palette.
328 \variable QAbstractTextDocumentLayout::PaintContext::clip
330 \brief a hint to the layout specifying the area around paragraphs, frames
331 or text require painting.
333 Everything outside of this rectangle does not need to be painted.
335 Specifying a clip rectangle can speed up drawing of large documents
336 significantly. Note that the clip rectangle is in document coordinates (not
337 in viewport coordinates). It is not a substitute for a clip region set on
338 the painter but merely a hint.
340 The default value is a null rectangle indicating everything needs to be
345 \variable QAbstractTextDocumentLayout::PaintContext::selections
347 \brief the collection of selections that will be rendered when passing this
348 paint context to QAbstractTextDocumentLayout's draw() function.
350 The default value is an empty vector indicating no selection.
354 \class QAbstractTextDocumentLayout::Selection
357 \brief The QAbstractTextDocumentLayout::Selection class is a convenience
358 class defining the parameters of a selection.
360 A selection can be used to specify a part of a document that should be
361 highlighted when drawing custom layouts for QTextDocuments with the
362 QAbstractTextDocumentLayout::draw() function. It is specified using
363 \l cursor and a \l format.
365 \sa QAbstractTextDocumentLayout, PaintContext
369 \variable QAbstractTextDocumentLayout::Selection::format
371 \brief the format of the selection
373 The default value is QTextFormat::InvalidFormat.
377 \variable QAbstractTextDocumentLayout::Selection::cursor
378 \brief the selection's cursor
380 The default value is a null cursor.
384 Creates a new text document layout for the given \a document.
386 QAbstractTextDocumentLayout::QAbstractTextDocumentLayout(QTextDocument *document)
387 : QObject(*new QAbstractTextDocumentLayoutPrivate, document)
389 Q_D(QAbstractTextDocumentLayout);
390 d->setDocument(document);
396 QAbstractTextDocumentLayout::QAbstractTextDocumentLayout(QAbstractTextDocumentLayoutPrivate &p, QTextDocument *document)
397 :QObject(p, document)
399 Q_D(QAbstractTextDocumentLayout);
400 d->setDocument(document);
406 QAbstractTextDocumentLayout::~QAbstractTextDocumentLayout()
411 \fn void QAbstractTextDocumentLayout::registerHandler(int objectType, QObject *component)
413 Registers the given \a component as a handler for items of the given \a objectType.
415 \note registerHandler() has to be called once for each object type. This
416 means that there is only one handler for multiple replacement characters
417 of the same object type.
419 void QAbstractTextDocumentLayout::registerHandler(int formatType, QObject *component)
421 Q_D(QAbstractTextDocumentLayout);
423 QTextObjectInterface *iface = qobject_cast<QTextObjectInterface *>(component);
425 return; // ### print error message on terminal?
427 connect(component, SIGNAL(destroyed(QObject*)), this, SLOT(_q_handlerDestroyed(QObject*)));
429 QTextObjectHandler h;
431 h.component = component;
432 d->handlers.insert(formatType, h);
436 Returns a handler for objects of the given \a objectType.
438 QTextObjectInterface *QAbstractTextDocumentLayout::handlerForObject(int objectType) const
440 Q_D(const QAbstractTextDocumentLayout);
442 QTextObjectHandler handler = d->handlers.value(objectType);
443 if (!handler.component)
446 return handler.iface;
450 Sets the size of the inline object \a item corresponding to the text
453 \a posInDocument specifies the position of the object within the document.
455 The default implementation resizes the \a item to the size returned by
456 the object handler's intrinsicSize() function. This function is called only
457 within Qt. Subclasses can reimplement this function to customize the
458 resizing of inline objects.
460 void QAbstractTextDocumentLayout::resizeInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format)
462 Q_D(QAbstractTextDocumentLayout);
464 QTextCharFormat f = format.toCharFormat();
465 Q_ASSERT(f.isValid());
466 QTextObjectHandler handler = d->handlers.value(f.objectType());
467 if (!handler.component)
470 QSizeF s = handler.iface->intrinsicSize(document(), posInDocument, format);
471 item.setWidth(s.width());
472 item.setAscent(s.height() - 1);
477 Lays out the inline object \a item using the given text \a format.
479 \a posInDocument specifies the position of the object within the document.
481 The default implementation does nothing. This function is called only
482 within Qt. Subclasses can reimplement this function to customize the
483 position of inline objects.
485 \sa drawInlineObject()
487 void QAbstractTextDocumentLayout::positionInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format)
490 Q_UNUSED(posInDocument);
495 \fn void QAbstractTextDocumentLayout::drawInlineObject(QPainter *painter, const QRectF &rect, QTextInlineObject object, int posInDocument, const QTextFormat &format)
497 This function is called to draw the inline object, \a object, with the
498 given \a painter within the rectangle specified by \a rect using the
499 specified text \a format.
501 \a posInDocument specifies the position of the object within the document.
503 The default implementation calls drawObject() on the object handlers. This
504 function is called only within Qt. Subclasses can reimplement this function
505 to customize the drawing of inline objects.
509 void QAbstractTextDocumentLayout::drawInlineObject(QPainter *p, const QRectF &rect, QTextInlineObject item,
510 int posInDocument, const QTextFormat &format)
513 Q_D(QAbstractTextDocumentLayout);
515 QTextCharFormat f = format.toCharFormat();
516 Q_ASSERT(f.isValid());
517 QTextObjectHandler handler = d->handlers.value(f.objectType());
518 if (!handler.component)
521 handler.iface->drawObject(p, rect, document(), posInDocument, format);
524 void QAbstractTextDocumentLayoutPrivate::_q_handlerDestroyed(QObject *obj)
526 HandlerHash::Iterator it = handlers.begin();
527 while (it != handlers.end())
528 if ((*it).component == obj)
529 it = handlers.erase(it);
537 Returns the index of the format at position \a pos.
539 int QAbstractTextDocumentLayout::formatIndex(int pos)
541 QTextDocumentPrivate *pieceTable = qobject_cast<QTextDocument *>(parent())->docHandle();
542 return pieceTable->find(pos).value()->format;
546 \fn QTextCharFormat QAbstractTextDocumentLayout::format(int position)
548 Returns the character format that is applicable at the given \a position.
550 QTextCharFormat QAbstractTextDocumentLayout::format(int pos)
552 QTextDocumentPrivate *pieceTable = qobject_cast<QTextDocument *>(parent())->docHandle();
553 int idx = pieceTable->find(pos).value()->format;
554 return pieceTable->formatCollection()->charFormat(idx);
560 Returns the text document that this layout is operating on.
562 QTextDocument *QAbstractTextDocumentLayout::document() const
564 Q_D(const QAbstractTextDocumentLayout);
569 \fn QString QAbstractTextDocumentLayout::anchorAt(const QPointF &position) const
571 Returns the reference of the anchor the given \a position, or an empty
572 string if no anchor exists at that point.
574 QString QAbstractTextDocumentLayout::anchorAt(const QPointF& pos) const
576 int cursorPos = hitTest(pos, Qt::ExactHit);
580 QTextDocumentPrivate *pieceTable = qobject_cast<const QTextDocument *>(parent())->docHandle();
581 QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos);
582 QTextCharFormat fmt = pieceTable->formatCollection()->charFormat(it->format);
583 return fmt.anchorHref();
587 \fn QRectF QAbstractTextDocumentLayout::frameBoundingRect(QTextFrame *frame) const
589 Returns the bounding rectangle of \a frame.
593 \fn QRectF QAbstractTextDocumentLayout::blockBoundingRect(const QTextBlock &block) const
595 Returns the bounding rectangle of \a block.
599 Sets the paint device used for rendering the document's layout to the given
604 void QAbstractTextDocumentLayout::setPaintDevice(QPaintDevice *device)
606 Q_D(QAbstractTextDocumentLayout);
607 d->paintDevice = device;
611 Returns the paint device used to render the document's layout.
615 QPaintDevice *QAbstractTextDocumentLayout::paintDevice() const
617 Q_D(const QAbstractTextDocumentLayout);
618 return d->paintDevice;
623 #include "moc_qabstracttextdocumentlayout.cpp"