qfileselector.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/corelib/io/qfileselector.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/***************************************************************************-
2**-
3** Copyright (C) 2013 BlackBerry Limited. All rights reserved.-
4** Contact: http://www.qt.io/licensing/-
5**-
6** This file is part of the QtCore module of the Qt Toolkit.-
7**-
8** $QT_BEGIN_LICENSE:LGPL21$-
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 2.1 or version 3 as published by the Free-
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and-
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the-
22** following information to ensure the GNU Lesser General Public License-
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and-
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.-
25**-
26** As a special exception, The Qt Company gives you certain additional-
27** rights. These rights are described in The Qt Company LGPL Exception-
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.-
29**-
30** $QT_END_LICENSE$-
31**-
32****************************************************************************/-
33-
34#include "qfileselector.h"-
35#include "qfileselector_p.h"-
36-
37#include <QtCore/QFile>-
38#include <QtCore/QDir>-
39#include <QtCore/QMutex>-
40#include <QtCore/QMutexLocker>-
41#include <QtCore/QUrl>-
42#include <QtCore/QFileInfo>-
43#include <QtCore/QLocale>-
44#include <QtCore/QDebug>-
45-
46QT_BEGIN_NAMESPACE-
47-
48//Environment variable to allow tooling full control of file selectors-
49static const char env_override[] = "QT_NO_BUILTIN_SELECTORS";-
50-
51static const ushort selectorIndicator = '+';-
52-
53Q_GLOBAL_STATIC(QFileSelectorSharedData, sharedData);
executed 1 time by 1 test: end of block
Executed by:
  • tst_qfileselectors - unknown status
executed 1 time by 1 test: guard.store(QtGlobalStatic::Destroyed);
Executed by:
  • tst_qfileselectors - unknown status
executed 40 times by 1 test: return &holder.value;
Executed by:
  • tst_QFileSelector
guard.load() =...c::InitializedDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • tst_qfileselectors - unknown status
FALSEnever evaluated
0-40
54static QBasicMutex sharedDataMutex;-
55-
56QFileSelectorPrivate::QFileSelectorPrivate()-
57 : QObjectPrivate()-
58{-
59}
executed 18 times by 1 test: end of block
Executed by:
  • tst_QFileSelector
