1/***************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
5** Contact: http://www.qt.io/licensing/
6**
7** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qquickstyleselector_p.h"
42#include "qquickstyleselector_p_p.h"
43
44#include <QtCore/qfileinfo.h>
45#include <QtCore/qlocale.h>
46#include <QtCore/qloggingcategory.h>
47#include <QtCore/private/qfileselector_p.h>
48
49QT_BEGIN_NAMESPACE
50
51Q_LOGGING_CATEGORY(lcQtQuickControlsStyle, "qt.quick.controls.style")
52
53static QString ensureSlash(const QString &path)
54{
55 if (path.isEmpty() || path.endsWith(c: QLatin1Char('/')))
56 return path;
57 return path + QLatin1Char('/');
58}
59
60static QStringList prefixedPlatformSelectors(const QChar &prefix)
61{
62 QStringList selectors = QFileSelectorPrivate::platformSelectors();
63 for (int i = 0; i < selectors.count(); ++i)
64 selectors[i].prepend(c: prefix);
65 return selectors;
66}
67
68static QStringList allSelectors()
69{
70 static const QStringList platformSelectors = prefixedPlatformSelectors(prefix: QLatin1Char('+'));
71 QStringList selectors = platformSelectors;
72 const QString locale = QLocale().name();
73 if (!locale.isEmpty())
74 selectors += QLatin1Char('+') + locale;
75 return selectors;
76}
77
78QUrl QQuickStyleSelectorPrivate::select(const QString &filePath) const
79{
80 QFileInfo fi(filePath);
81 // If file doesn't exist, don't select
82 if (!fi.exists())
83 return QUrl();
84
85 const QString selected = QFileSelectorPrivate::selectionHelper(path: ensureSlash(path: fi.canonicalPath()),
86 fileName: fi.fileName(), selectors: allSelectors(), indicator: QChar());
87
88 if (selected.startsWith(c: QLatin1Char(':')))
89 return QUrl(QLatin1String("qrc") + selected);
90
91 return QUrl::fromLocalFile(localfile: selected.isEmpty() ? filePath : selected);
92}
93
94QQuickStyleSelector::QQuickStyleSelector() : d_ptr(new QQuickStyleSelectorPrivate)
95{
96}
97
98QQuickStyleSelector::~QQuickStyleSelector()
99{
100}
101
102QStringList QQuickStyleSelector::selectors() const
103{
104 Q_D(const QQuickStyleSelector);
105 return d->selectors;
106}
107
108void QQuickStyleSelector::addSelector(const QString &selector)
109{
110 Q_D(QQuickStyleSelector);
111 if (d->selectors.contains(str: selector))
112 return;
113
114 d->selectors += selector;
115}
116
117QStringList QQuickStyleSelector::paths() const
118{
119 Q_D(const QQuickStyleSelector);
120 return d->paths;
121}
122
123void QQuickStyleSelector::setPaths(const QStringList &paths)
124{
125 Q_D(QQuickStyleSelector);
126 d->paths = paths;
127}
128
129QUrl QQuickStyleSelector::select(const QString &fileName) const
130{
131 Q_D(const QQuickStyleSelector);
132 // The lookup order is
133 // 1) requested style (e.g. "MyStyle", included in d->selectors)
134 // 2) fallback style (e.g. "Material", included in d->selectors)
135 // 3) default style (empty selector, not in d->selectors)
136 qCDebug(lcQtQuickControlsStyle) << "selecting" << fileName << "from" << d->paths << "with selectors" << d->selectors;
137
138 int to = d->selectors.count() - 1;
139 if (d->selectors.isEmpty() || !d->selectors.first().isEmpty())
140 ++to; // lookup #3 unless #1 is also empty (redundant)
141
142 // NOTE: last iteration intentionally out of bounds => empty selector
143 for (int i = 0; i <= to; ++i) {
144 const QString selector = d->selectors.value(i);
145 for (const QString &path : d->paths) {
146 const QUrl selectedUrl = d->select(filePath: ensureSlash(path) + selector + QLatin1Char('/') + fileName);
147 if (selectedUrl.isValid()) {
148 qCDebug(lcQtQuickControlsStyle) << "==>" << selectedUrl << "from" << path << "with selector" << selector;
149 return selectedUrl;
150 }
151 }
152 }
153
154 return fileName;
155}
156
157QT_END_NAMESPACE
158

source code of qtquickcontrols2/src/quickcontrols2/qquickstyleselector.cpp