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