1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QML preview debug service.
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 "qqmlpreviewfileloader.h"
41#include "qqmlpreviewservice.h"
42
43#include <QtQml/qqmlfile.h>
44
45#include <QtCore/qlibraryinfo.h>
46#include <QtCore/qstandardpaths.h>
47
48QT_BEGIN_NAMESPACE
49
50QQmlPreviewFileLoader::QQmlPreviewFileLoader(QQmlPreviewServiceImpl *service) : m_service(service)
51{
52 // Exclude some resource paths used by Qt itself. There is no point in loading those from the
53 // client as the client will not have the files (or even worse, it may have different ones).
54 m_blacklist.blacklist(path: ":/qt-project.org");
55 m_blacklist.blacklist(path: ":/QtQuick/Controls/Styles");
56 m_blacklist.blacklist(path: ":/ExtrasImports/QtQuick/Controls/Styles");
57 m_blacklist.blacklist(path: ":/qgradient");
58
59 // Target specific configuration should not replaced with files from the host.
60 m_blacklist.blacklist(path: "/etc");
61
62 for (int loc = QLibraryInfo::PrefixPath; loc < QLibraryInfo::TestsPath; ++loc) {
63 m_blacklist.blacklist(path: QLibraryInfo::location(
64 static_cast<QLibraryInfo::LibraryLocation>(loc)));
65 }
66 m_blacklist.blacklist(path: QLibraryInfo::location(QLibraryInfo::SettingsPath));
67
68 static const QStandardPaths::StandardLocation blackListLocations[] = {
69 QStandardPaths::DataLocation,
70 QStandardPaths::CacheLocation,
71 QStandardPaths::GenericDataLocation,
72 QStandardPaths::ConfigLocation,
73 QStandardPaths::GenericCacheLocation,
74 QStandardPaths::GenericConfigLocation,
75 QStandardPaths::AppDataLocation,
76 QStandardPaths::AppConfigLocation
77 };
78
79 for (auto locationType : blackListLocations) {
80 const QStringList locations = QStandardPaths::standardLocations(type: locationType);
81 for (const QString &location : locations)
82 m_blacklist.blacklist(path: location);
83 }
84
85 m_blacklist.whitelist(path: QLibraryInfo::location(QLibraryInfo::TestsPath));
86
87 connect(sender: this, signal: &QQmlPreviewFileLoader::request, receiver: service, slot: &QQmlPreviewServiceImpl::forwardRequest,
88 type: Qt::DirectConnection);
89 connect(sender: service, signal: &QQmlPreviewServiceImpl::directory, receiver: this, slot: &QQmlPreviewFileLoader::directory);
90 connect(sender: service, signal: &QQmlPreviewServiceImpl::file, receiver: this, slot: &QQmlPreviewFileLoader::file);
91 connect(sender: service, signal: &QQmlPreviewServiceImpl::error, receiver: this, slot: &QQmlPreviewFileLoader::error);
92 connect(sender: service, signal: &QQmlPreviewServiceImpl::clearCache, receiver: this, slot: &QQmlPreviewFileLoader::clearCache);
93 moveToThread(thread: &m_thread);
94 m_thread.start();
95}
96
97QQmlPreviewFileLoader::~QQmlPreviewFileLoader() {
98 m_thread.quit();
99 m_thread.wait();
100}
101
102QQmlPreviewFileLoader::Result QQmlPreviewFileLoader::load(const QString &path)
103{
104 QMutexLocker locker(&m_contentMutex);
105 m_path = path;
106
107 auto fileIterator = m_fileCache.constFind(akey: path);
108 if (fileIterator != m_fileCache.constEnd()) {
109 m_result = File;
110 m_contents = *fileIterator;
111 m_entries.clear();
112 return m_result;
113 }
114
115 auto dirIterator = m_directoryCache.constFind(akey: path);
116 if (dirIterator != m_directoryCache.constEnd()) {
117 m_result = Directory;
118 m_contents.clear();
119 m_entries = *dirIterator;
120 return m_result;
121 }
122
123 m_result = Unknown;
124 m_entries.clear();
125 m_contents.clear();
126 emit request(file: path);
127 m_waitCondition.wait(lockedMutex: &m_contentMutex);
128 return m_result;
129}
130
131QByteArray QQmlPreviewFileLoader::contents()
132{
133 QMutexLocker locker(&m_contentMutex);
134 return m_contents;
135}
136
137QStringList QQmlPreviewFileLoader::entries()
138{
139 QMutexLocker locker(&m_contentMutex);
140 return m_entries;
141}
142
143void QQmlPreviewFileLoader::whitelist(const QUrl &url)
144{
145 const QString path = QQmlFile::urlToLocalFileOrQrc(url);
146 if (!path.isEmpty()) {
147 QMutexLocker locker(&m_contentMutex);
148 m_blacklist.whitelist(path);
149 }
150}
151
152bool QQmlPreviewFileLoader::isBlacklisted(const QString &path)
153{
154 QMutexLocker locker(&m_contentMutex);
155 return m_blacklist.isBlacklisted(path);
156}
157
158void QQmlPreviewFileLoader::file(const QString &path, const QByteArray &contents)
159{
160 QMutexLocker locker(&m_contentMutex);
161 m_blacklist.whitelist(path);
162 m_fileCache[path] = contents;
163 if (path == m_path) {
164 m_contents = contents;
165 m_result = File;
166 m_waitCondition.wakeOne();
167 }
168}
169
170void QQmlPreviewFileLoader::directory(const QString &path, const QStringList &entries)
171{
172 QMutexLocker locker(&m_contentMutex);
173 m_blacklist.whitelist(path);
174 m_directoryCache[path] = entries;
175 if (path == m_path) {
176 m_entries = entries;
177 m_result = Directory;
178 m_waitCondition.wakeOne();
179 }
180}
181
182void QQmlPreviewFileLoader::error(const QString &path)
183{
184 QMutexLocker locker(&m_contentMutex);
185 m_blacklist.blacklist(path);
186 if (path == m_path) {
187 m_result = Fallback;
188 m_waitCondition.wakeOne();
189 }
190}
191
192void QQmlPreviewFileLoader::clearCache()
193{
194 QMutexLocker locker(&m_contentMutex);
195 m_fileCache.clear();
196 m_directoryCache.clear();
197}
198
199QT_END_NAMESPACE
200

source code of qtdeclarative/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp