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