1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qwindowdefs.h"
41 #include "qfontdialog.h"
42
43 #include "qfontdialog_p.h"
44
45 #include <qapplication.h>
46 #include <qcheckbox.h>
47 #include <qcombobox.h>
48 #include <qevent.h>
49 #include <qfontdatabase.h>
50 #include <qgroupbox.h>
51 #include <qlabel.h>
52 #include <qlayout.h>
53 #include <qlineedit.h>
54 #include <qpushbutton.h>
55 #include <qstyle.h>
56 #include <qdialogbuttonbox.h>
57 #include <qheaderview.h>
58 #include <qlistview.h>
59 #include <qstringlistmodel.h>
60 #include <qvalidator.h>
61 #include <private/qdialog_p.h>
62 #include <private/qfont_p.h>
63
64 QT_BEGIN_NAMESPACE
65
66 class QFontListView : public QListView
67 {
68 Q_OBJECT
69 public:
70 QFontListView(QWidget *parent);
model() const71 inline QStringListModel *model() const {
72 return static_cast<QStringListModel *>(QListView::model());
73 }
setCurrentItem(int item)74 inline void setCurrentItem(int item) {
75 QListView::setCurrentIndex(static_cast<QAbstractListModel*>(model())->index(item));
76 }
currentItem() const77 inline int currentItem() const {
78 return QListView::currentIndex().row();
79 }
count() const80 inline int count() const {
81 return model()->rowCount();
82 }
currentText() const83 inline QString currentText() const {
84 int row = QListView::currentIndex().row();
85 return row < 0 ? QString() : model()->stringList().at(row);
86 }
currentChanged(const QModelIndex & current,const QModelIndex & previous)87 void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override {
88 QListView::currentChanged(current, previous);
89 if (current.isValid())
90 emit highlighted(current.row());
91 }
text(int i) const92 QString text(int i) const {
93 return model()->stringList().at(i);
94 }
95 signals:
96 void highlighted(int);
97 };
98
QFontListView(QWidget * parent)99 QFontListView::QFontListView(QWidget *parent)
100 : QListView(parent)
101 {
102 setModel(new QStringListModel(parent));
103 setEditTriggers(NoEditTriggers);
104 }
105
106 static const Qt::WindowFlags DefaultWindowFlags =
107 Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
108
QFontDialogPrivate()109 QFontDialogPrivate::QFontDialogPrivate()
110 : writingSystem(QFontDatabase::Any),
111 options(QFontDialogOptions::create())
112 {
113 }
114
~QFontDialogPrivate()115 QFontDialogPrivate::~QFontDialogPrivate()
116 {
117 }
118
119 /*!
120 \class QFontDialog
121 \ingroup standard-dialogs
122 \inmodule QtWidgets
123
124 \brief The QFontDialog class provides a dialog widget for selecting a font.
125
126 A font dialog is created through one of the static getFont()
127 functions.
128
129 Examples:
130
131 \snippet code/src_gui_dialogs_qfontdialog.cpp 0
132
133 The dialog can also be used to set a widget's font directly:
134 \snippet code/src_gui_dialogs_qfontdialog.cpp 1
135 If the user clicks OK the font they chose will be used for myWidget,
136 and if they click Cancel the original font is used.
137
138 \image fusion-fontdialog.png A font dialog in the Fusion widget style.
139
140 \sa QFont, QFontInfo, QFontMetrics, QColorDialog, QFileDialog,
141 {Standard Dialogs Example}
142 */
143
144 /*!
145 \since 4.5
146
147 Constructs a standard font dialog.
148
149 Use setCurrentFont() to set the initial font attributes.
150
151 The \a parent parameter is passed to the QDialog constructor.
152
153 \sa getFont()
154 */
QFontDialog(QWidget * parent)155 QFontDialog::QFontDialog(QWidget *parent)
156 : QDialog(*new QFontDialogPrivate, parent, DefaultWindowFlags)
157 {
158 Q_D(QFontDialog);
159 d->init();
160 }
161
162 /*!
163 \since 4.5
164
165 Constructs a standard font dialog with the given \a parent and specified
166 \a initial font.
167 */
QFontDialog(const QFont & initial,QWidget * parent)168 QFontDialog::QFontDialog(const QFont &initial, QWidget *parent)
169 : QFontDialog(parent)
170 {
171 setCurrentFont(initial);
172 }
173
init()174 void QFontDialogPrivate::init()
175 {
176 Q_Q(QFontDialog);
177
178 q->setSizeGripEnabled(true);
179 q->setWindowTitle(QFontDialog::tr("Select Font"));
180
181 // grid
182 familyEdit = new QLineEdit(q);
183 familyEdit->setReadOnly(true);
184 familyList = new QFontListView(q);
185 familyEdit->setFocusProxy(familyList);
186
187 familyAccel = new QLabel(q);
188 #ifndef QT_NO_SHORTCUT
189 familyAccel->setBuddy(familyList);
190 #endif
191 familyAccel->setIndent(2);
192
193 styleEdit = new QLineEdit(q);
194 styleEdit->setReadOnly(true);
195 styleList = new QFontListView(q);
196 styleEdit->setFocusProxy(styleList);
197
198 styleAccel = new QLabel(q);
199 #ifndef QT_NO_SHORTCUT
200 styleAccel->setBuddy(styleList);
201 #endif
202 styleAccel->setIndent(2);
203
204 sizeEdit = new QLineEdit(q);
205 sizeEdit->setFocusPolicy(Qt::ClickFocus);
206 QIntValidator *validator = new QIntValidator(1, 512, q);
207 sizeEdit->setValidator(validator);
208 sizeList = new QFontListView(q);
209
210 sizeAccel = new QLabel(q);
211 #ifndef QT_NO_SHORTCUT
212 sizeAccel->setBuddy(sizeEdit);
213 #endif
214 sizeAccel->setIndent(2);
215
216 // effects box
217 effects = new QGroupBox(q);
218 QVBoxLayout *vbox = new QVBoxLayout(effects);
219 strikeout = new QCheckBox(effects);
220 vbox->addWidget(strikeout);
221 underline = new QCheckBox(effects);
222 vbox->addWidget(underline);
223
224 sample = new QGroupBox(q);
225 QHBoxLayout *hbox = new QHBoxLayout(sample);
226 sampleEdit = new QLineEdit(sample);
227 sampleEdit->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
228 sampleEdit->setAlignment(Qt::AlignCenter);
229 // Note that the sample text is *not* translated with tr(), as the
230 // characters used depend on the charset encoding.
231 sampleEdit->setText(QLatin1String("AaBbYyZz"));
232 hbox->addWidget(sampleEdit);
233
234 writingSystemCombo = new QComboBox(q);
235
236 writingSystemAccel = new QLabel(q);
237 #ifndef QT_NO_SHORTCUT
238 writingSystemAccel->setBuddy(writingSystemCombo);
239 #endif
240 writingSystemAccel->setIndent(2);
241
242 size = 0;
243 smoothScalable = false;
244
245 QObject::connect(writingSystemCombo, SIGNAL(activated(int)), q, SLOT(_q_writingSystemHighlighted(int)));
246 QObject::connect(familyList, SIGNAL(highlighted(int)), q, SLOT(_q_familyHighlighted(int)));
247 QObject::connect(styleList, SIGNAL(highlighted(int)), q, SLOT(_q_styleHighlighted(int)));
248 QObject::connect(sizeList, SIGNAL(highlighted(int)), q, SLOT(_q_sizeHighlighted(int)));
249 QObject::connect(sizeEdit, SIGNAL(textChanged(QString)), q, SLOT(_q_sizeChanged(QString)));
250
251 QObject::connect(strikeout, SIGNAL(clicked()), q, SLOT(_q_updateSample()));
252 QObject::connect(underline, SIGNAL(clicked()), q, SLOT(_q_updateSample()));
253
254 for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
255 QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i);
256 QString writingSystemName = QFontDatabase::writingSystemName(ws);
257 if (writingSystemName.isEmpty())
258 break;
259 writingSystemCombo->addItem(writingSystemName);
260 }
261
262 updateFamilies();
263 if (familyList->count() != 0) {
264 familyList->setCurrentItem(0);
265 sizeList->setCurrentItem(0);
266 }
267
268 // grid layout
269 QGridLayout *mainGrid = new QGridLayout(q);
270
271 int spacing = mainGrid->spacing();
272 if (spacing >= 0) { // uniform spacing
273 mainGrid->setSpacing(0);
274
275 mainGrid->setColumnMinimumWidth(1, spacing);
276 mainGrid->setColumnMinimumWidth(3, spacing);
277
278 int margin = 0;
279 mainGrid->getContentsMargins(nullptr, nullptr, nullptr, &margin);
280
281 mainGrid->setRowMinimumHeight(3, margin);
282 mainGrid->setRowMinimumHeight(6, 2);
283 mainGrid->setRowMinimumHeight(8, margin);
284 }
285
286 mainGrid->addWidget(familyAccel, 0, 0);
287 mainGrid->addWidget(familyEdit, 1, 0);
288 mainGrid->addWidget(familyList, 2, 0);
289
290 mainGrid->addWidget(styleAccel, 0, 2);
291 mainGrid->addWidget(styleEdit, 1, 2);
292 mainGrid->addWidget(styleList, 2, 2);
293
294 mainGrid->addWidget(sizeAccel, 0, 4);
295 mainGrid->addWidget(sizeEdit, 1, 4);
296 mainGrid->addWidget(sizeList, 2, 4);
297
298 mainGrid->setColumnStretch(0, 38);
299 mainGrid->setColumnStretch(2, 24);
300 mainGrid->setColumnStretch(4, 10);
301
302 mainGrid->addWidget(effects, 4, 0);
303
304 mainGrid->addWidget(sample, 4, 2, 4, 3);
305
306 mainGrid->addWidget(writingSystemAccel, 5, 0);
307 mainGrid->addWidget(writingSystemCombo, 7, 0);
308
309 buttonBox = new QDialogButtonBox(q);
310 mainGrid->addWidget(buttonBox, 9, 0, 1, 5);
311
312 QPushButton *button
313 = static_cast<QPushButton *>(buttonBox->addButton(QDialogButtonBox::Ok));
314 QObject::connect(buttonBox, SIGNAL(accepted()), q, SLOT(accept()));
315 button->setDefault(true);
316
317 buttonBox->addButton(QDialogButtonBox::Cancel);
318 QObject::connect(buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
319
320 q->resize(500, 360);
321
322 sizeEdit->installEventFilter(q);
323 familyList->installEventFilter(q);
324 styleList->installEventFilter(q);
325 sizeList->installEventFilter(q);
326
327 familyList->setFocus();
328 retranslateStrings();
329 sampleEdit->setObjectName(QLatin1String("qt_fontDialog_sampleEdit"));
330 }
331
332 /*!
333 \internal
334 Destroys the font dialog and frees up its storage.
335 */
336
~QFontDialog()337 QFontDialog::~QFontDialog()
338 {
339 }
340
341 /*!
342 Executes a modal font dialog and returns a font.
343
344 If the user clicks \uicontrol OK, the selected font is returned. If the user
345 clicks \uicontrol Cancel, the \a initial font is returned.
346
347 The dialog is constructed with the given \a parent and the options specified
348 in \a options. \a title is shown as the window title of the dialog and \a
349 initial is the initially selected font. If the \a ok parameter is not-null,
350 the value it refers to is set to true if the user clicks \uicontrol OK, and set to
351 false if the user clicks \uicontrol Cancel.
352
353 Examples:
354 \snippet code/src_gui_dialogs_qfontdialog.cpp 2
355
356 The dialog can also be used to set a widget's font directly:
357 \snippet code/src_gui_dialogs_qfontdialog.cpp 3
358 In this example, if the user clicks OK the font they chose will be
359 used, and if they click Cancel the original font is used.
360
361 \warning Do not delete \a parent during the execution of the dialog.
362 If you want to do this, you should create the dialog
363 yourself using one of the QFontDialog constructors.
364 */
getFont(bool * ok,const QFont & initial,QWidget * parent,const QString & title,FontDialogOptions options)365 QFont QFontDialog::getFont(bool *ok, const QFont &initial, QWidget *parent, const QString &title,
366 FontDialogOptions options)
367 {
368 return QFontDialogPrivate::getFont(ok, initial, parent, title, options);
369 }
370
371 /*!
372 \overload
373
374 Executes a modal font dialog and returns a font.
375
376 If the user clicks \uicontrol OK, the selected font is returned. If the user
377 clicks \uicontrol Cancel, the Qt default font is returned.
378
379 The dialog is constructed with the given \a parent.
380 If the \a ok parameter is not-null, the value it refers to is set
381 to true if the user clicks \uicontrol OK, and false if the user clicks
382 \uicontrol Cancel.
383
384 Example:
385 \snippet code/src_gui_dialogs_qfontdialog.cpp 4
386
387 \warning Do not delete \a parent during the execution of the dialog.
388 If you want to do this, you should create the dialog
389 yourself using one of the QFontDialog constructors.
390 */
getFont(bool * ok,QWidget * parent)391 QFont QFontDialog::getFont(bool *ok, QWidget *parent)
392 {
393 QFont initial;
394 return QFontDialogPrivate::getFont(ok, initial, parent, QString(), { });
395 }
396
getFont(bool * ok,const QFont & initial,QWidget * parent,const QString & title,QFontDialog::FontDialogOptions options)397 QFont QFontDialogPrivate::getFont(bool *ok, const QFont &initial, QWidget *parent,
398 const QString &title, QFontDialog::FontDialogOptions options)
399 {
400 QFontDialog dlg(parent);
401 dlg.setOptions(options);
402 dlg.setCurrentFont(initial);
403 if (!title.isEmpty())
404 dlg.setWindowTitle(title);
405
406 int ret = (dlg.exec() || (options & QFontDialog::NoButtons));
407 if (ok)
408 *ok = !!ret;
409 if (ret) {
410 return dlg.selectedFont();
411 } else {
412 return initial;
413 }
414 }
415
416 /*!
417 \internal
418 An event filter to make the Up, Down, PageUp and PageDown keys work
419 correctly in the line edits. The source of the event is the object
420 \a o and the event is \a e.
421 */
422
eventFilter(QObject * o,QEvent * e)423 bool QFontDialog::eventFilter(QObject *o , QEvent *e)
424 {
425 Q_D(QFontDialog);
426 if (e->type() == QEvent::KeyPress) {
427 QKeyEvent *k = (QKeyEvent *)e;
428 if (o == d->sizeEdit &&
429 (k->key() == Qt::Key_Up ||
430 k->key() == Qt::Key_Down ||
431 k->key() == Qt::Key_PageUp ||
432 k->key() == Qt::Key_PageDown)) {
433
434 int ci = d->sizeList->currentItem();
435 QCoreApplication::sendEvent(d->sizeList, k);
436
437 if (ci != d->sizeList->currentItem()
438 && style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, this))
439 d->sizeEdit->selectAll();
440 return true;
441 } else if ((o == d->familyList || o == d->styleList) &&
442 (k->key() == Qt::Key_Return || k->key() == Qt::Key_Enter)) {
443 k->accept();
444 accept();
445 return true;
446 }
447 } else if (e->type() == QEvent::FocusIn
448 && style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, this)) {
449 if (o == d->familyList)
450 d->familyEdit->selectAll();
451 else if (o == d->styleList)
452 d->styleEdit->selectAll();
453 else if (o == d->sizeList)
454 d->sizeEdit->selectAll();
455 } else if (e->type() == QEvent::MouseButtonPress && o == d->sizeList) {
456 d->sizeEdit->setFocus();
457 }
458 return QDialog::eventFilter(o, e);
459 }
460
initHelper(QPlatformDialogHelper * h)461 void QFontDialogPrivate::initHelper(QPlatformDialogHelper *h)
462 {
463 QFontDialog *d = q_func();
464 QObject::connect(h, SIGNAL(currentFontChanged(QFont)), d, SIGNAL(currentFontChanged(QFont)));
465 QObject::connect(h, SIGNAL(fontSelected(QFont)), d, SIGNAL(fontSelected(QFont)));
466 static_cast<QPlatformFontDialogHelper *>(h)->setOptions(options);
467 }
468
helperPrepareShow(QPlatformDialogHelper *)469 void QFontDialogPrivate::helperPrepareShow(QPlatformDialogHelper *)
470 {
471 options->setWindowTitle(q_func()->windowTitle());
472 }
473
474 /*
475 Updates the contents of the "font family" list box. This
476 function can be reimplemented if you have special requirements.
477 */
478
updateFamilies()479 void QFontDialogPrivate::updateFamilies()
480 {
481 Q_Q(QFontDialog);
482
483 enum match_t { MATCH_NONE = 0, MATCH_LAST_RESORT = 1, MATCH_APP = 2, MATCH_FAMILY = 3 };
484
485 const QFontDialog::FontDialogOptions scalableMask = (QFontDialog::ScalableFonts | QFontDialog::NonScalableFonts);
486 const QFontDialog::FontDialogOptions spacingMask = (QFontDialog::ProportionalFonts | QFontDialog::MonospacedFonts);
487 const QFontDialog::FontDialogOptions options = q->options();
488
489 QFontDatabase fdb;
490
491 QStringList familyNames;
492 const auto families = fdb.families(writingSystem);
493 for (const QString &family : families) {
494 if (fdb.isPrivateFamily(family))
495 continue;
496
497 if ((options & scalableMask) && (options & scalableMask) != scalableMask) {
498 if (bool(options & QFontDialog::ScalableFonts) != fdb.isSmoothlyScalable(family))
499 continue;
500 }
501 if ((options & spacingMask) && (options & spacingMask) != spacingMask) {
502 if (bool(options & QFontDialog::MonospacedFonts) != fdb.isFixedPitch(family))
503 continue;
504 }
505 familyNames << family;
506 }
507
508 familyList->model()->setStringList(familyNames);
509
510 QString foundryName1, familyName1, foundryName2, familyName2;
511 int bestFamilyMatch = -1;
512 match_t bestFamilyType = MATCH_NONE;
513
514 QFont f;
515
516 // ##### do the right thing for a list of family names in the font.
517 QFontDatabase::parseFontName(family, foundryName1, familyName1);
518
519 QStringList::const_iterator it = familyNames.constBegin();
520 int i = 0;
521 for(; it != familyNames.constEnd(); ++it, ++i) {
522 QFontDatabase::parseFontName(*it, foundryName2, familyName2);
523
524 //try to match...
525 if (familyName1 == familyName2) {
526 bestFamilyType = MATCH_FAMILY;
527 if (foundryName1 == foundryName2) {
528 bestFamilyMatch = i;
529 break;
530 }
531 if (bestFamilyMatch < MATCH_FAMILY)
532 bestFamilyMatch = i;
533 }
534
535 //and try some fall backs
536 match_t type = MATCH_NONE;
537 if (bestFamilyType <= MATCH_NONE && familyName2 == QStringLiteral("helvetica"))
538 type = MATCH_LAST_RESORT;
539 if (bestFamilyType <= MATCH_LAST_RESORT && familyName2 == f.family())
540 type = MATCH_APP;
541 // ### add fallback for writingSystem
542 if (type != MATCH_NONE) {
543 bestFamilyType = type;
544 bestFamilyMatch = i;
545 }
546 }
547
548 if (i != -1 && bestFamilyType != MATCH_NONE)
549 familyList->setCurrentItem(bestFamilyMatch);
550 else
551 familyList->setCurrentItem(0);
552 familyEdit->setText(familyList->currentText());
553 if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
554 && familyList->hasFocus())
555 familyEdit->selectAll();
556
557 updateStyles();
558 }
559
560 /*
561 Updates the contents of the "font style" list box. This
562 function can be reimplemented if you have special requirements.
563 */
updateStyles()564 void QFontDialogPrivate::updateStyles()
565 {
566 Q_Q(QFontDialog);
567 QStringList styles = fdb.styles(familyList->currentText());
568 styleList->model()->setStringList(styles);
569
570 if (styles.isEmpty()) {
571 styleEdit->clear();
572 smoothScalable = false;
573 } else {
574 if (!style.isEmpty()) {
575 bool found = false;
576 bool first = true;
577 QString cstyle = style;
578
579 redo:
580 for (int i = 0; i < (int)styleList->count(); i++) {
581 if (cstyle == styleList->text(i)) {
582 styleList->setCurrentItem(i);
583 found = true;
584 break;
585 }
586 }
587 if (!found && first) {
588 if (cstyle.contains(QLatin1String("Italic"))) {
589 cstyle.replace(QLatin1String("Italic"), QLatin1String("Oblique"));
590 first = false;
591 goto redo;
592 } else if (cstyle.contains(QLatin1String("Oblique"))) {
593 cstyle.replace(QLatin1String("Oblique"), QLatin1String("Italic"));
594 first = false;
595 goto redo;
596 }
597 }
598 if (!found)
599 styleList->setCurrentItem(0);
600 } else {
601 styleList->setCurrentItem(0);
602 }
603
604 styleEdit->setText(styleList->currentText());
605 if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
606 && styleList->hasFocus())
607 styleEdit->selectAll();
608
609 smoothScalable = fdb.isSmoothlyScalable(familyList->currentText(), styleList->currentText());
610 }
611
612 updateSizes();
613 }
614
615 /*!
616 \internal
617 Updates the contents of the "font size" list box. This
618 function can be reimplemented if you have special requirements.
619 */
620
updateSizes()621 void QFontDialogPrivate::updateSizes()
622 {
623 Q_Q(QFontDialog);
624
625 if (!familyList->currentText().isEmpty()) {
626 QList<int> sizes = fdb.pointSizes(familyList->currentText(), styleList->currentText());
627
628 int i = 0;
629 int current = -1;
630 QStringList str_sizes;
631 str_sizes.reserve(sizes.size());
632 for(QList<int>::const_iterator it = sizes.constBegin(); it != sizes.constEnd(); ++it) {
633 str_sizes.append(QString::number(*it));
634 if (current == -1 && *it == size)
635 current = i;
636 ++i;
637 }
638 sizeList->model()->setStringList(str_sizes);
639 if (current != -1)
640 sizeList->setCurrentItem(current);
641
642 const QSignalBlocker blocker(sizeEdit);
643 sizeEdit->setText((smoothScalable ? QString::number(size) : sizeList->currentText()));
644 if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
645 && sizeList->hasFocus())
646 sizeEdit->selectAll();
647 } else {
648 sizeEdit->clear();
649 }
650
651 _q_updateSample();
652 }
653
_q_updateSample()654 void QFontDialogPrivate::_q_updateSample()
655 {
656 // compute new font
657 int pSize = sizeEdit->text().toInt();
658 QFont newFont(fdb.font(familyList->currentText(), style, pSize));
659 newFont.setStrikeOut(strikeout->isChecked());
660 newFont.setUnderline(underline->isChecked());
661
662 if (familyList->currentText().isEmpty())
663 sampleEdit->clear();
664
665 updateSampleFont(newFont);
666 }
667
updateSampleFont(const QFont & newFont)668 void QFontDialogPrivate::updateSampleFont(const QFont &newFont)
669 {
670 Q_Q(QFontDialog);
671 if (newFont != sampleEdit->font()) {
672 sampleEdit->setFont(newFont);
673 emit q->currentFontChanged(newFont);
674 }
675 }
676
677 /*!
678 \internal
679 */
_q_writingSystemHighlighted(int index)680 void QFontDialogPrivate::_q_writingSystemHighlighted(int index)
681 {
682 writingSystem = QFontDatabase::WritingSystem(index);
683 sampleEdit->setText(QFontDatabase::writingSystemSample(writingSystem));
684 updateFamilies();
685 }
686
687 /*!
688 \internal
689 */
_q_familyHighlighted(int i)690 void QFontDialogPrivate::_q_familyHighlighted(int i)
691 {
692 Q_Q(QFontDialog);
693 family = familyList->text(i);
694 familyEdit->setText(family);
695 if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
696 && familyList->hasFocus())
697 familyEdit->selectAll();
698
699 updateStyles();
700 }
701
702
703 /*!
704 \internal
705 */
706
_q_styleHighlighted(int index)707 void QFontDialogPrivate::_q_styleHighlighted(int index)
708 {
709 Q_Q(QFontDialog);
710 QString s = styleList->text(index);
711 styleEdit->setText(s);
712 if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
713 && styleList->hasFocus())
714 styleEdit->selectAll();
715
716 style = s;
717
718 updateSizes();
719 }
720
721
722 /*!
723 \internal
724 */
725
_q_sizeHighlighted(int index)726 void QFontDialogPrivate::_q_sizeHighlighted(int index)
727 {
728 Q_Q(QFontDialog);
729 QString s = sizeList->text(index);
730 sizeEdit->setText(s);
731 if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
732 && sizeEdit->hasFocus())
733 sizeEdit->selectAll();
734
735 size = s.toInt();
736 _q_updateSample();
737 }
738
739 /*!
740 \internal
741 This slot is called if the user changes the font size.
742 The size is passed in the \a s argument as a \e string.
743 */
744
_q_sizeChanged(const QString & s)745 void QFontDialogPrivate::_q_sizeChanged(const QString &s)
746 {
747 // no need to check if the conversion is valid, since we have an QIntValidator in the size edit
748 int size = s.toInt();
749 if (this->size == size)
750 return;
751
752 this->size = size;
753 if (sizeList->count() != 0) {
754 int i;
755 for (i = 0; i < sizeList->count() - 1; i++) {
756 if (sizeList->text(i).toInt() >= this->size)
757 break;
758 }
759 const QSignalBlocker blocker(sizeList);
760 if (sizeList->text(i).toInt() == this->size)
761 sizeList->setCurrentItem(i);
762 else
763 sizeList->clearSelection();
764 }
765 _q_updateSample();
766 }
767
retranslateStrings()768 void QFontDialogPrivate::retranslateStrings()
769 {
770 familyAccel->setText(QFontDialog::tr("&Font"));
771 styleAccel->setText(QFontDialog::tr("Font st&yle"));
772 sizeAccel->setText(QFontDialog::tr("&Size"));
773 effects->setTitle(QFontDialog::tr("Effects"));
774 strikeout->setText(QFontDialog::tr("Stri&keout"));
775 underline->setText(QFontDialog::tr("&Underline"));
776 sample->setTitle(QFontDialog::tr("Sample"));
777 writingSystemAccel->setText(QFontDialog::tr("Wr&iting System"));
778 }
779
780 /*!
781 \reimp
782 */
changeEvent(QEvent * e)783 void QFontDialog::changeEvent(QEvent *e)
784 {
785 Q_D(QFontDialog);
786 if (e->type() == QEvent::LanguageChange) {
787 d->retranslateStrings();
788 }
789 QDialog::changeEvent(e);
790 }
791
792 /*!
793 \since 4.5
794
795 \property QFontDialog::currentFont
796 \brief the current font of the dialog.
797 */
798
799 /*!
800 \since 4.5
801
802 Sets the font highlighted in the QFontDialog to the given \a font.
803
804 \sa selectedFont()
805 */
setCurrentFont(const QFont & font)806 void QFontDialog::setCurrentFont(const QFont &font)
807 {
808 Q_D(QFontDialog);
809 d->family = font.family();
810 d->style = d->fdb.styleString(font);
811 d->size = font.pointSize();
812 if (d->size == -1) {
813 QFontInfo fi(font);
814 d->size = fi.pointSize();
815 }
816 d->strikeout->setChecked(font.strikeOut());
817 d->underline->setChecked(font.underline());
818 d->updateFamilies();
819 if (QPlatformFontDialogHelper *helper = d->platformFontDialogHelper())
820 helper->setCurrentFont(font);
821 }
822
823 /*!
824 \since 4.5
825
826 Returns the current font.
827
828 \sa selectedFont()
829 */
currentFont() const830 QFont QFontDialog::currentFont() const
831 {
832 Q_D(const QFontDialog);
833 if (const QPlatformFontDialogHelper *helper = d->platformFontDialogHelper())
834 return helper->currentFont();
835 return d->sampleEdit->font();
836 }
837
838 /*!
839 Returns the font that the user selected by clicking the \uicontrol{OK}
840 or equivalent button.
841
842 \note This font is not always the same as the font held by the
843 \l currentFont property since the user can choose different fonts
844 before finally selecting the one to use.
845 */
selectedFont() const846 QFont QFontDialog::selectedFont() const
847 {
848 Q_D(const QFontDialog);
849 return d->selectedFont;
850 }
851
852 /*!
853 \enum QFontDialog::FontDialogOption
854 \since 4.5
855
856 This enum specifies various options that affect the look and feel
857 of a font dialog.
858
859 For instance, it allows to specify which type of font should be
860 displayed. If none are specified all fonts available will be listed.
861
862 Note that the font filtering options might not be supported on some
863 platforms (e.g. Mac). They are always supported by the non native
864 dialog (used on Windows or Linux).
865
866 \value NoButtons Don't display \uicontrol{OK} and \uicontrol{Cancel} buttons. (Useful for "live dialogs".)
867 \value DontUseNativeDialog Use Qt's standard font dialog on the Mac instead of Apple's
868 native font panel.
869 \value ScalableFonts Show scalable fonts
870 \value NonScalableFonts Show non scalable fonts
871 \value MonospacedFonts Show monospaced fonts
872 \value ProportionalFonts Show proportional fonts
873
874 \sa options, setOption(), testOption()
875 */
876
877 /*!
878 Sets the given \a option to be enabled if \a on is true;
879 otherwise, clears the given \a option.
880
881 \sa options, testOption()
882 */
setOption(FontDialogOption option,bool on)883 void QFontDialog::setOption(FontDialogOption option, bool on)
884 {
885 const QFontDialog::FontDialogOptions previousOptions = options();
886 if (!(previousOptions & option) != !on)
887 setOptions(previousOptions ^ option);
888 }
889
890 /*!
891 Returns \c true if the given \a option is enabled; otherwise, returns
892 false.
893
894 \sa options, setOption()
895 */
testOption(FontDialogOption option) const896 bool QFontDialog::testOption(FontDialogOption option) const
897 {
898 Q_D(const QFontDialog);
899 return d->options->testOption(static_cast<QFontDialogOptions::FontDialogOption>(option));
900 }
901
902 /*!
903 \property QFontDialog::options
904 \brief the various options that affect the look and feel of the dialog
905 \since 4.5
906
907 By default, all options are disabled.
908
909 Options should be set before showing the dialog. Setting them while the
910 dialog is visible is not guaranteed to have an immediate effect on the
911 dialog (depending on the option and on the platform).
912
913 \sa setOption(), testOption()
914 */
setOptions(FontDialogOptions options)915 void QFontDialog::setOptions(FontDialogOptions options)
916 {
917 Q_D(QFontDialog);
918
919 if (QFontDialog::options() == options)
920 return;
921
922 d->options->setOptions(QFontDialogOptions::FontDialogOptions(int(options)));
923 d->buttonBox->setVisible(!(options & NoButtons));
924 }
925
options() const926 QFontDialog::FontDialogOptions QFontDialog::options() const
927 {
928 Q_D(const QFontDialog);
929 return QFontDialog::FontDialogOptions(int(d->options->options()));
930 }
931
932 /*!
933 \since 4.5
934
935 Opens the dialog and connects its fontSelected() signal to the slot specified
936 by \a receiver and \a member.
937
938 The signal will be disconnected from the slot when the dialog is closed.
939 */
open(QObject * receiver,const char * member)940 void QFontDialog::open(QObject *receiver, const char *member)
941 {
942 Q_D(QFontDialog);
943 connect(this, SIGNAL(fontSelected(QFont)), receiver, member);
944 d->receiverToDisconnectOnClose = receiver;
945 d->memberToDisconnectOnClose = member;
946 QDialog::open();
947 }
948
949 /*!
950 \since 4.5
951
952 \fn void QFontDialog::currentFontChanged(const QFont &font)
953
954 This signal is emitted when the current font is changed. The new font is
955 specified in \a font.
956
957 The signal is emitted while a user is selecting a font. Ultimately, the
958 chosen font may differ from the font currently selected.
959
960 \sa currentFont, fontSelected(), selectedFont()
961 */
962
963 /*!
964 \since 4.5
965
966 \fn void QFontDialog::fontSelected(const QFont &font)
967
968 This signal is emitted when a font has been selected. The selected font is
969 specified in \a font.
970
971 The signal is only emitted when a user has chosen the final font to be
972 used. It is not emitted while the user is changing the current font in the
973 font dialog.
974
975 \sa selectedFont(), currentFontChanged(), currentFont
976 */
977
978 /*!
979 \reimp
980 */
setVisible(bool visible)981 void QFontDialog::setVisible(bool visible)
982 {
983 if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) != visible)
984 return;
985 Q_D(QFontDialog);
986 if (d->canBeNativeDialog())
987 d->setNativeDialogVisible(visible);
988 if (d->nativeDialogInUse) {
989 // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
990 // updates the state correctly, but skips showing the non-native version:
991 setAttribute(Qt::WA_DontShowOnScreen, true);
992 } else {
993 d->nativeDialogInUse = false;
994 setAttribute(Qt::WA_DontShowOnScreen, false);
995 }
996 QDialog::setVisible(visible);
997 }
998
999 /*!
1000 Closes the dialog and sets its result code to \a result. If this dialog
1001 is shown with exec(), done() causes the local event loop to finish,
1002 and exec() to return \a result.
1003
1004 \sa QDialog::done()
1005 */
done(int result)1006 void QFontDialog::done(int result)
1007 {
1008 Q_D(QFontDialog);
1009 if (result == Accepted) {
1010 // We check if this is the same font we had before, if so we emit currentFontChanged
1011 QFont selectedFont = currentFont();
1012 if(selectedFont != d->selectedFont)
1013 emit(currentFontChanged(selectedFont));
1014 d->selectedFont = selectedFont;
1015 emit fontSelected(d->selectedFont);
1016 } else
1017 d->selectedFont = QFont();
1018 if (d->receiverToDisconnectOnClose) {
1019 disconnect(this, SIGNAL(fontSelected(QFont)),
1020 d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
1021 d->receiverToDisconnectOnClose = nullptr;
1022 }
1023 d->memberToDisconnectOnClose.clear();
1024 QDialog::done(result);
1025 }
1026
canBeNativeDialog() const1027 bool QFontDialogPrivate::canBeNativeDialog() const
1028 {
1029 // Don't use Q_Q here! This function is called from ~QDialog,
1030 // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()).
1031 const QDialog * const q = static_cast<const QDialog*>(q_ptr);
1032 if (nativeDialogInUse)
1033 return true;
1034 if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
1035 || q->testAttribute(Qt::WA_DontShowOnScreen)
1036 || (options->options() & QFontDialog::DontUseNativeDialog)) {
1037 return false;
1038 }
1039
1040 QLatin1String staticName(QFontDialog::staticMetaObject.className());
1041 QLatin1String dynamicName(q->metaObject()->className());
1042 return (staticName == dynamicName);
1043 }
1044
1045 QT_END_NAMESPACE
1046
1047 #include "qfontdialog.moc"
1048 #include "moc_qfontdialog.cpp"
1049