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

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 14.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** 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 have questions regarding the use of this file, please contact
37** Nokia 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.height());
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 //we need to block the signals so that the model doesn't emit reset
251 //this prevents the current index from changing
252 //it will be updated just after this
253 ///TODO: we should finda way to avoid blocking signals and have a real update of the model
254 const bool old = m->blockSignals(true);
255 m->setStringList(list);
256 m->blockSignals(old);
257
258 if (list.isEmpty()) {
259 if (currentFont != QFont()) {
260 currentFont = QFont();
261 emit q->currentFontChanged(currentFont);
262 }
263 } else {
264 q->setCurrentIndex(offset);
265 }
266}
267
268
269void QFontComboBoxPrivate::_q_currentChanged(const QString &text)
270{
271 Q_Q(QFontComboBox);
272 if (currentFont.family() != text) {
273 currentFont.setFamily(text);
274 emit q->currentFontChanged(currentFont);
275 }
276}
277
278/*!
279 \class QFontComboBox
280 \brief The QFontComboBox widget is a combobox that lets the user
281 select a font family.
282
283 \since 4.2
284 \ingroup basicwidgets
285
286 The combobox is populated with an alphabetized list of font
287 family names, such as Arial, Helvetica, and Times New Roman.
288 Family names are displayed using the actual font when possible.
289 For fonts such as Symbol, where the name is not representable in
290 the font itself, a sample of the font is displayed next to the
291 family name.
292
293 QFontComboBox is often used in toolbars, in conjunction with a
294 QComboBox for controlling the font size and two \l{QToolButton}s
295 for bold and italic.
296
297 When the user selects a new font, the currentFontChanged() signal
298 is emitted in addition to currentIndexChanged().
299
300 Call setWritingSystem() to tell QFontComboBox to show only fonts
301 that support a given writing system, and setFontFilters() to
302 filter out certain types of fonts as e.g. non scalable fonts or
303 monospaced fonts.
304
305 \image windowsxp-fontcombobox.png Screenshot of QFontComboBox on Windows XP
306
307 \sa QComboBox, QFont, QFontInfo, QFontMetrics, QFontDatabase, {Character Map Example}
308*/
309
310/*!
311 \fn void QFontComboBox::setWritingSystem(QFontDatabase::WritingSystem script)
312*/
313
314/*!
315 \fn void QFontComboBox::setCurrentFont(const QFont &font);
316*/
317
318/*!
319 Constructs a font combobox with the given \a parent.
320*/
321QFontComboBox::QFontComboBox(QWidget *parent)
322 : QComboBox(*new QFontComboBoxPrivate, parent)
323{
324 Q_D(QFontComboBox);
325 d->currentFont = font();
326 setEditable(true);
327
328 QStringListModel *m = new QStringListModel(this);
329 setModel(m);
330 setItemDelegate(new QFontFamilyDelegate(this));
331 QListView *lview = qobject_cast<QListView*>(view());
332 if (lview)
333 lview->setUniformItemSizes(true);
334 setWritingSystem(QFontDatabase::Any);
335
336 connect(this, SIGNAL(currentIndexChanged(QString)),
337 this, SLOT(_q_currentChanged(QString)));
338
339 connect(qApp, SIGNAL(fontDatabaseChanged()),
340 this, SLOT(_q_updateModel()));
341}
342
343
344/*!
345 Destroys the combobox.
346*/
347QFontComboBox::~QFontComboBox()
348{
349}
350
351/*!
352 \property QFontComboBox::writingSystem
353 \brief the writing system that serves as a filter for the combobox
354
355 If \a script is QFontDatabase::Any (the default), all fonts are
356 listed.
357
358 \sa fontFilters
359*/
360
361void QFontComboBox::setWritingSystem(QFontDatabase::WritingSystem script)
362{
363 Q_D(QFontComboBox);
364 QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(view()->itemDelegate());
365 if (delegate)
366 delegate->writingSystem = script;
367 d->_q_updateModel();
368}
369
370QFontDatabase::WritingSystem QFontComboBox::writingSystem() const
371{
372 QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(view()->itemDelegate());
373 if (delegate)
374 return delegate->writingSystem;
375 return QFontDatabase::Any;
376}
377
378
379/*!
380 \enum QFontComboBox::FontFilter
381
382 This enum can be used to only show certain types of fonts in the font combo box.
383
384 \value AllFonts Show all fonts
385 \value ScalableFonts Show scalable fonts
386 \value NonScalableFonts Show non scalable fonts
387 \value MonospacedFonts Show monospaced fonts
388 \value ProportionalFonts Show proportional fonts
389*/
390
391/*!
392 \property QFontComboBox::fontFilters
393 \brief the filter for the combobox
394
395 By default, all fonts are listed.
396
397 \sa writingSystem
398*/
399void QFontComboBox::setFontFilters(FontFilters filters)
400{
401 Q_D(QFontComboBox);
402 d->filters = filters;
403 d->_q_updateModel();
404}
405
406QFontComboBox::FontFilters QFontComboBox::fontFilters() const
407{
408 Q_D(const QFontComboBox);
409 return d->filters;
410}
411
412/*!
413 \property QFontComboBox::currentFont
414 \brief the currently selected font
415
416 \sa currentFontChanged(), currentIndex, currentText
417*/
418QFont QFontComboBox::currentFont() const
419{
420 Q_D(const QFontComboBox);
421 return d->currentFont;
422}
423
424void QFontComboBox::setCurrentFont(const QFont &font)
425{
426 Q_D(QFontComboBox);
427 if (font != d->currentFont) {
428 d->currentFont = font;
429 d->_q_updateModel();
430 if (d->currentFont == font) { //else the signal has already be emitted by _q_updateModel
431 emit currentFontChanged(d->currentFont);
432 }
433 }
434}
435
436/*!
437 \fn QFontComboBox::currentFontChanged(const QFont &font)
438
439 This signal is emitted whenever the current font changes, with
440 the new \a font.
441
442 \sa currentFont
443*/
444
445/*!
446 \reimp
447*/
448bool QFontComboBox::event(QEvent *e)
449{
450 if (e->type() == QEvent::Resize) {
451 QListView *lview = qobject_cast<QListView*>(view());
452 if (lview)
453 lview->window()->setFixedWidth(width() * 5 / 3);
454 }
455 return QComboBox::event(e);
456}
457
458/*!
459 \reimp
460*/
461QSize QFontComboBox::sizeHint() const
462{
463 QSize sz = QComboBox::sizeHint();
464 QFontMetrics fm(font());
465 sz.setWidth(fm.width(QLatin1Char('m'))*14);
466 return sz;
467}
468
469QT_END_NAMESPACE
470
471#include "qfontcombobox.moc"
472#include "moc_qfontcombobox.cpp"
473
474#endif // QT_NO_FONTCOMBOBOX
Note: See TracBrowser for help on using the repository browser.