source: trunk/src/gui/widgets/qfontcombobox.cpp@ 22

Last change on this file since 22 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 13.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
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
55QT_BEGIN_NAMESPACE
56
57static 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
101class QFontFamilyDelegate : public QAbstractItemDelegate
102{
103 Q_OBJECT
104public:
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
120QFontFamilyDelegate::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
128void 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
189QSize 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
201class QFontComboBoxPrivate : public QComboBoxPrivate
202{
203public:
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
216void 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
262void QFontComboBoxPrivate::_q_currentChanged(const QString &text)
263{
264 Q_Q(QFontComboBox);
265 QFont newFont(text);
266 if (currentFont != newFont) {
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 \ingroup text
280
281 The combobox is populated with an alphabetized list of font
282 family names, such as Arial, Helvetica, and Times New Roman.
283 Family names are displayed using the actual font when possible.
284 For fonts such as Symbol, where the name is not representable in
285 the font itself, a sample of the font is displayed next to the
286 family name.
287
288 QFontComboBox is often used in toolbars, in conjunction with a
289 QComboBox for controlling the font size and two \l{QToolButton}s
290 for bold and italic.
291
292 When the user selects a new font, the currentFontChanged() signal
293 is emitted in addition to currentIndexChanged().
294
295 Call setWritingSystem() to tell QFontComboBox to show only fonts
296 that support a given writing system, and setFontFilters() to
297 filter out certain types of fonts as e.g. non scalable fonts or
298 monospaced fonts.
299
300 \image windowsxp-fontcombobox.png Screenshot of QFontComboBox on Windows XP
301
302 \sa QComboBox, QFont, QFontInfo, QFontMetrics, QFontDatabase, {Character Map Example}
303*/
304
305/*!
306 \fn void QFontComboBox::setWritingSystem(QFontDatabase::WritingSystem script)
307*/
308
309/*!
310 \fn void QFontComboBox::setCurrentFont(const QFont &font);
311*/
312
313/*!
314 Constructs a font combobox with the given \a parent.
315*/
316QFontComboBox::QFontComboBox(QWidget *parent)
317 : QComboBox(*new QFontComboBoxPrivate, parent)
318{
319 Q_D(QFontComboBox);
320 d->currentFont = font();
321 setEditable(true);
322
323 QStringListModel *m = new QStringListModel(this);
324 setModel(m);
325 setItemDelegate(new QFontFamilyDelegate(this));
326 QListView *lview = qobject_cast<QListView*>(view());
327 if (lview)
328 lview->setUniformItemSizes(true);
329 setWritingSystem(QFontDatabase::Any);
330
331 connect(this, SIGNAL(currentIndexChanged(QString)),
332 this, SLOT(_q_currentChanged(QString)));
333
334 connect(qApp, SIGNAL(fontDatabaseChanged()),
335 this, SLOT(_q_updateModel()));
336}
337
338
339/*!
340 Destroys the combobox.
341*/
342QFontComboBox::~QFontComboBox()
343{
344}
345
346/*!
347 \property QFontComboBox::writingSystem
348 \brief the writing system that serves as a filter for the combobox
349
350 If \a script is QFontDatabase::Any (the default), all fonts are
351 listed.
352
353 \sa fontFilters
354*/
355
356void QFontComboBox::setWritingSystem(QFontDatabase::WritingSystem script)
357{
358 Q_D(QFontComboBox);
359 QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(view()->itemDelegate());
360 if (delegate)
361 delegate->writingSystem = script;
362 d->_q_updateModel();
363}
364
365QFontDatabase::WritingSystem QFontComboBox::writingSystem() const
366{
367 QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(view()->itemDelegate());
368 if (delegate)
369 return delegate->writingSystem;
370 return QFontDatabase::Any;
371}
372
373
374/*!
375 \enum QFontComboBox::FontFilter
376
377 This enum can be used to only show certain types of fonts in the font combo box.
378
379 \value AllFonts Show all fonts
380 \value ScalableFonts Show scalable fonts
381 \value NonScalableFonts Show non scalable fonts
382 \value MonospacedFonts Show monospaced fonts
383 \value ProportionalFonts Show proportional fonts
384*/
385
386/*!
387 \property QFontComboBox::fontFilters
388 \brief the filter for the combobox
389
390 By default, all fonts are listed.
391
392 \sa writingSystem
393*/
394void QFontComboBox::setFontFilters(FontFilters filters)
395{
396 Q_D(QFontComboBox);
397 d->filters = filters;
398 d->_q_updateModel();
399}
400
401QFontComboBox::FontFilters QFontComboBox::fontFilters() const
402{
403 Q_D(const QFontComboBox);
404 return d->filters;
405}
406
407/*!
408 \property QFontComboBox::currentFont
409 \brief the currently selected font
410
411 \sa currentFontChanged(), currentIndex, currentText
412*/
413QFont QFontComboBox::currentFont() const
414{
415 Q_D(const QFontComboBox);
416 return d->currentFont;
417}
418
419void QFontComboBox::setCurrentFont(const QFont &font)
420{
421 Q_D(QFontComboBox);
422 if (font != d->currentFont) {
423 d->currentFont = font;
424 emit currentFontChanged(d->currentFont);
425 d->_q_updateModel();
426 }
427}
428
429/*!
430 \fn QFontComboBox::currentFontChanged(const QFont &font)
431
432 This signal is emitted whenever the current font changes, with
433 the new \a font.
434
435 \sa currentFont
436*/
437
438/*!
439 \reimp
440*/
441bool QFontComboBox::event(QEvent *e)
442{
443 if (e->type() == QEvent::Resize) {
444 QListView *lview = qobject_cast<QListView*>(view());
445 if (lview)
446 lview->window()->setFixedWidth(width() * 5 / 3);
447 }
448 return QComboBox::event(e);
449}
450
451/*!
452 \reimp
453*/
454QSize QFontComboBox::sizeHint() const
455{
456 QSize sz = QComboBox::sizeHint();
457 QFontMetrics fm(font());
458 sz.setWidth(fm.width(QLatin1Char('m'))*14);
459 return sz;
460}
461
462QT_END_NAMESPACE
463
464#include "qfontcombobox.moc"
465#include "moc_qfontcombobox.cpp"
466
467#endif // QT_NO_FONTCOMBOBOX
Note: See TracBrowser for help on using the repository browser.