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