1 | // Copyright (C) 2021 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 "qquickfontdialogimpl_p.h" |
5 | #include "qquickfontdialogimpl_p_p.h" |
6 | |
7 | #include <QtQuickTemplates2/private/qquickdialogbuttonbox_p_p.h> |
8 | #include <private/qfontdatabase_p.h> |
9 | |
10 | #include <QRegularExpression> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | Q_LOGGING_CATEGORY(lcAttachedProperty, "qt.quick.dialogs.quickfontdialogimpl.attachedOrWarn" ) |
15 | |
16 | QQuickFontDialogImplPrivate::QQuickFontDialogImplPrivate() |
17 | { |
18 | } |
19 | |
20 | QQuickFontDialogImplAttached *QQuickFontDialogImplPrivate::attachedOrWarn() |
21 | { |
22 | Q_Q(QQuickFontDialogImpl); |
23 | QQuickFontDialogImplAttached *attached = static_cast<QQuickFontDialogImplAttached *>( |
24 | qmlAttachedPropertiesObject<QQuickFontDialogImpl>(obj: q)); |
25 | if (!attached) { |
26 | qCWarning(lcAttachedProperty) |
27 | << "Expected FontDialogImpl attached object to be present on" << this; |
28 | } |
29 | return attached; |
30 | } |
31 | |
32 | void QQuickFontDialogImplPrivate::handleAccept() { } |
33 | |
34 | void QQuickFontDialogImplPrivate::handleClick(QQuickAbstractButton *button) |
35 | { |
36 | Q_Q(QQuickFontDialogImpl); |
37 | if (buttonRole(button) == QPlatformDialogHelper::AcceptRole) { |
38 | q->accept(); |
39 | QQuickDialogPrivate::handleClick(button); |
40 | } |
41 | } |
42 | |
43 | QQuickFontDialogImpl::QQuickFontDialogImpl(QObject *parent) |
44 | : QQuickDialog(*(new QQuickFontDialogImplPrivate), parent) |
45 | { |
46 | } |
47 | |
48 | QQuickFontDialogImplAttached *QQuickFontDialogImpl::qmlAttachedProperties(QObject *object) |
49 | { |
50 | return new QQuickFontDialogImplAttached(object); |
51 | } |
52 | |
53 | QSharedPointer<QFontDialogOptions> QQuickFontDialogImpl::options() const |
54 | { |
55 | Q_D(const QQuickFontDialogImpl); |
56 | |
57 | return d->options; |
58 | } |
59 | |
60 | void QQuickFontDialogImpl::setOptions(const QSharedPointer<QFontDialogOptions> &options) |
61 | { |
62 | Q_D(QQuickFontDialogImpl); |
63 | |
64 | if (options == d->options) |
65 | return; |
66 | |
67 | d->options = options; |
68 | |
69 | emit optionsChanged(); |
70 | } |
71 | |
72 | QFont QQuickFontDialogImpl::currentFont() const |
73 | { |
74 | Q_D(const QQuickFontDialogImpl); |
75 | return d->currentFont; |
76 | } |
77 | |
78 | void QQuickFontDialogImpl::setCurrentFont(const QFont &font, bool selectInListViews) |
79 | { |
80 | Q_D(QQuickFontDialogImpl); |
81 | |
82 | if (font == d->currentFont) |
83 | return; |
84 | |
85 | d->currentFont = font; |
86 | |
87 | emit currentFontChanged(font); |
88 | |
89 | if (!selectInListViews) |
90 | return; |
91 | |
92 | QQuickFontDialogImplAttached *attached = d->attachedOrWarn(); |
93 | if (!attached) |
94 | return; |
95 | |
96 | if (!attached->familyListView()->model().isValid()) { |
97 | const QSignalBlocker blocker(attached->sampleEdit()); |
98 | attached->updateFamilies(); |
99 | } |
100 | |
101 | attached->selectFontInListViews(font); |
102 | } |
103 | |
104 | void QQuickFontDialogImpl::init() |
105 | { |
106 | Q_D(QQuickFontDialogImpl); |
107 | QQuickFontDialogImplAttached *attached = d->attachedOrWarn(); |
108 | if (!attached) |
109 | return; |
110 | |
111 | if (!attached->familyListView()->model().isValid()) |
112 | attached->updateFamilies(); |
113 | |
114 | attached->buttonBox()->setVisible(!(options()->options() & QFontDialogOptions::NoButtons)); |
115 | } |
116 | |
117 | void QQuickFontDialogImpl::keyReleaseEvent(QKeyEvent *event) |
118 | { |
119 | Q_D(QQuickFontDialogImpl); |
120 | |
121 | QQuickDialog::keyReleaseEvent(event); |
122 | |
123 | QQuickFontDialogImplAttached *attached = d->attachedOrWarn(); |
124 | if (!attached) |
125 | return; |
126 | |
127 | // The family and style text edits are read-only so that they |
128 | // can show the current selection but also allow key input to "search". |
129 | // This is why we handle just the release event, and don't accept it. |
130 | if (window()->activeFocusItem() == attached->familyEdit()) |
131 | attached->searchFamily(s: event->text()); |
132 | else if (window()->activeFocusItem() == attached->styleEdit()) |
133 | attached->searchStyle(s: event->text()); |
134 | } |
135 | |
136 | void QQuickFontDialogImpl::focusOutEvent(QFocusEvent *event) |
137 | { |
138 | Q_D(QQuickFontDialogImpl); |
139 | |
140 | QQuickDialog::focusOutEvent(event); |
141 | |
142 | QQuickFontDialogImplAttached *attached = d->attachedOrWarn(); |
143 | if (!attached) |
144 | return; |
145 | |
146 | attached->clearSearch(); |
147 | } |
148 | |
149 | QQuickFontDialogImplAttached::QQuickFontDialogImplAttached(QObject *parent) |
150 | : QObject(*(new QQuickFontDialogImplAttachedPrivate), parent), |
151 | m_writingSystem(QFontDatabase::Any), |
152 | m_selectedSize(-1), |
153 | m_smoothlyScalable(false), |
154 | m_ignoreFamilyUpdate(false), |
155 | m_ignoreStyleUpdate(false) |
156 | { |
157 | if (!qobject_cast<QQuickFontDialogImpl *>(object: parent)) { |
158 | qmlWarning(me: this) << "FontDialogImpl attached properties should only be " |
159 | << "accessed through the root FileDialogImpl instance" ; |
160 | } |
161 | } |
162 | |
163 | QQuickListView *QQuickFontDialogImplAttached::familyListView() const |
164 | { |
165 | Q_D(const QQuickFontDialogImplAttached); |
166 | return d->familyListView; |
167 | } |
168 | |
169 | void QQuickFontDialogImplAttached::setFamilyListView(QQuickListView *familyListView) |
170 | { |
171 | Q_D(QQuickFontDialogImplAttached); |
172 | if (d->familyListView == familyListView) |
173 | return; |
174 | |
175 | if (d->familyListView) { |
176 | disconnect(sender: d->familyListView, signal: &QQuickListView::currentIndexChanged, |
177 | receiver: this, slot: &QQuickFontDialogImplAttached::_q_familyChanged); |
178 | } |
179 | |
180 | d->familyListView = familyListView; |
181 | |
182 | if (familyListView) { |
183 | connect(sender: d->familyListView, signal: &QQuickListView::currentIndexChanged, |
184 | context: this, slot: &QQuickFontDialogImplAttached::_q_familyChanged); |
185 | } |
186 | |
187 | emit familyListViewChanged(); |
188 | } |
189 | |
190 | QQuickListView *QQuickFontDialogImplAttached::styleListView() const |
191 | { |
192 | Q_D(const QQuickFontDialogImplAttached); |
193 | return d->styleListView; |
194 | } |
195 | |
196 | void QQuickFontDialogImplAttached::setStyleListView(QQuickListView *styleListView) |
197 | { |
198 | Q_D(QQuickFontDialogImplAttached); |
199 | if (d->styleListView == styleListView) |
200 | return; |
201 | |
202 | if (d->styleListView) { |
203 | disconnect(sender: d->styleListView, signal: &QQuickListView::currentIndexChanged, |
204 | receiver: this, slot: &QQuickFontDialogImplAttached::_q_styleChanged); |
205 | } |
206 | |
207 | d->styleListView = styleListView; |
208 | |
209 | if (styleListView) { |
210 | connect(sender: d->styleListView, signal: &QQuickListView::currentIndexChanged, |
211 | context: this, slot: &QQuickFontDialogImplAttached::_q_styleChanged); |
212 | } |
213 | |
214 | emit styleListViewChanged(); |
215 | } |
216 | |
217 | QQuickListView *QQuickFontDialogImplAttached::sizeListView() const |
218 | { |
219 | Q_D(const QQuickFontDialogImplAttached); |
220 | return d->sizeListView; |
221 | } |
222 | |
223 | void QQuickFontDialogImplAttached::setSizeListView(QQuickListView *sizeListView) |
224 | { |
225 | Q_D(QQuickFontDialogImplAttached); |
226 | if (d->sizeListView == sizeListView) |
227 | return; |
228 | |
229 | if (d->sizeListView) { |
230 | disconnect(sender: d->sizeListView, signal: &QQuickListView::currentIndexChanged, |
231 | receiver: this, slot: &QQuickFontDialogImplAttached::_q_sizeChanged); |
232 | } |
233 | |
234 | d->sizeListView = sizeListView; |
235 | |
236 | if (d->sizeListView) { |
237 | connect(sender: d->sizeListView, signal: &QQuickListView::currentIndexChanged, |
238 | context: this, slot: &QQuickFontDialogImplAttached::_q_sizeChanged); |
239 | } |
240 | |
241 | emit sizeListViewChanged(); |
242 | } |
243 | |
244 | QQuickTextEdit *QQuickFontDialogImplAttached::sampleEdit() const |
245 | { |
246 | Q_D(const QQuickFontDialogImplAttached); |
247 | return d->sampleEdit; |
248 | } |
249 | |
250 | void QQuickFontDialogImplAttached::setSampleEdit(QQuickTextEdit *sampleEdit) |
251 | { |
252 | Q_D(QQuickFontDialogImplAttached); |
253 | |
254 | if (d->sampleEdit == sampleEdit) |
255 | return; |
256 | |
257 | if (d->sampleEdit) { |
258 | QObjectPrivate::disconnect(sender: d->sampleEdit, signal: &QQuickTextEdit::fontChanged, |
259 | receiverPrivate: d, slot: &QQuickFontDialogImplAttachedPrivate::currentFontChanged); |
260 | } |
261 | |
262 | d->sampleEdit = sampleEdit; |
263 | |
264 | if (d->sampleEdit) { |
265 | QObjectPrivate::connect(sender: d->sampleEdit, signal: &QQuickTextEdit::fontChanged, |
266 | receiverPrivate: d, slot: &QQuickFontDialogImplAttachedPrivate::currentFontChanged); |
267 | |
268 | d->sampleEdit->setText(QFontDatabase::writingSystemSample(writingSystem: m_writingSystem)); |
269 | } |
270 | |
271 | emit sampleEditChanged(); |
272 | } |
273 | |
274 | QQuickDialogButtonBox *QQuickFontDialogImplAttached::buttonBox() const |
275 | { |
276 | Q_D(const QQuickFontDialogImplAttached); |
277 | return d->buttonBox; |
278 | } |
279 | |
280 | void QQuickFontDialogImplAttached::setButtonBox(QQuickDialogButtonBox *buttonBox) |
281 | { |
282 | Q_D(QQuickFontDialogImplAttached); |
283 | if (buttonBox == d->buttonBox) |
284 | return; |
285 | |
286 | if (d->buttonBox) { |
287 | QQuickFontDialogImpl *fontDialogImpl = qobject_cast<QQuickFontDialogImpl *>(object: parent()); |
288 | if (fontDialogImpl) { |
289 | auto dialogPrivate = QQuickDialogPrivate::get(dialog: fontDialogImpl); |
290 | QObjectPrivate::disconnect(sender: d->buttonBox, signal: &QQuickDialogButtonBox::accepted, |
291 | receiverPrivate: dialogPrivate, slot: &QQuickDialogPrivate::handleAccept); |
292 | QObjectPrivate::disconnect(sender: d->buttonBox, signal: &QQuickDialogButtonBox::rejected, |
293 | receiverPrivate: dialogPrivate, slot: &QQuickDialogPrivate::handleReject); |
294 | QObjectPrivate::disconnect(sender: d->buttonBox, signal: &QQuickDialogButtonBox::clicked, receiverPrivate: dialogPrivate, |
295 | slot: &QQuickDialogPrivate::handleClick); |
296 | } |
297 | } |
298 | |
299 | d->buttonBox = buttonBox; |
300 | |
301 | if (buttonBox) { |
302 | QQuickFontDialogImpl *fontDialogImpl = qobject_cast<QQuickFontDialogImpl *>(object: parent()); |
303 | if (fontDialogImpl) { |
304 | auto dialogPrivate = QQuickDialogPrivate::get(dialog: fontDialogImpl); |
305 | QObjectPrivate::connect(sender: d->buttonBox, signal: &QQuickDialogButtonBox::accepted, receiverPrivate: dialogPrivate, |
306 | slot: &QQuickDialogPrivate::handleAccept); |
307 | QObjectPrivate::connect(sender: d->buttonBox, signal: &QQuickDialogButtonBox::rejected, receiverPrivate: dialogPrivate, |
308 | slot: &QQuickDialogPrivate::handleReject); |
309 | QObjectPrivate::connect(sender: d->buttonBox, signal: &QQuickDialogButtonBox::clicked, receiverPrivate: dialogPrivate, |
310 | slot: &QQuickDialogPrivate::handleClick); |
311 | } |
312 | } |
313 | |
314 | emit buttonBoxChanged(); |
315 | } |
316 | |
317 | QQuickComboBox *QQuickFontDialogImplAttached::writingSystemComboBox() const |
318 | { |
319 | Q_D(const QQuickFontDialogImplAttached); |
320 | return d->writingSystemComboBox; |
321 | } |
322 | |
323 | void QQuickFontDialogImplAttached::setWritingSystemComboBox(QQuickComboBox *writingSystemComboBox) |
324 | { |
325 | Q_D(QQuickFontDialogImplAttached); |
326 | |
327 | if (d->writingSystemComboBox == writingSystemComboBox) |
328 | return; |
329 | |
330 | if (d->writingSystemComboBox) { |
331 | disconnect(sender: d->writingSystemComboBox, signal: &QQuickComboBox::activated, |
332 | receiver: this, slot: &QQuickFontDialogImplAttached::_q_writingSystemChanged); |
333 | } |
334 | |
335 | d->writingSystemComboBox = writingSystemComboBox; |
336 | |
337 | if (d->writingSystemComboBox) { |
338 | QStringList writingSystemModel; |
339 | for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) { |
340 | QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i); |
341 | QString wsName = QFontDatabase::writingSystemName(writingSystem: ws); |
342 | if (wsName.isEmpty()) |
343 | break; |
344 | writingSystemModel.append(t: wsName); |
345 | } |
346 | |
347 | d->writingSystemComboBox->setModel(writingSystemModel); |
348 | |
349 | connect(sender: d->writingSystemComboBox, signal: &QQuickComboBox::activated, |
350 | context: this, slot: &QQuickFontDialogImplAttached::_q_writingSystemChanged); |
351 | } |
352 | |
353 | emit writingSystemComboBoxChanged(); |
354 | } |
355 | |
356 | QQuickCheckBox *QQuickFontDialogImplAttached::underlineCheckBox() const |
357 | { |
358 | Q_D(const QQuickFontDialogImplAttached); |
359 | return d->underlineCheckBox; |
360 | } |
361 | |
362 | void QQuickFontDialogImplAttached::setUnderlineCheckBox(QQuickCheckBox *underlineCheckBox) |
363 | { |
364 | Q_D(QQuickFontDialogImplAttached); |
365 | |
366 | if (d->underlineCheckBox == underlineCheckBox) |
367 | return; |
368 | |
369 | if (d->underlineCheckBox) { |
370 | disconnect(sender: d->underlineCheckBox, signal: &QQuickCheckBox::checkStateChanged, |
371 | receiver: this, slot: &QQuickFontDialogImplAttached::_q_updateSample); |
372 | } |
373 | |
374 | d->underlineCheckBox = underlineCheckBox; |
375 | |
376 | if (d->underlineCheckBox) { |
377 | connect(sender: d->underlineCheckBox, signal: &QQuickCheckBox::checkStateChanged, |
378 | context: this, slot: &QQuickFontDialogImplAttached::_q_updateSample); |
379 | } |
380 | |
381 | emit underlineCheckBoxChanged(); |
382 | } |
383 | |
384 | QQuickCheckBox *QQuickFontDialogImplAttached::strikeoutCheckBox() const |
385 | { |
386 | Q_D(const QQuickFontDialogImplAttached); |
387 | return d->strikeoutCheckBox; |
388 | } |
389 | |
390 | void QQuickFontDialogImplAttached::setStrikeoutCheckBox(QQuickCheckBox *strikeoutCheckBox) |
391 | { |
392 | Q_D(QQuickFontDialogImplAttached); |
393 | |
394 | if (d->strikeoutCheckBox == strikeoutCheckBox) |
395 | return; |
396 | |
397 | if (d->strikeoutCheckBox) { |
398 | disconnect(sender: d->strikeoutCheckBox, signal: &QQuickCheckBox::checkStateChanged, |
399 | receiver: this, slot: &QQuickFontDialogImplAttached::_q_updateSample); |
400 | } |
401 | |
402 | d->strikeoutCheckBox = strikeoutCheckBox; |
403 | |
404 | if (d->strikeoutCheckBox) { |
405 | connect(sender: d->strikeoutCheckBox, signal: &QQuickCheckBox::checkStateChanged, |
406 | context: this, slot: &QQuickFontDialogImplAttached::_q_updateSample); |
407 | } |
408 | |
409 | emit strikeoutCheckBoxChanged(); |
410 | } |
411 | |
412 | QQuickTextField *QQuickFontDialogImplAttached::familyEdit() const |
413 | { |
414 | Q_D(const QQuickFontDialogImplAttached); |
415 | return d->familyEdit; |
416 | } |
417 | |
418 | void QQuickFontDialogImplAttached::setFamilyEdit(QQuickTextField *familyEdit) |
419 | { |
420 | Q_D(QQuickFontDialogImplAttached); |
421 | |
422 | if (d->familyEdit == familyEdit) |
423 | return; |
424 | |
425 | d->familyEdit = familyEdit; |
426 | |
427 | emit familyEditChanged(); |
428 | } |
429 | |
430 | QQuickTextField *QQuickFontDialogImplAttached::styleEdit() const |
431 | { |
432 | Q_D(const QQuickFontDialogImplAttached); |
433 | return d->styleEdit; |
434 | } |
435 | |
436 | void QQuickFontDialogImplAttached::setStyleEdit(QQuickTextField *styleEdit) |
437 | { |
438 | Q_D(QQuickFontDialogImplAttached); |
439 | |
440 | if (d->styleEdit == styleEdit) |
441 | return; |
442 | |
443 | d->styleEdit = styleEdit; |
444 | |
445 | emit styleEditChanged(); |
446 | } |
447 | |
448 | QQuickTextField *QQuickFontDialogImplAttached::sizeEdit() const |
449 | { |
450 | Q_D(const QQuickFontDialogImplAttached); |
451 | return d->sizeEdit; |
452 | } |
453 | |
454 | void QQuickFontDialogImplAttached::setSizeEdit(QQuickTextField *sizeEdit) |
455 | { |
456 | Q_D(QQuickFontDialogImplAttached); |
457 | |
458 | if (d->sizeEdit == sizeEdit) |
459 | return; |
460 | |
461 | if (d->sizeEdit) { |
462 | disconnect(sender: d->sizeEdit, signal: &QQuickTextField::textChanged, |
463 | receiver: this, slot: &QQuickFontDialogImplAttached::_q_sizeEdited); |
464 | } |
465 | |
466 | d->sizeEdit = sizeEdit; |
467 | |
468 | if (d->sizeEdit) { |
469 | connect(sender: d->sizeEdit, signal: &QQuickTextField::textChanged, |
470 | context: this, slot: &QQuickFontDialogImplAttached::_q_sizeEdited); |
471 | } |
472 | |
473 | emit sizeEditChanged(); |
474 | } |
475 | |
476 | static int findFamilyInModel(const QString &selectedFamily, const QStringList &model) |
477 | { |
478 | enum match_t { MATCH_NONE = 0, MATCH_LAST_RESORT = 1, MATCH_APP = 2, MATCH_FAMILY = 3 }; |
479 | QString foundryName1, familyName1, foundryName2, familyName2; |
480 | int bestFamilyMatch = -1; |
481 | match_t bestFamilyType = MATCH_NONE; |
482 | const QFont f; |
483 | |
484 | QFontDatabasePrivate::parseFontName(name: selectedFamily, foundry&: foundryName1, family&: familyName1); |
485 | |
486 | int i = 0; |
487 | for (auto it = model.constBegin(); it != model.constEnd(); ++it, ++i) { |
488 | QFontDatabasePrivate::parseFontName(name: *it, foundry&: foundryName2, family&: familyName2); |
489 | |
490 | if (familyName1 == familyName2) { |
491 | bestFamilyType = MATCH_FAMILY; |
492 | if (foundryName1 == foundryName2) |
493 | return i; |
494 | else |
495 | bestFamilyMatch = i; |
496 | } |
497 | |
498 | // fallbacks |
499 | match_t type = MATCH_NONE; |
500 | if (bestFamilyType <= MATCH_NONE && familyName2 == QStringLiteral("helvetica" )) |
501 | type = MATCH_LAST_RESORT; |
502 | if (bestFamilyType <= MATCH_LAST_RESORT && familyName2 == f.families().constFirst()) |
503 | type = MATCH_APP; |
504 | if (type != MATCH_NONE) { |
505 | bestFamilyType = type; |
506 | bestFamilyMatch = i; |
507 | } |
508 | } |
509 | |
510 | return bestFamilyMatch; |
511 | } |
512 | |
513 | static int findStyleInModel(const QString &selectedStyle, const QStringList &model) |
514 | { |
515 | if (model.isEmpty()) |
516 | return -1; |
517 | |
518 | if (!selectedStyle.isEmpty()) { |
519 | const int idx = model.indexOf(re: QRegularExpression(QRegularExpression::escape(str: selectedStyle), QRegularExpression::CaseInsensitiveOption)); |
520 | if (idx >= 0) |
521 | return idx; |
522 | |
523 | enum class StyleClass {Unknown, Normal, Italic}; |
524 | auto classifyStyleFallback = [](const QString & style) { |
525 | if (style.toLower() == QLatin1String("italic" ) || style.toLower() == QLatin1String("oblique" )) |
526 | return StyleClass::Italic; |
527 | if (style.toLower() == QLatin1String("normal" ) || style.toLower() == QLatin1String("regular" )) |
528 | return StyleClass::Normal; |
529 | return StyleClass::Unknown; |
530 | }; |
531 | |
532 | auto styleClass = classifyStyleFallback(selectedStyle); |
533 | |
534 | if (styleClass != StyleClass::Unknown) |
535 | for (int i = 0; i < model.size(); ++i) |
536 | if (classifyStyleFallback(model.at(i)) == styleClass) |
537 | return i; |
538 | } |
539 | return 0; |
540 | } |
541 | |
542 | /*! |
543 | \internal |
544 | |
545 | Updates the model for the family list view, and attempt |
546 | to reselect the previously selected font family. |
547 | */ |
548 | void QQuickFontDialogImplAttached::updateFamilies() |
549 | { |
550 | const QFontDialogOptions::FontDialogOptions scalableMask( |
551 | QFontDialogOptions::ScalableFonts | QFontDialogOptions::NonScalableFonts); |
552 | |
553 | const QFontDialogOptions::FontDialogOptions spacingMask(QFontDialogOptions::ProportionalFonts |
554 | | QFontDialogOptions::MonospacedFonts); |
555 | |
556 | const auto p = qobject_cast<QQuickFontDialogImpl *>(object: parent()); |
557 | |
558 | const auto options = p->options()->options(); |
559 | |
560 | QStringList familyNames; |
561 | const auto families = QFontDatabase::families(writingSystem: m_writingSystem); |
562 | for (const auto &family : families) { |
563 | if (QFontDatabase::isPrivateFamily(family)) |
564 | continue; |
565 | |
566 | if ((options & scalableMask) && (options & scalableMask) != scalableMask) { |
567 | if (bool(options & QFontDialogOptions::ScalableFonts) |
568 | != QFontDatabase::isSmoothlyScalable(family)) |
569 | continue; |
570 | } |
571 | |
572 | if ((options & spacingMask) && (options & scalableMask) != spacingMask) { |
573 | if (bool(options & QFontDialogOptions::MonospacedFonts) |
574 | != QFontDatabase::isFixedPitch(family)) |
575 | continue; |
576 | } |
577 | |
578 | familyNames << family; |
579 | } |
580 | |
581 | auto listView = familyListView(); |
582 | |
583 | // Index will be set to -1 on empty model, and 0 for non empty models. |
584 | m_ignoreFamilyUpdate = !m_selectedFamily.isEmpty(); |
585 | listView->setModel(familyNames); |
586 | m_ignoreFamilyUpdate = false; |
587 | |
588 | // Will overwrite selectedFamily and selectedStyle |
589 | listView->setCurrentIndex(findFamilyInModel(selectedFamily: m_selectedFamily, model: familyNames)); |
590 | |
591 | if (familyNames.isEmpty()) |
592 | _q_familyChanged(); |
593 | } |
594 | |
595 | /*! |
596 | \internal |
597 | |
598 | Updates the model for the style list view, and |
599 | attempt to reselect the style that was previously selected. |
600 | |
601 | Calls updateSizes() |
602 | */ |
603 | void QQuickFontDialogImplAttached::updateStyles() |
604 | { |
605 | const QString family = familyListView()->currentIndex() >= 0 ? m_selectedFamily : QString(); |
606 | const QStringList styles = QFontDatabase::styles(family); |
607 | |
608 | auto listView = styleListView(); |
609 | |
610 | m_ignoreStyleUpdate = !m_selectedStyle.isEmpty(); |
611 | listView->setModel(styles); |
612 | |
613 | if (styles.isEmpty()) { |
614 | styleEdit()->clear(); |
615 | m_smoothlyScalable = false; |
616 | } else { |
617 | int newIndex = findStyleInModel(selectedStyle: m_selectedStyle, model: styles); |
618 | |
619 | listView->setCurrentIndex(newIndex); |
620 | |
621 | m_selectedStyle = styles.at(i: newIndex); |
622 | styleEdit()->setText(m_selectedStyle); |
623 | |
624 | m_smoothlyScalable = QFontDatabase::isSmoothlyScalable(family: m_selectedFamily, style: m_selectedStyle); |
625 | } |
626 | |
627 | m_ignoreStyleUpdate = false; |
628 | |
629 | updateSizes(); |
630 | } |
631 | |
632 | /*! |
633 | \internal |
634 | |
635 | Updates the model for the size list view, |
636 | and attempts to reselect the size that was previously selected |
637 | */ |
638 | void QQuickFontDialogImplAttached::updateSizes() |
639 | { |
640 | if (!m_selectedFamily.isEmpty()) { |
641 | const QList<int> sizes = QFontDatabase::pointSizes(family: m_selectedFamily, style: m_selectedStyle); |
642 | |
643 | QStringList str_sizes; |
644 | |
645 | str_sizes.reserve(size: sizes.size()); |
646 | |
647 | int idx = 0, current = -1; |
648 | for (QList<int>::const_iterator it = sizes.constBegin(); it != sizes.constEnd(); it++) { |
649 | str_sizes.append(t: QString::number(*it)); |
650 | if (current == -1 && m_selectedSize == *it) { |
651 | current = idx; |
652 | } |
653 | ++idx; |
654 | } |
655 | |
656 | auto listView = sizeListView(); |
657 | |
658 | // only select the first element in the model when this function is first called and the new model isn't empty |
659 | listView->setModel(str_sizes); |
660 | |
661 | if (current != -1) |
662 | listView->setCurrentIndex(current); |
663 | |
664 | sizeEdit()->setText(!m_smoothlyScalable && listView->currentIndex() > 0 |
665 | ? str_sizes.at(i: listView->currentIndex()) |
666 | : QString::number(m_selectedSize)); |
667 | } else { |
668 | qCWarning(lcAttachedProperty) << "Warning! selectedFamily is empty" ; |
669 | sizeEdit()->clear(); |
670 | } |
671 | |
672 | _q_updateSample(); |
673 | } |
674 | |
675 | void QQuickFontDialogImplAttached::_q_updateSample() |
676 | { |
677 | if (m_selectedFamily.isEmpty()) |
678 | return; |
679 | |
680 | const int pSize = sizeEdit()->text().toInt(); |
681 | |
682 | QFont newFont = QFontDatabase::font(family: m_selectedFamily, style: m_selectedStyle, pointSize: pSize); |
683 | |
684 | newFont.setUnderline(underlineCheckBox()->isChecked()); |
685 | newFont.setStrikeOut(strikeoutCheckBox()->isChecked()); |
686 | |
687 | sampleEdit()->setFont(newFont); |
688 | } |
689 | |
690 | void QQuickFontDialogImplAttached::_q_writingSystemChanged(int index) |
691 | { |
692 | m_writingSystem = QFontDatabase::WritingSystem(index); |
693 | sampleEdit()->setText(QFontDatabase::writingSystemSample(writingSystem: m_writingSystem)); |
694 | |
695 | updateFamilies(); |
696 | } |
697 | |
698 | void QQuickFontDialogImplAttached::searchListView(const QString &s, QQuickListView *listView) |
699 | { |
700 | if (s.isEmpty()) |
701 | return; |
702 | |
703 | const QStringList model = listView->model().toStringList(); |
704 | |
705 | bool redo = false; |
706 | |
707 | do { |
708 | m_search.append(s); |
709 | |
710 | for (int i = 0; i < model.size(); ++i) { |
711 | if (model.at(i).startsWith(s: m_search, cs: Qt::CaseInsensitive)) { |
712 | listView->setCurrentIndex(i); |
713 | return; |
714 | } |
715 | } |
716 | |
717 | clearSearch(); |
718 | |
719 | redo = !redo; |
720 | } while (redo); |
721 | } |
722 | |
723 | void QQuickFontDialogImplAttached::clearSearch() |
724 | { |
725 | m_search.clear(); |
726 | } |
727 | |
728 | void QQuickFontDialogImplAttached::_q_familyChanged() |
729 | { |
730 | if (m_ignoreFamilyUpdate) |
731 | return; |
732 | |
733 | const int index = familyListView()->currentIndex(); |
734 | |
735 | if (index < 0) { |
736 | familyEdit()->clear(); |
737 | } else { |
738 | m_selectedFamily = familyListView()->model().toStringList().at(i: index); |
739 | familyEdit()->setText(m_selectedFamily); |
740 | } |
741 | |
742 | updateStyles(); |
743 | } |
744 | |
745 | void QQuickFontDialogImplAttached::_q_styleChanged() |
746 | { |
747 | if (m_ignoreStyleUpdate) |
748 | return; |
749 | |
750 | const int index = styleListView()->currentIndex(); |
751 | |
752 | if (index < 0) { |
753 | qCWarning(lcAttachedProperty) << "currentIndex changed to -1" ; |
754 | return; |
755 | } |
756 | |
757 | m_selectedStyle = styleListView()->model().toStringList().at(i: index); |
758 | styleEdit()->setText(m_selectedStyle); |
759 | m_smoothlyScalable = QFontDatabase::isSmoothlyScalable(family: m_selectedFamily, style: m_selectedStyle); |
760 | |
761 | updateSizes(); |
762 | } |
763 | |
764 | void QQuickFontDialogImplAttached::_q_sizeEdited() |
765 | { |
766 | const int size = qAbs(t: sizeEdit()->text().toInt()); |
767 | |
768 | if (size == m_selectedSize) |
769 | return; |
770 | |
771 | m_selectedSize = size; |
772 | |
773 | if (sizeListView()->count()) { |
774 | auto model = sizeListView()->model().toStringList(); |
775 | |
776 | int i; |
777 | for (i = 0; i < model.size() - 1; ++i) { |
778 | if (model.at(i).toInt() >= size) |
779 | break; |
780 | } |
781 | |
782 | QSignalBlocker blocker(sizeListView()); |
783 | if (model.at(i).toInt() == size) |
784 | sizeListView()->setCurrentIndex(i); |
785 | else |
786 | sizeListView()->setCurrentIndex(-1); |
787 | } |
788 | |
789 | _q_updateSample(); |
790 | } |
791 | |
792 | void QQuickFontDialogImplAttached::_q_sizeChanged() |
793 | { |
794 | const int index = sizeListView()->currentIndex(); |
795 | |
796 | if (index < 0) { |
797 | qCWarning(lcAttachedProperty) << "currentIndex changed to -1" ; |
798 | return; |
799 | } |
800 | |
801 | const QString s = sizeListView()->model().toStringList().at(i: index); |
802 | m_selectedSize = s.toInt(); |
803 | |
804 | sizeEdit()->setText(s); |
805 | |
806 | _q_updateSample(); |
807 | } |
808 | |
809 | void QQuickFontDialogImplAttachedPrivate::currentFontChanged(const QFont &font) |
810 | { |
811 | auto fontDialogImpl = qobject_cast<QQuickFontDialogImpl *>(object: parent); |
812 | |
813 | if (!fontDialogImpl) { |
814 | return; |
815 | } |
816 | |
817 | fontDialogImpl->setCurrentFont(font); |
818 | } |
819 | |
820 | void QQuickFontDialogImplAttached::selectFontInListViews(const QFont &font) |
821 | { |
822 | { |
823 | QSignalBlocker blocker(sampleEdit()); |
824 | familyListView()->setCurrentIndex(findFamilyInModel(selectedFamily: font.families().constFirst(), model: familyListView()->model().toStringList())); |
825 | styleListView()->setCurrentIndex(findStyleInModel(selectedStyle: QFontDatabase::styleString(font), model: styleListView()->model().toStringList())); |
826 | sizeEdit()->setText(QString::number(font.pointSize())); |
827 | |
828 | underlineCheckBox()->setChecked(font.underline()); |
829 | strikeoutCheckBox()->setChecked(font.strikeOut()); |
830 | } |
831 | |
832 | _q_updateSample(); |
833 | } |
834 | |
835 | QT_END_NAMESPACE |
836 | |
837 | #include "moc_qquickfontdialogimpl_p.cpp" |
838 | |