1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the Qt Designer of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include "qtresourcemodel_p.h"
|
---|
43 | #include <rcc.h>
|
---|
44 |
|
---|
45 | #include <QtCore/QStringList>
|
---|
46 | #include <QtCore/QMap>
|
---|
47 | #include <QtCore/QResource>
|
---|
48 | #include <QtCore/QFileInfo>
|
---|
49 | #include <QtCore/QIODevice>
|
---|
50 | #include <QtCore/QDir>
|
---|
51 | #include <QtCore/QDebug>
|
---|
52 | #include <QtCore/QBuffer>
|
---|
53 | #include <QtCore/QFileSystemWatcher>
|
---|
54 |
|
---|
55 | QT_BEGIN_NAMESPACE
|
---|
56 |
|
---|
57 | enum { debugResourceModel = 0 };
|
---|
58 |
|
---|
59 | // ------------------- QtResourceSetPrivate
|
---|
60 | class QtResourceSetPrivate
|
---|
61 | {
|
---|
62 | QtResourceSet *q_ptr;
|
---|
63 | Q_DECLARE_PUBLIC(QtResourceSet)
|
---|
64 | public:
|
---|
65 | QtResourceSetPrivate(QtResourceModel *model = 0);
|
---|
66 |
|
---|
67 | QtResourceModel *m_resourceModel;
|
---|
68 | };
|
---|
69 |
|
---|
70 | QtResourceSetPrivate::QtResourceSetPrivate(QtResourceModel *model) :
|
---|
71 | q_ptr(0),
|
---|
72 | m_resourceModel(model)
|
---|
73 | {
|
---|
74 | }
|
---|
75 |
|
---|
76 | // -------------------- QtResourceModelPrivate
|
---|
77 | class QtResourceModelPrivate
|
---|
78 | {
|
---|
79 | QtResourceModel *q_ptr;
|
---|
80 | Q_DECLARE_PUBLIC(QtResourceModel)
|
---|
81 | Q_DISABLE_COPY(QtResourceModelPrivate)
|
---|
82 | public:
|
---|
83 | QtResourceModelPrivate();
|
---|
84 | void activate(QtResourceSet *resourceSet, const QStringList &newPaths, int *errorCount = 0, QString *errorMessages = 0);
|
---|
85 | void removeOldPaths(QtResourceSet *resourceSet, const QStringList &newPaths);
|
---|
86 |
|
---|
87 | QMap<QString, bool> m_pathToModified;
|
---|
88 | QMap<QtResourceSet *, QStringList> m_resourceSetToPaths;
|
---|
89 | QMap<QtResourceSet *, bool> m_resourceSetToReload; // while path is recreated it needs to be reregistered
|
---|
90 | // (it is - in the new current resource set, but when the path was used in
|
---|
91 | // other resource set
|
---|
92 | // then later when that resource set is activated it needs to be reregistered)
|
---|
93 | QMap<QtResourceSet *, bool> m_newlyCreated; // all created but not activated yet
|
---|
94 | // (if was active at some point and it's not now it will not be on that map)
|
---|
95 | QMap<QString, QList<QtResourceSet *> > m_pathToResourceSet;
|
---|
96 | QtResourceSet *m_currentResourceSet;
|
---|
97 |
|
---|
98 | typedef QMap<QString, const QByteArray *> PathDataMap;
|
---|
99 | PathDataMap m_pathToData;
|
---|
100 |
|
---|
101 | QMap<QString, QStringList> m_pathToContents; // qrc path to its contents.
|
---|
102 | QMap<QString, QString> m_fileToQrc; // this map contains the content of active resource set only.
|
---|
103 | // Activating different resource set changes the contents.
|
---|
104 |
|
---|
105 | QFileSystemWatcher *m_fileWatcher;
|
---|
106 | bool m_fileWatcherEnabled;
|
---|
107 | QMap<QString, bool> m_fileWatchedMap;
|
---|
108 | private:
|
---|
109 | void registerResourceSet(QtResourceSet *resourceSet);
|
---|
110 | void unregisterResourceSet(QtResourceSet *resourceSet);
|
---|
111 | void setWatcherEnabled(const QString &path, bool enable);
|
---|
112 | void addWatcher(const QString &path);
|
---|
113 | void removeWatcher(const QString &path);
|
---|
114 |
|
---|
115 | void slotFileChanged(const QString &);
|
---|
116 |
|
---|
117 | const QByteArray *createResource(const QString &path, QStringList *contents, int *errorCount, QIODevice &errorDevice) const;
|
---|
118 | void deleteResource(const QByteArray *data) const;
|
---|
119 | };
|
---|
120 |
|
---|
121 | QtResourceModelPrivate::QtResourceModelPrivate() :
|
---|
122 | q_ptr(0),
|
---|
123 | m_currentResourceSet(0),
|
---|
124 | m_fileWatcher(0),
|
---|
125 | m_fileWatcherEnabled(true)
|
---|
126 | {
|
---|
127 | }
|
---|
128 |
|
---|
129 | // --------------------- QtResourceSet
|
---|
130 | QtResourceSet::QtResourceSet() :
|
---|
131 | d_ptr(new QtResourceSetPrivate)
|
---|
132 | {
|
---|
133 | d_ptr->q_ptr = this;
|
---|
134 | }
|
---|
135 |
|
---|
136 | QtResourceSet::QtResourceSet(QtResourceModel *model) :
|
---|
137 | d_ptr(new QtResourceSetPrivate(model))
|
---|
138 | {
|
---|
139 | d_ptr->q_ptr = this;
|
---|
140 | }
|
---|
141 |
|
---|
142 | QtResourceSet::~QtResourceSet()
|
---|
143 | {
|
---|
144 | }
|
---|
145 |
|
---|
146 | QStringList QtResourceSet::activeQrcPaths() const
|
---|
147 | {
|
---|
148 | QtResourceSet *that = const_cast<QtResourceSet *>(this);
|
---|
149 | return d_ptr->m_resourceModel->d_ptr->m_resourceSetToPaths.value(that);
|
---|
150 | }
|
---|
151 |
|
---|
152 | void QtResourceSet::activateQrcPaths(const QStringList &paths, int *errorCount, QString *errorMessages)
|
---|
153 | {
|
---|
154 | d_ptr->m_resourceModel->d_ptr->activate(this, paths, errorCount, errorMessages);
|
---|
155 | }
|
---|
156 |
|
---|
157 | bool QtResourceSet::isModified(const QString &path) const
|
---|
158 | {
|
---|
159 | return d_ptr->m_resourceModel->isModified(path);
|
---|
160 | }
|
---|
161 |
|
---|
162 | void QtResourceSet::setModified(const QString &path)
|
---|
163 | {
|
---|
164 | d_ptr->m_resourceModel->setModified(path);
|
---|
165 | }
|
---|
166 |
|
---|
167 | // ------------------- QtResourceModelPrivate
|
---|
168 | const QByteArray *QtResourceModelPrivate::createResource(const QString &path, QStringList *contents, int *errorCount, QIODevice &errorDevice) const
|
---|
169 | {
|
---|
170 | typedef RCCResourceLibrary::ResourceDataFileMap ResourceDataFileMap;
|
---|
171 | const QByteArray *rc = 0;
|
---|
172 | *errorCount = -1;
|
---|
173 | contents->clear();
|
---|
174 | do {
|
---|
175 | // run RCC
|
---|
176 | RCCResourceLibrary library;
|
---|
177 | library.setVerbose(true);
|
---|
178 | library.setInputFiles(QStringList(path));
|
---|
179 | library.setFormat(RCCResourceLibrary::Binary);
|
---|
180 |
|
---|
181 | QBuffer buffer;
|
---|
182 | buffer.open(QIODevice::WriteOnly);
|
---|
183 | if (!library.readFiles(/* ignore errors*/ true, errorDevice))
|
---|
184 | break;
|
---|
185 | // return code cannot be fully trusted, might still be empty
|
---|
186 | const ResourceDataFileMap resMap = library.resourceDataFileMap();
|
---|
187 | if (resMap.empty())
|
---|
188 | break;
|
---|
189 |
|
---|
190 | if (!library.output(buffer, errorDevice))
|
---|
191 | break;
|
---|
192 |
|
---|
193 | *errorCount = library.failedResources().size();
|
---|
194 | *contents = resMap.keys();
|
---|
195 |
|
---|
196 | buffer.close();
|
---|
197 | rc = new QByteArray(buffer.data());
|
---|
198 | } while (false);
|
---|
199 |
|
---|
200 | if (debugResourceModel)
|
---|
201 | qDebug() << "createResource" << path << "returns data=" << rc << " hasWarnings=" << *errorCount;
|
---|
202 | return rc;
|
---|
203 | }
|
---|
204 |
|
---|
205 | void QtResourceModelPrivate::deleteResource(const QByteArray *data) const
|
---|
206 | {
|
---|
207 | if (data) {
|
---|
208 | if (debugResourceModel)
|
---|
209 | qDebug() << "deleteResource";
|
---|
210 | delete data;
|
---|
211 | }
|
---|
212 | }
|
---|
213 |
|
---|
214 | void QtResourceModelPrivate::registerResourceSet(QtResourceSet *resourceSet)
|
---|
215 | {
|
---|
216 | if (!resourceSet)
|
---|
217 | return;
|
---|
218 |
|
---|
219 | // unregister old paths (all because the order of registration is important), later it can be optimized a bit
|
---|
220 | QStringList toRegister = resourceSet->activeQrcPaths();
|
---|
221 | QStringListIterator itRegister(toRegister);
|
---|
222 | while (itRegister.hasNext()) {
|
---|
223 | const QString path = itRegister.next();
|
---|
224 | if (debugResourceModel)
|
---|
225 | qDebug() << "registerResourceSet " << path;
|
---|
226 | const PathDataMap::const_iterator itRcc = m_pathToData.constFind(path);
|
---|
227 | if (itRcc != m_pathToData.constEnd()) { // otherwise data was not created yet
|
---|
228 | if (!QResource::registerResource(reinterpret_cast<const uchar *>(itRcc.value()->constData()))) {
|
---|
229 | qDebug() << "** WARNING: Failed to register " << path << " (QResource failure).";
|
---|
230 | } else {
|
---|
231 | QStringList contents = m_pathToContents.value(path);
|
---|
232 | QStringListIterator itContents(contents);
|
---|
233 | while (itContents.hasNext()) {
|
---|
234 | const QString filePath = itContents.next();
|
---|
235 | if (!m_fileToQrc.contains(filePath)) // the first loaded resource has higher priority in qt resource system
|
---|
236 | m_fileToQrc.insert(filePath, path);
|
---|
237 | }
|
---|
238 | }
|
---|
239 | }
|
---|
240 | }
|
---|
241 | }
|
---|
242 |
|
---|
243 | void QtResourceModelPrivate::unregisterResourceSet(QtResourceSet *resourceSet)
|
---|
244 | {
|
---|
245 | if (!resourceSet)
|
---|
246 | return;
|
---|
247 |
|
---|
248 | // unregister old paths (all because the order of registration is importans), later it can be optimized a bit
|
---|
249 | QStringList toUnregister = resourceSet->activeQrcPaths();
|
---|
250 | QStringListIterator itUnregister(toUnregister);
|
---|
251 | while (itUnregister.hasNext()) {
|
---|
252 | const QString path = itUnregister.next();
|
---|
253 | if (debugResourceModel)
|
---|
254 | qDebug() << "unregisterResourceSet " << path;
|
---|
255 | const PathDataMap::const_iterator itRcc = m_pathToData.constFind(path);
|
---|
256 | if (itRcc != m_pathToData.constEnd()) { // otherwise data was not created yet
|
---|
257 | if (!QResource::unregisterResource(reinterpret_cast<const uchar *>(itRcc.value()->constData())))
|
---|
258 | qDebug() << "** WARNING: Failed to unregister " << path << " (QResource failure).";
|
---|
259 | }
|
---|
260 | }
|
---|
261 | m_fileToQrc.clear();
|
---|
262 | }
|
---|
263 |
|
---|
264 | void QtResourceModelPrivate::activate(QtResourceSet *resourceSet, const QStringList &newPaths, int *errorCountPtr, QString *errorMessages)
|
---|
265 | {
|
---|
266 | if (debugResourceModel)
|
---|
267 | qDebug() << "activate " << resourceSet;
|
---|
268 | if (errorCountPtr)
|
---|
269 | *errorCountPtr = 0;
|
---|
270 | if (errorMessages)
|
---|
271 | errorMessages->clear();
|
---|
272 |
|
---|
273 | QBuffer errorStream;
|
---|
274 | errorStream.open(QIODevice::WriteOnly);
|
---|
275 |
|
---|
276 | int errorCount = 0;
|
---|
277 | int generatedCount = 0;
|
---|
278 | bool newResourceSetChanged = false;
|
---|
279 |
|
---|
280 | if (resourceSet && resourceSet->activeQrcPaths() != newPaths && !m_newlyCreated.contains(resourceSet))
|
---|
281 | newResourceSetChanged = true;
|
---|
282 |
|
---|
283 | PathDataMap newPathToData = m_pathToData;
|
---|
284 |
|
---|
285 | QStringListIterator itPath(newPaths);
|
---|
286 | while (itPath.hasNext()) {
|
---|
287 | const QString path = itPath.next();
|
---|
288 | if (resourceSet && !m_pathToResourceSet[path].contains(resourceSet))
|
---|
289 | m_pathToResourceSet[path].append(resourceSet);
|
---|
290 | const QMap<QString, bool>::iterator itMod = m_pathToModified.find(path);
|
---|
291 | if (itMod == m_pathToModified.end() || itMod.value()) { // new path or path is already created, but needs to be recreated
|
---|
292 | QStringList contents;
|
---|
293 | int qrcErrorCount;
|
---|
294 | generatedCount++;
|
---|
295 | if (const QByteArray *data = createResource(path, &contents, &qrcErrorCount, errorStream)) {
|
---|
296 | newPathToData.insert(path, data);
|
---|
297 | if (qrcErrorCount) // Count single failed files as sort of 1/2 error
|
---|
298 | errorCount++;
|
---|
299 | addWatcher(path);
|
---|
300 | } else {
|
---|
301 | newPathToData.remove(path);
|
---|
302 | errorCount++;
|
---|
303 | }
|
---|
304 | m_pathToModified.insert(path, false);
|
---|
305 | m_pathToContents.insert(path, contents);
|
---|
306 | newResourceSetChanged = true;
|
---|
307 | const QMap<QString, QList<QtResourceSet *> >::iterator itReload = m_pathToResourceSet.find(path);
|
---|
308 | if (itReload != m_pathToResourceSet.end()) {
|
---|
309 | QList<QtResourceSet *> resources = itReload.value();
|
---|
310 | QListIterator<QtResourceSet *> itRes(resources);
|
---|
311 | while (itRes.hasNext()) {
|
---|
312 | QtResourceSet *res = itRes.next();
|
---|
313 | if (res != resourceSet) {
|
---|
314 | m_resourceSetToReload[res] = true;
|
---|
315 | }
|
---|
316 | }
|
---|
317 | }
|
---|
318 | } else { // path is already created, don't need to recreate
|
---|
319 | }
|
---|
320 | }
|
---|
321 |
|
---|
322 | QList<const QByteArray *> oldData = m_pathToData.values();
|
---|
323 | QList<const QByteArray *> newData = newPathToData.values();
|
---|
324 |
|
---|
325 | QList<const QByteArray *> toDelete;
|
---|
326 | QListIterator<const QByteArray *> itOld(oldData);
|
---|
327 | if (itOld.hasNext()) {
|
---|
328 | const QByteArray *array = itOld.next();
|
---|
329 | if (!newData.contains(array))
|
---|
330 | toDelete.append(array);
|
---|
331 | }
|
---|
332 |
|
---|
333 | // Nothing can fail below here?
|
---|
334 | if (generatedCount) {
|
---|
335 | if (errorCountPtr)
|
---|
336 | *errorCountPtr = errorCount;
|
---|
337 | errorStream.close();
|
---|
338 | const QString stderrOutput = QString::fromUtf8(errorStream.data());
|
---|
339 | if (debugResourceModel)
|
---|
340 | qDebug() << "Output: (" << errorCount << ")\n" << stderrOutput;
|
---|
341 | if (errorMessages)
|
---|
342 | *errorMessages = stderrOutput;
|
---|
343 | }
|
---|
344 | // register
|
---|
345 | const QMap<QtResourceSet *, bool>::iterator itReload = m_resourceSetToReload.find(resourceSet);
|
---|
346 | if (itReload != m_resourceSetToReload.end()) {
|
---|
347 | if (itReload.value()) {
|
---|
348 | newResourceSetChanged = true;
|
---|
349 | m_resourceSetToReload.insert(resourceSet, false);
|
---|
350 | }
|
---|
351 | }
|
---|
352 |
|
---|
353 | QStringList oldActivePaths;
|
---|
354 | if (m_currentResourceSet)
|
---|
355 | oldActivePaths = m_currentResourceSet->activeQrcPaths();
|
---|
356 |
|
---|
357 | const bool needReregister = (oldActivePaths != newPaths) || newResourceSetChanged;
|
---|
358 |
|
---|
359 | QMap<QtResourceSet *, bool>::iterator itNew = m_newlyCreated.find(resourceSet);
|
---|
360 | if (itNew != m_newlyCreated.end()) {
|
---|
361 | m_newlyCreated.remove(resourceSet);
|
---|
362 | if (needReregister)
|
---|
363 | newResourceSetChanged = true;
|
---|
364 | }
|
---|
365 |
|
---|
366 | if (!newResourceSetChanged && !needReregister && (m_currentResourceSet == resourceSet)) {
|
---|
367 | foreach (const QByteArray *data, toDelete)
|
---|
368 | deleteResource(data);
|
---|
369 |
|
---|
370 | return; // nothing changed
|
---|
371 | }
|
---|
372 |
|
---|
373 | if (needReregister)
|
---|
374 | unregisterResourceSet(m_currentResourceSet);
|
---|
375 |
|
---|
376 | foreach (const QByteArray *data, toDelete)
|
---|
377 | deleteResource(data);
|
---|
378 |
|
---|
379 | m_pathToData = newPathToData;
|
---|
380 | m_currentResourceSet = resourceSet;
|
---|
381 |
|
---|
382 | if (resourceSet)
|
---|
383 | removeOldPaths(resourceSet, newPaths);
|
---|
384 |
|
---|
385 | if (needReregister)
|
---|
386 | registerResourceSet(m_currentResourceSet);
|
---|
387 |
|
---|
388 | emit q_ptr->resourceSetActivated(m_currentResourceSet, newResourceSetChanged);
|
---|
389 |
|
---|
390 | // deactivates the paths from old current resource set
|
---|
391 | // add new paths to the new current resource set
|
---|
392 | // reloads all paths which are marked as modified from the current resource set;
|
---|
393 | // activates the paths from current resource set
|
---|
394 | // emits resourceSetActivated() (don't emit only in case when old resource set is the same as new one
|
---|
395 | // AND no path was reloaded AND the list of paths is exactly the same)
|
---|
396 | }
|
---|
397 |
|
---|
398 | void QtResourceModelPrivate::removeOldPaths(QtResourceSet *resourceSet, const QStringList &newPaths)
|
---|
399 | {
|
---|
400 | QStringList oldPaths = m_resourceSetToPaths.value(resourceSet);
|
---|
401 | if (oldPaths != newPaths) {
|
---|
402 | // remove old
|
---|
403 | QStringListIterator itOldPaths(oldPaths);
|
---|
404 | while (itOldPaths.hasNext()) {
|
---|
405 | QString oldPath = itOldPaths.next();
|
---|
406 | if (!newPaths.contains(oldPath)) {
|
---|
407 | const QMap<QString, QList<QtResourceSet *> >::iterator itRemove = m_pathToResourceSet.find(oldPath);
|
---|
408 | if (itRemove != m_pathToResourceSet.end()) {
|
---|
409 | const int idx = itRemove.value().indexOf(resourceSet);
|
---|
410 | if (idx >= 0)
|
---|
411 | itRemove.value().removeAt(idx);
|
---|
412 | if (itRemove.value().count() == 0) {
|
---|
413 | PathDataMap::iterator it = m_pathToData.find(oldPath);
|
---|
414 | if (it != m_pathToData.end())
|
---|
415 | deleteResource(it.value());
|
---|
416 | m_pathToResourceSet.erase(itRemove);
|
---|
417 | m_pathToModified.remove(oldPath);
|
---|
418 | m_pathToContents.remove(oldPath);
|
---|
419 | m_pathToData.remove(oldPath);
|
---|
420 | removeWatcher(oldPath);
|
---|
421 | }
|
---|
422 | }
|
---|
423 | }
|
---|
424 | }
|
---|
425 | m_resourceSetToPaths[resourceSet] = newPaths;
|
---|
426 | }
|
---|
427 | }
|
---|
428 |
|
---|
429 | void QtResourceModelPrivate::setWatcherEnabled(const QString &path, bool enable)
|
---|
430 | {
|
---|
431 | if (!enable) {
|
---|
432 | m_fileWatcher->removePath(path);
|
---|
433 | return;
|
---|
434 | }
|
---|
435 |
|
---|
436 | QFileInfo fi(path);
|
---|
437 | if (fi.exists())
|
---|
438 | m_fileWatcher->addPath(path);
|
---|
439 | }
|
---|
440 |
|
---|
441 | void QtResourceModelPrivate::addWatcher(const QString &path)
|
---|
442 | {
|
---|
443 | QMap<QString, bool>::ConstIterator it = m_fileWatchedMap.constFind(path);
|
---|
444 | if (it != m_fileWatchedMap.constEnd() && it.value() == false)
|
---|
445 | return;
|
---|
446 |
|
---|
447 | m_fileWatchedMap.insert(path, true);
|
---|
448 | if (!m_fileWatcherEnabled)
|
---|
449 | return;
|
---|
450 | setWatcherEnabled(path, true);
|
---|
451 | }
|
---|
452 |
|
---|
453 | void QtResourceModelPrivate::removeWatcher(const QString &path)
|
---|
454 | {
|
---|
455 | if (!m_fileWatchedMap.contains(path))
|
---|
456 | return;
|
---|
457 |
|
---|
458 | m_fileWatchedMap.remove(path);
|
---|
459 | if (!m_fileWatcherEnabled)
|
---|
460 | return;
|
---|
461 | setWatcherEnabled(path, false);
|
---|
462 | }
|
---|
463 |
|
---|
464 | void QtResourceModelPrivate::slotFileChanged(const QString &path)
|
---|
465 | {
|
---|
466 | setWatcherEnabled(path, false);
|
---|
467 | emit q_ptr->qrcFileModifiedExternally(path);
|
---|
468 | setWatcherEnabled(path, true); //readd
|
---|
469 | }
|
---|
470 |
|
---|
471 | // ----------------------- QtResourceModel
|
---|
472 | QtResourceModel::QtResourceModel(QObject *parent) :
|
---|
473 | QObject(parent),
|
---|
474 | d_ptr(new QtResourceModelPrivate)
|
---|
475 | {
|
---|
476 | d_ptr->q_ptr = this;
|
---|
477 |
|
---|
478 | d_ptr->m_fileWatcher = new QFileSystemWatcher(this);
|
---|
479 | connect(d_ptr->m_fileWatcher, SIGNAL(fileChanged(QString)),
|
---|
480 | this, SLOT(slotFileChanged(QString)));
|
---|
481 | }
|
---|
482 |
|
---|
483 | QtResourceModel::~QtResourceModel()
|
---|
484 | {
|
---|
485 | blockSignals(true);
|
---|
486 | QList<QtResourceSet *> resourceList = resourceSets();
|
---|
487 | QListIterator<QtResourceSet *> it(resourceList);
|
---|
488 | while (it.hasNext())
|
---|
489 | removeResourceSet(it.next());
|
---|
490 | blockSignals(false);
|
---|
491 | }
|
---|
492 |
|
---|
493 | QStringList QtResourceModel::loadedQrcFiles() const
|
---|
494 | {
|
---|
495 | return d_ptr->m_pathToModified.keys();
|
---|
496 | }
|
---|
497 |
|
---|
498 | bool QtResourceModel::isModified(const QString &path) const
|
---|
499 | {
|
---|
500 | QMap<QString, bool>::const_iterator it = d_ptr->m_pathToModified.find(path);
|
---|
501 | if (it != d_ptr->m_pathToModified.constEnd())
|
---|
502 | return it.value();
|
---|
503 | return true;
|
---|
504 | }
|
---|
505 |
|
---|
506 | void QtResourceModel::setModified(const QString &path)
|
---|
507 | {
|
---|
508 | QMap<QString, bool>::const_iterator itMod = d_ptr->m_pathToModified.find(path);
|
---|
509 | if (itMod == d_ptr->m_pathToModified.constEnd())
|
---|
510 | return;
|
---|
511 |
|
---|
512 | d_ptr->m_pathToModified[path] = true;
|
---|
513 | QMap<QString, QList<QtResourceSet *> >::const_iterator it = d_ptr->m_pathToResourceSet.constFind(path);
|
---|
514 | if (it == d_ptr->m_pathToResourceSet.constEnd())
|
---|
515 | return;
|
---|
516 |
|
---|
517 | QList<QtResourceSet *> resourceList = it.value();
|
---|
518 | QListIterator<QtResourceSet *> itReload(resourceList);
|
---|
519 | while (itReload.hasNext())
|
---|
520 | d_ptr->m_resourceSetToReload.insert(itReload.next(), true);
|
---|
521 | }
|
---|
522 |
|
---|
523 | QList<QtResourceSet *> QtResourceModel::resourceSets() const
|
---|
524 | {
|
---|
525 | return d_ptr->m_resourceSetToPaths.keys();
|
---|
526 | }
|
---|
527 |
|
---|
528 | QtResourceSet *QtResourceModel::currentResourceSet() const
|
---|
529 | {
|
---|
530 | return d_ptr->m_currentResourceSet;
|
---|
531 | }
|
---|
532 |
|
---|
533 | void QtResourceModel::setCurrentResourceSet(QtResourceSet *resourceSet, int *errorCount, QString *errorMessages)
|
---|
534 | {
|
---|
535 | d_ptr->activate(resourceSet, d_ptr->m_resourceSetToPaths.value(resourceSet), errorCount, errorMessages);
|
---|
536 | }
|
---|
537 |
|
---|
538 | QtResourceSet *QtResourceModel::addResourceSet(const QStringList &paths)
|
---|
539 | {
|
---|
540 | QtResourceSet *newResource = new QtResourceSet(this);
|
---|
541 | d_ptr->m_resourceSetToPaths.insert(newResource, paths);
|
---|
542 | d_ptr->m_resourceSetToReload.insert(newResource, false);
|
---|
543 | d_ptr->m_newlyCreated.insert(newResource, true);
|
---|
544 | QStringListIterator it(paths);
|
---|
545 | while (it.hasNext()) {
|
---|
546 | const QString path = it.next();
|
---|
547 | d_ptr->m_pathToResourceSet[path].append(newResource);
|
---|
548 | }
|
---|
549 | return newResource;
|
---|
550 | }
|
---|
551 |
|
---|
552 | // TODO
|
---|
553 | void QtResourceModel::removeResourceSet(QtResourceSet *resourceSet)
|
---|
554 | {
|
---|
555 | if (!resourceSet)
|
---|
556 | return;
|
---|
557 | if (currentResourceSet() == resourceSet)
|
---|
558 | setCurrentResourceSet(0);
|
---|
559 |
|
---|
560 | // remove rcc files for those paths which are not used in any other resource set
|
---|
561 | d_ptr->removeOldPaths(resourceSet, QStringList());
|
---|
562 |
|
---|
563 | d_ptr->m_resourceSetToPaths.remove(resourceSet);
|
---|
564 | d_ptr->m_resourceSetToReload.remove(resourceSet);
|
---|
565 | d_ptr->m_newlyCreated.remove(resourceSet);
|
---|
566 | delete resourceSet;
|
---|
567 | }
|
---|
568 |
|
---|
569 | void QtResourceModel::reload(const QString &path, int *errorCount, QString *errorMessages)
|
---|
570 | {
|
---|
571 | setModified(path);
|
---|
572 |
|
---|
573 | d_ptr->activate(d_ptr->m_currentResourceSet, d_ptr->m_resourceSetToPaths.value(d_ptr->m_currentResourceSet), errorCount, errorMessages);
|
---|
574 | }
|
---|
575 |
|
---|
576 | void QtResourceModel::reload(int *errorCount, QString *errorMessages)
|
---|
577 | {
|
---|
578 | QMap<QString, bool>::iterator it = d_ptr->m_pathToModified.begin();
|
---|
579 | QMap<QString, bool>::iterator itEnd = d_ptr->m_pathToModified.end(); // will it be valid when I iterate the map and change it???
|
---|
580 | while (it != itEnd) {
|
---|
581 | it = d_ptr->m_pathToModified.insert(it.key(), true);
|
---|
582 | ++it;
|
---|
583 | }
|
---|
584 |
|
---|
585 | QMap<QtResourceSet *, bool>::iterator itReload = d_ptr->m_resourceSetToReload.begin();
|
---|
586 | QMap<QtResourceSet *, bool>::iterator itReloadEnd = d_ptr->m_resourceSetToReload.end();
|
---|
587 | while (itReload != itReloadEnd) {
|
---|
588 | itReload = d_ptr->m_resourceSetToReload.insert(itReload.key(), true); // empty resourceSets could be omitted here
|
---|
589 | ++itReload;
|
---|
590 | }
|
---|
591 |
|
---|
592 | d_ptr->activate(d_ptr->m_currentResourceSet, d_ptr->m_resourceSetToPaths.value(d_ptr->m_currentResourceSet), errorCount, errorMessages);
|
---|
593 | }
|
---|
594 |
|
---|
595 | QMap<QString, QString> QtResourceModel::contents() const
|
---|
596 | {
|
---|
597 | return d_ptr->m_fileToQrc;
|
---|
598 | }
|
---|
599 |
|
---|
600 | QString QtResourceModel::qrcPath(const QString &file) const
|
---|
601 | {
|
---|
602 | return d_ptr->m_fileToQrc.value(file);
|
---|
603 | }
|
---|
604 |
|
---|
605 | void QtResourceModel::setWatcherEnabled(bool enable)
|
---|
606 | {
|
---|
607 | if (d_ptr->m_fileWatcherEnabled == enable)
|
---|
608 | return;
|
---|
609 |
|
---|
610 | d_ptr->m_fileWatcherEnabled = enable;
|
---|
611 |
|
---|
612 | QMapIterator<QString, bool> it(d_ptr->m_fileWatchedMap);
|
---|
613 | if (it.hasNext())
|
---|
614 | d_ptr->setWatcherEnabled(it.next().key(), d_ptr->m_fileWatcherEnabled);
|
---|
615 | }
|
---|
616 |
|
---|
617 | bool QtResourceModel::isWatcherEnabled() const
|
---|
618 | {
|
---|
619 | return d_ptr->m_fileWatcherEnabled;
|
---|
620 | }
|
---|
621 |
|
---|
622 | void QtResourceModel::setWatcherEnabled(const QString &path, bool enable)
|
---|
623 | {
|
---|
624 | QMap<QString, bool>::Iterator it = d_ptr->m_fileWatchedMap.find(path);
|
---|
625 | if (it == d_ptr->m_fileWatchedMap.end())
|
---|
626 | return;
|
---|
627 |
|
---|
628 | if (it.value() == enable)
|
---|
629 | return;
|
---|
630 |
|
---|
631 | it.value() = enable;
|
---|
632 |
|
---|
633 | if (!d_ptr->m_fileWatcherEnabled)
|
---|
634 | return;
|
---|
635 |
|
---|
636 | d_ptr->setWatcherEnabled(it.key(), enable);
|
---|
637 | }
|
---|
638 |
|
---|
639 | bool QtResourceModel::isWatcherEnabled(const QString &path)
|
---|
640 | {
|
---|
641 | return d_ptr->m_fileWatchedMap.value(path, false);
|
---|
642 | }
|
---|
643 |
|
---|
644 | QT_END_NAMESPACE
|
---|
645 |
|
---|
646 | #include "moc_qtresourcemodel_p.cpp"
|
---|