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