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
64QT_BEGIN_NAMESPACE
65
66class QFontListView : public QListView
67{
68 Q_OBJECT
69public:
70 QFontListView(QWidget *parent);
71 inline QStringListModel *model() const {
72 return static_cast<QStringListModel *>(QListView::model());
73 }
74 inline void setCurrentItem(int item) {
75 QListView::setCurrentIndex(static_cast<QAbstractListModel*>(model())->index(row: item));
76 }
77 inline int currentItem() const {
78 return QListView::currentIndex().row();
79 }
80 inline int count() const {
81 return model()->rowCount();
82 }
83 inline QString currentText() const {
84 int row = QListView::currentIndex().row();
85 return row < 0 ? QString() : model()->stringList().at(i: row);
86 }
87 void currentChanged(const QModelIndex &current, const QModelIndex &previous) override {
88 QListView::currentChanged(current, previous);
89 if (current.isValid())
90 emit highlighted(current.row());
91 }
92 QString text(int i) const {
93 return model()->stringList().at(i);
94 }
95signals:
96 void highlighted(int);
97};
98
99QFontListView::QFontListView(QWidget *parent)
100 : QListView(parent)
101{
102 setModel(new QStringListModel(parent));
103 setEditTriggers(NoEditTriggers);
104}
105
106static const Qt::WindowFlags DefaultWindowFlags =
107 Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
108
109QFontDialogPrivate::QFontDialogPrivate()
110 : writingSystem(QFontDatabase::Any),
111 options(QFontDialogOptions::create())
112{
113}
114
115QFontDialogPrivate::~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*/
155QFontDialog::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*/
168QFontDialog::QFontDialog(const QFont &initial, QWidget *parent)
169 : QFontDialog(parent)
170{
171 setCurrentFont(initial);
172}
173
174void QFontDialogPrivate::init()
175{
176 Q_Q(QFontDialog);
177
178 q->setSizeGripEnabled(true);
179 q->setWindowTitle(QFontDialog::tr(s: "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(sender: writingSystemCombo, SIGNAL(activated(int)), receiver: q, SLOT(_q_writingSystemHighlighted(int)));
246 QObject::connect(sender: familyList, SIGNAL(highlighted(int)), receiver: q, SLOT(_q_familyHighlighted(int)));
247 QObject::connect(sender: styleList, SIGNAL(highlighted(int)), receiver: q, SLOT(_q_styleHighlighted(int)));
248 QObject::connect(sender: sizeList, SIGNAL(highlighted(int)), receiver: q, SLOT(_q_sizeHighlighted(int)));
249 QObject::connect(sender: sizeEdit, SIGNAL(textChanged(QString)), receiver: q, SLOT(_q_sizeChanged(QString)));
250
251 QObject::connect(sender: strikeout, SIGNAL(clicked()), receiver: q, SLOT(_q_updateSample()));
252 QObject::connect(sender: underline, SIGNAL(clicked()), receiver: 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(writingSystem: ws);
257 if (writingSystemName.isEmpty())
258 break;
259 writingSystemCombo->addItem(atext: 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(column: 1, minSize: spacing);
276 mainGrid->setColumnMinimumWidth(column: 3, minSize: spacing);
277
278 int margin = 0;
279 mainGrid->getContentsMargins(left: nullptr, top: nullptr, right: nullptr, bottom: &margin);
280
281 mainGrid->setRowMinimumHeight(row: 3, minSize: margin);
282 mainGrid->setRowMinimumHeight(row: 6, minSize: 2);
283 mainGrid->setRowMinimumHeight(row: 8, minSize: margin);
284 }
285
286 mainGrid->addWidget(familyAccel, row: 0, column: 0);
287 mainGrid->addWidget(familyEdit, row: 1, column: 0);
288 mainGrid->addWidget(familyList, row: 2, column: 0);
289
290 mainGrid->addWidget(styleAccel, row: 0, column: 2);
291 mainGrid->addWidget(styleEdit, row: 1, column: 2);
292 mainGrid->addWidget(styleList, row: 2, column: 2);
293
294 mainGrid->addWidget(sizeAccel, row: 0, column: 4);
295 mainGrid->addWidget(sizeEdit, row: 1, column: 4);
296 mainGrid->addWidget(sizeList, row: 2, column: 4);
297
298 mainGrid->setColumnStretch(column: 0, stretch: 38);
299 mainGrid->setColumnStretch(column: 2, stretch: 24);
300 mainGrid->setColumnStretch(column: 4, stretch: 10);
301
302 mainGrid->addWidget(effects, row: 4, column: 0);
303
304 mainGrid->addWidget(sample, row: 4, column: 2, rowSpan: 4, columnSpan: 3);
305
306 mainGrid->addWidget(writingSystemAccel, row: 5, column: 0);
307 mainGrid->addWidget(writingSystemCombo, row: 7, column: 0);
308
309 buttonBox = new QDialogButtonBox(q);
310 mainGrid->addWidget(buttonBox, row: 9, column: 0, rowSpan: 1, columnSpan: 5);
311
312 QPushButton *button
313 = static_cast<QPushButton *>(buttonBox->addButton(button: QDialogButtonBox::Ok));
314 QObject::connect(sender: buttonBox, SIGNAL(accepted()), receiver: q, SLOT(accept()));
315 button->setDefault(true);
316
317 buttonBox->addButton(button: QDialogButtonBox::Cancel);
318 QObject::connect(sender: buttonBox, SIGNAL(rejected()), receiver: q, SLOT(reject()));
319
320 q->resize(w: 500, h: 360);
321
322 sizeEdit->installEventFilter(filterObj: q);
323 familyList->installEventFilter(filterObj: q);
324 styleList->installEventFilter(filterObj: q);
325 sizeList->installEventFilter(filterObj: 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
337QFontDialog::~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*/
365QFont 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*/
391QFont QFontDialog::getFont(bool *ok, QWidget *parent)
392{
393 QFont initial;
394 return QFontDialogPrivate::getFont(ok, initial, parent, title: QString(), options: { });
395}
396
397QFont 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
423bool 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(receiver: d->sizeList, event: k);
436
437 if (ci != d->sizeList->currentItem()
438 && style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: 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(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: 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
461void QFontDialogPrivate::initHelper(QPlatformDialogHelper *h)
462{
463 QFontDialog *d = q_func();
464 QObject::connect(sender: h, SIGNAL(currentFontChanged(QFont)), receiver: d, SIGNAL(currentFontChanged(QFont)));
465 QObject::connect(sender: h, SIGNAL(fontSelected(QFont)), receiver: d, SIGNAL(fontSelected(QFont)));
466 static_cast<QPlatformFontDialogHelper *>(h)->setOptions(options);
467}
468
469void 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
479void 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(name: family, foundry&: foundryName1, family&: familyName1);
518
519 QStringList::const_iterator it = familyNames.constBegin();
520 int i = 0;
521 for(; it != familyNames.constEnd(); ++it, ++i) {
522 QFontDatabase::parseFontName(name: *it, foundry&: foundryName2, family&: 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(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: 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*/
564void QFontDialogPrivate::updateStyles()
565{
566 Q_Q(QFontDialog);
567 QStringList styles = fdb.styles(family: 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(s: QLatin1String("Italic"))) {
589 cstyle.replace(before: QLatin1String("Italic"), after: QLatin1String("Oblique"));
590 first = false;
591 goto redo;
592 } else if (cstyle.contains(s: QLatin1String("Oblique"))) {
593 cstyle.replace(before: QLatin1String("Oblique"), after: QLatin1String("Italic"));
594 first = false;
595 goto redo;
596 } else if (cstyle.contains(s: QLatin1String("Regular"))) {
597 cstyle.replace(before: QLatin1String("Regular"), after: QLatin1String("Normal"));
598 first = false;
599 goto redo;
600 } else if (cstyle.contains(s: QLatin1String("Normal"))) {
601 cstyle.replace(before: QLatin1String("Normal"), after: QLatin1String("Regular"));
602 first = false;
603 goto redo;
604 }
605 }
606 if (!found)
607 styleList->setCurrentItem(0);
608 } else {
609 styleList->setCurrentItem(0);
610 }
611
612 styleEdit->setText(styleList->currentText());
613 if (q->style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: q)
614 && styleList->hasFocus())
615 styleEdit->selectAll();
616
617 smoothScalable = fdb.isSmoothlyScalable(family: familyList->currentText(), style: styleList->currentText());
618 }
619
620 updateSizes();
621}
622
623/*!
624 \internal
625 Updates the contents of the "font size" list box. This
626 function can be reimplemented if you have special requirements.
627*/
628
629void QFontDialogPrivate::updateSizes()
630{
631 Q_Q(QFontDialog);
632
633 if (!familyList->currentText().isEmpty()) {
634 QList<int> sizes = fdb.pointSizes(family: familyList->currentText(), style: styleList->currentText());
635
636 int i = 0;
637 int current = -1;
638 QStringList str_sizes;
639 str_sizes.reserve(alloc: sizes.size());
640 for(QList<int>::const_iterator it = sizes.constBegin(); it != sizes.constEnd(); ++it) {
641 str_sizes.append(t: QString::number(*it));
642 if (current == -1 && *it == size)
643 current = i;
644 ++i;
645 }
646 sizeList->model()->setStringList(str_sizes);
647 if (current != -1)
648 sizeList->setCurrentItem(current);
649
650 const QSignalBlocker blocker(sizeEdit);
651 sizeEdit->setText((smoothScalable ? QString::number(size) : sizeList->currentText()));
652 if (q->style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: q)
653 && sizeList->hasFocus())
654 sizeEdit->selectAll();
655 } else {
656 sizeEdit->clear();
657 }
658
659 _q_updateSample();
660}
661
662void QFontDialogPrivate::_q_updateSample()
663{
664 // compute new font
665 int pSize = sizeEdit->text().toInt();
666 QFont newFont(fdb.font(family: familyList->currentText(), style, pointSize: pSize));
667 newFont.setStrikeOut(strikeout->isChecked());
668 newFont.setUnderline(underline->isChecked());
669
670 if (familyList->currentText().isEmpty())
671 sampleEdit->clear();
672
673 updateSampleFont(newFont);
674}
675
676void QFontDialogPrivate::updateSampleFont(const QFont &newFont)
677{
678 Q_Q(QFontDialog);
679 if (newFont != sampleEdit->font()) {
680 sampleEdit->setFont(newFont);
681 emit q->currentFontChanged(font: newFont);
682 }
683}
684
685/*!
686 \internal
687*/
688void QFontDialogPrivate::_q_writingSystemHighlighted(int index)
689{
690 writingSystem = QFontDatabase::WritingSystem(index);
691 sampleEdit->setText(QFontDatabase::writingSystemSample(writingSystem));
692 updateFamilies();
693}
694
695/*!
696 \internal
697*/
698void QFontDialogPrivate::_q_familyHighlighted(int i)
699{
700 Q_Q(QFontDialog);
701 family = familyList->text(i);
702 familyEdit->setText(family);
703 if (q->style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: q)
704 && familyList->hasFocus())
705 familyEdit->selectAll();
706
707 updateStyles();
708}
709
710
711/*!
712 \internal
713*/
714
715void QFontDialogPrivate::_q_styleHighlighted(int index)
716{
717 Q_Q(QFontDialog);
718 QString s = styleList->text(i: index);
719 styleEdit->setText(s);
720 if (q->style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: q)
721 && styleList->hasFocus())
722 styleEdit->selectAll();
723
724 style = s;
725
726 updateSizes();
727}
728
729
730/*!
731 \internal
732*/
733
734void QFontDialogPrivate::_q_sizeHighlighted(int index)
735{
736 Q_Q(QFontDialog);
737 QString s = sizeList->text(i: index);
738 sizeEdit->setText(s);
739 if (q->style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: q)
740 && sizeEdit->hasFocus())
741 sizeEdit->selectAll();
742
743 size = s.toInt();
744 _q_updateSample();
745}
746
747/*!
748 \internal
749 This slot is called if the user changes the font size.
750 The size is passed in the \a s argument as a \e string.
751*/
752
753void QFontDialogPrivate::_q_sizeChanged(const QString &s)
754{
755 // no need to check if the conversion is valid, since we have an QIntValidator in the size edit
756 int size = s.toInt();
757 if (this->size == size)
758 return;
759
760 this->size = size;
761 if (sizeList->count() != 0) {
762 int i;
763 for (i = 0; i < sizeList->count() - 1; i++) {
764 if (sizeList->text(i).toInt() >= this->size)
765 break;
766 }
767 const QSignalBlocker blocker(sizeList);
768 if (sizeList->text(i).toInt() == this->size)
769 sizeList->setCurrentItem(i);
770 else
771 sizeList->clearSelection();
772 }
773 _q_updateSample();
774}
775
776void QFontDialogPrivate::retranslateStrings()
777{
778 familyAccel->setText(QFontDialog::tr(s: "&Font"));
779 styleAccel->setText(QFontDialog::tr(s: "Font st&yle"));
780 sizeAccel->setText(QFontDialog::tr(s: "&Size"));
781 effects->setTitle(QFontDialog::tr(s: "Effects"));
782 strikeout->setText(QFontDialog::tr(s: "Stri&keout"));
783 underline->setText(QFontDialog::tr(s: "&Underline"));
784 sample->setTitle(QFontDialog::tr(s: "Sample"));
785 writingSystemAccel->setText(QFontDialog::tr(s: "Wr&iting System"));
786}
787
788/*!
789 \reimp
790*/
791void QFontDialog::changeEvent(QEvent *e)
792{
793 Q_D(QFontDialog);
794 if (e->type() == QEvent::LanguageChange) {
795 d->retranslateStrings();
796 }
797 QDialog::changeEvent(e);
798}
799
800/*!
801 \since 4.5
802
803 \property QFontDialog::currentFont
804 \brief the current font of the dialog.
805*/
806
807/*!
808 \since 4.5
809
810 Sets the font highlighted in the QFontDialog to the given \a font.
811
812 \sa selectedFont()
813*/
814void QFontDialog::setCurrentFont(const QFont &font)
815{
816 Q_D(QFontDialog);
817 d->family = font.family();
818 d->style = d->fdb.styleString(font);
819 d->size = font.pointSize();
820 if (d->size == -1) {
821 QFontInfo fi(font);
822 d->size = fi.pointSize();
823 }
824 d->strikeout->setChecked(font.strikeOut());
825 d->underline->setChecked(font.underline());
826 d->updateFamilies();
827 if (QPlatformFontDialogHelper *helper = d->platformFontDialogHelper())
828 helper->setCurrentFont(font);
829}
830
831/*!
832 \since 4.5
833
834 Returns the current font.
835
836 \sa selectedFont()
837*/
838QFont QFontDialog::currentFont() const
839{
840 Q_D(const QFontDialog);
841 if (const QPlatformFontDialogHelper *helper = d->platformFontDialogHelper())
842 return helper->currentFont();
843 return d->sampleEdit->font();
844}
845
846/*!
847 Returns the font that the user selected by clicking the \uicontrol{OK}
848 or equivalent button.
849
850 \note This font is not always the same as the font held by the
851 \l currentFont property since the user can choose different fonts
852 before finally selecting the one to use.
853*/
854QFont QFontDialog::selectedFont() const
855{
856 Q_D(const QFontDialog);
857 return d->selectedFont;
858}
859
860/*!
861 \enum QFontDialog::FontDialogOption
862 \since 4.5
863
864 This enum specifies various options that affect the look and feel
865 of a font dialog.
866
867 For instance, it allows to specify which type of font should be
868 displayed. If none are specified all fonts available will be listed.
869
870 Note that the font filtering options might not be supported on some
871 platforms (e.g. Mac). They are always supported by the non native
872 dialog (used on Windows or Linux).
873
874 \value NoButtons Don't display \uicontrol{OK} and \uicontrol{Cancel} buttons. (Useful for "live dialogs".)
875 \value DontUseNativeDialog Use Qt's standard font dialog on the Mac instead of Apple's
876 native font panel.
877 \value ScalableFonts Show scalable fonts
878 \value NonScalableFonts Show non scalable fonts
879 \value MonospacedFonts Show monospaced fonts
880 \value ProportionalFonts Show proportional fonts
881
882 \sa options, setOption(), testOption()
883*/
884
885/*!
886 Sets the given \a option to be enabled if \a on is true;
887 otherwise, clears the given \a option.
888
889 \sa options, testOption()
890*/
891void QFontDialog::setOption(FontDialogOption option, bool on)
892{
893 const QFontDialog::FontDialogOptions previousOptions = options();
894 if (!(previousOptions & option) != !on)
895 setOptions(previousOptions ^ option);
896}
897
898/*!
899 Returns \c true if the given \a option is enabled; otherwise, returns
900 false.
901
902 \sa options, setOption()
903*/
904bool QFontDialog::testOption(FontDialogOption option) const
905{
906 Q_D(const QFontDialog);
907 return d->options->testOption(option: static_cast<QFontDialogOptions::FontDialogOption>(option));
908}
909
910/*!
911 \property QFontDialog::options
912 \brief the various options that affect the look and feel of the dialog
913 \since 4.5
914
915 By default, all options are disabled.
916
917 Options should be set before showing the dialog. Setting them while the
918 dialog is visible is not guaranteed to have an immediate effect on the
919 dialog (depending on the option and on the platform).
920
921 \sa setOption(), testOption()
922*/
923void QFontDialog::setOptions(FontDialogOptions options)
924{
925 Q_D(QFontDialog);
926
927 if (QFontDialog::options() == options)
928 return;
929
930 d->options->setOptions(QFontDialogOptions::FontDialogOptions(int(options)));
931 d->buttonBox->setVisible(!(options & NoButtons));
932}
933
934QFontDialog::FontDialogOptions QFontDialog::options() const
935{
936 Q_D(const QFontDialog);
937 return QFontDialog::FontDialogOptions(int(d->options->options()));
938}
939
940/*!
941 \since 4.5
942
943 Opens the dialog and connects its fontSelected() signal to the slot specified
944 by \a receiver and \a member.
945
946 The signal will be disconnected from the slot when the dialog is closed.
947*/
948void QFontDialog::open(QObject *receiver, const char *member)
949{
950 Q_D(QFontDialog);
951 connect(sender: this, SIGNAL(fontSelected(QFont)), receiver, member);
952 d->receiverToDisconnectOnClose = receiver;
953 d->memberToDisconnectOnClose = member;
954 QDialog::open();
955}
956
957/*!
958 \since 4.5
959
960 \fn void QFontDialog::currentFontChanged(const QFont &font)
961
962 This signal is emitted when the current font is changed. The new font is
963 specified in \a font.
964
965 The signal is emitted while a user is selecting a font. Ultimately, the
966 chosen font may differ from the font currently selected.
967
968 \sa currentFont, fontSelected(), selectedFont()
969*/
970
971/*!
972 \since 4.5
973
974 \fn void QFontDialog::fontSelected(const QFont &font)
975
976 This signal is emitted when a font has been selected. The selected font is
977 specified in \a font.
978
979 The signal is only emitted when a user has chosen the final font to be
980 used. It is not emitted while the user is changing the current font in the
981 font dialog.
982
983 \sa selectedFont(), currentFontChanged(), currentFont
984*/
985
986/*!
987 \reimp
988*/
989void QFontDialog::setVisible(bool visible)
990{
991 if (testAttribute(attribute: Qt::WA_WState_ExplicitShowHide) && testAttribute(attribute: Qt::WA_WState_Hidden) != visible)
992 return;
993 Q_D(QFontDialog);
994 if (d->canBeNativeDialog())
995 d->setNativeDialogVisible(visible);
996 if (d->nativeDialogInUse) {
997 // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
998 // updates the state correctly, but skips showing the non-native version:
999 setAttribute(Qt::WA_DontShowOnScreen, on: true);
1000 } else {
1001 d->nativeDialogInUse = false;
1002 setAttribute(Qt::WA_DontShowOnScreen, on: false);
1003 }
1004 QDialog::setVisible(visible);
1005}
1006
1007/*!
1008 Closes the dialog and sets its result code to \a result. If this dialog
1009 is shown with exec(), done() causes the local event loop to finish,
1010 and exec() to return \a result.
1011
1012 \sa QDialog::done()
1013*/
1014void QFontDialog::done(int result)
1015{
1016 Q_D(QFontDialog);
1017 if (result == Accepted) {
1018 // We check if this is the same font we had before, if so we emit currentFontChanged
1019 QFont selectedFont = currentFont();
1020 if(selectedFont != d->selectedFont)
1021 emit(currentFontChanged(font: selectedFont));
1022 d->selectedFont = selectedFont;
1023 emit fontSelected(font: d->selectedFont);
1024 } else
1025 d->selectedFont = QFont();
1026 if (d->receiverToDisconnectOnClose) {
1027 disconnect(sender: this, SIGNAL(fontSelected(QFont)),
1028 receiver: d->receiverToDisconnectOnClose, member: d->memberToDisconnectOnClose);
1029 d->receiverToDisconnectOnClose = nullptr;
1030 }
1031 d->memberToDisconnectOnClose.clear();
1032 QDialog::done(result);
1033}
1034
1035bool QFontDialogPrivate::canBeNativeDialog() const
1036{
1037 // Don't use Q_Q here! This function is called from ~QDialog,
1038 // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()).
1039 const QDialog * const q = static_cast<const QDialog*>(q_ptr);
1040 if (nativeDialogInUse)
1041 return true;
1042 if (QCoreApplication::testAttribute(attribute: Qt::AA_DontUseNativeDialogs)
1043 || q->testAttribute(attribute: Qt::WA_DontShowOnScreen)
1044 || (options->options() & QFontDialog::DontUseNativeDialog)) {
1045 return false;
1046 }
1047
1048 QLatin1String staticName(QFontDialog::staticMetaObject.className());
1049 QLatin1String dynamicName(q->metaObject()->className());
1050 return (staticName == dynamicName);
1051}
1052
1053QT_END_NAMESPACE
1054
1055#include "qfontdialog.moc"
1056#include "moc_qfontdialog.cpp"
1057

source code of qtbase/src/widgets/dialogs/qfontdialog.cpp