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
qqmlfileselector.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
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
4
5#include <QtCore/QFileSelector>
6#include <QtQml/QQmlAbstractUrlInterceptor>
7#include <QtQml/private/qqmlengine_p.h>
8#include <QtQml/private/qqmlapplicationengine_p.h>
9#include <qobjectdefs.h>
12#include "qqmlengine_p.h"
13#include <QDebug>
14
16
17/*!
18 \class QQmlFileSelector
19 \since 5.2
20 \inmodule QtQml
21 \brief A class for applying a QFileSelector to QML file loading.
22
23 QQmlFileSelector will automatically apply a QFileSelector to
24 qml file and asset paths.
25
26 It is used as follows:
27
28 \code
29 QQmlEngine engine;
30 QQmlFileSelector* selector = new QQmlFileSelector(&engine);
31 \endcode
32
33 Then you can swap out files like so:
34 \code
35 main.qml
36 Component.qml
37 asset.png
38 +unix/Component.qml
39 +mac/asset.png
40 \endcode
41
42 In this example, main.qml will normally use Component.qml for the Component type. However on a
43 unix platform, the unix selector will be present and the +unix/Component.qml version will be
44 used instead. Note that this acts like swapping out Component.qml with +unix/Component.qml, so
45 when using Component.qml you should not need to alter any paths based on which version was
46 selected.
47
48 For example, to pass the "asset.png" file path around you would refer to it just as "asset.png" in
49 all of main.qml, Component.qml, and +linux/Component.qml. It will be replaced with +mac/asset.png
50 on Mac platforms in all cases.
51
52 For a list of available selectors, see \c QFileSelector.
53
54 Your platform may also provide additional selectors for you to use. As specified by QFileSelector,
55 directories used for selection must start with a '+' character, so you will not accidentally
56 trigger this feature unless you have directories with such names inside your project.
57
58 If a new QQmlFileSelector is set on the engine, the old one will be replaced.
59 */
60
61/*!
62 Creates a new QQmlFileSelector with parent object \a parent, which includes
63 its own QFileSelector. \a engine is the QQmlEngine you wish to apply file
64 selectors to. It will also take ownership of the QQmlFileSelector.
65*/
66
67QQmlFileSelector::QQmlFileSelector(QQmlEngine* engine, QObject* parent)
68 : QObject(*(new QQmlFileSelectorPrivate), parent)
69{
70 Q_D(QQmlFileSelector);
71 d->engine = engine;
72 d->engine->addUrlInterceptor(d->myInstance.data());
73}
74
75/*!
76 Destroys the QQmlFileSelector object.
77*/
78QQmlFileSelector::~QQmlFileSelector()
79{
80 Q_D(QQmlFileSelector);
81 if (d->engine) {
82 d->engine->removeUrlInterceptor(d->myInstance.data());
83 d->engine = nullptr;
84 }
85}
86
87/*!
88 \since 5.7
89 Returns the QFileSelector instance used by the QQmlFileSelector.
90*/
91QFileSelector *QQmlFileSelector::selector() const noexcept
92{
93 Q_D(const QQmlFileSelector);
94 return d->selector.data();
95}
96
97QQmlFileSelectorPrivate::QQmlFileSelectorPrivate()
98{
99 selector = QTaggedPointer(new QFileSelector, Owned::Yes);
100 myInstance.reset(new QQmlFileSelectorInterceptor(this));
101}
102
103QQmlFileSelectorPrivate::~QQmlFileSelectorPrivate()
104{
105 deleteSelectorIfOwned();
106}
107
108void QQmlFileSelectorPrivate::deleteSelectorIfOwned()
109{
110 if (selector.tag() == Owned::Yes)
111 delete selector.data();
112}
113
114/*!
115 Sets the QFileSelector instance for use by the QQmlFileSelector to \a selector.
116 QQmlFileSelector does not take ownership of the new QFileSelector. To reset QQmlFileSelector
117 to use its internal QFileSelector instance, call setSelector(\nullptr).
118*/
119
120void QQmlFileSelector::setSelector(QFileSelector *selector)
121{
122 Q_D(QQmlFileSelector);
123
124 using Owned = QQmlFileSelectorPrivate::Owned;
125
126 if (selector) {
127 d->deleteSelectorIfOwned();
128 d->selector = QTaggedPointer(selector, Owned::No);
129 } else if (d->selector.tag() == Owned::No) {
130 // Replace previous explicit file selector with default one.
131 d->selector = QTaggedPointer(new QFileSelector, Owned::Yes);
132 } else {
133 // Do nothing if already using internal selector and none given.
134 // NB: The internal one has to be the default one.
135 }
136}
137
138/*!
139 Adds extra selectors contained in \a strings to the current QFileSelector being used.
140 Use this when extra selectors are all you need to avoid having to create your own
141 QFileSelector instance.
142*/
143void QQmlFileSelector::setExtraSelectors(const QStringList &strings)
144{
145 Q_D(QQmlFileSelector);
146 d->selector->setExtraSelectors(strings);
147}
148
149#if QT_DEPRECATED_SINCE(6, 0)
150/*!
151 \deprecated [6.0] The file selector should not be accessed after it
152 is set. It may be in use. See below for further details.
153
154 Gets the QQmlFileSelector currently active on the target \a engine.
155
156 This method is deprecated. You should not retrieve the files selector from an
157 engine after setting it. It may be in use.
158
159 If the \a engine passed here is a QQmlApplicationEngine that hasn't loaded any
160 QML files, yet, it will be initialized. Any later calls to
161 QQmlApplicationEngine::setExtraFileSelectors() will have no effect.
162
163 \sa QQmlApplicationEngine
164*/
165QQmlFileSelector* QQmlFileSelector::get(QQmlEngine* engine)
166{
167 QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
168
169 if (qobject_cast<QQmlApplicationEngine *>(engine)) {
170 auto *appEnginePrivate = static_cast<QQmlApplicationEnginePrivate *>(enginePrivate);
171 appEnginePrivate->ensureInitialized();
172 }
173
174 const QUrl nonEmptyInvalid(QLatin1String(":"));
175 const auto interceptors = QQmlTypeLoader::get(engine)->urlInterceptors();
176 for (QQmlAbstractUrlInterceptor *interceptor : interceptors) {
177 const QUrl result = interceptor->intercept(
178 nonEmptyInvalid, QQmlAbstractUrlInterceptor::UrlString);
179 if (result.scheme() == QLatin1String("type")
180 && result.path() == QLatin1String("fileselector")) {
181 return static_cast<QQmlFileSelectorInterceptor *>(interceptor)->d->q_func();
182 }
183 }
184 return nullptr;
185}
186#endif
187
188/*!
189 \internal
190*/
191QQmlFileSelectorInterceptor::QQmlFileSelectorInterceptor(QQmlFileSelectorPrivate* pd)
192 : d(pd)
193{
194}
195
196/*!
197 \internal
198*/
199QUrl QQmlFileSelectorInterceptor::intercept(const QUrl &path, DataType type)
200{
201 if (!path.isEmpty() && !path.isValid())
202 return QUrl(QLatin1String("type:fileselector"));
203
204 return type == QQmlAbstractUrlInterceptor::QmldirFile
205 ? path // Don't intercept qmldir files, to prevent double interception
206 : d->selector->select(path);
207}
208
209QT_END_NAMESPACE
210
211#include "moc_qqmlfileselector.cpp"
Combined button and popup list for selecting options.