1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QtQml/qqml.h>
41#include <QtQml/qqmlextensionplugin.h>
42#include <QtQml/qqmlcomponent.h>
43#include <QtQml/qqmlengine.h>
44#include "qquickmessagedialog_p.h"
45#include "qquickabstractmessagedialog_p.h"
46#include "qquickdialogassets_p.h"
47#include "qquickplatformmessagedialog_p.h"
48#include "qquickfiledialog_p.h"
49#include "qquickabstractfiledialog_p.h"
50#include "qquickplatformfiledialog_p.h"
51#include "qquickcolordialog_p.h"
52#include "qquickabstractcolordialog_p.h"
53#include "qquickplatformcolordialog_p.h"
54#include "qquickfontdialog_p.h"
55#include "qquickabstractfontdialog_p.h"
56#include "qquickplatformfontdialog_p.h"
57#include "qquickdialog_p.h"
58#include <private/qguiapplication_p.h>
59#include <qpa/qplatformintegration.h>
60#include <QTouchDevice>
61
62//#define PURE_QML_ONLY
63
64Q_LOGGING_CATEGORY(lcRegistration, "qt.quick.dialogs.registration")
65
66QT_BEGIN_NAMESPACE
67
68/*!
69 \qmlmodule QtQuick.Dialogs 1.3
70 \title Qt Quick Dialogs QML Types
71 \ingroup qmlmodules
72 \brief Provides QML types for standard file, color picker and message dialogs
73
74 This QML module contains types for creating and interacting with system dialogs.
75
76 To use the types in this module, import the module with the following line:
77
78 \code
79 import QtQuick.Dialogs 1.3
80 \endcode
81*/
82
83class QtQuick2DialogsPlugin : public QQmlExtensionPlugin
84{
85 Q_OBJECT
86 Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
87
88public:
89 QtQuick2DialogsPlugin() : QQmlExtensionPlugin(), m_useResources(true) { }
90
91 void registerTypes(const char *uri) override {
92 Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Dialogs"));
93 bool hasTopLevelWindows = QGuiApplicationPrivate::platformIntegration()->
94 hasCapability(cap: QPlatformIntegration::MultipleWindows);
95 qCDebug(lcRegistration) << uri << "can use top-level windows?" << hasTopLevelWindows;
96 QDir qmlDir(baseUrl().toLocalFile());
97 QDir widgetsDir(baseUrl().toLocalFile());
98#ifndef QT_STATIC
99 widgetsDir.cd(dirName: "../PrivateWidgets");
100#endif
101#ifdef QT_STATIC
102 m_useResources = false;
103#else
104#ifndef ALWAYS_LOAD_FROM_RESOURCES
105 // If at least one file was actually installed, then use installed qml files instead of resources.
106 // This makes debugging and incremental development easier, whereas the "normal" installation
107 // uses resources to save space and cut down on the number of files to deploy.
108 if (qmlDir.exists(name: QString("DefaultFileDialog.qml")))
109 m_useResources = false;
110#endif
111#endif
112
113 QQuickAbstractDialog::m_decorationComponentUrl = fileLocation(moduleName: "qml/DefaultWindowDecoration");
114 // Prefer the QPA dialog helpers if the platform supports them.
115 // Else if there is a QWidget-based implementation, check whether it's
116 // possible to instantiate it from Qt Quick.
117 // Otherwise fall back to a pure-QML implementation.
118
119 // MessageDialog
120 qmlRegisterUncreatableType<QQuickStandardButton>(uri, versionMajor: 1, versionMinor: 1, qmlName: "StandardButton",
121 reason: QLatin1String("Do not create objects of type StandardButton"));
122 qmlRegisterUncreatableType<QQuickStandardIcon>(uri, versionMajor: 1, versionMinor: 1, qmlName: "StandardIcon",
123 reason: QLatin1String("Do not create objects of type StandardIcon"));
124#ifndef PURE_QML_ONLY
125 if (QGuiApplicationPrivate::platformTheme()->usePlatformNativeDialog(type: QPlatformTheme::MessageDialog))
126 qmlRegisterType<QQuickPlatformMessageDialog1>(uri, versionMajor: 1, versionMinor: 0, qmlName: "MessageDialog");
127 else
128#endif
129 registerWidgetOrQmlImplementation<QQuickMessageDialog>(widgetsDir, qmlDir, qmlName: "MessageDialog", uri, hasTopLevelWindows, versionMajor: 1, versionMinor: 1);
130
131 // FileDialog
132#ifndef PURE_QML_ONLY
133 // We register the QML version of the filedialog, even if the platform has native support.
134 // QQuickAbstractDialog::setVisible() will check if a native dialog can be shown, and
135 // only fall back to use the QML version if showing fails.
136 if (QGuiApplicationPrivate::platformTheme()->usePlatformNativeDialog(type: QPlatformTheme::FileDialog))
137 registerQmlImplementation<QQuickPlatformFileDialog1>(qmlDir, qmlName: "FileDialog", uri, versionMajor: 1, versionMinor: 0);
138 else
139#endif
140 registerWidgetOrQmlImplementation<QQuickFileDialog>(widgetsDir, qmlDir, qmlName: "FileDialog", uri, hasTopLevelWindows, versionMajor: 1, versionMinor: 0);
141
142 // ColorDialog
143#ifndef PURE_QML_ONLY
144 if (QGuiApplicationPrivate::platformTheme()->usePlatformNativeDialog(type: QPlatformTheme::ColorDialog))
145 qmlRegisterType<QQuickPlatformColorDialog1>(uri, versionMajor: 1, versionMinor: 0, qmlName: "ColorDialog");
146 else
147#endif
148 registerWidgetOrQmlImplementation<QQuickColorDialog>(widgetsDir, qmlDir, qmlName: "ColorDialog", uri, hasTopLevelWindows, versionMajor: 1, versionMinor: 0);
149
150 // FontDialog
151#ifndef PURE_QML_ONLY
152 if (QGuiApplicationPrivate::platformTheme()->usePlatformNativeDialog(type: QPlatformTheme::FontDialog))
153 qmlRegisterType<QQuickPlatformFontDialog1>(uri, versionMajor: 1, versionMinor: 1, qmlName: "FontDialog");
154 else
155#endif
156 registerWidgetOrQmlImplementation<QQuickFontDialog>(widgetsDir, qmlDir, qmlName: "FontDialog", uri, hasTopLevelWindows, versionMajor: 1, versionMinor: 1);
157
158 // Dialog
159 {
160 // @uri QtQuick.Dialogs.AbstractDialog
161 qmlRegisterType<QQuickDialog1>(uri, versionMajor: 1, versionMinor: 2, qmlName: "AbstractDialog"); // implementation wrapper
162 QUrl dialogQmlPath = fileLocation(moduleName: "DefaultDialogWrapper");
163 qCDebug(lcRegistration) << " registering" << dialogQmlPath << "as Dialog";
164 qmlRegisterType(url: dialogQmlPath, uri, versionMajor: 1, versionMinor: 2, qmlName: "Dialog");
165 qmlRegisterType(url: dialogQmlPath, uri, versionMajor: 1, versionMinor: 3, qmlName: "Dialog");
166 }
167 }
168
169protected:
170 template <class WrapperType>
171 void registerWidgetOrQmlImplementation(const QDir &widgetsDir, const QDir &qmlDir,
172 const char *qmlName, const char *uri, bool hasTopLevelWindows, int versionMajor, int versionMinor) {
173 qCDebug(lcRegistration) << qmlName << uri << ": QML in" << qmlDir.absolutePath()
174 << "using resources?" << m_useResources << "; widgets in" << widgetsDir.absolutePath();
175
176#ifndef PURE_QML_ONLY
177 if (!registerWidgetImplementation<WrapperType>(
178 widgetsDir, qmlDir, qmlName, uri, hasTopLevelWindows, versionMajor, versionMinor))
179#else
180 Q_UNUSED(widgetsDir)
181 Q_UNUSED(hasTopLevelWindows)
182#endif
183 registerQmlImplementation<WrapperType>(qmlDir, qmlName, uri, versionMajor, versionMinor);
184 }
185
186 template <class WrapperType>
187 bool registerWidgetImplementation(const QDir &widgetsDir, const QDir &qmlDir,
188 const char *qmlName, const char *uri, bool hasTopLevelWindows, int versionMajor, int versionMinor)
189 {
190 Q_UNUSED(qmlDir)
191 bool mobileTouchPlatform = false;
192#if defined(Q_OS_IOS)
193 mobileTouchPlatform = true;
194#elif defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_QNX)
195 const auto devices = QTouchDevice::devices();
196 for (const QTouchDevice *dev : devices)
197 if (dev->type() == QTouchDevice::TouchScreen)
198 mobileTouchPlatform = true;
199#endif
200
201 // If there is a qmldir and we have a QApplication instance (as opposed to a
202 // widget-free QGuiApplication), and this isn't a mobile touch-based platform,
203 // assume that the widget-based dialog will work. Otherwise an application developer
204 // can ensure that widgets are omitted from the deployment to ensure that the widget
205 // dialogs won't be used.
206 if (!mobileTouchPlatform && hasTopLevelWindows && widgetsDir.exists(name: "qmldir") &&
207 QCoreApplication::instance()->inherits(classname: "QApplication")) {
208 QUrl dialogQmlPath = fileLocation(moduleName: QString("Widget%1").arg(a: qmlName));
209 if (qmlRegisterType(url: dialogQmlPath, uri, versionMajor, versionMinor, qmlName) >= 0) {
210 qCDebug(lcRegistration) << " registering" << qmlName << " as " << dialogQmlPath;
211 return true;
212 }
213 }
214 return false;
215 }
216
217 template <class WrapperType>
218 void registerQmlImplementation(const QDir &qmlDir, const char *qmlName, const char *uri , int versionMajor, int versionMinor)
219 {
220 Q_UNUSED(qmlDir)
221 qCDebug(lcRegistration) << "Register QML version for" << qmlName << "with uri:" << uri;
222
223 QByteArray abstractTypeName = QByteArray("Abstract") + qmlName;
224 qmlRegisterType<WrapperType>(uri, versionMajor, versionMinor, abstractTypeName);
225 QUrl dialogQmlPath = fileLocation(moduleName: QString("Default%1").arg(a: qmlName));
226 qCDebug(lcRegistration) << " registering" << qmlName << " as " << dialogQmlPath;
227 qmlRegisterType(url: dialogQmlPath, uri, versionMajor, versionMinor, qmlName);
228 }
229
230 QUrl fileLocation(const QString &moduleName) const
231 {
232 return m_useResources ?
233#ifdef Q_OS_ANDROID
234 QUrl(QString("qrc:/android_rcc_bundle/qml/QtQuick/Dialogs/%1.qml").arg(moduleName)) :
235#else
236 QUrl(QString("qrc:/QtQuick/Dialogs/%1.qml").arg(a: moduleName)) :
237#endif
238#ifndef QT_STATIC
239 QUrl::fromLocalFile(localfile: QDir(baseUrl().toLocalFile()).filePath(fileName: moduleName + ".qml"));
240#else
241 QUrl(QString("qrc:/qt-project.org/imports/QtQuick/Dialogs/%1.qml").arg(moduleName));
242#endif
243 }
244
245 bool m_useResources;
246};
247
248QT_END_NAMESPACE
249
250#include "plugin.moc"
251

source code of qtquickcontrols/src/dialogs/plugin.cpp