1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include <QtCore/qdir.h>
38#include <QtCore/qfile.h>
39#include <QtCore/qfileinfo.h>
40#include <QtCore/qpluginloader.h>
41#include <QtCore/private/qfileselector_p.h>
42#include <QtQml/qqmlfile.h>
43#include <QtQml/private/qqmldirparser_p.h>
44#include <QtQuickControls2/qquickstyle.h>
45#include <QtQuickControls2/private/qquickchecklabel_p.h>
46#include <QtQuickControls2/private/qquickcolor_p.h>
47#include <QtQuickControls2/private/qquickcolorimage_p.h>
48#include <QtQuickControls2/private/qquickiconimage_p.h>
49#include <QtQuickControls2/private/qquickmnemoniclabel_p.h>
50#include <QtQuickControls2/private/qquickpaddedrectangle_p.h>
51#include <QtQuickControls2/private/qquickplaceholdertext_p.h>
52#include <QtQuickControls2/private/qquickiconlabel_p.h>
53#include <QtQuickControls2/private/qquickstyle_p.h>
54#include <QtQuickControls2/private/qquickstyleplugin_p.h>
55#if QT_CONFIG(quick_listview) && QT_CONFIG(quick_pathview)
56#include <QtQuickControls2/private/qquicktumblerview_p.h>
57#endif
58#include <QtQuickTemplates2/private/qquickoverlay_p.h>
59#include <QtQuickTemplates2/private/qquicksplitview_p.h>
60#include <QtQuickControls2/private/qquickclippedtext_p.h>
61#include <QtQuickControls2/private/qquickitemgroup_p.h>
62#include <QtQuickTemplates2/private/qquicktheme_p_p.h>
63
64#include "qquickdefaultbusyindicator_p.h"
65#include "qquickdefaultdial_p.h"
66#include "qquickdefaultprogressbar_p.h"
67#include "qquickdefaultstyle_p.h"
68#include "qquickdefaulttheme_p.h"
69
70QT_BEGIN_NAMESPACE
71
72class QtQuickControls2Plugin: public QQuickStylePlugin
73{
74 Q_OBJECT
75 Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
76
77public:
78 QtQuickControls2Plugin(QObject *parent = nullptr);
79 ~QtQuickControls2Plugin();
80
81 void registerTypes(const char *uri) override;
82
83 QString name() const override;
84 void initializeTheme(QQuickTheme *theme) override;
85
86private:
87 QList<QQuickStylePlugin *> loadStylePlugins();
88 QQuickTheme *createTheme(const QString &name);
89};
90
91QtQuickControls2Plugin::QtQuickControls2Plugin(QObject *parent) : QQuickStylePlugin(parent)
92{
93}
94
95QtQuickControls2Plugin::~QtQuickControls2Plugin()
96{
97 QQuickStylePrivate::reset();
98}
99
100static bool isDefaultStyle(const QString &style)
101{
102 return style.isEmpty() || style.compare(QStringLiteral("Default"), cs: Qt::CaseInsensitive) == 0;
103}
104
105void QtQuickControls2Plugin::registerTypes(const char *uri)
106{
107 QQuickStylePrivate::init(baseUrl: baseUrl());
108
109 const QString style = QQuickStyle::name();
110 if (!style.isEmpty())
111 QFileSelectorPrivate::addStatics(QStringList() << style.toLower());
112
113 QQuickTheme *theme = createTheme(name: style.isEmpty() ? name() : style);
114 if (isDefaultStyle(style))
115 initializeTheme(theme);
116
117 // load the style's plugins to get access to its resources and initialize the theme
118 QList<QQuickStylePlugin *> stylePlugins = loadStylePlugins();
119 for (QQuickStylePlugin *stylePlugin : stylePlugins)
120 stylePlugin->initializeTheme(theme);
121 qDeleteAll(c: stylePlugins);
122
123 // Register the latest version, even if there are no new types or new revisions for existing types yet.
124 // Before Qt 5.12, we would do the following:
125 //
126 // qmlRegisterModule(uri, 2, QT_VERSION_MINOR - 7); // Qt 5.7->2.0, 5.8->2.1, 5.9->2.2...
127 //
128 // However, we want to align with the rest of Qt Quick which uses Qt's minor version.
129 qmlRegisterModule(uri, versionMajor: 2, QT_VERSION_MINOR);
130
131 // QtQuick.Controls 2.0 (originally introduced in Qt 5.7)
132 qmlRegisterType(url: resolvedUrl(QStringLiteral("AbstractButton.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "AbstractButton");
133 qmlRegisterType(url: resolvedUrl(QStringLiteral("ApplicationWindow.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "ApplicationWindow");
134 qmlRegisterType(url: resolvedUrl(QStringLiteral("BusyIndicator.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "BusyIndicator");
135 qmlRegisterType(url: resolvedUrl(QStringLiteral("Button.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Button");
136 qmlRegisterType(url: resolvedUrl(QStringLiteral("ButtonGroup.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "ButtonGroup");
137 qmlRegisterType(url: resolvedUrl(QStringLiteral("CheckBox.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "CheckBox");
138 qmlRegisterType(url: resolvedUrl(QStringLiteral("CheckDelegate.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "CheckDelegate");
139 qmlRegisterType(url: resolvedUrl(QStringLiteral("ComboBox.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "ComboBox");
140 qmlRegisterType(url: resolvedUrl(QStringLiteral("Container.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Container");
141 qmlRegisterType(url: resolvedUrl(QStringLiteral("Control.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Control");
142 qmlRegisterType(url: resolvedUrl(QStringLiteral("Dial.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Dial");
143 qmlRegisterType(url: resolvedUrl(QStringLiteral("Drawer.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Drawer");
144 qmlRegisterType(url: resolvedUrl(QStringLiteral("Frame.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Frame");
145 qmlRegisterType(url: resolvedUrl(QStringLiteral("GroupBox.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "GroupBox");
146 qmlRegisterType(url: resolvedUrl(QStringLiteral("ItemDelegate.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "ItemDelegate");
147 qmlRegisterType(url: resolvedUrl(QStringLiteral("Label.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Label");
148 qmlRegisterType(url: resolvedUrl(QStringLiteral("Menu.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Menu");
149 qmlRegisterType(url: resolvedUrl(QStringLiteral("MenuItem.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "MenuItem");
150 qmlRegisterType(url: resolvedUrl(QStringLiteral("Page.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Page");
151 qmlRegisterType(url: resolvedUrl(QStringLiteral("PageIndicator.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "PageIndicator");
152 qmlRegisterType(url: resolvedUrl(QStringLiteral("Pane.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Pane");
153 qmlRegisterType(url: resolvedUrl(QStringLiteral("Popup.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Popup");
154 qmlRegisterType(url: resolvedUrl(QStringLiteral("ProgressBar.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "ProgressBar");
155 qmlRegisterType(url: resolvedUrl(QStringLiteral("RadioButton.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "RadioButton");
156 qmlRegisterType(url: resolvedUrl(QStringLiteral("RadioDelegate.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "RadioDelegate");
157 qmlRegisterType(url: resolvedUrl(QStringLiteral("RangeSlider.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "RangeSlider");
158 qmlRegisterType(url: resolvedUrl(QStringLiteral("ScrollBar.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "ScrollBar");
159 qmlRegisterType(url: resolvedUrl(QStringLiteral("ScrollIndicator.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "ScrollIndicator");
160 qmlRegisterType(url: resolvedUrl(QStringLiteral("Slider.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Slider");
161 qmlRegisterType(url: resolvedUrl(QStringLiteral("SpinBox.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "SpinBox");
162 qmlRegisterType(url: resolvedUrl(QStringLiteral("StackView.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "StackView");
163 qmlRegisterType(url: resolvedUrl(QStringLiteral("SwipeDelegate.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "SwipeDelegate");
164 qmlRegisterType(url: resolvedUrl(QStringLiteral("SwipeView.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "SwipeView");
165 qmlRegisterType(url: resolvedUrl(QStringLiteral("Switch.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Switch");
166 qmlRegisterType(url: resolvedUrl(QStringLiteral("SwitchDelegate.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "SwitchDelegate");
167 qmlRegisterType(url: resolvedUrl(QStringLiteral("TabBar.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "TabBar");
168 qmlRegisterType(url: resolvedUrl(QStringLiteral("TabButton.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "TabButton");
169 qmlRegisterType(url: resolvedUrl(QStringLiteral("TextArea.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "TextArea");
170 qmlRegisterType(url: resolvedUrl(QStringLiteral("TextField.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "TextField");
171 qmlRegisterType(url: resolvedUrl(QStringLiteral("ToolBar.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "ToolBar");
172 qmlRegisterType(url: resolvedUrl(QStringLiteral("ToolButton.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "ToolButton");
173 qmlRegisterType(url: resolvedUrl(QStringLiteral("ToolTip.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "ToolTip");
174#if QT_CONFIG(quick_listview) && QT_CONFIG(quick_pathview)
175 qmlRegisterType(url: resolvedUrl(QStringLiteral("Tumbler.qml")), uri, versionMajor: 2, versionMinor: 0, qmlName: "Tumbler");
176#endif
177
178 // QtQuick.Controls 2.1 (new types in Qt 5.8)
179 qmlRegisterType(url: resolvedUrl(QStringLiteral("Dialog.qml")), uri, versionMajor: 2, versionMinor: 1, qmlName: "Dialog");
180 qmlRegisterType(url: resolvedUrl(QStringLiteral("DialogButtonBox.qml")), uri, versionMajor: 2, versionMinor: 1, qmlName: "DialogButtonBox");
181 qmlRegisterType(url: resolvedUrl(QStringLiteral("MenuSeparator.qml")), uri, versionMajor: 2, versionMinor: 1, qmlName: "MenuSeparator");
182 qmlRegisterType(url: resolvedUrl(QStringLiteral("RoundButton.qml")), uri, versionMajor: 2, versionMinor: 1, qmlName: "RoundButton");
183 qmlRegisterType(url: resolvedUrl(QStringLiteral("ToolSeparator.qml")), uri, versionMajor: 2, versionMinor: 1, qmlName: "ToolSeparator");
184
185 // QtQuick.Controls 2.2 (new types in Qt 5.9)
186 qmlRegisterType(url: resolvedUrl(QStringLiteral("DelayButton.qml")), uri, versionMajor: 2, versionMinor: 2, qmlName: "DelayButton");
187 qmlRegisterType(url: resolvedUrl(QStringLiteral("ScrollView.qml")), uri, versionMajor: 2, versionMinor: 2, qmlName: "ScrollView");
188
189 // QtQuick.Controls 2.3 (new types in Qt 5.10)
190 qmlRegisterType(url: resolvedUrl(QStringLiteral("Action.qml")), uri, versionMajor: 2, versionMinor: 3, qmlName: "Action");
191 qmlRegisterType(url: resolvedUrl(QStringLiteral("ActionGroup.qml")), uri, versionMajor: 2, versionMinor: 3, qmlName: "ActionGroup");
192 qmlRegisterType(url: resolvedUrl(QStringLiteral("MenuBar.qml")), uri, versionMajor: 2, versionMinor: 3, qmlName: "MenuBar");
193 qmlRegisterType(url: resolvedUrl(QStringLiteral("MenuBarItem.qml")), uri, versionMajor: 2, versionMinor: 3, qmlName: "MenuBarItem");
194 qmlRegisterUncreatableType<QQuickOverlay>(uri, versionMajor: 2, versionMinor: 3, qmlName: "Overlay", QStringLiteral("Overlay is only available as an attached property."));
195
196 // QtQuick.Controls 2.13 (new types in Qt 5.13)
197 qmlRegisterType(url: resolvedUrl(QStringLiteral("SplitView.qml")), uri, versionMajor: 2, versionMinor: 13, qmlName: "SplitView");
198 qmlRegisterUncreatableType<QQuickSplitHandleAttached>(uri, versionMajor: 2, versionMinor: 13, qmlName: "SplitHandle",
199 QStringLiteral("SplitHandle is only available as an attached property."));
200
201 // QtQuick.Controls 2.15 (new types in Qt 5.15)
202 qmlRegisterType(url: resolvedUrl(QStringLiteral("HorizontalHeaderView.qml")), uri, versionMajor: 2, versionMinor: 15, qmlName: "HorizontalHeaderView");
203 qmlRegisterType(url: resolvedUrl(QStringLiteral("VerticalHeaderView.qml")), uri, versionMajor: 2, versionMinor: 15, qmlName: "VerticalHeaderView");
204
205 // Register the latest version, even if there are no new types or new revisions for existing types yet.
206 // Before Qt 5.12, we would do the following:
207 //
208 // qmlRegisterModule(import, 2, QT_VERSION_MINOR - 7); // Qt 5.7->2.0, 5.8->2.1, 5.9->2.2...
209 //
210 // However, we want to align with the rest of Qt Quick which uses Qt's minor version.
211 const QByteArray import = QByteArray(uri) + ".impl";
212 qmlRegisterModule(uri: import, versionMajor: 2, QT_VERSION_MINOR);
213
214 // QtQuick.Controls.impl 2.0 (Qt 5.7)
215 qmlRegisterType<QQuickDefaultBusyIndicator>(uri: import, versionMajor: 2, versionMinor: 0, qmlName: "BusyIndicatorImpl");
216 qmlRegisterType<QQuickDefaultDial>(uri: import, versionMajor: 2, versionMinor: 0, qmlName: "DialImpl");
217 qmlRegisterType<QQuickPaddedRectangle>(uri: import, versionMajor: 2, versionMinor: 0, qmlName: "PaddedRectangle");
218 qmlRegisterType<QQuickDefaultProgressBar>(uri: import, versionMajor: 2, versionMinor: 0, qmlName: "ProgressBarImpl");
219
220 // QtQuick.Controls.impl 2.1 (Qt 5.8)
221#if QT_CONFIG(quick_listview) && QT_CONFIG(quick_pathview)
222 qmlRegisterType<QQuickTumblerView>(uri: import, versionMajor: 2, versionMinor: 1, qmlName: "TumblerView");
223#endif
224 qmlRegisterSingletonType<QQuickDefaultStyle>(uri: import, versionMajor: 2, versionMinor: 1, typeName: "Default", callback: [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* {
225 Q_UNUSED(engine);
226 Q_UNUSED(scriptEngine);
227 return new QQuickDefaultStyle;
228 });
229
230 // QtQuick.Controls.impl 2.2 (Qt 5.9)
231 qmlRegisterType<QQuickClippedText>(uri: import, versionMajor: 2, versionMinor: 2, qmlName: "ClippedText");
232 qmlRegisterType<QQuickItemGroup>(uri: import, versionMajor: 2, versionMinor: 2, qmlName: "ItemGroup");
233 qmlRegisterType<QQuickPlaceholderText>(uri: import, versionMajor: 2, versionMinor: 2, qmlName: "PlaceholderText");
234
235 // QtQuick.Controls.impl 2.3 (Qt 5.10)
236 qmlRegisterType<QQuickColorImage>(uri: import, versionMajor: 2, versionMinor: 3, qmlName: "ColorImage");
237 qmlRegisterType<QQuickIconImage>(uri: import, versionMajor: 2, versionMinor: 3, qmlName: "IconImage");
238 qmlRegisterSingletonType<QQuickColor>(uri: import, versionMajor: 2, versionMinor: 3, typeName: "Color", callback: [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* {
239 Q_UNUSED(engine);
240 Q_UNUSED(scriptEngine);
241 return new QQuickColor;
242 });
243 qmlRegisterType<QQuickIconLabel>(uri: import, versionMajor: 2, versionMinor: 3, qmlName: "IconLabel");
244 qmlRegisterType<QQuickCheckLabel>(uri: import, versionMajor: 2, versionMinor: 3, qmlName: "CheckLabel");
245 qmlRegisterType<QQuickMnemonicLabel>(uri: import, versionMajor: 2, versionMinor: 3, qmlName: "MnemonicLabel");
246 qmlRegisterRevision<QQuickText, 6>(uri: import, versionMajor: 2, versionMinor: 3);
247}
248
249QString QtQuickControls2Plugin::name() const
250{
251 return QStringLiteral("Default");
252}
253
254void QtQuickControls2Plugin::initializeTheme(QQuickTheme *theme)
255{
256 QQuickDefaultTheme::initialize(theme);
257}
258
259QList<QQuickStylePlugin *> QtQuickControls2Plugin::loadStylePlugins()
260{
261 QList<QQuickStylePlugin *> stylePlugins;
262
263 QFileInfo fileInfo = QQmlFile::urlToLocalFileOrQrc(resolvedUrl(QStringLiteral("qmldir")));
264 if (fileInfo.exists() && fileInfo.path() != QQmlFile::urlToLocalFileOrQrc(baseUrl())) {
265 QFile file(fileInfo.filePath());
266 if (file.open(flags: QIODevice::ReadOnly | QIODevice::Text)) {
267 QQmlDirParser parser;
268 parser.parse(source: QString::fromUtf8(str: file.readAll()));
269 if (!parser.hasError()) {
270#ifdef QT_STATIC
271 const auto plugins = QPluginLoader::staticInstances();
272 for (QObject *instance : plugins) {
273 QQuickStylePlugin *stylePlugin = qobject_cast<QQuickStylePlugin *>(instance);
274 if (!stylePlugin || parser.className() != QLatin1String(instance->metaObject()->className()))
275 continue;
276 stylePlugins += stylePlugin;
277 }
278#elif QT_CONFIG(library)
279 QPluginLoader loader;
280 const auto plugins = parser.plugins();
281 for (const QQmlDirParser::Plugin &plugin : plugins) {
282 QDir dir = fileInfo.dir();
283 if (!plugin.path.isEmpty() && !dir.cd(dirName: plugin.path))
284 continue;
285 QString filePath = dir.filePath(fileName: plugin.name);
286#if defined(Q_OS_MACOS) && defined(QT_DEBUG)
287 // Avoid mismatching plugins on macOS so that we don't end up loading both debug and
288 // release versions of the same Qt libraries (due to the plugin's dependencies).
289 filePath += QStringLiteral("_debug");
290#endif // Q_OS_MACOS && QT_DEBUG
291#if defined(Q_OS_WIN) && defined(QT_DEBUG)
292 // Debug versions of plugins have a "d" prefix on Windows.
293 filePath += QLatin1Char('d');
294#endif // Q_OS_WIN && QT_DEBUG
295 loader.setFileName(filePath);
296 QQuickStylePlugin *stylePlugin = qobject_cast<QQuickStylePlugin *>(object: loader.instance());
297 if (stylePlugin)
298 stylePlugins += stylePlugin;
299 }
300#endif
301 }
302 }
303 }
304 return stylePlugins;
305}
306
307QQuickTheme *QtQuickControls2Plugin::createTheme(const QString &name)
308{
309 QQuickTheme *theme = new QQuickTheme;
310#if QT_CONFIG(settings)
311 QQuickThemePrivate *p = QQuickThemePrivate::get(theme);
312 QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(name);
313 if (settings) {
314 p->defaultFont.reset(other: QQuickStylePrivate::readFont(settings));
315 // Set the default font as the System scope, because that's what
316 // QQuickControlPrivate::parentFont() uses as its fallback if no
317 // parent item has a font explicitly set. QQuickControlPrivate::parentFont()
318 // is used as the starting point for font inheritance/resolution.
319 // The same goes for palettes below.
320 theme->setFont(scope: QQuickTheme::System, font: *p->defaultFont);
321
322 p->defaultPalette.reset(other: QQuickStylePrivate::readPalette(settings));
323 theme->setPalette(scope: QQuickTheme::System, palette: *p->defaultPalette);
324 }
325#endif
326 QQuickThemePrivate::instance.reset(other: theme);
327 return theme;
328}
329
330QT_END_NAMESPACE
331
332#include "qtquickcontrols2plugin.moc"
333

source code of qtquickcontrols2/src/imports/controls/qtquickcontrols2plugin.cpp