00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "qtextdocument.h"
00025 #include <qtextformat.h>
00026 #include "qtextdocumentlayout_p.h"
00027 #include "qtextdocumentfragment.h"
00028 #include "qtextdocumentfragment_p.h"
00029 #include "qtexttable.h"
00030 #include "qtextlist.h"
00031 #include <qdebug.h>
00032 #include <qregexp.h>
00033 #include <qvarlengtharray.h>
00034 #include <qtextcodec.h>
00035 #include "qtexthtmlparser_p.h"
00036 #include "qpainter.h"
00037 #include "qprinter.h"
00038 #include "qtextedit.h"
00039 #include "qtextcontrol_p.h"
00040
00041 #include "qtextdocument_p.h"
00042
00043 #include <limits.h>
00044
00056 bool Qt::mightBeRichText(const QString& text)
00057 {
00058 if (text.isEmpty())
00059 return false;
00060 int start = 0;
00061
00062 while (start < text.length() && text.at(start).isSpace())
00063 ++start;
00064
00065
00066 if (text.mid(start, 5) == QLatin1String("<?xml")) {
00067 while (start < text.length()) {
00068 if (text.at(start) == QLatin1Char('?')
00069 && start + 2 < text.length()
00070 && text.at(start + 1) == QLatin1Char('>')) {
00071 start += 2;
00072 break;
00073 }
00074 ++start;
00075 }
00076
00077 while (start < text.length() && text.at(start).isSpace())
00078 ++start;
00079 }
00080
00081 if (text.mid(start, 5).toLower() == QLatin1String("<!doc"))
00082 return true;
00083 int open = start;
00084 while (open < text.length() && text.at(open) != QLatin1Char('<')
00085 && text.at(open) != QLatin1Char('\n')) {
00086 if (text.at(open) == QLatin1Char('&') && text.mid(open+1,3) == QLatin1String("lt;"))
00087 return true;
00088 ++open;
00089 }
00090 if (open < text.length() && text.at(open) == QLatin1Char('<')) {
00091 const int close = text.indexOf(QLatin1Char('>'), open);
00092 if (close > -1) {
00093 QString tag;
00094 for (int i = open+1; i < close; ++i) {
00095 if (text[i].isDigit() || text[i].isLetter())
00096 tag += text[i];
00097 else if (!tag.isEmpty() && text[i].isSpace())
00098 break;
00099 else if (!text[i].isSpace() && (!tag.isEmpty() || text[i] != QLatin1Char('!')))
00100 return false;
00101 }
00102 return QTextHtmlParser::lookupElement(tag.toLower()) != -1;
00103 }
00104 }
00105 return false;
00106 }
00107
00125 QString Qt::escape(const QString& plain)
00126 {
00127 QString rich;
00128 rich.reserve(int(plain.length() * 1.1));
00129 for (int i = 0; i < plain.length(); ++i) {
00130 if (plain.at(i) == QLatin1Char('<'))
00131 rich += QLatin1String("<");
00132 else if (plain.at(i) == QLatin1Char('>'))
00133 rich += QLatin1String(">");
00134 else if (plain.at(i) == QLatin1Char('&'))
00135 rich += QLatin1String("&");
00136 else
00137 rich += plain.at(i);
00138 }
00139 return rich;
00140 }
00141
00154 QString Qt::convertFromPlainText(const QString &plain, Qt::WhiteSpaceMode mode)
00155 {
00156 int col = 0;
00157 QString rich;
00158 rich += QLatin1String("<p>");
00159 for (int i = 0; i < plain.length(); ++i) {
00160 if (plain[i] == QLatin1Char('\n')){
00161 int c = 1;
00162 while (i+1 < plain.length() && plain[i+1] == QLatin1Char('\n')) {
00163 i++;
00164 c++;
00165 }
00166 if (c == 1)
00167 rich += QLatin1String("<br>\n");
00168 else {
00169 rich += QLatin1String("</p>\n");
00170 while (--c > 1)
00171 rich += QLatin1String("<br>\n");
00172 rich += QLatin1String("<p>");
00173 }
00174 col = 0;
00175 } else {
00176 if (mode == Qt::WhiteSpacePre && plain[i] == QLatin1Char('\t')){
00177 rich += QChar(0x00a0U);
00178 ++col;
00179 while (col % 8) {
00180 rich += QChar(0x00a0U);
00181 ++col;
00182 }
00183 }
00184 else if (mode == Qt::WhiteSpacePre && plain[i].isSpace())
00185 rich += QChar(0x00a0U);
00186 else if (plain[i] == QLatin1Char('<'))
00187 rich += QLatin1String("<");
00188 else if (plain[i] == QLatin1Char('>'))
00189 rich += QLatin1String(">");
00190 else if (plain[i] == QLatin1Char('&'))
00191 rich += QLatin1String("&");
00192 else
00193 rich += plain[i];
00194 ++col;
00195 }
00196 }
00197 if (col != 0)
00198 rich += QLatin1String("</p>");
00199 return rich;
00200 }
00201
00202 #ifndef QT_NO_TEXTCODEC
00203
00208 QTextCodec *Qt::codecForHtml(const QByteArray &ba)
00209 {
00210 return QTextCodec::codecForHtml(ba);
00211 }
00212 #endif
00213
00268 QTextDocument::QTextDocument(QObject *parent)
00269 : QObject(*new QTextDocumentPrivate, parent)
00270 {
00271 Q_D(QTextDocument);
00272 d->init();
00273 }
00274
00279 QTextDocument::QTextDocument(const QString &text, QObject *parent)
00280 : QObject(*new QTextDocumentPrivate, parent)
00281 {
00282 Q_D(QTextDocument);
00283 d->init();
00284 QTextCursor(this).insertText(text);
00285 }
00286
00290 QTextDocument::QTextDocument(QTextDocumentPrivate &dd, QObject *parent)
00291 : QObject(dd, parent)
00292 {
00293 Q_D(QTextDocument);
00294 d->init();
00295 }
00296
00300 QTextDocument::~QTextDocument()
00301 {
00302 }
00303
00304
00309 QTextDocument *QTextDocument::clone(QObject *parent) const
00310 {
00311 Q_D(const QTextDocument);
00312 QTextDocument *doc = new QTextDocument(parent);
00313 QTextCursor(doc).insertFragment(QTextDocumentFragment(this));
00314 doc->d_func()->title = d->title;
00315 doc->d_func()->pageSize = d->pageSize;
00316 doc->d_func()->useDesignMetrics = d->useDesignMetrics;
00317 doc->d_func()->setDefaultFont(d->defaultFont());
00318 doc->d_func()->resources = d->resources;
00319 doc->d_func()->defaultStyleSheet = d->defaultStyleSheet;
00320 doc->d_func()->parsedDefaultStyleSheet = d->parsedDefaultStyleSheet;
00321 return doc;
00322 }
00323
00327 bool QTextDocument::isEmpty() const
00328 {
00329 Q_D(const QTextDocument);
00330
00331
00332 return d->length() <= 1;
00333 }
00334
00338 void QTextDocument::clear()
00339 {
00340 Q_D(QTextDocument);
00341 d->clear();
00342 d->resources.clear();
00343 }
00344
00353 void QTextDocument::undo(QTextCursor *cursor)
00354 {
00355 Q_D(QTextDocument);
00356 const int pos = d->undoRedo(true);
00357 if (cursor && pos >= 0) {
00358 *cursor = QTextCursor(this);
00359 cursor->setPosition(pos);
00360 }
00361 }
00362
00371 void QTextDocument::redo(QTextCursor *cursor)
00372 {
00373 Q_D(QTextDocument);
00374 const int pos = d->undoRedo(false);
00375 if (cursor && pos >= 0) {
00376 *cursor = QTextCursor(this);
00377 cursor->setPosition(pos);
00378 }
00379 }
00380
00386 void QTextDocument::undo()
00387 {
00388 Q_D(QTextDocument);
00389 d->undoRedo(true);
00390 }
00391
00397 void QTextDocument::redo()
00398 {
00399 Q_D(QTextDocument);
00400 d->undoRedo(false);
00401 }
00402
00408 void QTextDocument::appendUndoItem(QAbstractUndoItem *item)
00409 {
00410 Q_D(QTextDocument);
00411 d->appendUndoItem(item);
00412 }
00413
00421 void QTextDocument::setUndoRedoEnabled(bool enable)
00422 {
00423 Q_D(QTextDocument);
00424 d->enableUndoRedo(enable);
00425 }
00426
00427 bool QTextDocument::isUndoRedoEnabled() const
00428 {
00429 Q_D(const QTextDocument);
00430 return d->isUndoRedoEnabled();
00431 }
00432
00452 int QTextDocument::maximumBlockCount() const
00453 {
00454 Q_D(const QTextDocument);
00455 return d->maximumBlockCount;
00456 }
00457
00458 void QTextDocument::setMaximumBlockCount(int maximum)
00459 {
00460 Q_D(QTextDocument);
00461 d->maximumBlockCount = maximum;
00462 d->ensureMaximumBlockCount();
00463 }
00464
00472 void QTextDocument::markContentsDirty(int from, int length)
00473 {
00474 Q_D(QTextDocument);
00475 if (!d->inContentsChange)
00476 d->beginEditBlock();
00477 d->documentChange(from, length);
00478 if (!d->inContentsChange)
00479 d->endEditBlock();
00480 }
00481
00487 void QTextDocument::setUseDesignMetrics(bool b)
00488 {
00489 Q_D(QTextDocument);
00490 d->useDesignMetrics = b;
00491 if (d->lout)
00492 d->lout->documentChanged(0, 0, d->length());
00493 }
00494
00495 bool QTextDocument::useDesignMetrics() const
00496 {
00497 Q_D(const QTextDocument);
00498 return d->useDesignMetrics;
00499 }
00500
00507 void QTextDocument::drawContents(QPainter *p, const QRectF &rect)
00508 {
00509 p->save();
00510 QAbstractTextDocumentLayout::PaintContext ctx;
00511 if (rect.isValid()) {
00512 p->setClipRect(rect);
00513 ctx.clip = rect;
00514 }
00515 documentLayout()->draw(p, ctx);
00516 p->restore();
00517 }
00518
00540 void QTextDocument::setTextWidth(qreal width)
00541 {
00542 Q_D(QTextDocument);
00543 QSizeF sz = d->pageSize;
00544 sz.setWidth(width);
00545 sz.setHeight(-1);
00546 setPageSize(sz);
00547 }
00548
00549 qreal QTextDocument::textWidth() const
00550 {
00551 Q_D(const QTextDocument);
00552 return d->pageSize.width();
00553 }
00554
00563 qreal QTextDocument::idealWidth() const
00564 {
00565 #ifndef QT_NO_PROPERTIES
00566 QAbstractTextDocumentLayout *lout = documentLayout();
00567 if (lout->metaObject()->indexOfProperty("idealWidth") == -1)
00568 return textWidth();
00569 return lout->property("idealWidth").toDouble();
00570 #else
00571 return textWidth();
00572 #endif
00573 }
00574
00582 void QTextDocument::adjustSize()
00583 {
00584
00585 Q_CORE_EXPORT unsigned int qt_int_sqrt(unsigned int n);
00586
00587 QFont f = defaultFont();
00588 QFontMetrics fm(f);
00589 int mw = fm.width(QLatin1Char('x')) * 80;
00590 int w = mw;
00591 setPageSize(QSizeF(w, -1));
00592 QSizeF size = documentLayout()->documentSize();
00593 if (size.width() != 0) {
00594 w = qt_int_sqrt((uint)(5 * size.height() * size.width() / 3));
00595 setPageSize(QSizeF(qMin(w, mw), -1));
00596
00597 size = documentLayout()->documentSize();
00598 if (w*3 < 5*size.height()) {
00599 w = qt_int_sqrt((uint)(2 * size.height() * size.width()));
00600 setPageSize(QSizeF(qMin(w, mw), -1));
00601 }
00602 }
00603 }
00604
00619 QSizeF QTextDocument::size() const
00620 {
00621 return documentLayout()->documentSize();
00622 }
00623
00632 int QTextDocument::blockCount() const
00633 {
00634 Q_D(const QTextDocument);
00635 return d->blockMap().numNodes();
00636 }
00637
00653 void QTextDocument::setDefaultStyleSheet(const QString &sheet)
00654 {
00655 Q_D(QTextDocument);
00656 d->defaultStyleSheet = sheet;
00657 QCss::Parser parser(sheet);
00658 d->parsedDefaultStyleSheet = QCss::StyleSheet();
00659 parser.parse(&d->parsedDefaultStyleSheet);
00660 }
00661
00662 QString QTextDocument::defaultStyleSheet() const
00663 {
00664 Q_D(const QTextDocument);
00665 return d->defaultStyleSheet;
00666 }
00667
00722 bool QTextDocument::isUndoAvailable() const
00723 {
00724 Q_D(const QTextDocument);
00725 return d->isUndoAvailable();
00726 }
00727
00731 bool QTextDocument::isRedoAvailable() const
00732 {
00733 Q_D(const QTextDocument);
00734 return d->isRedoAvailable();
00735 }
00736
00745 void QTextDocument::setDocumentLayout(QAbstractTextDocumentLayout *layout)
00746 {
00747 Q_D(QTextDocument);
00748 d->setLayout(layout);
00749 }
00750
00754 QAbstractTextDocumentLayout *QTextDocument::documentLayout() const
00755 {
00756 Q_D(const QTextDocument);
00757 if (!d->lout) {
00758 QTextDocument *that = const_cast<QTextDocument *>(this);
00759 that->d_func()->setLayout(new QTextDocumentLayout(that));
00760 }
00761 return d->lout;
00762 }
00763
00764
00771 QString QTextDocument::metaInformation(MetaInformation info) const
00772 {
00773 if (info != DocumentTitle)
00774 return QString();
00775 Q_D(const QTextDocument);
00776 return d->title;
00777 }
00778
00785 void QTextDocument::setMetaInformation(MetaInformation info, const QString &string)
00786 {
00787 if (info != DocumentTitle)
00788 return;
00789 Q_D(QTextDocument);
00790 d->title = string;
00791 }
00792
00799 QString QTextDocument::toPlainText() const
00800 {
00801 Q_D(const QTextDocument);
00802 QString txt = d->plainText();
00803 txt.replace(QTextBeginningOfFrame, QLatin1Char('\n'));
00804 txt.replace(QTextEndOfFrame, QLatin1Char('\n'));
00805 txt.replace(QChar::ParagraphSeparator, QLatin1Char('\n'));
00806 txt.replace(QChar::LineSeparator, QLatin1Char('\n'));
00807 txt.replace(QChar::Nbsp, QLatin1Char(' '));
00808 return txt;
00809 }
00810
00817 void QTextDocument::setPlainText(const QString &text)
00818 {
00819 Q_D(QTextDocument);
00820 setUndoRedoEnabled(false);
00821 d->clear();
00822 QTextCursor(this).insertText(text);
00823 setUndoRedoEnabled(true);
00824 }
00825
00836 void QTextDocument::setHtml(const QString &html)
00837 {
00838 Q_D(QTextDocument);
00839 setUndoRedoEnabled(false);
00840 d->clear();
00841 QTextHtmlImporter(this, html).import();
00842 setUndoRedoEnabled(true);
00843 }
00844
00884 QTextCursor QTextDocument::find(const QString &subString, int from, FindFlags options) const
00885 {
00886 QRegExp expr(subString);
00887 expr.setPatternSyntax(QRegExp::FixedString);
00888 expr.setCaseSensitivity((options & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive);
00889
00890 return find(expr, from, options);
00891 }
00892
00910 QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &from, FindFlags options) const
00911 {
00912 const int pos = (from.isNull() ? 0 : from.selectionEnd());
00913 QRegExp expr(subString);
00914 expr.setPatternSyntax(QRegExp::FixedString);
00915 expr.setCaseSensitivity((options & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive);
00916
00917 return find(expr, pos, options);
00918 }
00919
00920
00921 static bool findInBlock(const QTextBlock &block, const QString &text, const QRegExp &expression, int offset,
00922 QTextDocument::FindFlags options, QTextCursor &cursor)
00923 {
00924 const QRegExp expr(expression);
00925
00926 int idx = -1;
00927 while (offset >=0 && offset <= text.length()) {
00928 idx = (options & QTextDocument::FindBackward) ?
00929 expr.lastIndexIn(text, offset) : expr.indexIn(text, offset);
00930 if (idx == -1)
00931 return false;
00932
00933 if (options & QTextDocument::FindWholeWords) {
00934 const int start = idx;
00935 const int end = start + expr.matchedLength();
00936 if ((start != 0 && text.at(start - 1).isLetterOrNumber())
00937 || (end != text.length() && text.at(end).isLetterOrNumber())) {
00938
00939 offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1;
00940 continue;
00941 }
00942 }
00943
00944 break;
00945 }
00946 if (idx == -1)
00947 return false;
00948 cursor = QTextCursor(block.docHandle(), block.position() + idx);
00949 cursor.setPosition(cursor.position() + expr.matchedLength(), QTextCursor::KeepAnchor);
00950 return true;
00951 }
00952
00970 QTextCursor QTextDocument::find(const QRegExp & expr, int from, FindFlags options) const
00971 {
00972 Q_D(const QTextDocument);
00973
00974 if (expr.isEmpty())
00975 return QTextCursor();
00976
00977 int pos = from;
00978
00979
00980 if (options & FindBackward) {
00981 --pos ;
00982 if(pos < 0)
00983 return QTextCursor();
00984 }
00985
00986 QTextCursor cursor;
00987 QTextBlock block = d->blocksFind(pos);
00988
00989 if (!(options & FindBackward)) {
00990 int blockOffset = qMax(0, pos - block.position());
00991 while (block.isValid()) {
00992 const QString blockText = block.text();
00993 if (findInBlock(block, blockText, expr, blockOffset, options, cursor))
00994 return cursor;
00995 blockOffset = 0;
00996 block = block.next();
00997 }
00998 } else {
00999 int blockOffset = pos - block.position();
01000 while (block.isValid()) {
01001 const QString blockText = block.text();
01002 if (findInBlock(block, blockText, expr, blockOffset, options, cursor))
01003 return cursor;
01004 block = block.previous();
01005 blockOffset = block.length() - 1;
01006 }
01007 }
01008
01009 return QTextCursor();
01010 }
01011
01030 QTextCursor QTextDocument::find(const QRegExp &expr, const QTextCursor &from, FindFlags options) const
01031 {
01032 const int pos = (from.isNull() ? 0 : from.selectionEnd());
01033 return find(expr, pos, options);
01034 }
01035
01036
01046 QTextObject *QTextDocument::createObject(const QTextFormat &f)
01047 {
01048 QTextObject *obj = 0;
01049 if (f.isListFormat())
01050 obj = new QTextList(this);
01051 else if (f.isTableFormat())
01052 obj = new QTextTable(this);
01053 else if (f.isFrameFormat())
01054 obj = new QTextFrame(this);
01055
01056 return obj;
01057 }
01058
01064 QTextFrame *QTextDocument::frameAt(int pos) const
01065 {
01066 Q_D(const QTextDocument);
01067 return d->frameAt(pos);
01068 }
01069
01073 QTextFrame *QTextDocument::rootFrame() const
01074 {
01075 Q_D(const QTextDocument);
01076 return d->rootFrame();
01077 }
01078
01082 QTextObject *QTextDocument::object(int objectIndex) const
01083 {
01084 Q_D(const QTextDocument);
01085 return d->objectForIndex(objectIndex);
01086 }
01087
01091 QTextObject *QTextDocument::objectForFormat(const QTextFormat &f) const
01092 {
01093 Q_D(const QTextDocument);
01094 return d->objectForFormat(f);
01095 }
01096
01097
01101 QTextBlock QTextDocument::findBlock(int pos) const
01102 {
01103 Q_D(const QTextDocument);
01104 return QTextBlock(docHandle(), d->blockMap().findNode(pos));
01105 }
01106
01110 QTextBlock QTextDocument::begin() const
01111 {
01112 Q_D(const QTextDocument);
01113 return QTextBlock(docHandle(), d->blockMap().begin().n);
01114 }
01115
01119 QTextBlock QTextDocument::end() const
01120 {
01121 return QTextBlock(docHandle(), 0);
01122 }
01123
01131 void QTextDocument::setPageSize(const QSizeF &size)
01132 {
01133 Q_D(QTextDocument);
01134 d->pageSize = size;
01135 if (d->lout)
01136 d->lout->documentChanged(0, 0, d->length());
01137 }
01138
01139 QSizeF QTextDocument::pageSize() const
01140 {
01141 Q_D(const QTextDocument);
01142 return d->pageSize;
01143 }
01144
01148 int QTextDocument::pageCount() const
01149 {
01150 return documentLayout()->pageCount();
01151 }
01152
01156 void QTextDocument::setDefaultFont(const QFont &font)
01157 {
01158 Q_D(QTextDocument);
01159 d->setDefaultFont(font);
01160 if (d->lout)
01161 d->lout->documentChanged(0, 0, d->length());
01162 }
01163
01167 QFont QTextDocument::defaultFont() const
01168 {
01169 Q_D(const QTextDocument);
01170 return d->defaultFont();
01171 }
01172
01194 bool QTextDocument::isModified() const
01195 {
01196 return docHandle()->isModified();
01197 }
01198
01199 void QTextDocument::setModified(bool m)
01200 {
01201 docHandle()->setModified(m);
01202 }
01203
01204 #ifndef QT_NO_PRINTER
01205 static void printPage(int index, QPainter *painter, const QTextDocument *doc, const QRectF &body, const QPointF &pageNumberPos)
01206 {
01207 painter->save();
01208 painter->translate(body.left(), body.top() - (index - 1) * body.height());
01209 QRectF view(0, (index - 1) * body.height(), body.width(), body.height());
01210
01211 QAbstractTextDocumentLayout *layout = doc->documentLayout();
01212 QAbstractTextDocumentLayout::PaintContext ctx;
01213
01214 painter->setClipRect(view);
01215 ctx.clip = view;
01216
01217
01218
01219
01220 ctx.palette.setColor(QPalette::Text, Qt::black);
01221
01222 layout->draw(painter, ctx);
01223
01224 if (!pageNumberPos.isNull()) {
01225 painter->setClipping(false);
01226 painter->setFont(QFont(doc->defaultFont()));
01227 const QString pageString = QString::number(index);
01228
01229 painter->drawText(qRound(pageNumberPos.x() - painter->fontMetrics().width(pageString)),
01230 qRound(pageNumberPos.y() + view.top()),
01231 pageString);
01232 }
01233
01234 painter->restore();
01235 }
01236
01254 void QTextDocument::print(QPrinter *printer) const
01255 {
01256 Q_D(const QTextDocument);
01257 QPainter p(printer);
01258
01259
01260 if (!p.isActive())
01261 return;
01262
01263 const QTextDocument *doc = this;
01264 QTextDocument *clonedDoc = 0;
01265 (void)doc->documentLayout();
01266
01267 QRectF body = QRectF(QPointF(0, 0), d->pageSize);
01268 QPointF pageNumberPos;
01269
01270 if (d->pageSize.isValid()
01271 && d->pageSize.height() != INT_MAX) {
01272 extern int qt_defaultDpi();
01273
01274 qreal sourceDpiX = qt_defaultDpi();
01275 qreal sourceDpiY = sourceDpiX;
01276
01277 QPaintDevice *dev = doc->documentLayout()->paintDevice();
01278 if (dev) {
01279 sourceDpiX = dev->logicalDpiX();
01280 sourceDpiY = dev->logicalDpiY();
01281 }
01282
01283 const qreal dpiScaleX = qreal(printer->logicalDpiX()) / sourceDpiX;
01284 const qreal dpiScaleY = qreal(printer->logicalDpiY()) / sourceDpiY;
01285
01286
01287 p.scale(dpiScaleX, dpiScaleY);
01288
01289 QSizeF scaledPageSize = d->pageSize;
01290 scaledPageSize.rwidth() *= dpiScaleX;
01291 scaledPageSize.rheight() *= dpiScaleY;
01292
01293 const QSizeF printerPageSize(printer->width(), printer->height());
01294
01295
01296 p.scale(printerPageSize.width() / scaledPageSize.width(),
01297 printerPageSize.height() / scaledPageSize.height());
01298 } else {
01299 doc = clone(const_cast<QTextDocument *>(this));
01300 clonedDoc = const_cast<QTextDocument *>(doc);
01301
01302 QAbstractTextDocumentLayout *layout = doc->documentLayout();
01303 layout->setPaintDevice(p.device());
01304
01305 const int dpiy = p.device()->logicalDpiY();
01306
01307 const int margin = (int) ((2/2.54)*dpiy);
01308 QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
01309 fmt.setMargin(margin);
01310 doc->rootFrame()->setFrameFormat(fmt);
01311
01312 body = QRectF(0, 0, p.device()->width(), p.device()->height());
01313 pageNumberPos = QPointF(body.width() - margin,
01314 body.height() - margin
01315 + QFontMetrics(doc->defaultFont(), p.device()).ascent()
01316 + 5 * p.device()->logicalDpiY() / 72);
01317
01318 QFont font(doc->defaultFont());
01319 font.setPointSize(10);
01320 clonedDoc->setDefaultFont(font);
01321 clonedDoc->setPageSize(body.size());
01322 }
01323
01324 int docCopies;
01325 int pageCopies;
01326 if (printer->collateCopies() == true){
01327 docCopies = 1;
01328 pageCopies = printer->numCopies();
01329 } else {
01330 docCopies = printer->numCopies();
01331 pageCopies = 1;
01332 }
01333
01334 int fromPage = printer->fromPage();
01335 int toPage = printer->toPage();
01336 bool ascending = true;
01337
01338 if (fromPage == 0 && toPage == 0) {
01339 fromPage = 1;
01340 toPage = doc->pageCount();
01341 }
01342
01343 if (printer->pageOrder() == QPrinter::LastPageFirst) {
01344 int tmp = fromPage;
01345 fromPage = toPage;
01346 toPage = tmp;
01347 ascending = false;
01348 }
01349
01350 for (int i = 0; i < docCopies; ++i) {
01351
01352 int page = fromPage;
01353 while (true) {
01354 for (int j = 0; j < pageCopies; ++j) {
01355 if (printer->printerState() == QPrinter::Aborted
01356 || printer->printerState() == QPrinter::Error)
01357 goto UserCanceled;
01358 printPage(page, &p, doc, body, pageNumberPos);
01359 if (j < pageCopies - 1)
01360 printer->newPage();
01361 }
01362
01363 if (page == toPage)
01364 break;
01365
01366 if (ascending)
01367 ++page;
01368 else
01369 --page;
01370
01371 printer->newPage();
01372 }
01373
01374 if ( i < docCopies - 1)
01375 printer->newPage();
01376 }
01377
01378 UserCanceled:
01379 delete clonedDoc;
01380 }
01381 #endif
01382
01418 QVariant QTextDocument::resource(int type, const QUrl &name) const
01419 {
01420 Q_D(const QTextDocument);
01421 QVariant r = d->resources.value(name);
01422 if (!r.isValid()) {
01423 r = d->cachedResources.value(name);
01424 if (!r.isValid())
01425 r = const_cast<QTextDocument *>(this)->loadResource(type, name);
01426 }
01427 return r;
01428 }
01429
01434 void QTextDocument::addResource(int type, const QUrl &name, const QVariant &resource)
01435 {
01436 Q_UNUSED(type);
01437 Q_D(QTextDocument);
01438 d->resources.insert(name, resource);
01439 }
01440
01457 QVariant QTextDocument::loadResource(int type, const QUrl &name)
01458 {
01459 Q_D(QTextDocument);
01460 QVariant r;
01461 if (QTextDocument *doc = qobject_cast<QTextDocument *>(parent()))
01462 r = doc->loadResource(type, name);
01463 #ifndef QT_NO_TEXTEDIT
01464 else if (QTextEdit *edit = qobject_cast<QTextEdit *>(parent()))
01465 r = edit->loadResource(type, name);
01466 #endif
01467 #ifndef QT_NO_TEXTCONTROL
01468 else if (QTextControl *control = qobject_cast<QTextControl *>(parent()))
01469 r = control->loadResource(type, name);
01470 #endif
01471 if (!r.isNull()) {
01472 if (type == ImageResource && r.type() == QVariant::ByteArray) {
01473 QPixmap pm;
01474 pm.loadFromData(r.toByteArray());
01475 if (!pm.isNull())
01476 r = pm;
01477 }
01478 d->cachedResources.insert(name, r);
01479 }
01480 return r;
01481 }
01482
01483 static QTextFormat formatDifference(const QTextFormat &from, const QTextFormat &to)
01484 {
01485 QTextFormat diff = to;
01486
01487 const QMap<int, QVariant> props = to.properties();
01488 for (QMap<int, QVariant>::ConstIterator it = props.begin(), end = props.end();
01489 it != end; ++it)
01490 if (it.value() == from.property(it.key()))
01491 diff.clearProperty(it.key());
01492
01493 return diff;
01494 }
01495
01496 QTextHtmlExporter::QTextHtmlExporter(const QTextDocument *_doc)
01497 : doc(_doc), fragmentMarkers(false)
01498 {
01499 const QFont defaultFont = doc->defaultFont();
01500 defaultCharFormat.setFont(defaultFont);
01501 }
01502
01508 QString QTextHtmlExporter::toHtml(const QByteArray &encoding)
01509 {
01510 html = QLatin1String("<html><head><meta name=\"qrichtext\" content=\"1\" />");
01511 html.reserve(doc->docHandle()->length());
01512
01513 if (!encoding.isEmpty())
01514 html += QString::fromLatin1("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%1\" />").arg(QString::fromAscii(encoding));
01515
01516 QString title = doc->metaInformation(QTextDocument::DocumentTitle);
01517 if (!title.isEmpty())
01518 html += QString::fromLatin1("<title>") + title + QString::fromLatin1("</title>");
01519 html += QLatin1String("<style type=\"text/css\">\n");
01520 html += QLatin1String("p, li { white-space: pre-wrap; }\n");
01521 html += QLatin1String("</style>");
01522 html += QLatin1String("</head><body style=\"");
01523
01524 html += QLatin1String(" font-family:'");
01525 html += defaultCharFormat.fontFamily();
01526 html += QLatin1String("';");
01527
01528 if (defaultCharFormat.hasProperty(QTextFormat::FontPointSize)) {
01529 html += QLatin1String(" font-size:");
01530 html += QString::number(defaultCharFormat.fontPointSize());
01531 html += QLatin1String("pt;");
01532 }
01533
01534 html += QLatin1String(" font-weight:");
01535 html += QString::number(defaultCharFormat.fontWeight() * 8);
01536 html += QLatin1Char(';');
01537
01538 html += QLatin1String(" font-style:");
01539 html += (defaultCharFormat.fontItalic() ? QLatin1String("italic") : QLatin1String("normal"));
01540 html += QLatin1Char(';');
01541
01542 {
01543 html += QLatin1String(" text-decoration:");
01544 bool atLeastOneDecorationSet = false;
01545
01546 if (defaultCharFormat.fontUnderline()) {
01547 html += QLatin1String(" underline");
01548 atLeastOneDecorationSet = true;
01549 }
01550
01551 if (defaultCharFormat.fontOverline()) {
01552 html += QLatin1String(" overline");
01553 atLeastOneDecorationSet = true;
01554 }
01555
01556 if (defaultCharFormat.fontStrikeOut()) {
01557 html += QLatin1String(" line-through");
01558 atLeastOneDecorationSet = true;
01559 }
01560
01561 if (!atLeastOneDecorationSet)
01562 html += QLatin1String("none");
01563 html += QLatin1Char(';');
01564 }
01565 html += QLatin1Char('\"');
01566
01567 const QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
01568 QBrush bg = fmt.background();
01569 if (bg != Qt::NoBrush)
01570 emitAttribute("bgcolor", bg.color().name());
01571
01572 html += QLatin1Char('>');
01573
01574 emitFrame(doc->rootFrame()->begin());
01575 html += QLatin1String("</body></html>");
01576 return html;
01577 }
01578
01579 void QTextHtmlExporter::emitAttribute(const char *attribute, const QString &value)
01580 {
01581 html += QLatin1Char(' ');
01582 html += QLatin1String(attribute);
01583 html += QLatin1String("=\"");
01584 html += value;
01585 html += QLatin1Char('"');
01586 }
01587
01588 bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)
01589 {
01590 bool attributesEmitted = false;
01591
01592 {
01593 const QString family = format.fontFamily();
01594 if (!family.isEmpty() && family != defaultCharFormat.fontFamily()) {
01595 html += QLatin1String(" font-family:'");
01596 html += family;
01597 html += QLatin1String("';");
01598 attributesEmitted = true;
01599 }
01600 }
01601
01602 if (format.hasProperty(QTextFormat::FontPointSize)
01603 && format.fontPointSize() != defaultCharFormat.fontPointSize()) {
01604 html += QLatin1String(" font-size:");
01605 html += QString::number(format.fontPointSize());
01606 html += QLatin1String("pt;");
01607 attributesEmitted = true;
01608 } else if (format.hasProperty(QTextFormat::FontSizeAdjustment)) {
01609 static const char * const sizeNames[] = {
01610 "small", "medium", "large", "x-large", "xx-large"
01611 };
01612 const char *name = 0;
01613 const int idx = format.intProperty(QTextFormat::FontSizeAdjustment) + 1;
01614 if (idx >= 0 && idx <= 4) {
01615 name = sizeNames[idx];
01616 }
01617 if (name) {
01618 html += QLatin1String(" font-size:");
01619 html += QLatin1String(name);
01620 html += QLatin1Char(';');
01621 attributesEmitted = true;
01622 }
01623 }
01624
01625 if (format.fontWeight() != defaultCharFormat.fontWeight()) {
01626 html += QLatin1String(" font-weight:");
01627 html += QString::number(format.fontWeight() * 8);
01628 html += QLatin1Char(';');
01629 attributesEmitted = true;
01630 }
01631
01632 if (format.fontItalic() != defaultCharFormat.fontItalic()) {
01633 html += QLatin1String(" font-style:");
01634 html += (format.fontItalic() ? QLatin1String("italic") : QLatin1String("normal"));
01635 html += QLatin1Char(';');
01636 attributesEmitted = true;
01637 }
01638
01639 QLatin1String decorationTag(" text-decoration:");
01640 html += decorationTag;
01641 bool hasDecoration = false;
01642 bool atLeastOneDecorationSet = false;
01643
01644 if (format.fontUnderline() != defaultCharFormat.fontUnderline()) {
01645 hasDecoration = true;
01646 if (format.fontUnderline()) {
01647 html += QLatin1String(" underline");
01648 atLeastOneDecorationSet = true;
01649 }
01650 }
01651
01652 if (format.fontOverline() != defaultCharFormat.fontOverline()) {
01653 hasDecoration = true;
01654 if (format.fontOverline()) {
01655 html += QLatin1String(" overline");
01656 atLeastOneDecorationSet = true;
01657 }
01658 }
01659
01660 if (format.fontStrikeOut() != defaultCharFormat.fontStrikeOut()) {
01661 hasDecoration = true;
01662 if (format.fontStrikeOut()) {
01663 html += QLatin1String(" line-through");
01664 atLeastOneDecorationSet = true;
01665 }
01666 }
01667
01668 if (hasDecoration) {
01669 if (!atLeastOneDecorationSet)
01670 html += QLatin1String("none");
01671 html += QLatin1Char(';');
01672 attributesEmitted = true;
01673 } else {
01674 html.chop(qstrlen(decorationTag.latin1()));
01675 }
01676
01677 if (format.foreground() != defaultCharFormat.foreground()
01678 && format.foreground().style() != Qt::NoBrush) {
01679 html += QLatin1String(" color:");
01680 html += format.foreground().color().name();
01681 html += QLatin1Char(';');
01682 attributesEmitted = true;
01683 }
01684
01685 if (format.background() != defaultCharFormat.background()
01686 && format.background().style() != Qt::NoBrush) {
01687 html += QLatin1String(" background-color:");
01688 html += format.background().color().name();
01689 html += QLatin1Char(';');
01690 attributesEmitted = true;
01691 }
01692
01693 if (format.verticalAlignment() != defaultCharFormat.verticalAlignment()) {
01694 html += QLatin1String(" vertical-align:");
01695
01696 QTextCharFormat::VerticalAlignment valign = format.verticalAlignment();
01697 if (valign == QTextCharFormat::AlignSubScript)
01698 html += QLatin1String("sub");
01699 else if (valign == QTextCharFormat::AlignSuperScript)
01700 html += QLatin1String("super");
01701
01702 html += QLatin1Char(';');
01703 attributesEmitted = true;
01704 }
01705
01706 return attributesEmitted;
01707 }
01708
01709 void QTextHtmlExporter::emitTextLength(const char *attribute, const QTextLength &length)
01710 {
01711 if (length.type() == QTextLength::VariableLength)
01712 return;
01713
01714 html += QLatin1Char(' ');
01715 html += QLatin1String(attribute);
01716 html += QLatin1String("=\"");
01717 html += QString::number(length.rawValue());
01718
01719 if (length.type() == QTextLength::PercentageLength)
01720 html += QLatin1String("%\"");
01721 else
01722 html += QLatin1String("\"");
01723 }
01724
01725 void QTextHtmlExporter::emitAlignment(Qt::Alignment align)
01726 {
01727 if (align & Qt::AlignLeft)
01728 return;
01729 else if (align & Qt::AlignRight)
01730 html += QLatin1String(" align=\"right\"");
01731 else if (align & Qt::AlignHCenter)
01732 html += QLatin1String(" align=\"center\"");
01733 else if (align & Qt::AlignJustify)
01734 html += QLatin1String(" align=\"justify\"");
01735 }
01736
01737 void QTextHtmlExporter::emitFloatStyle(QTextFrameFormat::Position pos, StyleMode mode)
01738 {
01739 if (pos == QTextFrameFormat::InFlow)
01740 return;
01741
01742 if (mode == EmitStyleTag)
01743 html += QLatin1String(" style=\"float:");
01744 else
01745 html += QLatin1String(" float:");
01746
01747 if (pos == QTextFrameFormat::FloatLeft)
01748 html += QLatin1String(" left;");
01749 else if (pos == QTextFrameFormat::FloatRight)
01750 html += QLatin1String(" right;");
01751 else
01752 Q_ASSERT_X(0, "QTextHtmlExporter::emitFloatStyle()", "pos should be a valid enum type");
01753
01754 if (mode == EmitStyleTag)
01755 html += QLatin1Char('\"');
01756 }
01757
01758 void QTextHtmlExporter::emitMargins(const QString &top, const QString &bottom, const QString &left, const QString &right)
01759 {
01760 html += QLatin1String(" margin-top:");
01761 html += top;
01762 html += QLatin1String("px;");
01763
01764 html += QLatin1String(" margin-bottom:");
01765 html += bottom;
01766 html += QLatin1String("px;");
01767
01768 html += QLatin1String(" margin-left:");
01769 html += left;
01770 html += QLatin1String("px;");
01771
01772 html += QLatin1String(" margin-right:");
01773 html += right;
01774 html += QLatin1String("px;");
01775 }
01776
01777 void QTextHtmlExporter::emitFragment(const QTextFragment &fragment)
01778 {
01779 const QTextCharFormat format = fragment.charFormat();
01780
01781 bool closeAnchor = false;
01782
01783 if (format.isAnchor()) {
01784 const QString name = format.anchorName();
01785 if (!name.isEmpty()) {
01786 html += QLatin1String("<a name=\"");
01787 html += name;
01788 html += QLatin1String("\"></a>");
01789 }
01790 const QString href = format.anchorHref();
01791 if (!href.isEmpty()) {
01792 html += QLatin1String("<a href=\"");
01793 html += href;
01794 html += QLatin1String("\">");
01795 closeAnchor = true;
01796 }
01797 }
01798
01799 QLatin1String styleTag("<span style=\"");
01800 html += styleTag;
01801
01802 const bool attributesEmitted = emitCharFormatStyle(format);
01803 if (attributesEmitted)
01804 html += QLatin1String("\">");
01805 else
01806 html.chop(qstrlen(styleTag.latin1()));
01807
01808 QString txt = fragment.text();
01809 if (txt.count() == 1 && txt.at(0) == QChar::ObjectReplacementCharacter) {
01810 if (format.isImageFormat()) {
01811 QTextImageFormat imgFmt = format.toImageFormat();
01812
01813 html += QLatin1String("<img");
01814
01815 if (imgFmt.hasProperty(QTextFormat::ImageName))
01816 emitAttribute("src", imgFmt.name());
01817
01818 if (imgFmt.hasProperty(QTextFormat::ImageWidth))
01819 emitAttribute("width", QString::number(imgFmt.width()));
01820
01821 if (imgFmt.hasProperty(QTextFormat::ImageHeight))
01822 emitAttribute("height", QString::number(imgFmt.height()));
01823
01824 if (QTextFrame *imageFrame = qobject_cast<QTextFrame *>(doc->objectForFormat(imgFmt)))
01825 emitFloatStyle(imageFrame->frameFormat().position());
01826
01827 html += QLatin1String(" />");
01828 }
01829 } else {
01830 Q_ASSERT(!txt.contains(QChar::ObjectReplacementCharacter));
01831
01832 txt = Qt::escape(txt);
01833
01834
01835 QString forcedLineBreakRegExp = QString::fromLatin1("[\\na]");
01836 forcedLineBreakRegExp[3] = QChar::LineSeparator;
01837
01838 const QStringList lines = txt.split(QRegExp(forcedLineBreakRegExp));
01839 for (int i = 0; i < lines.count(); ++i) {
01840 if (i > 0)
01841 html += QLatin1String("<br />");
01842 html += lines.at(i);
01843 }
01844 }
01845
01846 if (attributesEmitted)
01847 html += QLatin1String("</span>");
01848
01849 if (closeAnchor)
01850 html += QLatin1String("</a>");
01851 }
01852
01853 static bool isOrderedList(int style)
01854 {
01855 return style == QTextListFormat::ListDecimal || style == QTextListFormat::ListLowerAlpha
01856 || style == QTextListFormat::ListUpperAlpha;
01857 }
01858
01859 void QTextHtmlExporter::emitBlockAttributes(const QTextBlock &block)
01860 {
01861 QTextBlockFormat format = block.blockFormat();
01862 emitAlignment(format.alignment());
01863
01864 Qt::LayoutDirection dir = format.layoutDirection();
01865 if (dir == Qt::LeftToRight) {
01866
01867
01868 } else {
01869 html += QLatin1String(" dir='rtl'");
01870 }
01871
01872 QLatin1String style(" style=\"");
01873 html += style;
01874
01875 if (block.begin().atEnd()) {
01876 html += QLatin1String("-qt-paragraph-type:empty;");
01877 }
01878
01879 emitMargins(QString::number(format.topMargin()),
01880 QString::number(format.bottomMargin()),
01881 QString::number(format.leftMargin()),
01882 QString::number(format.rightMargin()));
01883
01884 html += QLatin1String(" -qt-block-indent:");
01885 html += QString::number(format.indent());
01886 html += QLatin1Char(';');
01887
01888 html += QLatin1String(" text-indent:");
01889 html += QString::number(format.indent());
01890 html += QLatin1String("px;");
01891
01892 QTextCharFormat diff = formatDifference(defaultCharFormat, block.charFormat()).toCharFormat();
01893 if (!diff.properties().isEmpty())
01894 emitCharFormatStyle(diff);
01895
01896 html += QLatin1Char('"');
01897
01898 QBrush bg = format.background();
01899 if (bg != Qt::NoBrush)
01900 emitAttribute("bgcolor", bg.color().name());
01901 }
01902
01903 void QTextHtmlExporter::emitBlock(const QTextBlock &block)
01904 {
01905 if (block.begin().atEnd()) {
01906
01907 int p = block.position();
01908 if (p > 0)
01909 --p;
01910 QTextDocumentPrivate::FragmentIterator frag = doc->docHandle()->find(p);
01911 QChar ch = doc->docHandle()->buffer().at(frag->stringPosition);
01912 if (ch == QTextBeginningOfFrame
01913 || ch == QTextEndOfFrame)
01914 return;
01915 }
01916
01917 html += QLatin1Char('\n');
01918
01919
01920
01921 QTextCharFormat oldDefaultCharFormat = defaultCharFormat;
01922
01923 QTextList *list = block.textList();
01924 if (list) {
01925 if (list->itemNumber(block) == 0) {
01926 const QTextListFormat format = list->format();
01927 const int style = format.style();
01928 switch (style) {
01929 case QTextListFormat::ListDecimal: html += QLatin1String("<ol"); break;
01930 case QTextListFormat::ListDisc: html += QLatin1String("<ul"); break;
01931 case QTextListFormat::ListCircle: html += QLatin1String("<ul type=\"circle\""); break;
01932 case QTextListFormat::ListSquare: html += QLatin1String("<ul type=\"square\""); break;
01933 case QTextListFormat::ListLowerAlpha: html += QLatin1String("<ol type=\"a\""); break;
01934 case QTextListFormat::ListUpperAlpha: html += QLatin1String("<ol type=\"A\""); break;
01935 default: html += QLatin1String("<ul");
01936 }
01937
01938 if (format.hasProperty(QTextFormat::ListIndent)) {
01939 html += QLatin1String(" style=\"-qt-list-indent: ");
01940 html += QString::number(format.indent());
01941 html += QLatin1String(";\"");
01942 }
01943
01944 html += QLatin1Char('>');
01945 }
01946
01947 html += QLatin1String("<li");
01948
01949 const QTextCharFormat blockFmt = formatDifference(defaultCharFormat, block.charFormat()).toCharFormat();
01950 if (!blockFmt.properties().isEmpty()) {
01951 html += QLatin1String(" style=\"");
01952 emitCharFormatStyle(blockFmt);
01953 html += QLatin1Char('\"');
01954
01955 defaultCharFormat.merge(block.charFormat());
01956 }
01957 }
01958
01959 const QTextBlockFormat blockFormat = block.blockFormat();
01960 if (blockFormat.hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)) {
01961 html += QLatin1String("<hr");
01962
01963 QTextLength width = blockFormat.lengthProperty(QTextFormat::BlockTrailingHorizontalRulerWidth);
01964 if (width.type() != QTextLength::VariableLength)
01965 emitTextLength("width", width);
01966 else
01967 html += QLatin1Char(' ');
01968
01969 html += QLatin1String("/>");
01970 return;
01971 }
01972
01973 const bool pre = blockFormat.nonBreakableLines();
01974 if (pre) {
01975 if (list)
01976 html += QLatin1Char('>');
01977 html += QLatin1String("<pre");
01978 } else if (!list) {
01979 html += QLatin1String("<p");
01980 }
01981
01982 emitBlockAttributes(block);
01983
01984 html += QLatin1Char('>');
01985
01986 const QTextCharFormat blockCharFmt = block.charFormat();
01987 const QTextCharFormat diff = formatDifference(defaultCharFormat, blockCharFmt).toCharFormat();
01988
01989 defaultCharFormat.merge(blockCharFmt);
01990
01991 QTextBlock::Iterator it = block.begin();
01992 if (fragmentMarkers && !it.atEnd() && block == doc->begin())
01993 html += QLatin1String("<!--StartFragment-->");
01994
01995 for (; !it.atEnd(); ++it)
01996 emitFragment(it.fragment());
01997
01998 if (fragmentMarkers && block.position() + block.length() == doc->docHandle()->length())
01999 html += QLatin1String("<!--EndFragment-->");
02000
02001 if (pre)
02002 html += QLatin1String("</pre>");
02003 else if (list)
02004 html += QLatin1String("</li>");
02005 else
02006 html += QLatin1String("</p>");
02007
02008 if (list) {
02009 if (list->itemNumber(block) == list->count() - 1) {
02010 if (isOrderedList(list->format().style()))
02011 html += QLatin1String("</ol>");
02012 else
02013 html += QLatin1String("</ul>");
02014 }
02015 }
02016
02017 defaultCharFormat = oldDefaultCharFormat;
02018 }
02019
02020 void QTextHtmlExporter::emitTable(const QTextTable *table)
02021 {
02022 QTextTableFormat format = table->format();
02023
02024 html += QLatin1String("\n<table");
02025
02026 if (format.hasProperty(QTextFormat::FrameBorder))
02027 emitAttribute("border", QString::number(format.border()));
02028
02029 emitFloatStyle(format.position());
02030 emitAlignment(format.alignment());
02031 emitTextLength("width", format.width());
02032
02033 if (format.hasProperty(QTextFormat::TableCellSpacing))
02034 emitAttribute("cellspacing", QString::number(format.cellSpacing()));
02035 if (format.hasProperty(QTextFormat::TableCellPadding))
02036 emitAttribute("cellpadding", QString::number(format.cellPadding()));
02037
02038 QBrush bg = format.background();
02039 if (bg != Qt::NoBrush)
02040 emitAttribute("bgcolor", bg.color().name());
02041
02042 html += QLatin1Char('>');
02043
02044 const int rows = table->rows();
02045 const int columns = table->columns();
02046
02047 QVector<QTextLength> columnWidths = format.columnWidthConstraints();
02048 if (columnWidths.isEmpty()) {
02049 columnWidths.resize(columns);
02050 columnWidths.fill(QTextLength());
02051 }
02052 Q_ASSERT(columnWidths.count() == columns);
02053
02054 QVarLengthArray<bool> widthEmittedForColumn(columns);
02055 for (int i = 0; i < columns; ++i)
02056 widthEmittedForColumn[i] = false;
02057
02058 const int headerRowCount = qMin(format.headerRowCount(), rows);
02059 if (headerRowCount > 0)
02060 html += QLatin1String("<thead>");
02061
02062 for (int row = 0; row < rows; ++row) {
02063 html += QLatin1String("\n<tr>");
02064
02065 for (int col = 0; col < columns; ++col) {
02066 const QTextTableCell cell = table->cellAt(row, col);
02067
02068
02069 if (cell.row() != row)
02070 continue;
02071
02072 if (cell.column() != col)
02073 continue;
02074
02075 html += QLatin1String("\n<td");
02076
02077 if (!widthEmittedForColumn[col]) {
02078 emitTextLength("width", columnWidths.at(col));
02079 widthEmittedForColumn[col] = true;
02080 }
02081
02082 if (cell.columnSpan() > 1)
02083 emitAttribute("colspan", QString::number(cell.columnSpan()));
02084
02085 if (cell.rowSpan() > 1)
02086 emitAttribute("rowspan", QString::number(cell.rowSpan()));
02087
02088 const QTextCharFormat cellFormat = cell.format();
02089 QBrush bg = cellFormat.background();
02090 if (bg != Qt::NoBrush)
02091 emitAttribute("bgcolor", bg.color().name());
02092
02093 html += QLatin1Char('>');
02094
02095 emitFrame(cell.begin());
02096
02097 html += QLatin1String("</td>");
02098 }
02099
02100 html += QLatin1String("</tr>");
02101 if (headerRowCount > 0 && row == headerRowCount - 1)
02102 html += QLatin1String("</thead>");
02103 }
02104
02105 html += QLatin1String("</table>");
02106 }
02107
02108 void QTextHtmlExporter::emitFrame(QTextFrame::Iterator frameIt)
02109 {
02110 if (!frameIt.atEnd()) {
02111 QTextFrame::Iterator next = frameIt;
02112 ++next;
02113 if (next.atEnd()
02114 && frameIt.currentFrame() == 0
02115 && frameIt.parentFrame() != doc->rootFrame()
02116 && frameIt.currentBlock().begin().atEnd())
02117 return;
02118 }
02119
02120 for (QTextFrame::Iterator it = frameIt;
02121 !it.atEnd(); ++it) {
02122 if (QTextFrame *f = it.currentFrame()) {
02123 if (QTextTable *table = qobject_cast<QTextTable *>(f)) {
02124 emitTable(table);
02125 } else {
02126 html += QLatin1String("\n<table");
02127 QTextFrameFormat format = f->frameFormat();
02128
02129 if (format.hasProperty(QTextFormat::FrameBorder))
02130 emitAttribute("border", QString::number(format.border()));
02131
02132 html += QLatin1String(" style=\"-qt-table-type: frame;");
02133 emitFloatStyle(format.position(), OmitStyleTag);
02134
02135 if (format.hasProperty(QTextFormat::FrameMargin)) {
02136 const QString margin = QString::number(format.margin());
02137 emitMargins(margin, margin, margin, margin);
02138 }
02139
02140 html += QLatin1Char('\"');
02141
02142 emitTextLength("width", format.width());
02143 emitTextLength("height", format.height());
02144
02145 QBrush bg = format.background();
02146 if (bg != Qt::NoBrush)
02147 emitAttribute("bgcolor", bg.color().name());
02148
02149 html += QLatin1Char('>');
02150 html += QLatin1String("\n<tr>\n<td style=\"border: none;\">");
02151 emitFrame(f->begin());
02152 html += QLatin1String("</td></tr></table>");
02153 }
02154 } else if (it.currentBlock().isValid()) {
02155 emitBlock(it.currentBlock());
02156 }
02157 }
02158 }
02159
02178 QString QTextDocument::toHtml(const QByteArray &encoding) const
02179 {
02180 return QTextHtmlExporter(this).toHtml(encoding);
02181 }
02182
02186 QVector<QTextFormat> QTextDocument::allFormats() const
02187 {
02188 Q_D(const QTextDocument);
02189 return d->formatCollection()->formats;
02190 }
02191
02192
02198 QTextDocumentPrivate *QTextDocument::docHandle() const
02199 {
02200 Q_D(const QTextDocument);
02201 return const_cast<QTextDocumentPrivate *>(d);
02202 }
02203