src/gui/widgets/qfontcombobox.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qfontcombobox.h"
       
    43 
       
    44 #ifndef QT_NO_FONTCOMBOBOX
       
    45 
       
    46 #include <qstringlistmodel.h>
       
    47 #include <qitemdelegate.h>
       
    48 #include <qlistview.h>
       
    49 #include <qpainter.h>
       
    50 #include <qevent.h>
       
    51 #include <qapplication.h>
       
    52 #include <private/qcombobox_p.h>
       
    53 #include <qdebug.h>
       
    54 
       
    55 QT_BEGIN_NAMESPACE
       
    56 
       
    57 static QFontDatabase::WritingSystem writingSystemForFont(const QFont &font, bool *hasLatin)
       
    58 {
       
    59     *hasLatin = true;
       
    60 
       
    61     QList<QFontDatabase::WritingSystem> writingSystems = QFontDatabase().writingSystems(font.family());
       
    62 //     qDebug() << font.family() << writingSystems;
       
    63 
       
    64     // this just confuses the algorithm below. Vietnamese is Latin with lots of special chars
       
    65     writingSystems.removeAll(QFontDatabase::Vietnamese);
       
    66 
       
    67     QFontDatabase::WritingSystem system = QFontDatabase::Any;
       
    68 
       
    69     if (!writingSystems.contains(QFontDatabase::Latin)) {
       
    70         *hasLatin = false;
       
    71         // we need to show something
       
    72         if (writingSystems.count())
       
    73             system = writingSystems.last();
       
    74     } else {
       
    75         writingSystems.removeAll(QFontDatabase::Latin);
       
    76     }
       
    77 
       
    78     if (writingSystems.isEmpty())
       
    79         return system;
       
    80 
       
    81     if (writingSystems.count() == 1 && writingSystems.at(0) > QFontDatabase::Cyrillic) {
       
    82         system = writingSystems.at(0);
       
    83         return system;
       
    84     }
       
    85 
       
    86     if (writingSystems.count() <= 2
       
    87         && writingSystems.last() > QFontDatabase::Armenian
       
    88         && writingSystems.last() < QFontDatabase::Vietnamese) {
       
    89         system = writingSystems.last();
       
    90         return system;
       
    91     }
       
    92 
       
    93     if (writingSystems.count() <= 5
       
    94         && writingSystems.last() >= QFontDatabase::SimplifiedChinese
       
    95         && writingSystems.last() <= QFontDatabase::Korean)
       
    96         system = writingSystems.last();
       
    97 
       
    98     return system;
       
    99 }
       
   100 
       
   101 class QFontFamilyDelegate : public QAbstractItemDelegate
       
   102 {
       
   103     Q_OBJECT
       
   104 public:
       
   105     explicit QFontFamilyDelegate(QObject *parent);
       
   106 
       
   107     // painting
       
   108     void paint(QPainter *painter,
       
   109                const QStyleOptionViewItem &option,
       
   110                const QModelIndex &index) const;
       
   111 
       
   112     QSize sizeHint(const QStyleOptionViewItem &option,
       
   113                    const QModelIndex &index) const;
       
   114 
       
   115     QIcon truetype;
       
   116     QIcon bitmap;
       
   117     QFontDatabase::WritingSystem writingSystem;
       
   118 };
       
   119 
       
   120 QFontFamilyDelegate::QFontFamilyDelegate(QObject *parent)
       
   121     : QAbstractItemDelegate(parent)
       
   122 {
       
   123     truetype = QIcon(QLatin1String(":/trolltech/styles/commonstyle/images/fonttruetype-16.png"));
       
   124     bitmap = QIcon(QLatin1String(":/trolltech/styles/commonstyle/images/fontbitmap-16.png"));
       
   125     writingSystem = QFontDatabase::Any;
       
   126 }
       
   127 
       
   128 void QFontFamilyDelegate::paint(QPainter *painter,
       
   129                                 const QStyleOptionViewItem &option,
       
   130                                 const QModelIndex &index) const
       
   131 {
       
   132     QString text = index.data(Qt::DisplayRole).toString();
       
   133     QFont font(option.font);
       
   134     font.setPointSize(QFontInfo(font).pointSize() * 3 / 2);
       
   135     QFont font2 = font;
       
   136     font2.setFamily(text);
       
   137 
       
   138     bool hasLatin;
       
   139     QFontDatabase::WritingSystem system = writingSystemForFont(font2, &hasLatin);
       
   140     if (hasLatin)
       
   141         font = font2;
       
   142 
       
   143     QRect r = option.rect;
       
   144 
       
   145     if (option.state & QStyle::State_Selected) {
       
   146         painter->save();
       
   147         painter->setBrush(option.palette.highlight());
       
   148         painter->setPen(Qt::NoPen);
       
   149         painter->drawRect(option.rect);
       
   150         painter->setPen(QPen(option.palette.highlightedText(), 0));
       
   151     }
       
   152 
       
   153     const QIcon *icon = &bitmap;
       
   154     if (QFontDatabase().isSmoothlyScalable(text)) {
       
   155         icon = &truetype;
       
   156     }
       
   157     QSize actualSize = icon->actualSize(r.size());
       
   158 
       
   159     icon->paint(painter, r, Qt::AlignLeft|Qt::AlignVCenter);
       
   160     if (option.direction == Qt::RightToLeft)
       
   161         r.setRight(r.right() - actualSize.width() - 4);
       
   162     else
       
   163         r.setLeft(r.left() + actualSize.width() + 4);
       
   164 
       
   165     QFont old = painter->font();
       
   166     painter->setFont(font);
       
   167     painter->drawText(r, Qt::AlignVCenter|Qt::AlignLeading|Qt::TextSingleLine, text);
       
   168 
       
   169     if (writingSystem != QFontDatabase::Any)
       
   170         system = writingSystem;
       
   171 
       
   172     if (system != QFontDatabase::Any) {
       
   173         int w = painter->fontMetrics().width(text + QLatin1String("  "));
       
   174         painter->setFont(font2);
       
   175         QString sample = QFontDatabase().writingSystemSample(system);
       
   176         if (option.direction == Qt::RightToLeft)
       
   177             r.setRight(r.right() - w);
       
   178         else
       
   179             r.setLeft(r.left() + w);
       
   180         painter->drawText(r, Qt::AlignVCenter|Qt::AlignLeading|Qt::TextSingleLine, sample);
       
   181     }
       
   182     painter->setFont(old);
       
   183 
       
   184     if (option.state & QStyle::State_Selected)
       
   185         painter->restore();
       
   186 
       
   187 }
       
   188 
       
   189 QSize QFontFamilyDelegate::sizeHint(const QStyleOptionViewItem &option,
       
   190                                     const QModelIndex &index) const
       
   191 {
       
   192     QString text = index.data(Qt::DisplayRole).toString();
       
   193     QFont font(option.font);
       
   194 //     font.setFamily(text);
       
   195     font.setPointSize(QFontInfo(font).pointSize() * 3/2);
       
   196     QFontMetrics fontMetrics(font);
       
   197     return QSize(fontMetrics.width(text), fontMetrics.lineSpacing());
       
   198 }
       
   199 
       
   200 
       
   201 class QFontComboBoxPrivate : public QComboBoxPrivate
       
   202 {
       
   203 public:
       
   204     inline QFontComboBoxPrivate() { filters = QFontComboBox::AllFonts; }
       
   205 
       
   206     QFontComboBox::FontFilters filters;
       
   207     QFont currentFont;
       
   208 
       
   209     void _q_updateModel();
       
   210     void _q_currentChanged(const QString &);
       
   211 
       
   212     Q_DECLARE_PUBLIC(QFontComboBox)
       
   213 };
       
   214 
       
   215 
       
   216 void QFontComboBoxPrivate::_q_updateModel()
       
   217 {
       
   218     Q_Q(QFontComboBox);
       
   219     const int scalableMask = (QFontComboBox::ScalableFonts | QFontComboBox::NonScalableFonts);
       
   220     const int spacingMask = (QFontComboBox::ProportionalFonts | QFontComboBox::MonospacedFonts);
       
   221 
       
   222     QStringListModel *m = qobject_cast<QStringListModel *>(q->model());
       
   223     if (!m)
       
   224         return;
       
   225     QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(q->view()->itemDelegate());
       
   226     QFontDatabase::WritingSystem system = delegate ? delegate->writingSystem : QFontDatabase::Any;
       
   227 
       
   228     QFontDatabase fdb;
       
   229     QStringList list = fdb.families(system);
       
   230     QStringList result;
       
   231 
       
   232     int offset = 0;
       
   233     QFontInfo fi(currentFont);
       
   234 
       
   235     for (int i = 0; i < list.size(); ++i) {
       
   236         if ((filters & scalableMask) && (filters & scalableMask) != scalableMask) {
       
   237             if (bool(filters & QFontComboBox::ScalableFonts) != fdb.isSmoothlyScalable(list.at(i)))
       
   238                 continue;
       
   239         }
       
   240         if ((filters & spacingMask) && (filters & spacingMask) != spacingMask) {
       
   241             if (bool(filters & QFontComboBox::MonospacedFonts) != fdb.isFixedPitch(list.at(i)))
       
   242                 continue;
       
   243         }
       
   244         result += list.at(i);
       
   245         if (list.at(i) == fi.family() || list.at(i).startsWith(fi.family() + QLatin1String(" [")))
       
   246             offset = result.count() - 1;
       
   247     }
       
   248     list = result;
       
   249 
       
   250     m->setStringList(list);
       
   251     if (list.isEmpty()) {
       
   252         if (currentFont != QFont()) {
       
   253             currentFont = QFont();
       
   254             emit q->currentFontChanged(currentFont);
       
   255         }
       
   256     } else {
       
   257         q->setCurrentIndex(offset);
       
   258     }
       
   259 }
       
   260 
       
   261 
       
   262 void QFontComboBoxPrivate::_q_currentChanged(const QString &text)
       
   263 {
       
   264     Q_Q(QFontComboBox);
       
   265     QFont newFont(text);
       
   266     if (currentFont.family() != newFont.family()) {
       
   267         currentFont = newFont;
       
   268         emit q->currentFontChanged(currentFont);
       
   269     }
       
   270 }
       
   271 
       
   272 /*!
       
   273     \class QFontComboBox
       
   274     \brief The QFontComboBox widget is a combobox that lets the user
       
   275     select a font family.
       
   276 
       
   277     \since 4.2
       
   278     \ingroup basicwidgets
       
   279 
       
   280     The combobox is populated with an alphabetized list of font
       
   281     family names, such as Arial, Helvetica, and Times New Roman.
       
   282     Family names are displayed using the actual font when possible.
       
   283     For fonts such as Symbol, where the name is not representable in
       
   284     the font itself, a sample of the font is displayed next to the
       
   285     family name.
       
   286 
       
   287     QFontComboBox is often used in toolbars, in conjunction with a
       
   288     QComboBox for controlling the font size and two \l{QToolButton}s
       
   289     for bold and italic.
       
   290 
       
   291     When the user selects a new font, the currentFontChanged() signal
       
   292     is emitted in addition to currentIndexChanged().
       
   293 
       
   294     Call setWritingSystem() to tell QFontComboBox to show only fonts
       
   295     that support a given writing system, and setFontFilters() to
       
   296     filter out certain types of fonts as e.g. non scalable fonts or
       
   297     monospaced fonts.
       
   298 
       
   299     \image windowsxp-fontcombobox.png Screenshot of QFontComboBox on Windows XP
       
   300 
       
   301     \sa QComboBox, QFont, QFontInfo, QFontMetrics, QFontDatabase, {Character Map Example}
       
   302 */
       
   303 
       
   304 /*!
       
   305     \fn void QFontComboBox::setWritingSystem(QFontDatabase::WritingSystem script)
       
   306 */
       
   307 
       
   308 /*!
       
   309     \fn void QFontComboBox::setCurrentFont(const QFont &font);
       
   310 */
       
   311 
       
   312 /*!
       
   313     Constructs a font combobox with the given \a parent.
       
   314 */
       
   315 QFontComboBox::QFontComboBox(QWidget *parent)
       
   316     : QComboBox(*new QFontComboBoxPrivate, parent)
       
   317 {
       
   318     Q_D(QFontComboBox);
       
   319     d->currentFont = font();
       
   320     setEditable(true);
       
   321 
       
   322     QStringListModel *m = new QStringListModel(this);
       
   323     setModel(m);
       
   324     setItemDelegate(new QFontFamilyDelegate(this));
       
   325     QListView *lview = qobject_cast<QListView*>(view());
       
   326     if (lview)
       
   327         lview->setUniformItemSizes(true);
       
   328     setWritingSystem(QFontDatabase::Any);
       
   329 
       
   330     connect(this, SIGNAL(currentIndexChanged(QString)),
       
   331             this, SLOT(_q_currentChanged(QString)));
       
   332 
       
   333     connect(qApp, SIGNAL(fontDatabaseChanged()),
       
   334             this, SLOT(_q_updateModel()));
       
   335 }
       
   336 
       
   337 
       
   338 /*!
       
   339     Destroys the combobox.
       
   340 */
       
   341 QFontComboBox::~QFontComboBox()
       
   342 {
       
   343 }
       
   344 
       
   345 /*!
       
   346     \property QFontComboBox::writingSystem
       
   347     \brief the writing system that serves as a filter for the combobox
       
   348 
       
   349     If \a script is QFontDatabase::Any (the default), all fonts are
       
   350     listed.
       
   351 
       
   352     \sa fontFilters
       
   353 */
       
   354 
       
   355 void QFontComboBox::setWritingSystem(QFontDatabase::WritingSystem script)
       
   356 {
       
   357     Q_D(QFontComboBox);
       
   358     QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(view()->itemDelegate());
       
   359     if (delegate)
       
   360         delegate->writingSystem = script;
       
   361     d->_q_updateModel();
       
   362 }
       
   363 
       
   364 QFontDatabase::WritingSystem QFontComboBox::writingSystem() const
       
   365 {
       
   366     QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(view()->itemDelegate());
       
   367     if (delegate)
       
   368         return delegate->writingSystem;
       
   369     return QFontDatabase::Any;
       
   370 }
       
   371 
       
   372 
       
   373 /*!
       
   374   \enum QFontComboBox::FontFilter
       
   375 
       
   376   This enum can be used to only show certain types of fonts in the font combo box.
       
   377 
       
   378   \value AllFonts Show all fonts
       
   379   \value ScalableFonts Show scalable fonts
       
   380   \value NonScalableFonts Show non scalable fonts
       
   381   \value MonospacedFonts Show monospaced fonts
       
   382   \value ProportionalFonts Show proportional fonts
       
   383 */
       
   384 
       
   385 /*!
       
   386     \property QFontComboBox::fontFilters
       
   387     \brief the filter for the combobox
       
   388 
       
   389     By default, all fonts are listed.
       
   390 
       
   391     \sa writingSystem
       
   392 */
       
   393 void QFontComboBox::setFontFilters(FontFilters filters)
       
   394 {
       
   395     Q_D(QFontComboBox);
       
   396     d->filters = filters;
       
   397     d->_q_updateModel();
       
   398 }
       
   399 
       
   400 QFontComboBox::FontFilters QFontComboBox::fontFilters() const
       
   401 {
       
   402     Q_D(const QFontComboBox);
       
   403     return d->filters;
       
   404 }
       
   405 
       
   406 /*!
       
   407     \property QFontComboBox::currentFont
       
   408     \brief the currently selected font
       
   409 
       
   410     \sa currentFontChanged(), currentIndex, currentText
       
   411 */
       
   412 QFont QFontComboBox::currentFont() const
       
   413 {
       
   414     Q_D(const QFontComboBox);
       
   415     return d->currentFont;
       
   416 }
       
   417 
       
   418 void QFontComboBox::setCurrentFont(const QFont &font)
       
   419 {
       
   420     Q_D(QFontComboBox);
       
   421     if (font != d->currentFont) {
       
   422         d->currentFont = font;
       
   423         emit currentFontChanged(d->currentFont);
       
   424         d->_q_updateModel();
       
   425     }
       
   426 }
       
   427 
       
   428 /*!
       
   429     \fn QFontComboBox::currentFontChanged(const QFont &font)
       
   430 
       
   431     This signal is emitted whenever the current font changes, with
       
   432     the new \a font.
       
   433 
       
   434     \sa currentFont
       
   435 */
       
   436 
       
   437 /*!
       
   438     \reimp
       
   439 */
       
   440 bool QFontComboBox::event(QEvent *e)
       
   441 {
       
   442     if (e->type() == QEvent::Resize) {
       
   443         QListView *lview = qobject_cast<QListView*>(view());
       
   444         if (lview)
       
   445             lview->window()->setFixedWidth(width() * 5 / 3);
       
   446     }
       
   447     return QComboBox::event(e);
       
   448 }
       
   449 
       
   450 /*!
       
   451     \reimp
       
   452 */
       
   453 QSize QFontComboBox::sizeHint() const
       
   454 {
       
   455     QSize sz = QComboBox::sizeHint();
       
   456     QFontMetrics fm(font());
       
   457     sz.setWidth(fm.width(QLatin1Char('m'))*14);
       
   458     return sz;
       
   459 }
       
   460 
       
   461 QT_END_NAMESPACE
       
   462 
       
   463 #include "qfontcombobox.moc"
       
   464 #include "moc_qfontcombobox.cpp"
       
   465 
       
   466 #endif // QT_NO_FONTCOMBOBOX