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

Generated on Sat May 24 18:47:40 2008 for Qwt User's Guide by  doxygen 1.5.0