1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Designer of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "qtresourceeditordialog_p.h"
30 #include "ui_qtresourceeditordialog.h"
31 #include "qtresourcemodel_p.h"
32 #include "iconloader_p.h"
33 
34 #include <abstractdialoggui_p.h>
35 
36 #include <QtDesigner/abstractsettings.h>
37 #include <QtDesigner/abstractformeditor.h>
38 
39 #include <QtCore/qfileinfo.h>
40 #include <QtCore/qdir.h>
41 #include <QtCore/qcoreapplication.h>
42 #include <QtXml/qdom.h>
43 #include <QtWidgets/qmenu.h>
44 #include <QtWidgets/qheaderview.h>
45 #include <QtWidgets/qinputdialog.h>
46 #include <QtWidgets/qmessagebox.h>
47 #include <QtWidgets/qpushbutton.h>
48 #include <QtGui/qstandarditemmodel.h>
49 
50 QT_BEGIN_NAMESPACE
51 
52 static const char *rccRootTag = "RCC";
53 static const char *rccTag = "qresource";
54 static const char *rccFileTag = "file";
55 static const char *rccAliasAttribute = "alias";
56 static const char *rccPrefixAttribute = "prefix";
57 static const char *rccLangAttribute = "lang";
58 static const char *SplitterPosition = "SplitterPosition";
59 static const char *Geometry = "Geometry";
60 static const char *QrcDialogC = "QrcDialog";
61 
msgOverwrite(const QString & fname)62 static QString msgOverwrite(const QString &fname)
63 {
64     return QCoreApplication::translate("QtResourceEditorDialog", "%1 already exists.\nDo you want to replace it?").arg(fname);
65 }
66 
msgTagMismatch(const QString & got,const QString & expected)67 static QString msgTagMismatch(const QString &got, const QString &expected)
68 {
69     return QCoreApplication::translate("QtResourceEditorDialog", "The file does not appear to be a resource file; element '%1' was found where '%2' was expected.").arg(got, expected);
70 }
71 
72 namespace {
73 
74 // below 3 data classes should be derived from QSharedData and made implicit shared class
75 struct QtResourceFileData {
76     QString path;
77     QString alias;
operator ==__anon2e706ab10111::QtResourceFileData78     bool operator==(const QtResourceFileData &other) const
79     { return path == other.path && alias == other.alias; }
80 };
81 
82 struct QtResourcePrefixData {
83     QString prefix;
84     QString language;
85     QList<QtResourceFileData> resourceFileList;
operator ==__anon2e706ab10111::QtResourcePrefixData86     bool operator==(const QtResourcePrefixData &other) const
87     {
88         return prefix == other.prefix && language == other.language
89             && resourceFileList == other.resourceFileList;
90     }
91 };
92 
93 struct QtQrcFileData {
94     QString qrcPath;
95     QList<QtResourcePrefixData> resourceList;
operator ==__anon2e706ab10111::QtQrcFileData96     bool operator==(const QtQrcFileData &other) const
97     { return qrcPath == other.qrcPath && resourceList == other.resourceList; }
98 };
99 
loadResourceFileData(const QDomElement & fileElem,QtResourceFileData * fileData,QString * errorMessage)100 bool loadResourceFileData(const QDomElement &fileElem, QtResourceFileData *fileData, QString *errorMessage)
101 {
102     if (!fileData)
103         return false;
104 
105     if (fileElem.tagName() != QLatin1String(rccFileTag)) {
106         *errorMessage = msgTagMismatch(fileElem.tagName(), QLatin1String(rccFileTag));
107         return false;
108     }
109 
110     QtResourceFileData &data = *fileData;
111 
112     data.path = fileElem.text();
113     data.alias = fileElem.attribute(QLatin1String(rccAliasAttribute));
114 
115     return true;
116 }
117 
loadResourcePrefixData(const QDomElement & prefixElem,QtResourcePrefixData * prefixData,QString * errorMessage)118 static bool loadResourcePrefixData(const QDomElement &prefixElem, QtResourcePrefixData *prefixData, QString *errorMessage)
119 {
120     if (!prefixData)
121         return false;
122 
123     if (prefixElem.tagName() != QLatin1String(rccTag)) {
124         *errorMessage = msgTagMismatch(prefixElem.tagName(), QLatin1String(rccTag));
125         return false;
126     }
127 
128     QtResourcePrefixData &data = *prefixData;
129 
130     data.prefix = prefixElem.attribute(QLatin1String(rccPrefixAttribute));
131     data.language = prefixElem.attribute(QLatin1String(rccLangAttribute));
132     QDomElement fileElem = prefixElem.firstChildElement();
133     while (!fileElem.isNull()) {
134         QtResourceFileData fileData;
135         if (!loadResourceFileData(fileElem, &fileData, errorMessage))
136             return false;
137         data.resourceFileList.append(fileData);
138         fileElem = fileElem.nextSiblingElement();
139     }
140     return true;
141 }
142 
loadQrcFileData(const QDomDocument & doc,const QString & path,QtQrcFileData * qrcFileData,QString * errorMessage)143 static bool loadQrcFileData(const QDomDocument &doc, const QString &path, QtQrcFileData *qrcFileData, QString *errorMessage)
144 {
145     if (!qrcFileData)
146         return false;
147 
148     QtQrcFileData &data = *qrcFileData;
149 
150     QDomElement docElem = doc.documentElement();
151     if (docElem.tagName() != QLatin1String(rccRootTag)) {
152         *errorMessage = msgTagMismatch(docElem.tagName(), QLatin1String(rccRootTag));
153         return false;
154     }
155 
156     QDomElement prefixElem = docElem.firstChildElement();
157     while (!prefixElem.isNull()) {
158         QtResourcePrefixData prefixData;
159         if (!loadResourcePrefixData(prefixElem, &prefixData, errorMessage))
160             return false;
161         data.resourceList.append(prefixData);
162         prefixElem = prefixElem.nextSiblingElement();
163     }
164 
165     data.qrcPath = path;
166 
167     return true;
168 }
169 
saveResourceFileData(QDomDocument & doc,const QtResourceFileData & fileData)170 QDomElement saveResourceFileData(QDomDocument &doc, const QtResourceFileData &fileData)
171 {
172     QDomElement fileElem = doc.createElement(QLatin1String(rccFileTag));
173     if (!fileData.alias.isEmpty())
174         fileElem.setAttribute(QLatin1String(rccAliasAttribute), fileData.alias);
175 
176     QDomText textElem = doc.createTextNode(fileData.path);
177     fileElem.appendChild(textElem);
178 
179     return fileElem;
180 }
181 
saveResourcePrefixData(QDomDocument & doc,const QtResourcePrefixData & prefixData)182 QDomElement saveResourcePrefixData(QDomDocument &doc, const QtResourcePrefixData &prefixData)
183 {
184     QDomElement prefixElem = doc.createElement(QLatin1String(rccTag));
185     if (!prefixData.prefix.isEmpty())
186         prefixElem.setAttribute(QLatin1String(rccPrefixAttribute), prefixData.prefix);
187     if (!prefixData.language.isEmpty())
188         prefixElem.setAttribute(QLatin1String(rccLangAttribute), prefixData.language);
189 
190     for (const QtResourceFileData &rfd : prefixData.resourceFileList) {
191         QDomElement fileElem = saveResourceFileData(doc, rfd);
192         prefixElem.appendChild(fileElem);
193     }
194 
195     return prefixElem;
196 }
197 
saveQrcFileData(const QtQrcFileData & qrcFileData)198 QDomDocument saveQrcFileData(const QtQrcFileData &qrcFileData)
199 {
200     QDomDocument doc;
201     QDomElement docElem = doc.createElement(QLatin1String(rccRootTag));
202     for (const QtResourcePrefixData &prefixData : qrcFileData.resourceList) {
203         QDomElement prefixElem = saveResourcePrefixData(doc, prefixData);
204 
205         docElem.appendChild(prefixElem);
206     }
207     doc.appendChild(docElem);
208 
209     return doc;
210 }
211 // --------------- QtResourceFile
212 class QtResourceFile {
213 public:
214     friend class QtQrcManager;
215 
path() const216     QString path() const { return m_path; }
alias() const217     QString alias() const { return m_alias; }
fullPath() const218     QString fullPath() const { return m_fullPath; }
219 private:
220     QtResourceFile() = default;
221 
222     QString m_path;
223     QString m_alias;
224     QString m_fullPath;
225 };
226 
227 class QtResourcePrefix {
228 public:
229     friend class QtQrcManager;
230 
prefix() const231     QString prefix() const { return m_prefix; }
language() const232     QString language() const { return m_language; }
resourceFiles() const233     QList<QtResourceFile *> resourceFiles() const { return m_resourceFiles; }
234 private:
235     QtResourcePrefix() = default;
236 
237     QString m_prefix;
238     QString m_language;
239     QList<QtResourceFile *> m_resourceFiles;
240 
241 };
242 // ------------------- QtQrcFile
243 class QtQrcFile {
244 public:
245     friend class QtQrcManager;
246 
path() const247     QString path() const { return m_path; }
fileName() const248     QString fileName() const { return m_fileName; }
resourcePrefixList() const249     QList<QtResourcePrefix *> resourcePrefixList() const { return m_resourcePrefixes; }
initialState() const250     QtQrcFileData initialState() const { return m_initialState; }
251 
252 private:
253     QtQrcFile() = default;
254 
setPath(const QString & path)255     void setPath(const QString &path) {
256         m_path = path;
257         QFileInfo fi(path);
258         m_fileName = fi.fileName();
259     }
260 
261     QString m_path;
262     QString m_fileName;
263     QList<QtResourcePrefix *> m_resourcePrefixes;
264     QtQrcFileData m_initialState;
265 };
266 
267 // ------------------ QtQrcManager
268 class QtQrcManager : public QObject
269 {
270     Q_OBJECT
271 public:
272     QtQrcManager(QObject *parent = nullptr);
273     ~QtQrcManager() override;
274 
275     QList<QtQrcFile *> qrcFiles() const;
276 
277     // helpers
278     QtQrcFile *qrcFileOf(const QString &path) const;
279     QtQrcFile *qrcFileOf(QtResourcePrefix *resourcePrefix) const;
280     QtResourcePrefix *resourcePrefixOf(QtResourceFile *resourceFile) const;
281 
282     QtQrcFile *importQrcFile(const QtQrcFileData &qrcFileData, QtQrcFile *beforeQrcFile = nullptr);
283     void exportQrcFile(QtQrcFile *qrcFile, QtQrcFileData *qrcFileData) const;
284 
285     QIcon icon(const QString &resourceFullPath) const;
286     bool exists(const QString &resourceFullPath) const;
287     bool exists(QtQrcFile *qrcFile) const;
288 
289     QtQrcFile *prevQrcFile(QtQrcFile *qrcFile) const;
290     QtQrcFile *nextQrcFile(QtQrcFile *qrcFile) const;
291     QtResourcePrefix *prevResourcePrefix(QtResourcePrefix *resourcePrefix) const;
292     QtResourcePrefix *nextResourcePrefix(QtResourcePrefix *resourcePrefix) const;
293     QtResourceFile *prevResourceFile(QtResourceFile *resourceFile) const;
294     QtResourceFile *nextResourceFile(QtResourceFile *resourceFile) const;
295 
296     void clear();
297 
298 public slots:
299 
300     QtQrcFile *insertQrcFile(const QString &path, QtQrcFile *beforeQrcFile = nullptr, bool newFile = false);
301     void moveQrcFile(QtQrcFile *qrcFile, QtQrcFile *beforeQrcFile);
302     void setInitialState(QtQrcFile *qrcFile, const QtQrcFileData &initialState);
303     void removeQrcFile(QtQrcFile *qrcFile);
304 
305     QtResourcePrefix *insertResourcePrefix(QtQrcFile *qrcFile, const QString &prefix,
306                     const QString &language, QtResourcePrefix *beforeResourcePrefix = nullptr);
307     void moveResourcePrefix(QtResourcePrefix *resourcePrefix, QtResourcePrefix *beforeResourcePrefix); // the same qrc file???
308     void changeResourcePrefix(QtResourcePrefix *resourcePrefix, const QString &newPrefix);
309     void changeResourceLanguage(QtResourcePrefix *resourcePrefix, const QString &newLanguage);
310     void removeResourcePrefix(QtResourcePrefix *resourcePrefix);
311 
312     QtResourceFile *insertResourceFile(QtResourcePrefix *resourcePrefix, const QString &path,
313                     const QString &alias, QtResourceFile *beforeResourceFile = nullptr);
314     void moveResourceFile(QtResourceFile *resourceFile, QtResourceFile *beforeResourceFile); // the same prefix???
315     void changeResourceAlias(QtResourceFile *resourceFile, const QString &newAlias);
316     void removeResourceFile(QtResourceFile *resourceFile);
317 
318 signals:
319     void qrcFileInserted(QtQrcFile *qrcFile);
320     void qrcFileMoved(QtQrcFile *qrcFile, QtQrcFile *oldBeforeQrcFile);
321     void qrcFileRemoved(QtQrcFile *qrcFile);
322 
323     void resourcePrefixInserted(QtResourcePrefix *resourcePrefix);
324     void resourcePrefixMoved(QtResourcePrefix *resourcePrefix, QtResourcePrefix *oldBeforeResourcePrefix);
325     void resourcePrefixChanged(QtResourcePrefix *resourcePrefix, const QString &oldPrefix);
326     void resourceLanguageChanged(QtResourcePrefix *resourcePrefix, const QString &oldLanguage);
327     void resourcePrefixRemoved(QtResourcePrefix *resourcePrefix);
328 
329     void resourceFileInserted(QtResourceFile *resourceFile);
330     void resourceFileMoved(QtResourceFile *resourceFile, QtResourceFile *oldBeforeResourceFile);
331     void resourceAliasChanged(QtResourceFile *resourceFile, const QString &oldAlias);
332     void resourceFileRemoved(QtResourceFile *resourceFile);
333 private:
334 
335     QList<QtQrcFile *> m_qrcFiles;
336     QMap<QString, QtQrcFile *> m_pathToQrc;
337     QMap<QtQrcFile *, bool> m_qrcFileToExists;
338     QMap<QtResourcePrefix *, QtQrcFile *> m_prefixToQrc;
339     QMap<QtResourceFile *, QtResourcePrefix *> m_fileToPrefix;
340     QMap<QString, QList<QtResourceFile *> > m_fullPathToResourceFiles;
341     QMap<QString, QIcon> m_fullPathToIcon;
342     QMap<QString, bool> m_fullPathToExists;
343 };
344 
QtQrcManager(QObject * parent)345 QtQrcManager::QtQrcManager(QObject *parent)
346     : QObject(parent)
347 {
348 
349 }
350 
~QtQrcManager()351 QtQrcManager::~QtQrcManager()
352 {
353     clear();
354 }
355 
qrcFiles() const356 QList<QtQrcFile *> QtQrcManager::qrcFiles() const
357 {
358     return m_qrcFiles;
359 }
360 
qrcFileOf(const QString & path) const361 QtQrcFile *QtQrcManager::qrcFileOf(const QString &path) const
362 {
363     return m_pathToQrc.value(path);
364 }
365 
qrcFileOf(QtResourcePrefix * resourcePrefix) const366 QtQrcFile *QtQrcManager::qrcFileOf(QtResourcePrefix *resourcePrefix) const
367 {
368     return m_prefixToQrc.value(resourcePrefix);
369 }
370 
resourcePrefixOf(QtResourceFile * resourceFile) const371 QtResourcePrefix *QtQrcManager::resourcePrefixOf(QtResourceFile *resourceFile) const
372 {
373     return m_fileToPrefix.value(resourceFile);
374 }
375 
importQrcFile(const QtQrcFileData & qrcFileData,QtQrcFile * beforeQrcFile)376 QtQrcFile *QtQrcManager::importQrcFile(const QtQrcFileData &qrcFileData, QtQrcFile *beforeQrcFile)
377 {
378     QtQrcFile *qrcFile = insertQrcFile(qrcFileData.qrcPath, beforeQrcFile);
379     if (!qrcFile)
380         return nullptr;
381     for (const QtResourcePrefixData &prefixData : qrcFileData.resourceList) {
382         QtResourcePrefix *resourcePrefix = insertResourcePrefix(qrcFile, prefixData.prefix, prefixData.language, nullptr);
383         for (const QtResourceFileData &fileData : prefixData.resourceFileList)
384             insertResourceFile(resourcePrefix, fileData.path, fileData.alias, nullptr);
385     }
386     setInitialState(qrcFile, qrcFileData);
387     return qrcFile;
388 }
389 
exportQrcFile(QtQrcFile * qrcFile,QtQrcFileData * qrcFileData) const390 void QtQrcManager::exportQrcFile(QtQrcFile *qrcFile, QtQrcFileData *qrcFileData) const
391 {
392     if (!qrcFileData)
393         return;
394 
395     if (!qrcFile)
396         return;
397 
398     QtQrcFileData &data = *qrcFileData;
399 
400     QList<QtResourcePrefixData> resourceList;
401 
402     const auto resourcePrefixes = qrcFile->resourcePrefixList();
403     for (const QtResourcePrefix *prefix : resourcePrefixes) {
404         QList<QtResourceFileData> resourceFileList;
405         const auto resourceFiles = prefix->resourceFiles();
406         for (QtResourceFile *file : resourceFiles) {
407             QtResourceFileData fileData;
408             fileData.path = file->path();
409             fileData.alias = file->alias();
410             resourceFileList << fileData;
411         }
412         QtResourcePrefixData prefixData;
413         prefixData.prefix = prefix->prefix();
414         prefixData.language = prefix->language();
415         prefixData.resourceFileList = resourceFileList;
416 
417         resourceList << prefixData;
418     }
419     data = QtQrcFileData();
420     data.qrcPath = qrcFile->path();
421     data.resourceList = resourceList;
422 }
423 
icon(const QString & resourceFullPath) const424 QIcon QtQrcManager::icon(const QString &resourceFullPath) const
425 {
426     return m_fullPathToIcon.value(resourceFullPath);
427 }
428 
exists(const QString & resourceFullPath) const429 bool QtQrcManager::exists(const QString &resourceFullPath) const
430 {
431     return m_fullPathToExists.value(resourceFullPath, false);
432 }
433 
exists(QtQrcFile * qrcFile) const434 bool QtQrcManager::exists(QtQrcFile *qrcFile) const
435 {
436     return m_qrcFileToExists.value(qrcFile, false);
437 }
438 
prevQrcFile(QtQrcFile * qrcFile) const439 QtQrcFile *QtQrcManager::prevQrcFile(QtQrcFile *qrcFile) const
440 {
441     if (!qrcFile)
442         return nullptr;
443     const int idx = m_qrcFiles.indexOf(qrcFile);
444     if (idx <= 0)
445         return nullptr;
446     return m_qrcFiles.at(idx - 1);
447 }
448 
nextQrcFile(QtQrcFile * qrcFile) const449 QtQrcFile *QtQrcManager::nextQrcFile(QtQrcFile *qrcFile) const
450 {
451     if (!qrcFile)
452         return nullptr;
453     const int idx = m_qrcFiles.indexOf(qrcFile);
454     if (idx < 0 || idx == m_qrcFiles.size() - 1)
455         return nullptr;
456     return m_qrcFiles.at(idx + 1);
457 }
458 
prevResourcePrefix(QtResourcePrefix * resourcePrefix) const459 QtResourcePrefix *QtQrcManager::prevResourcePrefix(QtResourcePrefix *resourcePrefix) const
460 {
461     if (!resourcePrefix)
462         return nullptr;
463     const auto prefixes = qrcFileOf(resourcePrefix)->resourcePrefixList();
464     const int idx = prefixes.indexOf(resourcePrefix);
465     if (idx <= 0)
466         return nullptr;
467     return prefixes.at(idx - 1);
468 }
469 
nextResourcePrefix(QtResourcePrefix * resourcePrefix) const470 QtResourcePrefix *QtQrcManager::nextResourcePrefix(QtResourcePrefix *resourcePrefix) const
471 {
472     if (!resourcePrefix)
473         return nullptr;
474     const auto prefixes = qrcFileOf(resourcePrefix)->resourcePrefixList();
475     const int idx = prefixes.indexOf(resourcePrefix);
476     if (idx < 0 || idx == prefixes.size() - 1)
477         return nullptr;
478     return prefixes.at(idx + 1);
479 }
480 
prevResourceFile(QtResourceFile * resourceFile) const481 QtResourceFile *QtQrcManager::prevResourceFile(QtResourceFile *resourceFile) const
482 {
483     if (!resourceFile)
484         return nullptr;
485     const auto files = resourcePrefixOf(resourceFile)->resourceFiles();
486     const int idx = files.indexOf(resourceFile);
487     if (idx <= 0)
488         return nullptr;
489     return files.at(idx - 1);
490 }
491 
nextResourceFile(QtResourceFile * resourceFile) const492 QtResourceFile *QtQrcManager::nextResourceFile(QtResourceFile *resourceFile) const
493 {
494     if (!resourceFile)
495         return nullptr;
496     const auto files = resourcePrefixOf(resourceFile)->resourceFiles();
497     const int idx = files.indexOf(resourceFile);
498     if (idx < 0 || idx == files.size() - 1)
499         return nullptr;
500     return files.at(idx + 1);
501 }
502 
clear()503 void QtQrcManager::clear()
504 {
505     const auto oldQrcFiles = qrcFiles();
506     for (QtQrcFile *qf : oldQrcFiles)
507         removeQrcFile(qf);
508 }
509 
insertQrcFile(const QString & path,QtQrcFile * beforeQrcFile,bool newFile)510 QtQrcFile *QtQrcManager::insertQrcFile(const QString &path, QtQrcFile *beforeQrcFile, bool newFile)
511 {
512     if (m_pathToQrc.contains(path))
513         return nullptr;
514 
515     int idx = m_qrcFiles.indexOf(beforeQrcFile);
516     if (idx < 0)
517         idx = m_qrcFiles.size();
518 
519     QtQrcFile *qrcFile = new QtQrcFile();
520     qrcFile->setPath(path);
521 
522     m_qrcFiles.insert(idx, qrcFile);
523     m_pathToQrc[path] = qrcFile;
524 
525     const QFileInfo fi(path);
526     m_qrcFileToExists[qrcFile] = fi.exists() || newFile;
527 
528     emit qrcFileInserted(qrcFile);
529     return qrcFile;
530 }
531 
moveQrcFile(QtQrcFile * qrcFile,QtQrcFile * beforeQrcFile)532 void QtQrcManager::moveQrcFile(QtQrcFile *qrcFile, QtQrcFile *beforeQrcFile)
533 {
534     if (qrcFile == beforeQrcFile)
535         return;
536 
537     const int idx = m_qrcFiles.indexOf(qrcFile);
538     if (idx < 0)
539         return;
540 
541     int beforeIdx = m_qrcFiles.indexOf(beforeQrcFile);
542     if (beforeIdx < 0)
543         beforeIdx = m_qrcFiles.size();
544 
545     if (idx == beforeIdx - 1) // the same position, nothing changes
546         return;
547 
548     QtQrcFile *oldBefore = nullptr;
549     if (idx < m_qrcFiles.size() - 1)
550         oldBefore = m_qrcFiles.at(idx + 1);
551 
552     m_qrcFiles.removeAt(idx);
553     if (idx < beforeIdx)
554         beforeIdx -= 1;
555 
556     m_qrcFiles.insert(beforeIdx, qrcFile);
557 
558     emit qrcFileMoved(qrcFile, oldBefore);
559 }
560 
setInitialState(QtQrcFile * qrcFile,const QtQrcFileData & initialState)561 void QtQrcManager::setInitialState(QtQrcFile *qrcFile, const QtQrcFileData &initialState)
562 {
563     qrcFile->m_initialState = initialState;
564 }
565 
removeQrcFile(QtQrcFile * qrcFile)566 void QtQrcManager::removeQrcFile(QtQrcFile *qrcFile)
567 {
568     const int idx = m_qrcFiles.indexOf(qrcFile);
569     if (idx < 0)
570         return;
571 
572     const auto resourcePrefixes = qrcFile->resourcePrefixList();
573     for (QtResourcePrefix *rp : resourcePrefixes)
574         removeResourcePrefix(rp);
575 
576     emit qrcFileRemoved(qrcFile);
577 
578     m_qrcFiles.removeAt(idx);
579     m_pathToQrc.remove(qrcFile->path());
580     m_qrcFileToExists.remove(qrcFile);
581     delete qrcFile;
582 }
583 
insertResourcePrefix(QtQrcFile * qrcFile,const QString & prefix,const QString & language,QtResourcePrefix * beforeResourcePrefix)584 QtResourcePrefix *QtQrcManager::insertResourcePrefix(QtQrcFile *qrcFile, const QString &prefix,
585         const QString &language, QtResourcePrefix *beforeResourcePrefix)
586 {
587     if (!qrcFile)
588         return nullptr;
589 
590     int idx = qrcFile->m_resourcePrefixes.indexOf(beforeResourcePrefix);
591     if (idx < 0)
592         idx = qrcFile->m_resourcePrefixes.size();
593 
594     QtResourcePrefix *resourcePrefix = new QtResourcePrefix();
595     resourcePrefix->m_prefix = prefix;
596     resourcePrefix->m_language = language;
597 
598     qrcFile->m_resourcePrefixes.insert(idx, resourcePrefix);
599     m_prefixToQrc[resourcePrefix] = qrcFile;
600 
601     emit resourcePrefixInserted(resourcePrefix);
602     return resourcePrefix;
603 }
604 
moveResourcePrefix(QtResourcePrefix * resourcePrefix,QtResourcePrefix * beforeResourcePrefix)605 void QtQrcManager::moveResourcePrefix(QtResourcePrefix *resourcePrefix, QtResourcePrefix *beforeResourcePrefix)
606 {
607     if (resourcePrefix == beforeResourcePrefix)
608         return;
609 
610     QtQrcFile *qrcFile = qrcFileOf(resourcePrefix);
611     if (!qrcFile)
612         return;
613 
614     if (beforeResourcePrefix && qrcFileOf(beforeResourcePrefix) != qrcFile)
615         return;
616 
617     const int idx = qrcFile->m_resourcePrefixes.indexOf(resourcePrefix);
618 
619     int beforeIdx = qrcFile->m_resourcePrefixes.indexOf(beforeResourcePrefix);
620     if (beforeIdx < 0)
621         beforeIdx = qrcFile->m_resourcePrefixes.size();
622 
623     if (idx == beforeIdx - 1) // the same position, nothing changes
624         return;
625 
626     QtResourcePrefix *oldBefore = nullptr;
627     if (idx < qrcFile->m_resourcePrefixes.size() - 1)
628         oldBefore = qrcFile->m_resourcePrefixes.at(idx + 1);
629 
630     qrcFile->m_resourcePrefixes.removeAt(idx);
631     if (idx < beforeIdx)
632         beforeIdx -= 1;
633 
634     qrcFile->m_resourcePrefixes.insert(beforeIdx, resourcePrefix);
635 
636     emit resourcePrefixMoved(resourcePrefix, oldBefore);
637 }
638 
changeResourcePrefix(QtResourcePrefix * resourcePrefix,const QString & newPrefix)639 void QtQrcManager::changeResourcePrefix(QtResourcePrefix *resourcePrefix, const QString &newPrefix)
640 {
641     if (!resourcePrefix)
642         return;
643 
644     const QString oldPrefix = resourcePrefix->m_prefix;
645     if (oldPrefix == newPrefix)
646         return;
647 
648     resourcePrefix->m_prefix = newPrefix;
649 
650     emit resourcePrefixChanged(resourcePrefix, oldPrefix);
651 }
652 
changeResourceLanguage(QtResourcePrefix * resourcePrefix,const QString & newLanguage)653 void QtQrcManager::changeResourceLanguage(QtResourcePrefix *resourcePrefix, const QString &newLanguage)
654 {
655     if (!resourcePrefix)
656         return;
657 
658     const QString oldLanguage = resourcePrefix->m_language;
659     if (oldLanguage == newLanguage)
660         return;
661 
662     resourcePrefix->m_language = newLanguage;
663 
664     emit resourceLanguageChanged(resourcePrefix, oldLanguage);
665 }
666 
removeResourcePrefix(QtResourcePrefix * resourcePrefix)667 void QtQrcManager::removeResourcePrefix(QtResourcePrefix *resourcePrefix)
668 {
669     QtQrcFile *qrcFile = qrcFileOf(resourcePrefix);
670     if (!qrcFile)
671         return;
672 
673     const int idx = qrcFile->m_resourcePrefixes.indexOf(resourcePrefix);
674 
675     const auto resourceFiles = resourcePrefix->resourceFiles();
676     for (QtResourceFile *rf : resourceFiles)
677         removeResourceFile(rf);
678 
679     emit resourcePrefixRemoved(resourcePrefix);
680 
681     qrcFile->m_resourcePrefixes.removeAt(idx);
682     m_prefixToQrc.remove(resourcePrefix);
683     delete resourcePrefix;
684 }
685 
insertResourceFile(QtResourcePrefix * resourcePrefix,const QString & path,const QString & alias,QtResourceFile * beforeResourceFile)686 QtResourceFile *QtQrcManager::insertResourceFile(QtResourcePrefix *resourcePrefix, const QString &path,
687         const QString &alias, QtResourceFile *beforeResourceFile)
688 {
689     if (!resourcePrefix)
690         return nullptr;
691 
692     int idx = resourcePrefix->m_resourceFiles.indexOf(beforeResourceFile);
693     if (idx < 0)
694         idx = resourcePrefix->m_resourceFiles.size();
695 
696     QtResourceFile *resourceFile = new QtResourceFile();
697     resourceFile->m_path = path;
698     resourceFile->m_alias = alias;
699     const QFileInfo fi(qrcFileOf(resourcePrefix)->path());
700     const QDir dir(fi.absolutePath());
701     const QString fullPath = dir.absoluteFilePath(path);
702     resourceFile->m_fullPath = fullPath;
703 
704     resourcePrefix->m_resourceFiles.insert(idx, resourceFile);
705     m_fileToPrefix[resourceFile] = resourcePrefix;
706     m_fullPathToResourceFiles[fullPath].append(resourceFile);
707     if (!m_fullPathToIcon.contains(fullPath)) {
708         m_fullPathToIcon[fullPath] = QIcon(fullPath);
709         const QFileInfo fullInfo(fullPath);
710         m_fullPathToExists[fullPath] = fullInfo.exists();
711     }
712 
713     emit resourceFileInserted(resourceFile);
714     return resourceFile;
715 }
716 
moveResourceFile(QtResourceFile * resourceFile,QtResourceFile * beforeResourceFile)717 void QtQrcManager::moveResourceFile(QtResourceFile *resourceFile, QtResourceFile *beforeResourceFile)
718 {
719     if (resourceFile == beforeResourceFile)
720         return;
721 
722     QtResourcePrefix *resourcePrefix = resourcePrefixOf(resourceFile);
723     if (!resourcePrefix)
724         return;
725 
726     if (beforeResourceFile && resourcePrefixOf(beforeResourceFile) != resourcePrefix)
727         return;
728 
729     const int idx = resourcePrefix->m_resourceFiles.indexOf(resourceFile);
730 
731     int beforeIdx = resourcePrefix->m_resourceFiles.indexOf(beforeResourceFile);
732     if (beforeIdx < 0)
733         beforeIdx = resourcePrefix->m_resourceFiles.size();
734 
735     if (idx == beforeIdx - 1) // the same position, nothing changes
736         return;
737 
738     QtResourceFile *oldBefore = nullptr;
739     if (idx < resourcePrefix->m_resourceFiles.size() - 1)
740         oldBefore = resourcePrefix->m_resourceFiles.at(idx + 1);
741 
742     resourcePrefix->m_resourceFiles.removeAt(idx);
743     if (idx < beforeIdx)
744         beforeIdx -= 1;
745 
746     resourcePrefix->m_resourceFiles.insert(beforeIdx, resourceFile);
747 
748     emit resourceFileMoved(resourceFile, oldBefore);
749 }
750 
changeResourceAlias(QtResourceFile * resourceFile,const QString & newAlias)751 void QtQrcManager::changeResourceAlias(QtResourceFile *resourceFile, const QString &newAlias)
752 {
753     if (!resourceFile)
754         return;
755 
756     const QString oldAlias = resourceFile->m_alias;
757     if (oldAlias == newAlias)
758         return;
759 
760     resourceFile->m_alias = newAlias;
761 
762     emit resourceAliasChanged(resourceFile, oldAlias);
763 }
764 
removeResourceFile(QtResourceFile * resourceFile)765 void QtQrcManager::removeResourceFile(QtResourceFile *resourceFile)
766 {
767     QtResourcePrefix *resourcePrefix = resourcePrefixOf(resourceFile);
768     if (!resourcePrefix)
769         return;
770 
771     const int idx = resourcePrefix->m_resourceFiles.indexOf(resourceFile);
772 
773     emit resourceFileRemoved(resourceFile);
774 
775     resourcePrefix->m_resourceFiles.removeAt(idx);
776     m_fileToPrefix.remove(resourceFile);
777     const QString fullPath = resourceFile->fullPath();
778     m_fullPathToResourceFiles[fullPath].removeAll(resourceFile); // optimize me
779     if (m_fullPathToResourceFiles[fullPath].isEmpty()) {
780         m_fullPathToResourceFiles.remove(fullPath);
781         m_fullPathToIcon.remove(fullPath);
782         m_fullPathToExists.remove(fullPath);
783     }
784     delete resourceFile;
785 }
786 
787 
788 
789 }
790 
791 // ----------------- QtResourceEditorDialogPrivate
792 class QtResourceEditorDialogPrivate
793 {
794     QtResourceEditorDialog *q_ptr;
795     Q_DECLARE_PUBLIC(QtResourceEditorDialog)
796 public:
797     QtResourceEditorDialogPrivate() = default;
798 
799     void slotQrcFileInserted(QtQrcFile *qrcFile);
800     void slotQrcFileMoved(QtQrcFile *qrcFile);
801     void slotQrcFileRemoved(QtQrcFile *qrcFile);
802 
803     QStandardItem *insertResourcePrefix(QtResourcePrefix *resourcePrefix);
804 
slotResourcePrefixInserted(QtResourcePrefix * resourcePrefix)805     void slotResourcePrefixInserted(QtResourcePrefix *resourcePrefix) { insertResourcePrefix(resourcePrefix); }
806     void slotResourcePrefixMoved(QtResourcePrefix *resourcePrefix);
807     void slotResourcePrefixChanged(QtResourcePrefix *resourcePrefix);
808     void slotResourceLanguageChanged(QtResourcePrefix *resourcePrefix);
809     void slotResourcePrefixRemoved(QtResourcePrefix *resourcePrefix);
810     void slotResourceFileInserted(QtResourceFile *resourceFile);
811     void slotResourceFileMoved(QtResourceFile *resourceFile);
812     void slotResourceAliasChanged(QtResourceFile *resourceFile);
813     void slotResourceFileRemoved(QtResourceFile *resourceFile);
814 
815     void slotCurrentQrcFileChanged(QListWidgetItem *item);
816     void slotCurrentTreeViewItemChanged(const QModelIndex &index);
817     void slotListWidgetContextMenuRequested(const QPoint &pos);
818     void slotTreeViewContextMenuRequested(const QPoint &pos);
819     void slotTreeViewItemChanged(QStandardItem *item);
820 
821     void slotNewQrcFile();
822     void slotImportQrcFile();
823     void slotRemoveQrcFile();
824     void slotMoveUpQrcFile();
825     void slotMoveDownQrcFile();
826 
827     void slotNewPrefix();
828     void slotAddFiles();
829     void slotChangePrefix();
830     void slotChangeLanguage();
831     void slotChangeAlias();
832     void slotClonePrefix();
833     void slotRemove();
834     void slotMoveUp();
835     void slotMoveDown();
836 
837     bool loadQrcFile(const QString &path, QtQrcFileData *qrcFileData, QString *errorMessage);
838     bool loadQrcFile(const QString &path, QtQrcFileData *qrcFileData);
839     bool saveQrcFile(const QtQrcFileData &qrcFileData);
840 
841     QString qrcFileText(QtQrcFile *qrcFile) const;
842 
843     QMessageBox::StandardButton warning(const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
844                                         QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) const;
845 
846     QString browseForNewLocation(const QString &resourceFile, const QDir &rootDir) const;
847     QString copyResourceFile(const QString &resourceFile, const QString &destPath) const;
848     QtResourceFile *getCurrentResourceFile() const;
849     QtResourcePrefix *getCurrentResourcePrefix() const;
850     void selectTreeRow(QStandardItem *item);
851     QString getSaveFileNameWithExtension(QWidget *parent,
852             const QString &title, QString dir, const QString &filter, const QString &extension) const;
853     QString qrcStartDirectory() const;
854 
855     Ui::QtResourceEditorDialog m_ui;
856     QDesignerFormEditorInterface *m_core = nullptr;
857     QtResourceModel *m_resourceModel = nullptr;
858     QDesignerDialogGuiInterface *m_dlgGui = nullptr;
859     QtQrcManager *m_qrcManager = nullptr;
860     QList<QtQrcFileData> m_initialState;
861 
862     QMap<QtQrcFile *, QListWidgetItem *> m_qrcFileToItem;
863     QMap<QListWidgetItem *, QtQrcFile *> m_itemToQrcFile;
864     QMap<QtResourcePrefix *, QStandardItem *> m_resourcePrefixToPrefixItem;
865     QMap<QtResourcePrefix *, QStandardItem *> m_resourcePrefixToLanguageItem;
866     QMap<QStandardItem *, QtResourcePrefix *> m_prefixItemToResourcePrefix;
867     QMap<QStandardItem *, QtResourcePrefix *> m_languageItemToResourcePrefix;
868     QMap<QtResourceFile *, QStandardItem *> m_resourceFileToPathItem;
869     QMap<QtResourceFile *, QStandardItem *> m_resourceFileToAliasItem;
870     QMap<QStandardItem *, QtResourceFile *> m_pathItemToResourceFile;
871     QMap<QStandardItem *, QtResourceFile *> m_aliasItemToResourceFile;
872 
873     bool m_ignoreCurrentChanged = false;
874     bool m_firstQrcFileDialog = true;
875     QtQrcFile *m_currentQrcFile = nullptr;
876 
877     QAction *m_newQrcFileAction = nullptr;
878     QAction *m_importQrcFileAction = nullptr;
879     QAction *m_removeQrcFileAction = nullptr;
880     QAction *m_moveUpQrcFileAction = nullptr;
881     QAction *m_moveDownQrcFileAction = nullptr;
882 
883     QAction *m_newPrefixAction = nullptr;
884     QAction *m_addResourceFileAction = nullptr;
885     QAction *m_changePrefixAction = nullptr;
886     QAction *m_changeLanguageAction = nullptr;
887     QAction *m_changeAliasAction = nullptr;
888     QAction *m_clonePrefixAction = nullptr;
889     QAction *m_moveUpAction = nullptr;
890     QAction *m_moveDownAction = nullptr;
891     QAction *m_removeAction = nullptr;
892 
893     QStandardItemModel *m_treeModel = nullptr;
894     QItemSelectionModel *m_treeSelection = nullptr;
895 };
896 
warning(const QString & title,const QString & text,QMessageBox::StandardButtons buttons,QMessageBox::StandardButton defaultButton) const897 QMessageBox::StandardButton QtResourceEditorDialogPrivate::warning(const QString &title, const QString &text, QMessageBox::StandardButtons buttons,
898                                                                    QMessageBox::StandardButton defaultButton) const
899 {
900     return m_dlgGui->message(q_ptr, QDesignerDialogGuiInterface::ResourceEditorMessage, QMessageBox::Warning, title, text, buttons, defaultButton);
901 }
902 
qrcFileText(QtQrcFile * qrcFile) const903 QString QtResourceEditorDialogPrivate::qrcFileText(QtQrcFile *qrcFile) const
904 {
905     const QString path = qrcFile->path();
906     const QString fileName = qrcFile->fileName();
907     const QFileInfo fi(path);
908     if (fi.exists() && !fi.isWritable())
909         return QApplication::translate("QtResourceEditorDialog", "%1 [read-only]").arg(fileName);
910     if (!m_qrcManager->exists(qrcFile))
911         return QApplication::translate("QtResourceEditorDialog", "%1 [missing]").arg(fileName);
912     return fileName;
913 }
914 
slotQrcFileInserted(QtQrcFile * qrcFile)915 void QtResourceEditorDialogPrivate::slotQrcFileInserted(QtQrcFile *qrcFile)
916 {
917     QListWidgetItem *currentItem = m_ui.qrcFileList->currentItem();
918     int idx = m_ui.qrcFileList->count();
919     QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(qrcFile);
920     QListWidgetItem *nextItem = m_qrcFileToItem.value(nextQrcFile);
921     if (nextItem) {
922         const int row = m_ui.qrcFileList->row(nextItem);
923         if (row >= 0)
924             idx = row;
925     }
926     const QString path = qrcFile->path();
927     QListWidgetItem *item = new QListWidgetItem(qrcFileText(qrcFile));
928     item->setToolTip(path);
929     m_ignoreCurrentChanged = true;
930     m_ui.qrcFileList->insertItem(idx, item);
931     m_ui.qrcFileList->setCurrentItem(currentItem);
932     m_ignoreCurrentChanged = false;
933     m_qrcFileToItem[qrcFile] = item;
934     m_itemToQrcFile[item] = qrcFile;
935     if (!m_qrcManager->exists(qrcFile))
936         item->setForeground(QBrush(Qt::red));
937 }
938 
slotQrcFileMoved(QtQrcFile * qrcFile)939 void QtResourceEditorDialogPrivate::slotQrcFileMoved(QtQrcFile *qrcFile)
940 {
941     QListWidgetItem *currentItem = m_ui.qrcFileList->currentItem();
942     QListWidgetItem *item = m_qrcFileToItem.value(qrcFile);
943     m_ignoreCurrentChanged = true;
944     m_ui.qrcFileList->takeItem(m_ui.qrcFileList->row(item));
945 
946     int idx = m_ui.qrcFileList->count();
947     QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(qrcFile);
948     QListWidgetItem *nextItem = m_qrcFileToItem.value(nextQrcFile);
949     if (nextItem) {
950         int row = m_ui.qrcFileList->row(nextItem);
951         if (row >= 0)
952             idx = row;
953     }
954     m_ui.qrcFileList->insertItem(idx, item);
955     if (currentItem == item)
956         m_ui.qrcFileList->setCurrentItem(item);
957     m_ignoreCurrentChanged = false;
958 }
959 
slotQrcFileRemoved(QtQrcFile * qrcFile)960 void QtResourceEditorDialogPrivate::slotQrcFileRemoved(QtQrcFile *qrcFile)
961 {
962     QListWidgetItem *item = m_qrcFileToItem.value(qrcFile);
963     if (item == m_ui.qrcFileList->currentItem())
964         m_ui.qrcFileList->setCurrentItem(nullptr); // this should trigger list view signal currentItemChanged(0), and slot should set m_currentQrcFile to 0
965     m_ignoreCurrentChanged = true;
966     delete item;
967     m_ignoreCurrentChanged = false;
968     m_itemToQrcFile.remove(item);
969     m_qrcFileToItem.remove(qrcFile);
970 }
971 
insertResourcePrefix(QtResourcePrefix * resourcePrefix)972 QStandardItem *QtResourceEditorDialogPrivate::insertResourcePrefix(QtResourcePrefix *resourcePrefix)
973 {
974     if (m_qrcManager->qrcFileOf(resourcePrefix) != m_currentQrcFile)
975         return nullptr;
976 
977     QtResourcePrefix *prevResourcePrefix = m_qrcManager->prevResourcePrefix(resourcePrefix);
978     QStandardItem *prevItem = m_resourcePrefixToPrefixItem.value(prevResourcePrefix);
979 
980     int row = 0;
981     if (prevItem)
982         row = m_treeModel->indexFromItem(prevItem).row() + 1;
983 
984     QStandardItem *prefixItem = new QStandardItem();
985     QStandardItem *languageItem = new QStandardItem();
986     QList<QStandardItem *> items;
987     items << prefixItem;
988     items << languageItem;
989     m_treeModel->insertRow(row, items);
990     const QModelIndex newIndex = m_treeModel->indexFromItem(prefixItem);
991     m_ui.resourceTreeView->setExpanded(newIndex, true);
992     prefixItem->setFlags(prefixItem->flags() | Qt::ItemIsEditable);
993     languageItem->setFlags(languageItem->flags() | Qt::ItemIsEditable);
994     m_resourcePrefixToPrefixItem[resourcePrefix] = prefixItem;
995     m_resourcePrefixToLanguageItem[resourcePrefix] = languageItem;
996     m_prefixItemToResourcePrefix[prefixItem] = resourcePrefix;
997     m_languageItemToResourcePrefix[languageItem] = resourcePrefix;
998     slotResourcePrefixChanged(resourcePrefix);
999     slotResourceLanguageChanged(resourcePrefix);
1000     return prefixItem;
1001 }
1002 
slotResourcePrefixMoved(QtResourcePrefix * resourcePrefix)1003 void QtResourceEditorDialogPrivate::slotResourcePrefixMoved(QtResourcePrefix *resourcePrefix)
1004 {
1005     QStandardItem *prefixItem = m_resourcePrefixToPrefixItem.value(resourcePrefix);
1006     if (!prefixItem)
1007         return;
1008 
1009     QStandardItem *languageItem = m_resourcePrefixToLanguageItem.value(resourcePrefix);
1010     if (!languageItem)
1011         return;
1012 
1013     const QModelIndex index = m_treeModel->indexFromItem(prefixItem);
1014     const bool expanded = m_ui.resourceTreeView->isExpanded(index);
1015     m_ignoreCurrentChanged = true;
1016     const auto items = m_treeModel->takeRow(index.row());
1017 
1018     int row = m_treeModel->rowCount();
1019     QtResourcePrefix *nextResourcePrefix = m_qrcManager->nextResourcePrefix(resourcePrefix);
1020     QStandardItem *nextItem = m_resourcePrefixToPrefixItem.value(nextResourcePrefix);
1021     if (nextItem)
1022         row = m_treeModel->indexFromItem(nextItem).row();
1023     m_treeModel->insertRow(row, items);
1024     m_ignoreCurrentChanged = false;
1025     m_ui.resourceTreeView->setExpanded(m_treeModel->indexFromItem(items.at(0)), expanded);
1026 }
1027 
slotResourcePrefixChanged(QtResourcePrefix * resourcePrefix)1028 void QtResourceEditorDialogPrivate::slotResourcePrefixChanged(QtResourcePrefix *resourcePrefix)
1029 {
1030     QStandardItem *item = m_resourcePrefixToPrefixItem.value(resourcePrefix);
1031     if (!item)
1032         return;
1033 
1034     m_ignoreCurrentChanged = true;
1035     QString prefix = resourcePrefix->prefix();
1036     if (prefix.isEmpty())
1037         prefix = QCoreApplication::translate("QtResourceEditorDialog", "<no prefix>");
1038     item->setText(prefix);
1039     item->setToolTip(prefix);
1040     m_ignoreCurrentChanged = false;
1041 }
1042 
slotResourceLanguageChanged(QtResourcePrefix * resourcePrefix)1043 void QtResourceEditorDialogPrivate::slotResourceLanguageChanged(QtResourcePrefix *resourcePrefix)
1044 {
1045     QStandardItem *item = m_resourcePrefixToLanguageItem.value(resourcePrefix);
1046     if (!item)
1047         return;
1048 
1049     m_ignoreCurrentChanged = true;
1050     const QString language = resourcePrefix->language();
1051     item->setText(language);
1052     item->setToolTip(language);
1053 
1054     m_ignoreCurrentChanged = false;
1055 }
1056 
slotResourcePrefixRemoved(QtResourcePrefix * resourcePrefix)1057 void QtResourceEditorDialogPrivate::slotResourcePrefixRemoved(QtResourcePrefix *resourcePrefix)
1058 {
1059     QStandardItem *prefixItem = m_resourcePrefixToPrefixItem.value(resourcePrefix);
1060     if (!prefixItem)
1061         return;
1062 
1063     QStandardItem *languageItem = m_resourcePrefixToLanguageItem.value(resourcePrefix);
1064     if (!languageItem)
1065         return;
1066 
1067     m_ignoreCurrentChanged = true;
1068     m_treeModel->takeRow(m_treeModel->indexFromItem(prefixItem).row());
1069     delete prefixItem;
1070     delete languageItem;
1071     m_ignoreCurrentChanged = false;
1072     m_prefixItemToResourcePrefix.remove(prefixItem);
1073     m_languageItemToResourcePrefix.remove(languageItem);
1074     m_resourcePrefixToPrefixItem.remove(resourcePrefix);
1075     m_resourcePrefixToLanguageItem.remove(resourcePrefix);
1076 }
1077 
slotResourceFileInserted(QtResourceFile * resourceFile)1078 void QtResourceEditorDialogPrivate::slotResourceFileInserted(QtResourceFile *resourceFile)
1079 {
1080     QtResourcePrefix *resourcePrefix = m_qrcManager->resourcePrefixOf(resourceFile);
1081     if (m_qrcManager->qrcFileOf(resourcePrefix) != m_currentQrcFile)
1082         return;
1083 
1084     QtResourceFile *prevResourceFile = m_qrcManager->prevResourceFile(resourceFile);
1085     QStandardItem *prevItem = m_resourceFileToPathItem.value(prevResourceFile);
1086 
1087     QStandardItem *pathItem = new QStandardItem(resourceFile->path());
1088     QStandardItem *aliasItem = new QStandardItem();
1089     QStandardItem *parentItem = m_resourcePrefixToPrefixItem.value(resourcePrefix);
1090     QList<QStandardItem *> items;
1091     items << pathItem;
1092     items << aliasItem;
1093 
1094     int row = 0;
1095     if (prevItem)
1096         row = m_treeModel->indexFromItem(prevItem).row() + 1;
1097 
1098     parentItem->insertRow(row, items);
1099 
1100     pathItem->setFlags(pathItem->flags() & ~Qt::ItemIsEditable);
1101     aliasItem->setFlags(aliasItem->flags() | Qt::ItemIsEditable);
1102     m_resourceFileToPathItem[resourceFile] = pathItem;
1103     m_resourceFileToAliasItem[resourceFile] = aliasItem;
1104     m_pathItemToResourceFile[pathItem] = resourceFile;
1105     m_aliasItemToResourceFile[aliasItem] = resourceFile;
1106     pathItem->setToolTip(resourceFile->path());
1107     pathItem->setIcon(m_qrcManager->icon(resourceFile->fullPath()));
1108     if (!m_qrcManager->exists(resourceFile->fullPath())) {
1109         pathItem->setText(QApplication::translate("QtResourceEditorDialog", "%1 [missing]").arg(resourceFile->path()));
1110         QBrush redBrush(Qt::red);
1111         pathItem->setForeground(redBrush);
1112         aliasItem->setForeground(redBrush);
1113     }
1114     slotResourceAliasChanged(resourceFile);
1115 }
1116 
slotResourceFileMoved(QtResourceFile * resourceFile)1117 void QtResourceEditorDialogPrivate::slotResourceFileMoved(QtResourceFile *resourceFile)
1118 {
1119     QStandardItem *pathItem = m_resourceFileToPathItem.value(resourceFile);
1120     if (!pathItem)
1121         return;
1122 
1123     QStandardItem *aliasItem = m_resourceFileToAliasItem.value(resourceFile);
1124     if (!aliasItem)
1125         return;
1126 
1127     QStandardItem *parentItem = pathItem->parent();
1128     m_ignoreCurrentChanged = true;
1129     const auto items = parentItem->takeRow(m_treeModel->indexFromItem(pathItem).row());
1130 
1131     int row = parentItem->rowCount();
1132     QtResourceFile *nextResourceFile = m_qrcManager->nextResourceFile(resourceFile);
1133     QStandardItem *nextItem = m_resourceFileToPathItem.value(nextResourceFile);
1134     if (nextItem)
1135         row = m_treeModel->indexFromItem(nextItem).row();
1136     parentItem->insertRow(row, items);
1137     m_ignoreCurrentChanged = false;
1138 }
1139 
slotResourceAliasChanged(QtResourceFile * resourceFile)1140 void QtResourceEditorDialogPrivate::slotResourceAliasChanged(QtResourceFile *resourceFile)
1141 {
1142     QStandardItem *item = m_resourceFileToAliasItem.value(resourceFile);
1143     if (!item)
1144         return;
1145 
1146     m_ignoreCurrentChanged = true;
1147     const QString alias = resourceFile->alias();
1148     item->setText(alias);
1149     item->setToolTip(alias);
1150 
1151     m_ignoreCurrentChanged = false;
1152 }
1153 
slotResourceFileRemoved(QtResourceFile * resourceFile)1154 void QtResourceEditorDialogPrivate::slotResourceFileRemoved(QtResourceFile *resourceFile)
1155 {
1156     QStandardItem *pathItem = m_resourceFileToPathItem.value(resourceFile);
1157     if (!pathItem)
1158         return;
1159 
1160     QStandardItem *aliasItem = m_resourceFileToAliasItem.value(resourceFile);
1161     if (!aliasItem)
1162         return;
1163 
1164     QStandardItem *parentItem = pathItem->parent();
1165 
1166     m_ignoreCurrentChanged = true;
1167     parentItem->takeRow(m_treeModel->indexFromItem(pathItem).row());
1168     delete pathItem;
1169     delete aliasItem;
1170     m_ignoreCurrentChanged = false;
1171     m_pathItemToResourceFile.remove(pathItem);
1172     m_aliasItemToResourceFile.remove(aliasItem);
1173     m_resourceFileToPathItem.remove(resourceFile);
1174     m_resourceFileToAliasItem.remove(resourceFile);
1175 }
1176 
1177 
slotCurrentQrcFileChanged(QListWidgetItem * item)1178 void QtResourceEditorDialogPrivate::slotCurrentQrcFileChanged(QListWidgetItem *item)
1179 {
1180     if (m_ignoreCurrentChanged)
1181         return;
1182 
1183     QtQrcFile *newCurrentQrcFile = m_itemToQrcFile.value(item);
1184 
1185     if (newCurrentQrcFile == m_currentQrcFile)
1186         return;
1187 
1188     if (m_currentQrcFile) {
1189         QMap<QtResourcePrefix *, QStandardItem *> currentPrefixList = m_resourcePrefixToPrefixItem;
1190         for (auto it = currentPrefixList.cbegin(), end = currentPrefixList.cend(); it != end; ++it) {
1191             QtResourcePrefix *resourcePrefix = it.key();
1192             const auto currentResourceFiles = resourcePrefix->resourceFiles();
1193             for (QtResourceFile *rf : currentResourceFiles)
1194                 slotResourceFileRemoved(rf);
1195             slotResourcePrefixRemoved(resourcePrefix);
1196         }
1197     }
1198 
1199     m_currentQrcFile = newCurrentQrcFile;
1200     slotCurrentTreeViewItemChanged(QModelIndex());
1201     QStandardItem *firstPrefix = nullptr; // select first prefix
1202     if (m_currentQrcFile) {
1203         const auto newPrefixList = m_currentQrcFile->resourcePrefixList();
1204         for (QtResourcePrefix *resourcePrefix : newPrefixList) {
1205             if (QStandardItem *newPrefixItem = insertResourcePrefix(resourcePrefix))
1206                 if (!firstPrefix)
1207                     firstPrefix = newPrefixItem;
1208             const auto newResourceFiles = resourcePrefix->resourceFiles();
1209             for (QtResourceFile *rf : newResourceFiles)
1210                 slotResourceFileInserted(rf);
1211         }
1212     }
1213     m_ui.resourceTreeView->setCurrentIndex(firstPrefix ? m_treeModel->indexFromItem(firstPrefix) : QModelIndex());
1214 
1215     m_removeQrcFileAction->setEnabled(m_currentQrcFile);
1216     m_moveUpQrcFileAction->setEnabled(m_currentQrcFile && m_qrcManager->prevQrcFile(m_currentQrcFile));
1217     m_moveDownQrcFileAction->setEnabled(m_currentQrcFile && m_qrcManager->nextQrcFile(m_currentQrcFile));
1218 }
1219 
slotCurrentTreeViewItemChanged(const QModelIndex & index)1220 void QtResourceEditorDialogPrivate::slotCurrentTreeViewItemChanged(const QModelIndex &index)
1221 {
1222     QStandardItem *item = m_treeModel->itemFromIndex(index);
1223     QtResourceFile *resourceFile = m_pathItemToResourceFile.value(item);
1224     if (!resourceFile)
1225         resourceFile = m_aliasItemToResourceFile.value(item);
1226     QtResourcePrefix *resourcePrefix = m_prefixItemToResourcePrefix.value(item);
1227     if (!resourcePrefix)
1228         resourcePrefix = m_languageItemToResourcePrefix.value(item);
1229 
1230     bool moveUpEnabled = false;
1231     bool moveDownEnabled = false;
1232     bool currentItem = resourceFile || resourcePrefix;
1233 
1234     if (resourceFile) {
1235         if (m_qrcManager->prevResourceFile(resourceFile))
1236             moveUpEnabled = true;
1237         if (m_qrcManager->nextResourceFile(resourceFile))
1238             moveDownEnabled = true;
1239     } else if (resourcePrefix) {
1240         if (m_qrcManager->prevResourcePrefix(resourcePrefix))
1241             moveUpEnabled = true;
1242         if (m_qrcManager->nextResourcePrefix(resourcePrefix))
1243             moveDownEnabled = true;
1244     }
1245 
1246     m_newPrefixAction->setEnabled(m_currentQrcFile);
1247     m_addResourceFileAction->setEnabled(currentItem);
1248     m_changePrefixAction->setEnabled(currentItem);
1249     m_changeLanguageAction->setEnabled(currentItem);
1250     m_changeAliasAction->setEnabled(resourceFile);
1251     m_removeAction->setEnabled(currentItem);
1252     m_moveUpAction->setEnabled(moveUpEnabled);
1253     m_moveDownAction->setEnabled(moveDownEnabled);
1254     m_clonePrefixAction->setEnabled(currentItem);
1255 }
1256 
slotListWidgetContextMenuRequested(const QPoint & pos)1257 void QtResourceEditorDialogPrivate::slotListWidgetContextMenuRequested(const QPoint &pos)
1258 {
1259     QMenu menu(q_ptr);
1260     menu.addAction(m_newQrcFileAction);
1261     menu.addAction(m_importQrcFileAction);
1262     menu.addAction(m_removeQrcFileAction);
1263     menu.addSeparator();
1264     menu.addAction(m_moveUpQrcFileAction);
1265     menu.addAction(m_moveDownQrcFileAction);
1266     menu.exec(m_ui.qrcFileList->mapToGlobal(pos));
1267 }
1268 
slotTreeViewContextMenuRequested(const QPoint & pos)1269 void QtResourceEditorDialogPrivate::slotTreeViewContextMenuRequested(const QPoint &pos)
1270 {
1271     QMenu menu(q_ptr);
1272     menu.addAction(m_newPrefixAction);
1273     menu.addAction(m_addResourceFileAction);
1274     menu.addAction(m_removeAction);
1275     menu.addSeparator();
1276     menu.addAction(m_changePrefixAction);
1277     menu.addAction(m_changeLanguageAction);
1278     menu.addAction(m_changeAliasAction);
1279     menu.addSeparator();
1280     menu.addAction(m_clonePrefixAction);
1281     menu.addSeparator();
1282     menu.addAction(m_moveUpAction);
1283     menu.addAction(m_moveDownAction);
1284     menu.exec(m_ui.resourceTreeView->mapToGlobal(pos));
1285 }
1286 
slotTreeViewItemChanged(QStandardItem * item)1287 void QtResourceEditorDialogPrivate::slotTreeViewItemChanged(QStandardItem *item)
1288 {
1289     if (m_ignoreCurrentChanged)
1290         return;
1291 
1292     const QString newValue = item->text();
1293     QtResourceFile *resourceFile = m_aliasItemToResourceFile.value(item);
1294     if (resourceFile) {
1295         m_qrcManager->changeResourceAlias(resourceFile, newValue);
1296         return;
1297     }
1298 
1299     QtResourcePrefix *resourcePrefix = m_prefixItemToResourcePrefix.value(item);
1300     if (resourcePrefix) {
1301         m_qrcManager->changeResourcePrefix(resourcePrefix, newValue);
1302         return;
1303     }
1304 
1305     resourcePrefix = m_languageItemToResourcePrefix.value(item);
1306     if (resourcePrefix) {
1307         m_qrcManager->changeResourceLanguage(resourcePrefix, newValue);
1308         return;
1309     }
1310 }
1311 
getSaveFileNameWithExtension(QWidget * parent,const QString & title,QString dir,const QString & filter,const QString & extension) const1312 QString QtResourceEditorDialogPrivate::getSaveFileNameWithExtension(QWidget *parent,
1313             const QString &title, QString dir, const QString &filter, const QString &extension) const
1314 {
1315     const QChar dot = QLatin1Char('.');
1316 
1317     QString saveFile;
1318     while (true) {
1319         saveFile = m_dlgGui->getSaveFileName(parent, title, dir, filter, nullptr, QFileDialog::DontConfirmOverwrite);
1320         if (saveFile.isEmpty())
1321             return saveFile;
1322 
1323         const QFileInfo fInfo(saveFile);
1324         if (fInfo.suffix().isEmpty() && !fInfo.fileName().endsWith(dot)) {
1325             saveFile += dot;
1326             saveFile += extension;
1327         }
1328 
1329         const QFileInfo fi(saveFile);
1330         if (!fi.exists())
1331             break;
1332 
1333         if (warning(title, msgOverwrite(fi.fileName()), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
1334             break;
1335 
1336         dir = saveFile;
1337     }
1338     return saveFile;
1339 }
1340 
qrcStartDirectory() const1341 QString QtResourceEditorDialogPrivate::qrcStartDirectory() const
1342 {
1343     if (!m_currentQrcFile)
1344         return QString();
1345     const QDir dir = QFileInfo(m_currentQrcFile->path()).dir();
1346     return dir.exists() ? dir.absolutePath() : QString();
1347 }
1348 
slotNewQrcFile()1349 void QtResourceEditorDialogPrivate::slotNewQrcFile()
1350 {
1351     const QString qrcPath = getSaveFileNameWithExtension(q_ptr,
1352                 QCoreApplication::translate("QtResourceEditorDialog", "New Resource File"),
1353                 m_firstQrcFileDialog ? qrcStartDirectory() : QString(),
1354                 QCoreApplication::translate("QtResourceEditorDialog", "Resource files (*.qrc)"),
1355                 QStringLiteral("qrc"));
1356     if (qrcPath.isEmpty())
1357         return;
1358 
1359     m_firstQrcFileDialog = false;
1360     if (QtQrcFile *sameQrcFile = m_qrcManager->qrcFileOf(qrcPath)) {
1361         // QMessageBox ???
1362         QListWidgetItem *item = m_qrcFileToItem.value(sameQrcFile);
1363         m_ui.qrcFileList->setCurrentItem(item);
1364         item->setSelected(true);
1365         return;
1366     }
1367 
1368     QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile);
1369 
1370     QtQrcFile *qrcFile = m_qrcManager->insertQrcFile(qrcPath, nextQrcFile, true);
1371     m_ui.qrcFileList->setCurrentItem(m_qrcFileToItem.value(qrcFile));
1372 }
1373 
slotImportQrcFile()1374 void QtResourceEditorDialogPrivate::slotImportQrcFile()
1375 {
1376     const QString qrcPath = m_dlgGui->getOpenFileName(q_ptr,
1377                 QCoreApplication::translate("QtResourceEditorDialog", "Import Resource File"),
1378                 m_firstQrcFileDialog ? qrcStartDirectory() : QString(),
1379                 QCoreApplication::translate("QtResourceEditorDialog", "Resource files (*.qrc)"));
1380     if (qrcPath.isEmpty())
1381         return;
1382     m_firstQrcFileDialog = false;
1383     if (QtQrcFile *sameQrcFile = m_qrcManager->qrcFileOf(qrcPath)) {
1384         // QMessageBox ???
1385         QListWidgetItem *item = m_qrcFileToItem.value(sameQrcFile);
1386         m_ui.qrcFileList->setCurrentItem(item);
1387         item->setSelected(true);
1388         return;
1389     }
1390 
1391     QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile);
1392 
1393     QtQrcFileData qrcFileData;
1394     loadQrcFile(qrcPath, &qrcFileData);
1395     QtQrcFile *qrcFile = m_qrcManager->importQrcFile(qrcFileData, nextQrcFile);
1396     m_ui.qrcFileList->setCurrentItem(m_qrcFileToItem.value(qrcFile));
1397 }
1398 
slotRemoveQrcFile()1399 void QtResourceEditorDialogPrivate::slotRemoveQrcFile()
1400 {
1401     if (!m_currentQrcFile)
1402         return;
1403 
1404     QtQrcFile *currentQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile);
1405     if (!currentQrcFile)
1406         currentQrcFile = m_qrcManager->prevQrcFile(m_currentQrcFile);
1407 
1408     m_qrcManager->removeQrcFile(m_currentQrcFile);
1409     QListWidgetItem *item = m_qrcFileToItem.value(currentQrcFile);
1410     if (item) {
1411         m_ui.qrcFileList->setCurrentItem(item);
1412         item->setSelected(true);
1413     }
1414 }
1415 
slotMoveUpQrcFile()1416 void QtResourceEditorDialogPrivate::slotMoveUpQrcFile()
1417 {
1418     if (!m_currentQrcFile)
1419         return;
1420 
1421     QtQrcFile *prevQrcFile = m_qrcManager->prevQrcFile(m_currentQrcFile);
1422     if (!prevQrcFile)
1423         return;
1424 
1425     m_qrcManager->moveQrcFile(m_currentQrcFile, prevQrcFile);
1426 }
1427 
slotMoveDownQrcFile()1428 void QtResourceEditorDialogPrivate::slotMoveDownQrcFile()
1429 {
1430     if (!m_currentQrcFile)
1431         return;
1432 
1433     QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile);
1434     if (!nextQrcFile)
1435         return;
1436     nextQrcFile = m_qrcManager->nextQrcFile(nextQrcFile);
1437 
1438     m_qrcManager->moveQrcFile(m_currentQrcFile, nextQrcFile);
1439 }
1440 
getCurrentResourceFile() const1441 QtResourceFile *QtResourceEditorDialogPrivate::getCurrentResourceFile() const
1442 {
1443     QStandardItem *currentItem = m_treeModel->itemFromIndex(m_treeSelection->currentIndex());
1444 
1445 
1446     QtResourceFile *currentResourceFile = nullptr;
1447     if (currentItem) {
1448         currentResourceFile = m_pathItemToResourceFile.value(currentItem);
1449         if (!currentResourceFile)
1450             currentResourceFile = m_aliasItemToResourceFile.value(currentItem);
1451     }
1452     return currentResourceFile;
1453 }
1454 
getCurrentResourcePrefix() const1455 QtResourcePrefix *QtResourceEditorDialogPrivate::getCurrentResourcePrefix() const
1456 {
1457     QStandardItem *currentItem = m_treeModel->itemFromIndex(m_treeSelection->currentIndex());
1458 
1459     QtResourcePrefix *currentResourcePrefix = nullptr;
1460     if (currentItem) {
1461         currentResourcePrefix = m_prefixItemToResourcePrefix.value(currentItem);
1462         if (!currentResourcePrefix) {
1463             currentResourcePrefix = m_languageItemToResourcePrefix.value(currentItem);
1464             if (!currentResourcePrefix) {
1465                 QtResourceFile *currentResourceFile = getCurrentResourceFile();
1466                 if (currentResourceFile)
1467                     currentResourcePrefix = m_qrcManager->resourcePrefixOf(currentResourceFile);
1468             }
1469         }
1470     }
1471     return currentResourcePrefix;
1472 }
1473 
selectTreeRow(QStandardItem * item)1474 void QtResourceEditorDialogPrivate::selectTreeRow(QStandardItem *item)
1475 {
1476     const QModelIndex index = m_treeModel->indexFromItem(item);
1477     m_treeSelection->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
1478     m_treeSelection->setCurrentIndex(index, QItemSelectionModel::Select);
1479 }
1480 
slotNewPrefix()1481 void QtResourceEditorDialogPrivate::slotNewPrefix()
1482 {
1483     if (!m_currentQrcFile)
1484         return;
1485 
1486     QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix();
1487     QtResourcePrefix *nextResourcePrefix = m_qrcManager->nextResourcePrefix(currentResourcePrefix);
1488     QtResourcePrefix *newResourcePrefix = m_qrcManager->insertResourcePrefix(m_currentQrcFile,
1489                 QCoreApplication::translate("QtResourceEditorDialog", "newPrefix"),
1490                 QString(), nextResourcePrefix);
1491     if (!newResourcePrefix)
1492         return;
1493 
1494     QStandardItem *newItem = m_resourcePrefixToPrefixItem.value(newResourcePrefix);
1495     if (!newItem)
1496         return;
1497 
1498     const QModelIndex index = m_treeModel->indexFromItem(newItem);
1499     selectTreeRow(newItem);
1500     m_ui.resourceTreeView->edit(index);
1501 }
1502 
outOfPathWarning(const QString & fname)1503 static inline QString outOfPathWarning(const QString &fname)
1504 {
1505     return QApplication::translate("QtResourceEditorDialog",
1506     "<p><b>Warning:</b> The file</p>"
1507     "<p>%1</p>"
1508     "<p>is outside of the current resource file's parent directory.</p>").arg(fname);
1509 }
1510 
outOfPathWarningInfo()1511 static inline QString outOfPathWarningInfo()
1512 {
1513     return QApplication::translate("QtResourceEditorDialog",
1514     "<p>To resolve the issue, press:</p>"
1515     "<table>"
1516     "<tr><th align=\"left\">Copy</th><td>to copy the file to the resource file's parent directory.</td></tr>"
1517     "<tr><th align=\"left\">Copy As...</th><td>to copy the file into a subdirectory of the resource file's parent directory.</td></tr>"
1518     "<tr><th align=\"left\">Keep</th><td>to use its current location.</td></tr></table>");
1519 }
1520 
slotAddFiles()1521 void QtResourceEditorDialogPrivate::slotAddFiles()
1522 {
1523     if (!m_currentQrcFile)
1524         return;
1525 
1526     QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix();
1527     QtResourceFile *currentResourceFile = getCurrentResourceFile();
1528     if (!currentResourcePrefix)
1529         return;
1530 
1531     QString initialPath = m_currentQrcFile->path();
1532     if (currentResourceFile) {
1533         QFileInfo fi(currentResourceFile->fullPath());
1534         initialPath = fi.absolutePath();
1535     }
1536 
1537     const QStringList resourcePaths = m_dlgGui->getOpenImageFileNames(q_ptr,
1538                 QCoreApplication::translate("QtResourceEditorDialog", "Add Files"),
1539                 initialPath);
1540     if (resourcePaths.isEmpty())
1541         return;
1542 
1543     QtResourceFile *nextResourceFile = m_qrcManager->nextResourceFile(currentResourceFile);
1544     if (!currentResourceFile) {
1545         const auto resourceFiles = currentResourcePrefix->resourceFiles();
1546         if (resourceFiles.count() > 0)
1547             nextResourceFile = resourceFiles.first();
1548     }
1549 
1550     const QFileInfo fi(m_currentQrcFile->path());
1551     const QString destDir = fi.absolutePath();
1552     const QDir dir(fi.absolutePath());
1553     for (QString resourcePath : resourcePaths) {
1554         QString relativePath = dir.relativeFilePath(resourcePath);
1555         if (relativePath.startsWith(QStringLiteral(".."))) {
1556             QMessageBox msgBox(QMessageBox::Warning,
1557                     QCoreApplication::translate("QtResourceEditorDialog", "Incorrect Path"),
1558                     outOfPathWarning(relativePath), QMessageBox::Cancel);
1559             msgBox.setInformativeText(outOfPathWarningInfo());
1560             QPushButton *copyButton = msgBox.addButton(QCoreApplication::translate("QtResourceEditorDialog",
1561                         "Copy"), QMessageBox::ActionRole);
1562             QPushButton *copyAsButton = msgBox.addButton(QCoreApplication::translate("QtResourceEditorDialog",
1563                         "Copy As..."), QMessageBox::ActionRole);
1564             QPushButton *keepButton = msgBox.addButton(QCoreApplication::translate("QtResourceEditorDialog",
1565                         "Keep"), QMessageBox::ActionRole);
1566             QPushButton *skipButton = msgBox.addButton(QCoreApplication::translate("QtResourceEditorDialog",
1567                         "Skip"), QMessageBox::ActionRole);
1568             msgBox.setEscapeButton(QMessageBox::Cancel);
1569             msgBox.setDefaultButton(copyButton);
1570             msgBox.exec();
1571             QString destPath;
1572             if (msgBox.clickedButton() == keepButton) {
1573                 // nothing
1574             } else if (msgBox.clickedButton() == copyButton) {
1575                 QFileInfo resInfo(resourcePath);
1576                 QDir dd(destDir);
1577                 destPath = dd.absoluteFilePath(resInfo.fileName());
1578                 if (dd.exists(resInfo.fileName())) {
1579                     if (warning(QCoreApplication::translate("QtResourceEditorDialog", "Copy"),
1580                                 msgOverwrite(resInfo.fileName()),
1581                                 QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Yes)
1582                         continue;
1583                 }
1584                 resourcePath = copyResourceFile(resourcePath, destPath); // returns empty string in case copy failed or was canceled
1585             } else if (msgBox.clickedButton() == copyAsButton) {
1586                 destPath = browseForNewLocation(resourcePath, dir); // returns empty string in case browsing was canceled
1587                 if (destPath.isEmpty())
1588                     continue;
1589                 resourcePath = copyResourceFile(resourcePath, destPath); // returns empty string in case copy failed or was canceled
1590             } else if (msgBox.clickedButton() == skipButton) { // skipped
1591                 continue;
1592             } else { // canceled
1593                 return;
1594             }
1595             if (resourcePath.isEmpty())
1596                 continue;
1597         }
1598         relativePath = dir.relativeFilePath(resourcePath);
1599         QtResourceFile *newResourceFile = m_qrcManager->insertResourceFile(currentResourcePrefix, relativePath, QString(), nextResourceFile);
1600 
1601         QStandardItem *newItem = m_resourceFileToPathItem.value(newResourceFile);
1602         if (newItem)
1603             selectTreeRow(newItem);
1604     }
1605 }
1606 
slotChangePrefix()1607 void QtResourceEditorDialogPrivate::slotChangePrefix()
1608 {
1609     QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix();
1610     if (!currentResourcePrefix)
1611         return;
1612 
1613     QStandardItem *item = m_resourcePrefixToPrefixItem.value(currentResourcePrefix);
1614     QModelIndex index = m_treeModel->indexFromItem(item);
1615     selectTreeRow(item);
1616     m_ui.resourceTreeView->scrollTo(index);
1617     m_ui.resourceTreeView->edit(index);
1618 }
1619 
slotChangeLanguage()1620 void QtResourceEditorDialogPrivate::slotChangeLanguage()
1621 {
1622     QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix();
1623     if (!currentResourcePrefix)
1624         return;
1625 
1626     QStandardItem *item = m_resourcePrefixToLanguageItem.value(currentResourcePrefix);
1627     QModelIndex index = m_treeModel->indexFromItem(item);
1628     selectTreeRow(item);
1629     m_ui.resourceTreeView->scrollTo(index);
1630     m_ui.resourceTreeView->edit(index);
1631 }
1632 
slotChangeAlias()1633 void QtResourceEditorDialogPrivate::slotChangeAlias()
1634 {
1635     QtResourceFile *currentResourceFile = getCurrentResourceFile();
1636     if (!currentResourceFile)
1637         return;
1638 
1639     QStandardItem *item = m_resourceFileToAliasItem.value(currentResourceFile);
1640     QModelIndex index = m_treeModel->indexFromItem(item);
1641     selectTreeRow(item);
1642     m_ui.resourceTreeView->scrollTo(index);
1643     m_ui.resourceTreeView->edit(index);
1644 }
1645 
slotClonePrefix()1646 void QtResourceEditorDialogPrivate::slotClonePrefix()
1647 {
1648     QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix();
1649     if (!currentResourcePrefix)
1650         return;
1651 
1652     bool ok;
1653     QString suffix = QInputDialog::getText(q_ptr, QApplication::translate("QtResourceEditorDialog", "Clone Prefix"),
1654             QCoreApplication::translate("QtResourceEditorDialog", "Enter the suffix which you want to add to the names of the cloned files.\n"
1655                 "This could for example be a language extension like \"_de\"."),
1656             QLineEdit::Normal, QString(), &ok);
1657     if (!ok)
1658         return;
1659 
1660     QtResourcePrefix *newResourcePrefix = m_qrcManager->insertResourcePrefix(m_currentQrcFile, currentResourcePrefix->prefix(),
1661                                     currentResourcePrefix->language(), m_qrcManager->nextResourcePrefix(currentResourcePrefix));
1662     if (newResourcePrefix) {
1663         const auto files = currentResourcePrefix->resourceFiles();
1664         for (QtResourceFile *resourceFile : files) {
1665             QString path = resourceFile->path();
1666             QFileInfo fi(path);
1667             QDir dir(fi.dir());
1668             QString oldSuffix = fi.completeSuffix();
1669             if (!oldSuffix.isEmpty())
1670                 oldSuffix = QLatin1Char('.') + oldSuffix;
1671             const QString newBaseName = fi.baseName() + suffix + oldSuffix;
1672             const QString newPath = QDir::cleanPath(dir.filePath(newBaseName));
1673             m_qrcManager->insertResourceFile(newResourcePrefix, newPath,
1674                     resourceFile->alias());
1675         }
1676     }
1677 }
1678 
slotRemove()1679 void QtResourceEditorDialogPrivate::slotRemove()
1680 {
1681     QStandardItem *item = m_treeModel->itemFromIndex(m_treeSelection->currentIndex());
1682     if (!item)
1683         return;
1684 
1685     QtResourceFile *resourceFile = m_pathItemToResourceFile.value(item);
1686     if (!resourceFile)
1687         resourceFile = m_aliasItemToResourceFile.value(item);
1688     QtResourcePrefix *resourcePrefix = m_prefixItemToResourcePrefix.value(item);
1689     if (!resourcePrefix)
1690         resourcePrefix = m_languageItemToResourcePrefix.value(item);
1691 
1692     QStandardItem *newCurrentItem = nullptr;
1693 
1694     if (resourceFile) {
1695         QtResourceFile *nextFile = m_qrcManager->nextResourceFile(resourceFile);
1696         if (!nextFile)
1697             nextFile = m_qrcManager->prevResourceFile(resourceFile);
1698         newCurrentItem = m_resourceFileToPathItem.value(nextFile);
1699         if (!newCurrentItem)
1700             newCurrentItem = m_resourcePrefixToPrefixItem.value(m_qrcManager->resourcePrefixOf(resourceFile));
1701     }
1702     if (!newCurrentItem) {
1703         QtResourcePrefix *nextPrefix = m_qrcManager->nextResourcePrefix(resourcePrefix);
1704         if (!nextPrefix)
1705             nextPrefix = m_qrcManager->prevResourcePrefix(resourcePrefix);
1706         newCurrentItem = m_resourcePrefixToPrefixItem.value(nextPrefix);
1707     }
1708 
1709     selectTreeRow(newCurrentItem);
1710 
1711     if (resourcePrefix)
1712         m_qrcManager->removeResourcePrefix(resourcePrefix);
1713     else if (resourceFile)
1714         m_qrcManager->removeResourceFile(resourceFile);
1715 }
1716 
slotMoveUp()1717 void QtResourceEditorDialogPrivate::slotMoveUp()
1718 {
1719     if (QtResourceFile *resourceFile = getCurrentResourceFile()) {
1720         QtResourceFile *prevFile = m_qrcManager->prevResourceFile(resourceFile);
1721 
1722         if (!prevFile)
1723             return;
1724 
1725         m_qrcManager->moveResourceFile(resourceFile, prevFile);
1726         selectTreeRow(m_resourceFileToPathItem.value(resourceFile));
1727     } else if (QtResourcePrefix *resourcePrefix = getCurrentResourcePrefix()) {
1728         QtResourcePrefix *prevPrefix = m_qrcManager->prevResourcePrefix(resourcePrefix);
1729 
1730         if (!prevPrefix)
1731             return;
1732 
1733         m_qrcManager->moveResourcePrefix(resourcePrefix, prevPrefix);
1734         selectTreeRow(m_resourcePrefixToPrefixItem.value(resourcePrefix));
1735     }
1736 }
1737 
slotMoveDown()1738 void QtResourceEditorDialogPrivate::slotMoveDown()
1739 {
1740     if (QtResourceFile *resourceFile = getCurrentResourceFile()) {
1741         QtResourceFile *nextFile = m_qrcManager->nextResourceFile(resourceFile);
1742 
1743         if (!nextFile)
1744             return;
1745 
1746         m_qrcManager->moveResourceFile(resourceFile, m_qrcManager->nextResourceFile(nextFile));
1747         selectTreeRow(m_resourceFileToPathItem.value(resourceFile));
1748     } else if (QtResourcePrefix *resourcePrefix = getCurrentResourcePrefix()) {
1749         QtResourcePrefix *nextPrefix = m_qrcManager->nextResourcePrefix(resourcePrefix);
1750 
1751         if (!nextPrefix)
1752             return;
1753 
1754         m_qrcManager->moveResourcePrefix(resourcePrefix, m_qrcManager->nextResourcePrefix(nextPrefix));
1755         selectTreeRow(m_resourcePrefixToPrefixItem.value(resourcePrefix));
1756     }
1757 }
1758 
browseForNewLocation(const QString & resourceFile,const QDir & rootDir) const1759 QString QtResourceEditorDialogPrivate::browseForNewLocation(const QString &resourceFile, const QDir &rootDir) const
1760 {
1761     QFileInfo fi(resourceFile);
1762     const QString initialPath = rootDir.absoluteFilePath(fi.fileName());
1763     while (true) {
1764         QString newPath = m_dlgGui->getSaveFileName(q_ptr,
1765                     QCoreApplication::translate("QtResourceEditorDialog", "Copy As"),
1766                     initialPath);
1767         QString relativePath = rootDir.relativeFilePath(newPath);
1768         if (relativePath.startsWith(QStringLiteral(".."))) {
1769             if (warning(QCoreApplication::translate("QtResourceEditorDialog", "Copy As"),
1770                         QCoreApplication::translate("QtResourceEditorDialog", "<p>The selected file:</p>"
1771                                         "<p>%1</p><p>is outside of the current resource file's directory:</p><p>%2</p>"
1772                                         "<p>Please select another path within this directory.<p>").
1773                         arg(relativePath, rootDir.absolutePath()),
1774                         QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) != QMessageBox::Ok)
1775                 return QString();
1776         } else {
1777             return newPath;
1778         }
1779     }
1780 
1781     return QString();
1782 }
1783 
copyResourceFile(const QString & resourceFile,const QString & destPath) const1784 QString QtResourceEditorDialogPrivate::copyResourceFile(const QString &resourceFile, const QString &destPath) const
1785 {
1786     QFileInfo fi(destPath);
1787     if (fi.exists()) {
1788         while (fi.exists() && !QFile::remove(destPath)) {
1789             if (warning(QCoreApplication::translate("QtResourceEditorDialog", "Copy"),
1790                         QCoreApplication::translate("QtResourceEditorDialog", "Could not overwrite %1.").arg(fi.fileName()),
1791                         QMessageBox::Retry | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Retry)
1792                 return QString();
1793         }
1794     }
1795     while (!QFile::copy(resourceFile, destPath)) {
1796         if (warning(QCoreApplication::translate("QtResourceEditorDialog", "Copy"),
1797                     QCoreApplication::translate("QtResourceEditorDialog", "Could not copy\n%1\nto\n%2")
1798                     .arg(resourceFile, destPath),
1799                     QMessageBox::Retry | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Retry)
1800             return QString();
1801     }
1802     return destPath;
1803 }
loadQrcFile(const QString & path,QtQrcFileData * qrcFileData)1804 bool QtResourceEditorDialogPrivate::loadQrcFile(const QString &path, QtQrcFileData *qrcFileData)
1805 {
1806     QString errorMessage;
1807     const bool rc = loadQrcFile(path, qrcFileData, &errorMessage);
1808 //    if (!rc)
1809 //        warning(QApplication::translate("QtResourceEditorDialog", "Resource File Load Error"), errorMessage);
1810     return rc;
1811 }
loadQrcFile(const QString & path,QtQrcFileData * qrcFileData,QString * errorMessage)1812 bool QtResourceEditorDialogPrivate::loadQrcFile(const QString &path, QtQrcFileData *qrcFileData, QString *errorMessage)
1813 {
1814     if (!qrcFileData)
1815         return false;
1816 
1817     qrcFileData->qrcPath = path;
1818 
1819     QFile file(path);
1820     if (!file.open(QIODevice::ReadOnly)) {
1821         // there is sufficient hint while loading a form and after opening the editor (qrc marked marked with red and with [missing] text)
1822         //*errorMessage =  QApplication::translate("QtResourceEditorDialog", "Unable to open %1 for reading: %2").arg(path).arg(file.errorString());
1823         return false;
1824     }
1825 
1826     QByteArray dataArray = file.readAll();
1827     file.close();
1828 
1829     QDomDocument doc;
1830     int errLine, errCol;
1831     if (!doc.setContent(dataArray, errorMessage, &errLine, &errCol))  {
1832         *errorMessage =
1833             QCoreApplication::translate("QtResourceEditorDialog",
1834                                         "A parse error occurred at line %1, column %2 of %3:\n%4")
1835                                        .arg(errLine).arg(errCol).arg(path, *errorMessage);
1836         return false;
1837     }
1838 
1839     return loadQrcFileData(doc, path, qrcFileData, errorMessage);
1840 }
1841 
saveQrcFile(const QtQrcFileData & qrcFileData)1842 bool QtResourceEditorDialogPrivate::saveQrcFile(const QtQrcFileData &qrcFileData)
1843 {
1844     QFile file(qrcFileData.qrcPath);
1845     while (!file.open(QIODevice::WriteOnly)) {
1846         QMessageBox msgBox(QMessageBox::Warning,
1847                 QCoreApplication::translate("QtResourceEditorDialog",
1848                                             "Save Resource File"),
1849                 QCoreApplication::translate("QtResourceEditorDialog",
1850                                             "Could not write %1: %2")
1851                                            .arg(qrcFileData.qrcPath,
1852                                                 file.errorString()),
1853                 QMessageBox::Cancel|QMessageBox::Ignore|QMessageBox::Retry);
1854         msgBox.setEscapeButton(QMessageBox::Cancel);
1855         msgBox.setDefaultButton(QMessageBox::Ignore);
1856         switch (msgBox.exec()) {
1857         case QMessageBox::Retry:
1858             break; // nothing
1859         case QMessageBox::Ignore:
1860             return true;
1861         default:
1862             return false;
1863         }
1864     }
1865 
1866     QDomDocument doc = saveQrcFileData(qrcFileData);
1867 
1868     QByteArray dataArray = doc.toByteArray(2);
1869     file.write(dataArray);
1870 
1871     file.close();
1872     return true;
1873 }
1874 
QtResourceEditorDialog(QDesignerFormEditorInterface * core,QDesignerDialogGuiInterface * dlgGui,QWidget * parent)1875 QtResourceEditorDialog::QtResourceEditorDialog(QDesignerFormEditorInterface *core, QDesignerDialogGuiInterface *dlgGui, QWidget *parent)
1876     : QDialog(parent), d_ptr(new QtResourceEditorDialogPrivate())
1877 {
1878     d_ptr->q_ptr = this;
1879     d_ptr->m_ui.setupUi(this);
1880     d_ptr->m_qrcManager = new QtQrcManager(this);
1881     d_ptr->m_dlgGui = dlgGui;
1882     d_ptr->m_core = core;
1883 
1884     setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
1885     setWindowTitle(tr("Edit Resources"));
1886 
1887     connect(d_ptr->m_qrcManager, SIGNAL(qrcFileInserted(QtQrcFile*)),
1888                 this, SLOT(slotQrcFileInserted(QtQrcFile*)));
1889     connect(d_ptr->m_qrcManager, SIGNAL(qrcFileMoved(QtQrcFile*,QtQrcFile*)),
1890                 this, SLOT(slotQrcFileMoved(QtQrcFile*)));
1891     connect(d_ptr->m_qrcManager, SIGNAL(qrcFileRemoved(QtQrcFile*)),
1892                 this, SLOT(slotQrcFileRemoved(QtQrcFile*)));
1893     connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixInserted(QtResourcePrefix*)),
1894                 this, SLOT(slotResourcePrefixInserted(QtResourcePrefix*)));
1895     connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixMoved(QtResourcePrefix*,QtResourcePrefix*)),
1896                 this, SLOT(slotResourcePrefixMoved(QtResourcePrefix*)));
1897     connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixChanged(QtResourcePrefix*,QString)),
1898                 this, SLOT(slotResourcePrefixChanged(QtResourcePrefix*)));
1899     connect(d_ptr->m_qrcManager, SIGNAL(resourceLanguageChanged(QtResourcePrefix*,QString)),
1900                 this, SLOT(slotResourceLanguageChanged(QtResourcePrefix*)));
1901     connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixRemoved(QtResourcePrefix*)),
1902                 this, SLOT(slotResourcePrefixRemoved(QtResourcePrefix*)));
1903     connect(d_ptr->m_qrcManager, SIGNAL(resourceFileInserted(QtResourceFile*)),
1904                 this, SLOT(slotResourceFileInserted(QtResourceFile*)));
1905     connect(d_ptr->m_qrcManager, SIGNAL(resourceFileMoved(QtResourceFile*,QtResourceFile*)),
1906                 this, SLOT(slotResourceFileMoved(QtResourceFile*)));
1907     connect(d_ptr->m_qrcManager, SIGNAL(resourceAliasChanged(QtResourceFile*,QString)),
1908                 this, SLOT(slotResourceAliasChanged(QtResourceFile*)));
1909     connect(d_ptr->m_qrcManager, SIGNAL(resourceFileRemoved(QtResourceFile*)),
1910                 this, SLOT(slotResourceFileRemoved(QtResourceFile*)));
1911 
1912     QIcon upIcon = qdesigner_internal::createIconSet(QString::fromUtf8("up.png"));
1913     QIcon downIcon = qdesigner_internal::createIconSet(QString::fromUtf8("down.png"));
1914     QIcon minusIcon = qdesigner_internal::createIconSet(QString::fromUtf8("minus-16.png"));
1915     QIcon newIcon = qdesigner_internal::createIconSet(QString::fromUtf8("filenew-16.png"));
1916     QIcon openIcon = qdesigner_internal::createIconSet(QString::fromUtf8("fileopen-16.png"));
1917     QIcon removeIcon = qdesigner_internal::createIconSet(QString::fromUtf8("editdelete-16.png"));
1918     QIcon addPrefixIcon = qdesigner_internal::createIconSet(QString::fromUtf8("prefix-add.png"));
1919 
1920     d_ptr->m_newQrcFileAction = new QAction(newIcon, tr("New..."), this);
1921     d_ptr->m_newQrcFileAction->setToolTip(tr("New Resource File"));
1922     d_ptr->m_importQrcFileAction = new QAction(openIcon, tr("Open..."), this);
1923     d_ptr->m_importQrcFileAction->setToolTip(tr("Open Resource File"));
1924     d_ptr->m_removeQrcFileAction = new QAction(removeIcon, tr("Remove"), this);
1925     d_ptr->m_moveUpQrcFileAction = new QAction(upIcon, tr("Move Up"), this);
1926     d_ptr->m_moveDownQrcFileAction = new QAction(downIcon, tr("Move Down"), this);
1927 
1928     d_ptr->m_newPrefixAction = new QAction(addPrefixIcon, tr("Add Prefix"), this);
1929     d_ptr->m_newPrefixAction->setToolTip(tr("Add Prefix"));
1930     d_ptr->m_addResourceFileAction = new QAction(openIcon, tr("Add Files..."), this);
1931     d_ptr->m_changePrefixAction = new QAction(tr("Change Prefix"), this);
1932     d_ptr->m_changeLanguageAction = new QAction(tr("Change Language"), this);
1933     d_ptr->m_changeAliasAction = new QAction(tr("Change Alias"), this);
1934     d_ptr->m_clonePrefixAction = new QAction(tr("Clone Prefix..."), this);
1935     d_ptr->m_removeAction = new QAction(minusIcon, tr("Remove"), this);
1936     d_ptr->m_moveUpAction = new QAction(upIcon, tr("Move Up"), this);
1937     d_ptr->m_moveDownAction = new QAction(downIcon, tr("Move Down"), this);
1938 
1939     d_ptr->m_ui.newQrcButton->setDefaultAction(d_ptr->m_newQrcFileAction);
1940     d_ptr->m_ui.importQrcButton->setDefaultAction(d_ptr->m_importQrcFileAction);
1941     d_ptr->m_ui.removeQrcButton->setDefaultAction(d_ptr->m_removeQrcFileAction);
1942 
1943     d_ptr->m_ui.newResourceButton->setDefaultAction(d_ptr->m_newPrefixAction);
1944     d_ptr->m_ui.addResourceButton->setDefaultAction(d_ptr->m_addResourceFileAction);
1945     d_ptr->m_ui.removeResourceButton->setDefaultAction(d_ptr->m_removeAction);
1946 
1947     connect(d_ptr->m_newQrcFileAction, SIGNAL(triggered()), this, SLOT(slotNewQrcFile()));
1948     connect(d_ptr->m_importQrcFileAction, SIGNAL(triggered()), this, SLOT(slotImportQrcFile()));
1949     connect(d_ptr->m_removeQrcFileAction, SIGNAL(triggered()), this, SLOT(slotRemoveQrcFile()));
1950     connect(d_ptr->m_moveUpQrcFileAction, SIGNAL(triggered()), this, SLOT(slotMoveUpQrcFile()));
1951     connect(d_ptr->m_moveDownQrcFileAction, SIGNAL(triggered()), this, SLOT(slotMoveDownQrcFile()));
1952 
1953     connect(d_ptr->m_newPrefixAction, SIGNAL(triggered()), this, SLOT(slotNewPrefix()));
1954     connect(d_ptr->m_addResourceFileAction, SIGNAL(triggered()), this, SLOT(slotAddFiles()));
1955     connect(d_ptr->m_changePrefixAction, SIGNAL(triggered()), this, SLOT(slotChangePrefix()));
1956     connect(d_ptr->m_changeLanguageAction, SIGNAL(triggered()), this, SLOT(slotChangeLanguage()));
1957     connect(d_ptr->m_changeAliasAction, SIGNAL(triggered()), this, SLOT(slotChangeAlias()));
1958     connect(d_ptr->m_clonePrefixAction, SIGNAL(triggered()), this, SLOT(slotClonePrefix()));
1959     connect(d_ptr->m_removeAction, SIGNAL(triggered()), this, SLOT(slotRemove()));
1960     connect(d_ptr->m_moveUpAction, SIGNAL(triggered()), this, SLOT(slotMoveUp()));
1961     connect(d_ptr->m_moveDownAction, SIGNAL(triggered()), this, SLOT(slotMoveDown()));
1962 
1963     d_ptr->m_ui.qrcFileList->setContextMenuPolicy(Qt::CustomContextMenu);
1964     connect(d_ptr->m_ui.qrcFileList, SIGNAL(customContextMenuRequested(QPoint)),
1965                 this, SLOT(slotListWidgetContextMenuRequested(QPoint)));
1966     connect(d_ptr->m_ui.qrcFileList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
1967                     this, SLOT(slotCurrentQrcFileChanged(QListWidgetItem*)));
1968 
1969     d_ptr->m_treeModel = new QStandardItemModel(this);
1970     d_ptr->m_treeModel->setColumnCount(2);
1971     d_ptr->m_treeModel->setHorizontalHeaderItem(0, new QStandardItem(tr("Prefix / Path")));
1972     d_ptr->m_treeModel->setHorizontalHeaderItem(1, new QStandardItem(tr("Language / Alias")));
1973     d_ptr->m_ui.resourceTreeView->setModel(d_ptr->m_treeModel);
1974     d_ptr->m_ui.resourceTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
1975     d_ptr->m_treeSelection = d_ptr->m_ui.resourceTreeView->selectionModel();
1976     connect(d_ptr->m_ui.resourceTreeView->header(), &QHeaderView::sectionDoubleClicked,
1977             d_ptr->m_ui.resourceTreeView, &QTreeView::resizeColumnToContents);
1978     d_ptr->m_ui.resourceTreeView->setTextElideMode(Qt::ElideLeft);
1979 
1980     connect(d_ptr->m_ui.resourceTreeView, SIGNAL(customContextMenuRequested(QPoint)),
1981                 this, SLOT(slotTreeViewContextMenuRequested(QPoint)));
1982     connect(d_ptr->m_treeModel, SIGNAL(itemChanged(QStandardItem*)),
1983                 this, SLOT(slotTreeViewItemChanged(QStandardItem*)));
1984     connect(d_ptr->m_treeSelection, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
1985                     this, SLOT(slotCurrentTreeViewItemChanged(QModelIndex)));
1986 
1987     d_ptr->m_ui.resourceTreeView->setColumnWidth(0, 200);
1988 
1989     d_ptr->slotCurrentTreeViewItemChanged(QModelIndex());
1990     d_ptr->m_removeQrcFileAction->setEnabled(false);
1991     d_ptr->m_moveUpQrcFileAction->setEnabled(false);
1992     d_ptr->m_moveDownQrcFileAction->setEnabled(false);
1993 
1994     QDesignerSettingsInterface *settings = core->settingsManager();
1995     settings->beginGroup(QLatin1String(QrcDialogC));
1996 
1997     d_ptr->m_ui.splitter->restoreState(settings->value(QLatin1String(SplitterPosition)).toByteArray());
1998     const QVariant geometry = settings->value(QLatin1String(Geometry));
1999     if (geometry.type() == QVariant::ByteArray) // Used to be a QRect up until 5.4.0, QTBUG-43374
2000         restoreGeometry(geometry.toByteArray());
2001 
2002     settings->endGroup();
2003 }
2004 
~QtResourceEditorDialog()2005 QtResourceEditorDialog::~QtResourceEditorDialog()
2006 {
2007     QDesignerSettingsInterface *settings = d_ptr->m_core->settingsManager();
2008     settings->beginGroup(QLatin1String(QrcDialogC));
2009 
2010     settings->setValue(QLatin1String(SplitterPosition), d_ptr->m_ui.splitter->saveState());
2011     settings->setValue(QLatin1String(Geometry), saveGeometry());
2012     settings->endGroup();
2013 }
2014 
model() const2015 QtResourceModel *QtResourceEditorDialog::model() const
2016 {
2017     return d_ptr->m_resourceModel;
2018 }
2019 
setResourceModel(QtResourceModel * model)2020 void QtResourceEditorDialog::setResourceModel(QtResourceModel *model)
2021 {
2022     d_ptr->m_resourceModel = model;
2023 
2024     QtResourceSet *resourceSet = d_ptr->m_resourceModel->currentResourceSet();
2025     if (!resourceSet) {
2026         // disable everything but cancel button
2027         return;
2028     }
2029 
2030     d_ptr->m_initialState.clear();
2031 
2032     // enable qrcBox
2033 
2034     const QStringList paths = resourceSet->activeResourceFilePaths();
2035     for (const QString &path : paths) {
2036         QtQrcFileData qrcFileData;
2037         d_ptr->loadQrcFile(path, &qrcFileData);
2038         d_ptr->m_initialState << qrcFileData;
2039         d_ptr->m_qrcManager->importQrcFile(qrcFileData);
2040     }
2041     if (d_ptr->m_ui.qrcFileList->count() > 0) {
2042         d_ptr->m_ui.qrcFileList->item(0)->setSelected(true);
2043     }
2044 }
2045 
selectedResource() const2046 QString QtResourceEditorDialog::selectedResource() const
2047 {
2048     //QtResourcePrefix *currentResourcePrefix = d_ptr->m_qrcManager->resourcePrefixOf(currentResourceFile);
2049     QtResourcePrefix *currentResourcePrefix = d_ptr->getCurrentResourcePrefix();
2050     if (!currentResourcePrefix)
2051         return QString();
2052 
2053     const QChar slash(QLatin1Char('/'));
2054     QString resource = currentResourcePrefix->prefix();
2055     if (!resource.startsWith(slash))
2056         resource.prepend(slash);
2057     if (!resource.endsWith(slash))
2058         resource.append(slash);
2059     resource.prepend(QLatin1Char(':'));
2060 
2061     QtResourceFile *currentResourceFile = d_ptr->getCurrentResourceFile();
2062     if (!currentResourceFile)
2063         return resource;
2064 
2065     QString resourceEnding = currentResourceFile->path();
2066     if (!currentResourceFile->alias().isEmpty())
2067         resourceEnding = currentResourceFile->alias();
2068 
2069     const QString dotSlash(QStringLiteral("./"));
2070     const QString dotDotSlash(QStringLiteral("../"));
2071     while (true) {
2072         if (resourceEnding.startsWith(slash))
2073             resourceEnding = resourceEnding.mid(1);
2074         else if (resourceEnding.startsWith(dotSlash))
2075             resourceEnding = resourceEnding.mid(dotSlash.count());
2076         else if (resourceEnding.startsWith(dotDotSlash))
2077             resourceEnding = resourceEnding.mid(dotDotSlash.count());
2078         else
2079             break;
2080     }
2081 
2082     resource.append(resourceEnding);
2083 
2084     return resource;
2085 }
2086 
displayResourceFailures(const QString & logOutput,QDesignerDialogGuiInterface * dlgGui,QWidget * parent)2087 void QtResourceEditorDialog::displayResourceFailures(const QString &logOutput, QDesignerDialogGuiInterface *dlgGui, QWidget *parent)
2088 {
2089     const QString msg = tr("<html><p><b>Warning:</b> There have been problems while reloading the resources:</p><pre>%1</pre></html>").arg(logOutput);
2090     dlgGui->message(parent, QDesignerDialogGuiInterface::ResourceEditorMessage, QMessageBox::Warning,
2091                     tr("Resource Warning"), msg);
2092 }
2093 
accept()2094 void QtResourceEditorDialog::accept()
2095 {
2096     QStringList newQrcPaths;
2097     QList<QtQrcFileData> currentState;
2098 
2099     const auto qrcFiles = d_ptr->m_qrcManager->qrcFiles();
2100     for (QtQrcFile *qrcFile : qrcFiles) {
2101         QtQrcFileData qrcFileData;
2102         d_ptr->m_qrcManager->exportQrcFile(qrcFile, &qrcFileData);
2103         currentState << qrcFileData;
2104         if (qrcFileData == qrcFile->initialState()) {
2105             // nothing
2106         } else {
2107             d_ptr->m_resourceModel->setWatcherEnabled(qrcFileData.qrcPath, false);
2108             bool ok = d_ptr->saveQrcFile(qrcFileData);
2109             d_ptr->m_resourceModel->setWatcherEnabled(qrcFileData.qrcPath, true);
2110             if (!ok)
2111                 return;
2112 
2113             d_ptr->m_resourceModel->setModified(qrcFileData.qrcPath);
2114         }
2115         newQrcPaths << qrcFileData.qrcPath;
2116     }
2117 
2118     if (currentState == d_ptr->m_initialState) {
2119         // nothing
2120     } else {
2121         int errorCount;
2122         QString errorMessages;
2123         d_ptr->m_resourceModel->currentResourceSet()->activateResourceFilePaths(newQrcPaths, &errorCount, &errorMessages);
2124         if (errorCount)
2125             displayResourceFailures(errorMessages, d_ptr->m_dlgGui, this);
2126     }
2127     QDialog::accept();
2128 }
2129 
editResources(QDesignerFormEditorInterface * core,QtResourceModel * model,QDesignerDialogGuiInterface * dlgGui,QWidget * parent)2130 QString QtResourceEditorDialog::editResources(QDesignerFormEditorInterface *core,
2131                                               QtResourceModel *model,
2132                                               QDesignerDialogGuiInterface *dlgGui,
2133                                               QWidget *parent)
2134 {
2135     QtResourceEditorDialog dialog(core, dlgGui, parent);
2136     dialog.setResourceModel(model);
2137     if (dialog.exec() == QDialog::Accepted)
2138         return dialog.selectedResource();
2139     return QString();
2140 }
2141 
2142 QT_END_NAMESPACE
2143 
2144 #include "moc_qtresourceeditordialog_p.cpp"
2145 #include "qtresourceeditordialog.moc"
2146