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

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