18
60-
61/*!-
62 \class QFileSelector-
63 \inmodule QtCore-
64 \brief QFileSelector provides a convenient way of selecting file variants.-
65 \since 5.2-
66-
67 QFileSelector is a convenience for selecting file variants based on platform or device-
68 characteristics. This allows you to develop and deploy one codebase containing all the-
69 different variants more easily in some circumstances, such as when the correct variant cannot-
70 be determined during the deploy step.-
71-
72 \section1 Using QFileSelector-
73-
74 If you always use the same file you do not need to use QFileSelector.-
75-
76 Consider the following example usage, where you want to use different settings files on-
77 different locales. You might select code between locales like this:-
78-
79 \code-
80 QString defaultsBasePath = "data/";-
81 QString defaultsPath = defaultsBasePath + "defaults.conf";-
82 QString localizedPath = defaultsBasePath-
83 + QString("%1/defaults.conf").arg(QLocale().name());-
84 if (QFile::exists(localizedPath))-
85 defaultsPath = localizedPath;-
86 QFile defaults(defaultsPath);-
87 \endcode-
88-
89 Similarly, if you want to pick a different data file based on target platform,-
90 your code might look something like this:-
91 \code-
92 QString defaultsPath = "data/defaults.conf";-
93#if defined(Q_OS_ANDROID)-
94 defaultsPath = "data/android/defaults.conf";-
95#elif defined(Q_OS_BLACKBERRY)-
96 defaultsPath = "data/blackberry/defaults.conf";-
97#elif defined(Q_OS_IOS)-
98 defaultsPath = "data/ios/defaults.conf";-
99#endif-
100 QFile defaults(defaultsPath);-
101 \endcode-
102-
103 QFileSelector provides a convenient alternative to writing such boilerplate code, and in the-
104 latter case it allows you to start using an platform-specific configuration without a recompile.-
105 QFileSelector also allows for chaining of multiple selectors in a convenient way, for example-
106 selecting a different file only on certain combinations of platform and locale. For example, to-
107 select based on platform and/or locale, the code is as follows:-
108-
109 \code-
110 QFileSelector selector;-
111 QFile defaultsFile(selector.select("data/defaults.conf"));-
112 \endcode-
113-
114 The files to be selected are placed in directories named with a \c'+' and a selector name. In the above-
115 example you could have the platform configurations selected by placing them in the following locations:-
116 \code-
117 data/defaults.conf-
118 data/+android/defaults.conf-
119 data/+blackberry/defaults.conf-
120 data/+ios/+en_GB/defaults.conf-
121 \endcode-
122-
123 To find selected files, QFileSelector looks in the same directory as the base file. If there are-
124 any directories of the form +<selector> with an active selector, QFileSelector will prefer a file-
125 with the same file name from that directory over the base file. These directories can be nested to-
126 check against multiple selectors, for example:-
127 \code-
128 images/background.png-
129 images/+android/+en_GB/background.png-
130 images/+blackberry/+en_GB/background.png-
131 \endcode-
132 With those files available, you would select a different file on android and blackberry platforms,-
133 but only if the locale was en_GB.-
134-
135 QFileSelector will not attempt to select if the base file does not exist. For error handling in-
136 the case no valid selectors are present, it is recommended to have a default or error-handling-
137 file in the base file location even if you expect selectors to be present for all deployments.-
138-
139 In a future version, some may be marked as deploy-time static and be moved during the-
140 deployment step as an optimization. As selectors come with a performance cost, it is-
141 recommended to avoid their use in circumstances involving performance-critical code.-
142-
143 \section1 Adding Selectors-
144-
145 Selectors normally available are-
146 \list-
147 \li platform, any of the following strings which match the platform the application is running-
148 on (list not exhaustive): android, blackberry, ios, osx, darwin, mac, linux, wince, unix,-
149 windows. On Linux, if it can be determined, the name of the distribution too, like debian,-
150 fedora or opensuse.-
151 \li locale, same as QLocale().name().-
152 \endlist-
153-
154 Further selectors will be added from the \c QT_FILE_SELECTORS environment variable, which-
155 when set should be a set of comma separated selectors. Note that this variable will only be-
156 read once; selectors may not update if the variable changes while the application is running.-
157 The initial set of selectors are evaluated only once, on first use.-
158-
159 You can also add extra selectors at runtime for custom behavior. These will be used in any-
160 future calls to select(). If the extra selectors list has been changed, calls to select() will-
161 use the new list and may return differently.-
162-
163 \section1 Conflict Resolution when Multiple Selectors Apply-
164-
165 When multiple selectors could be applied to the same file, the first matching selector is chosen.-
166 The order selectors are checked in are:-
167-
168 \list 1-
169 \li Selectors set via setExtraSelectors(), in the order they are in the list-
170 \li Selectors in the \c QT_FILE_SELECTORS environment variable, from left to right-
171 \li Locale-
172 \li Platform-
173 \endlist-
174-
175 Here is an example involving multiple selectors matching at the same time. It uses platform-
176 selectors, plus an extra selector named "admin" is set by the application based on user-
177 credentials. The example is sorted so that the lowest matching file would be chosen if all-
178 selectors were present:-
179-
180 \code-
181 images/background.png-
182 images/+linux/background.png-
183 images/+windows/background.png-
184 images/+admin/background.png-
185 images/+admin/+linux/background.png-
186 \endcode-
187-
188 Because extra selectors are checked before platform the \c{+admin/background.png} will be chosen-
189 on Windows when the admin selector is set, and \c{+windows/background.png} will be chosen on-
190 Windows when the admin selector is not set. On Linux, the \c{+admin/+linux/background.png} will be-
191 chosen when admin is set, and the \c{+linux/background.png} when it is not.-
192-
193*/-
194-
195/*!-
196 Create a QFileSelector instance. This instance will have the same static selectors as other-
197 QFileSelector instances, but its own set of extra selectors.-
198-
199 If supplied, it will have the given QObject \a parent.-
200*/-
201QFileSelector::QFileSelector(QObject *parent)-
202 : QObject(*(new QFileSelectorPrivate()), parent)-
203{-
204}
executed 18 times by 1 test: end of block
Executed by:
  • tst_QFileSelector
