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