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