/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qfontcombobox.h" #ifndef QT_NO_FONTCOMBOBOX #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE static QFontDatabase::WritingSystem writingSystemForFont(const QFont &font, bool *hasLatin) { *hasLatin = true; QList writingSystems = QFontDatabase().writingSystems(font.family()); // qDebug() << font.family() << writingSystems; // this just confuses the algorithm below. Vietnamese is Latin with lots of special chars writingSystems.removeAll(QFontDatabase::Vietnamese); QFontDatabase::WritingSystem system = QFontDatabase::Any; if (!writingSystems.contains(QFontDatabase::Latin)) { *hasLatin = false; // we need to show something if (writingSystems.count()) system = writingSystems.last(); } else { writingSystems.removeAll(QFontDatabase::Latin); } if (writingSystems.isEmpty()) return system; if (writingSystems.count() == 1 && writingSystems.at(0) > QFontDatabase::Cyrillic) { system = writingSystems.at(0); return system; } if (writingSystems.count() <= 2 && writingSystems.last() > QFontDatabase::Armenian && writingSystems.last() < QFontDatabase::Vietnamese) { system = writingSystems.last(); return system; } if (writingSystems.count() <= 5 && writingSystems.last() >= QFontDatabase::SimplifiedChinese && writingSystems.last() <= QFontDatabase::Korean) system = writingSystems.last(); return system; } class QFontFamilyDelegate : public QAbstractItemDelegate { Q_OBJECT public: explicit QFontFamilyDelegate(QObject *parent); // painting void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; QIcon truetype; QIcon bitmap; QFontDatabase::WritingSystem writingSystem; }; QFontFamilyDelegate::QFontFamilyDelegate(QObject *parent) : QAbstractItemDelegate(parent) { truetype = QIcon(QLatin1String(":/trolltech/styles/commonstyle/images/fonttruetype-16.png")); bitmap = QIcon(QLatin1String(":/trolltech/styles/commonstyle/images/fontbitmap-16.png")); writingSystem = QFontDatabase::Any; } void QFontFamilyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QString text = index.data(Qt::DisplayRole).toString(); QFont font(option.font); font.setPointSize(QFontInfo(font).pointSize() * 3 / 2); QFont font2 = font; font2.setFamily(text); bool hasLatin; QFontDatabase::WritingSystem system = writingSystemForFont(font2, &hasLatin); if (hasLatin) font = font2; QRect r = option.rect; if (option.state & QStyle::State_Selected) { painter->save(); painter->setBrush(option.palette.highlight()); painter->setPen(Qt::NoPen); painter->drawRect(option.rect); painter->setPen(QPen(option.palette.highlightedText(), 0)); } const QIcon *icon = &bitmap; if (QFontDatabase().isSmoothlyScalable(text)) { icon = &truetype; } QSize actualSize = icon->actualSize(r.size()); icon->paint(painter, r, Qt::AlignLeft|Qt::AlignVCenter); if (option.direction == Qt::RightToLeft) r.setRight(r.right() - actualSize.width() - 4); else r.setLeft(r.left() + actualSize.width() + 4); QFont old = painter->font(); painter->setFont(font); painter->drawText(r, Qt::AlignVCenter|Qt::AlignLeading|Qt::TextSingleLine, text); if (writingSystem != QFontDatabase::Any) system = writingSystem; if (system != QFontDatabase::Any) { int w = painter->fontMetrics().width(text + QLatin1String(" ")); painter->setFont(font2); QString sample = QFontDatabase().writingSystemSample(system); if (option.direction == Qt::RightToLeft) r.setRight(r.right() - w); else r.setLeft(r.left() + w); painter->drawText(r, Qt::AlignVCenter|Qt::AlignLeading|Qt::TextSingleLine, sample); } painter->setFont(old); if (option.state & QStyle::State_Selected) painter->restore(); } QSize QFontFamilyDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QString text = index.data(Qt::DisplayRole).toString(); QFont font(option.font); // font.setFamily(text); font.setPointSize(QFontInfo(font).pointSize() * 3/2); QFontMetrics fontMetrics(font); return QSize(fontMetrics.width(text), fontMetrics.lineSpacing()); } class QFontComboBoxPrivate : public QComboBoxPrivate { public: inline QFontComboBoxPrivate() { filters = QFontComboBox::AllFonts; } QFontComboBox::FontFilters filters; QFont currentFont; void _q_updateModel(); void _q_currentChanged(const QString &); Q_DECLARE_PUBLIC(QFontComboBox) }; void QFontComboBoxPrivate::_q_updateModel() { Q_Q(QFontComboBox); const int scalableMask = (QFontComboBox::ScalableFonts | QFontComboBox::NonScalableFonts); const int spacingMask = (QFontComboBox::ProportionalFonts | QFontComboBox::MonospacedFonts); QStringListModel *m = qobject_cast(q->model()); if (!m) return; QFontFamilyDelegate *delegate = qobject_cast(q->view()->itemDelegate()); QFontDatabase::WritingSystem system = delegate ? delegate->writingSystem : QFontDatabase::Any; QFontDatabase fdb; QStringList list = fdb.families(system); QStringList result; int offset = 0; QFontInfo fi(currentFont); for (int i = 0; i < list.size(); ++i) { if ((filters & scalableMask) && (filters & scalableMask) != scalableMask) { if (bool(filters & QFontComboBox::ScalableFonts) != fdb.isSmoothlyScalable(list.at(i))) continue; } if ((filters & spacingMask) && (filters & spacingMask) != spacingMask) { if (bool(filters & QFontComboBox::MonospacedFonts) != fdb.isFixedPitch(list.at(i))) continue; } result += list.at(i); if (list.at(i) == fi.family() || list.at(i).startsWith(fi.family() + QLatin1String(" ["))) offset = result.count() - 1; } list = result; m->setStringList(list); if (list.isEmpty()) { if (currentFont != QFont()) { currentFont = QFont(); emit q->currentFontChanged(currentFont); } } else { q->setCurrentIndex(offset); } } void QFontComboBoxPrivate::_q_currentChanged(const QString &text) { Q_Q(QFontComboBox); QFont newFont(text); if (currentFont.family() != newFont.family()) { currentFont = newFont; emit q->currentFontChanged(currentFont); } } /*! \class QFontComboBox \brief The QFontComboBox widget is a combobox that lets the user select a font family. \since 4.2 \ingroup basicwidgets The combobox is populated with an alphabetized list of font family names, such as Arial, Helvetica, and Times New Roman. Family names are displayed using the actual font when possible. For fonts such as Symbol, where the name is not representable in the font itself, a sample of the font is displayed next to the family name. QFontComboBox is often used in toolbars, in conjunction with a QComboBox for controlling the font size and two \l{QToolButton}s for bold and italic. When the user selects a new font, the currentFontChanged() signal is emitted in addition to currentIndexChanged(). Call setWritingSystem() to tell QFontComboBox to show only fonts that support a given writing system, and setFontFilters() to filter out certain types of fonts as e.g. non scalable fonts or monospaced fonts. \image windowsxp-fontcombobox.png Screenshot of QFontComboBox on Windows XP \sa QComboBox, QFont, QFontInfo, QFontMetrics, QFontDatabase, {Character Map Example} */ /*! \fn void QFontComboBox::setWritingSystem(QFontDatabase::WritingSystem script) */ /*! \fn void QFontComboBox::setCurrentFont(const QFont &font); */ /*! Constructs a font combobox with the given \a parent. */ QFontComboBox::QFontComboBox(QWidget *parent) : QComboBox(*new QFontComboBoxPrivate, parent) { Q_D(QFontComboBox); d->currentFont = font(); setEditable(true); QStringListModel *m = new QStringListModel(this); setModel(m); setItemDelegate(new QFontFamilyDelegate(this)); QListView *lview = qobject_cast(view()); if (lview) lview->setUniformItemSizes(true); setWritingSystem(QFontDatabase::Any); connect(this, SIGNAL(currentIndexChanged(QString)), this, SLOT(_q_currentChanged(QString))); connect(qApp, SIGNAL(fontDatabaseChanged()), this, SLOT(_q_updateModel())); } /*! Destroys the combobox. */ QFontComboBox::~QFontComboBox() { } /*! \property QFontComboBox::writingSystem \brief the writing system that serves as a filter for the combobox If \a script is QFontDatabase::Any (the default), all fonts are listed. \sa fontFilters */ void QFontComboBox::setWritingSystem(QFontDatabase::WritingSystem script) { Q_D(QFontComboBox); QFontFamilyDelegate *delegate = qobject_cast(view()->itemDelegate()); if (delegate) delegate->writingSystem = script; d->_q_updateModel(); } QFontDatabase::WritingSystem QFontComboBox::writingSystem() const { QFontFamilyDelegate *delegate = qobject_cast(view()->itemDelegate()); if (delegate) return delegate->writingSystem; return QFontDatabase::Any; } /*! \enum QFontComboBox::FontFilter This enum can be used to only show certain types of fonts in the font combo box. \value AllFonts Show all fonts \value ScalableFonts Show scalable fonts \value NonScalableFonts Show non scalable fonts \value MonospacedFonts Show monospaced fonts \value ProportionalFonts Show proportional fonts */ /*! \property QFontComboBox::fontFilters \brief the filter for the combobox By default, all fonts are listed. \sa writingSystem */ void QFontComboBox::setFontFilters(FontFilters filters) { Q_D(QFontComboBox); d->filters = filters; d->_q_updateModel(); } QFontComboBox::FontFilters QFontComboBox::fontFilters() const { Q_D(const QFontComboBox); return d->filters; } /*! \property QFontComboBox::currentFont \brief the currently selected font \sa currentFontChanged(), currentIndex, currentText */ QFont QFontComboBox::currentFont() const { Q_D(const QFontComboBox); return d->currentFont; } void QFontComboBox::setCurrentFont(const QFont &font) { Q_D(QFontComboBox); if (font != d->currentFont) { d->currentFont = font; emit currentFontChanged(d->currentFont); d->_q_updateModel(); } } /*! \fn QFontComboBox::currentFontChanged(const QFont &font) This signal is emitted whenever the current font changes, with the new \a font. \sa currentFont */ /*! \reimp */ bool QFontComboBox::event(QEvent *e) { if (e->type() == QEvent::Resize) { QListView *lview = qobject_cast(view()); if (lview) lview->window()->setFixedWidth(width() * 5 / 3); } return QComboBox::event(e); } /*! \reimp */ QSize QFontComboBox::sizeHint() const { QSize sz = QComboBox::sizeHint(); QFontMetrics fm(font()); sz.setWidth(fm.width(QLatin1Char('m'))*14); return sz; } QT_END_NAMESPACE #include "qfontcombobox.moc" #include "moc_qfontcombobox.cpp" #endif // QT_NO_FONTCOMBOBOX