aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quickcontrols/CMakeLists.txt7
-rw-r--r--src/quickcontrols/qmldir2
-rw-r--r--src/quickcontrols/qtquickcontrols2plugin.cpp154
-rw-r--r--tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsFusion/Action.qml4
-rw-r--r--tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsFusion/qmldir3
-rw-r--r--tests/auto/quickcontrols/styleimports/tst_styleimports.cpp27
6 files changed, 170 insertions, 27 deletions
diff --git a/src/quickcontrols/CMakeLists.txt b/src/quickcontrols/CMakeLists.txt
index e5d8e68e39..6eff9b10d3 100644
--- a/src/quickcontrols/CMakeLists.txt
+++ b/src/quickcontrols/CMakeLists.txt
@@ -55,6 +55,13 @@ qt_internal_extend_target(qtquickcontrols2plugin
Qt::QuickTemplates2Private
)
+qt_internal_add_resource(qtquickcontrols2plugin "indirectBasic"
+ PREFIX
+ "/qt-project.org/imports/QtQuick/Controls/IndirectBasic"
+ FILES
+ qmldir
+)
+
if(QT_FEATURE_quick_designer)
add_subdirectory(designer)
endif()
diff --git a/src/quickcontrols/qmldir b/src/quickcontrols/qmldir
new file mode 100644
index 0000000000..02967c0b0f
--- /dev/null
+++ b/src/quickcontrols/qmldir
@@ -0,0 +1,2 @@
+module QtQuick.Controls.IndirectBasic
+import QtQuick.Controls.Basic auto
diff --git a/src/quickcontrols/qtquickcontrols2plugin.cpp b/src/quickcontrols/qtquickcontrols2plugin.cpp
index 8e30e8428b..9a29401841 100644
--- a/src/quickcontrols/qtquickcontrols2plugin.cpp
+++ b/src/quickcontrols/qtquickcontrols2plugin.cpp
@@ -38,6 +38,7 @@ private:
bool customStyle = false;
QString registeredStyleUri;
QString registeredFallbackStyleUri;
+ QString rawFallbackStyleName;
};
static const char *qtQuickControlsUri = "QtQuick.Controls";
@@ -78,6 +79,58 @@ QtQuickControls2Plugin::~QtQuickControls2Plugin()
// initialization and cleanup, as plugins are not unloaded on macOS.
}
+/*!
+ \internal
+
+ If this function is called, it means QtQuick.Controls was imported,
+ and we're doing runtime style selection.
+
+ For example, where:
+ \list
+ \li styleName="Material"
+ \li rawFallbackStyleName=""
+ \li fallbackStyleName="Basic"
+ \li registeredStyleUri="QtQuick.Controls.Material"
+ \li rawFallbackStyleName is empty => parentModule="QtQuick.Controls.Material"
+ \li registeredFallbackStyleUri="QtQuick.Controls.Basic"
+ \endlist
+
+ The following registrations would be made:
+
+ qmlRegisterModuleImport("QtQuick.Controls.Material", "QtQuick.Controls.Basic")
+ qmlRegisterModuleImport("QtQuick.Controls", "QtQuick.Controls.Material")
+
+ As another example, where:
+ \list
+ \li styleName="Material"
+ \li rawFallbackStyleName="Fusion"
+ \li fallbackStyleName="Fusion"
+ \li registeredStyleUri="QtQuick.Controls.Material"
+ \li rawFallbackStyleName is not empty => parentModule="QtQuick.Controls"
+ \li registeredFallbackStyleUri="QtQuick.Controls.Fusion"
+ \endlist
+
+ The following registrations would be made:
+
+ qmlRegisterModuleImport("QtQuick.Controls", "QtQuick.Controls.Fusion")
+ qmlRegisterModuleImport("QtQuick.Controls", "QtQuick.Controls.Material")
+
+ In this case, the Material style imports a fallback (Basic) via the IMPORTS
+ section in its CMakeLists.txt, \e and the user specifies a different fallback
+ using an env var/.conf/C++. We want the user's fallback to take priority,
+ which means we have to place the user-specified fallback at a more immediate place,
+ and that place is as an import of QtQuick.Controls itself rather than as an
+ import of the current style, Material (as we did in the first example).
+
+ If the style to be imported is a custom style and no specific fallback was
+ selected, we need to indirectly import Basic, but we cannot import Basic through
+ the custom style since the versions don't match. For that case we have a
+ "QtQuick.Controls.IndirectBasic" which does nothing but import
+ QtQuick.Controls.Basic. Instead of QtQuick.Controls.Basic we import that one:
+
+ qmlRegisterModuleImport("QtQuick.Controls", "Some.Custom.Style")
+ qmlRegisterModuleImport("QtQuick.Controls", "QtQuick.Controls.IndirectBasic")
+*/
void QtQuickControls2Plugin::registerTypes(const char *uri)
{
qCDebug(lcQtQuickControls2Plugin) << "registerTypes() called with uri" << uri;
@@ -85,34 +138,71 @@ void QtQuickControls2Plugin::registerTypes(const char *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();
+ // The fallback style that was set via env var/.conf/C++.
+ rawFallbackStyleName = QQuickStylePrivate::fallbackStyle();
+ // The style that was set via env var/.conf/C++, or Basic if none was set.
const QString styleName = QQuickStylePrivate::effectiveStyleName(QQuickStyle::name());
- const QString fallbackStyleName = QQuickStylePrivate::effectiveStyleName(QQuickStylePrivate::fallbackStyle());
+ // The effective fallback style: rawFallbackStyleName, or Basic if empty.
+ const QString fallbackStyleName = QQuickStylePrivate::effectiveStyleName(rawFallbackStyleName);
qCDebug(lcQtQuickControls2Plugin) << "style:" << QQuickStyle::name() << "effective style:" << styleName
- << "fallback style:" << QQuickStylePrivate::fallbackStyle() << "effective fallback style:" << fallbackStyleName;
+ << "fallback style:" << rawFallbackStyleName << "effective fallback style:" << fallbackStyleName;
+
+ customStyle = QQuickStylePrivate::isCustomStyle();
+ // The URI of the current style. For built-in styles, the style name is appended to "QtQuick.Controls.".
+ // For custom styles that are embedded in resources, we need to remove the ":/" prefix.
+ registeredStyleUri = ::styleUri();
// If the style is Basic, we don't need to register the fallback because the Basic 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 Basic.
if (styleName != fallbackStyleName && styleName != QLatin1String("Basic")) {
+ // If no specific fallback is given, the fallback is of lower precedence than recursive
+ // imports of the main style (i.e. IMPORTS in a style's CMakeLists.txt).
+ // If a specific fallback is given, it is of higher precedence.
+
+ QString parentModule;
+ QString fallbackModule;
+
+ // The fallback style has to be a built-in style, so it will become "QtQuick.Controls.<fallback>".
registeredFallbackStyleUri = ::fallbackStyleUri();
- qCDebug(lcQtQuickControls2Plugin) << "calling qmlRegisterModuleImport() to register fallback style with"
- << " uri \"" << qtQuickControlsUri << "\" moduleMajor" << QQmlModuleImportModuleAny
- << "import" << registeredFallbackStyleUri << "importMajor" << QQmlModuleImportAuto;
+
+ if (!rawFallbackStyleName.isEmpty()) {
+ parentModule = qtQuickControlsUri;
+ fallbackModule = registeredFallbackStyleUri;
+ } else if (customStyle) {
+ // Since we don't know the versioning scheme of custom styles, but we want the
+ // version of QtQuick.Controls to be propagated, we need to do our own indirection.
+ // QtQuick.Controls.IndirectBasic indirectly imports QtQuick.Controls.Basic
+ Q_ASSERT(registeredFallbackStyleUri == QLatin1String("QtQuick.Controls.Basic"));
+ parentModule = qtQuickControlsUri;
+ fallbackModule = QLatin1String("QtQuick.Controls.IndirectBasic");
+ } else {
+ parentModule = registeredStyleUri;
+ fallbackModule = registeredFallbackStyleUri;
+ }
+
+ qCDebug(lcQtQuickControls2Plugin)
+ << "calling qmlRegisterModuleImport() to register fallback style with"
+ << " uri \"" << parentModule << "\" moduleMajor" << QQmlModuleImportModuleAny
+ << "import" << fallbackModule << "importMajor" << QQmlModuleImportAuto;
+ // Whenever parentModule is imported, registeredFallbackStyleUri will be imported too.
// The fallback style must be a built-in style, so we match the version number.
- qmlRegisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, registeredFallbackStyleUri.toUtf8().constData(),
- QQmlModuleImportAuto, QQmlModuleImportAuto);
+ qmlRegisterModuleImport(parentModule.toUtf8().constData(), QQmlModuleImportModuleAny,
+ fallbackModule.toUtf8().constData(),
+ QQmlModuleImportAuto, QQmlModuleImportAuto);
}
// 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.
- customStyle = QQuickStylePrivate::isCustomStyle();
- registeredStyleUri = ::styleUri();
- const int importMajor = !customStyle ? QQmlModuleImportAuto : QQmlModuleImportLatest;
- qCDebug(lcQtQuickControls2Plugin).nospace() << "calling qmlRegisterModuleImport() to register primary style with"
- << " uri \"" << qtQuickControlsUri << "\" moduleMajor " << importMajor
- << " import " << registeredStyleUri << " importMajor " << importMajor;
- qmlRegisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, registeredStyleUri.toUtf8().constData(), importMajor);
+ const int importMajor = customStyle ? QQmlModuleImportLatest : QQmlModuleImportAuto;
+ qCDebug(lcQtQuickControls2Plugin).nospace()
+ << "calling qmlRegisterModuleImport() to register primary style with"
+ << " uri \"" << qtQuickControlsUri << "\" moduleMajor " << importMajor
+ << " import " << registeredStyleUri << " importMajor " << importMajor;
+ // When QtQuick.Controls is imported, the selected style will be imported too.
+ qmlRegisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny,
+ registeredStyleUri.toUtf8().constData(), importMajor);
if (customStyle)
QFileSelectorPrivate::addStatics(QStringList() << styleName);
@@ -122,15 +212,41 @@ void QtQuickControls2Plugin::unregisterTypes()
{
qCDebug(lcQtQuickControls2Plugin) << "unregisterTypes() called";
+ const int importMajor = customStyle ? QQmlModuleImportLatest : QQmlModuleImportAuto;
+ qCDebug(lcQtQuickControls2Plugin).nospace()
+ << "calling qmlUnregisterModuleImport() to unregister primary style with"
+ << " uri \"" << qtQuickControlsUri << "\" moduleMajor " << importMajor
+ << " import " << registeredStyleUri << " importMajor " << importMajor;
+ qmlUnregisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny,
+ registeredStyleUri.toUtf8().constData(), importMajor);
+
if (!registeredFallbackStyleUri.isEmpty()) {
- // We registered a fallback style, so now we need to unregister it.
- qmlUnregisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, registeredFallbackStyleUri.toUtf8().constData(),
- QQmlModuleImportAuto, QQmlModuleImportAuto);
+ QString parentModule;
+ QString fallbackModule;
+
+ if (!rawFallbackStyleName.isEmpty()) {
+ parentModule = qtQuickControlsUri;
+ fallbackModule = registeredFallbackStyleUri;
+ rawFallbackStyleName.clear();
+ } else if (customStyle) {
+ parentModule = qtQuickControlsUri;
+ fallbackModule = QLatin1String("QtQuick.Controls.IndirectBasic");
+ } else {
+ parentModule = registeredStyleUri;
+ fallbackModule = registeredFallbackStyleUri;
+ }
+
+ qCDebug(lcQtQuickControls2Plugin)
+ << "calling qmlUnregisterModuleImport() to unregister fallback style with"
+ << " uri \"" << parentModule << "\" moduleMajor" << QQmlModuleImportModuleAny
+ << "import" << fallbackModule << "importMajor" << QQmlModuleImportAuto;
+ qmlUnregisterModuleImport(parentModule.toUtf8().constData(), QQmlModuleImportModuleAny,
+ fallbackModule.toUtf8().constData(),
+ QQmlModuleImportAuto, QQmlModuleImportAuto);
+
registeredFallbackStyleUri.clear();
}
- const int importMajor = !customStyle ? QQmlModuleImportAuto : QQmlModuleImportLatest;
- qmlUnregisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, registeredStyleUri.toUtf8().constData(), importMajor);
customStyle = false;
registeredStyleUri.clear();
}
diff --git a/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsFusion/Action.qml b/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsFusion/Action.qml
new file mode 100644
index 0000000000..f0a1459891
--- /dev/null
+++ b/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsFusion/Action.qml
@@ -0,0 +1,4 @@
+import QtQuick.Templates as T
+T.Action {
+ objectName: "StyleThatImportsFusion"
+}
diff --git a/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsFusion/qmldir b/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsFusion/qmldir
new file mode 100644
index 0000000000..824792a4e5
--- /dev/null
+++ b/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsFusion/qmldir
@@ -0,0 +1,3 @@
+module StyleThatImportsFusion
+Action 6.0 Action.qml
+import QtQuick.Controls.Fusion auto
diff --git a/tests/auto/quickcontrols/styleimports/tst_styleimports.cpp b/tests/auto/quickcontrols/styleimports/tst_styleimports.cpp
index dbc56e1022..175541296a 100644
--- a/tests/auto/quickcontrols/styleimports/tst_styleimports.cpp
+++ b/tests/auto/quickcontrols/styleimports/tst_styleimports.cpp
@@ -69,44 +69,52 @@ void tst_StyleImports::select_data()
QTest::newRow("control=Action,style=fs,fallback=empty") << "Action.qml" << "FileSystemStyle" << "" << "FileSystemStyle";
QTest::newRow("control=Action,style=qrc,fallback=empty") << "Action.qml" << "ResourceStyle" << "" << "Basic";
QTest::newRow("control=Action,style=nosuch,fallback=empty") << "Action.qml" << "NoSuchStyle" << "" << "Basic";
+ QTest::newRow("control=Action,style=import,fallback=empty") << "Action.qml" << "StyleThatImportsFusion" << "" << "StyleThatImportsFusion";
QTest::newRow("control=Action,style=basic,fallback=mat") << "Action.qml" << "Basic" << "Material" << "";
QTest::newRow("control=Action,style=fs,fallback=mat") << "Action.qml" << "FileSystemStyle" << "Material" << "FileSystemStyle";
QTest::newRow("control=Action,style=qrc,fallback=mat") << "Action.qml" << "ResourceStyle" << "Material" << "Basic";
QTest::newRow("control=Action,style=nosuch,fallback=mat") << "Action.qml" << "NoSuchStyle" << "Material" << "Basic";
+ QTest::newRow("control=Action,style=import,fallback=mat") << "Action.qml" << "StyleThatImportsFusion" << "Material" << "StyleThatImportsFusion";
// Amongst the styles we're testing here, ScrollView.qml only exists in the Basic style.
QTest::newRow("control=ScrollView,style=basic,fallback=empty") << "ScrollView.qml" << "Basic" << "" << "Basic";
QTest::newRow("control=ScrollView,style=fs,fallback=empty") << "ScrollView.qml" << "FileSystemStyle" << "" << "Basic";
QTest::newRow("control=ScrollView,style=qrc,fallback=empty") << "ScrollView.qml" << "ResourceStyle" << "" << "Basic";
QTest::newRow("control=ScrollView,style=nosuch,fallback=empty") << "ScrollView.qml" << "NoSuchStyle" << "" << "Basic";
+ QTest::newRow("control=ScrollView,style=import,fallback=empty") << "ScrollView.qml" << "StyleThatImportsFusion" << "" << "Fusion";
QTest::newRow("control=ScrollView,style=basic,fallback=mat") << "ScrollView.qml" << "Basic" << "Material" << "Basic";
- QTest::newRow("control=ScrollView,style=fs,fallback=mat") << "ScrollView.qml" << "FileSystemStyle" << "Material" << "Basic";
- QTest::newRow("control=ScrollView,style=qrc,fallback=mat") << "ScrollView.qml" << "ResourceStyle" << "Material" << "Basic";
+ QTest::newRow("control=ScrollView,style=fs,fallback=mat") << "ScrollView.qml" << "FileSystemStyle" << "Material" << "Material";
+ QTest::newRow("control=ScrollView,style=qrc,fallback=mat") << "ScrollView.qml" << "ResourceStyle" << "Material" << "Material";
QTest::newRow("control=ScrollView,style=nosuch,fallback=mat") << "ScrollView.qml" << "NoSuchStyle" << "Material" << "Basic";
+ QTest::newRow("control=ScrollView,style=import,fallback=mat") << "ScrollView.qml" << "StyleThatImportsFusion" << "Material" << "Material";
// Label.qml exists in the FileSystemStyle, Basic and Material styles.
QTest::newRow("control=Label,style=basic,fallback=empty") << "Label.qml" << "Basic" << "" << "Basic";
QTest::newRow("control=Label,style=fs,fallback=empty") << "Label.qml" << "FileSystemStyle" << "" << "FileSystemStyle";
QTest::newRow("control=Label,style=qrc,fallback=empty") << "Label.qml" << "ResourceStyle" << "" << "Basic";
QTest::newRow("control=Label,style=nosuch,fallback=empty") << "Label.qml" << "NoSuchStyle" << "" << "Basic";
+ QTest::newRow("control=Label,style=import,fallback=empty") << "Label.qml" << "StyleThatImportsFusion" << "" << "Fusion";
QTest::newRow("control=Label,style=basic,fallback=mat") << "Label.qml" << "Basic" << "Material" << "Basic";
QTest::newRow("control=Label,style=fs,fallback=mat") << "Label.qml" << "FileSystemStyle" << "Material" << "FileSystemStyle";
- QTest::newRow("control=Label,style=qrc,fallback=mat") << "Label.qml" << "ResourceStyle" << "Material" << "Basic";
+ QTest::newRow("control=Label,style=qrc,fallback=mat") << "Label.qml" << "ResourceStyle" << "Material" << "Material";
QTest::newRow("control=Label,style=nosuch,fallback=mat") << "Label.qml" << "NoSuchStyle" << "Material" << "Basic";
+ QTest::newRow("control=Label,style=import,fallback=mat") << "Label.qml" << "StyleThatImportsFusion" << "Material" << "Material";
// Button.qml exists in all styles including the fs and qrc styles
QTest::newRow("control=Button,style=basic,fallback=empty") << "Button.qml" << "Basic" << "" << "Basic";
QTest::newRow("control=Button,style=fs,fallback=empty") << "Button.qml" << "FileSystemStyle" << "" << "FileSystemStyle";
QTest::newRow("control=Button,style=qrc,fallback=empty") << "Button.qml" << "ResourceStyle" << "" << "ResourceStyle";
QTest::newRow("control=Button,style=nosuch,fallback=empty") << "Button.qml" << "NoSuchStyle" << "" << "Basic";
+ QTest::newRow("control=Button,style=import,fallback=empty") << "Button.qml" << "StyleThatImportsFusion" << "" << "Fusion";
QTest::newRow("control=Button,style=basic,fallback=mat") << "Button.qml" << "Basic" << "Material" << "Basic";
QTest::newRow("control=Button,style=fs,fallback=mat") << "Button.qml" << "FileSystemStyle" << "Material" << "FileSystemStyle";
QTest::newRow("control=Button,style=qrc,fallback=mat") << "Button.qml" << "ResourceStyle" << "Material" << "ResourceStyle";
QTest::newRow("control=Button,style=nosuch,fallback=mat") << "Button.qml" << "NoSuchStyle" << "Material" << "Basic";
+ QTest::newRow("control=Button,style=import,fallback=mat") << "Button.qml" << "StyleThatImportsFusion" << "Material" << "Material";
}
void tst_StyleImports::select()
@@ -144,14 +152,17 @@ void tst_StyleImports::select()
QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
- // TODO: test built-in styles below too
- // We can't check for the attached style object since that API is in a plugin,
- // and it's not possible to use e.g. the baseUrl of the QQmlContext
- // nor the metaObject to test it either.
-
if (!QQuickStylePrivate::builtInStyles().contains(expected)) {
// We're expecting a custom style.
QCOMPARE(object->objectName(), expected);
+ } else {
+ const QUrl expectedUrl(
+ QLatin1String("qrc:///qt-project.org/imports/QtQuick/Controls/%1/%2")
+ .arg(expected, file));
+ QQmlComponent c2(&engine, expectedUrl);
+ QVERIFY2(c2.isReady(), qPrintable(c2.errorString()));
+ QScopedPointer<QObject> o2(c2.create());
+ QCOMPARE(object->metaObject(), o2->metaObject());
}
}