1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
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 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 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.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 later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qquickstyle.h"
38#include "qquickstyle_p.h"
39
40#include <QtCore/qdir.h>
41#include <QtCore/qfile.h>
42#include <QtCore/qdebug.h>
43#include <QtCore/qsettings.h>
44#include <QtCore/qfileselector.h>
45#include <QtCore/qlibraryinfo.h>
46#include <QtCore/qmetaobject.h>
47#include <QtGui/qcolor.h>
48#include <QtGui/qfont.h>
49#include <QtGui/qpalette.h>
50#include <QtGui/private/qguiapplication_p.h>
51#include <QtGui/qpa/qplatformtheme.h>
52#include <QtQml/private/qqmlmetatype_p.h>
53#include <QtQml/qqmlengine.h>
54#include <QtQml/qqmlfile.h>
55
56#include <functional>
57
58QT_BEGIN_NAMESPACE
59
60/*!
61 \class QQuickStyle
62 \brief The QQuickStyle class allows configuring the application style.
63 \inmodule QtQuickControls2
64 \since 5.7
65
66 QQuickStyle provides API for querying and configuring the application
67 \l {Styling Qt Quick Controls}{styles} of Qt Quick Controls.
68
69 \code
70 #include <QGuiApplication>
71 #include <QQmlApplicationEngine>
72 #include <QQuickStyle>
73
74 int main(int argc, char *argv[])
75 {
76 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
77 QGuiApplication app(argc, argv);
78
79 QQuickStyle::setStyle("Material");
80
81 QQmlApplicationEngine engine;
82 engine.load(QUrl("qrc:/main.qml"));
83
84 return app.exec();
85 }
86 \endcode
87
88 \note The style must be configured \b before loading QML that imports
89 Qt Quick Controls. It is not possible to change the style after the QML
90 types have been registered.
91
92 The style can also be specified as a path to a custom style, such as
93 \c ":/mystyle". See \l {Creating a Custom Style} for more details about
94 building custom styles. Custom styles do not need to implement all controls.
95 By default, the styling system uses the \l {Default style} as a fallback
96 for controls that a custom style does not provide. It is possible to
97 specify a different fallback style to customize or extend one of the
98 built-in styles.
99
100 \code
101 QQuickStyle::setStyle(":/mystyle");
102 QQuickStyle::setFallbackStyle("Material");
103 \endcode
104
105 \sa {Styling Qt Quick Controls}
106*/
107
108static QStringList envPathList(const QByteArray &var)
109{
110 QStringList paths;
111 if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var))) {
112 const QByteArray value = qgetenv(varName: var);
113 paths += QString::fromLocal8Bit(str: value).split(sep: QDir::listSeparator(), behavior: Qt::SkipEmptyParts);
114 }
115 return paths;
116}
117
118static QStringList defaultImportPathList()
119{
120 QStringList importPaths;
121 importPaths.reserve(alloc: 3);
122#ifdef Q_OS_ANDROID
123 // androiddeployqt puts the QML files inside a resource file and they are not
124 // showing up in the Qml2ImportsPath as a result
125 importPaths += QStringLiteral(":/android_rcc_bundle/qml");
126#else
127# ifndef QT_STATIC
128 importPaths += QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
129# endif
130#endif
131 importPaths += envPathList(var: "QML2_IMPORT_PATH");
132 importPaths += QStringLiteral(":/qt-project.org/imports");
133 importPaths += QCoreApplication::applicationDirPath();
134 return importPaths;
135}
136
137struct QQuickStyleSpec
138{
139 QQuickStyleSpec() : custom(false), resolved(false) { }
140
141 QString name()
142 {
143 if (!resolved)
144 resolve();
145 return style.mid(position: style.lastIndexOf(c: QLatin1Char('/')) + 1);
146 }
147
148 QString path()
149 {
150 if (!resolved)
151 resolve();
152 QString s = style;
153 if (QQmlFile::isLocalFile(url: s))
154 s = QQmlFile::urlToLocalFileOrQrc(s);
155 return s.left(n: s.lastIndexOf(c: QLatin1Char('/')) + 1);
156 }
157
158 void setStyle(const QString &s)
159 {
160 style = s;
161 resolved = false;
162 resolve();
163 }
164
165 void setFallbackStyle(const QString &fallback, const QByteArray &method)
166 {
167 fallbackStyle = fallback;
168 fallbackMethod = method;
169 }
170
171 static QString findStyle(const QString &path, const QString &name)
172 {
173 QDir dir(path);
174 if (!dir.exists())
175 return QString();
176
177 if (name.isEmpty())
178 return dir.absolutePath() + QLatin1Char('/');
179
180 const QStringList entries = dir.entryList(nameFilters: QStringList(), filters: QDir::Dirs | QDir::NoDotAndDotDot);
181 for (const QString &entry : entries) {
182 if (entry.compare(s: name, cs: Qt::CaseInsensitive) == 0)
183 return dir.absoluteFilePath(fileName: entry);
184 }
185
186 return QString();
187 }
188
189 void resolve(const QUrl &baseUrl = QUrl())
190 {
191 if (style.isEmpty())
192 style = QGuiApplicationPrivate::styleOverride;
193 if (style.isEmpty())
194 style = QString::fromLocal8Bit(str: qgetenv(varName: "QT_QUICK_CONTROLS_STYLE"));
195 if (fallbackStyle.isEmpty())
196 setFallbackStyle(fallback: QString::fromLocal8Bit(str: qgetenv(varName: "QT_QUICK_CONTROLS_FALLBACK_STYLE")), method: "QT_QUICK_CONTROLS_FALLBACK_STYLE");
197#if QT_CONFIG(settings)
198 if (style.isEmpty() || fallbackStyle.isEmpty()) {
199 QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Controls"));
200 if (settings) {
201 if (style.isEmpty())
202 style = settings->value(QStringLiteral("Style")).toString();
203 if (fallbackStyle.isEmpty())
204 setFallbackStyle(fallback: settings->value(QStringLiteral("FallbackStyle")).toString(), method: ":/qtquickcontrols2.conf");
205 }
206 }
207#endif
208
209 // resolve a path relative to the config
210 QString configPath = QFileInfo(resolveConfigFilePath()).path();
211 QString stylePath = findStyle(path: configPath, name: style);
212 if (!stylePath.isEmpty()) {
213 style = stylePath;
214 resolved = true;
215 }
216
217 custom = style.contains(c: QLatin1Char('/'));
218
219 if (baseUrl.isValid()) {
220 QString path = QQmlFile::urlToLocalFileOrQrc(baseUrl);
221 QString stylePath = findStyle(path, name: style);
222 if (!stylePath.isEmpty()) {
223 style = stylePath;
224 resolved = true;
225 }
226 }
227
228 if (QGuiApplication::instance()) {
229 if (!custom) {
230 const QStringList stylePaths = QQuickStylePrivate::stylePaths();
231 for (const QString &path : stylePaths) {
232 QString stylePath = findStyle(path, name: style);
233 if (!stylePath.isEmpty()) {
234 custom = !stylePath.startsWith(s: QQmlFile::urlToLocalFileOrQrc(baseUrl));
235 style = stylePath;
236 resolved = true;
237 break;
238 }
239 }
240 }
241 resolved = true;
242 }
243 }
244
245 void reset()
246 {
247 custom = false;
248 resolved = false;
249 style.clear();
250 fallbackStyle.clear();
251 fallbackMethod.clear();
252 configFilePath.clear();
253 }
254
255 QString resolveConfigFilePath()
256 {
257 if (configFilePath.isEmpty()) {
258 configFilePath = QFile::decodeName(localFileName: qgetenv(varName: "QT_QUICK_CONTROLS_CONF"));
259 if (configFilePath.isEmpty() || !QFile::exists(fileName: configFilePath)) {
260 if (!configFilePath.isEmpty())
261 qWarning(msg: "QT_QUICK_CONTROLS_CONF=%s: No such file", qPrintable(configFilePath));
262
263 configFilePath = QStringLiteral(":/qtquickcontrols2.conf");
264 }
265 }
266 return configFilePath;
267 }
268
269 bool custom;
270 bool resolved;
271 QString style;
272 QString fallbackStyle;
273 QByteArray fallbackMethod;
274 QString configFilePath;
275 QStringList customStylePaths;
276};
277
278Q_GLOBAL_STATIC(QQuickStyleSpec, styleSpec)
279
280static QStringList parseStylePathsWithColon(const QString &var)
281{
282 QStringList paths;
283 const QChar colon = QLatin1Char(':');
284 int currentIndex = 0;
285
286 do {
287 int nextColonIndex = -1;
288 QString path;
289
290 if (var.at(i: currentIndex) == colon) {
291 // This is either a list separator, or a qrc path.
292 if (var.at(i: currentIndex + 1) == colon) {
293 // It's a double colon (list separator followed by qrc path);
294 // find the end of the path.
295 nextColonIndex = var.indexOf(c: colon, from: currentIndex + 2);
296 path = var.mid(position: currentIndex + 1,
297 n: nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex - 1);
298 } else {
299 // It's a single colon.
300 nextColonIndex = var.indexOf(c: colon, from: currentIndex + 1);
301 if (currentIndex == 0) {
302 // If we're at the start of the string, then it's a qrc path.
303 path = var.mid(position: currentIndex,
304 n: nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex);
305 } else {
306 // Otherwise, it's a separator.
307 path = var.mid(position: currentIndex + 1,
308 n: nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex - 1);
309 }
310 }
311 } else {
312 // It's a file path.
313 nextColonIndex = var.indexOf(c: colon, from: currentIndex);
314 path = var.mid(position: currentIndex,
315 n: nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex);
316 }
317
318 paths += path;
319 currentIndex = nextColonIndex;
320
321 // Keep going until we can't find any more colons,
322 // or we're at the last character.
323 } while (currentIndex != -1 && currentIndex < var.size() - 1);
324
325 return paths;
326}
327
328QStringList QQuickStylePrivate::stylePaths(bool resolve)
329{
330 // user-requested style path
331 QStringList paths;
332 if (resolve) {
333 QString path = styleSpec()->path();
334 if (path.endsWith(c: QLatin1Char('/')))
335 path.chop(n: 1);
336 if (!path.isEmpty())
337 paths += path;
338 }
339
340 if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE_PATH"))) {
341 const QString value = QString::fromLocal8Bit(str: qgetenv(varName: "QT_QUICK_CONTROLS_STYLE_PATH"));
342 const QChar listSeparator = QDir::listSeparator();
343 if (listSeparator == QLatin1Char(':')) {
344 // Split manually to avoid breaking paths on systems where : is the list separator,
345 // since it's also used for qrc paths.
346 paths += parseStylePathsWithColon(var: value);
347 } else {
348 // Fast/simpler path for systems where something other than : is used as
349 // the list separator (such as ';').
350 const QStringList customPaths = value.split(sep: listSeparator, behavior: Qt::SkipEmptyParts);
351 paths += customPaths;
352 }
353 }
354
355 // system/custom style paths
356 paths += styleSpec()->customStylePaths;
357 paths += envPathList(var: "QT_QUICK_CONTROLS_STYLE_PATH");
358
359 // built-in import paths
360 const QString targetPath = QStringLiteral("QtQuick/Controls.2");
361 const QStringList importPaths = defaultImportPathList();
362 for (const QString &importPath : importPaths) {
363 QDir dir(importPath);
364 if (dir.cd(dirName: targetPath))
365 paths += dir.absolutePath();
366 }
367
368 paths.removeDuplicates();
369 return paths;
370}
371
372QString QQuickStylePrivate::fallbackStyle()
373{
374 return styleSpec()->fallbackStyle;
375}
376
377bool QQuickStylePrivate::isCustomStyle()
378{
379 return styleSpec()->custom;
380}
381
382void QQuickStylePrivate::init(const QUrl &baseUrl)
383{
384 QQuickStyleSpec *spec = styleSpec();
385 spec->resolve(baseUrl);
386
387 if (!spec->fallbackStyle.isEmpty()) {
388 QString fallbackStyle;
389 const QStringList stylePaths = QQuickStylePrivate::stylePaths();
390 for (const QString &path : stylePaths) {
391 fallbackStyle = spec->findStyle(path, name: spec->fallbackStyle);
392 if (!fallbackStyle.isEmpty())
393 break;
394 }
395 if (fallbackStyle.isEmpty()) {
396 if (spec->fallbackStyle.compare(QStringLiteral("Default")) != 0) {
397 qWarning() << "ERROR: unable to locate fallback style" << spec->fallbackStyle;
398 qInfo().nospace().noquote() << spec->fallbackMethod << ": the fallback style must be the name of one of the built-in Qt Quick Controls 2 styles.";
399 }
400 spec->fallbackStyle.clear();
401 }
402 }
403}
404
405void QQuickStylePrivate::reset()
406{
407 if (styleSpec())
408 styleSpec()->reset();
409}
410
411QString QQuickStylePrivate::configFilePath()
412{
413 return styleSpec()->resolveConfigFilePath();
414}
415
416QSharedPointer<QSettings> QQuickStylePrivate::settings(const QString &group)
417{
418#ifndef QT_NO_SETTINGS
419 const QString filePath = QQuickStylePrivate::configFilePath();
420 if (QFile::exists(fileName: filePath)) {
421 QFileSelector selector;
422 QSettings *settings = new QSettings(selector.select(filePath), QSettings::IniFormat);
423 if (!group.isEmpty())
424 settings->beginGroup(prefix: group);
425 return QSharedPointer<QSettings>(settings);
426 }
427#endif // QT_NO_SETTINGS
428 return QSharedPointer<QSettings>();
429}
430
431#if QT_CONFIG(settings)
432static void readValue(const QSharedPointer<QSettings> &settings, const QString &name, std::function<void(const QVariant &)> setValue)
433{
434 const QVariant var = settings->value(key: name);
435 if (var.isValid())
436 setValue(var);
437}
438
439template <typename Enum>
440static Enum toEnumValue(const QVariant &var)
441{
442 // ### TODO: expose QFont enums to the meta object system using Q_ENUM
443 //QMetaEnum enumeration = QMetaEnum::fromType<Enum>();
444 //bool ok = false;
445 //int value = enumeration.keyToValue(var.toByteArray(), &ok);
446 //if (!ok)
447 // value = var.toInt();
448 //return static_cast<Enum>(value);
449
450 return static_cast<Enum>(var.toInt());
451}
452
453const QFont *QQuickStylePrivate::readFont(const QSharedPointer<QSettings> &settings)
454{
455 const QVariant var = settings->value(QStringLiteral("Font"));
456 if (var.isValid())
457 return new QFont(var.value<QFont>());
458
459 QFont f;
460 settings->beginGroup(QStringLiteral("Font"));
461 readValue(settings, QStringLiteral("Family"), setValue: [&f](const QVariant &var) { f.setFamily(var.toString()); });
462 readValue(settings, QStringLiteral("PointSize"), setValue: [&f](const QVariant &var) { f.setPointSizeF(var.toReal()); });
463 readValue(settings, QStringLiteral("PixelSize"), setValue: [&f](const QVariant &var) { f.setPixelSize(var.toInt()); });
464 readValue(settings, QStringLiteral("StyleHint"), setValue: [&f](const QVariant &var) { f.setStyleHint(toEnumValue<QFont::StyleHint>(var: var.toInt())); });
465 readValue(settings, QStringLiteral("Weight"), setValue: [&f](const QVariant &var) { f.setWeight(toEnumValue<QFont::Weight>(var)); });
466 readValue(settings, QStringLiteral("Style"), setValue: [&f](const QVariant &var) { f.setStyle(toEnumValue<QFont::Style>(var: var.toInt())); });
467 settings->endGroup();
468 return new QFont(f);
469}
470
471static void readColorGroup(const QSharedPointer<QSettings> &settings, QPalette::ColorGroup group, QPalette *palette)
472{
473 const QStringList keys = settings->childKeys();
474 if (keys.isEmpty())
475 return;
476
477 static const int index = QPalette::staticMetaObject.indexOfEnumerator(name: "ColorRole");
478 Q_ASSERT(index != -1);
479 QMetaEnum metaEnum = QPalette::staticMetaObject.enumerator(index);
480
481 for (const QString &key : keys) {
482 bool ok = false;
483 int role = metaEnum.keyToValue(key: key.toUtf8(), ok: &ok);
484 if (ok)
485 palette->setColor(acg: group, acr: static_cast<QPalette::ColorRole>(role), acolor: settings->value(key).value<QColor>());
486 }
487}
488
489const QPalette *QQuickStylePrivate::readPalette(const QSharedPointer<QSettings> &settings)
490{
491 QPalette p;
492 settings->beginGroup(QStringLiteral("Palette"));
493 readColorGroup(settings, group: QPalette::All, palette: &p);
494
495 settings->beginGroup(QStringLiteral("Normal"));
496 readColorGroup(settings, group: QPalette::Normal, palette: &p);
497 settings->endGroup();
498
499 settings->beginGroup(QStringLiteral("Disabled"));
500 readColorGroup(settings, group: QPalette::Disabled, palette: &p);
501 settings->endGroup();
502 return new QPalette(p);
503}
504#endif // QT_CONFIG(settings)
505
506static bool qt_is_dark_system_theme()
507{
508 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
509 if (const QPalette *systemPalette = theme->palette(type: QPlatformTheme::SystemPalette)) {
510 const QColor &textColor = systemPalette->color(cr: QPalette::WindowText);
511 return textColor.red() > 128 && textColor.blue() > 128 && textColor.green() > 128;
512 }
513 }
514 return false;
515}
516
517bool QQuickStylePrivate::isDarkSystemTheme()
518{
519 static bool dark = qt_is_dark_system_theme();
520 return dark;
521}
522
523/*!
524 Returns the name of the application style.
525
526 \note The application style can be specified by passing a \c -style command
527 line argument. Therefore \c name() may not return a fully resolved
528 value if called before constructing a QGuiApplication.
529*/
530QString QQuickStyle::name()
531{
532 return styleSpec()->name();
533}
534
535/*!
536 Returns the path of an overridden application style, or an empty
537 string if the style is one of the built-in Qt Quick Controls 2 styles.
538
539 \note The application style can be specified by passing a \c -style command
540 line argument. Therefore \c path() may not return a fully resolved
541 value if called before constructing a QGuiApplication.
542*/
543QString QQuickStyle::path()
544{
545 return styleSpec()->path();
546}
547
548/*!
549 Sets the application style to \a style.
550
551 \note The style must be configured \b before loading QML that imports Qt Quick Controls.
552 It is not possible to change the style after the QML types have been registered.
553
554 \sa setFallbackStyle(), {Using Styles in Qt Quick Controls}
555*/
556void QQuickStyle::setStyle(const QString &style)
557{
558 if (QQmlMetaType::isModule(QStringLiteral("QtQuick.Controls"), versionMajor: 2, versionMinor: 0)) {
559 qWarning() << "ERROR: QQuickStyle::setStyle() must be called before loading QML that imports Qt Quick Controls 2.";
560 return;
561 }
562
563 styleSpec()->setStyle(style);
564}
565
566/*!
567 \since 5.8
568 Sets the application fallback style to \a style.
569
570 \note The fallback style must be the name of one of the built-in Qt Quick Controls styles, e.g. "Material".
571
572 \note The style must be configured \b before loading QML that imports Qt Quick Controls.
573 It is not possible to change the style after the QML types have been registered.
574
575 The fallback style can be also specified by setting the \c QT_QUICK_CONTROLS_FALLBACK_STYLE
576 \l {Supported Environment Variables in Qt Quick Controls}{environment variable}.
577
578 \sa setStyle(), {Using Styles in Qt Quick Controls}
579*/
580void QQuickStyle::setFallbackStyle(const QString &style)
581{
582 if (QQmlMetaType::isModule(QStringLiteral("QtQuick.Controls"), versionMajor: 2, versionMinor: 0)) {
583 qWarning() << "ERROR: QQuickStyle::setFallbackStyle() must be called before loading QML that imports Qt Quick Controls 2.";
584 return;
585 }
586
587 styleSpec()->setFallbackStyle(fallback: style, method: "QQuickStyle::setFallbackStyle()");
588}
589
590/*!
591 \since 5.9
592 Returns the names of the available styles.
593
594 \note The method must be called \b after creating an instance of QGuiApplication.
595
596 \sa stylePathList(), addStylePath()
597*/
598QStringList QQuickStyle::availableStyles()
599{
600 QStringList styles;
601 if (!QGuiApplication::instance()) {
602 qWarning() << "ERROR: QQuickStyle::availableStyles() must be called after creating an instance of QGuiApplication.";
603 return styles;
604 }
605
606 const QStringList stylePaths = QQuickStylePrivate::stylePaths();
607 for (const QString &path : stylePaths) {
608 const QList<QFileInfo> entries = QDir(path).entryInfoList(filters: QDir::Dirs | QDir::NoDotAndDotDot);
609 for (const QFileInfo &entry : entries) {
610 const QString name = entry.fileName();
611 if (!name.endsWith(s: QLatin1String(".dSYM")) && name != QLatin1String("designer"))
612 styles += name;
613 }
614 }
615 styles.prepend(QStringLiteral("Default"));
616 styles.removeDuplicates();
617 return styles;
618}
619
620/*!
621 \since 5.12
622
623 Returns the list of directories where Qt Quick Controls 2 searches for available styles.
624
625 By default, the list contains paths specified in the \c QT_QUICK_CONTROLS_STYLE_PATH
626 environment variable, and any existing \c QtQuick/Controls.2 sub-directories in
627 \l QQmlEngine::importPathList().
628
629 \sa addStylePath(), availableStyles()
630*/
631QStringList QQuickStyle::stylePathList()
632{
633 return QQuickStylePrivate::stylePaths();
634}
635
636/*!
637 \since 5.12
638
639 Adds \a path as a directory where Qt Quick Controls 2 searches for available styles.
640
641 The \a path may be any local filesystem directory or \l {The Qt Resource System}{Qt Resource} directory.
642 For example, the following paths are all valid:
643
644 \list
645 \li \c {/path/to/styles/}
646 \li \c {file:///path/to/styles/}
647 \li \c {:/path/to/styles/}
648 \li \c {qrc:/path/to/styles/})
649 \endlist
650
651 The \a path will be converted into \l {QDir::canonicalPath}{canonical form} before it is added to
652 the style path list.
653
654 The newly added \a path will be first in the stylePathList().
655
656 \sa stylePathList(), availableStyles()
657*/
658void QQuickStyle::addStylePath(const QString &path)
659{
660 if (path.isEmpty())
661 return;
662
663 const QUrl url = QUrl(path);
664 if (url.isRelative() || url.scheme() == QLatin1String("file")
665 || (url.scheme().length() == 1 && QFile::exists(fileName: path)) ) { // windows path
666 styleSpec()->customStylePaths.prepend(t: QDir(path).canonicalPath());
667 } else if (url.scheme() == QLatin1String("qrc")) {
668 styleSpec()->customStylePaths.prepend(t: QLatin1Char(':') + url.path());
669 } else {
670 styleSpec()->customStylePaths.prepend(t: path);
671 }
672}
673
674QT_END_NAMESPACE
675

source code of qtquickcontrols2/src/quickcontrols2/qquickstyle.cpp