aboutsummaryrefslogtreecommitdiffstats
path: root/src/quickcontrols2/qquickstyleselector.cpp
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2018-03-12 16:51:32 +0100
committerJ-P Nurmi <jpnurmi@qt.io>2018-03-13 10:37:59 +0000
commit0cd3f970fff9643129a046a2bab1d79ce2f97c28 (patch)
tree54f9453c55068ba864cb3c212f6476dc7ed71310 /src/quickcontrols2/qquickstyleselector.cpp
parent57aa9580f07307c5e277e52362943e7efd1f9ac9 (diff)
Refactor QQuickStyleSelector
Instead of trying to determine a single base URL based on the import URI of the plugin, and whether built in static mode, provide a list of paths where to lookup styles, in priority order: - requested style path (-style /path/to/style) - QT_QUICK_CONTROLS_STYLE_PATH environment variable - QT_INSTALL_QML/QtQuick/Controls.2/ - qrc://qt-project.org/imports/QtQuick/Controls.2/ Furthermore, provide the requested style name and the fallback style name as a simple list of selectors. The lookup order is: 1) requested style 2) fallback style 3) default style As a result, QQuickStyleSelector implementation is a lot simpler, completely independent of QQuickStyle, and the style lookup works regardless of whether the files are in QRC or on the file system. This allows us to utilize QRC and the Qt Quick Compiler in the future. Note: two data rows in tst_QQuickStyleSelector::select_data() had to be fixed. Not sure how the expected values ended up like that, but as the comments say, "Label.qml exists in the default and fallback styles" and "Button.qml exists in all styles", so it makes no sense to expect that Label.qml or Button.qml is selected from the FallbackStyle when a valid "data" folder is specified. Change-Id: I18dea9fddf8f079e0140b51b567814da0df2802c Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'src/quickcontrols2/qquickstyleselector.cpp')
-rw-r--r--src/quickcontrols2/qquickstyleselector.cpp122
1 files changed, 45 insertions, 77 deletions
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