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 | |
28 | QT_BEGIN_NAMESPACE |
29 | |
30 | using namespace Qt::StringLiterals; |
31 | |
32 | class QFontListView : public QListView |
33 | { |
34 | Q_OBJECT |
35 | public: |
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 ¤t, 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 | } |
61 | signals: |
62 | void highlighted(int); |
63 | }; |
64 | |
65 | QFontListView::QFontListView(QWidget *parent) |
66 | : QListView(parent) |
67 | { |
68 | setModel(new QStringListModel(parent)); |
69 | setEditTriggers(NoEditTriggers); |
70 | } |
71 | |
72 | static const Qt::WindowFlags qfd_DefaultWindowFlags = |
73 | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint; |
74 | |
75 | QFontDialogPrivate::QFontDialogPrivate() |
76 | : writingSystem(QFontDatabase::Any), |
77 | options(QFontDialogOptions::create()) |
78 | { |
79 | } |
80 | |
81 | QFontDialogPrivate::~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 | */ |
121 | QFontDialog::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 | */ |
134 | QFontDialog::QFontDialog(const QFont &initial, QWidget *parent) |
135 | : QFontDialog(parent) |
136 | { |
137 | setCurrentFont(initial); |
138 | } |
139 | |
140 | void 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 | |
303 | QFontDialog::~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 | */ |
331 | QFont 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 | */ |
357 | QFont QFontDialog::getFont(bool *ok, QWidget *parent) |
358 | { |
359 | QFont initial; |
360 | return QFontDialogPrivate::getFont(ok, initial, parent, title: QString(), options: { }); |
361 | } |
362 | |
363 | QFont 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 | |
389 | bool 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 | |
427 | void 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 | |
437 | void 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 | |
447 | void 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 | */ |
530 | void 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 | |
595 | void 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 | |
628 | void 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 | |
642 | void 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 | */ |
654 | void 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 | */ |
664 | void 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 | |
681 | void 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 | |
700 | void 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 | |
719 | void 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 | |
742 | void 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 | */ |
757 | void 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 | */ |
780 | void 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 | */ |
807 | QFont 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 | */ |
826 | QFont 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 | */ |
863 | void 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 | */ |
876 | bool 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 | */ |
895 | void 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 | |
906 | QFontDialog::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 | */ |
920 | void 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 | */ |
961 | void 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 | */ |
974 | void 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 | */ |
998 | void 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 | |
1019 | bool 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 | |
1035 | QT_END_NAMESPACE |
1036 | |
1037 | #include "qfontdialog.moc" |
1038 | #include "moc_qfontdialog.cpp" |
1039 | |