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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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