# qwt_text_engine.cpp

    00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
    00002  * Qwt Widget Library
    00003  * Copyright (C) 1997   Josef Wilgen
    00004  * Copyright (C) 2003   Uwe Rathmann
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the Qwt License, Version 1.0
    00008  *****************************************************************************/
    00009
    00010 // vim: expandtab
    00011
    00012 #include <qpainter.h>
    00013 #include <qpixmap.h>
    00014 #include <qimage.h>
    00015 #include <qmap.h>
    00016 #include <qwidget.h>
    00017 #include "qwt_math.h"
    00018 #include "qwt_painter.h"
    00019 #include "qwt_text_engine.h"
    00020
    00021 static QString taggedRichText(const QString &text, int flags)
    00022 {
    00023     QString richText = text;
    00024
    00025     // By default QSimpleRichText is Qt::AlignLeft
    00026     if (flags & Qt::AlignJustify)
    00027     {
    00028         richText.prepend(QString::fromLatin1("<div align=\"justify\">"));
    00029         richText.append(QString::fromLatin1("</div>"));
    00030     }
    00031     else if (flags & Qt::AlignRight)
    00032     {
    00033         richText.prepend(QString::fromLatin1("<div align=\"right\">"));
    00034         richText.append(QString::fromLatin1("</div>"));
    00035     }
    00036     else if (flags & Qt::AlignHCenter)
    00037     {
    00038         richText.prepend(QString::fromLatin1("<div align=\"center\">"));
    00039         richText.append(QString::fromLatin1("</div>"));
    00040     }
    00041
    00042     return richText;
    00043 }
    00044
    00045 #if QT_VERSION < 0x040000
    00046
    00047 #include <qsimplerichtext.h>
    00048 #include <qstylesheet.h>
    00049
    00050 class QwtRichTextDocument: public QSimpleRichText
    00051 {
    00052 public:
    00053     QwtRichTextDocument(const QString &text, int flags, const QFont &font):
    00054         QSimpleRichText(taggedRichText(text, flags), font)
    00055     {
    00056     }
    00057 };
    00058
    00059 #else // QT_VERSION >= 0x040000
    00060
    00061 #include <qtextobject.h>
    00062 #include <qtextdocument.h>
    00063 #include <qabstracttextdocumentlayout.h>
    00064
    00065 #if QT_VERSION < 0x040200
    00066 #include <qlabel.h>
    00067 #endif
    00068
    00069 class QwtRichTextDocument: public QTextDocument
    00070 {
    00071 public:
    00072     QwtRichTextDocument(const QString &text, int flags, const QFont &font)
    00073     {
    00074         setUndoRedoEnabled(false);
    00075         setDefaultFont(font);
    00076 #if QT_VERSION >= 0x040300
    00077         setHtml(text);
    00078 #else
    00079         setHtml(taggedRichText(text, flags));
    00080 #endif
    00081
    00082         // make sure we have a document layout
    00083         (void)documentLayout();
    00084
    00085 #if QT_VERSION >= 0x040300
    00086         QTextOption option = defaultTextOption();
    00087         if ( flags & Qt::TextWordWrap )
    00088             option.setWrapMode(QTextOption::WordWrap);
    00089         else
    00090             option.setWrapMode(QTextOption::NoWrap);
    00091
    00092         option.setAlignment((Qt::Alignment) flags);
    00093         setDefaultTextOption(option);
    00094
    00095         QTextFrame *root = rootFrame();
    00096         QTextFrameFormat fm = root->frameFormat();
    00097         fm.setBorder(0);
    00098         fm.setMargin(0);
    00099         fm.setPadding(0);
    00100         fm.setBottomMargin(0);
    00101         fm.setLeftMargin(0);
    00102         root->setFrameFormat(fm);
    00103
    00104         adjustSize();
    00105 #endif
    00106     }
    00107 };
    00108
    00109 #endif
    00110
    00111 class QwtPlainTextEngine::PrivateData
    00112 {
    00113 public:
    00114     int effectiveAscent(const QFont &font) const
    00115     {
    00116         const QString fontKey = font.key();
    00117
    00118         QMap<QString, int>::const_iterator it =
    00119             d_ascentCache.find(fontKey);
    00120         if ( it == d_ascentCache.end() )
    00121         {
    00122             int ascent = findAscent(font);
    00123             it = d_ascentCache.insert(fontKey, ascent);
    00124         }
    00125
    00126         return (*it);
    00127     }
    00128
    00129 private:
    00130     int findAscent(const QFont &font) const
    00131     {
    00132         static const QString dummy("E");
    00133         static const QColor white(Qt::white);
    00134
    00135         const QFontMetrics fm(font);
    00136         QPixmap pm(fm.width(dummy), fm.height());
    00137         pm.fill(white);
    00138
    00139         QPainter p(&pm);
    00140         p.setFont(font);
    00141         p.drawText(0, 0,  pm.width(), pm.height(), 0, dummy);
    00142         p.end();
    00143
    00144 #if QT_VERSION < 0x040000
    00145         const QImage img = pm.convertToImage();
    00146 #else
    00147         const QImage img = pm.toImage();
    00148 #endif
    00149
    00150         int row = 0;
    00151         for ( row = 0; row < img.height(); row++ )
    00152         {
    00153             const QRgb *line = (const QRgb *)img.scanLine(row);
    00154
    00155             const int w = pm.width();
    00156             for ( int col = 0; col < w; col++ )
    00157             {
    00158                 if ( line[col] != white.rgb() )
    00159                     return fm.ascent() - row + 1;
    00160             }
    00161         }
    00162
    00163         return fm.ascent();
    00164     }
    00165
    00166     mutable QMap<QString, int> d_ascentCache;
    00167 };
    00168
    00170 QwtTextEngine::QwtTextEngine()
    00171 {
    00172 }
    00173
    00175 QwtTextEngine::~QwtTextEngine()
    00176 {
    00177 }
    00178
    00180 QwtPlainTextEngine::QwtPlainTextEngine()
    00181 {
    00182     d_data = new PrivateData;
    00183 }
    00184
    00186 QwtPlainTextEngine::~QwtPlainTextEngine()
    00187 {
    00188     delete d_data;
    00189 }
    00190
    00201 int QwtPlainTextEngine::heightForWidth(const QFont& font, int flags,
    00202         const QString& text, int width) const
    00203 {
    00204     const QFontMetrics fm(font);
    00205     const QRect rect = fm.boundingRect(
    00206         0, 0, width, QWIDGETSIZE_MAX, flags, text);
    00207
    00208     return rect.height();
    00209 }
    00210
    00220 QSize QwtPlainTextEngine::textSize(const QFont &font,
    00221     int flags, const QString& text) const
    00222 {
    00223     const QFontMetrics fm(font);
    00224     const QRect rect = fm.boundingRect(
    00225         0, 0, QWIDGETSIZE_MAX, QWIDGETSIZE_MAX, flags, text);
    00226
    00227     return rect.size();
    00228 }
    00229
    00239 void QwtPlainTextEngine::textMargins(const QFont &font, const QString &,
    00240     int &left, int &right, int &top, int &bottom) const
    00241 {
    00242     left = right = top = 0;
    00243
    00244     const QFontMetrics fm(font);
    00245     top = fm.ascent() - d_data->effectiveAscent(font);
    00246     bottom = fm.descent() + 1;
    00247 }
    00248
    00259 void QwtPlainTextEngine::draw(QPainter *painter, const QRect &rect,
    00260     int flags, const QString& text) const
    00261 {
    00262     QwtPainter::drawText(painter, rect, flags, text);
    00263 }
    00264
    00269 bool QwtPlainTextEngine::mightRender(const QString &) const
    00270 {
    00271     return true;
    00272 }
    00273
    00274 #ifndef QT_NO_RICHTEXT
    00275
    00277 QwtRichTextEngine::QwtRichTextEngine()
    00278 {
    00279 }
    00280
    00291 int QwtRichTextEngine::heightForWidth(const QFont& font, int flags,
    00292         const QString& text, int width) const
    00293 {
    00294     QwtRichTextDocument doc(text, flags, font);
    00295
    00296 #if QT_VERSION < 0x040000
    00297     doc.setWidth(width);
    00298     const int h = doc.height();
    00299 #else
    00300     doc.setPageSize(QSize(width, QWIDGETSIZE_MAX));
    00301     const int h = qRound(doc.documentLayout()->documentSize().height());
    00302 #endif
    00303     return h;
    00304 }
    00305
    00316 QSize QwtRichTextEngine::textSize(const QFont &font,
    00317     int flags, const QString& text) const
    00318 {
    00319     QwtRichTextDocument doc(text, flags, font);
    00320
    00321 #if QT_VERSION < 0x040000
    00322     doc.setWidth(QWIDGETSIZE_MAX);
    00323
    00324     const int w = doc.widthUsed();
    00325     const int h = doc.height();
    00326     return QSize(w, h);
    00327
    00328 #else // QT_VERSION >= 0x040000
    00329
    00330 #if QT_VERSION < 0x040200
    00331     /*
    00332       Unfortunately offering the bounding rect calculation in the
    00333       API of QTextDocument has been forgotten in Qt <= 4.1.x. It
    00334       is planned to come with Qt 4.2.x.
    00335       In the meantime we need a hack with a temporary QLabel,
    00336       to reengineer the internal calculations.
    00337     */
    00338
    00339     static int off = 0;
    00340     static QLabel *label = NULL;
    00341     if ( label == NULL )
    00342     {
    00343         label = new QLabel;
    00344         label->hide();
    00345
    00346         const char *s = "XXXXX";
    00347         label->setText(s);
    00348         int w1 = label->sizeHint().width();
    00349         const QFontMetrics fm(label->font());
    00350         int w2 = fm.width(s);
    00351         off = w1 - w2;
    00352     }
    00353     label->setFont(doc.defaultFont());
    00354     label->setText(text);
    00355
    00356     int w = qwtMax(label->sizeHint().width() - off, 0);
    00357     doc.setPageSize(QSize(w, QWIDGETSIZE_MAX));
    00358
    00359     int h = qRound(doc.documentLayout()->documentSize().height());
    00360     return QSize(w, h);
    00361
    00362 #else // QT_VERSION >= 0x040200
    00363
    00364 #if QT_VERSION >= 0x040300
    00365     QTextOption option = doc.defaultTextOption();
    00366     if ( option.wrapMode() != QTextOption::NoWrap )
    00367     {
    00368         option.setWrapMode(QTextOption::NoWrap);
    00369         doc.setDefaultTextOption(option);
    00370         doc.adjustSize();
    00371     }
    00372 #endif
    00373
    00374     return doc.size().toSize();
    00375 #endif
    00376 #endif
    00377 }
    00378
    00387 void QwtRichTextEngine::draw(QPainter *painter, const QRect &rect,
    00388     int flags, const QString& text) const
    00389 {
    00390     QwtRichTextDocument doc(text, flags, painter->font());
    00391     QwtPainter::drawSimpleRichText(painter, rect, flags, doc);
    00392 }
    00393
    00402 QString QwtRichTextEngine::taggedText(const QString &text, int flags) const
    00403 {
    00404     return taggedRichText(text, flags);
    00405 }
    00406
    00413 bool QwtRichTextEngine::mightRender(const QString &text) const
    00414 {
    00415 #if QT_VERSION < 0x040000
    00416     return QStyleSheet::mightBeRichText(text);
    00417 #else
    00418     return Qt::mightBeRichText(text);
    00419 #endif
    00420 }
    00421
    00430 void QwtRichTextEngine::textMargins(const QFont &, const QString &,
    00431     int &left, int &right, int &top, int &bottom) const
    00432 {
    00433     left = right = top = bottom = 0;
    00434 }
    00435
    00436 #endif // !QT_NO_RICHTEXT