18
205-
206/*!-
207 Destroys this selector instance.-
208*/-
209QFileSelector::~QFileSelector()-
210{-
211}-
212-
213/*!-
214 This function returns the selected version of the path, based on the conditions at runtime.-
215 If no selectable files are present, returns the original \a filePath.-
216-
217 If the original file does not exist, the original \a filePath is returned. This means that you-
218 must have a base file to fall back on, you cannot have only files in selectable sub-directories.-
219-
220 See the class overview for the selection algorithm.-
221*/-
222QString QFileSelector::select(const QString &filePath) const-
223{-
224 Q_D(const QFileSelector);-
225 return d->select(filePath);
executed 15 times by 1 test: return d->select(filePath);
Executed by:
  • tst_QFileSelector
15
226}-
227-
228static bool isLocalScheme(const QString &file)-
229{-
230 bool local = file == QLatin1String("qrc");-
231#ifdef Q_OS_ANDROID-
232 local |= file == QLatin1String("assets");-
233#endif-
234 return local;
executed 10 times by 1 test: return local;
Executed by:
  • tst_QFileSelector
10
235}-
236-
237/*!-
238 This is a convenience version of select operating on QUrl objects. If the scheme is not file or qrc,-
239 \a filePath is returned immediately. Otherwise selection is applied to the path of \a filePath-
240 and a QUrl is returned with the selected path and other QUrl parts the same as \a filePath.-
241-
242 See the class overview for the selection algorithm.-
243*/-
244QUrl QFileSelector::select(const QUrl &filePath) const-
245{-
246 Q_D(const QFileSelector);-
247 if (!isLocalScheme(filePath.scheme()) && !filePath.isLocalFile())
!isLocalScheme...Path.scheme())Description
TRUEevaluated 4 times by 1 test
Evaluated by:
  • tst_QFileSelector
FALSEevaluated 2 times by 1 test
Evaluated by:
  • tst_QFileSelector
!filePath.isLocalFile()Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • tst_QFileSelector
FALSEevaluated 2 times by 1 test
Evaluated by:
  • tst_QFileSelector
2-4
248 return filePath;
executed 2 times by 1 test: return filePath;
Executed by:
  • tst_QFileSelector
2
249 QUrl ret(filePath);-
250 if (isLocalScheme(filePath.scheme())) {
isLocalScheme(...Path.scheme())Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • tst_QFileSelector
FALSEevaluated 2 times by 1 test
Evaluated by:
  • tst_QFileSelector
2
251 QLatin1String scheme(":");-
252#ifdef Q_OS_ANDROID-
253 // use other scheme because ":" means "qrc" here-
254 if (filePath.scheme() == QLatin1String("assets"))-
255 scheme = QLatin1String("assets:");-
256#endif-
257-
258 QString equivalentPath = scheme + filePath.path();-
259 QString selectedPath = d->select(equivalentPath);-
260 ret.setPath(selectedPath.remove(0, scheme.size()));-
261 } else {
executed 2 times by 1 test: end of block
Executed by:
  • tst_QFileSelector
2
262 ret = QUrl::fromLocalFile(d->select(ret.toLocalFile()));-
263 }
executed 2 times by 1 test: end of block
Executed by:
  • tst_QFileSelector
2
264 return ret;
executed 4 times by 1 test: return ret;
Executed by:
  • tst_QFileSelector
