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.setPointSizeF(familyFont.pointSizeF() * 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.setPointSizeF(sampleFont.pointSizeF() * 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.setPointSizeF(familyFont.pointSizeF() * sizeFactFamily); 00201 QFontMetrics familyMetrics(familyFont); 00202 00203 QFont sampleFont = baseFont; 00204 sampleFont.setFamily(fontFamily); 00205 sampleFont.setPointSizeF(sampleFont.pointSizeF() * sizeFactSample); 00206 QFontMetrics sampleMetrics(sampleFont); 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 QStringList fontList; 00229 }; 00230 00231 KFontComboBoxPrivate::KFontComboBoxPrivate (KFontComboBox *parent) 00232 { 00233 k = parent; 00234 currentFont = KGlobalSettings::generalFont(); 00235 onlyFixed = false; 00236 signalsAllowed = true; 00237 } 00238 00239 void KFontComboBoxPrivate::updateDatabase () 00240 { 00241 QStringList fontFamilies = fontList; 00242 if (fontList.isEmpty()) { 00243 KFontChooser::getFontList(fontFamilies, 00244 onlyFixed ? KFontChooser::FixedWidthFonts : 0); 00245 } 00246 00247 // Translate font families for the list model. 00248 delegate->fontFamilyTrMap.clear(); 00249 QStringList trFontFamilies = 00250 translateFontNameList(fontFamilies, &(delegate->fontFamilyTrMap)); 00251 00252 // Add families to the list model and completion. 00253 model->setStringList(trFontFamilies); 00254 KCompletion *completion = k->completionObject(); 00255 if (completion) { 00256 completion->setItems(trFontFamilies); 00257 completion->setIgnoreCase(true); 00258 } 00259 } 00260 00261 void KFontComboBoxPrivate::updateIndexToFont () 00262 { 00263 // QFontInfo necessary to return the family with proper casing. 00264 QString selectedFontFamily = QFontInfo(currentFont).family(); 00265 QString trSelectedFontFamily = translateFontName(selectedFontFamily); 00266 const QStringList trFontFamilies = model->stringList(); 00267 if (!trFontFamilies.count()) { 00268 return; 00269 } 00270 00271 // Match the font's family with an item in the list. 00272 int index = 0; 00273 foreach (const QString &trFontFamily, trFontFamilies) { 00274 if (trSelectedFontFamily == trFontFamily) { 00275 break; 00276 } 00277 ++index; 00278 } 00279 if (index == trFontFamilies.count()) { 00280 // If no family matched, change font to first on the list. 00281 index = 0; 00282 currentFont = QFont(delegate->fontFamilyTrMap[trFontFamilies[0]]); 00283 emit k->currentFontChanged(currentFont); 00284 } 00285 00286 // Set the new list item. 00287 signalsAllowed = false; 00288 k->setCurrentIndex(index); 00289 signalsAllowed = true; 00290 } 00291 00292 void KFontComboBoxPrivate::_k_currentFontChanged (int index) 00293 { 00294 if (!signalsAllowed) { 00295 return; 00296 } 00297 00298 QString trFontFamily = k->itemText(index); 00299 QString fontFamily = delegate->fontFamilyTrMap[trFontFamily]; 00300 if (!fontFamily.isEmpty()) { 00301 currentFont = QFont(fontFamily); 00302 emit k->currentFontChanged(currentFont); 00303 } else { 00304 // Unknown font family given. Just remove from the list. 00305 // This should not happen, as adding arbitrary font names is prevented. 00306 QStringList lst = model->stringList(); 00307 lst.removeAll(trFontFamily); 00308 model->setStringList(lst); 00309 } 00310 } 00311 00312 KFontComboBox::KFontComboBox (QWidget *parent) 00313 : KComboBox(true, parent), d(new KFontComboBoxPrivate(this)) 00314 { 00315 // Inputing arbitrary font names does not make sense. 00316 setInsertPolicy(QComboBox::NoInsert); 00317 00318 // Special list item painter showing font previews and its list model. 00319 d->delegate = new KFontFamilyDelegate(this); 00320 setItemDelegate(d->delegate); 00321 d->model = new QStringListModel(this); 00322 setModel(d->model); 00323 00324 // Set current font when a new family has been chosen in the combo. 00325 connect(this, SIGNAL(currentIndexChanged(int)), 00326 this, SLOT(_k_currentFontChanged(int))); 00327 00328 // Initialize font selection and list of available fonts. 00329 d->updateDatabase(); 00330 d->updateIndexToFont(); 00331 } 00332 00333 KFontComboBox::~KFontComboBox () 00334 { 00335 delete d; 00336 } 00337 00338 void KFontComboBox::setOnlyFixed (bool onlyFixed) 00339 { 00340 if (onlyFixed != d->onlyFixed) { 00341 d->onlyFixed = onlyFixed; 00342 d->updateDatabase(); 00343 } 00344 } 00345 00346 void KFontComboBox::setFontList (const QStringList &fontList) 00347 { 00348 if (fontList != d->fontList) { 00349 d->fontList = fontList; 00350 d->updateDatabase(); 00351 } 00352 } 00353 00354 QFont KFontComboBox::currentFont () const 00355 { 00356 return d->currentFont; 00357 } 00358 00359 void KFontComboBox::setCurrentFont (const QFont &font) 00360 { 00361 if (font != d->currentFont) { 00362 d->currentFont = font; 00363 emit currentFontChanged(d->currentFont); 00364 d->updateIndexToFont(); 00365 } 00366 } 00367 00368 bool KFontComboBox::event (QEvent *e) 00369 { 00370 if (e->type() == QEvent::Resize) { 00371 QListView *lview = qobject_cast<QListView*>(view()); 00372 if (lview) { 00373 QString sample = alphabetSample(); 00374 // Limit text sample length to avoid too wide list view. 00375 if (sample.length() > 60) { 00376 sample = sample.left(57) + "..."; 00377 } 00378 QFont approxFont = KGlobalSettings::generalFont(); 00379 approxFont.setPointSizeF(approxFont.pointSizeF() 00380 * d->delegate->sizeFactSample); 00381 int widgetWidth = width(); 00382 int sampleWidth = QFontMetrics(approxFont).width(sample); 00383 sampleWidth = qRound(sampleWidth * 1.1); // extra for wider fonts 00384 int iconWidth = d->delegate->truetype.actualSize(size()).width(); 00385 int vsbarWidth = 0; 00386 if (lview->verticalScrollBar()) { 00387 vsbarWidth = lview->verticalScrollBar()->width(); 00388 } 00389 lview->window()->setFixedWidth( qMax(widgetWidth, sampleWidth) 00390 + iconWidth + vsbarWidth); 00391 } 00392 } 00393 return KComboBox::event(e); 00394 } 00395 00396 QSize KFontComboBox::sizeHint() const 00397 { 00398 QSize sz = KComboBox::sizeHint(); 00399 QFontMetrics fm(KGlobalSettings::generalFont()); 00400 sz.setWidth(fm.width("m") * 14); 00401 return sz; 00402 } 00403 00404 #include "kfontcombobox.moc" 00405 #include "moc_kfontcombobox.moc" 00406
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:32:39 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:32:39 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.