qtextdocument.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/gui/text/qtextdocument.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2016 The Qt Company Ltd.-
4** Contact: https://www.qt.io/licensing/-
5**-
6** This file is part of the QtGui module of the Qt Toolkit.-
7**-
8** $QT_BEGIN_LICENSE:LGPL$-
9** Commercial License Usage-
10** Licensees holding valid commercial Qt licenses may use this file in-
11** accordance with the commercial license agreement provided with the-
12** Software or, alternatively, in accordance with the terms contained in-
13** a written agreement between you and The Qt Company. For licensing terms-
14** and conditions see https://www.qt.io/terms-conditions. For further-
15** information use the contact form at https://www.qt.io/contact-us.-
16**-
17** GNU Lesser General Public License Usage-
18** Alternatively, this file may be used under the terms of the GNU Lesser-
19** General Public License version 3 as published by the Free Software-
20** Foundation and appearing in the file LICENSE.LGPL3 included in the-
21** packaging of this file. Please review the following information to-
22** ensure the GNU Lesser General Public License version 3 requirements-
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.-
24**-
25** GNU General Public License Usage-
26** Alternatively, this file may be used under the terms of the GNU-
27** General Public License version 2.0 or (at your option) the GNU General-
28** Public license version 3 or any later version approved by the KDE Free-
29** Qt Foundation. The licenses are as published by the Free Software-
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3-
31** included in the packaging of this file. Please review the following-
32** information to ensure the GNU General Public License requirements will-
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and-
34** https://www.gnu.org/licenses/gpl-3.0.html.-
35**-
36** $QT_END_LICENSE$-
37**-
38****************************************************************************/-
39-
40#include "qtextdocument.h"-
41#include <qtextformat.h>-
42#include "qtextcursor_p.h"-
43#include "qtextdocumentlayout_p.h"-
44#include "qtextdocumentfragment.h"-
45#include "qtextdocumentfragment_p.h"-
46#include "qtexttable.h"-
47#include "qtextlist.h"-
48#include <qdebug.h>-
49#include <qregexp.h>-
50#include <qregularexpression.h>-
51#include <qvarlengtharray.h>-
52#include <qtextcodec.h>-
53#include <qthread.h>-
54#include <qcoreapplication.h>-
55#include <qmetaobject.h>-
56-
57#include "qtexthtmlparser_p.h"-
58#include "qpainter.h"-
59#include <qfile.h>-
60#include <qfileinfo.h>-
61#include <qdir.h>-
62#include "qfont_p.h"-
63#include "private/qdataurl_p.h"-
64-
65#include "qtextdocument_p.h"-
66#include <private/qabstracttextdocumentlayout_p.h>-
67#include "qpagedpaintdevice.h"-
68#include "private/qpagedpaintdevice_p.h"-
69-
70#include <limits.h>-
71-
72QT_BEGIN_NAMESPACE-
73-
74Q_CORE_EXPORT unsigned int qt_int_sqrt(unsigned int n);-
75-
76/*!-
77 Returns \c true if the string \a text is likely to be rich text;-
78 otherwise returns \c false.-
79-
80 This function uses a fast and therefore simple heuristic. It-
81 mainly checks whether there is something that looks like a tag-
82 before the first line break. Although the result may be correct-
83 for common cases, there is no guarantee.-
84-
85 This function is defined in the \c <QTextDocument> header file.-
86*/-
87bool Qt::mightBeRichText(const QString& text)-
88{-
89 if (text.isEmpty())-
90 return false;-
91 int start = 0;-
92-
93 while (start < text.length() && text.at(start).isSpace())-
94 ++start;-
95-
96 // skip a leading <?xml ... ?> as for example with xhtml-
97 if (text.mid(start, 5) == QLatin1String("<?xml")) {-
98 while (start < text.length()) {-
99 if (text.at(start) == QLatin1Char('?')-
100 && start + 2 < text.length()-
101 && text.at(start + 1) == QLatin1Char('>')) {-
102 start += 2;-
103 break;-
104 }-
105 ++start;-
106 }-
107-
108 while (start < text.length() && text.at(start).isSpace())-
109 ++start;-
110 }-
111-
112 if (text.mid(start, 5).toLower() == QLatin1String("<!doc"))-
113 return true;-
114 int open = start;-
115 while (open < text.length() && text.at(open) != QLatin1Char('<')-
116 && text.at(open) != QLatin1Char('\n')) {-
117 if (text.at(open) == QLatin1Char('&') && text.mid(open+1,3) == QLatin1String("lt;"))-
118 return true; // support desperate attempt of user to see <...>-
119 ++open;-
120 }-
121 if (open < text.length() && text.at(open) == QLatin1Char('<')) {-
122 const int close = text.indexOf(QLatin1Char('>'), open);-
123 if (close > -1) {-
124 QString tag;-
125 for (int i = open+1; i < close; ++i) {-
126 if (text[i].isDigit() || text[i].isLetter())-
127 tag += text[i];-
128 else if (!tag.isEmpty() && text[i].isSpace())-
129 break;-
130 else if (!tag.isEmpty() && text[i] == QLatin1Char('/') && i + 1 == close)-
131 break;-
132 else if (!text[i].isSpace() && (!tag.isEmpty() || text[i] != QLatin1Char('!')))-
133 return false; // that's not a tag-
134 }-
135#ifndef QT_NO_TEXTHTMLPARSER-
136 return QTextHtmlParser::lookupElement(tag.toLower()) != -1;-
137#else-
138 return false;-
139#endif // QT_NO_TEXTHTMLPARSER-
140 }-
141 }-
142 return false;-
143}-
144-
145-
146/*!-
147 Converts the plain text string \a plain to an HTML-formatted-
148 paragraph while preserving most of its look.-
149-
150 \a mode defines how whitespace is handled.-
151-
152 This function is defined in the \c <QTextDocument> header file.-
153-
154 \sa escape(), mightBeRichText()-
155*/-
156QString Qt::convertFromPlainText(const QString &plain, Qt::WhiteSpaceMode mode)-
157{-
158 int col = 0;-
159 QString rich;-
160 rich += QLatin1String("<p>");-
161 for (int i = 0; i < plain.length(); ++i) {-
162 if (plain[i] == QLatin1Char('\n')){-
163 int c = 1;-
164 while (i+1 < plain.length() && plain[i+1] == QLatin1Char('\n')) {-
165 i++;-
166 c++;-
167 }-
168 if (c == 1)-
169 rich += QLatin1String("<br>\n");-
170 else {-
171 rich += QLatin1String("</p>\n");-
172 while (--c > 1)-
173 rich += QLatin1String("<br>\n");-
174 rich += QLatin1String("<p>");-
175 }-
176 col = 0;-
177 } else {-
178 if (mode == Qt::WhiteSpacePre && plain[i] == QLatin1Char('\t')){-
179 rich += QChar(0x00a0U);-
180 ++col;-
181 while (col % 8) {-
182 rich += QChar(0x00a0U);-
183 ++col;-
184 }-
185 }-
186 else if (mode == Qt::WhiteSpacePre && plain[i].isSpace())-
187 rich += QChar(0x00a0U);-
188 else if (plain[i] == QLatin1Char('<'))-
189 rich += QLatin1String("&lt;");-
190 else if (plain[i] == QLatin1Char('>'))-
191 rich += QLatin1String("&gt;");-
192 else if (plain[i] == QLatin1Char('&'))-
193 rich += QLatin1String("&amp;");-
194 else-
195 rich += plain[i];-
196 ++col;-
197 }-
198 }-
199 if (col != 0)-
200 rich += QLatin1String("</p>");-
201 return rich;-
202}-
203-
204#ifndef QT_NO_TEXTCODEC-
205/*!-
206 \internal-
207-
208 This function is defined in the \c <QTextDocument> header file.-
209*/-
210QTextCodec *Qt::codecForHtml(const QByteArray &ba)-
211{-
212 return QTextCodec::codecForHtml(ba);-
213}-
214#endif-
215-
216/*!-
217 \class QTextDocument-
218 \reentrant-
219 \inmodule QtGui-
220-
221 \brief The QTextDocument class holds formatted text.-
222-
223 \ingroup richtext-processing-
224-
225-
226 QTextDocument is a container for structured rich text documents, providing-
227 support for styled text and various types of document elements, such as-
228 lists, tables, frames, and images.-
229 They can be created for use in a QTextEdit, or used independently.-
230-
231 Each document element is described by an associated format object. Each-
232 format object is treated as a unique object by QTextDocuments, and can be-
233 passed to objectForFormat() to obtain the document element that it is-
234 applied to.-
235-
236 A QTextDocument can be edited programmatically using a QTextCursor, and-
237 its contents can be examined by traversing the document structure. The-
238 entire document structure is stored as a hierarchy of document elements-
239 beneath the root frame, found with the rootFrame() function. Alternatively,-
240 if you just want to iterate over the textual contents of the document you-
241 can use begin(), end(), and findBlock() to retrieve text blocks that you-
242 can examine and iterate over.-
243-
244 The layout of a document is determined by the documentLayout();-
245 you can create your own QAbstractTextDocumentLayout subclass and-
246 set it using setDocumentLayout() if you want to use your own-
247 layout logic. The document's title and other meta-information can be-
248 obtained by calling the metaInformation() function. For documents that-
249 are exposed to users through the QTextEdit class, the document title-
250 is also available via the QTextEdit::documentTitle() function.-
251-
252 The toPlainText() and toHtml() convenience functions allow you to retrieve the-
253 contents of the document as plain text and HTML.-
254 The document's text can be searched using the find() functions.-
255-
256 Undo/redo of operations performed on the document can be controlled using-
257 the setUndoRedoEnabled() function. The undo/redo system can be controlled-
258 by an editor widget through the undo() and redo() slots; the document also-
259 provides contentsChanged(), undoAvailable(), and redoAvailable() signals-
260 that inform connected editor widgets about the state of the undo/redo-
261 system. The following are the undo/redo operations of a QTextDocument:-
262-
263 \list-
264 \li Insertion or removal of characters. A sequence of insertions or removals-
265 within the same text block are regarded as a single undo/redo operation.-
266 \li Insertion or removal of text blocks. Sequences of insertion or removals-
267 in a single operation (e.g., by selecting and then deleting text) are-
268 regarded as a single undo/redo operation.-
269 \li Text character format changes.-
270 \li Text block format changes.-
271 \li Text block group format changes.-
272 \endlist-
273-
274 \sa QTextCursor, QTextEdit, {Rich Text Processing}, {Text Object Example}-
275*/-
276-
277/*!-
278 \property QTextDocument::defaultFont-
279 \brief the default font used to display the document's text-
280*/-
281-
282/*!-
283 \property QTextDocument::defaultTextOption-
284 \brief the default text option will be set on all \l{QTextLayout}s in the document.-
285-
286 When \l{QTextBlock}s are created, the defaultTextOption is set on their-
287 QTextLayout. This allows setting global properties for the document such as the-
288 default word wrap mode.-
289 */-
290-
291/*!-
292 Constructs an empty QTextDocument with the given \a parent.-
293*/-
294QTextDocument::QTextDocument(QObject *parent)-
295 : QObject(*new QTextDocumentPrivate, parent)-
296{-
297 Q_D(QTextDocument);-
298 d->init();-
299}-
300-
301/*!-
302 Constructs a QTextDocument containing the plain (unformatted) \a text-
303 specified, and with the given \a parent.-
304*/-
305QTextDocument::QTextDocument(const QString &text, QObject *parent)-
306 : QObject(*new QTextDocumentPrivate, parent)-
307{-
308 Q_D(QTextDocument);-
309 d->init();-
310 QTextCursor(this).insertText(text);-
311}-
312-
313/*!-
314 \internal-
315*/-
316QTextDocument::QTextDocument(QTextDocumentPrivate &dd, QObject *parent)-
317 : QObject(dd, parent)-
318{-
319 Q_D(QTextDocument);-
320 d->init();-
321}-
322-
323/*!-
324 Destroys the document.-
325*/-
326QTextDocument::~QTextDocument()-
327{-
328}-
329-
330-
331/*!-
332 Creates a new QTextDocument that is a copy of this text document. \a-
333 parent is the parent of the returned text document.-
334*/-
335QTextDocument *QTextDocument::clone(QObject *parent) const-
336{-
337 Q_D(const QTextDocument);-
338 QTextDocument *doc = new QTextDocument(parent);-
339 QTextCursor(doc).insertFragment(QTextDocumentFragment(this));-
340 doc->rootFrame()->setFrameFormat(rootFrame()->frameFormat());-
341 QTextDocumentPrivate *priv = doc->d_func();-
342 priv->title = d->title;-
343 priv->url = d->url;-
344 priv->pageSize = d->pageSize;-
345 priv->indentWidth = d->indentWidth;-
346 priv->defaultTextOption = d->defaultTextOption;-
347 priv->setDefaultFont(d->defaultFont());-
348 priv->resources = d->resources;-
349 priv->cachedResources.clear();-
350#ifndef QT_NO_CSSPARSER-
351 priv->defaultStyleSheet = d->defaultStyleSheet;-
352 priv->parsedDefaultStyleSheet = d->parsedDefaultStyleSheet;-
353#endif-
354 return doc;-
355}-
356-
357/*!-
358 Returns \c true if the document is empty; otherwise returns \c false.-
359*/-
360bool QTextDocument::isEmpty() const-
361{-
362 Q_D(const QTextDocument);-
363 /* because if we're empty we still have one single paragraph as-
364 * one single fragment */-
365 return d->length() <= 1;-
366}-
367-
368/*!-
369 Clears the document.-
370*/-
371void QTextDocument::clear()-
372{-
373 Q_D(QTextDocument);-
374 d->clear();-
375 d->resources.clear();-
376}-
377-
378/*!-
379 \since 4.2-
380-
381 Undoes the last editing operation on the document if undo is-
382 available. The provided \a cursor is positioned at the end of the-
383 location where the edition operation was undone.-
384-
385 See the \l {Overview of Qt's Undo Framework}{Qt Undo Framework}-
386 documentation for details.-
387-
388 \sa undoAvailable(), isUndoRedoEnabled()-
389*/-
390void QTextDocument::undo(QTextCursor *cursor)-
391{-
392 Q_D(QTextDocument);-
393 const int pos = d->undoRedo(true);-
394 if (cursor && pos >= 0) {-
395 *cursor = QTextCursor(this);-
396 cursor->setPosition(pos);-
397 }-
398}-
399-
400/*!-
401 \since 4.2-
402 Redoes the last editing operation on the document if \l{QTextDocument::isRedoAvailable()}{redo is available}.-
403-
404 The provided \a cursor is positioned at the end of the location where-
405 the edition operation was redone.-
406*/-
407void QTextDocument::redo(QTextCursor *cursor)-
408{-
409 Q_D(QTextDocument);-
410 const int pos = d->undoRedo(false);-
411 if (cursor && pos >= 0) {-
412 *cursor = QTextCursor(this);-
413 cursor->setPosition(pos);-
414 }-
415}-
416-
417/*! \enum QTextDocument::Stacks-
418-
419 \value UndoStack The undo stack.-
420 \value RedoStack The redo stack.-
421 \value UndoAndRedoStacks Both the undo and redo stacks.-
422*/-
423-
424/*!-
425 \since 4.7-
426 Clears the stacks specified by \a stacksToClear.-
427-
428 This method clears any commands on the undo stack, the redo stack,-
429 or both (the default). If commands are cleared, the appropriate-
430 signals are emitted, QTextDocument::undoAvailable() or-
431 QTextDocument::redoAvailable().-
432-
433 \sa QTextDocument::undoAvailable(), QTextDocument::redoAvailable()-
434*/-
435void QTextDocument::clearUndoRedoStacks(Stacks stacksToClear)-
436{-
437 Q_D(QTextDocument);-
438 d->clearUndoRedoStacks(stacksToClear, true);-
439}-
440-
441/*!-
442 \overload-
443-
444*/-
445void QTextDocument::undo()-
446{-
447 Q_D(QTextDocument);-
448 d->undoRedo(true);-
449}-
450-
451/*!-
452 \overload-
453 Redoes the last editing operation on the document if \l{QTextDocument::isRedoAvailable()}{redo is available}.-
454*/-
455void QTextDocument::redo()-
456{-
457 Q_D(QTextDocument);-
458 d->undoRedo(false);-
459}-
460-
461/*!-
462 \internal-
463-
464 Appends a custom undo \a item to the undo stack.-
465*/-
466void QTextDocument::appendUndoItem(QAbstractUndoItem *item)-
467{-
468 Q_D(QTextDocument);-
469 d->appendUndoItem(item);-
470}-
471-
472/*!-
473 \property QTextDocument::undoRedoEnabled-
474 \brief whether undo/redo are enabled for this document-
475-
476 This defaults to true. If disabled, the undo stack is cleared and-
477 no items will be added to it.-
478*/-
479void QTextDocument::setUndoRedoEnabled(bool enable)-
480{-
481 Q_D(QTextDocument);-
482 d->enableUndoRedo(enable);-
483}-
484-
485bool QTextDocument::isUndoRedoEnabled() const-
486{-
487 Q_D(const QTextDocument);-
488 return d->isUndoRedoEnabled();-
489}-
490-
491/*!-
492 \property QTextDocument::maximumBlockCount-
493 \since 4.2-
494 \brief Specifies the limit for blocks in the document.-
495-
496 Specifies the maximum number of blocks the document may have. If there are-
497 more blocks in the document that specified with this property blocks are removed-
498 from the beginning of the document.-
499-
500 A negative or zero value specifies that the document may contain an unlimited-
501 amount of blocks.-
502-
503 The default value is 0.-
504-
505 Note that setting this property will apply the limit immediately to the document-
506 contents.-
507-
508 Setting this property also disables the undo redo history.-
509-
510 This property is undefined in documents with tables or frames.-
511*/-
512int QTextDocument::maximumBlockCount() const-
513{-
514 Q_D(const QTextDocument);-
515 return d->maximumBlockCount;-
516}-
517-
518void QTextDocument::setMaximumBlockCount(int maximum)-
519{-
520 Q_D(QTextDocument);-
521 d->maximumBlockCount = maximum;-
522 d->ensureMaximumBlockCount();-
523 setUndoRedoEnabled(false);-
524}-
525-
526/*!-
527 \since 4.3-
528-
529 The default text option is used on all QTextLayout objects in the document.-
530 This allows setting global properties for the document such as the default-
531 word wrap mode.-
532*/-
533QTextOption QTextDocument::defaultTextOption() const-
534{-
535 Q_D(const QTextDocument);-
536 return d->defaultTextOption;-
537}-
538-
539/*!-
540 \since 4.3-
541-
542 Sets the default text option to \a option.-
543*/-
544void QTextDocument::setDefaultTextOption(const QTextOption &option)-
545{-
546 Q_D(QTextDocument);-
547 d->defaultTextOption = option;-
548 if (d->lout)-
549 d->lout->documentChanged(0, 0, d->length());-
550}-
551-
552/*!-
553 \property QTextDocument::baseUrl-
554 \since 5.3-
555 \brief the base URL used to resolve relative resource URLs within the document.-
556-
557 Resource URLs are resolved to be within the same directory as the target of the base-
558 URL meaning any portion of the path after the last '/' will be ignored.-
559-
560 \table-
561 \header \li Base URL \li Relative URL \li Resolved URL-
562 \row \li file:///path/to/content \li images/logo.png \li file:///path/to/images/logo.png-
563 \row \li file:///path/to/content/ \li images/logo.png \li file:///path/to/content/images/logo.png-
564 \row \li file:///path/to/content/index.html \li images/logo.png \li file:///path/to/content/images/logo.png-
565 \row \li file:///path/to/content/images/ \li ../images/logo.png \li file:///path/to/content/images/logo.png-
566 \endtable-
567*/-
568QUrl QTextDocument::baseUrl() const-
569{-
570 Q_D(const QTextDocument);-
571 return d->baseUrl;-
572}-
573-
574void QTextDocument::setBaseUrl(const QUrl &url)-
575{-
576 Q_D(QTextDocument);-
577 if (d->baseUrl != url) {-
578 d->baseUrl = url;-
579 if (d->lout)-
580 d->lout->documentChanged(0, 0, d->length());-
581 emit baseUrlChanged(url);-
582 }-
583}-
584-
585/*!-
586 \since 4.8-
587-
588 The default cursor movement style is used by all QTextCursor objects-
589 created from the document. The default is Qt::LogicalMoveStyle.-
590*/-
591Qt::CursorMoveStyle QTextDocument::defaultCursorMoveStyle() const-
592{-
593 Q_D(const QTextDocument);-
594 return d->defaultCursorMoveStyle;-
595}-
596-
597/*!-
598 \since 4.8-
599-
600 Sets the default cursor movement style to the given \a style.-
601*/-
602void QTextDocument::setDefaultCursorMoveStyle(Qt::CursorMoveStyle style)-
603{-
604 Q_D(QTextDocument);-
605 d->defaultCursorMoveStyle = style;-
606}-
607-
608/*!-
609 \fn void QTextDocument::markContentsDirty(int position, int length)-
610-
611 Marks the contents specified by the given \a position and \a length-
612 as "dirty", informing the document that it needs to be laid out-
613 again.-
614*/-
615void QTextDocument::markContentsDirty(int from, int length)-
616{-
617 Q_D(QTextDocument);-
618 d->documentChange(from, length);-
619 if (!d->inContentsChange) {-
620 if (d->lout) {-
621 d->lout->documentChanged(d->docChangeFrom, d->docChangeOldLength, d->docChangeLength);-
622 d->docChangeFrom = -1;-
623 }-
624 }-
625}-
626-
627/*!-
628 \property QTextDocument::useDesignMetrics-
629 \since 4.1-
630 \brief whether the document uses design metrics of fonts to improve the accuracy of text layout-
631-
632 If this property is set to true, the layout will use design metrics.-
633 Otherwise, the metrics of the paint device as set on-
634 QAbstractTextDocumentLayout::setPaintDevice() will be used.-
635-
636 Using design metrics makes a layout have a width that is no longer dependent on hinting-
637 and pixel-rounding. This means that WYSIWYG text layout becomes possible because the width-
638 scales much more linearly based on paintdevice metrics than it would otherwise.-
639-
640 By default, this property is \c false.-
641*/-
642-
643void QTextDocument::setUseDesignMetrics(bool b)-
644{-
645 Q_D(QTextDocument);-
646 if (b == d->defaultTextOption.useDesignMetrics())-
647 return;-
648 d->defaultTextOption.setUseDesignMetrics(b);-
649 if (d->lout)-
650 d->lout->documentChanged(0, 0, d->length());-
651}-
652-
653bool QTextDocument::useDesignMetrics() const-
654{-
655 Q_D(const QTextDocument);-
656 return d->defaultTextOption.useDesignMetrics();-
657}-
658-
659/*!-
660 \since 4.2-
661-
662 Draws the content of the document with painter \a p, clipped to \a rect.-
663 If \a rect is a null rectangle (default) then the document is painted unclipped.-
664*/-
665void QTextDocument::drawContents(QPainter *p, const QRectF &rect)-
666{-
667 p->save();-
668 QAbstractTextDocumentLayout::PaintContext ctx;-
669 if (rect.isValid()) {-
670 p->setClipRect(rect);-
671 ctx.clip = rect;-
672 }-
673 documentLayout()->draw(p, ctx);-
674 p->restore();-
675}-
676-
677/*!-
678 \property QTextDocument::textWidth-
679 \since 4.2-
680-
681 The text width specifies the preferred width for text in the document. If-
682 the text (or content in general) is wider than the specified with it is broken-
683 into multiple lines and grows vertically. If the text cannot be broken into multiple-
684 lines to fit into the specified text width it will be larger and the size() and the-
685 idealWidth() property will reflect that.-
686-
687 If the text width is set to -1 then the text will not be broken into multiple lines-
688 unless it is enforced through an explicit line break or a new paragraph.-
689-
690 The default value is -1.-
691-
692 Setting the text width will also set the page height to -1, causing the document to-
693 grow or shrink vertically in a continuous way. If you want the document layout to break-
694 the text into multiple pages then you have to set the pageSize property instead.-
695-
696 \sa size(), idealWidth(), pageSize()-
697*/-
698void QTextDocument::setTextWidth(qreal width)-
699{-
700 Q_D(QTextDocument);-
701 QSizeF sz = d->pageSize;-
702 sz.setWidth(width);-
703 sz.setHeight(-1);-
704 setPageSize(sz);-
705}-
706-
707qreal QTextDocument::textWidth() const-
708{-
709 Q_D(const QTextDocument);-
710 return d->pageSize.width();-
711}-
712-
713/*!-
714 \since 4.2-
715-
716 Returns the ideal width of the text document. The ideal width is the actually used width-
717 of the document without optional alignments taken into account. It is always <= size().width().-
718-
719 \sa adjustSize(), textWidth-
720*/-
721qreal QTextDocument::idealWidth() const-
722{-
723 if (QTextDocumentLayout *lout = qobject_cast<QTextDocumentLayout *>(documentLayout()))-
724 return lout->idealWidth();-
725 return textWidth();-
726}-
727-
728/*!-
729 \property QTextDocument::documentMargin-
730 \since 4.5-
731-
732 The margin around the document. The default is 4.-
733*/-
734qreal QTextDocument::documentMargin() const-
735{-
736 Q_D(const QTextDocument);-
737 return d->documentMargin;-
738}-
739-
740void QTextDocument::setDocumentMargin(qreal margin)-
741{-
742 Q_D(QTextDocument);-
743 if (d->documentMargin != margin) {-
744 d->documentMargin = margin;-
745-
746 QTextFrame* root = rootFrame();-
747 QTextFrameFormat format = root->frameFormat();-
748 format.setMargin(margin);-
749 root->setFrameFormat(format);-
750-
751 if (d->lout)-
752 d->lout->documentChanged(0, 0, d->length());-
753 }-
754}-
755-
756-
757/*!-
758 \property QTextDocument::indentWidth-
759 \since 4.4-
760-
761 Returns the width used for text list and text block indenting.-
762-
763 The indent properties of QTextListFormat and QTextBlockFormat specify-
764 multiples of this value. The default indent width is 40.-
765*/-
766qreal QTextDocument::indentWidth() const-
767{-
768 Q_D(const QTextDocument);-
769 return d->indentWidth;-
770}-
771-
772-
773/*!-
774 \since 4.4-
775-
776 Sets the \a width used for text list and text block indenting.-
777-
778 The indent properties of QTextListFormat and QTextBlockFormat specify-
779 multiples of this value. The default indent width is 40 .-
780-
781 \sa indentWidth()-
782*/-
783void QTextDocument::setIndentWidth(qreal width)-
784{-
785 Q_D(QTextDocument);-
786 if (d->indentWidth != width) {-
787 d->indentWidth = width;-
788 if (d->lout)-
789 d->lout->documentChanged(0, 0, d->length());-
790 }-
791}-
792-
793-
794-
795-
796/*!-
797 \since 4.2-
798-
799 Adjusts the document to a reasonable size.-
800-
801 \sa idealWidth(), textWidth, size-
802*/-
803void QTextDocument::adjustSize()-
804{-
805 // Pull this private function in from qglobal.cpp-
806 QFont f = defaultFont();-
807 QFontMetrics fm(f);-
808 int mw = fm.width(QLatin1Char('x')) * 80;-
809 int w = mw;-
810 setTextWidth(w);-
811 QSizeF size = documentLayout()->documentSize();-
812 if (size.width() != 0) {-
813 w = qt_int_sqrt((uint)(5 * size.height() * size.width() / 3));-
814 setTextWidth(qMin(w, mw));-
815-
816 size = documentLayout()->documentSize();-
817 if (w*3 < 5*size.height()) {-
818 w = qt_int_sqrt((uint)(2 * size.height() * size.width()));-
819 setTextWidth(qMin(w, mw));-
820 }-
821 }-
822 setTextWidth(idealWidth());-
823}-
824-
825/*!-
826 \property QTextDocument::size-
827 \since 4.2-
828-
829 Returns the actual size of the document.-
830 This is equivalent to documentLayout()->documentSize();-
831-
832 The size of the document can be changed either by setting-
833 a text width or setting an entire page size.-
834-
835 Note that the width is always >= pageSize().width().-
836-
837 By default, for a newly-created, empty document, this property contains-
838 a configuration-dependent size.-
839-
840 \sa setTextWidth(), setPageSize(), idealWidth()-
841*/-
842QSizeF QTextDocument::size() const-
843{-
844 return documentLayout()->documentSize();-
845}-
846-
847/*!-
848 \property QTextDocument::blockCount-
849 \since 4.2-
850-
851 Returns the number of text blocks in the document.-
852-
853 The value of this property is undefined in documents with tables or frames.-
854-
855 By default, if defined, this property contains a value of 1.-
856 \sa lineCount(), characterCount()-
857*/-
858int QTextDocument::blockCount() const-
859{-
860 Q_D(const QTextDocument);-
861 return d->blockMap().numNodes();-
862}-
863-
864-
865/*!-
866 \since 4.5-
867-
868 Returns the number of lines of this document (if the layout supports-
869 this). Otherwise, this is identical to the number of blocks.-
870-
871 \sa blockCount(), characterCount()-
872 */-
873int QTextDocument::lineCount() const-
874{-
875 Q_D(const QTextDocument);-
876 return d->blockMap().length(2);-
877}-
878-
879/*!-
880 \since 4.5-
881-
882 Returns the number of characters of this document.-
883-
884 \sa blockCount(), characterAt()-
885 */-
886int QTextDocument::characterCount() const-
887{-
888 Q_D(const QTextDocument);-
889 return d->length();-
890}-
891-
892/*!-
893 \since 4.5-
894-
895 Returns the character at position \a pos, or a null character if the-
896 position is out of range.-
897-
898 \sa characterCount()-
899 */-
900QChar QTextDocument::characterAt(int pos) const-
901{-
902 Q_D(const QTextDocument);-
903 if (pos < 0 || pos >= d->length())-
904 return QChar();-
905 QTextDocumentPrivate::FragmentIterator fragIt = d->find(pos);-
906 const QTextFragmentData * const frag = fragIt.value();-
907 const int offsetInFragment = qMax(0, pos - fragIt.position());-
908 return d->text.at(frag->stringPosition + offsetInFragment);-
909}-
910-
911-
912/*!-
913 \property QTextDocument::defaultStyleSheet-
914 \since 4.2-
915-
916 The default style sheet is applied to all newly HTML formatted text that is-
917 inserted into the document, for example using setHtml() or QTextCursor::insertHtml().-
918-
919 The style sheet needs to be compliant to CSS 2.1 syntax.-
920-
921 \b{Note:} Changing the default style sheet does not have any effect to the existing content-
922 of the document.-
923-
924 \sa {Supported HTML Subset}-
925*/-
926-
927#ifndef QT_NO_CSSPARSER-
928void QTextDocument::setDefaultStyleSheet(const QString &sheet)-
929{-
930 Q_D(QTextDocument);-
931 d->defaultStyleSheet = sheet;-
932 QCss::Parser parser(sheet);-
933 d->parsedDefaultStyleSheet = QCss::StyleSheet();-
934 d->parsedDefaultStyleSheet.origin = QCss::StyleSheetOrigin_UserAgent;-
935 parser.parse(&d->parsedDefaultStyleSheet);-
936}-
937-
938QString QTextDocument::defaultStyleSheet() const-
939{-
940 Q_D(const QTextDocument);-
941 return d->defaultStyleSheet;-
942}-
943#endif // QT_NO_CSSPARSER-
944-
945/*!-
946 \fn void QTextDocument::contentsChanged()-
947-
948 This signal is emitted whenever the document's content changes; for-
949 example, when text is inserted or deleted, or when formatting is applied.-
950-
951 \sa contentsChange()-
952*/-
953-
954/*!-
955 \fn void QTextDocument::contentsChange(int position, int charsRemoved, int charsAdded)-
956-
957 This signal is emitted whenever the document's content changes; for-
958 example, when text is inserted or deleted, or when formatting is applied.-
959-
960 Information is provided about the \a position of the character in the-
961 document where the change occurred, the number of characters removed-
962 (\a charsRemoved), and the number of characters added (\a charsAdded).-
963-
964 The signal is emitted before the document's layout manager is notified-
965 about the change. This hook allows you to implement syntax highlighting-
966 for the document.-
967-
968 \sa QAbstractTextDocumentLayout::documentChanged(), contentsChanged()-
969*/-
970-
971-
972/*!-
973 \fn QTextDocument::undoAvailable(bool available);-
974-
975 This signal is emitted whenever undo operations become available-
976 (\a available is true) or unavailable (\a available is false).-
977-
978 See the \l {Overview of Qt's Undo Framework}{Qt Undo Framework}-
979 documentation for details.-
980-
981 \sa undo(), isUndoRedoEnabled()-
982*/-
983-
984/*!-
985 \fn QTextDocument::redoAvailable(bool available);-
986-
987 This signal is emitted whenever redo operations become available-
988 (\a available is true) or unavailable (\a available is false).-
989*/-
990-
991/*!-
992 \fn QTextDocument::cursorPositionChanged(const QTextCursor &cursor);-
993-
994 This signal is emitted whenever the position of a cursor changed-
995 due to an editing operation. The cursor that changed is passed in-
996 \a cursor. If the document is used with the QTextEdit class and you need a signal when the-
997 cursor is moved with the arrow keys you can use the \l{QTextEdit::}{cursorPositionChanged()}-
998 signal in QTextEdit.-
999*/-
1000-
1001/*!-
1002 \fn QTextDocument::blockCountChanged(int newBlockCount);-
1003 \since 4.3-
1004-
1005 This signal is emitted when the total number of text blocks in the-
1006 document changes. The value passed in \a newBlockCount is the new-
1007 total.-
1008*/-
1009-
1010/*!-
1011 \fn QTextDocument::documentLayoutChanged();-
1012 \since 4.4-
1013-
1014 This signal is emitted when a new document layout is set.-
1015-
1016 \sa setDocumentLayout()-
1017-
1018*/-
1019-
1020-
1021/*!-
1022 Returns \c true if undo is available; otherwise returns \c false.-
1023-
1024 \sa isRedoAvailable(), availableUndoSteps()-
1025*/-
1026bool QTextDocument::isUndoAvailable() const-
1027{-
1028 Q_D(const QTextDocument);-
1029 return d->isUndoAvailable();-
1030}-
1031-
1032/*!-
1033 Returns \c true if redo is available; otherwise returns \c false.-
1034-
1035 \sa isUndoAvailable(), availableRedoSteps()-
1036*/-
1037bool QTextDocument::isRedoAvailable() const-
1038{-
1039 Q_D(const QTextDocument);-
1040 return d->isRedoAvailable();-
1041}-
1042-
1043/*! \since 4.6-
1044-
1045 Returns the number of available undo steps.-
1046-
1047 \sa isUndoAvailable()-
1048*/-
1049int QTextDocument::availableUndoSteps() const-
1050{-
1051 Q_D(const QTextDocument);-
1052 return d->availableUndoSteps();-
1053}-
1054-
1055/*! \since 4.6-
1056-
1057 Returns the number of available redo steps.-
1058-
1059 \sa isRedoAvailable()-
1060*/-
1061int QTextDocument::availableRedoSteps() const-
1062{-
1063 Q_D(const QTextDocument);-
1064 return d->availableRedoSteps();-
1065}-
1066-
1067/*! \since 4.4-
1068-
1069 Returns the document's revision (if undo is enabled).-
1070-
1071 The revision is guaranteed to increase when a document that is not-
1072 modified is edited.-
1073-
1074 \sa QTextBlock::revision(), isModified()-
1075 */-
1076int QTextDocument::revision() const-
1077{-
1078 Q_D(const QTextDocument);-
1079 return d->revision;-
1080}-
1081-
1082-
1083-
1084/*!-
1085 Sets the document to use the given \a layout. The previous layout-
1086 is deleted.-
1087-
1088 \sa documentLayoutChanged()-
1089*/-
1090void QTextDocument::setDocumentLayout(QAbstractTextDocumentLayout *layout)-
1091{-
1092 Q_D(QTextDocument);-
1093 d->setLayout(layout);-
1094}-
1095-
1096/*!-
1097 Returns the document layout for this document.-
1098*/-
1099QAbstractTextDocumentLayout *QTextDocument::documentLayout() const-
1100{-
1101 Q_D(const QTextDocument);-
1102 if (!d->lout) {-
1103 QTextDocument *that = const_cast<QTextDocument *>(this);-
1104 that->d_func()->setLayout(new QTextDocumentLayout(that));-
1105 }-
1106 return d->lout;-
1107}-
1108-
1109-
1110/*!-
1111 Returns meta information about the document of the type specified by-
1112 \a info.-
1113-
1114 \sa setMetaInformation()-
1115*/-
1116QString QTextDocument::metaInformation(MetaInformation info) const-
1117{-
1118 Q_D(const QTextDocument);-
1119 switch (info) {-
1120 case DocumentTitle:-
1121 return d->title;-
1122 case DocumentUrl:-
1123 return d->url;-
1124 }-
1125 return QString();-
1126}-
1127-
1128/*!-
1129 Sets the document's meta information of the type specified by \a info-
1130 to the given \a string.-
1131-
1132 \sa metaInformation()-
1133*/-
1134void QTextDocument::setMetaInformation(MetaInformation info, const QString &string)-
1135{-
1136 Q_D(QTextDocument);-
1137 switch (info) {-
1138 case DocumentTitle:-
1139 d->title = string;-
1140 break;-
1141 case DocumentUrl:-
1142 d->url = string;-
1143 break;-
1144 }-
1145}-
1146-
1147/*!-
1148 Returns the plain text contained in the document. If you want-
1149 formatting information use a QTextCursor instead.-
1150-
1151 \note Embedded objects, such as images, are represented by a-
1152 Unicode value U+FFFC (OBJECT REPLACEMENT CHARACTER).-
1153-
1154 \sa toHtml()-
1155*/-
1156QString QTextDocument::toPlainText() const-
1157{-
1158 Q_D(const QTextDocument);-
1159 QString txt = d->plainText();-
1160-
1161 QChar *uc = txt.data();-
1162 QChar *e = uc + txt.size();-
1163-
1164 for (; uc != e; ++uc) {-
1165 switch (uc->unicode()) {-
1166 case 0xfdd0: // QTextBeginningOfFrame-
1167 case 0xfdd1: // QTextEndOfFrame-
1168 case QChar::ParagraphSeparator:-
1169 case QChar::LineSeparator:-
1170 *uc = QLatin1Char('\n');-
1171 break;-
1172 case QChar::Nbsp:-
1173 *uc = QLatin1Char(' ');-
1174 break;-
1175 default:-
1176 ;-
1177 }-
1178 }-
1179 return txt;-
1180}-
1181-
1182/*!-
1183 Replaces the entire contents of the document with the given plain-
1184 \a text. The undo/redo history is reset when this function is called.-
1185-
1186 \sa setHtml()-
1187*/-
1188void QTextDocument::setPlainText(const QString &text)-
1189{-
1190 Q_D(QTextDocument);-
1191 bool previousState = d->isUndoRedoEnabled();-
1192 d->enableUndoRedo(false);-
1193 d->beginEditBlock();-
1194 d->clear();-
1195 QTextCursor(this).insertText(text);-
1196 d->endEditBlock();-
1197 d->enableUndoRedo(previousState);-
1198}-
1199-
1200/*!-
1201 Replaces the entire contents of the document with the given-
1202 HTML-formatted text in the \a html string. The undo/redo history-
1203 is reset when this function is called.-
1204-
1205 The HTML formatting is respected as much as possible; for example,-
1206 "<b>bold</b> text" will produce text where the first word has a font-
1207 weight that gives it a bold appearance: "\b{bold} text".-
1208-
1209 \note It is the responsibility of the caller to make sure that the-
1210 text is correctly decoded when a QString containing HTML is created-
1211 and passed to setHtml().-
1212-
1213 \sa setPlainText(), {Supported HTML Subset}-
1214*/-
1215-
1216#ifndef QT_NO_TEXTHTMLPARSER-
1217-
1218void QTextDocument::setHtml(const QString &html)-
1219{-
1220 Q_D(QTextDocument);-
1221 bool previousState = d->isUndoRedoEnabled();-
1222 d->enableUndoRedo(false);-
1223 d->beginEditBlock();-
1224 d->clear();-
1225 QTextHtmlImporter(this, html, QTextHtmlImporter::ImportToDocument).import();-
1226 d->endEditBlock();-
1227 d->enableUndoRedo(previousState);-
1228}-
1229-
1230#endif // QT_NO_TEXTHTMLPARSER-
1231-
1232/*!-
1233 \enum QTextDocument::FindFlag-
1234-
1235 This enum describes the options available to QTextDocument's find function. The options-
1236 can be OR-ed together from the following list:-
1237-
1238 \value FindBackward Search backwards instead of forwards.-
1239 \value FindCaseSensitively By default find works case insensitive. Specifying this option-
1240 changes the behaviour to a case sensitive find operation.-
1241 \value FindWholeWords Makes find match only complete words.-
1242*/-
1243-
1244/*!-
1245 \enum QTextDocument::MetaInformation-
1246-
1247 This enum describes the different types of meta information that can be-
1248 added to a document.-
1249-
1250 \value DocumentTitle The title of the document.-
1251 \value DocumentUrl The url of the document. The loadResource() function uses-
1252 this url as the base when loading relative resources.-
1253-
1254 \sa metaInformation(), setMetaInformation()-
1255*/-
1256-
1257static bool findInBlock(const QTextBlock &block, const QString &expression, int offset,-
1258 QTextDocument::FindFlags options, QTextCursor *cursor)-
1259{-
1260 QString text = block.text();-
1261 text.replace(QChar::Nbsp, QLatin1Char(' '));-
1262 Qt::CaseSensitivity sensitivity = options & QTextDocument::FindCaseSensitively ? Qt::CaseSensitive : Qt::CaseInsensitive;-
1263 int idx = -1;-
1264-
1265 while (offset >= 0 && offset <= text.length()) {-
1266 idx = (options & QTextDocument::FindBackward) ?-
1267 text.lastIndexOf(expression, offset, sensitivity) : text.indexOf(expression, offset, sensitivity);-
1268 if (idx == -1)-
1269 return false;-
1270-
1271 if (options & QTextDocument::FindWholeWords) {-
1272 const int start = idx;-
1273 const int end = start + expression.length();-
1274 if ((start != 0 && text.at(start - 1).isLetterOrNumber())-
1275 || (end != text.length() && text.at(end).isLetterOrNumber())) {-
1276 //if this is not a whole word, continue the search in the string-
1277 offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1;-
1278 idx = -1;-
1279 continue;-
1280 }-
1281 }-
1282 //we have a hit, return the cursor for that.-
1283 *cursor = QTextCursorPrivate::fromPosition(block.docHandle(), block.position() + idx);-
1284 cursor->setPosition(cursor->position() + expression.length(), QTextCursor::KeepAnchor);-
1285 return true;-
1286 }-
1287 return false;-
1288}-
1289-
1290/*!-
1291 \fn QTextCursor QTextDocument::find(const QString &subString, int position, FindFlags options) const-
1292-
1293 \overload-
1294-
1295 Finds the next occurrence of the string, \a subString, in the document.-
1296 The search starts at the given \a position, and proceeds forwards-
1297 through the document unless specified otherwise in the search options.-
1298 The \a options control the type of search performed.-
1299-
1300 Returns a cursor with the match selected if \a subString-
1301 was found; otherwise returns a null cursor.-
1302-
1303 If the \a position is 0 (the default) the search begins from the beginning-
1304 of the document; otherwise it begins at the specified position.-
1305*/-
1306QTextCursor QTextDocument::find(const QString &subString, int from, FindFlags options) const-
1307{-
1308 Q_D(const QTextDocument);-
1309-
1310 if (subString.isEmpty())-
1311 return QTextCursor();-
1312-
1313 int pos = from;-
1314 //the cursor is positioned between characters, so for a backward search-
1315 //do not include the character given in the position.-
1316 if (options & FindBackward) {-
1317 --pos ;-
1318 if (pos < 0)-
1319 return QTextCursor();-
1320 }-
1321-
1322 QTextCursor cursor;-
1323 QTextBlock block = d->blocksFind(pos);-
1324 int blockOffset = pos - block.position();-
1325-
1326 if (!(options & FindBackward)) {-
1327 while (block.isValid()) {-
1328 if (findInBlock(block, subString, blockOffset, options, &cursor))-
1329 return cursor;-
1330 block = block.next();-
1331 blockOffset = 0;-
1332 }-
1333 } else {-
1334 while (block.isValid()) {-
1335 if (findInBlock(block, subString, blockOffset, options, &cursor))-
1336 return cursor;-
1337 block = block.previous();-
1338 blockOffset = block.length() - 2;-
1339 }-
1340 }-
1341-
1342 return QTextCursor();-
1343}-
1344-
1345/*!-
1346 Finds the next occurrence of the string, \a subString, in the document.-
1347 The search starts at the position of the given \a cursor, and proceeds-
1348 forwards through the document unless specified otherwise in the search-
1349 options. The \a options control the type of search performed.-
1350-
1351 Returns a cursor with the match selected if \a subString was found; otherwise-
1352 returns a null cursor.-
1353-
1354 If the given \a cursor has a selection, the search begins after the-
1355 selection; otherwise it begins at the cursor's position.-
1356-
1357 By default the search is case-sensitive, and can match text anywhere in the-
1358 document.-
1359*/-
1360QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &cursor, FindFlags options) const-
1361{-
1362 int pos = 0;-
1363 if (!cursor.isNull()) {-
1364 if (options & QTextDocument::FindBackward)-
1365 pos = cursor.selectionStart();-
1366 else-
1367 pos = cursor.selectionEnd();-
1368 }-
1369-
1370 return find(subString, pos, options);-
1371}-
1372-
1373-
1374#ifndef QT_NO_REGEXP-
1375static bool findInBlock(const QTextBlock &block, const QRegExp &expression, int offset,-
1376 QTextDocument::FindFlags options, QTextCursor *cursor)-
1377{-
1378 QRegExp expr(expression);-
1379 QString text = block.text();-
1380 text.replace(QChar::Nbsp, QLatin1Char(' '));-
1381-
1382 int idx = -1;-
1383 while (offset >=0 && offset <= text.length()) {-
1384 idx = (options & QTextDocument::FindBackward) ?-
1385 expr.lastIndexIn(text, offset) : expr.indexIn(text, offset);-
1386 if (idx == -1)-
1387 return false;-
1388-
1389 if (options & QTextDocument::FindWholeWords) {-
1390 const int start = idx;-
1391 const int end = start + expr.matchedLength();-
1392 if ((start != 0 && text.at(start - 1).isLetterOrNumber())-
1393 || (end != text.length() && text.at(end).isLetterOrNumber())) {-
1394 //if this is not a whole word, continue the search in the string-
1395 offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1;-
1396 idx = -1;-
1397 continue;-
1398 }-
1399 }-
1400 //we have a hit, return the cursor for that.-
1401 *cursor = QTextCursorPrivate::fromPosition(block.docHandle(), block.position() + idx);-
1402 cursor->setPosition(cursor->position() + expr.matchedLength(), QTextCursor::KeepAnchor);-
1403 return true;-
1404 }-
1405 return false;-
1406}-
1407-
1408/*!-
1409 \overload-
1410-
1411 Finds the next occurrence that matches the given regular expression,-
1412 \a expr, within the same paragraph in the document.-
1413-
1414 The search starts at the given \a from position, and proceeds forwards-
1415 through the document unless specified otherwise in the search options.-
1416 The \a options control the type of search performed. The FindCaseSensitively-
1417 option is ignored for this overload, use QRegExp::caseSensitivity instead.-
1418-
1419 Returns a cursor with the match selected if a match was found; otherwise-
1420 returns a null cursor.-
1421-
1422 If the \a from position is 0 (the default) the search begins from the beginning-
1423 of the document; otherwise it begins at the specified position.-
1424*/-
1425QTextCursor QTextDocument::find(const QRegExp & expr, int from, FindFlags options) const-
1426{-
1427 Q_D(const QTextDocument);-
1428-
1429 if (expr.isEmpty())-
1430 return QTextCursor();-
1431-
1432 int pos = from;-
1433 //the cursor is positioned between characters, so for a backward search-
1434 //do not include the character given in the position.-
1435 if (options & FindBackward) {-
1436 --pos ;-
1437 if(pos < 0)-
1438 return QTextCursor();-
1439 }-
1440-
1441 QTextCursor cursor;-
1442 QTextBlock block = d->blocksFind(pos);-
1443 int blockOffset = pos - block.position();-
1444 if (!(options & FindBackward)) {-
1445 while (block.isValid()) {-
1446 if (findInBlock(block, expr, blockOffset, options, &cursor))-
1447 return cursor;-
1448 block = block.next();-
1449 blockOffset = 0;-
1450 }-
1451 } else {-
1452 while (block.isValid()) {-
1453 if (findInBlock(block, expr, blockOffset, options, &cursor))-
1454 return cursor;-
1455 block = block.previous();-
1456 blockOffset = block.length() - 1;-
1457 }-
1458 }-
1459-
1460 return QTextCursor();-
1461}-
1462-
1463/*!-
1464 \overload-
1465-
1466 Finds the next occurrence that matches the given regular expression,-
1467 \a expr, within the same paragraph in the document.-
1468-
1469 The search starts at the position of the given from \a cursor, and proceeds-
1470 forwards through the document unless specified otherwise in the search-
1471 options. The \a options control the type of search performed. The FindCaseSensitively-
1472 option is ignored for this overload, use QRegExp::caseSensitivity instead.-
1473-
1474 Returns a cursor with the match selected if a match was found; otherwise-
1475 returns a null cursor.-
1476-
1477 If the given \a cursor has a selection, the search begins after the-
1478 selection; otherwise it begins at the cursor's position.-
1479-
1480 By default the search is case-sensitive, and can match text anywhere in the-
1481 document.-
1482*/-
1483QTextCursor QTextDocument::find(const QRegExp &expr, const QTextCursor &cursor, FindFlags options) const-
1484{-
1485 int pos = 0;-
1486 if (!cursor.isNull()) {-
1487 if (options & QTextDocument::FindBackward)-
1488 pos = cursor.selectionStart();-
1489 else-
1490 pos = cursor.selectionEnd();-
1491 }-
1492 return find(expr, pos, options);-
1493}-
1494#endif // QT_REGEXP-
1495-
1496#ifndef QT_NO_REGULAREXPRESSION-
1497static bool findInBlock(const QTextBlock &block, const QRegularExpression &expression, int offset,-
1498 QTextDocument::FindFlags options, QTextCursor *cursor)-
1499{-
1500 QRegularExpression expr(expression);-
1501 if (!(options & QTextDocument::FindCaseSensitively))-
1502 expr.setPatternOptions(expr.patternOptions() | QRegularExpression::CaseInsensitiveOption);-
1503 else-
1504 expr.setPatternOptions(expr.patternOptions() & ~QRegularExpression::CaseInsensitiveOption);-
1505-
1506 QString text = block.text();-
1507 text.replace(QChar::Nbsp, QLatin1Char(' '));-
1508 QRegularExpressionMatch match;-
1509 int idx = -1;-
1510-
1511 while (offset >= 0 && offset <= text.length()) {-
1512 idx = (options & QTextDocument::FindBackward) ?-
1513 text.lastIndexOf(expr, offset, &match) : text.indexOf(expr, offset, &match);-
1514 if (idx == -1)-
1515 return false;-
1516-
1517 if (options & QTextDocument::FindWholeWords) {-
1518 const int start = idx;-
1519 const int end = start + match.capturedLength();-
1520 if ((start != 0 && text.at(start - 1).isLetterOrNumber())-
1521 || (end != text.length() && text.at(end).isLetterOrNumber())) {-
1522 //if this is not a whole word, continue the search in the string-
1523 offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1;-
1524 idx = -1;-
1525 continue;-
1526 }-
1527 }-
1528 //we have a hit, return the cursor for that.-
1529 *cursor = QTextCursorPrivate::fromPosition(block.docHandle(), block.position() + idx);-
1530 cursor->setPosition(cursor->position() + match.capturedLength(), QTextCursor::KeepAnchor);-
1531 return true;-
1532 }-
1533 return false;-
1534}-
1535-
1536/*!-
1537 \since 5.5-
1538-
1539 Finds the next occurrence that matches the given regular expression,-
1540 \a expr, within the same paragraph in the document.-
1541-
1542 The search starts at the given \a from position, and proceeds forwards-
1543 through the document unless specified otherwise in the search options.-
1544 The \a options control the type of search performed.-
1545-
1546 Returns a cursor with the match selected if a match was found; otherwise-
1547 returns a null cursor.-
1548-
1549 If the \a from position is 0 (the default) the search begins from the beginning-
1550 of the document; otherwise it begins at the specified position.-
1551*/-
1552QTextCursor QTextDocument::find(const QRegularExpression &expr, int from, FindFlags options) const-
1553{-
1554 Q_D(const QTextDocument);-
1555-
1556 if (!expr.isValid())-
1557 return QTextCursor();-
1558-
1559 int pos = from;-
1560 //the cursor is positioned between characters, so for a backward search-
1561 //do not include the character given in the position.-
1562 if (options & FindBackward) {-
1563 --pos ;-
1564 if (pos < 0)-
1565 return QTextCursor();-
1566 }-
1567-
1568 QTextCursor cursor;-
1569 QTextBlock block = d->blocksFind(pos);-
1570 int blockOffset = pos - block.position();-
1571-
1572 if (!(options & FindBackward)) {-
1573 while (block.isValid()) {-
1574 if (findInBlock(block, expr, blockOffset, options, &cursor))-
1575 return cursor;-
1576 block = block.next();-
1577 blockOffset = 0;-
1578 }-
1579 } else {-
1580 while (block.isValid()) {-
1581 if (findInBlock(block, expr, blockOffset, options, &cursor))-
1582 return cursor;-
1583 block = block.previous();-
1584 blockOffset = block.length() - 1;-
1585 }-
1586 }-
1587-
1588 return QTextCursor();-
1589}-
1590-
1591/*!-
1592 \since 5.5-
1593-
1594 Finds the next occurrence that matches the given regular expression,-
1595 \a expr, within the same paragraph in the document.-
1596-
1597 The search starts at the position of the given \a cursor, and proceeds-
1598 forwards through the document unless specified otherwise in the search-
1599 options. The \a options control the type of search performed.-
1600-
1601 Returns a cursor with the match selected if a match was found; otherwise-
1602 returns a null cursor.-
1603-
1604 If the given \a cursor has a selection, the search begins after the-
1605 selection; otherwise it begins at the cursor's position.-
1606-
1607 By default the search is case-sensitive, and can match text anywhere in the-
1608 document.-
1609*/-
1610QTextCursor QTextDocument::find(const QRegularExpression &expr, const QTextCursor &cursor, FindFlags options) const-
1611{-
1612 int pos = 0;-
1613 if (!cursor.isNull()) {-
1614 if (options & QTextDocument::FindBackward)-
1615 pos = cursor.selectionStart();-
1616 else-
1617 pos = cursor.selectionEnd();-
1618 }-
1619 return find(expr, pos, options);-
1620}-
1621#endif // QT_NO_REGULAREXPRESSION-
1622-
1623/*!-
1624 \fn QTextObject *QTextDocument::createObject(const QTextFormat &format)-
1625-
1626 Creates and returns a new document object (a QTextObject), based-
1627 on the given \a format.-
1628-
1629 QTextObjects will always get created through this method, so you-
1630 must reimplement it if you use custom text objects inside your document.-
1631*/-
1632QTextObject *QTextDocument::createObject(const QTextFormat &f)-
1633{-
1634 QTextObject *obj = 0;-
1635 if (f.isListFormat())-
1636 obj = new QTextList(this);-
1637 else if (f.isTableFormat())-
1638 obj = new QTextTable(this);-
1639 else if (f.isFrameFormat())-
1640 obj = new QTextFrame(this);-
1641-
1642 return obj;-
1643}-
1644-
1645/*!-
1646 \internal-
1647-
1648 Returns the frame that contains the text cursor position \a pos.-
1649*/-
1650QTextFrame *QTextDocument::frameAt(int pos) const-
1651{-
1652 Q_D(const QTextDocument);-
1653 return d->frameAt(pos);-
1654}-
1655-
1656/*!-
1657 Returns the document's root frame.-
1658*/-
1659QTextFrame *QTextDocument::rootFrame() const-
1660{-
1661 Q_D(const QTextDocument);-
1662 return d->rootFrame();-
1663}-
1664-
1665/*!-
1666 Returns the text object associated with the given \a objectIndex.-
1667*/-
1668QTextObject *QTextDocument::object(int objectIndex) const-
1669{-
1670 Q_D(const QTextDocument);-
1671 return d->objectForIndex(objectIndex);-
1672}-
1673-
1674/*!-
1675 Returns the text object associated with the format \a f.-
1676*/-
1677QTextObject *QTextDocument::objectForFormat(const QTextFormat &f) const-
1678{-
1679 Q_D(const QTextDocument);-
1680 return d->objectForFormat(f);-
1681}-
1682-
1683-
1684/*!-
1685 Returns the text block that contains the \a{pos}-th character.-
1686*/-
1687QTextBlock QTextDocument::findBlock(int pos) const-
1688{-
1689 Q_D(const QTextDocument);-
1690 return QTextBlock(docHandle(), d->blockMap().findNode(pos));-
1691}-
1692-
1693/*!-
1694 \since 4.4-
1695 Returns the text block with the specified \a blockNumber.-
1696-
1697 \sa QTextBlock::blockNumber()-
1698*/-
1699QTextBlock QTextDocument::findBlockByNumber(int blockNumber) const-
1700{-
1701 Q_D(const QTextDocument);-
1702 return QTextBlock(docHandle(), d->blockMap().findNode(blockNumber, 1));-
1703}-
1704-
1705/*!-
1706 \since 4.5-
1707 Returns the text block that contains the specified \a lineNumber.-
1708-
1709 \sa QTextBlock::firstLineNumber()-
1710*/-
1711QTextBlock QTextDocument::findBlockByLineNumber(int lineNumber) const-
1712{-
1713 Q_D(const QTextDocument);-
1714 return QTextBlock(docHandle(), d->blockMap().findNode(lineNumber, 2));-
1715}-
1716-
1717/*!-
1718 Returns the document's first text block.-
1719-
1720 \sa firstBlock()-
1721*/-
1722QTextBlock QTextDocument::begin() const-
1723{-
1724 Q_D(const QTextDocument);-
1725 return QTextBlock(docHandle(), d->blockMap().begin().n);-
1726}-
1727-
1728/*!-
1729 This function returns a block to test for the end of the document-
1730 while iterating over it.-
1731-
1732 \snippet textdocumentendsnippet.cpp 0-
1733-
1734 The block returned is invalid and represents the block after the-
1735 last block in the document. You can use lastBlock() to retrieve the-
1736 last valid block of the document.-
1737-
1738 \sa lastBlock()-
1739*/-
1740QTextBlock QTextDocument::end() const-
1741{-
1742 return QTextBlock(docHandle(), 0);-
1743}-
1744-
1745/*!-
1746 \since 4.4-
1747 Returns the document's first text block.-
1748*/-
1749QTextBlock QTextDocument::firstBlock() const-
1750{-
1751 Q_D(const QTextDocument);-
1752 return QTextBlock(docHandle(), d->blockMap().begin().n);-
1753}-
1754-
1755/*!-
1756 \since 4.4-
1757 Returns the document's last (valid) text block.-
1758*/-
1759QTextBlock QTextDocument::lastBlock() const-
1760{-
1761 Q_D(const QTextDocument);-
1762 return QTextBlock(docHandle(), d->blockMap().last().n);-
1763}-
1764-
1765/*!-
1766 \property QTextDocument::pageSize-
1767 \brief the page size that should be used for laying out the document-
1768-
1769 The units are determined by the underlying paint device. The size is-
1770 measured in logical pixels when painting to the screen, and in points-
1771 (1/72 inch) when painting to a printer.-
1772-
1773 By default, for a newly-created, empty document, this property contains-
1774 an undefined size.-
1775-
1776 \sa modificationChanged()-
1777*/-
1778-
1779void QTextDocument::setPageSize(const QSizeF &size)-
1780{-
1781 Q_D(QTextDocument);-
1782 d->pageSize = size;-
1783 if (d->lout)-
1784 d->lout->documentChanged(0, 0, d->length());-
1785}-
1786-
1787QSizeF QTextDocument::pageSize() const-
1788{-
1789 Q_D(const QTextDocument);-
1790 return d->pageSize;-
1791}-
1792-
1793/*!-
1794 returns the number of pages in this document.-
1795*/-
1796int QTextDocument::pageCount() const-
1797{-
1798 return documentLayout()->pageCount();-
1799}-
1800-
1801/*!-
1802 Sets the default \a font to use in the document layout.-
1803*/-
1804void QTextDocument::setDefaultFont(const QFont &font)-
1805{-
1806 Q_D(QTextDocument);-
1807 d->setDefaultFont(font);-
1808 if (d->lout)-
1809 d->lout->documentChanged(0, 0, d->length());-
1810}-
1811-
1812/*!-
1813 Returns the default font to be used in the document layout.-
1814*/-
1815QFont QTextDocument::defaultFont() const-
1816{-
1817 Q_D(const QTextDocument);-
1818 return d->defaultFont();-
1819}-
1820-
1821/*!-
1822 \fn QTextDocument::modificationChanged(bool changed)-
1823-
1824 This signal is emitted whenever the content of the document-
1825 changes in a way that affects the modification state. If \a-
1826 changed is true, the document has been modified; otherwise it is-
1827 false.-
1828-
1829 For example, calling setModified(false) on a document and then-
1830 inserting text causes the signal to get emitted. If you undo that-
1831 operation, causing the document to return to its original-
1832 unmodified state, the signal will get emitted again.-
1833*/-
1834-
1835/*!-
1836 \property QTextDocument::modified-
1837 \brief whether the document has been modified by the user-
1838-
1839 By default, this property is \c false.-
1840-
1841 \sa modificationChanged()-
1842*/-
1843-
1844bool QTextDocument::isModified() const-
1845{-
1846 return docHandle()->isModified();-
1847}-
1848-
1849void QTextDocument::setModified(bool m)-
1850{-
1851 docHandle()->setModified(m);-
1852}-
1853-
1854#ifndef QT_NO_PRINTER-
1855static void printPage(int index, QPainter *painter, const QTextDocument *doc, const QRectF &body, const QPointF &pageNumberPos)-
1856{-
1857 painter->save();-
1858 painter->translate(body.left(), body.top() - (index - 1) * body.height());-
1859 QRectF view(0, (index - 1) * body.height(), body.width(), body.height());-
1860-
1861 QAbstractTextDocumentLayout *layout = doc->documentLayout();-
1862 QAbstractTextDocumentLayout::PaintContext ctx;-
1863-
1864 painter->setClipRect(view);-
1865 ctx.clip = view;-
1866-
1867 // don't use the system palette text as default text color, on HP/UX-
1868 // for example that's white, and white text on white paper doesn't-
1869 // look that nice-
1870 ctx.palette.setColor(QPalette::Text, Qt::black);-
1871-
1872 layout->draw(painter, ctx);-
1873-
1874 if (!pageNumberPos.isNull()) {-
1875 painter->setClipping(false);-
1876 painter->setFont(QFont(doc->defaultFont()));-
1877 const QString pageString = QString::number(index);-
1878-
1879 painter->drawText(qRound(pageNumberPos.x() - painter->fontMetrics().width(pageString)),-
1880 qRound(pageNumberPos.y() + view.top()),-
1881 pageString);-
1882 }-
1883-
1884 painter->restore();-
1885}-
1886-
1887/*!-
1888 Prints the document to the given \a printer. The QPageablePaintDevice must be-
1889 set up before being used with this function.-
1890-
1891 This is only a convenience method to print the whole document to the printer.-
1892-
1893 If the document is already paginated through a specified height in the pageSize()-
1894 property it is printed as-is.-
1895-
1896 If the document is not paginated, like for example a document used in a QTextEdit,-
1897 then a temporary copy of the document is created and the copy is broken into-
1898 multiple pages according to the size of the paint device's paperRect(). By default-
1899 a 2 cm margin is set around the document contents. In addition the current page-
1900 number is printed at the bottom of each page.-
1901-
1902 \sa QTextEdit::print()-
1903*/-
1904-
1905void QTextDocument::print(QPagedPaintDevice *printer) const-
1906{-
1907 Q_D(const QTextDocument);-
1908-
1909 if (!printer)-
1910 return;-
1911-
1912 bool documentPaginated = d->pageSize.isValid() && !d->pageSize.isNull()-
1913 && d->pageSize.height() != INT_MAX;-
1914-
1915 QPagedPaintDevicePrivate *pd = QPagedPaintDevicePrivate::get(printer);-
1916-
1917 // ### set page size to paginated size?-
1918 QPagedPaintDevice::Margins m = printer->margins();-
1919 if (!documentPaginated && m.left == 0. && m.right == 0. && m.top == 0. && m.bottom == 0.) {-
1920 m.left = m.right = m.top = m.bottom = 2.;-
1921 printer->setMargins(m);-
1922 }-
1923 // ### use the margins correctly-
1924-
1925 QPainter p(printer);-
1926-
1927 // Check that there is a valid device to print to.-
1928 if (!p.isActive())-
1929 return;-
1930-
1931 const QTextDocument *doc = this;-
1932 QScopedPointer<QTextDocument> clonedDoc;-
1933 (void)doc->documentLayout(); // make sure that there is a layout-
1934-
1935 QRectF body = QRectF(QPointF(0, 0), d->pageSize);-
1936 QPointF pageNumberPos;-
1937-
1938 if (documentPaginated) {-
1939 qreal sourceDpiX = qt_defaultDpi();-
1940 qreal sourceDpiY = sourceDpiX;-
1941-
1942 QPaintDevice *dev = doc->documentLayout()->paintDevice();-
1943 if (dev) {-
1944 sourceDpiX = dev->logicalDpiX();-
1945 sourceDpiY = dev->logicalDpiY();-
1946 }-
1947-
1948 const qreal dpiScaleX = qreal(printer->logicalDpiX()) / sourceDpiX;-
1949 const qreal dpiScaleY = qreal(printer->logicalDpiY()) / sourceDpiY;-
1950-
1951 // scale to dpi-
1952 p.scale(dpiScaleX, dpiScaleY);-
1953-
1954 QSizeF scaledPageSize = d->pageSize;-
1955 scaledPageSize.rwidth() *= dpiScaleX;-
1956 scaledPageSize.rheight() *= dpiScaleY;-
1957-
1958 const QSizeF printerPageSize(printer->width(), printer->height());-
1959-
1960 // scale to page-
1961 p.scale(printerPageSize.width() / scaledPageSize.width(),-
1962 printerPageSize.height() / scaledPageSize.height());-
1963 } else {-
1964 doc = clone(const_cast<QTextDocument *>(this));-
1965 clonedDoc.reset(const_cast<QTextDocument *>(doc));-
1966-
1967 for (QTextBlock srcBlock = firstBlock(), dstBlock = clonedDoc->firstBlock();-
1968 srcBlock.isValid() && dstBlock.isValid();-
1969 srcBlock = srcBlock.next(), dstBlock = dstBlock.next()) {-
1970 dstBlock.layout()->setFormats(srcBlock.layout()->formats());-
1971 }-
1972-
1973 QAbstractTextDocumentLayout *layout = doc->documentLayout();-
1974 layout->setPaintDevice(p.device());-
1975-
1976 // copy the custom object handlers-
1977 layout->d_func()->handlers = documentLayout()->d_func()->handlers;-
1978-
1979 int dpiy = p.device()->logicalDpiY();-
1980 int margin = (int) ((2/2.54)*dpiy); // 2 cm margins-
1981 QTextFrameFormat fmt = doc->rootFrame()->frameFormat();-
1982 fmt.setMargin(margin);-
1983 doc->rootFrame()->setFrameFormat(fmt);-
1984-
1985 body = QRectF(0, 0, printer->width(), printer->height());-
1986 pageNumberPos = QPointF(body.width() - margin,-
1987 body.height() - margin-
1988 + QFontMetrics(doc->defaultFont(), p.device()).ascent()-
1989 + 5 * dpiy / 72.0);-
1990 clonedDoc->setPageSize(body.size());-
1991 }-
1992-
1993 int fromPage = pd->fromPage;-
1994 int toPage = pd->toPage;-
1995 bool ascending = true;-
1996-
1997 if (fromPage == 0 && toPage == 0) {-
1998 fromPage = 1;-
1999 toPage = doc->pageCount();-
2000 }-
2001 // paranoia check-
2002 fromPage = qMax(1, fromPage);-
2003 toPage = qMin(doc->pageCount(), toPage);-
2004-
2005 if (toPage < fromPage) {-
2006 // if the user entered a page range outside the actual number-
2007 // of printable pages, just return-
2008 return;-
2009 }-
2010-
2011// if (printer->pageOrder() == QPrinter::LastPageFirst) {-
2012// int tmp = fromPage;-
2013// fromPage = toPage;-
2014// toPage = tmp;-
2015// ascending = false;-
2016// }-
2017-
2018 int page = fromPage;-
2019 while (true) {-
2020 printPage(page, &p, doc, body, pageNumberPos);-
2021-
2022 if (page == toPage)-
2023 break;-
2024-
2025 if (ascending)-
2026 ++page;-
2027 else-
2028 --page;-
2029-
2030 if (!printer->newPage())-
2031 return;-
2032 }-
2033}-
2034#endif-
2035-
2036/*!-
2037 \enum QTextDocument::ResourceType-
2038-
2039 This enum describes the types of resources that can be loaded by-
2040 QTextDocument's loadResource() function.-
2041-
2042 \value HtmlResource The resource contains HTML.-
2043 \value ImageResource The resource contains image data.-
2044 Currently supported data types are QVariant::Pixmap and-
2045 QVariant::Image. If the corresponding variant is of type-
2046 QVariant::ByteArray then Qt attempts to load the image using-
2047 QImage::loadFromData. QVariant::Icon is currently not supported.-
2048 The icon needs to be converted to one of the supported types first,-
2049 for example using QIcon::pixmap.-
2050 \value StyleSheetResource The resource contains CSS.-
2051 \value UserResource The first available value for user defined-
2052 resource types.-
2053-
2054 \sa loadResource()-
2055*/-
2056-
2057/*!-
2058 Returns data of the specified \a type from the resource with the-
2059 given \a name.-
2060-
2061 This function is called by the rich text engine to request data that isn't-
2062 directly stored by QTextDocument, but still associated with it. For example,-
2063 images are referenced indirectly by the name attribute of a QTextImageFormat-
2064 object.-
2065-
2066 Resources are cached internally in the document. If a resource can-
2067 not be found in the cache, loadResource is called to try to load-
2068 the resource. loadResource should then use addResource to add the-
2069 resource to the cache.-
2070-
2071 \sa QTextDocument::ResourceType-
2072*/-
2073QVariant QTextDocument::resource(int type, const QUrl &name) const-
2074{-
2075 Q_D(const QTextDocument);-
2076 const QUrl url = d->baseUrl.resolved(name);-
2077 QVariant r = d->resources.value(url);-
2078 if (!r.isValid()) {-
2079 r = d->cachedResources.value(url);-
2080 if (!r.isValid())-
2081 r = const_cast<QTextDocument *>(this)->loadResource(type, url);-
2082 }-
2083 return r;-
2084}-
2085-
2086/*!-
2087 Adds the resource \a resource to the resource cache, using \a-
2088 type and \a name as identifiers. \a type should be a value from-
2089 QTextDocument::ResourceType.-
2090-
2091 For example, you can add an image as a resource in order to reference it-
2092 from within the document:-
2093-
2094 \snippet textdocument-resources/main.cpp Adding a resource-
2095-
2096 The image can be inserted into the document using the QTextCursor API:-
2097-
2098 \snippet textdocument-resources/main.cpp Inserting an image with a cursor-
2099-
2100 Alternatively, you can insert images using the HTML \c img tag:-
2101-
2102 \snippet textdocument-resources/main.cpp Inserting an image using HTML-
2103*/-
2104void QTextDocument::addResource(int type, const QUrl &name, const QVariant &resource)-
2105{-
2106 Q_UNUSED(type);-
2107 Q_D(QTextDocument);-
2108 d->resources.insert(name, resource);-
2109}-
2110-
2111/*!-
2112 Loads data of the specified \a type from the resource with the-
2113 given \a name.-
2114-
2115 This function is called by the rich text engine to request data that isn't-
2116 directly stored by QTextDocument, but still associated with it. For example,-
2117 images are referenced indirectly by the name attribute of a QTextImageFormat-
2118 object.-
2119-
2120 When called by Qt, \a type is one of the values of-
2121 QTextDocument::ResourceType.-
2122-
2123 If the QTextDocument is a child object of a QObject that has an invokable-
2124 loadResource method such as QTextEdit, QTextBrowser-
2125 or a QTextDocument itself then the default implementation tries-
2126 to retrieve the data from the parent.-
2127*/-
2128QVariant QTextDocument::loadResource(int type, const QUrl &name)-
2129{-
2130 Q_D(QTextDocument);-
2131 QVariant r;-
2132-
2133 QObject *p = parent();-
2134 if (p) {-
2135 const QMetaObject *me = p->metaObject();-
2136 int index = me->indexOfMethod("loadResource(int,QUrl)");-
2137 if (index >= 0) {-
2138 QMetaMethod loader = me->method(index);-
2139 loader.invoke(p, Q_RETURN_ARG(QVariant, r), Q_ARG(int, type), Q_ARG(QUrl, name));-
2140 }-
2141 }-
2142-
2143 // handle data: URLs-
2144 if (r.isNull() && name.scheme().compare(QLatin1String("data"), Qt::CaseInsensitive) == 0) {-
2145 QString mimetype;-
2146 QByteArray payload;-
2147 if (qDecodeDataUrl(name, mimetype, payload))-
2148 r = payload;-
2149 }-
2150-
2151 // if resource was not loaded try to load it here-
2152 if (!qobject_cast<QTextDocument *>(p) && r.isNull()) {-
2153 QUrl resourceUrl = name;-
2154-
2155 if (name.isRelative()) {-
2156 QUrl currentURL = d->url;-
2157 // For the second case QUrl can merge "#someanchor" with "foo.html"-
2158 // correctly to "foo.html#someanchor"-
2159 if (!(currentURL.isRelative()-
2160 || (currentURL.scheme() == QLatin1String("file")-
2161 && !QFileInfo(currentURL.toLocalFile()).isAbsolute()))-
2162 || (name.hasFragment() && name.path().isEmpty())) {-
2163 resourceUrl = currentURL.resolved(name);-
2164 } else {-
2165 // this is our last resort when current url and new url are both relative-
2166 // we try to resolve against the current working directory in the local-
2167 // file system.-
2168 QFileInfo fi(currentURL.toLocalFile());-
2169 if (fi.exists()) {-
2170 resourceUrl =-
2171 QUrl::fromLocalFile(fi.absolutePath() + QDir::separator()).resolved(name);-
2172 } else if (currentURL.isEmpty()) {-
2173 resourceUrl.setScheme(QLatin1String("file"));-
2174 }-
2175 }-
2176 }-
2177-
2178 QString s = resourceUrl.toLocalFile();-
2179 QFile f(s);-
2180 if (!s.isEmpty() && f.open(QFile::ReadOnly)) {-
2181 r = f.readAll();-
2182 f.close();-
2183 }-
2184 }-
2185-
2186 if (!r.isNull()) {-
2187 if (type == ImageResource && r.type() == QVariant::ByteArray) {-
2188 if (qApp->thread() != QThread::currentThread()) {-
2189 // must use images in non-GUI threads-
2190 QImage image;-
2191 image.loadFromData(r.toByteArray());-
2192 if (!image.isNull())-
2193 r = image;-
2194 } else {-
2195 QPixmap pm;-
2196 pm.loadFromData(r.toByteArray());-
2197 if (!pm.isNull())-
2198 r = pm;-
2199 }-
2200 }-
2201 d->cachedResources.insert(name, r);-
2202 }-
2203 return r;-
2204}-
2205-
2206static QTextFormat formatDifference(const QTextFormat &from, const QTextFormat &to)-
2207{-
2208 QTextFormat diff = to;-
2209-
2210 const QMap<int, QVariant> props = to.properties();-
2211 for (QMap<int, QVariant>::ConstIterator it = props.begin(), end = props.end();-
2212 it != end; ++it)-
2213 if (it.value() == from.property(it.key()))-
2214 diff.clearProperty(it.key());-
2215-
2216 return diff;-
2217}-
2218-
2219static QString colorValue(QColor color)-
2220{-
2221 QString result;-
2222-
2223 if (color.alpha() == 255) {-
2224 result = color.name();-
2225 } else if (color.alpha()) {-
2226 QString alphaValue = QString::number(color.alphaF(), 'f', 6).remove(QRegExp(QLatin1String("\\.?0*$")));-
2227 result = QString::fromLatin1("rgba(%1,%2,%3,%4)").arg(color.red())-
2228 .arg(color.green())-
2229 .arg(color.blue())-
2230 .arg(alphaValue);-
2231 } else {-
2232 result = QLatin1String("transparent");-
2233 }-
2234-
2235 return result;-
2236}-
2237-
2238QTextHtmlExporter::QTextHtmlExporter(const QTextDocument *_doc)-
2239 : doc(_doc), fragmentMarkers(false)-
2240{-
2241 const QFont defaultFont = doc->defaultFont();-
2242 defaultCharFormat.setFont(defaultFont);-
2243 // don't export those for the default font since we cannot turn them off with CSS-
2244 defaultCharFormat.clearProperty(QTextFormat::FontUnderline);-
2245 defaultCharFormat.clearProperty(QTextFormat::FontOverline);-
2246 defaultCharFormat.clearProperty(QTextFormat::FontStrikeOut);-
2247 defaultCharFormat.clearProperty(QTextFormat::TextUnderlineStyle);-
2248}-
2249-
2250/*!-
2251 Returns the document in HTML format. The conversion may not be-
2252 perfect, especially for complex documents, due to the limitations-
2253 of HTML.-
2254*/-
2255QString QTextHtmlExporter::toHtml(const QByteArray &encoding, ExportMode mode)-
2256{-
2257 html = QLatin1String("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" "-
2258 "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"-
2259 "<html><head><meta name=\"qrichtext\" content=\"1\" />");-
2260 html.reserve(doc->docHandle()->length());-
2261-
2262 fragmentMarkers = (mode == ExportFragment);-
2263-
2264 if (!encoding.isEmpty())-
2265 html += QString::fromLatin1("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%1\" />").arg(QString::fromLatin1(encoding));-
2266-
2267 QString title = doc->metaInformation(QTextDocument::DocumentTitle);-
2268 if (!title.isEmpty())-
2269 html += QString::fromLatin1("<title>") + title + QString::fromLatin1("</title>");-
2270 html += QLatin1String("<style type=\"text/css\">\n");-
2271 html += QLatin1String("p, li { white-space: pre-wrap; }\n");-
2272 html += QLatin1String("</style>");-
2273 html += QLatin1String("</head><body");-
2274-
2275 if (mode == ExportEntireDocument) {-
2276 html += QLatin1String(" style=\"");-
2277-
2278 emitFontFamily(defaultCharFormat.fontFamily());-
2279-
2280 if (defaultCharFormat.hasProperty(QTextFormat::FontPointSize)) {-
2281 html += QLatin1String(" font-size:");-
2282 html += QString::number(defaultCharFormat.fontPointSize());-
2283 html += QLatin1String("pt;");-
2284 } else if (defaultCharFormat.hasProperty(QTextFormat::FontPixelSize)) {-
2285 html += QLatin1String(" font-size:");-
2286 html += QString::number(defaultCharFormat.intProperty(QTextFormat::FontPixelSize));-
2287 html += QLatin1String("px;");-
2288 }-
2289-
2290 html += QLatin1String(" font-weight:");-
2291 html += QString::number(defaultCharFormat.fontWeight() * 8);-
2292 html += QLatin1Char(';');-
2293-
2294 html += QLatin1String(" font-style:");-
2295 html += (defaultCharFormat.fontItalic() ? QLatin1String("italic") : QLatin1String("normal"));-
2296 html += QLatin1Char(';');-
2297-
2298 // do not set text-decoration on the default font since those values are /always/ propagated-
2299 // and cannot be turned off with CSS-
2300-
2301 html += QLatin1Char('\"');-
2302-
2303 const QTextFrameFormat fmt = doc->rootFrame()->frameFormat();-
2304 emitBackgroundAttribute(fmt);-
2305-
2306 } else {-
2307 defaultCharFormat = QTextCharFormat();-
2308 }-
2309 html += QLatin1Char('>');-
2310-
2311 QTextFrameFormat rootFmt = doc->rootFrame()->frameFormat();-
2312 rootFmt.clearProperty(QTextFormat::BackgroundBrush);-
2313-
2314 QTextFrameFormat defaultFmt;-
2315 defaultFmt.setMargin(doc->documentMargin());-
2316-
2317 if (rootFmt == defaultFmt)-
2318 emitFrame(doc->rootFrame()->begin());-
2319 else-
2320 emitTextFrame(doc->rootFrame());-
2321-
2322 html += QLatin1String("</body></html>");-
2323 return html;-
2324}-
2325-
2326void QTextHtmlExporter::emitAttribute(const char *attribute, const QString &value)-
2327{-
2328 html += QLatin1Char(' ');-
2329 html += QLatin1String(attribute);-
2330 html += QLatin1String("=\"");-
2331 html += value.toHtmlEscaped();-
2332 html += QLatin1Char('"');-
2333}-
2334-
2335bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)-
2336{-
2337 bool attributesEmitted = false;-
2338-
2339 {-
2340 const QString family = format.fontFamily();-
2341 if (!family.isEmpty() && family != defaultCharFormat.fontFamily()) {
!family.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
family != defa...t.fontFamily()Description
TRUEnever evaluated
FALSEnever evaluated
0
2342 emitFontFamily(family);-
2343 attributesEmitted = true;-
2344 }
never executed: end of block
0
2345 }-
2346-
2347 if (format.hasProperty(QTextFormat::FontPointSize)
format.hasProp...FontPointSize)Description
TRUEnever evaluated
FALSEnever evaluated
0
2348 && format.fontPointSize() != defaultCharFormat.fontPointSize()) {
format.fontPoi...ontPointSize()Description
TRUEnever evaluated
FALSEnever evaluated
0
2349 html += QLatin1String(" font-size:");-
2350 html += QString::number(format.fontPointSize());-
2351 html += QLatin1String("pt;");-
2352 attributesEmitted = true;-
2353 } else if (format.hasProperty(QTextFormat::FontSizeAdjustment)) {
never executed: end of block
format.hasProp...izeAdjustment)Description
TRUEnever evaluated
FALSEnever evaluated
0
2354 static const char sizeNameData[] =-
2355 "small" "\0"-
2356 "medium" "\0"-
2357 "xx-large" ;-
2358 static const quint8 sizeNameOffsets[] = {-
2359 0, // "small"-
2360 sizeof("small"), // "medium"-
2361 sizeof("small") + sizeof("medium") + 3, // "large" )-
2362 sizeof("small") + sizeof("medium") + 1, // "x-large" )> compressed into "xx-large"-
2363 sizeof("small") + sizeof("medium"), // "xx-large" )-
2364 };-
2365 const char *name = 0;-
2366 const int idx = format.intProperty(QTextFormat::FontSizeAdjustment) + 1;-
2367 if (idx >= 0 && idx <= 4) {
idx >= 0Description
TRUEnever evaluated
FALSEnever evaluated
idx <= 4Description
TRUEnever evaluated
FALSEnever evaluated
0
2368 name = sizeNameData + sizeNameOffsets[idx];-
2369 }
never executed: end of block
0
2370 if (name) {
nameDescription
TRUEnever evaluated
FALSEnever evaluated
0
2371 html += QLatin1String(" font-size:");-
2372 html += QLatin1String(name);-
2373 html += QLatin1Char(';');-
2374 attributesEmitted = true;-
2375 }
never executed: end of block
0
2376 } else if (format.hasProperty(QTextFormat::FontPixelSize)) {
never executed: end of block
format.hasProp...FontPixelSize)Description
TRUEnever evaluated
FALSEnever evaluated
0
2377 html += QLatin1String(" font-size:");-
2378 html += QString::number(format.intProperty(QTextFormat::FontPixelSize));-
2379 html += QLatin1String("px;");-
2380 attributesEmitted = true;-
2381 }
never executed: end of block
0
2382-
2383 if (format.hasProperty(QTextFormat::FontWeight)
format.hasProp...t::FontWeight)Description
TRUEnever evaluated
FALSEnever evaluated
0
2384 && format.fontWeight() != defaultCharFormat.fontWeight()) {
format.fontWei...t.fontWeight()Description
TRUEnever evaluated
FALSEnever evaluated
0
2385 html += QLatin1String(" font-weight:");-
2386 html += QString::number(format.fontWeight() * 8);-
2387 html += QLatin1Char(';');-
2388 attributesEmitted = true;-
2389 }
never executed: end of block
0
2390-
2391 if (format.hasProperty(QTextFormat::FontItalic)
format.hasProp...t::FontItalic)Description
TRUEnever evaluated
FALSEnever evaluated
0
2392 && format.fontItalic() != defaultCharFormat.fontItalic()) {
format.fontIta...t.fontItalic()Description
TRUEnever evaluated
FALSEnever evaluated
0
2393 html += QLatin1String(" font-style:");-
2394 html += (format.fontItalic() ? QLatin1String("italic") : QLatin1String("normal"));
format.fontItalic()Description
TRUEnever evaluated
FALSEnever evaluated
0
2395 html += QLatin1Char(';');-
2396 attributesEmitted = true;-
2397 }
never executed: end of block
0
2398-
2399 QLatin1String decorationTag(" text-decoration:");-
2400 html += decorationTag;-
2401 bool hasDecoration = false;-
2402 bool atLeastOneDecorationSet = false;-
2403-
2404 if ((format.hasProperty(QTextFormat::FontUnderline) || format.hasProperty(QTextFormat::TextUnderlineStyle))
format.hasProp...FontUnderline)Description
TRUEnever evaluated
FALSEnever evaluated
format.hasProp...nderlineStyle)Description
TRUEnever evaluated
FALSEnever evaluated
0
2405 && format.fontUnderline() != defaultCharFormat.fontUnderline()) {
format.fontUnd...ontUnderline()Description
TRUEnever evaluated
FALSEnever evaluated
0
2406 hasDecoration = true;-
2407 if (format.fontUnderline()) {
format.fontUnderline()Description
TRUEnever evaluated
FALSEnever evaluated
0
2408 html += QLatin1String(" underline");-
2409 atLeastOneDecorationSet = true;-
2410 }
never executed: end of block
0
2411 }
never executed: end of block
0
2412-
2413 if (format.hasProperty(QTextFormat::FontOverline)
format.hasProp...:FontOverline)Description
TRUEnever evaluated
FALSEnever evaluated
0
2414 && format.fontOverline() != defaultCharFormat.fontOverline()) {
format.fontOve...fontOverline()Description
TRUEnever evaluated
FALSEnever evaluated
0
2415 hasDecoration = true;-
2416 if (format.fontOverline()) {
format.fontOverline()Description
TRUEnever evaluated
FALSEnever evaluated
0
2417 html += QLatin1String(" overline");-
2418 atLeastOneDecorationSet = true;-
2419 }
never executed: end of block
0
2420 }
never executed: end of block
0
2421-
2422 if (format.hasProperty(QTextFormat::FontStrikeOut)
format.hasProp...FontStrikeOut)Description
TRUEnever evaluated
FALSEnever evaluated
0
2423 && format.fontStrikeOut() != defaultCharFormat.fontStrikeOut()) {
format.fontStr...ontStrikeOut()Description
TRUEnever evaluated
FALSEnever evaluated
0
2424 hasDecoration = true;-
2425 if (format.fontStrikeOut()) {
format.fontStrikeOut()Description
TRUEnever evaluated
FALSEnever evaluated
0
2426 html += QLatin1String(" line-through");-
2427 atLeastOneDecorationSet = true;-
2428 }
never executed: end of block
0
2429 }
never executed: end of block
0
2430-
2431 if (hasDecoration) {
hasDecorationDescription
TRUEnever evaluated
FALSEnever evaluated
0
2432 if (!atLeastOneDecorationSet)
!atLeastOneDecorationSetDescription
TRUEnever evaluated
FALSEnever evaluated
0
2433 html += QLatin1String("none");
never executed: html += QLatin1String("none");
0
2434 html += QLatin1Char(';');-
2435 attributesEmitted = true;-
2436 } else {
never executed: end of block
0
2437 html.chop(qstrlen(decorationTag.latin1()));size());-
2438 }
never executed: end of block
0
2439-
2440 if (format.foreground() != defaultCharFormat.foreground()
format.foregro...t.foreground()Description
TRUEnever evaluated
FALSEnever evaluated
0
2441 && format.foreground().style() != Qt::NoBrush) {
format.foregro...!= Qt::NoBrushDescription
TRUEnever evaluated
FALSEnever evaluated
0
2442 html += QLatin1String(" color:");-
2443 html += colorValue(format.foreground().color());-
2444 html += QLatin1Char(';');-
2445 attributesEmitted = true;-
2446 }
never executed: end of block
0
2447-
2448 if (format.background() != defaultCharFormat.background()
format.backgro...t.background()Description
TRUEnever evaluated
FALSEnever evaluated
0
2449 && format.background().style() == Qt::SolidPattern) {
format.backgro...::SolidPatternDescription
TRUEnever evaluated
FALSEnever evaluated
0
2450 html += QLatin1String(" background-color:");-
2451 html += colorValue(format.background().color());-
2452 html += QLatin1Char(';');-
2453 attributesEmitted = true;-
2454 }
never executed: end of block
0
2455-
2456 if (format.verticalAlignment() != defaultCharFormat.verticalAlignment()
format.vertica...calAlignment()Description
TRUEnever evaluated
FALSEnever evaluated
0
2457 && format.verticalAlignment() != QTextCharFormat::AlignNormal)
format.vertica...t::AlignNormalDescription
TRUEnever evaluated
FALSEnever evaluated
0
2458 {-
2459 html += QLatin1String(" vertical-align:");-
2460-
2461 QTextCharFormat::VerticalAlignment valign = format.verticalAlignment();-
2462 if (valign == QTextCharFormat::AlignSubScript)
valign == QTex...AlignSubScriptDescription
TRUEnever evaluated
FALSEnever evaluated
0
2463 html += QLatin1String("sub");
never executed: html += QLatin1String("sub");
0
2464 else if (valign == QTextCharFormat::AlignSuperScript)
valign == QTex...ignSuperScriptDescription
TRUEnever evaluated
FALSEnever evaluated
0
2465 html += QLatin1String("super");
never executed: html += QLatin1String("super");
0
2466 else if (valign == QTextCharFormat::AlignMiddle)
valign == QTex...t::AlignMiddleDescription
TRUEnever evaluated
FALSEnever evaluated
0
2467 html += QLatin1String("middle");
never executed: html += QLatin1String("middle");
0
2468 else if (valign == QTextCharFormat::AlignTop)
valign == QTex...rmat::AlignTopDescription
TRUEnever evaluated
FALSEnever evaluated
0
2469 html += QLatin1String("top");
never executed: html += QLatin1String("top");
0
2470 else if (valign == QTextCharFormat::AlignBottom)
valign == QTex...t::AlignBottomDescription
TRUEnever evaluated
FALSEnever evaluated
0
2471 html += QLatin1String("bottom");
never executed: html += QLatin1String("bottom");
0
2472-
2473 html += QLatin1Char(';');-
2474 attributesEmitted = true;-
2475 }
never executed: end of block
0
2476-
2477 if (format.fontCapitalization() != QFont::MixedCase) {
format.fontCap...ont::MixedCaseDescription
TRUEnever evaluated
FALSEnever evaluated
0
2478 const QFont::Capitalization caps = format.fontCapitalization();-
2479 if (caps == QFont::AllUppercase)
caps == QFont::AllUppercaseDescription
TRUEnever evaluated
FALSEnever evaluated
0
2480 html += QLatin1String(" text-transform:uppercase;");
never executed: html += QLatin1String(" text-transform:uppercase;");
0
2481 else if (caps == QFont::AllLowercase)
caps == QFont::AllLowercaseDescription
TRUEnever evaluated
FALSEnever evaluated
0
2482 html += QLatin1String(" text-transform:lowercase;");
never executed: html += QLatin1String(" text-transform:lowercase;");
0
2483 else if (caps == QFont::SmallCaps)
caps == QFont::SmallCapsDescription
TRUEnever evaluated
FALSEnever evaluated
0
2484 html += QLatin1String(" font-variant:small-caps;");
never executed: html += QLatin1String(" font-variant:small-caps;");
0
2485 attributesEmitted = true;-
2486 }
never executed: end of block
0
2487-
2488 if (format.fontWordSpacing() != 0.0) {
format.fontWor...acing() != 0.0Description
TRUEnever evaluated
FALSEnever evaluated
0
2489 html += QLatin1String(" word-spacing:");-
2490 html += QString::number(format.fontWordSpacing());-
2491 html += QLatin1String("px;");-
2492 attributesEmitted = true;-
2493 }
never executed: end of block
0
2494-
2495 return attributesEmitted;
never executed: return attributesEmitted;
0
2496}-
2497-
2498void QTextHtmlExporter::emitTextLength(const char *attribute, const QTextLength &length)-
2499{-
2500 if (length.type() == QTextLength::VariableLength) // default-
2501 return;-
2502-
2503 html += QLatin1Char(' ');-
2504 html += QLatin1String(attribute);-
2505 html += QLatin1String("=\"");-
2506 html += QString::number(length.rawValue());-
2507-
2508 if (length.type() == QTextLength::PercentageLength)-
2509 html += QLatin1String("%\"");-
2510 else-
2511 html += QLatin1Char('\"');-
2512}-
2513-
2514void QTextHtmlExporter::emitAlignment(Qt::Alignment align)-
2515{-
2516 if (align & Qt::AlignLeft)-
2517 return;-
2518 else if (align & Qt::AlignRight)-
2519 html += QLatin1String(" align=\"right\"");-
2520 else if (align & Qt::AlignHCenter)-
2521 html += QLatin1String(" align=\"center\"");-
2522 else if (align & Qt::AlignJustify)-
2523 html += QLatin1String(" align=\"justify\"");-
2524}-
2525-
2526void QTextHtmlExporter::emitFloatStyle(QTextFrameFormat::Position pos, StyleMode mode)-
2527{-
2528 if (pos == QTextFrameFormat::InFlow)-
2529 return;-
2530-
2531 if (mode == EmitStyleTag)-
2532 html += QLatin1String(" style=\"float:");-
2533 else-
2534 html += QLatin1String(" float:");-
2535-
2536 if (pos == QTextFrameFormat::FloatLeft)-
2537 html += QLatin1String(" left;");-
2538 else if (pos == QTextFrameFormat::FloatRight)-
2539 html += QLatin1String(" right;");-
2540 else-
2541 Q_ASSERT_X(0, "QTextHtmlExporter::emitFloatStyle()", "pos should be a valid enum type");-
2542-
2543 if (mode == EmitStyleTag)-
2544 html += QLatin1Char('\"');-
2545}-
2546-
2547void QTextHtmlExporter::emitBorderStyle(QTextFrameFormat::BorderStyle style)-
2548{-
2549 Q_ASSERT(style <= QTextFrameFormat::BorderStyle_Outset);-
2550-
2551 html += QLatin1String(" border-style:");-
2552-
2553 switch (style) {-
2554 case QTextFrameFormat::BorderStyle_None:-
2555 html += QLatin1String("none");-
2556 break;-
2557 case QTextFrameFormat::BorderStyle_Dotted:-
2558 html += QLatin1String("dotted");-
2559 break;-
2560 case QTextFrameFormat::BorderStyle_Dashed:-
2561 html += QLatin1String("dashed");-
2562 break;-
2563 case QTextFrameFormat::BorderStyle_Solid:-
2564 html += QLatin1String("solid");-
2565 break;-
2566 case QTextFrameFormat::BorderStyle_Double:-
2567 html += QLatin1String("double");-
2568 break;-
2569 case QTextFrameFormat::BorderStyle_DotDash:-
2570 html += QLatin1String("dot-dash");-
2571 break;-
2572 case QTextFrameFormat::BorderStyle_DotDotDash:-
2573 html += QLatin1String("dot-dot-dash");-
2574 break;-
2575 case QTextFrameFormat::BorderStyle_Groove:-
2576 html += QLatin1String("groove");-
2577 break;-
2578 case QTextFrameFormat::BorderStyle_Ridge:-
2579 html += QLatin1String("ridge");-
2580 break;-
2581 case QTextFrameFormat::BorderStyle_Inset:-
2582 html += QLatin1String("inset");-
2583 break;-
2584 case QTextFrameFormat::BorderStyle_Outset:-
2585 html += QLatin1String("outset");-
2586 break;-
2587 default:-
2588 Q_ASSERT(false);-
2589 break;-
2590 };-
2591-
2592 html += QLatin1Char(';');-
2593}-
2594-
2595void QTextHtmlExporter::emitPageBreakPolicy(QTextFormat::PageBreakFlags policy)-
2596{-
2597 if (policy & QTextFormat::PageBreak_AlwaysBefore)-
2598 html += QLatin1String(" page-break-before:always;");-
2599-
2600 if (policy & QTextFormat::PageBreak_AlwaysAfter)-
2601 html += QLatin1String(" page-break-after:always;");-
2602}-
2603-
2604void QTextHtmlExporter::emitFontFamily(const QString &family)-
2605{-
2606 html += QLatin1String(" font-family:");-
2607-
2608 QLatin1String quote("\'");-
2609 if (family.contains(QLatin1Char('\'')))-
2610 quote = QLatin1String("&quot;");-
2611-
2612 html += quote;-
2613 html += family.toHtmlEscaped();-
2614 html += quote;-
2615 html += QLatin1Char(';');-
2616}-
2617-
2618void QTextHtmlExporter::emitMargins(const QString &top, const QString &bottom, const QString &left, const QString &right)-
2619{-
2620 html += QLatin1String(" margin-top:");-
2621 html += top;-
2622 html += QLatin1String("px;");-
2623-
2624 html += QLatin1String(" margin-bottom:");-
2625 html += bottom;-
2626 html += QLatin1String("px;");-
2627-
2628 html += QLatin1String(" margin-left:");-
2629 html += left;-
2630 html += QLatin1String("px;");-
2631-
2632 html += QLatin1String(" margin-right:");-
2633 html += right;-
2634 html += QLatin1String("px;");-
2635}-
2636-
2637void QTextHtmlExporter::emitFragment(const QTextFragment &fragment)-
2638{-
2639 const QTextCharFormat format = fragment.charFormat();-
2640-
2641 bool closeAnchor = false;-
2642-
2643 if (format.isAnchor()) {
format.isAnchor()Description
TRUEnever evaluated
FALSEnever evaluated
0
2644 const QString name = format.anchorName();-
2645 if (!name.isEmpty()) {
!name.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
2646 html += QLatin1String("<a name=\"");-
2647 html += name.toHtmlEscaped();-
2648 html += QLatin1String("\"></a>");-
2649 }
never executed: end of block
0
2650 const QString href = format.anchorHref();-
2651 if (!href.isEmpty()) {
!href.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
2652 html += QLatin1String("<a href=\"");-
2653 html += href.toHtmlEscaped();-
2654 html += QLatin1String("\">");-
2655 closeAnchor = true;-
2656 }
never executed: end of block
0
2657 }
never executed: end of block
0
2658-
2659 QString txt = fragment.text();-
2660 const bool isObject = txt.contains(QChar::ObjectReplacementCharacter);-
2661 const bool isImage = isObject && format.isImageFormat();
isObjectDescription
TRUEnever evaluated
FALSEnever evaluated
format.isImageFormat()Description
TRUEnever evaluated
FALSEnever evaluated
0
2662-
2663 QLatin1String styleTag("<span style=\"");-
2664 html += styleTag;-
2665-
2666 bool attributesEmitted = false;-
2667 if (!isImage)
!isImageDescription
TRUEnever evaluated
FALSEnever evaluated
0
2668 attributesEmitted = emitCharFormatStyle(format);
never executed: attributesEmitted = emitCharFormatStyle(format);
0
2669 if (attributesEmitted)
attributesEmittedDescription
TRUEnever evaluated
FALSEnever evaluated
0
2670 html += QLatin1String("\">");
never executed: html += QLatin1String("\">");
0
2671 else-
2672 html.chop(qstrlen(styleTag.latin1()));size());
never executed: html.chop(styleTag.size());
0
2673-
2674 if (isObject) {
isObjectDescription
TRUEnever evaluated
FALSEnever evaluated
0
2675 for (int i = 0; isImage && i < txt.length(); ++i) {
isImageDescription
TRUEnever evaluated
FALSEnever evaluated
i < txt.length()Description
TRUEnever evaluated
FALSEnever evaluated
0
2676 QTextImageFormat imgFmt = format.toImageFormat();-
2677-
2678 html += QLatin1String("<img");-
2679-
2680 if (imgFmt.hasProperty(QTextFormat::ImageName))
imgFmt.hasProp...at::ImageName)Description
TRUEnever evaluated
FALSEnever evaluated
0
2681 emitAttribute("src", imgFmt.name());
never executed: emitAttribute("src", imgFmt.name());
0
2682-
2683 if (imgFmt.hasProperty(QTextFormat::ImageWidth))
imgFmt.hasProp...t::ImageWidth)Description
TRUEnever evaluated
FALSEnever evaluated
0
2684 emitAttribute("width", QString::number(imgFmt.width()));
never executed: emitAttribute("width", QString::number(imgFmt.width()));
0
2685-
2686 if (imgFmt.hasProperty(QTextFormat::ImageHeight))
imgFmt.hasProp...::ImageHeight)Description
TRUEnever evaluated
FALSEnever evaluated
0
2687 emitAttribute("height", QString::number(imgFmt.height()));
never executed: emitAttribute("height", QString::number(imgFmt.height()));
0
2688-
2689 if (imgFmt.verticalAlignment() == QTextCharFormat::AlignMiddle)
imgFmt.vertica...t::AlignMiddleDescription
TRUEnever evaluated
FALSEnever evaluated
0
2690 html += QLatin1String(" style=\"vertical-align: middle;\"");
never executed: html += QLatin1String(" style=\"vertical-align: middle;\"");
0
2691 else if (imgFmt.verticalAlignment() == QTextCharFormat::AlignTop)
imgFmt.vertica...rmat::AlignTopDescription
TRUEnever evaluated
FALSEnever evaluated
0
2692 html += QLatin1String(" style=\"vertical-align: top;\"");
never executed: html += QLatin1String(" style=\"vertical-align: top;\"");
0
2693-
2694 if (QTextFrame *imageFrame = qobject_cast<QTextFrame *>(doc->objectForFormat(imgFmt)))
QTextFrame *im...ormat(imgFmt))Description
TRUEnever evaluated
FALSEnever evaluated
0
2695 emitFloatStyle(imageFrame->frameFormat().position());
never executed: emitFloatStyle(imageFrame->frameFormat().position());
0
2696-
2697 html += QLatin1String(" />");-
2698 }
never executed: end of block
0
2699 } else {
never executed: end of block
0
2700 Q_ASSERT(!txt.contains(QChar::ObjectReplacementCharacter));-
2701-
2702 txt = txt.toHtmlEscaped();-
2703-
2704 // split for [\n{LineSeparator}]-
2705 QString forcedLineBreakRegExp = QString::fromLatin1("[\\na]");-
2706 forcedLineBreakRegExp[3] = QChar::LineSeparator;-
const QStringList lines = txt.split(QRegExp(forcedLineBreakRegExp));
2707 for (int i = 0; i < lines.count(); ++i) {-
if (i > 0)
html += QLatin1String("<br />"); // space in BR on purpose for compatibility with Netscape, Lynx &old-fashioned Co.
browsers
2708 html += linestxt.atreplace(i);-
}QRegExp(forcedLineBreakRegExp), QLatin1String("<br />"));
2709 }
never executed: end of block
0
2710-
2711 if (attributesEmitted)
attributesEmittedDescription
TRUEnever evaluated
FALSEnever evaluated
0
2712 html += QLatin1String("</span>");
never executed: html += QLatin1String("</span>");
0
2713-
2714 if (closeAnchor)
closeAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
2715 html += QLatin1String("</a>");
never executed: html += QLatin1String("</a>");
0
2716}
never executed: end of block
0
2717-
2718static bool isOrderedList(int style)-
2719{-
2720 return style == QTextListFormat::ListDecimal || style == QTextListFormat::ListLowerAlpha-
2721 || style == QTextListFormat::ListUpperAlpha-
2722 || style == QTextListFormat::ListUpperRoman-
2723 || style == QTextListFormat::ListLowerRoman-
2724 ;-
2725}-
2726-
2727void QTextHtmlExporter::emitBlockAttributes(const QTextBlock &block)-
2728{-
2729 QTextBlockFormat format = block.blockFormat();-
2730 emitAlignment(format.alignment());-
2731-
2732 // assume default to not bloat the html too much-
2733 // html += QLatin1String(" dir='ltr'");-
2734 if (block.textDirection() == Qt::RightToLeft)
block.textDire...t::RightToLeftDescription
TRUEnever evaluated
FALSEnever evaluated
0
2735 html += QLatin1String(" dir='rtl'");
never executed: html += QLatin1String(" dir='rtl'");
0
2736-
2737 QLatin1String style(" style=\"");-
2738 html += style;-
2739-
2740 const bool emptyBlock = block.begin().atEnd();-
2741 if (emptyBlock) {
emptyBlockDescription
TRUEnever evaluated
FALSEnever evaluated
0
2742 html += QLatin1String("-qt-paragraph-type:empty;");-
2743 }
never executed: end of block
0
2744-
2745 emitMargins(QString::number(format.topMargin()),-
2746 QString::number(format.bottomMargin()),-
2747 QString::number(format.leftMargin()),-
2748 QString::number(format.rightMargin()));-
2749-
2750 html += QLatin1String(" -qt-block-indent:");-
2751 html += QString::number(format.indent());-
2752 html += QLatin1Char(';');-
2753-
2754 html += QLatin1String(" text-indent:");-
2755 html += QString::number(format.textIndent());-
2756 html += QLatin1String("px;");-
2757-
2758 if (block.userState() != -1) {
block.userState() != -1Description
TRUEnever evaluated
FALSEnever evaluated
0
2759 html += QLatin1String(" -qt-user-state:");-
2760 html += QString::number(block.userState());-
2761 html += QLatin1Char(';');-
2762 }
never executed: end of block
0
2763-
2764 if (format.lineHeightType() != QTextBlockFormat::SingleHeight) {
format.lineHei...::SingleHeightDescription
TRUEnever evaluated
FALSEnever evaluated
0
2765 html += QLatin1String(" line-height:")-
2766 + QString::number(format.lineHeight());-
2767 switch (format.lineHeightType()) {-
2768 case QTextBlockFormat::ProportionalHeight:
never executed: case QTextBlockFormat::ProportionalHeight:
0
2769 html += QLatin1String("%;");-
2770 break;
never executed: break;
0
2771 case QTextBlockFormat::FixedHeight:
never executed: case QTextBlockFormat::FixedHeight:
0
2772 html += QLatin1String("; -qt-line-height-type: fixed;");-
2773 break;
never executed: break;
0
2774 case QTextBlockFormat::MinimumHeight:
never executed: case QTextBlockFormat::MinimumHeight:
0
2775 html += QLatin1String(" min-height:"px;");-
2776 break;
never executed: break;
0
2777 case QTextBlockFormat::LineDistanceHeight:
never executed: case QTextBlockFormat::LineDistanceHeight:
0
2778 html += QLatin1String("; -qt-line-spacingheight-type: line-distance;");-
2779 break;
never executed: break;
0
case QTextBlockFormat::SingleHeight:
never executed: break;
2780 default:
never executed: default:
0
2781 html += QLatin1String(";");-
2782 break; // Should never reach here
never executed: break;
0
2783 }-
html += QString::number(format.lineHeight());
if (format.lineHeightType() == QTextBlockFormat::ProportionalHeight)
html += QLatin1String("%;");
else
html += QLatin1String("px;");
2784 }-
2785-
2786 emitPageBreakPolicy(format.pageBreakPolicy());-
2787-
2788 QTextCharFormat diff;-
2789 if (emptyBlock) { // only print character properties when we don't expect them to be repeated by actual text in the parag
emptyBlockDescription
TRUEnever evaluated
FALSEnever evaluated
0
2790 const QTextCharFormat blockCharFmt = block.charFormat();-
2791 diff = formatDifference(defaultCharFormat, blockCharFmt).toCharFormat();-
2792 }
never executed: end of block
0
2793-
2794 diff.clearProperty(QTextFormat::BackgroundBrush);-
2795 if (format.hasProperty(QTextFormat::BackgroundBrush)) {
format.hasProp...ckgroundBrush)Description
TRUEnever evaluated
FALSEnever evaluated
0
2796 QBrush bg = format.background();-
2797 if (bg.style() != Qt::NoBrush)
bg.style() != Qt::NoBrushDescription
TRUEnever evaluated
FALSEnever evaluated
0
2798 diff.setProperty(QTextFormat::BackgroundBrush, format.property(QTextFormat::BackgroundBrush));
never executed: diff.setProperty(QTextFormat::BackgroundBrush, format.property(QTextFormat::BackgroundBrush));
0
2799 }
never executed: end of block
0
2800-
2801 if (!diff.properties().isEmpty())
!diff.properties().isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
2802 emitCharFormatStyle(diff);
never executed: emitCharFormatStyle(diff);
0
2803-
2804 html += QLatin1Char('"');-
2805-
2806}
never executed: end of block
0
2807-
2808void QTextHtmlExporter::emitBlock(const QTextBlock &block)-
2809{-
2810 if (block.begin().atEnd()) {-
2811 // ### HACK, remove once QTextFrame::Iterator is fixed-
2812 int p = block.position();-
2813 if (p > 0)-
2814 --p;-
2815 QTextDocumentPrivate::FragmentIterator frag = doc->docHandle()->find(p);-
2816 QChar ch = doc->docHandle()->buffer().at(frag->stringPosition);-
2817 if (ch == QTextBeginningOfFrame-
2818 || ch == QTextEndOfFrame)-
2819 return;-
2820 }-
2821-
2822 html += QLatin1Char('\n');-
2823-
2824 // save and later restore, in case we 'change' the default format by-
2825 // emitting block char format information-
2826 QTextCharFormat oldDefaultCharFormat = defaultCharFormat;-
2827-
2828 QTextList *list = block.textList();-
2829 if (list) {-
2830 if (list->itemNumber(block) == 0) { // first item? emit <ul> or appropriate-
2831 const QTextListFormat format = list->format();-
2832 const int style = format.style();-
2833 switch (style) {-
2834 case QTextListFormat::ListDecimal: html += QLatin1String("<ol"); break;-
2835 case QTextListFormat::ListDisc: html += QLatin1String("<ul"); break;-
2836 case QTextListFormat::ListCircle: html += QLatin1String("<ul type=\"circle\""); break;-
2837 case QTextListFormat::ListSquare: html += QLatin1String("<ul type=\"square\""); break;-
2838 case QTextListFormat::ListLowerAlpha: html += QLatin1String("<ol type=\"a\""); break;-
2839 case QTextListFormat::ListUpperAlpha: html += QLatin1String("<ol type=\"A\""); break;-
2840 case QTextListFormat::ListLowerRoman: html += QLatin1String("<ol type=\"i\""); break;-
2841 case QTextListFormat::ListUpperRoman: html += QLatin1String("<ol type=\"I\""); break;-
2842 default: html += QLatin1String("<ul"); // ### should not happen-
2843 }-
2844-
2845 QString styleString = QString::fromLatin1("margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px;");-
2846-
2847 if (format.hasProperty(QTextFormat::ListIndent)) {-
2848 styleString += QLatin1String(" -qt-list-indent: ");-
2849 styleString += QString::number(format.indent());-
2850 styleString += QLatin1Char(';');-
2851 }-
2852-
2853 if (format.hasProperty(QTextFormat::ListNumberPrefix)) {-
2854 QString numberPrefix = format.numberPrefix();-
2855 numberPrefix.replace(QLatin1Char('"'), QLatin1String("\\22"));-
2856 numberPrefix.replace(QLatin1Char('\''), QLatin1String("\\27")); // FIXME: There's a problem in the CSS parser the prevents this from being correctly restored-
2857 styleString += QLatin1String(" -qt-list-number-prefix: ");-
2858 styleString += QLatin1Char('\'');-
2859 styleString += numberPrefix;-
2860 styleString += QLatin1Char('\'');-
2861 styleString += QLatin1Char(';');-
2862 }-
2863-
2864 if (format.hasProperty(QTextFormat::ListNumberSuffix)) {-
2865 if (format.numberSuffix() != QLatin1String(".")) { // this is our default-
2866 QString numberSuffix = format.numberSuffix();-
2867 numberSuffix.replace(QLatin1Char('"'), QLatin1String("\\22"));-
2868 numberSuffix.replace(QLatin1Char('\''), QLatin1String("\\27")); // see above-
2869 styleString += QLatin1String(" -qt-list-number-suffix: ");-
2870 styleString += QLatin1Char('\'');-
2871 styleString += numberSuffix;-
2872 styleString += QLatin1Char('\'');-
2873 styleString += QLatin1Char(';');-
2874 }-
2875 }-
2876-
2877 html += QLatin1String(" style=\"");-
2878 html += styleString;-
2879 html += QLatin1String("\">");-
2880 }-
2881-
2882 html += QLatin1String("<li");-
2883-
2884 const QTextCharFormat blockFmt = formatDifference(defaultCharFormat, block.charFormat()).toCharFormat();-
2885 if (!blockFmt.properties().isEmpty()) {-
2886 html += QLatin1String(" style=\"");-
2887 emitCharFormatStyle(blockFmt);-
2888 html += QLatin1Char('\"');-
2889-
2890 defaultCharFormat.merge(block.charFormat());-
2891 }-
2892 }-
2893-
2894 const QTextBlockFormat blockFormat = block.blockFormat();-
2895 if (blockFormat.hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)) {-
2896 html += QLatin1String("<hr");-
2897-
2898 QTextLength width = blockFormat.lengthProperty(QTextFormat::BlockTrailingHorizontalRulerWidth);-
2899 if (width.type() != QTextLength::VariableLength)-
2900 emitTextLength("width", width);-
2901 else-
2902 html += QLatin1Char(' ');-
2903-
2904 html += QLatin1String("/>");-
2905 return;-
2906 }-
2907-
2908 const bool pre = blockFormat.nonBreakableLines();-
2909 if (pre) {-
2910 if (list)-
2911 html += QLatin1Char('>');-
2912 html += QLatin1String("<pre");-
2913 } else if (!list) {-
2914 html += QLatin1String("<p");-
2915 }-
2916-
2917 emitBlockAttributes(block);-
2918-
2919 html += QLatin1Char('>');-
2920 if (block.begin().atEnd())-
2921 html += QLatin1String("<br />");-
2922-
2923 QTextBlock::Iterator it = block.begin();-
2924 if (fragmentMarkers && !it.atEnd() && block == doc->begin())-
2925 html += QLatin1String("<!--StartFragment-->");-
2926-
2927 for (; !it.atEnd(); ++it)-
2928 emitFragment(it.fragment());-
2929-
2930 if (fragmentMarkers && block.position() + block.length() == doc->docHandle()->length())-
2931 html += QLatin1String("<!--EndFragment-->");-
2932-
2933 if (pre)-
2934 html += QLatin1String("</pre>");-
2935 else if (list)-
2936 html += QLatin1String("</li>");-
2937 else-
2938 html += QLatin1String("</p>");-
2939-
2940 if (list) {-
2941 if (list->itemNumber(block) == list->count() - 1) { // last item? close list-
2942 if (isOrderedList(list->format().style()))-
2943 html += QLatin1String("</ol>");-
2944 else-
2945 html += QLatin1String("</ul>");-
2946 }-
2947 }-
2948-
2949 defaultCharFormat = oldDefaultCharFormat;-
2950}-
2951-
2952extern bool qHasPixmapTexture(const QBrush& brush);-
2953-
2954QString QTextHtmlExporter::findUrlForImage(const QTextDocument *doc, qint64 cacheKey, bool isPixmap)-
2955{-
2956 QString url;-
2957 if (!doc)-
2958 return url;-
2959-
2960 if (QTextDocument *parent = qobject_cast<QTextDocument *>(doc->parent()))-
2961 return findUrlForImage(parent, cacheKey, isPixmap);-
2962-
2963 if (doc && doc->docHandle()) {-
2964 QTextDocumentPrivate *priv = doc->docHandle();-
2965 QMap<QUrl, QVariant>::const_iterator it = priv->cachedResources.constBegin();-
2966 for (; it != priv->cachedResources.constEnd(); ++it) {-
2967-
2968 const QVariant &v = it.value();-
2969 if (v.type() == QVariant::Image && !isPixmap) {-
2970 if (qvariant_cast<QImage>(v).cacheKey() == cacheKey)-
2971 break;-
2972 }-
2973-
2974 if (v.type() == QVariant::Pixmap && isPixmap) {-
2975 if (qvariant_cast<QPixmap>(v).cacheKey() == cacheKey)-
2976 break;-
2977 }-
2978 }-
2979-
2980 if (it != priv->cachedResources.constEnd())-
2981 url = it.key().toString();-
2982 }-
2983-
2984 return url;-
2985}-
2986-
2987void QTextDocumentPrivate::mergeCachedResources(const QTextDocumentPrivate *priv)-
2988{-
2989 if (!priv)-
2990 return;-
2991-
2992 cachedResources.unite(priv->cachedResources);-
2993}-
2994-
2995void QTextHtmlExporter::emitBackgroundAttribute(const QTextFormat &format)-
2996{-
2997 if (format.hasProperty(QTextFormat::BackgroundImageUrl)) {-
2998 QString url = format.property(QTextFormat::BackgroundImageUrl).toString();-
2999 emitAttribute("background", url);-
3000 } else {-
3001 const QBrush &brush = format.background();-
3002 if (brush.style() == Qt::SolidPattern) {-
3003 emitAttribute("bgcolor", colorValue(brush.color()));-
3004 } else if (brush.style() == Qt::TexturePattern) {-
3005 const bool isPixmap = qHasPixmapTexture(brush);-
3006 const qint64 cacheKey = isPixmap ? brush.texture().cacheKey() : brush.textureImage().cacheKey();-
3007-
3008 const QString url = findUrlForImage(doc, cacheKey, isPixmap);-
3009-
3010 if (!url.isEmpty())-
3011 emitAttribute("background", url);-
3012 }-
3013 }-
3014}-
3015-
3016void QTextHtmlExporter::emitTable(const QTextTable *table)-
3017{-
3018 QTextTableFormat format = table->format();-
3019-
3020 html += QLatin1String("\n<table");-
3021-
3022 if (format.hasProperty(QTextFormat::FrameBorder))-
3023 emitAttribute("border", QString::number(format.border()));-
3024-
3025 emitFrameStyle(format, TableFrame);-
3026-
3027 emitAlignment(format.alignment());-
3028 emitTextLength("width", format.width());-
3029-
3030 if (format.hasProperty(QTextFormat::TableCellSpacing))-
3031 emitAttribute("cellspacing", QString::number(format.cellSpacing()));-
3032 if (format.hasProperty(QTextFormat::TableCellPadding))-
3033 emitAttribute("cellpadding", QString::number(format.cellPadding()));-
3034-
3035 emitBackgroundAttribute(format);-
3036-
3037 html += QLatin1Char('>');-
3038-
3039 const int rows = table->rows();-
3040 const int columns = table->columns();-
3041-
3042 QVector<QTextLength> columnWidths = format.columnWidthConstraints();-
3043 if (columnWidths.isEmpty()) {-
3044 columnWidths.resize(columns);-
3045 columnWidths.fill(QTextLength());-
3046 }-
3047 Q_ASSERT(columnWidths.count() == columns);-
3048-
3049 QVarLengthArray<bool> widthEmittedForColumn(columns);-
3050 for (int i = 0; i < columns; ++i)-
3051 widthEmittedForColumn[i] = false;-
3052-
3053 const int headerRowCount = qMin(format.headerRowCount(), rows);-
3054 if (headerRowCount > 0)-
3055 html += QLatin1String("<thead>");-
3056-
3057 for (int row = 0; row < rows; ++row) {-
3058 html += QLatin1String("\n<tr>");-
3059-
3060 for (int col = 0; col < columns; ++col) {-
3061 const QTextTableCell cell = table->cellAt(row, col);-
3062-
3063 // for col/rowspans-
3064 if (cell.row() != row)-
3065 continue;-
3066-
3067 if (cell.column() != col)-
3068 continue;-
3069-
3070 html += QLatin1String("\n<td");-
3071-
3072 if (!widthEmittedForColumn[col] && cell.columnSpan() == 1) {-
3073 emitTextLength("width", columnWidths.at(col));-
3074 widthEmittedForColumn[col] = true;-
3075 }-
3076-
3077 if (cell.columnSpan() > 1)-
3078 emitAttribute("colspan", QString::number(cell.columnSpan()));-
3079-
3080 if (cell.rowSpan() > 1)-
3081 emitAttribute("rowspan", QString::number(cell.rowSpan()));-
3082-
3083 const QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();-
3084 emitBackgroundAttribute(cellFormat);-
3085-
3086 QTextCharFormat oldDefaultCharFormat = defaultCharFormat;-
3087-
3088 QTextCharFormat::VerticalAlignment valign = cellFormat.verticalAlignment();-
3089-
3090 QString styleString;-
3091 if (valign >= QTextCharFormat::AlignMiddle && valign <= QTextCharFormat::AlignBottom) {-
3092 styleString += QLatin1String(" vertical-align:");-
3093 switch (valign) {-
3094 case QTextCharFormat::AlignMiddle:-
3095 styleString += QLatin1String("middle");-
3096 break;-
3097 case QTextCharFormat::AlignTop:-
3098 styleString += QLatin1String("top");-
3099 break;-
3100 case QTextCharFormat::AlignBottom:-
3101 styleString += QLatin1String("bottom");-
3102 break;-
3103 default:-
3104 break;-
3105 }-
3106 styleString += QLatin1Char(';');-
3107-
3108 QTextCharFormat temp;-
3109 temp.setVerticalAlignment(valign);-
3110 defaultCharFormat.merge(temp);-
3111 }-
3112-
3113 if (cellFormat.hasProperty(QTextFormat::TableCellLeftPadding))-
3114 styleString += QLatin1String(" padding-left:") + QString::number(cellFormat.leftPadding()) + QLatin1Char(';');-
3115 if (cellFormat.hasProperty(QTextFormat::TableCellRightPadding))-
3116 styleString += QLatin1String(" padding-right:") + QString::number(cellFormat.rightPadding()) + QLatin1Char(';');-
3117 if (cellFormat.hasProperty(QTextFormat::TableCellTopPadding))-
3118 styleString += QLatin1String(" padding-top:") + QString::number(cellFormat.topPadding()) + QLatin1Char(';');-
3119 if (cellFormat.hasProperty(QTextFormat::TableCellBottomPadding))-
3120 styleString += QLatin1String(" padding-bottom:") + QString::number(cellFormat.bottomPadding()) + QLatin1Char(';');-
3121-
3122 if (!styleString.isEmpty())-
3123 html += QLatin1String(" style=\"") + styleString + QLatin1Char('\"');-
3124-
3125 html += QLatin1Char('>');-
3126-
3127 emitFrame(cell.begin());-
3128-
3129 html += QLatin1String("</td>");-
3130-
3131 defaultCharFormat = oldDefaultCharFormat;-
3132 }-
3133-
3134 html += QLatin1String("</tr>");-
3135 if (headerRowCount > 0 && row == headerRowCount - 1)-
3136 html += QLatin1String("</thead>");-
3137 }-
3138-
3139 html += QLatin1String("</table>");-
3140}-
3141-
3142void QTextHtmlExporter::emitFrame(QTextFrame::Iterator frameIt)-
3143{-
3144 if (!frameIt.atEnd()) {-
3145 QTextFrame::Iterator next = frameIt;-
3146 ++next;-
3147 if (next.atEnd()-
3148 && frameIt.currentFrame() == 0-
3149 && frameIt.parentFrame() != doc->rootFrame()-
3150 && frameIt.currentBlock().begin().atEnd())-
3151 return;-
3152 }-
3153-
3154 for (QTextFrame::Iterator it = frameIt;-
3155 !it.atEnd(); ++it) {-
3156 if (QTextFrame *f = it.currentFrame()) {-
3157 if (QTextTable *table = qobject_cast<QTextTable *>(f)) {-
3158 emitTable(table);-
3159 } else {-
3160 emitTextFrame(f);-
3161 }-
3162 } else if (it.currentBlock().isValid()) {-
3163 emitBlock(it.currentBlock());-
3164 }-
3165 }-
3166}-
3167-
3168void QTextHtmlExporter::emitTextFrame(const QTextFrame *f)-
3169{-
3170 FrameType frameType = f->parentFrame() ? TextFrame : RootFrame;-
3171-
3172 html += QLatin1String("\n<table");-
3173 QTextFrameFormat format = f->frameFormat();-
3174-
3175 if (format.hasProperty(QTextFormat::FrameBorder))-
3176 emitAttribute("border", QString::number(format.border()));-
3177-
3178 emitFrameStyle(format, frameType);-
3179-
3180 emitTextLength("width", format.width());-
3181 emitTextLength("height", format.height());-
3182-
3183 // root frame's bcolor goes in the <body> tag-
3184 if (frameType != RootFrame)-
3185 emitBackgroundAttribute(format);-
3186-
3187 html += QLatin1Char('>');-
3188 html += QLatin1String("\n<tr>\n<td style=\"border: none;\">");-
3189 emitFrame(f->begin());-
3190 html += QLatin1String("</td></tr></table>");-
3191}-
3192-
3193void QTextHtmlExporter::emitFrameStyle(const QTextFrameFormat &format, FrameType frameType)-
3194{-
3195 QLatin1String styleAttribute(" style=\"");-
3196 html += styleAttribute;-
3197 const int originalHtmlLength = html.length();-
3198-
3199 if (frameType == TextFrame)
frameType == TextFrameDescription
TRUEnever evaluated
FALSEnever evaluated
0
3200 html += QLatin1String("-qt-table-type: frame;");
never executed: html += QLatin1String("-qt-table-type: frame;");
0
3201 else if (frameType == RootFrame)
frameType == RootFrameDescription
TRUEnever evaluated
FALSEnever evaluated
0
3202 html += QLatin1String("-qt-table-type: root;");
never executed: html += QLatin1String("-qt-table-type: root;");
0
3203-
3204 const QTextFrameFormat defaultFormat;-
3205-
3206 emitFloatStyle(format.position(), OmitStyleTag);-
3207 emitPageBreakPolicy(format.pageBreakPolicy());-
3208-
3209 if (format.borderBrush() != defaultFormat.borderBrush()) {
format.borderB....borderBrush()Description
TRUEnever evaluated
FALSEnever evaluated
0
3210 html += QLatin1String(" border-color:");-
3211 html += colorValue(format.borderBrush().color());-
3212 html += QLatin1Char(';');-
3213 }
never executed: end of block
0
3214-
3215 if (format.borderStyle() != defaultFormat.borderStyle())
format.borderS....borderStyle()Description
TRUEnever evaluated
FALSEnever evaluated
0
3216 emitBorderStyle(format.borderStyle());
never executed: emitBorderStyle(format.borderStyle());
0
3217-
3218 if (format.hasProperty(QTextFormat::FrameMargin)
format.hasProp...::FrameMargin)Description
TRUEnever evaluated
FALSEnever evaluated
0
3219 || format.hasProperty(QTextFormat::FrameLeftMargin)
format.hasProp...ameLeftMargin)Description
TRUEnever evaluated
FALSEnever evaluated
0
3220 || format.hasProperty(QTextFormat::FrameRightMargin)
format.hasProp...meRightMargin)Description
TRUEnever evaluated
FALSEnever evaluated
0
3221 || format.hasProperty(QTextFormat::FrameTopMargin)
format.hasProp...rameTopMargin)Description
TRUEnever evaluated
FALSEnever evaluated
0
3222 || format.hasProperty(QTextFormat::FrameBottomMargin))
format.hasProp...eBottomMargin)Description
TRUEnever evaluated
FALSEnever evaluated
0
3223 emitMargins(QString::number(format.topMargin()),
never executed: emitMargins(QString::number(format.topMargin()), QString::number(format.bottomMargin()), QString::number(format.leftMargin()), QString::number(format.rightMargin()));
0
3224 QString::number(format.bottomMargin()),
never executed: emitMargins(QString::number(format.topMargin()), QString::number(format.bottomMargin()), QString::number(format.leftMargin()), QString::number(format.rightMargin()));
0
3225 QString::number(format.leftMargin()),
never executed: emitMargins(QString::number(format.topMargin()), QString::number(format.bottomMargin()), QString::number(format.leftMargin()), QString::number(format.rightMargin()));
0
3226 QString::number(format.rightMargin()));
never executed: emitMargins(QString::number(format.topMargin()), QString::number(format.bottomMargin()), QString::number(format.leftMargin()), QString::number(format.rightMargin()));
0
3227-
3228 if (html.length() == originalHtmlLength) // nothing emitted?
html.length() ...inalHtmlLengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
3229 html.chop(qstrlen(styleAttribute.latin1()));size());
never executed: html.chop(styleAttribute.size());
0
3230 else-
3231 html += QLatin1Char('\"');
never executed: html += QLatin1Char('\"');
0
3232}-
3233-
3234/*!-
3235 Returns a string containing an HTML representation of the document.-
3236-
3237 The \a encoding parameter specifies the value for the charset attribute-
3238 in the html header. For example if 'utf-8' is specified then the-
3239 beginning of the generated html will look like this:-
3240 \snippet code/src_gui_text_qtextdocument.cpp 0-
3241-
3242 If no encoding is specified then no such meta information is generated.-
3243-
3244 If you later on convert the returned html string into a byte array for-
3245 transmission over a network or when saving to disk you should specify-
3246 the encoding you're going to use for the conversion to a byte array here.-
3247-
3248 \sa {Supported HTML Subset}-
3249*/-
3250#ifndef QT_NO_TEXTHTMLPARSER-
3251QString QTextDocument::toHtml(const QByteArray &encoding) const-
3252{-
3253 return QTextHtmlExporter(this).toHtml(encoding);-
3254}-
3255#endif // QT_NO_TEXTHTMLPARSER-
3256-
3257/*!-
3258 Returns a vector of text formats for all the formats used in the document.-
3259*/-
3260QVector<QTextFormat> QTextDocument::allFormats() const-
3261{-
3262 Q_D(const QTextDocument);-
3263 return d->formatCollection()->formats;-
3264}-
3265-
3266-
3267/*!-
3268 \internal-
3269-
3270 So that not all classes have to be friends of each other...-
3271*/-
3272QTextDocumentPrivate *QTextDocument::docHandle() const-
3273{-
3274 Q_D(const QTextDocument);-
3275 return const_cast<QTextDocumentPrivate *>(d);-
3276}-
3277-
3278/*!-
3279 \since 4.4-
3280 \fn QTextDocument::undoCommandAdded()-
3281-
3282 This signal is emitted every time a new level of undo is added to the QTextDocument.-
3283*/-
3284-
3285QT_END_NAMESPACE-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9