4
265}-
266-
267static QString selectionHelper(const QString &path, const QString &fileName, const QStringList &selectors)-
268{-
269 /* selectionHelper does a depth-first search of possible selected files. Because there is strict-
270 selector ordering in the API, we can stop checking as soon as we find the file in a directory-
271 which does not contain any other valid selector directories.-
272 */-
273 Q_ASSERT(path.isEmpty() || path.endsWith(QLatin1Char('/')));-
274-
275 foreach (const QString &s, selectors) {-
276 QString prospectiveBase = path + QLatin1Char(selectorIndicator) + s + QLatin1Char('/');-
277 QStringList remainingSelectors = selectors;-
278 remainingSelectors.removeAll(s);-
279 if (!QDir(prospectiveBase).exists())
!QDir(prospect...Base).exists()Description
TRUEevaluated 87 times by 1 test
Evaluated by:
  • tst_QFileSelector
FALSEevaluated 22 times by 1 test
Evaluated by:
  • tst_QFileSelector
22-87
280 continue;
executed 87 times by 1 test: continue;
Executed by:
  • tst_QFileSelector
87
281 QString prospectiveFile = selectionHelper(prospectiveBase, fileName, remainingSelectors);-
282 if (!prospectiveFile.isEmpty())
!prospectiveFile.isEmpty()Description
TRUEevaluated 18 times by 1 test
Evaluated by:
  • tst_QFileSelector
FALSEevaluated 4 times by 1 test
Evaluated by:
  • tst_QFileSelector
4-18
283 return prospectiveFile;
executed 18 times by 1 test: return prospectiveFile;
Executed by:
  • tst_QFileSelector
18
284 }
executed 4 times by 1 test: end of block
Executed by:
  • tst_QFileSelector
4
285-
286 // If we reach here there were no successful files found at a lower level in this branch, so we-
287 // should check this level as a potential result.-
288 if (!QFile::exists(path + fileName))
!QFile::exists...th + fileName)Description
TRUEevaluated 4 times by 1 test
Evaluated by:
  • tst_QFileSelector
FALSEevaluated 18 times by 1 test
Evaluated by:
  • tst_QFileSelector
4-18
289 return QString();
executed 4 times by 1 test: return QString();
Executed by:
  • tst_QFileSelector
4
290 return path + fileName;
executed 18 times by 1 test: return path + fileName;
Executed by:
  • tst_QFileSelector
18
291}-
292-
293QString QFileSelectorPrivate::select(const QString &filePath) const-
294{-
295 Q_Q(const QFileSelector);-
296 QFileInfo fi(filePath);-
297 // If file doesn't exist, don't select-
298 if (!fi.exists())
!fi.exists()Description
TRUEevaluated 1 time by 1 test
Evaluated by:
  • tst_QFileSelector
FALSEevaluated 18 times by 1 test
Evaluated by:
  • tst_QFileSelector
1-18
299 return filePath;
executed 1 time by 1 test: return filePath;
Executed by:
  • tst_QFileSelector
1
300-
301 QString ret = selectionHelper(fi.path().isEmpty() ? QString() : fi.path() + QLatin1Char('/'),-
302 fi.fileName(), q->allSelectors());-
303-
304 if (!ret.isEmpty())
!ret.isEmpty()Description
TRUEevaluated 18 times by 1 test
Evaluated by:
  • tst_QFileSelector
FALSEnever evaluated
0-18
305 return ret;
executed 18 times by 1 test: return ret;
Executed by:
  • tst_QFileSelector
18
306 return filePath;
never executed: return filePath;
0
307}-
308-
309/*!-
310 Returns the list of extra selectors which have been added programmatically to this instance.-
311*/-
312QStringList QFileSelector::extraSelectors() const-
313{-
314 Q_D(const QFileSelector);-
315 return d->extras;
never executed: return d->extras;
0
316}-
317-
318/*!-
319 Sets the \a list of extra selectors which have been added programmatically to this instance.-
320-
321 These selectors have priority over any which have been automatically picked up.-
322*/-
323void QFileSelector::setExtraSelectors(const QStringList &list)-
324{-
325 Q_D(QFileSelector);-
326 d->extras = list;-
327}
executed 18 times by 1 test: end of block
Executed by:
  • tst_QFileSelector
