diff options
-rw-r--r-- | src/imports/controls/qtquickcontrols2plugin.cpp | 7 | ||||
-rw-r--r-- | src/quickcontrols2/qquickstyle.cpp | 17 | ||||
-rw-r--r-- | src/quickcontrols2/qquickstyle_p.h | 2 | ||||
-rw-r--r-- | src/quickcontrols2/qquickstyleselector.cpp | 122 | ||||
-rw-r--r-- | src/quickcontrols2/qquickstyleselector_p.h | 9 | ||||
-rw-r--r-- | src/quickcontrols2/qquickstyleselector_p_p.h | 9 | ||||
-rw-r--r-- | tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp | 11 |
7 files changed, 82 insertions, 95 deletions
diff --git a/src/imports/controls/qtquickcontrols2plugin.cpp b/src/imports/controls/qtquickcontrols2plugin.cpp index c495b6b2..d0018901 100644 --- a/src/imports/controls/qtquickcontrols2plugin.cpp +++ b/src/imports/controls/qtquickcontrols2plugin.cpp @@ -98,12 +98,17 @@ QtQuickControls2Plugin::~QtQuickControls2Plugin() void QtQuickControls2Plugin::registerTypes(const char *uri) { QQuickStylePrivate::init(typeUrl()); + const QString style = QQuickStyle::name(); + const QString fallback = QQuickStylePrivate::fallbackStyle(); if (!style.isEmpty()) QFileSelectorPrivate::addStatics(QStringList() << style.toLower()); QQuickStyleSelector selector; - selector.setBaseUrl(typeUrl()); + selector.addSelector(style); + if (!fallback.isEmpty()) + selector.addSelector(fallback); + selector.setPaths(QQuickStylePrivate::stylePaths(true)); qmlRegisterModule(uri, 2, QT_VERSION_MINOR - 7); // Qt 5.7->2.0, 5.8->2.1, 5.9->2.2... diff --git a/src/quickcontrols2/qquickstyle.cpp b/src/quickcontrols2/qquickstyle.cpp index 5a295b6c..139e65f1 100644 --- a/src/quickcontrols2/qquickstyle.cpp +++ b/src/quickcontrols2/qquickstyle.cpp @@ -117,7 +117,7 @@ static QStringList defaultImportPathList() importPaths.reserve(3); importPaths += QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); importPaths += envPathList("QML2_IMPORT_PATH"); - importPaths += QStringLiteral("qrc:/qt-project.org/imports"); + importPaths += QStringLiteral(":/qt-project.org/imports"); importPaths += QCoreApplication::applicationDirPath(); return importPaths; } @@ -264,10 +264,20 @@ struct QQuickStyleSpec Q_GLOBAL_STATIC(QQuickStyleSpec, styleSpec) -QStringList QQuickStylePrivate::stylePaths() +QStringList QQuickStylePrivate::stylePaths(bool resolve) { + // user-requested style path + QStringList paths; + if (resolve) { + QString path = styleSpec->path(); + if (path.endsWith(QLatin1Char('/'))) + path.chop(1); + if (!path.isEmpty()) + paths += path; + } + // system/custom style paths - QStringList paths = envPathList("QT_QUICK_CONTROLS_STYLE_PATH"); + paths += envPathList("QT_QUICK_CONTROLS_STYLE_PATH"); // built-in import paths const QString targetPath = QStringLiteral("QtQuick/Controls.2"); @@ -278,6 +288,7 @@ QStringList QQuickStylePrivate::stylePaths() paths += dir.absolutePath(); } + paths.removeDuplicates(); return paths; } diff --git a/src/quickcontrols2/qquickstyle_p.h b/src/quickcontrols2/qquickstyle_p.h index b92df3c2..f6034fa0 100644 --- a/src/quickcontrols2/qquickstyle_p.h +++ b/src/quickcontrols2/qquickstyle_p.h @@ -59,7 +59,7 @@ class QSettings; class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickStylePrivate { public: - static QStringList stylePaths(); + static QStringList stylePaths(bool resolve = false); static QString fallbackStyle(); static bool isCustomStyle(); static void init(const QUrl &baseUrl); diff --git a/src/quickcontrols2/qquickstyleselector.cpp b/src/quickcontrols2/qquickstyleselector.cpp index d5543c17..1dee4dcc 100644 --- a/src/quickcontrols2/qquickstyleselector.cpp +++ b/src/quickcontrols2/qquickstyleselector.cpp @@ -40,33 +40,16 @@ #include "qquickstyleselector_p.h" #include "qquickstyleselector_p_p.h" -#include "qquickstyle.h" -#include "qquickstyle_p.h" -#include <QtCore/qdir.h> -#include <QtCore/qfile.h> #include <QtCore/qfileinfo.h> -#include <QtCore/qsysinfo.h> #include <QtCore/qlocale.h> -#include <QtQml/qqmlfile.h> - #include <QtCore/private/qfileselector_p.h> -#include <QtGui/private/qguiapplication_p.h> QT_BEGIN_NAMESPACE -static bool isLocalScheme(const QString &scheme) -{ - bool local = scheme == QLatin1String("qrc"); -#ifdef Q_OS_ANDROID - local |= scheme == QLatin1String("assets"); -#endif - return local; -} - static QString ensureSlash(const QString &path) { - if (path.endsWith(QLatin1Char('/'))) + if (path.isEmpty() || path.endsWith(QLatin1Char('/'))) return path; return path + QLatin1Char('/'); } @@ -79,105 +62,90 @@ static QStringList prefixedPlatformSelectors(const QChar &prefix) return selectors; } -static QStringList allSelectors(const QString &style = QString()) +static QStringList allSelectors() { static const QStringList platformSelectors = prefixedPlatformSelectors(QLatin1Char('+')); QStringList selectors = platformSelectors; const QString locale = QLocale().name(); if (!locale.isEmpty()) selectors += QLatin1Char('+') + locale; - if (!style.isEmpty()) - selectors.prepend(style); return selectors; } -QString QQuickStyleSelectorPrivate::select(const QString &filePath) const +QUrl QQuickStyleSelectorPrivate::select(const QString &filePath) const { QFileInfo fi(filePath); // If file doesn't exist, don't select if (!fi.exists()) - return filePath; + return QUrl(); - const QString path = fi.path(); - const QString ret = QFileSelectorPrivate::selectionHelper(path.isEmpty() ? QString() : path + QLatin1Char('/'), - fi.fileName(), allSelectors(styleName), QChar()); + const QString selected = QFileSelectorPrivate::selectionHelper(ensureSlash(fi.canonicalPath()), + fi.fileName(), allSelectors(), QChar()); - if (!ret.isEmpty()) - return ret; - return filePath; -} + if (selected.startsWith(QLatin1Char(':'))) + return QUrl(QLatin1String("qrc") + selected); -QString QQuickStyleSelectorPrivate::trySelect(const QString &filePath, const QString &fallback) const -{ - QFileInfo fi(filePath); - if (!fi.exists()) - return fallback; - - // the path contains the name of the custom/fallback style, so exclude it from - // the selectors. the rest of the selectors (os, locale) are still valid, though. - const QString path = fi.path(); - const QString selectedPath = QFileSelectorPrivate::selectionHelper(path.isEmpty() ? QString() : path + QLatin1Char('/'), - fi.fileName(), allSelectors(), QChar()); - if (selectedPath.startsWith(QLatin1Char(':'))) - return QLatin1String("qrc") + selectedPath; - return QUrl::fromLocalFile(QFileInfo(selectedPath).absoluteFilePath()).toString(); + return QUrl::fromLocalFile(selected.isEmpty() ? filePath : selected); } QQuickStyleSelector::QQuickStyleSelector() : d_ptr(new QQuickStyleSelectorPrivate) { - Q_D(QQuickStyleSelector); - d->styleName = QQuickStyle::name(); - d->stylePath = QQuickStyle::path(); } QQuickStyleSelector::~QQuickStyleSelector() { } -QUrl QQuickStyleSelector::baseUrl() const +QStringList QQuickStyleSelector::selectors() const { Q_D(const QQuickStyleSelector); - return d->baseUrl; + return d->selectors; } -void QQuickStyleSelector::setBaseUrl(const QUrl &url) +void QQuickStyleSelector::addSelector(const QString &selector) { Q_D(QQuickStyleSelector); - d->baseUrl = url; - d->basePath = QQmlFile::urlToLocalFileOrQrc(url.toString(QUrl::StripTrailingSlash) + QLatin1Char('/')); + if (d->selectors.contains(selector)) + return; + + d->selectors += selector; } -QString QQuickStyleSelector::select(const QString &fileName) const +QStringList QQuickStyleSelector::paths() const { Q_D(const QQuickStyleSelector); + return d->paths; +} - // 1) try selecting from a custom style path, for example ":/mystyle" - if (QQuickStylePrivate::isCustomStyle()) { - // NOTE: this path may contain a subset of controls - const QString selectedPath = d->trySelect(ensureSlash(d->stylePath) + d->styleName + QLatin1Char('/') + fileName); - if (!selectedPath.isEmpty()) - return selectedPath; - } +void QQuickStyleSelector::setPaths(const QStringList &paths) +{ + Q_D(QQuickStyleSelector); + d->paths = paths; +} - // 2) try selecting from the fallback style path, for example QT_INSTALL_QML/QtQuick/Controls.2/Material - const QString fallbackStyle = QQuickStylePrivate::fallbackStyle(); - if (!fallbackStyle.isEmpty()) { - // NOTE: this path may also contain a subset of controls - const QString selectedPath = d->trySelect(ensureSlash(d->basePath) + fallbackStyle + QLatin1Char('/') + fileName); - if (!selectedPath.isEmpty()) - return selectedPath; +QUrl QQuickStyleSelector::select(const QString &fileName) const +{ + Q_D(const QQuickStyleSelector); + // The lookup order is + // 1) requested style (e.g. "MyStyle", included in d->selectors) + // 2) fallback style (e.g. "Material", included in d->selectors) + // 3) default style (empty selector, not in d->selectors) + + int to = d->selectors.count() - 1; + if (d->selectors.isEmpty() || !d->selectors.first().isEmpty()) + ++to; // lookup #3 unless #1 is also empty (redundant) + + // NOTE: last iteration intentionally out of bounds => empty selector + for (int i = 0; i <= to; ++i) { + const QString selector = d->selectors.value(i); + for (const QString &path : d->paths) { + const QUrl selectedUrl = d->select(ensureSlash(path) + selector + QLatin1Char('/') + fileName); + if (selectedUrl.isValid()) + return selectedUrl; + } } - // 3) fallback to the default style that is guaranteed to contain all controls - QUrl url(ensureSlash(d->baseUrl.toString()) + fileName); - if (isLocalScheme(url.scheme())) { - QString equivalentPath = QLatin1Char(':') + url.path(); - QString selectedPath = d->select(equivalentPath); - url.setPath(selectedPath.remove(0, 1)); - } else if (url.isLocalFile()) { - url = QUrl::fromLocalFile(d->select(url.toLocalFile())); - } - return url.toString(QUrl::NormalizePathSegments); + return fileName; } QT_END_NAMESPACE diff --git a/src/quickcontrols2/qquickstyleselector_p.h b/src/quickcontrols2/qquickstyleselector_p.h index 29dba836..c4c0f540 100644 --- a/src/quickcontrols2/qquickstyleselector_p.h +++ b/src/quickcontrols2/qquickstyleselector_p.h @@ -67,10 +67,13 @@ public: QQuickStyleSelector(); ~QQuickStyleSelector(); - QUrl baseUrl() const; - void setBaseUrl(const QUrl &url); + QStringList selectors() const; + void addSelector(const QString &selector); - QString select(const QString &fileName) const; + QStringList paths() const; + void setPaths(const QStringList &paths); + + QUrl select(const QString &fileName) const; private: Q_DISABLE_COPY(QQuickStyleSelector) diff --git a/src/quickcontrols2/qquickstyleselector_p_p.h b/src/quickcontrols2/qquickstyleselector_p_p.h index e940cd87..e69e7db2 100644 --- a/src/quickcontrols2/qquickstyleselector_p_p.h +++ b/src/quickcontrols2/qquickstyleselector_p_p.h @@ -59,13 +59,10 @@ QT_BEGIN_NAMESPACE class QQuickStyleSelectorPrivate { public: - QString select(const QString &filePath) const; - QString trySelect(const QString &filePath, const QString &fallback = QString()) const; + QUrl select(const QString &filePath) const; - QUrl baseUrl; - QString basePath; - QString styleName; - QString stylePath; + QStringList paths; + QStringList selectors; }; QT_END_NAMESPACE diff --git a/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp b/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp index e90a8bd9..ce2e2e99 100644 --- a/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp +++ b/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp @@ -96,7 +96,7 @@ void tst_QQuickStyleSelector::select_data() QTest::newRow("nosuch/label") << "Label.qml" << "NoSuchStyle" << "data" << "" << testFileUrl("Label.qml").toString(); QTest::newRow("/nosuch/label") << "Label.qml" << "NoSuchStyle" << dataDirectory() << "" << testFileUrl("Label.qml").toString(); - QTest::newRow("label->base") << "Label.qml" << "" << "data" << "FallbackStyle" << testFileUrl("FallbackStyle/Label.qml").toString(); + QTest::newRow("label->base") << "Label.qml" << "" << "data" << "FallbackStyle" << testFileUrl("Label.qml").toString(); QTest::newRow("/label->base") << "Label.qml" << "" << dataDirectory() << "FallbackStyle" << testFileUrl("Label.qml").toString(); QTest::newRow("fs/label->base") << "Label.qml" << "FileSystemStyle" << "data" << "FallbackStyle" << testFileUrl("FallbackStyle/Label.qml").toString(); QTest::newRow("/fs/label->base") << "Label.qml" << "FileSystemStyle" << dataDirectory() << "FallbackStyle" << testFileUrl("FallbackStyle/Label.qml").toString(); @@ -115,7 +115,7 @@ void tst_QQuickStyleSelector::select_data() QTest::newRow("nosuch/button") << "Button.qml" << "NoSuchStyle" << "data" << "" << testFileUrl("Button.qml").toString(); QTest::newRow("/nosuch/button") << "Button.qml" << "NoSuchStyle" << dataDirectory() << "" << testFileUrl("Button.qml").toString(); - QTest::newRow("button->base") << "Button.qml" << "" << "data" << "FallbackStyle" << testFileUrl("FallbackStyle/Button.qml").toString(); + QTest::newRow("button->base") << "Button.qml" << "" << "data" << "FallbackStyle" << testFileUrl("Button.qml").toString(); QTest::newRow("/button->base") << "Button.qml" << "" << dataDirectory() << "FallbackStyle" << testFileUrl("Button.qml").toString(); QTest::newRow("fs/button->base") << "Button.qml" << "FileSystemStyle" << "data" << "FallbackStyle" << testFileUrl("FileSystemStyle/Button.qml").toString(); QTest::newRow("/fs/button->base") << "Button.qml" << "FileSystemStyle" << dataDirectory() << "FallbackStyle" << testFileUrl("FileSystemStyle/Button.qml").toString(); @@ -137,7 +137,9 @@ void tst_QQuickStyleSelector::select() QQuickStyle::setFallbackStyle(fallback); QQuickStyleSelector selector; - selector.setBaseUrl(dataDirectoryUrl()); + selector.addSelector(style); + selector.addSelector(fallback); + selector.setPaths(QStringList() << dataDirectory() << ":/"); QCOMPARE(selector.select(file), expected); } @@ -146,7 +148,8 @@ void tst_QQuickStyleSelector::platformSelectors() QQuickStyle::setStyle(QDir(dataDirectory()).filePath("PlatformStyle")); QQuickStyleSelector selector; - selector.setBaseUrl(dataDirectoryUrl()); + selector.addSelector("PlatformStyle"); + selector.setPaths(QStringList() << dataDirectory()); #if defined(Q_OS_LINUX) QCOMPARE(selector.select("Button.qml"), testFileUrl("PlatformStyle/+linux/Button.qml").toString()); |