aboutsummaryrefslogtreecommitdiffstats
path: root/src/quickcontrols2/qquickstyle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quickcontrols2/qquickstyle.cpp')
-rw-r--r--src/quickcontrols2/qquickstyle.cpp350
1 files changed, 48 insertions, 302 deletions
diff --git a/src/quickcontrols2/qquickstyle.cpp b/src/quickcontrols2/qquickstyle.cpp
index 836eb2f4..72078a0e 100644
--- a/src/quickcontrols2/qquickstyle.cpp
+++ b/src/quickcontrols2/qquickstyle.cpp
@@ -92,54 +92,23 @@ Q_LOGGING_CATEGORY(lcQtQuickControlsStyle, "qt.quick.controls.style")
Qt Quick Controls. 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.
+ To create your own custom style, see \l {Creating a Custom Style}. 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::setStyle("MyStyle");
QQuickStyle::setFallbackStyle("Material");
\endcode
\sa {Styling Qt Quick Controls}
*/
-static QStringList envPathList(const QByteArray &var)
-{
- QStringList paths;
- if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var))) {
- const QByteArray value = qgetenv(var);
- paths += QString::fromLocal8Bit(value).split(QDir::listSeparator(), Qt::SkipEmptyParts);
- }
- return paths;
-}
-
-static QStringList defaultImportPathList()
-{
- QStringList importPaths;
- importPaths.reserve(3);
-#ifdef Q_OS_ANDROID
- // androiddeployqt puts the QML files inside a resource file and they are not
- // showing up in the Qml2ImportsPath as a result
- importPaths += QStringLiteral(":/android_rcc_bundle/qml");
-#else
-# ifndef QT_STATIC
- importPaths += QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
-# endif
-#endif
- importPaths += envPathList("QML2_IMPORT_PATH");
- importPaths += QStringLiteral(":/qt-project.org/imports");
- importPaths += QCoreApplication::applicationDirPath();
- return importPaths;
-}
-
struct QQuickStyleSpec
{
- QQuickStyleSpec() : custom(false), resolved(false) { }
+ QQuickStyleSpec() { }
QString name()
{
@@ -160,6 +129,13 @@ struct QQuickStyleSpec
void setStyle(const QString &s)
{
+ qCDebug(lcQtQuickControlsStyle) << "style" << s << "set on QQuickStyleSpec";
+ if (s.contains(QLatin1Char('/'))) {
+ qWarning() << "Style names must not contain paths; see the \"Definition of a Style\" documentation for more information";
+ return;
+ }
+
+ qCDebug(lcQtQuickControlsStyle) << "clearing resolved flag and resolving";
style = s;
resolved = false;
resolve();
@@ -171,27 +147,9 @@ struct QQuickStyleSpec
fallbackMethod = method;
}
- static QString findStyle(const QString &path, const QString &name)
+ void resolve()
{
- 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())
- {
- qCDebug(lcQtQuickControlsStyle) << "resolving style with baseUrl" << baseUrl;
+ qCDebug(lcQtQuickControlsStyle) << "resolving style";
if (style.isEmpty())
style = QGuiApplicationPrivate::styleOverride;
@@ -211,53 +169,33 @@ struct QQuickStyleSpec
}
#endif
- // resolve a path relative to the config
- QString configPath = QFileInfo(resolveConfigFilePath()).path();
- QString stylePath = findStyle(configPath, style);
- if (!stylePath.isEmpty()) {
- style = stylePath;
- resolved = true;
+ auto builtInStyleList = QQuickStylePrivate::builtInStyles();
+ if (!fallbackStyle.isEmpty() && !builtInStyleList.contains(fallbackStyle)) {
+ qWarning().nospace().noquote() << fallbackMethod << ": the specified fallback style \"" <<
+ fallbackStyle << "\" is not one of the built-in Qt Quick Controls 2 styles";
+ fallbackStyle.clear();
}
- custom = style.contains(QLatin1Char('/'));
+ // Find the config file.
+ resolveConfigFilePath();
- if (baseUrl.isValid()) {
- QString path = QQmlFile::urlToLocalFileOrQrc(baseUrl);
- QString stylePath = findStyle(path, style);
- if (!stylePath.isEmpty()) {
- style = stylePath;
- resolved = true;
- }
- }
+ custom = !builtInStyleList.contains(QQuickStylePrivate::effectiveStyleName(style));
- if (QGuiApplication::instance()) {
- if (!custom) {
- const QStringList stylePaths = QQuickStylePrivate::stylePaths();
- for (const QString &path : stylePaths) {
- QString stylePath = findStyle(path, style);
- if (!stylePath.isEmpty()) {
- custom = !stylePath.startsWith(QQmlFile::urlToLocalFileOrQrc(baseUrl));
- style = stylePath;
- resolved = true;
- break;
- }
- }
- }
- resolved = true;
- }
+ resolved = true;
qCDebug(lcQtQuickControlsStyle).nospace() << "done resolving:"
+ << "\n style=" << style
<< "\n custom=" << custom
<< "\n resolved=" << resolved
- << "\n style=" << style
<< "\n fallbackStyle=" << fallbackStyle
<< "\n fallbackMethod=" << fallbackMethod
- << "\n configFilePath=" << configFilePath
- << "\n customStylePaths=" << customStylePaths;
+ << "\n configFilePath=" << configFilePath;
}
void reset()
{
+ qCDebug(lcQtQuickControlsStyle) << "resetting values to their defaults";
+
custom = false;
resolved = false;
style.clear();
@@ -281,10 +219,10 @@ struct QQuickStyleSpec
}
// Is this a custom style defined by the user and not "built-in" style?
- bool custom;
- // Did we manage to find a valid style path?
- bool resolved;
- // The full path to the style.
+ bool custom = false;
+ // Have we resolved the style yet?
+ bool resolved = false;
+ // The name of the style.
QString style;
// The built-in style to use if the requested style cannot be found.
QString fallbackStyle;
@@ -292,102 +230,13 @@ struct QQuickStyleSpec
QByteArray fallbackMethod;
// The path to the qtquickcontrols2.conf file.
QString configFilePath;
- // An extra list of directories where we search for available styles before any other directories.
- QStringList customStylePaths;
};
Q_GLOBAL_STATIC(QQuickStyleSpec, styleSpec)
-static QStringList parseStylePathsWithColon(const QString &var)
+QString QQuickStylePrivate::effectiveStyleName(const QString &styleName)
{
- QStringList paths;
- const QChar colon = QLatin1Char(':');
- int currentIndex = 0;
-
- do {
- int nextColonIndex = -1;
- QString path;
-
- if (var.at(currentIndex) == colon) {
- // This is either a list separator, or a qrc path.
- if (var.at(currentIndex + 1) == colon) {
- // It's a double colon (list separator followed by qrc path);
- // find the end of the path.
- nextColonIndex = var.indexOf(colon, currentIndex + 2);
- path = var.mid(currentIndex + 1,
- nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex - 1);
- } else {
- // It's a single colon.
- nextColonIndex = var.indexOf(colon, currentIndex + 1);
- if (currentIndex == 0) {
- // If we're at the start of the string, then it's a qrc path.
- path = var.mid(currentIndex,
- nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex);
- } else {
- // Otherwise, it's a separator.
- path = var.mid(currentIndex + 1,
- nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex - 1);
- }
- }
- } else {
- // It's a file path.
- nextColonIndex = var.indexOf(colon, currentIndex);
- path = var.mid(currentIndex,
- nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex);
- }
-
- paths += path;
- currentIndex = nextColonIndex;
-
- // Keep going until we can't find any more colons,
- // or we're at the last character.
- } while (currentIndex != -1 && currentIndex < var.size() - 1);
-
- return paths;
-}
-
-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;
- }
-
- if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE_PATH"))) {
- const QString value = QString::fromLocal8Bit(qgetenv("QT_QUICK_CONTROLS_STYLE_PATH"));
- const QChar listSeparator = QDir::listSeparator();
- if (listSeparator == QLatin1Char(':')) {
- // Split manually to avoid breaking paths on systems where : is the list separator,
- // since it's also used for qrc paths.
- paths += parseStylePathsWithColon(value);
- } else {
- // Fast/simpler path for systems where something other than : is used as
- // the list separator (such as ';').
- const QStringList customPaths = value.split(listSeparator, Qt::SkipEmptyParts);
- paths += customPaths;
- }
- }
-
- // system/custom style paths
- paths += styleSpec()->customStylePaths;
- paths += envPathList("QT_QUICK_CONTROLS_STYLE_PATH");
-
- // built-in import paths
- const QString targetPath = QStringLiteral("QtQuick/Controls");
- const QStringList importPaths = defaultImportPathList();
- for (const QString &importPath : importPaths) {
- QDir dir(importPath);
- if (dir.cd(targetPath))
- paths += dir.absolutePath();
- }
-
- paths.removeDuplicates();
- return paths;
+ return !styleName.isEmpty() ? styleName : QLatin1String("Default");
}
QString QQuickStylePrivate::fallbackStyle()
@@ -400,27 +249,15 @@ bool QQuickStylePrivate::isCustomStyle()
return styleSpec()->custom;
}
-void QQuickStylePrivate::init(const QUrl &baseUrl)
+bool QQuickStylePrivate::isResolved()
+{
+ return styleSpec()->resolved;
+}
+
+void QQuickStylePrivate::init()
{
QQuickStyleSpec *spec = styleSpec();
- spec->resolve(baseUrl);
-
- if (!spec->fallbackStyle.isEmpty()) {
- QString fallbackStyle;
- const QStringList stylePaths = QQuickStylePrivate::stylePaths();
- for (const QString &path : stylePaths) {
- fallbackStyle = spec->findStyle(path, spec->fallbackStyle);
- if (!fallbackStyle.isEmpty())
- break;
- }
- 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();
- }
- }
+ spec->resolve();
}
void QQuickStylePrivate::reset()
@@ -541,6 +378,12 @@ bool QQuickStylePrivate::isDarkSystemTheme()
return dark;
}
+QStringList QQuickStylePrivate::builtInStyles()
+{
+ return { QLatin1String("Default"), QLatin1String("Fusion"),
+ QLatin1String("Imagine"), QLatin1String("Material"), QLatin1String("Universal") };
+}
+
/*!
Returns the name of the application style.
@@ -554,19 +397,6 @@ QString QQuickStyle::name()
}
/*!
- Returns the path of an overridden application style, or an empty
- string if the style is one of the built-in Qt Quick Controls 2 styles.
-
- \note The application style can be specified by passing a \c -style command
- line argument. Therefore \c path() may not return a fully resolved
- value if called before constructing a QGuiApplication.
-*/
-QString QQuickStyle::path()
-{
- return styleSpec()->path();
-}
-
-/*!
Sets the application style to \a style.
\note The style must be configured \b before loading QML that imports Qt Quick Controls.
@@ -612,88 +442,4 @@ void QQuickStyle::setFallbackStyle(const QString &style)
styleSpec()->setFallbackStyle(style, "QQuickStyle::setFallbackStyle()");
}
-/*!
- \since 5.9
- Returns the names of the available styles.
-
- \note The method must be called \b after creating an instance of QGuiApplication.
-
- \sa stylePathList(), addStylePath()
-*/
-QStringList QQuickStyle::availableStyles()
-{
- QStringList styles;
- if (!QGuiApplication::instance()) {
- qWarning() << "ERROR: QQuickStyle::availableStyles() must be called after creating an instance of QGuiApplication.";
- return styles;
- }
-
- const QStringList stylePaths = QQuickStylePrivate::stylePaths();
- for (const QString &path : stylePaths) {
- const QList<QFileInfo> entries = QDir(path).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
- for (const QFileInfo &entry : entries) {
- const QString name = entry.fileName();
- if (!name.endsWith(QLatin1String(".dSYM")) && name != QLatin1String("designer"))
- styles += name;
- }
- }
- styles.prepend(QStringLiteral("Default"));
- styles.removeDuplicates();
- return styles;
-}
-
-/*!
- \since 5.12
-
- Returns the list of directories where Qt Quick Controls 2 searches for available styles.
-
- By default, the list contains paths specified in the \c QT_QUICK_CONTROLS_STYLE_PATH
- environment variable, and any existing \c QtQuick/Controls sub-directories in
- \l QQmlEngine::importPathList().
-
- \sa addStylePath(), availableStyles()
-*/
-QStringList QQuickStyle::stylePathList()
-{
- return QQuickStylePrivate::stylePaths();
-}
-
-/*!
- \since 5.12
-
- Adds \a path as a directory where Qt Quick Controls 2 searches for available styles.
-
- The \a path may be any local filesystem directory or \l {The Qt Resource System}{Qt Resource} directory.
- For example, the following paths are all valid:
-
- \list
- \li \c {/path/to/styles/}
- \li \c {file:///path/to/styles/}
- \li \c {:/path/to/styles/}
- \li \c {qrc:/path/to/styles/})
- \endlist
-
- The \a path will be converted into \l {QDir::canonicalPath}{canonical form} before it is added to
- the style path list.
-
- The newly added \a path will be first in the stylePathList().
-
- \sa stylePathList(), availableStyles()
-*/
-void QQuickStyle::addStylePath(const QString &path)
-{
- if (path.isEmpty())
- return;
-
- const QUrl url = QUrl(path);
- if (url.isRelative() || url.scheme() == QLatin1String("file")
- || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
- styleSpec()->customStylePaths.prepend(QDir(path).canonicalPath());
- } else if (url.scheme() == QLatin1String("qrc")) {
- styleSpec()->customStylePaths.prepend(QLatin1Char(':') + url.path());
- } else {
- styleSpec()->customStylePaths.prepend(path);
- }
-}
-
QT_END_NAMESPACE