• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

kfontcombobox.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002 
00003     Copyright (C) 2008 Chusslove Illich <caslav.ilic@gmx.net>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "kfontcombobox.h"
00022 #include "fonthelpers_p.h"
00023 
00024 #include "kdebug.h"
00025 #include "klocale.h"
00026 #include "kcolorscheme.h"
00027 #include "kglobalsettings.h"
00028 #include "kfontchooser.h"
00029 #include "kcompletion.h"
00030 
00031 #include <QEvent>
00032 #include <QListView>
00033 #include <QFontDatabase>
00034 #include <QIcon>
00035 #include <QAbstractItemDelegate>
00036 #include <QStringListModel>
00037 #include <QPainter>
00038 #include <QList>
00039 #include <QHash>
00040 #include <QScrollBar>
00041 
00042 static QString alphabetSample ()
00043 {
00044     return i18nc("short",
00045     // i18n: A shorter version of the alphabet test phrase translated in
00046     // another message. It is displayed in the dropdown list of font previews
00047     // (the font selection combo box), so keep it under the length equivalent
00048     // to 60 or so proportional Latin characters.
00049                  "The Quick Brown Fox Jumps Over The Lazy Dog");
00050 }
00051 
00052 class KFontFamilyDelegate : public QAbstractItemDelegate
00053 {
00054     Q_OBJECT
00055 public:
00056     explicit KFontFamilyDelegate (QObject *parent);
00057 
00058     void paint (QPainter *painter,
00059                 const QStyleOptionViewItem &option,
00060                 const QModelIndex &index) const;
00061 
00062     QSize sizeHint (const QStyleOptionViewItem &option,
00063                     const QModelIndex &index) const;
00064 
00065     QIcon truetype;
00066     QIcon bitmap;
00067     double sizeFactFamily;
00068     double sizeFactSample;
00069 
00070     QHash<QString, QString> fontFamilyTrMap;
00071 };
00072 
00073 KFontFamilyDelegate::KFontFamilyDelegate (QObject *parent)
00074 : QAbstractItemDelegate(parent)
00075 {
00076     truetype = QIcon(QLatin1String(":/trolltech/styles/commonstyle/images/fonttruetype-16.png"));
00077     bitmap = QIcon(QLatin1String(":/trolltech/styles/commonstyle/images/fontbitmap-16.png"));
00078 
00079     // Font size factors for family name and text sample in font previes,
00080     // multiplies normal font size.
00081     sizeFactFamily = 1.0;
00082     sizeFactSample = 1.0; // better leave at 1, so that user can relate sizes to default
00083 }
00084 
00085 void KFontFamilyDelegate::paint (QPainter *painter,
00086                                  const QStyleOptionViewItem &option,
00087                                  const QModelIndex &index) const
00088 {
00089     QBrush sampleBrush;
00090     if (option.state & QStyle::State_Selected) {
00091         painter->save();
00092         painter->setBrush(option.palette.highlight());
00093         painter->setPen(Qt::NoPen);
00094         painter->drawRect(option.rect);
00095         painter->setPen(QPen(option.palette.highlightedText(), 0));
00096         sampleBrush = option.palette.highlightedText();
00097     } else {
00098         sampleBrush = KColorScheme(QPalette::Normal).foreground(KColorScheme::InactiveText);
00099     }
00100 
00101     QFont baseFont = KGlobalSettings::generalFont();
00102     QString trFontFamily = index.data(Qt::DisplayRole).toString();
00103     QString fontFamily = fontFamilyTrMap[trFontFamily];
00104 
00105     // Writing systems provided by the font.
00106     QList<QFontDatabase::WritingSystem> availableSystems = QFontDatabase().writingSystems(fontFamily);
00107 
00108     // Intersect font's writing systems with that specified for
00109     // the language's sample text, to see if the sample can be shown.
00110     // If the font reports no writing systems, assume it can show the sample.
00111     bool canShowLanguageSample = true;
00112     if (availableSystems.count() > 0) {
00113         canShowLanguageSample = false;
00114         QString scriptsSpec = i18nc("Numeric IDs of scripts for font previews",
00115         // i18n: Integer which indicates the script you used in the sample text
00116         // for font previews in your language. For the possible values, see
00117         // http://doc.trolltech.com/qfontdatabase.html#WritingSystem-enum
00118         // If the sample text contains several scripts, their IDs can be given
00119         // as a comma-separated list (e.g. for Japanese it is "1,27").
00120                                     "1");
00121         QStringList scriptStrIds = scriptsSpec.split(',');
00122         foreach (const QString &scriptStrId, scriptStrIds) {
00123             bool convOk;
00124             int ws = scriptStrId.toInt(&convOk);
00125             if (   convOk && ws > 0 && ws < QFontDatabase::WritingSystemsCount
00126                 && availableSystems.contains(static_cast<QFontDatabase::WritingSystem>(ws))) {
00127                 canShowLanguageSample = true;
00128                 break;
00129             }
00130         }
00131     }
00132 
00133     // Choose and paint an icon according to the font type, scalable or bitmat.
00134     const QIcon *icon = &bitmap;
00135     if (QFontDatabase().isSmoothlyScalable(fontFamily)) {
00136         icon = &truetype;
00137     }
00138     QRect r = option.rect;
00139     icon->paint(painter, r, Qt::AlignLeft|Qt::AlignTop);
00140 
00141     // Claim space taken up by the icon.
00142     QSize actualSize = icon->actualSize(r.size());
00143     if (option.direction == Qt::RightToLeft) {
00144         r.setRight(r.right() - actualSize.width() - 4);
00145     } else {
00146         r.setLeft(r.left() + actualSize.width() + 4);
00147     }
00148 
00149     // Draw the font family.
00150     QFont oldPainterFont = painter->font();
00151     QFont familyFont = baseFont;
00152     familyFont.setPointSize(qRound(familyFont.pointSize() * sizeFactFamily));
00153     painter->setFont(familyFont);
00154     painter->drawText(r, Qt::AlignTop|Qt::AlignLeading|Qt::TextSingleLine, trFontFamily);
00155 
00156     // Claim space taken up by the font family name.
00157     int h = painter->fontMetrics().lineSpacing();
00158     r.setTop(r.top() + h);
00159 
00160     // Show text sample in user's language if the writing system is supported,
00161     // otherwise show a collage of generic script samples provided by Qt.
00162     // If the font does not report what it supports, assume all.
00163     QString sample;
00164     if (canShowLanguageSample) {
00165         sample = alphabetSample();
00166     } else {
00167         foreach (const QFontDatabase::WritingSystem &ws, availableSystems) {
00168             sample += QFontDatabase::writingSystemSample(ws) + "  ";
00169             if (sample.length() > 40) { // do not let the sample be too long
00170                 break;
00171             }
00172         }
00173         sample = sample.trimmed();
00174     }
00175     QFont sampleFont;
00176     sampleFont.setFamily(fontFamily);
00177     sampleFont.setPointSize(qRound(sampleFont.pointSize() * sizeFactSample));
00178     painter->setFont(sampleFont);
00179     QPen oldPen = painter->pen();
00180     painter->setPen(sampleBrush.color());
00181     painter->drawText(r, Qt::AlignTop|Qt::AlignLeading|Qt::TextSingleLine, sample);
00182     painter->setFont(oldPainterFont);
00183     painter->setPen(oldPen);
00184 
00185     if (option.state & QStyle::State_Selected) {
00186         painter->restore();
00187     }
00188 }
00189 
00190 QSize KFontFamilyDelegate::sizeHint (const QStyleOptionViewItem &option,
00191                                      const QModelIndex &index) const
00192 {
00193     Q_UNUSED(option);
00194 
00195     QFont baseFont = KGlobalSettings::generalFont();
00196     QString trFontFamily = index.data(Qt::DisplayRole).toString();
00197     QString fontFamily = fontFamilyTrMap[trFontFamily];
00198 
00199     QFont familyFont = baseFont;
00200     familyFont.setPointSize(qRound(familyFont.pointSize() * sizeFactFamily));
00201     QFontMetrics familyMetrics(familyFont);
00202 
00203     QFont sampleFont = baseFont;
00204     sampleFont.setFamily(fontFamily);
00205     sampleFont.setPointSize(qRound(sampleFont.pointSize() * sizeFactSample));
00206     QFontMetrics sampleMetrics(familyFont);
00207     QString sample = alphabetSample();
00208 
00209     // Only the hight matters here, the width is mandated by KFontComboBox::event()
00210     return QSize(qMax(familyMetrics.width(trFontFamily), sampleMetrics.width(sample)),
00211                  qRound(familyMetrics.lineSpacing() + sampleMetrics.lineSpacing() * 1.2));
00212 }
00213 
00214 class KFontComboBoxPrivate
00215 {
00216 public:
00217     KFontComboBoxPrivate (KFontComboBox *parent);
00218     void updateDatabase ();
00219     void updateIndexToFont ();
00220     void _k_currentFontChanged (int index);
00221 
00222     KFontComboBox *k;
00223     QFont currentFont;
00224     bool onlyFixed;
00225     bool signalsAllowed;
00226     KFontFamilyDelegate *delegate;
00227     QStringListModel *model;
00228 };
00229 
00230 KFontComboBoxPrivate::KFontComboBoxPrivate (KFontComboBox *parent)
00231 {
00232     k = parent;
00233     currentFont = KGlobalSettings::generalFont();
00234     onlyFixed = false;
00235     signalsAllowed = true;
00236 }
00237 
00238 void KFontComboBoxPrivate::updateDatabase ()
00239 {
00240     QStringList fontFamilies;
00241     KFontChooser::getFontList(fontFamilies,
00242                               onlyFixed ? KFontChooser::FixedWidthFonts : 0);
00243 
00244     // Translate font families for the list model.
00245     delegate->fontFamilyTrMap.clear();
00246     QStringList trFontFamilies =
00247         translateFontNameList(fontFamilies, &(delegate->fontFamilyTrMap));
00248 
00249     // Add families to the list model and completion.
00250     model->setStringList(trFontFamilies);
00251     KCompletion *completion = k->completionObject();
00252     if (completion) {
00253         completion->insertItems(trFontFamilies);
00254         completion->setIgnoreCase(true);
00255     }
00256 }
00257 
00258 void KFontComboBoxPrivate::updateIndexToFont ()
00259 {
00260     // QFontInfo necessary to return the family with proper casing.
00261     QString selectedFontFamily = QFontInfo(currentFont).family();
00262     QString trSelectedFontFamily = translateFontName(selectedFontFamily);
00263     const QStringList trFontFamilies = model->stringList();
00264     if (!trFontFamilies.count()) {
00265         return;
00266     }
00267 
00268     // Match the font's family with an item in the list.
00269     int index = 0;
00270     foreach (const QString &trFontFamily, trFontFamilies) {
00271         if (trSelectedFontFamily == trFontFamily) {
00272             break;
00273         }
00274         ++index;
00275     }
00276     if (index == trFontFamilies.count()) {
00277         // If no family matched, change font to first on the list.
00278         index = 0;
00279         currentFont = QFont(delegate->fontFamilyTrMap[trFontFamilies[0]]);
00280         emit k->currentFontChanged(currentFont);
00281     }
00282 
00283     // Set the new list item.
00284     signalsAllowed = false;
00285     k->setCurrentIndex(index);
00286     signalsAllowed = true;
00287 }
00288 
00289 void KFontComboBoxPrivate::_k_currentFontChanged (int index)
00290 {
00291     if (!signalsAllowed) {
00292         return;
00293     }
00294 
00295     QString trFontFamily = k->itemText(index);
00296     QString fontFamily = delegate->fontFamilyTrMap[trFontFamily];
00297     if (!fontFamily.isEmpty()) {
00298         currentFont = QFont(fontFamily);
00299         emit k->currentFontChanged(currentFont);
00300     } else {
00301         // Unknown font family given. Just remove from the list.
00302         // This should not happen, as adding arbitrary font names is prevented.
00303         QStringList lst = model->stringList();
00304         lst.removeAll(trFontFamily);
00305         model->setStringList(lst);
00306     }
00307 }
00308 
00309 KFontComboBox::KFontComboBox (QWidget *parent)
00310 : KComboBox(true, parent), d(new KFontComboBoxPrivate(this))
00311 {
00312     // Inputing arbitrary font names does not make sense.
00313     setInsertPolicy(QComboBox::NoInsert);
00314 
00315     // Special list item painter showing font previews and its list model.
00316     d->delegate = new KFontFamilyDelegate(this);
00317     setItemDelegate(d->delegate);
00318     d->model = new QStringListModel(this);
00319     setModel(d->model);
00320 
00321     // Set current font when a new family has been chosen in the combo.
00322     connect(this, SIGNAL(currentIndexChanged(int)),
00323             this, SLOT(_k_currentFontChanged(int)));
00324 
00325     // Initialize font selection and list of available fonts.
00326     d->updateDatabase();
00327     d->updateIndexToFont();
00328 }
00329 
00330 KFontComboBox::~KFontComboBox ()
00331 {
00332     delete d;
00333 }
00334 
00335 void KFontComboBox::setOnlyFixed (bool onlyFixed)
00336 {
00337     if (onlyFixed != d->onlyFixed) {
00338         d->onlyFixed = onlyFixed;
00339         d->updateDatabase();
00340     }
00341 }
00342 
00343 QFont KFontComboBox::currentFont () const
00344 {
00345     return d->currentFont;
00346 }
00347 
00348 void KFontComboBox::setCurrentFont (const QFont &font)
00349 {
00350     if (font != d->currentFont) {
00351         d->currentFont = font;
00352         emit currentFontChanged(d->currentFont);
00353         d->updateIndexToFont();
00354     }
00355 }
00356 
00357 bool KFontComboBox::event (QEvent *e)
00358 {
00359     if (e->type() == QEvent::Resize) {
00360         QListView *lview = qobject_cast<QListView*>(view());
00361         if (lview) {
00362             QString sample = alphabetSample();
00363             // Limit text sample length to avoid too wide list view.
00364             if (sample.length() > 60) {
00365                 sample = sample.left(57) + "...";
00366             }
00367             QFont approxFont = KGlobalSettings::generalFont();
00368             approxFont.setPointSize(qRound(  approxFont.pointSize()
00369                                            * d->delegate->sizeFactSample));
00370             int widgetWidth = width();
00371             int sampleWidth = QFontMetrics(approxFont).width(sample);
00372             sampleWidth = qRound(sampleWidth * 1.1); // extra for wider fonts
00373             int iconWidth = d->delegate->truetype.actualSize(size()).width();
00374             int vsbarWidth = 0;
00375             if (lview->verticalScrollBar()) {
00376                 vsbarWidth = lview->verticalScrollBar()->width();
00377             }
00378             lview->window()->setFixedWidth(  qMax(widgetWidth, sampleWidth)
00379                                            + iconWidth + vsbarWidth);
00380         }
00381     }
00382     return KComboBox::event(e);
00383 }
00384 
00385 QSize KFontComboBox::sizeHint() const
00386 {
00387     QSize sz = KComboBox::sizeHint();
00388     QFontMetrics fm(KGlobalSettings::generalFont());
00389     sz.setWidth(fm.width("m") * 14);
00390     return sz;
00391 }
00392 
00393 #include "kfontcombobox.moc"
00394 #include "moc_kfontcombobox.moc"
00395 

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal