source: trunk/src/gui/text/qabstracttextdocumentlayout.cpp@ 318

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

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

File size: 20.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <qabstracttextdocumentlayout.h>
43#include <qtextformat.h>
44#include "qtextdocument_p.h"
45#include "qtextengine_p.h"
46
47#include "qabstracttextdocumentlayout_p.h"
48
49QT_BEGIN_NAMESPACE
50
51/*!
52 \class QAbstractTextDocumentLayout
53 \reentrant
54
55 \brief The QAbstractTextDocumentLayout class is an abstract base
56 class used to implement custom layouts for QTextDocuments.
57
58 \ingroup text
59
60 The standard layout provided by Qt can handle simple word processing
61 including inline images, lists and tables.
62
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.
67
68 An instance of the QAbstractTextDocumentLayout subclass can be installed
69 on a QTextDocument object with the
70 \l{QTextDocument::}{setDocumentLayout()} function.
71
72 You can insert custom objects into a QTextDocument; see the
73 QTextObjectInterface class description for details.
74
75 \sa QTextObjectInterface
76*/
77
78/*!
79 \class QTextObjectInterface
80 \brief The QTextObjectInterface class allows drawing of
81 custom text objects in \l{QTextDocument}s.
82
83 A text object describes the structure of one or more elements in a
84 text document; for instance, images imported from HTML are
85 implemented using text objects. A text object knows how to lay out
86 and draw its elements when a document is being rendered.
87
88 Qt allows custom text objects to be inserted into a document by
89 registering a custom \l{QTextCharFormat::objectType()}{object
90 type} with QTextCharFormat. A QTextObjectInterface must also be
91 implemented for this type and be
92 \l{QAbstractTextDocumentLayout::registerHandler()}{registered}
93 with the QAbstractTextDocumentLayout of the document. When the
94 object type is encountered while rendering a QTextDocument, the
95 intrinsicSize() and drawObject() functions of the interface are
96 called.
97
98 The following list explains the required steps of inserting a
99 custom text object into a document:
100
101 \list
102 \o Choose an \a objectType. The \a objectType is an integer with a
103 value greater or equal to QTextFormat::UserObject.
104 \o Create a QTextCharFormat object and set the object type to the
105 chosen type using the setObjectType() function.
106 \o Implement the QTextObjectInterface class.
107 \o Call QAbstractTextDocumentLayout::registerHandler() with an instance of your
108 QTextObjectInterface subclass to register your object type.
109 \o Insert QChar::ObjectReplacementCharacter with the aforementioned
110 QTextCharFormat of the chosen object type into the document.
111 As mentioned, the functions of QTextObjectInterface
112 \l{QTextObjectInterface::}{intrinsicSize()} and
113 \l{QTextObjectInterface::}{drawObject()} will then be called with the
114 QTextFormat as parameter whenever the replacement character is
115 encountered.
116 \endlist
117
118 A class implementing a text object needs to inherit both QObject
119 and QTextObjectInterface. QObject must be the first class
120 inherited. For instance:
121
122 \snippet examples/richtext/textobject/svgtextobject.h 1
123
124 The data of a text object is usually stored in the QTextCharFormat
125 using QTextCharFormat::setProperty(), and then retrieved with
126 QTextCharFormat::property().
127
128 \warning Copy and Paste operations ignore custom text objects.
129
130 \sa {Text Object Example}, QTextCharFormat, QTextLayout
131*/
132
133/*!
134 \fn QTextObjectInterface::~QTextObjectInterface()
135
136 Destroys this QTextObjectInterface.
137*/
138
139/*!
140 \fn virtual QSizeF QTextObjectInterface::intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) = 0
141
142 The intrinsicSize() function returns the size of the text object
143 represented by \a format in the given document (\a doc) at the
144 given position (\a posInDocument).
145
146 The size calculated will be used for subsequent calls to
147 drawObject() for this \a format.
148
149 \sa drawObject()
150*/
151
152/*!
153 \fn virtual void QTextObjectInterface::drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format) = 0
154
155 Draws this text object using the specified \a painter.
156
157 The size of the rectangle, \a rect, to draw in is the size
158 previously calculated by intrinsicSize(). The rectangles position
159 is relative to the \a painter.
160
161 You also get the document (\a doc) and the position (\a
162 posInDocument) of the \a format in that document.
163
164 \sa intrinsicSize()
165*/
166
167/*!
168 \fn void QAbstractTextDocumentLayout::update(const QRectF &rect)
169
170 This signal is emitted when the rectangle \a rect has been updated.
171
172 Subclasses of QAbstractTextDocumentLayout should emit this signal when
173 the layout of the contents change in order to repaint.
174*/
175
176/*!
177 \fn void QAbstractTextDocumentLayout::updateBlock(const QTextBlock &block)
178 \since 4.4
179
180 This signal is emitted when the specified \a block has been updated.
181
182 Subclasses of QAbstractTextDocumentLayout should emit this signal when
183 the layout of \a block has changed in order to repaint.
184*/
185
186/*!
187 \fn void QAbstractTextDocumentLayout::documentSizeChanged(const QSizeF &newSize)
188
189 This signal is emitted when the size of the document layout changes to
190 \a newSize.
191
192 Subclasses of QAbstractTextDocumentLayout should emit this signal when the
193 document's entire layout size changes. This signal is useful for widgets
194 that display text documents since it enables them to update their scroll
195 bars correctly.
196
197 \sa documentSize()
198*/
199
200/*!
201 \fn void QAbstractTextDocumentLayout::pageCountChanged(int newPages)
202
203 This signal is emitted when the number of pages in the layout changes;
204 \a newPages is the updated page count.
205
206 Subclasses of QAbstractTextDocumentLayout should emit this signal when
207 the number of pages in the layout has changed. Changes to the page count
208 are caused by changes to the layout or the document content itself.
209
210 \sa pageCount()
211*/
212
213/*!
214 \fn int QAbstractTextDocumentLayout::pageCount() const
215
216 Returns the number of pages contained in the layout.
217
218 \sa pageCountChanged()
219*/
220
221/*!
222 \fn QSizeF QAbstractTextDocumentLayout::documentSize() const
223
224 Returns the total size of the document's layout.
225
226 This information can be used by display widgets to update their scroll bars
227 correctly.
228
229 \sa documentSizeChanged(), QTextDocument::pageSize
230*/
231
232/*!
233 \fn void QAbstractTextDocumentLayout::draw(QPainter *painter, const PaintContext &context)
234
235 Draws the layout with the given \a painter using the given \a context.
236*/
237
238/*!
239 \fn int QAbstractTextDocumentLayout::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
240
241 Returns the cursor postion for the given \a point with the specified
242 \a accuracy. Returns -1 if no valid cursor position was found.
243*/
244
245/*!
246 \fn void QAbstractTextDocumentLayout::documentChanged(int position, int charsRemoved, int charsAdded)
247
248 This function is called whenever the contents of the document change. A
249 change occurs when text is inserted, removed, or a combination of these
250 two. The change is specified by \a position, \a charsRemoved, and
251 \a charsAdded corresponding to the starting character position of the
252 change, the number of characters removed from the document, and the
253 number of characters added.
254
255 For example, when inserting the text "Hello" into an empty document,
256 \a charsRemoved would be 0 and \a charsAdded would be 5 (the length of
257 the string).
258
259 Replacing text is a combination of removing and inserting. For example, if
260 the text "Hello" gets replaced by "Hi", \a charsRemoved would be 5 and
261 \a charsAdded would be 2.
262
263 For subclasses of QAbstractTextDocumentLayout, this is the central function
264 where a large portion of the work to lay out and position document contents
265 is done.
266
267 For example, in a subclass that only arranges blocks of text, an
268 implementation of this function would have to do the following:
269
270 \list
271 \o Determine the list of changed \l{QTextBlock}(s) using the parameters
272 provided.
273 \o Each QTextBlock object's corresponding QTextLayout object needs to
274 be processed. You can access the \l{QTextBlock}'s layout using the
275 QTextBlock::layout() function. This processing should take the
276 document's page size into consideration.
277 \o If the total number of pages changed, the pageCountChanged() signal
278 should be emitted.
279 \o If the total size changed, the documentSizeChanged() signal should
280 be emitted.
281 \o The update() signal should be emitted to schedule a repaint of areas
282 in the layout that require repainting.
283 \endlist
284
285 \sa QTextLayout
286*/
287
288/*!
289 \class QAbstractTextDocumentLayout::PaintContext
290 \reentrant
291
292 \brief The QAbstractTextDocumentLayout::PaintContext class is a convenience
293 class defining the parameters used when painting a document's layout.
294
295 A paint context is used when rendering custom layouts for QTextDocuments
296 with the QAbstractTextDocumentLayout::draw() function. It is specified by
297 a \l {cursorPosition}{cursor position}, \l {palette}{default text color},
298 \l clip rectangle and a collection of \l selections.
299
300 \sa QAbstractTextDocumentLayout
301*/
302
303/*!
304 \fn QAbstractTextDocumentLayout::PaintContext::PaintContext()
305 \internal
306*/
307
308/*!
309 \variable QAbstractTextDocumentLayout::PaintContext::cursorPosition
310
311 \brief the position within the document, where the cursor line should be
312 drawn.
313
314 The default value is -1.
315*/
316
317/*!
318 \variable QAbstractTextDocumentLayout::PaintContext::palette
319
320 \brief the default color that is used for the text, when no color is
321 specified.
322
323 The default value is the application's default palette.
324*/
325
326/*!
327 \variable QAbstractTextDocumentLayout::PaintContext::clip
328
329 \brief a hint to the layout specifying the area around paragraphs, frames
330 or text require painting.
331
332 Everything outside of this rectangle does not need to be painted.
333
334 Specifying a clip rectangle can speed up drawing of large documents
335 significantly. Note that the clip rectangle is in document coordinates (not
336 in viewport coordinates). It is not a substitute for a clip region set on
337 the painter but merely a hint.
338
339 The default value is a null rectangle indicating everything needs to be
340 painted.
341*/
342
343/*!
344 \variable QAbstractTextDocumentLayout::PaintContext::selections
345
346 \brief the collection of selections that will be rendered when passing this
347 paint context to QAbstractTextDocumentLayout's draw() function.
348
349 The default value is an empty vector indicating no selection.
350*/
351
352/*!
353 \class QAbstractTextDocumentLayout::Selection
354 \reentrant
355
356 \brief The QAbstractTextDocumentLayout::Selection class is a convenience
357 class defining the parameters of a selection.
358
359 A selection can be used to specify a part of a document that should be
360 highlighted when drawing custom layouts for QTextDocuments with the
361 QAbstractTextDocumentLayout::draw() function. It is specified using
362 \l cursor and a \l format.
363
364 \sa QAbstractTextDocumentLayout, PaintContext
365*/
366
367/*!
368 \variable QAbstractTextDocumentLayout::Selection::format
369
370 \brief the format of the selection
371
372 The default value is QTextFormat::InvalidFormat.
373*/
374
375/*!
376 \variable QAbstractTextDocumentLayout::Selection::cursor
377 \brief the selection's cursor
378
379 The default value is a null cursor.
380*/
381
382/*!
383 Creates a new text document layout for the given \a document.
384*/
385QAbstractTextDocumentLayout::QAbstractTextDocumentLayout(QTextDocument *document)
386 : QObject(*new QAbstractTextDocumentLayoutPrivate, document)
387{
388 Q_D(QAbstractTextDocumentLayout);
389 d->setDocument(document);
390}
391
392/*!
393 \internal
394*/
395QAbstractTextDocumentLayout::QAbstractTextDocumentLayout(QAbstractTextDocumentLayoutPrivate &p, QTextDocument *document)
396 :QObject(p, document)
397{
398 Q_D(QAbstractTextDocumentLayout);
399 d->setDocument(document);
400}
401
402/*!
403 \internal
404*/
405QAbstractTextDocumentLayout::~QAbstractTextDocumentLayout()
406{
407}
408
409/*!
410 \fn void QAbstractTextDocumentLayout::registerHandler(int objectType, QObject *component)
411
412 Registers the given \a component as a handler for items of the given \a objectType.
413
414 \note registerHandler() has to be called once for each object type. This
415 means that there is only one handler for multiple replacement characters
416 of the same object type.
417*/
418void QAbstractTextDocumentLayout::registerHandler(int formatType, QObject *component)
419{
420 Q_D(QAbstractTextDocumentLayout);
421
422 QTextObjectInterface *iface = qobject_cast<QTextObjectInterface *>(component);
423 if (!iface)
424 return; // ### print error message on terminal?
425
426 connect(component, SIGNAL(destroyed(QObject*)), this, SLOT(_q_handlerDestroyed(QObject*)));
427
428 QTextObjectHandler h;
429 h.iface = iface;
430 h.component = component;
431 d->handlers.insert(formatType, h);
432}
433
434/*!
435 Returns a handler for objects of the given \a objectType.
436*/
437QTextObjectInterface *QAbstractTextDocumentLayout::handlerForObject(int objectType) const
438{
439 Q_D(const QAbstractTextDocumentLayout);
440
441 QTextObjectHandler handler = d->handlers.value(objectType);
442 if (!handler.component)
443 return 0;
444
445 return handler.iface;
446}
447
448/*!
449 Sets the size of the inline object \a item corresponding to the text
450 \a format.
451
452 \a posInDocument specifies the position of the object within the document.
453
454 The default implementation resizes the \a item to the size returned by
455 the object handler's intrinsicSize() function. This function is called only
456 within Qt. Subclasses can reimplement this function to customize the
457 resizing of inline objects.
458*/
459void QAbstractTextDocumentLayout::resizeInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format)
460{
461 Q_D(QAbstractTextDocumentLayout);
462
463 QTextCharFormat f = format.toCharFormat();
464 Q_ASSERT(f.isValid());
465 QTextObjectHandler handler = d->handlers.value(f.objectType());
466 if (!handler.component)
467 return;
468
469 QSizeF s = handler.iface->intrinsicSize(document(), posInDocument, format);
470 item.setWidth(s.width());
471 item.setAscent(s.height() - 1);
472 item.setDescent(0);
473}
474
475/*!
476 Lays out the inline object \a item using the given text \a format.
477
478 \a posInDocument specifies the position of the object within the document.
479
480 The default implementation does nothing. This function is called only
481 within Qt. Subclasses can reimplement this function to customize the
482 position of inline objects.
483
484 \sa drawInlineObject()
485*/
486void QAbstractTextDocumentLayout::positionInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format)
487{
488 Q_UNUSED(item);
489 Q_UNUSED(posInDocument);
490 Q_UNUSED(format);
491}
492
493/*!
494 \fn void QAbstractTextDocumentLayout::drawInlineObject(QPainter *painter, const QRectF &rect, QTextInlineObject object, int posInDocument, const QTextFormat &format)
495
496 This function is called to draw the inline object, \a object, with the
497 given \a painter within the rectangle specified by \a rect using the
498 specified text \a format.
499
500 \a posInDocument specifies the position of the object within the document.
501
502 The default implementation calls drawObject() on the object handlers. This
503 function is called only within Qt. Subclasses can reimplement this function
504 to customize the drawing of inline objects.
505
506 \sa draw()
507*/
508void QAbstractTextDocumentLayout::drawInlineObject(QPainter *p, const QRectF &rect, QTextInlineObject item,
509 int posInDocument, const QTextFormat &format)
510{
511 Q_UNUSED(item);
512 Q_D(QAbstractTextDocumentLayout);
513
514 QTextCharFormat f = format.toCharFormat();
515 Q_ASSERT(f.isValid());
516 QTextObjectHandler handler = d->handlers.value(f.objectType());
517 if (!handler.component)
518 return;
519
520 handler.iface->drawObject(p, rect, document(), posInDocument, format);
521}
522
523void QAbstractTextDocumentLayoutPrivate::_q_handlerDestroyed(QObject *obj)
524{
525 HandlerHash::Iterator it = handlers.begin();
526 while (it != handlers.end())
527 if ((*it).component == obj)
528 it = handlers.erase(it);
529 else
530 ++it;
531}
532
533/*!
534 \internal
535
536 Returns the index of the format at position \a pos.
537*/
538int QAbstractTextDocumentLayout::formatIndex(int pos)
539{
540 QTextDocumentPrivate *pieceTable = qobject_cast<QTextDocument *>(parent())->docHandle();
541 return pieceTable->find(pos).value()->format;
542}
543
544/*!
545 \fn QTextCharFormat QAbstractTextDocumentLayout::format(int position)
546
547 Returns the character format that is applicable at the given \a position.
548*/
549QTextCharFormat QAbstractTextDocumentLayout::format(int pos)
550{
551 QTextDocumentPrivate *pieceTable = qobject_cast<QTextDocument *>(parent())->docHandle();
552 int idx = pieceTable->find(pos).value()->format;
553 return pieceTable->formatCollection()->charFormat(idx);
554}
555
556
557
558/*!
559 Returns the text document that this layout is operating on.
560*/
561QTextDocument *QAbstractTextDocumentLayout::document() const
562{
563 Q_D(const QAbstractTextDocumentLayout);
564 return d->document;
565}
566
567/*!
568 \fn QString QAbstractTextDocumentLayout::anchorAt(const QPointF &position) const
569
570 Returns the reference of the anchor the given \a position, or an empty
571 string if no anchor exists at that point.
572*/
573QString QAbstractTextDocumentLayout::anchorAt(const QPointF& pos) const
574{
575 int cursorPos = hitTest(pos, Qt::ExactHit);
576 if (cursorPos == -1)
577 return QString();
578
579 QTextDocumentPrivate *pieceTable = qobject_cast<const QTextDocument *>(parent())->docHandle();
580 QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos);
581 QTextCharFormat fmt = pieceTable->formatCollection()->charFormat(it->format);
582 return fmt.anchorHref();
583}
584
585/*!
586 \fn QRectF QAbstractTextDocumentLayout::frameBoundingRect(QTextFrame *frame) const
587
588 Returns the bounding rectangle of \a frame.
589*/
590
591/*!
592 \fn QRectF QAbstractTextDocumentLayout::blockBoundingRect(const QTextBlock &block) const
593
594 Returns the bounding rectangle of \a block.
595*/
596
597/*!
598 Sets the paint device used for rendering the document's layout to the given
599 \a device.
600
601 \sa paintDevice()
602*/
603void QAbstractTextDocumentLayout::setPaintDevice(QPaintDevice *device)
604{
605 Q_D(QAbstractTextDocumentLayout);
606 d->paintDevice = device;
607}
608
609/*!
610 Returns the paint device used to render the document's layout.
611
612 \sa setPaintDevice()
613*/
614QPaintDevice *QAbstractTextDocumentLayout::paintDevice() const
615{
616 Q_D(const QAbstractTextDocumentLayout);
617 return d->paintDevice;
618}
619
620QT_END_NAMESPACE
621
622#include "moc_qabstracttextdocumentlayout.cpp"
Note: See TracBrowser for help on using the repository browser.