diff options
Diffstat (limited to 'src')
17 files changed, 254 insertions, 431 deletions
diff --git a/src/imports/controls/default/qtquickcontrols2defaultstyleplugin.cpp b/src/imports/controls/default/qtquickcontrols2defaultstyleplugin.cpp index 0ed33d12..a486658e 100644 --- a/src/imports/controls/default/qtquickcontrols2defaultstyleplugin.cpp +++ b/src/imports/controls/default/qtquickcontrols2defaultstyleplugin.cpp @@ -38,6 +38,7 @@ #include "qquickdefaulttheme_p.h" #include <QtQuickControls2/private/qquickstyleplugin_p.h> +#include <QtQuickTemplates2/private/qquicktheme_p.h> QT_BEGIN_NAMESPACE @@ -50,7 +51,10 @@ public: QtQuickControls2DefaultStylePlugin(QObject *parent = nullptr); QString name() const override; - void initializeTheme(QQuickTheme *theme) override; + + void registerTypes(const char *uri) override; + + QQuickDefaultTheme theme; }; QtQuickControls2DefaultStylePlugin::QtQuickControls2DefaultStylePlugin(QObject *parent) : QQuickStylePlugin(parent) @@ -62,9 +66,11 @@ QString QtQuickControls2DefaultStylePlugin::name() const return QStringLiteral("Default"); } -void QtQuickControls2DefaultStylePlugin::initializeTheme(QQuickTheme *theme) +void QtQuickControls2DefaultStylePlugin::registerTypes(const char *uri) { - QQuickDefaultTheme::initialize(theme); + QQuickStylePlugin::registerTypes(uri); + + theme.initialize(QQuickTheme::instance()); } QT_END_NAMESPACE diff --git a/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc index 6ab649d0..58138a07 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc @@ -112,7 +112,7 @@ \section2 Definition of a Style In Qt Quick Controls, a style is essentially an interchangeable set of - QML files within a single directory. There are three requirements for a style + QML files within a single directory. There are four requirements for a style to be \l {Using Styles in Qt Quick Controls}{usable}: \list @@ -125,21 +125,37 @@ If we instead used the corresponding type from the \l {Qt Quick Controls} {QtQuick.Controls} import as we did in the previous section, it would not work: the control we were defining would try to derive from itself. - \li The files must be in a directory in the filesystem or in the - \l {The Qt Resource System}{resource system}. + \li A \l {Module Definition qmldir Files}{qmldir} file must exist alongside + the QML file(s). Below is an example of a simple \c qmldir file for a style that + provides a button: - For example, these are all valid paths to a style: + \badcode + module MyStyle + Button 2.15 Button.qml + \endcode + + The directory structure for such a style looks like this: + + \badcode + MyStyle + ├─── Button.qml + └─── qmldir + \endcode + \li The files must be in a directory that is findable via the \l {QML Import Path}. + + For example, if the path to \e MyStyle directory mentioned above was + \c /home/user/MyApp/MyStyle, then \c /home/user/MyApp must be added to + the QML import path. + + To \l {Using Styles in Qt Quick Controls}{use} \e MyStyle in \e MyApp, + refer to it by name: \list - \li \c {./myapp -style /home/absolute/path/to/my/style} - \li \c {./myapp -style :/mystyle} - \li \c {./myapp -style relative/path/to/my/style} - \li \c {./myapp -style MyStyle} + \li \c {./MyApp -style MyStyle} \endlist - The third and fourth paths will be looked up within the QML engine's import path - list. This is the same as what happens when you pass \c Material as the style, - for example. + The style name must match the casing of the style directory; passing + \e mystyle or \e MYSTYLE is not supported. \endlist By default, the styling system uses the Default style as a fallback for @@ -302,7 +318,7 @@ style will illustrate the elevation with a drop shadow; the higher the elevation, the larger the shadow. - The first step is to \l {Qt Creator: Creating Qt Quick Projects}{create a new Qt Quick + The first step is to \l {Creating Qt Quick Projects}{create a new Qt Quick Controls 2 application} in Qt Creator. After that, we \l {Qt Creator: Creating C++ Classes}{add a C++ type} that stores the elevation. Since the type will be used for every control supported by our style, and because @@ -390,6 +406,8 @@ qmlRegisterUncreatableType<MyStyle>("MyStyle", 1, 0, "MyStyle", "MyStyle is an attached property"); QQmlApplicationEngine engine; + // Make the directory containing our style known to the QML engine. + engine.addImportPath(":/"); engine.load(QUrl(QLatin1String("qrc:/main.qml"))); return app.exec(); @@ -465,7 +483,7 @@ One button has no elevation, and the other has an elevation of \c 10. With that in place, we can run our example. To tell the application to - use our new style, we pass \c {-style :/mystyle} as an application + use our new style, we pass \c {-style MyStyle} as an application argument, but there are \l {Using Styles in Qt Quick Controls}{many ways} to specify the style to use. diff --git a/src/imports/controls/doc/src/qtquickcontrols2-environment.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-environment.qdoc index e1461ee4..4484acf3 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-environment.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-environment.qdoc @@ -41,18 +41,12 @@ \li \c QT_QUICK_CONTROLS_STYLE \li Specifies the default \l {Styling Qt Quick Controls}{Qt Quick Controls style}. The value can be either one of the built-in styles, for example \c "Material", - or the path to a custom style such as \c ":/mystyle". + or a custom style such as \c "MyStyle". \row \li \c QT_QUICK_CONTROLS_FALLBACK_STYLE \li Specifies a fallback style for \l {Creating a Custom Style}{custom styles}. The value can be one of the built-in styles, for example \c "Material", \row - \li \c QT_QUICK_CONTROLS_STYLE_PATH - \li Specifies a list of additional paths that are used to lookup \l {Styling Qt Quick Controls} - {Qt Quick Controls styles}. Multiple path entries must be \l {QDir::listSeparator}{separated} - by \c ':' under Unix and \c ';' under Windows. By default, styles are looked up from - \c $QML2_IMPORT_PATH/QtQuick/Controls. - \row \li \c QT_QUICK_CONTROLS_CONF \li Specifies the location of the \l {Qt Quick Controls configuration file}. By default, the configuration file is loaded from the application's diff --git a/src/imports/controls/fusion/qmldir b/src/imports/controls/fusion/qmldir index 572a6dd2..84c0b211 100644 --- a/src/imports/controls/fusion/qmldir +++ b/src/imports/controls/fusion/qmldir @@ -1,7 +1,7 @@ module QtQuick.Controls.Fusion plugin qtquickcontrols2fusionstyleplugin classname QtQuickControls2FusionStylePlugin -depends QtQuick.Controls 2.5 +import QtQuick.Controls.Default auto # QtQuick.Controls 2.0 (originally introduced in Qt 5.7) ApplicationWindow 2.0 ApplicationWindow.qml diff --git a/src/imports/controls/fusion/qtquickcontrols2fusionstyleplugin.cpp b/src/imports/controls/fusion/qtquickcontrols2fusionstyleplugin.cpp index b9df2e7d..c70c9602 100644 --- a/src/imports/controls/fusion/qtquickcontrols2fusionstyleplugin.cpp +++ b/src/imports/controls/fusion/qtquickcontrols2fusionstyleplugin.cpp @@ -34,12 +34,13 @@ ** ****************************************************************************/ -#include <QtQuickControls2/private/qquickstyleplugin_p.h> -#include <QtQml/qqml.h> - #include "qquickfusionstyle_p.h" #include "qquickfusiontheme_p.h" +#include <QtQml/qqml.h> +#include <QtQuickControls2/private/qquickstyleplugin_p.h> +#include <QtQuickTemplates2/private/qquicktheme_p.h> + QT_BEGIN_NAMESPACE class QtQuickControls2FusionStylePlugin : public QQuickStylePlugin @@ -51,7 +52,10 @@ public: QtQuickControls2FusionStylePlugin(QObject *parent = nullptr); QString name() const override; - void initializeTheme(QQuickTheme *theme) override; + + void registerTypes(const char *uri) override; + + QQuickFusionTheme theme; }; QtQuickControls2FusionStylePlugin::QtQuickControls2FusionStylePlugin(QObject *parent) : QQuickStylePlugin(parent) @@ -63,9 +67,11 @@ QString QtQuickControls2FusionStylePlugin::name() const return QStringLiteral("Fusion"); } -void QtQuickControls2FusionStylePlugin::initializeTheme(QQuickTheme *theme) +void QtQuickControls2FusionStylePlugin::registerTypes(const char *uri) { - QQuickFusionTheme::initialize(theme); + QQuickStylePlugin::registerTypes(uri); + + theme.initialize(QQuickTheme::instance()); } QT_END_NAMESPACE diff --git a/src/imports/controls/imagine/qmldir b/src/imports/controls/imagine/qmldir index 380a0dc3..e3d7d8d5 100644 --- a/src/imports/controls/imagine/qmldir +++ b/src/imports/controls/imagine/qmldir @@ -1,7 +1,7 @@ module QtQuick.Controls.Imagine plugin qtquickcontrols2imaginestyleplugin classname QtQuickControls2ImagineStylePlugin -depends QtQuick.Controls 2.5 +import QtQuick.Controls.Default auto # QtQuick.Controls 2.0 (originally introduced in Qt 5.7) ApplicationWindow 2.0 ApplicationWindow.qml diff --git a/src/imports/controls/imagine/qtquickcontrols2imaginestyleplugin.cpp b/src/imports/controls/imagine/qtquickcontrols2imaginestyleplugin.cpp index d59cf555..0c864254 100644 --- a/src/imports/controls/imagine/qtquickcontrols2imaginestyleplugin.cpp +++ b/src/imports/controls/imagine/qtquickcontrols2imaginestyleplugin.cpp @@ -34,13 +34,14 @@ ** ****************************************************************************/ -#include <QtQuickControls2/private/qquickstyleplugin_p.h> -#include <QtCore/qloggingcategory.h> -#include <QtQml/qqml.h> - #include "qquickimaginestyle_p.h" #include "qquickimaginetheme_p.h" +#include <QtCore/qloggingcategory.h> +#include <QtQml/qqml.h> +#include <QtQuickControls2/private/qquickstyleplugin_p.h> +#include <QtQuickTemplates2/private/qquicktheme_p.h> + QT_BEGIN_NAMESPACE class QtQuickControls2ImagineStylePlugin : public QQuickStylePlugin @@ -52,7 +53,10 @@ public: QtQuickControls2ImagineStylePlugin(QObject *parent = nullptr); QString name() const override; - void initializeTheme(QQuickTheme *theme) override; + + void registerTypes(const char *uri) override; + + QQuickImagineTheme theme; }; QtQuickControls2ImagineStylePlugin::QtQuickControls2ImagineStylePlugin(QObject *parent) : QQuickStylePlugin(parent) @@ -64,9 +68,11 @@ QString QtQuickControls2ImagineStylePlugin::name() const return QStringLiteral("Imagine"); } -void QtQuickControls2ImagineStylePlugin::initializeTheme(QQuickTheme *theme) +void QtQuickControls2ImagineStylePlugin::registerTypes(const char *uri) { - QQuickImagineTheme::initialize(theme); + QQuickStylePlugin::registerTypes(uri); + + theme.initialize(QQuickTheme::instance()); } QT_END_NAMESPACE diff --git a/src/imports/controls/material/qmldir b/src/imports/controls/material/qmldir index a1064229..39dae48a 100644 --- a/src/imports/controls/material/qmldir +++ b/src/imports/controls/material/qmldir @@ -1,7 +1,7 @@ module QtQuick.Controls.Material plugin qtquickcontrols2materialstyleplugin classname QtQuickControls2MaterialStylePlugin -depends QtQuick.Controls 2.5 +import QtQuick.Controls.Default auto # QtQuick.Controls 2.0 (originally introduced in Qt 5.7) ApplicationWindow 2.0 ApplicationWindow.qml diff --git a/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp b/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp index dc6873bb..6066d3f5 100644 --- a/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp +++ b/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp @@ -34,12 +34,12 @@ ** ****************************************************************************/ -#include <QtQuickControls2/private/qquickstyleplugin_p.h> - #include "qquickmaterialstyle_p.h" #include "qquickmaterialtheme_p.h" +#include <QtQuickControls2/private/qquickstyleplugin_p.h> #include <QtQuickControls2Impl/private/qquickpaddedrectangle_p.h> +#include <QtQuickTemplates2/private/qquicktheme_p.h> QT_BEGIN_NAMESPACE @@ -52,12 +52,14 @@ public: QtQuickControls2MaterialStylePlugin(QObject *parent = nullptr); QString name() const override; - void initializeTheme(QQuickTheme *theme) override; + + void registerTypes(const char *uri) override; + + QQuickMaterialTheme theme; }; QtQuickControls2MaterialStylePlugin::QtQuickControls2MaterialStylePlugin(QObject *parent) : QQuickStylePlugin(parent) { - QQuickMaterialStyle::initGlobals(); } QString QtQuickControls2MaterialStylePlugin::name() const @@ -65,9 +67,12 @@ QString QtQuickControls2MaterialStylePlugin::name() const return QStringLiteral("Material"); } -void QtQuickControls2MaterialStylePlugin::initializeTheme(QQuickTheme *theme) +void QtQuickControls2MaterialStylePlugin::registerTypes(const char *uri) { - QQuickMaterialTheme::initialize(theme); + QQuickStylePlugin::registerTypes(uri); + + QQuickMaterialStyle::initGlobals(); + theme.initialize(QQuickTheme::instance()); } QT_END_NAMESPACE diff --git a/src/imports/controls/qtquickcontrols2plugin.cpp b/src/imports/controls/qtquickcontrols2plugin.cpp index 17eb2be9..ef642905 100644 --- a/src/imports/controls/qtquickcontrols2plugin.cpp +++ b/src/imports/controls/qtquickcontrols2plugin.cpp @@ -37,6 +37,7 @@ #include <QtCore/qdir.h> #include <QtCore/qfile.h> #include <QtCore/qfileinfo.h> +#include <QtCore/qloggingcategory.h> #include <QtCore/qpluginloader.h> #include <QtCore/private/qfileselector_p.h> #include <QtQml/qqmlfile.h> @@ -50,6 +51,8 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcQtQuickControlsStylePlugin, "qt.quick.controls.qtquickcontrols2plugin") + class QtQuickControls2Plugin : public QQmlExtensionPlugin { Q_OBJECT @@ -59,17 +62,41 @@ public: QtQuickControls2Plugin(QObject *parent = nullptr); ~QtQuickControls2Plugin(); - void initializeEngine(QQmlEngine *engine, const char *uri) override; void registerTypes(const char *uri) override; void unregisterTypes() override; private: - void init(); - - QList<QQuickStylePlugin *> loadStylePlugins(); QQuickTheme *createTheme(const QString &name); + + bool registeredFallbackImport = false; }; +static const char *qtQuickControlsUri = "QtQuick.Controls"; + +QString styleUri() +{ + const QString style = QQuickStyle::name(); + if (!QQuickStylePrivate::isCustomStyle()) { + // The style set is a built-in style. + const QString styleName = QQuickStylePrivate::effectiveStyleName(style); + return QString::fromLatin1("QtQuick.Controls.%1").arg(styleName); + } + + // This is a custom style, so just use the name as the import uri. + QString styleName = style; + if (styleName.startsWith(QLatin1String(":/"))) + styleName.remove(0, 2); + return styleName; +} + +QString fallbackStyleUri() +{ + // The fallback style must be a built-in style, so we don't need to check for custom styles here. + const QString fallbackStyle = QQuickStylePrivate::fallbackStyle(); + const QString fallbackStyleName = QQuickStylePrivate::effectiveStyleName(fallbackStyle); + return QString::fromLatin1("QtQuick.Controls.%1").arg(fallbackStyleName); +} + QtQuickControls2Plugin::QtQuickControls2Plugin(QObject *parent) : QQmlExtensionPlugin(parent) { } @@ -80,88 +107,83 @@ QtQuickControls2Plugin::~QtQuickControls2Plugin() // initialization and cleanup, as plugins are not unloaded on macOS. } -void QtQuickControls2Plugin::initializeEngine(QQmlEngine *engine, const char */*uri*/) +void QtQuickControls2Plugin::registerTypes(const char *uri) { - engine->addUrlInterceptor(&QQuickStylePrivate::urlInterceptor); - init(); -} + qCDebug(lcQtQuickControlsStylePlugin) << "registerTypes() called with uri" << uri; + + // It's OK that the style is resolved more than once; some accessors like name() cause it to be called, for example. + QQuickStylePrivate::init(); + + const QString styleName = QQuickStylePrivate::effectiveStyleName(QQuickStyle::name()); + const QString fallbackStyleName = QQuickStylePrivate::effectiveStyleName(QQuickStylePrivate::fallbackStyle()); + qCDebug(lcQtQuickControlsStylePlugin) << "style:" << QQuickStyle::name() << "effective style:" << styleName + << "fallback style:" << QQuickStylePrivate::fallbackStyle() << "effective fallback style:" << fallbackStyleName; + + createTheme(styleName); + + // If the style is Default, we don't need to register the fallback because the Default style + // provides all controls. Also, if we didn't return early here, we can get an infinite import loop + // when the style is set to Default. + if (styleName != fallbackStyleName && styleName != QLatin1String("Default")) { + const QString fallbackstyleUri = ::fallbackStyleUri(); + qCDebug(lcQtQuickControlsStylePlugin) << "calling qmlRegisterModuleImport() to register fallback style with" + << "uri \"" << qtQuickControlsUri << "\" moduleMajor" << QQmlModuleImportModuleAny << "import" << fallbackstyleUri + << "importMajor" << QQmlModuleImportAuto; + // The fallback style must be a built-in style, so we match the version number. + qmlRegisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, fallbackstyleUri.toUtf8().constData(), + QQmlModuleImportAuto, QQmlModuleImportAuto); + registeredFallbackImport = true; + } -void QtQuickControls2Plugin::registerTypes(const char */*uri*/) -{ - QQuickStylePrivate::init(baseUrl()); + const QString styleUri = ::styleUri(); + // If the user imports QtQuick.Controls 2.15, and they're using the Material style, we should import version 2.15. + // However, if they import QtQuick.Controls 2.15, but are using a custom style, we want to use the latest version + // number of their style. + const int importMajor = !QQuickStylePrivate::isCustomStyle() ? QQmlModuleImportAuto : QQmlModuleImportLatest; + qCDebug(lcQtQuickControlsStylePlugin).nospace() << "calling qmlRegisterModuleImport() to register primary style with" + << " uri \"" << qtQuickControlsUri << "\" moduleMajor " << importMajor << " import " << styleUri + << " importMajor " << importMajor; + qmlRegisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, styleUri.toUtf8().constData(), importMajor); const QString style = QQuickStyle::name(); if (!style.isEmpty()) - QFileSelectorPrivate::addStatics(QStringList() << style.toLower()); + QFileSelectorPrivate::addStatics(QStringList() << style); } void QtQuickControls2Plugin::unregisterTypes() { + qCDebug(lcQtQuickControlsStylePlugin) << "unregisterTypes() called"; + + if (registeredFallbackImport) { + const QString fallbackStyleUri = ::fallbackStyleUri(); + qmlUnregisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, fallbackStyleUri.toUtf8().constData(), + QQmlModuleImportAuto, QQmlModuleImportAuto); + } + + const QString primary = QQuickStylePrivate::effectiveStyleName(QQuickStyle::name()); + const QString styleUri = ::styleUri(); + const int importMajor = !QQuickStylePrivate::isCustomStyle() ? QQmlModuleImportAuto : QQmlModuleImportLatest; + qmlUnregisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, styleUri.toUtf8().constData(), importMajor); + QQuickStylePrivate::reset(); } -void QtQuickControls2Plugin::init() -{ - const QString style = QQuickStyle::name(); - QQuickTheme *theme = createTheme(style.isEmpty() ? QLatin1String("Default") : style); +/*! + \internal - // load the style's plugins to get access to its resources and initialize the theme - QList<QQuickStylePlugin *> stylePlugins = loadStylePlugins(); - for (QQuickStylePlugin *stylePlugin : stylePlugins) - stylePlugin->initializeTheme(theme); - qDeleteAll(stylePlugins); -} + Responsible for setting the font and palette settings that were specified in the + qtquickcontrols2.conf file. -QList<QQuickStylePlugin *> QtQuickControls2Plugin::loadStylePlugins() -{ - QList<QQuickStylePlugin *> stylePlugins; - - QFileInfo fileInfo = QQmlFile::urlToLocalFileOrQrc(resolvedUrl(QStringLiteral("qmldir"))); - if (fileInfo.exists() && fileInfo.path() != QQmlFile::urlToLocalFileOrQrc(baseUrl())) { - QFile file(fileInfo.filePath()); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QQmlDirParser parser; - parser.parse(QString::fromUtf8(file.readAll())); - if (!parser.hasError()) { -#ifdef QT_STATIC - const auto plugins = QPluginLoader::staticInstances(); - for (QObject *instance : plugins) { - QQuickStylePlugin *stylePlugin = qobject_cast<QQuickStylePlugin *>(instance); - if (!stylePlugin || !parser.classNames().contains(QLatin1String(instance->metaObject()->className()))) - continue; - stylePlugins += stylePlugin; - } -#elif QT_CONFIG(library) - QPluginLoader loader; - const auto plugins = parser.plugins(); - for (const QQmlDirParser::Plugin &plugin : plugins) { - QDir dir = fileInfo.dir(); - if (!plugin.path.isEmpty() && !dir.cd(plugin.path)) - continue; - QString filePath = dir.filePath(plugin.name); -#if defined(Q_OS_MACOS) && defined(QT_DEBUG) - // Avoid mismatching plugins on macOS so that we don't end up loading both debug and - // release versions of the same Qt libraries (due to the plugin's dependencies). - filePath += QStringLiteral("_debug"); -#endif // Q_OS_MACOS && QT_DEBUG -#if defined(Q_OS_WIN) && defined(QT_DEBUG) - // Debug versions of plugins have a "d" prefix on Windows. - filePath += QLatin1Char('d'); -#endif // Q_OS_WIN && QT_DEBUG - loader.setFileName(filePath); - QQuickStylePlugin *stylePlugin = qobject_cast<QQuickStylePlugin *>(loader.instance()); - if (stylePlugin) - stylePlugins += stylePlugin; - } -#endif - } - } - } - return stylePlugins; -} + Style-specific settings (e.g. Variant=Dense) are read in the constructor of the + appropriate style plugin (e.g. QtQuickControls2MaterialStylePlugin). + Implicit style-specific font and palette values are assigned in the relevant theme + (e.g. QQuickMaterialTheme). +*/ QQuickTheme *QtQuickControls2Plugin::createTheme(const QString &name) { + qCDebug(lcQtQuickControlsStylePlugin) << "creating QQuickTheme instance to be initialized by style-specific theme of" << name; + QQuickTheme *theme = new QQuickTheme; #if QT_CONFIG(settings) QQuickThemePrivate *p = QQuickThemePrivate::get(theme); diff --git a/src/imports/controls/universal/qmldir b/src/imports/controls/universal/qmldir index 28bd5706..e2faf020 100644 --- a/src/imports/controls/universal/qmldir +++ b/src/imports/controls/universal/qmldir @@ -1,7 +1,7 @@ module QtQuick.Controls.Universal plugin qtquickcontrols2universalstyleplugin classname QtQuickControls2UniversalStylePlugin -depends QtQuick.Controls 2.5 +import QtQuick.Controls.Default auto # QtQuick.Controls 2.0 (originally introduced in Qt 5.7) ApplicationWindow 2.0 ApplicationWindow.qml diff --git a/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp b/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp index ac154911..d6f7746d 100644 --- a/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp +++ b/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp @@ -34,11 +34,12 @@ ** ****************************************************************************/ -#include <QtQuickControls2/private/qquickstyleplugin_p.h> - #include "qquickuniversalstyle_p.h" #include "qquickuniversaltheme_p.h" +#include <QtQuickControls2/private/qquickstyleplugin_p.h> +#include <QtQuickTemplates2/private/qquicktheme_p.h> + QT_BEGIN_NAMESPACE class QtQuickControls2UniversalStylePlugin : public QQuickStylePlugin @@ -50,12 +51,14 @@ public: QtQuickControls2UniversalStylePlugin(QObject *parent = nullptr); QString name() const override; - void initializeTheme(QQuickTheme *theme) override; + + void registerTypes(const char *uri) override; + + QQuickUniversalTheme theme; }; QtQuickControls2UniversalStylePlugin::QtQuickControls2UniversalStylePlugin(QObject *parent) : QQuickStylePlugin(parent) { - QQuickUniversalStyle::initGlobals(); } QString QtQuickControls2UniversalStylePlugin::name() const @@ -63,9 +66,12 @@ QString QtQuickControls2UniversalStylePlugin::name() const return QStringLiteral("Universal"); } -void QtQuickControls2UniversalStylePlugin::initializeTheme(QQuickTheme *theme) +void QtQuickControls2UniversalStylePlugin::registerTypes(const char *uri) { - QQuickUniversalTheme::initialize(theme); + QQuickStylePlugin::registerTypes(uri); + + QQuickUniversalStyle::initGlobals(); + theme.initialize(QQuickTheme::instance()); } QT_END_NAMESPACE 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 diff --git a/src/quickcontrols2/qquickstyle.h b/src/quickcontrols2/qquickstyle.h index ce55b76b..e26ec90b 100644 --- a/src/quickcontrols2/qquickstyle.h +++ b/src/quickcontrols2/qquickstyle.h @@ -47,12 +47,8 @@ class Q_QUICKCONTROLS2_EXPORT QQuickStyle { public: static QString name(); - static QString path(); static void setStyle(const QString &style); static void setFallbackStyle(const QString &style); - static QStringList availableStyles(); - static QStringList stylePathList(); - static void addStylePath(const QString &path); }; QT_END_NAMESPACE diff --git a/src/quickcontrols2/qquickstyle_p.h b/src/quickcontrols2/qquickstyle_p.h index 7c837423..e2db35d7 100644 --- a/src/quickcontrols2/qquickstyle_p.h +++ b/src/quickcontrols2/qquickstyle_p.h @@ -48,7 +48,6 @@ // We mean it. // -#include <QtCore/qurl.h> #include <QtCore/qsharedpointer.h> #include <QtQuickControls2/qtquickcontrols2global.h> @@ -59,16 +58,19 @@ class QSettings; class Q_QUICKCONTROLS2_EXPORT QQuickStylePrivate { public: - static QStringList stylePaths(bool resolve = false); + static QString effectiveStyleName(const QString &styleName); static QString fallbackStyle(); static bool isCustomStyle(); - static void init(const QUrl &baseUrl); + static bool isResolved(); + static bool exists(); + static void init(); static void reset(); static QString configFilePath(); static QSharedPointer<QSettings> settings(const QString &group = QString()); static const QFont *readFont(const QSharedPointer<QSettings> &settings); static const QPalette *readPalette(const QSharedPointer<QSettings> &settings); static bool isDarkSystemTheme(); + static QStringList builtInStyles(); }; QT_END_NAMESPACE diff --git a/src/quickcontrols2/qquickstyleplugin.cpp b/src/quickcontrols2/qquickstyleplugin.cpp index 18f0d485..1f1c3875 100644 --- a/src/quickcontrols2/qquickstyleplugin.cpp +++ b/src/quickcontrols2/qquickstyleplugin.cpp @@ -34,14 +34,20 @@ ** ****************************************************************************/ +#include "qquickstyle.h" #include "qquickstyle_p.h" #include "qquickstyleplugin_p.h" +#include <QtCore/qloggingcategory.h> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlfile.h> +#include <QtQuickTemplates2/private/qquicktheme_p_p.h> + QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcStylePlugin, "qt.quick.controls.styleplugin") + QQuickStylePlugin::QQuickStylePlugin(QObject *parent) : QQmlExtensionPlugin(parent) { @@ -56,4 +62,14 @@ QString QQuickStylePlugin::name() const return QString(); } +void QQuickStylePlugin::registerTypes(const char *uri) +{ + qCDebug(lcStylePlugin).nospace() << "registerTypes called with uri " << uri << "; plugin name is " << name(); +} + +void QQuickStylePlugin::unregisterTypes() +{ + qCDebug(lcStylePlugin) << "unregisterTypes called; plugin name is" << name(); +} + QT_END_NAMESPACE diff --git a/src/quickcontrols2/qquickstyleplugin_p.h b/src/quickcontrols2/qquickstyleplugin_p.h index 7ae129d9..37d070db 100644 --- a/src/quickcontrols2/qquickstyleplugin_p.h +++ b/src/quickcontrols2/qquickstyleplugin_p.h @@ -64,9 +64,9 @@ public: ~QQuickStylePlugin(); virtual QString name() const; - virtual void initializeTheme(QQuickTheme *theme) = 0; void registerTypes(const char *uri) override; + void unregisterTypes() override; private: Q_DISABLE_COPY(QQuickStylePlugin) |