Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtquickcontrols2plugin.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include <QtCore/private/qfileselector_p.h>
6#include <QtCore/qloggingcategory.h>
7#include <QtQml/qqmlengine.h>
8#include <QtQml/qqmlextensionplugin.h>
9#include <QtQuickTemplates2/private/qquicktheme_p_p.h>
10#include <QtQuickControls2/private/qquickstyle_p.h>
11#include <QtQuickControls2/private/qquickstyleplugin_p.h>
12#include <QtQuickControls2/qquickstyle.h>
13#include <QtQuickControls2/qtquickcontrols2global.h>
14
16
18
19Q_LOGGING_CATEGORY(lcQtQuickControls2Plugin, "qt.quick.controls.qtquickcontrols2plugin")
20
22{
23 Q_OBJECT
24 Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
25
26public:
29
30 void registerTypes(const char *uri) override;
32
33private:
34 // We store these because the style plugins can be unregistered before
35 // QtQuickControls2Plugin, and since QQuickStylePlugin calls QQuickStylePrivate::reset(),
36 // the style information can be lost when it comes time to call qmlUnregisterModuleImport().
37 // It also avoids unnecessarily resolving the style after resetting it just to get the style
38 // name in unregisterTypes().
39 bool customStyle = false;
40 QString registeredStyleUri;
41 QString registeredFallbackStyleUri;
42 QString rawFallbackStyleName;
43};
44
45static const char *qtQuickControlsUri = "QtQuick.Controls";
46
48{
49 const QString style = QQuickStyle::name();
50 if (!QQuickStylePrivate::isCustomStyle()) {
51 // The style set is a built-in style.
52 const QString styleName = QQuickStylePrivate::effectiveStyleName(style);
53 return QString::fromLatin1("QtQuick.Controls.%1").arg(styleName);
54 }
55
56 // This is a custom style, so just use the name as the import uri.
57 QString styleName = style;
58 if (styleName.startsWith(QLatin1String(":/")))
59 styleName.remove(0, 2);
60 return styleName;
61}
62
64{
65 // The fallback style must be a built-in style, so we don't need to check for custom styles here.
66 const QString fallbackStyle = QQuickStylePrivate::fallbackStyle();
67 const QString fallbackStyleName = QQuickStylePrivate::effectiveStyleName(fallbackStyle);
68 return QString::fromLatin1("QtQuick.Controls.%1").arg(fallbackStyleName);
69}
70
71QtQuickControls2Plugin::QtQuickControls2Plugin(QObject *parent) : QQmlExtensionPlugin(parent)
72{
73 volatile auto registration = &qml_register_types_QtQuick_Controls;
74 Q_UNUSED(registration);
75}
76
78{
79 // Intentionally empty: we use register/unregisterTypes() to do
80 // initialization and cleanup, as plugins are not unloaded on macOS.
81}
82
83/*!
84 \internal
85
86 If this function is called, it means QtQuick.Controls was imported,
87 and we're doing runtime style selection.
88
89 For example, where:
90 \list
91 \li styleName="Material"
92 \li rawFallbackStyleName=""
93 \li fallbackStyleName="Basic"
94 \li registeredStyleUri="QtQuick.Controls.Material"
95 \li rawFallbackStyleName is empty => parentModule="QtQuick.Controls.Material"
96 \li registeredFallbackStyleUri="QtQuick.Controls.Basic"
97 \endlist
98
99 The following registrations would be made:
100
101 qmlRegisterModuleImport("QtQuick.Controls.Material", "QtQuick.Controls.Basic")
102 qmlRegisterModuleImport("QtQuick.Controls", "QtQuick.Controls.Material")
103
104 As another example, where:
105 \list
106 \li styleName="Material"
107 \li rawFallbackStyleName="Fusion"
108 \li fallbackStyleName="Fusion"
109 \li registeredStyleUri="QtQuick.Controls.Material"
110 \li rawFallbackStyleName is not empty => parentModule="QtQuick.Controls"
111 \li registeredFallbackStyleUri="QtQuick.Controls.Fusion"
112 \endlist
113
114 The following registrations would be made:
115
116 qmlRegisterModuleImport("QtQuick.Controls", "QtQuick.Controls.Fusion")
117 qmlRegisterModuleImport("QtQuick.Controls", "QtQuick.Controls.Material")
118
119 In this case, the Material style imports a fallback (Basic) via the IMPORTS
120 section in its CMakeLists.txt, \e and the user specifies a different fallback
121 using an env var/.conf/C++. We want the user's fallback to take priority,
122 which means we have to place the user-specified fallback at a more immediate place,
123 and that place is as an import of QtQuick.Controls itself rather than as an
124 import of the current style, Material (as we did in the first example).
125
126 If the style to be imported is a custom style and no specific fallback was
127 selected, we need to indirectly import Basic, but we cannot import Basic through
128 the custom style since the versions don't match. For that case we have a
129 "QtQuick.Controls.IndirectBasic" which does nothing but import
130 QtQuick.Controls.Basic. Instead of QtQuick.Controls.Basic we import that one:
131
132 qmlRegisterModuleImport("QtQuick.Controls", "Some.Custom.Style")
133 qmlRegisterModuleImport("QtQuick.Controls", "QtQuick.Controls.IndirectBasic")
134*/
136{
137 qCDebug(lcQtQuickControls2Plugin) << "registerTypes() called with uri" << uri;
138
139 // It's OK that the style is resolved more than once; some accessors like name() cause it to be called, for example.
140 QQuickStylePrivate::init();
141
142 // The fallback style that was set via env var/.conf/C++.
143 rawFallbackStyleName = QQuickStylePrivate::fallbackStyle();
144 // The style that was set via env var/.conf/C++, or Basic if none was set.
145 const QString styleName = QQuickStylePrivate::effectiveStyleName(QQuickStyle::name());
146 // The effective fallback style: rawFallbackStyleName, or Basic if empty.
147 const QString fallbackStyleName = QQuickStylePrivate::effectiveStyleName(rawFallbackStyleName);
148 qCDebug(lcQtQuickControls2Plugin) << "style:" << QQuickStyle::name() << "effective style:" << styleName
149 << "fallback style:" << rawFallbackStyleName << "effective fallback style:" << fallbackStyleName;
150
151 customStyle = QQuickStylePrivate::isCustomStyle();
152 // The URI of the current style. For built-in styles, the style name is appended to "QtQuick.Controls.".
153 // For custom styles that are embedded in resources, we need to remove the ":/" prefix.
154 registeredStyleUri = ::styleUri();
155
156 // If the style is Basic, we don't need to register the fallback because the Basic style
157 // provides all controls. Also, if we didn't return early here, we can get an infinite import loop
158 // when the style is set to Basic.
159 if (styleName != fallbackStyleName && styleName != QLatin1String("Basic")) {
160 // If no specific fallback is given, the fallback is of lower precedence than recursive
161 // imports of the main style (i.e. IMPORTS in a style's CMakeLists.txt).
162 // If a specific fallback is given, it is of higher precedence.
163
164 QString parentModule;
165 QString fallbackModule;
166
167 // The fallback style has to be a built-in style, so it will become "QtQuick.Controls.<fallback>".
168 registeredFallbackStyleUri = ::fallbackStyleUri();
169
170 if (!rawFallbackStyleName.isEmpty()) {
171 parentModule = qtQuickControlsUri;
172 fallbackModule = registeredFallbackStyleUri;
173 } else if (customStyle) {
174 // Since we don't know the versioning scheme of custom styles, but we want the
175 // version of QtQuick.Controls to be propagated, we need to do our own indirection.
176 // QtQuick.Controls.IndirectBasic indirectly imports QtQuick.Controls.Basic
177 Q_ASSERT(registeredFallbackStyleUri == QLatin1String("QtQuick.Controls.Basic"));
178 parentModule = qtQuickControlsUri;
179 fallbackModule = QLatin1String("QtQuick.Controls.IndirectBasic");
180 } else {
181 parentModule = registeredStyleUri;
182 fallbackModule = registeredFallbackStyleUri;
183 }
184
185 qCDebug(lcQtQuickControls2Plugin)
186 << "calling qmlRegisterModuleImport() to register fallback style with"
187 << " uri \"" << parentModule << "\" moduleMajor" << QQmlModuleImportModuleAny
188 << "import" << fallbackModule << "importMajor" << QQmlModuleImportAuto;
189 // Whenever parentModule is imported, registeredFallbackStyleUri will be imported too.
190 // The fallback style must be a built-in style, so we match the version number.
191 qmlRegisterModuleImport(parentModule.toUtf8().constData(), QQmlModuleImportModuleAny,
192 fallbackModule.toUtf8().constData(),
193 QQmlModuleImportAuto, QQmlModuleImportAuto);
194 }
195
196 // If the user imports QtQuick.Controls 2.15, and they're using the Material style, we should import version 2.15.
197 // However, if they import QtQuick.Controls 2.15, but are using a custom style, we want to use the latest version
198 // number of their style.
199 const int importMajor = customStyle ? QQmlModuleImportLatest : QQmlModuleImportAuto;
200 qCDebug(lcQtQuickControls2Plugin).nospace()
201 << "calling qmlRegisterModuleImport() to register primary style with"
202 << " uri \"" << qtQuickControlsUri << "\" moduleMajor " << importMajor
203 << " import " << registeredStyleUri << " importMajor " << importMajor;
204 // When QtQuick.Controls is imported, the selected style will be imported too.
205 qmlRegisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny,
206 registeredStyleUri.toUtf8().constData(), importMajor);
207
208 if (customStyle)
209 QFileSelectorPrivate::addStatics(QStringList() << styleName);
210}
211
213{
214 qCDebug(lcQtQuickControls2Plugin) << "unregisterTypes() called";
215
216 const int importMajor = customStyle ? QQmlModuleImportLatest : QQmlModuleImportAuto;
217 qCDebug(lcQtQuickControls2Plugin).nospace()
218 << "calling qmlUnregisterModuleImport() to unregister primary style with"
219 << " uri \"" << qtQuickControlsUri << "\" moduleMajor " << importMajor
220 << " import " << registeredStyleUri << " importMajor " << importMajor;
221 qmlUnregisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny,
222 registeredStyleUri.toUtf8().constData(), importMajor);
223
224 if (!registeredFallbackStyleUri.isEmpty()) {
225 QString parentModule;
226 QString fallbackModule;
227
228 if (!rawFallbackStyleName.isEmpty()) {
229 parentModule = qtQuickControlsUri;
230 fallbackModule = registeredFallbackStyleUri;
231 rawFallbackStyleName.clear();
232 } else if (customStyle) {
233 parentModule = qtQuickControlsUri;
234 fallbackModule = QLatin1String("QtQuick.Controls.IndirectBasic");
235 } else {
236 parentModule = registeredStyleUri;
237 fallbackModule = registeredFallbackStyleUri;
238 }
239
240 qCDebug(lcQtQuickControls2Plugin)
241 << "calling qmlUnregisterModuleImport() to unregister fallback style with"
242 << " uri \"" << parentModule << "\" moduleMajor" << QQmlModuleImportModuleAny
243 << "import" << fallbackModule << "importMajor" << QQmlModuleImportAuto;
244 qmlUnregisterModuleImport(parentModule.toUtf8().constData(), QQmlModuleImportModuleAny,
245 fallbackModule.toUtf8().constData(),
246 QQmlModuleImportAuto, QQmlModuleImportAuto);
247
248 registeredFallbackStyleUri.clear();
249 }
250
251 customStyle = false;
252 registeredStyleUri.clear();
253}
254
255QT_END_NAMESPACE
256
257#include "qtquickcontrols2plugin.moc"
void registerTypes(const char *uri) override
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
QString fallbackStyleUri()
static const char * qtQuickControlsUri
QString styleUri()
QT_BEGIN_NAMESPACE Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick)