1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 BlackBerry Limited. All rights reserved. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQml 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 <QtCore/QFileSelector> |
41 | #include <QtQml/QQmlAbstractUrlInterceptor> |
42 | #include <qobjectdefs.h> |
43 | #include "qqmlfileselector.h" |
44 | #include "qqmlfileselector_p.h" |
45 | #include <QDebug> |
46 | |
47 | QT_BEGIN_NAMESPACE |
48 | |
49 | typedef QHash<QQmlAbstractUrlInterceptor*, QQmlFileSelector*> interceptorSelectorMap; |
50 | Q_GLOBAL_STATIC(interceptorSelectorMap, interceptorInstances); |
51 | /*! |
52 | \class QQmlFileSelector |
53 | \since 5.2 |
54 | \inmodule QtQml |
55 | \brief A class for applying a QFileSelector to QML file loading. |
56 | |
57 | QQmlFileSelector will automatically apply a QFileSelector to |
58 | qml file and asset paths. |
59 | |
60 | It is used as follows: |
61 | |
62 | \code |
63 | QQmlEngine engine; |
64 | QQmlFileSelector* selector = new QQmlFileSelector(&engine); |
65 | \endcode |
66 | |
67 | Then you can swap out files like so: |
68 | \code |
69 | main.qml |
70 | Component.qml |
71 | asset.png |
72 | +unix/Component.qml |
73 | +mac/asset.png |
74 | \endcode |
75 | |
76 | In this example, main.qml will normally use Component.qml for the Component type. However on a |
77 | unix platform, the unix selector will be present and the +unix/Component.qml version will be |
78 | used instead. Note that this acts like swapping out Component.qml with +unix/Component.qml, so |
79 | when using Component.qml you should not need to alter any paths based on which version was |
80 | selected. |
81 | |
82 | For example, to pass the "asset.png" file path around you would refer to it just as "asset.png" in |
83 | all of main.qml, Component.qml, and +linux/Component.qml. It will be replaced with +mac/asset.png |
84 | on Mac platforms in all cases. |
85 | |
86 | For a list of available selectors, see \c QFileSelector. |
87 | |
88 | Your platform may also provide additional selectors for you to use. As specified by QFileSelector, |
89 | directories used for selection must start with a '+' character, so you will not accidentally |
90 | trigger this feature unless you have directories with such names inside your project. |
91 | |
92 | If a new QQmlFileSelector is set on the engine, the old one will be replaced. Use |
93 | \l QQmlFileSelector::get() to query or use the existing instance. |
94 | */ |
95 | |
96 | /*! |
97 | Creates a new QQmlFileSelector with parent object \a parent, which includes |
98 | its own QFileSelector. \a engine is the QQmlEngine you wish to apply file |
99 | selectors to. It will also take ownership of the QQmlFileSelector. |
100 | */ |
101 | |
102 | QQmlFileSelector::QQmlFileSelector(QQmlEngine* engine, QObject* parent) |
103 | : QObject(*(new QQmlFileSelectorPrivate), parent) |
104 | { |
105 | Q_D(QQmlFileSelector); |
106 | d->engine = engine; |
107 | interceptorInstances()->insert(key: d->myInstance.data(), value: this); |
108 | d->engine->setUrlInterceptor(d->myInstance.data()); |
109 | } |
110 | |
111 | /*! |
112 | Destroys the QQmlFileSelector object. |
113 | */ |
114 | QQmlFileSelector::~QQmlFileSelector() |
115 | { |
116 | Q_D(QQmlFileSelector); |
117 | if (d->engine && QQmlFileSelector::get(d->engine) == this) { |
118 | d->engine->setUrlInterceptor(nullptr); |
119 | d->engine = nullptr; |
120 | } |
121 | interceptorInstances()->remove(key: d->myInstance.data()); |
122 | } |
123 | |
124 | /*! |
125 | \since 5.7 |
126 | Returns the QFileSelector instance used by the QQmlFileSelector. |
127 | */ |
128 | QFileSelector *QQmlFileSelector::selector() const Q_DECL_NOTHROW |
129 | { |
130 | Q_D(const QQmlFileSelector); |
131 | return d->selector; |
132 | } |
133 | |
134 | QQmlFileSelectorPrivate::QQmlFileSelectorPrivate() |
135 | { |
136 | Q_Q(QQmlFileSelector); |
137 | ownSelector = true; |
138 | selector = new QFileSelector(q); |
139 | myInstance.reset(other: new QQmlFileSelectorInterceptor(this)); |
140 | } |
141 | |
142 | QQmlFileSelectorPrivate::~QQmlFileSelectorPrivate() |
143 | { |
144 | if (ownSelector) |
145 | delete selector; |
146 | } |
147 | |
148 | /*! |
149 | Sets the QFileSelector instance for use by the QQmlFileSelector to \a selector. |
150 | QQmlFileSelector does not take ownership of the new QFileSelector. To reset QQmlFileSelector |
151 | to use its internal QFileSelector instance, call setSelector(\nullptr). |
152 | */ |
153 | |
154 | void QQmlFileSelector::setSelector(QFileSelector *selector) |
155 | { |
156 | Q_D(QQmlFileSelector); |
157 | if (selector) { |
158 | if (d->ownSelector) { |
159 | delete d->selector; |
160 | d->ownSelector = false; |
161 | } |
162 | d->selector = selector; |
163 | } else { |
164 | if (!d->ownSelector) { |
165 | d->ownSelector = true; |
166 | d->selector = new QFileSelector(this); |
167 | } // Do nothing if already using internal selector |
168 | } |
169 | } |
170 | |
171 | /*! |
172 | Adds extra selectors contained in \a strings to the current QFileSelector being used. |
173 | Use this when extra selectors are all you need to avoid having to create your own |
174 | QFileSelector instance. |
175 | */ |
176 | void QQmlFileSelector::(QStringList &strings) |
177 | { |
178 | Q_D(QQmlFileSelector); |
179 | d->selector->setExtraSelectors(strings); |
180 | } |
181 | |
182 | |
183 | /*! |
184 | Adds extra selectors contained in \a strings to the current QFileSelector being used. |
185 | Use this when extra selectors are all you need to avoid having to create your own |
186 | QFileSelector instance. |
187 | */ |
188 | void QQmlFileSelector::(const QStringList &strings) |
189 | { |
190 | Q_D(QQmlFileSelector); |
191 | d->selector->setExtraSelectors(strings); |
192 | } |
193 | |
194 | /*! |
195 | Gets the QQmlFileSelector currently active on the target \a engine. |
196 | */ |
197 | QQmlFileSelector* QQmlFileSelector::get(QQmlEngine* engine) |
198 | { |
199 | //Since I think we still can't use dynamic_cast inside Qt... |
200 | QQmlAbstractUrlInterceptor* current = engine->urlInterceptor(); |
201 | if (current && interceptorInstances()->contains(key: current)) |
202 | return interceptorInstances()->value(key: current); |
203 | return nullptr; |
204 | } |
205 | |
206 | /*! |
207 | \internal |
208 | */ |
209 | QQmlFileSelectorInterceptor::QQmlFileSelectorInterceptor(QQmlFileSelectorPrivate* pd) |
210 | : d(pd) |
211 | { |
212 | } |
213 | |
214 | /*! |
215 | \internal |
216 | */ |
217 | QUrl QQmlFileSelectorInterceptor::intercept(const QUrl &path, DataType type) |
218 | { |
219 | if ( type == QQmlAbstractUrlInterceptor::QmldirFile ) //Don't intercept qmldir files, to prevent double interception |
220 | return path; |
221 | return d->selector->select(filePath: path); |
222 | } |
223 | |
224 | QT_END_NAMESPACE |
225 | |
226 | #include "moc_qqmlfileselector.cpp" |
227 | |