1 | // Copyright (C) 2018 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qqmlpreviewfileloader.h" |
5 | #include "qqmlpreviewservice.h" |
6 | |
7 | #include <QtQml/qqmlfile.h> |
8 | |
9 | #include <QtCore/qlibraryinfo.h> |
10 | #include <QtCore/qstandardpaths.h> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | QQmlPreviewFileLoader::QQmlPreviewFileLoader(QQmlPreviewServiceImpl *service) : m_service(service) |
15 | { |
16 | // Exclude some resource paths used by Qt itself. There is no point in loading those from the |
17 | // client as the client will not have the files (or even worse, it may have different ones). |
18 | m_blacklist.blacklist(path: ":/qt-project.org" ); |
19 | m_blacklist.blacklist(path: ":/QtQuick/Controls/Styles" ); |
20 | m_blacklist.blacklist(path: ":/ExtrasImports/QtQuick/Controls/Styles" ); |
21 | |
22 | // Target specific configuration should not replaced with files from the host. |
23 | m_blacklist.blacklist(path: "/etc" ); |
24 | |
25 | for (int loc = QLibraryInfo::PrefixPath; loc < QLibraryInfo::TestsPath; ++loc) { |
26 | m_blacklist.blacklist(path: QLibraryInfo::path( |
27 | p: static_cast<QLibraryInfo::LibraryPath>(loc))); |
28 | } |
29 | m_blacklist.blacklist(path: QLibraryInfo::path(p: QLibraryInfo::SettingsPath)); |
30 | |
31 | static const QStandardPaths::StandardLocation blackListLocations[] = { |
32 | QStandardPaths::CacheLocation, |
33 | QStandardPaths::GenericDataLocation, |
34 | QStandardPaths::ConfigLocation, |
35 | QStandardPaths::GenericCacheLocation, |
36 | QStandardPaths::GenericConfigLocation, |
37 | QStandardPaths::AppDataLocation, |
38 | QStandardPaths::AppConfigLocation |
39 | }; |
40 | |
41 | for (auto locationType : blackListLocations) { |
42 | const QStringList locations = QStandardPaths::standardLocations(type: locationType); |
43 | for (const QString &location : locations) |
44 | m_blacklist.blacklist(path: location); |
45 | } |
46 | |
47 | m_blacklist.whitelist(path: QLibraryInfo::path(p: QLibraryInfo::TestsPath)); |
48 | |
49 | connect(sender: this, signal: &QQmlPreviewFileLoader::request, context: service, slot: &QQmlPreviewServiceImpl::forwardRequest, |
50 | type: Qt::DirectConnection); |
51 | connect(sender: service, signal: &QQmlPreviewServiceImpl::directory, context: this, slot: &QQmlPreviewFileLoader::directory); |
52 | connect(sender: service, signal: &QQmlPreviewServiceImpl::file, context: this, slot: &QQmlPreviewFileLoader::file); |
53 | connect(sender: service, signal: &QQmlPreviewServiceImpl::error, context: this, slot: &QQmlPreviewFileLoader::error); |
54 | connect(sender: service, signal: &QQmlPreviewServiceImpl::clearCache, context: this, slot: &QQmlPreviewFileLoader::clearCache); |
55 | moveToThread(thread: &m_thread); |
56 | m_thread.start(); |
57 | } |
58 | |
59 | QQmlPreviewFileLoader::~QQmlPreviewFileLoader() { |
60 | m_thread.quit(); |
61 | m_thread.wait(); |
62 | } |
63 | |
64 | QQmlPreviewFileLoader::Result QQmlPreviewFileLoader::load(const QString &path) |
65 | { |
66 | QMutexLocker locker(&m_contentMutex); |
67 | m_path = path; |
68 | |
69 | auto fileIterator = m_fileCache.constFind(key: path); |
70 | if (fileIterator != m_fileCache.constEnd()) { |
71 | m_result = File; |
72 | m_contents = *fileIterator; |
73 | m_entries.clear(); |
74 | return m_result; |
75 | } |
76 | |
77 | auto dirIterator = m_directoryCache.constFind(key: path); |
78 | if (dirIterator != m_directoryCache.constEnd()) { |
79 | m_result = Directory; |
80 | m_contents.clear(); |
81 | m_entries = *dirIterator; |
82 | return m_result; |
83 | } |
84 | |
85 | m_result = Unknown; |
86 | m_entries.clear(); |
87 | m_contents.clear(); |
88 | emit request(file: path); |
89 | m_waitCondition.wait(lockedMutex: &m_contentMutex); |
90 | return m_result; |
91 | } |
92 | |
93 | QByteArray QQmlPreviewFileLoader::contents() |
94 | { |
95 | QMutexLocker locker(&m_contentMutex); |
96 | return m_contents; |
97 | } |
98 | |
99 | QStringList QQmlPreviewFileLoader::entries() |
100 | { |
101 | QMutexLocker locker(&m_contentMutex); |
102 | return m_entries; |
103 | } |
104 | |
105 | void QQmlPreviewFileLoader::whitelist(const QUrl &url) |
106 | { |
107 | const QString path = QQmlFile::urlToLocalFileOrQrc(url); |
108 | if (!path.isEmpty()) { |
109 | QMutexLocker locker(&m_contentMutex); |
110 | m_blacklist.whitelist(path); |
111 | } |
112 | } |
113 | |
114 | bool QQmlPreviewFileLoader::isBlacklisted(const QString &path) |
115 | { |
116 | QMutexLocker locker(&m_contentMutex); |
117 | return m_blacklist.isBlacklisted(path); |
118 | } |
119 | |
120 | void QQmlPreviewFileLoader::file(const QString &path, const QByteArray &contents) |
121 | { |
122 | QMutexLocker locker(&m_contentMutex); |
123 | m_blacklist.whitelist(path); |
124 | m_fileCache[path] = contents; |
125 | if (path == m_path) { |
126 | m_contents = contents; |
127 | m_result = File; |
128 | m_waitCondition.wakeOne(); |
129 | } |
130 | } |
131 | |
132 | void QQmlPreviewFileLoader::directory(const QString &path, const QStringList &entries) |
133 | { |
134 | QMutexLocker locker(&m_contentMutex); |
135 | m_blacklist.whitelist(path); |
136 | m_directoryCache[path] = entries; |
137 | if (path == m_path) { |
138 | m_entries = entries; |
139 | m_result = Directory; |
140 | m_waitCondition.wakeOne(); |
141 | } |
142 | } |
143 | |
144 | void QQmlPreviewFileLoader::error(const QString &path) |
145 | { |
146 | QMutexLocker locker(&m_contentMutex); |
147 | m_blacklist.blacklist(path); |
148 | if (path == m_path) { |
149 | m_result = Fallback; |
150 | m_waitCondition.wakeOne(); |
151 | } |
152 | } |
153 | |
154 | void QQmlPreviewFileLoader::clearCache() |
155 | { |
156 | QMutexLocker locker(&m_contentMutex); |
157 | m_fileCache.clear(); |
158 | m_directoryCache.clear(); |
159 | } |
160 | |
161 | QT_END_NAMESPACE |
162 | |
163 | #include "moc_qqmlpreviewfileloader.cpp" |
164 | |