18
328-
329/*!-
330 Returns the complete, ordered list of selectors used by this instance-
331*/-
332QStringList QFileSelector::allSelectors() const-
333{-
334 Q_D(const QFileSelector);-
335 QMutexLocker locker(&sharedDataMutex);-
336 QFileSelectorPrivate::updateSelectors();-
337 return d->extras + sharedData->staticSelectors;
executed 18 times by 1 test: return d->extras + sharedData->staticSelectors;
Executed by:
  • tst_QFileSelector
18
338}-
339-
340void QFileSelectorPrivate::updateSelectors()-
341{-
342 if (!sharedData->staticSelectors.isEmpty())
!sharedData->s...tors.isEmpty()Description
TRUEevaluated 17 times by 1 test
Evaluated by:
  • tst_QFileSelector
FALSEevaluated 1 time by 1 test
Evaluated by:
  • tst_QFileSelector
1-17
343 return; //Already loaded
executed 17 times by 1 test: return;
Executed by:
  • tst_QFileSelector
17
344-
345 QLatin1Char pathSep(',');-
346 QStringList envSelectors = QString::fromLatin1(qgetenv("QT_FILE_SELECTORS"))-
347 .split(pathSep, QString::SkipEmptyParts);-
348 if (envSelectors.count())
envSelectors.count()Description
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • tst_QFileSelector
0-1
349 sharedData->staticSelectors << envSelectors;
never executed: sharedData->staticSelectors << envSelectors;
0
350-
351 if (!qEnvironmentVariableIsEmpty(env_override))
!qEnvironmentV...(env_override)Description
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • tst_QFileSelector
0-1
352 return;
never executed: return;
0
353-
354 sharedData->staticSelectors << sharedData->preloadedStatics; //Potential for static selectors from other modules-
355-
356 // TODO: Update on locale changed?-
357 sharedData->staticSelectors << QLocale().name();-
358-
359 sharedData->staticSelectors << platformSelectors();-
360}
executed 1 time by 1 test: end of block
Executed by:
  • tst_QFileSelector
1
361-
362QStringList QFileSelectorPrivate::platformSelectors()-
363{-
364 // similar, but not identical to QSysInfo::osType-
365 QStringList ret;-
366#if defined(Q_OS_WIN)-
367 // can't fall back to QSysInfo because we need both "winphone" and "winrt" for the Windows Phone case-
368 ret << QStringLiteral("windows");-
369 ret << QSysInfo::kernelType(); // "wince" and "winnt"-
370# if defined(Q_OS_WINRT)-
371 ret << QStringLiteral("winrt");-
372# if defined(Q_OS_WINPHONE)-
373 ret << QStringLiteral("winphone");-
374# endif-
375# endif-
376#elif defined(Q_OS_UNIX)-
377 ret << QStringLiteral("unix");
executed 2 times by 1 test: return qstring_literal_temp;
Executed by:
  • tst_QFileSelector
2
378# if !defined(Q_OS_ANDROID) && !defined(Q_OS_BLACKBERRY)-
379 // we don't want "linux" for Android or "qnx" for Blackberry here-
380 ret << QSysInfo::kernelType();-
381# ifdef Q_OS_MAC-
382 ret << QStringLiteral("mac"); // compatibility, since kernelType() is "darwin"-
383# endif-
384# endif-
385 QString productName = QSysInfo::productType();-
386# ifdef Q_OS_MACOS-
387 if (productName != QStringLiteral("osx"))-
388 ret << QStringLiteral("osx"); // compatibility-
389# endif-
390 if (productName != QLatin1String("unknown"))
productName !=...ing("unknown")Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • tst_QFileSelector
FALSEnever evaluated
0-2
391 ret << productName; // "opensuse", "fedora", "macos", "ios", "blackberry", "android"
executed 2 times by 1 test: ret << productName;
Executed by:
  • tst_QFileSelector
2
392#endif-
393 return ret;
executed 2 times by 1 test: return ret;
Executed by:
  • tst_QFileSelector
2
394}-
395-
396void QFileSelectorPrivate::addStatics(const QStringList &statics)-
397{-
398 QMutexLocker locker(&sharedDataMutex);-
399 sharedData->preloadedStatics << statics;-
400}
never executed: end of block
0
401-
402QT_END_NAMESPACE-
403-
404#include "moc_qfileselector.cpp"-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9