diff options
Diffstat (limited to 'src/quickcontrols2/qquickstyle.cpp')
-rw-r--r-- | src/quickcontrols2/qquickstyle.cpp | 183 |
1 files changed, 160 insertions, 23 deletions
diff --git a/src/quickcontrols2/qquickstyle.cpp b/src/quickcontrols2/qquickstyle.cpp index 143f599a..3ad7c074 100644 --- a/src/quickcontrols2/qquickstyle.cpp +++ b/src/quickcontrols2/qquickstyle.cpp @@ -35,6 +35,7 @@ ****************************************************************************/ #include "qquickstyle.h" +#include "qquickstyle_p.h" #include "qquickstyleattached_p.h" #include <QtCore/qdir.h> @@ -80,6 +81,19 @@ QT_BEGIN_NAMESPACE Qt Quick Controls 2. It is not possible to change the style after the QML types have been registered. + The style can also be specified as a path to a custom style, such as + \c ":/mystyle". See \l {Creating a Custom Style} for more details about + building custom styles. Custom styles do not need to implement all controls. + By default, the styling system uses the \l {Default style} as a fallback + for controls that a custom style does not provide. It is possible to + specify a different fallback style to customize or extend one of the + built-in styles. + + \code + QQuickStyle::setStyle(":/mystyle"); + QQuickStyle::setFallbackStyle("Material"); + \endcode + \sa {Styling Qt Quick Controls 2} */ @@ -102,7 +116,7 @@ static QStringList defaultImportPathList() struct QQuickStyleSpec { - QQuickStyleSpec() : resolved(false) { } + QQuickStyleSpec() : custom(false), resolved(false) { } QString name() { @@ -128,54 +142,155 @@ struct QQuickStyleSpec resolve(); } - void resolve() + void setFallbackStyle(const QString &fallback, const QByteArray &method) + { + fallbackStyle = fallback; + fallbackMethod = method; + } + + static QString findStyle(const QString &path, const QString &name) + { + QDir dir(path); + if (!dir.exists()) + return QString(); + + if (name.isEmpty()) + return dir.absolutePath() + QLatin1Char('/'); + + const QStringList entries = dir.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot); + for (const QString &entry : entries) { + if (entry.compare(name, Qt::CaseInsensitive) == 0) + return dir.absoluteFilePath(entry); + } + + return QString(); + } + + void resolve(const QUrl &baseUrl = QUrl()) { if (style.isEmpty()) style = QGuiApplicationPrivate::styleOverride; if (style.isEmpty()) style = QString::fromLatin1(qgetenv("QT_QUICK_CONTROLS_STYLE")); - if (style.isEmpty()) { + if (fallbackStyle.isEmpty()) + setFallbackStyle(QString::fromLatin1(qgetenv("QT_QUICK_CONTROLS_FALLBACK_STYLE")), "QT_QUICK_CONTROLS_FALLBACK_STYLE"); + if (style.isEmpty() || fallbackStyle.isEmpty()) { QSharedPointer<QSettings> settings = QQuickStyleAttached::settings(QStringLiteral("Controls")); - if (settings) - style = settings->value(QStringLiteral("Style")).toString(); + if (settings) { + if (style.isEmpty()) + style = settings->value(QStringLiteral("Style")).toString(); + if (fallbackStyle.isEmpty()) + setFallbackStyle(settings->value(QStringLiteral("FallbackStyle")).toString(), ":/qtquickcontrols2.conf"); + } + } + + // resolve a path relative to the config + QString configPath = QFileInfo(resolveConfigFilePath()).path(); + QString stylePath = findStyle(configPath, style); + if (!stylePath.isEmpty()) { + style = stylePath; + resolved = true; + } + + custom = style.contains(QLatin1Char('/')); + + if (baseUrl.isValid()) { + QString path = QQmlFile::urlToLocalFileOrQrc(baseUrl); + QString stylePath = findStyle(path, style); + if (!stylePath.isEmpty()) { + style = stylePath; + resolved = true; + } } if (QGuiApplication::instance()) { - if (!style.contains(QLatin1Char('/'))) { + if (!custom) { const QString targetPath = QStringLiteral("QtQuick/Controls.2"); const QStringList importPaths = defaultImportPathList(); for (const QString &importPath : importPaths) { - QDir importDir(importPath); - if (importDir.cd(targetPath)) { - if (style.isEmpty()) { - style = importDir.absolutePath() + QLatin1Char('/'); - resolved = true; - break; - } - const QStringList entries = importDir.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot); - for (const QString &entry : entries) { - if (entry.compare(style, Qt::CaseInsensitive) == 0) { - style = importDir.absoluteFilePath(entry); - resolved = true; - break; - } - } - } - if (resolved) + QString stylePath = findStyle(importPath + QLatin1Char('/') + targetPath, style); + if (!stylePath.isEmpty()) { + style = stylePath; + resolved = true; break; + } } } resolved = true; } } + void reset() + { + custom = false; + resolved = false; + style.clear(); + fallbackStyle.clear(); + fallbackMethod.clear(); + } + + QString resolveConfigFilePath() + { + if (configFilePath.isEmpty()) { + configFilePath = QFile::decodeName(qgetenv("QT_QUICK_CONTROLS_CONF")); + if (!QFile::exists(configFilePath)) { + if (!configFilePath.isEmpty()) + qWarning("QT_QUICK_CONTROLS_CONF=%s: No such file", qPrintable(configFilePath)); + + configFilePath = QStringLiteral(":/qtquickcontrols2.conf"); + } + } + return configFilePath; + } + + bool custom; bool resolved; QString style; + QString fallbackStyle; + QByteArray fallbackMethod; + QString configFilePath; }; Q_GLOBAL_STATIC(QQuickStyleSpec, styleSpec) +QString QQuickStylePrivate::fallbackStyle() +{ + return styleSpec()->fallbackStyle; +} + +bool QQuickStylePrivate::isCustomStyle() +{ + return styleSpec()->custom; +} + +void QQuickStylePrivate::init(const QUrl &baseUrl) +{ + QQuickStyleSpec *spec = styleSpec(); + spec->resolve(baseUrl); + + if (!spec->fallbackStyle.isEmpty()) { + QString fallbackStyle = spec->findStyle(baseUrl.toLocalFile(), spec->fallbackStyle); + if (fallbackStyle.isEmpty()) { + if (spec->fallbackStyle.compare(QStringLiteral("Default")) != 0) { + qWarning() << "ERROR: unable to locate fallback style" << spec->fallbackStyle; + qInfo().nospace().noquote() << spec->fallbackMethod << ": the fallback style must be the name of one of the built-in Qt Quick Controls 2 styles."; + } + spec->fallbackStyle.clear(); + } + } +} + +void QQuickStylePrivate::reset() +{ + styleSpec()->reset(); +} + +QString QQuickStylePrivate::configFilePath() +{ + return styleSpec()->resolveConfigFilePath(); +} + /*! Returns the name of the application style. @@ -217,4 +332,26 @@ void QQuickStyle::setStyle(const QString &style) styleSpec()->setStyle(style); } +/*! + \since 5.8 + Sets the application fallback style to \a style. + + \note The fallback style must be the name of one of the built-in Qt Quick Controls 2 styles, e.g. "Material". + + \note The style must be configured \b before loading QML that imports Qt Quick Controls 2. + It is not possible to change the style after the QML types have been registered. + + The fallback style can be also specified by setting the \c QT_QUICK_CONTROLS_FALLBACK_STYLE + \l {Supported Environment Variables in Qt Quick Controls 2}{environment variable}. +*/ +void QQuickStyle::setFallbackStyle(const QString &style) +{ + if (QQmlMetaType::isModule(QStringLiteral("QtQuick.Controls"), 2, 0)) { + qWarning() << "ERROR: QQuickStyle::setFallbackStyle() must be called before loading QML that imports Qt Quick Controls 2."; + return; + } + + styleSpec()->setFallbackStyle(style, "QQuickStyle::setFallbackStyle()"); +} + QT_END_NAMESPACE |