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
qdesigner_utils.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
9
10#include <QtDesigner/abstractformeditor.h>
11#include <QtDesigner/abstractformwindow.h>
12#include <QtDesigner/abstractresourcebrowser.h>
13#include <QtDesigner/abstractlanguage.h>
14#include <QtDesigner/taskmenu.h>
15#include <QtDesigner/qextensionmanager.h>
16
17#include <QtCore/qcoreapplication.h>
18#include <QtCore/qdir.h>
19#include <QtCore/qfileinfo.h>
20#include <QtCore/qoperatingsystemversion.h>
21#include <QtCore/qprocess.h>
22#include <QtCore/qlibraryinfo.h>
23#include <QtCore/qdebug.h>
24#include <QtCore/qqueue.h>
25#include <QtCore/qshareddata.h>
26#include <QtCore/qstandardpaths.h>
27
28#include <QtWidgets/qapplication.h>
29#include <QtGui/qicon.h>
30#include <QtGui/qpalette.h>
31#include <QtGui/qpixmap.h>
32#include <QtWidgets/qlistwidget.h>
33#include <QtWidgets/qtreewidget.h>
34#include <QtWidgets/qtablewidget.h>
35#include <QtWidgets/qcombobox.h>
36
38
39using namespace Qt::StringLiterals;
40
41namespace qdesigner_internal
42{
43 // ### FIXME Qt 8: Remove (QTBUG-96005)
44 QString legacyDataDirectory()
45 {
46 return QDir::homePath() + u"/.designer"_s;
47 }
48
49 QString dataDirectory()
50 {
51#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
52 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
53 + u'/' + QCoreApplication::organizationName() + u"/Designer"_s;
54#else
55 return legacyDataDirectory();
56#endif
57 }
58
59
60 QDESIGNER_SHARED_EXPORT void designerWarning(const QString &message)
61 {
62 qWarning("Designer: %s", qPrintable(message));
63 }
64
65 void reloadTreeItem(DesignerIconCache *iconCache, QTreeWidgetItem *item)
66 {
67 if (!item)
68 return;
69
70 for (int c = 0; c < item->columnCount(); c++) {
71 const QVariant v = item->data(c, Qt::DecorationPropertyRole);
72 if (v.canConvert<PropertySheetIconValue>())
73 item->setIcon(c, iconCache->icon(qvariant_cast<PropertySheetIconValue>(v)));
74 }
75 }
76
77 void reloadListItem(DesignerIconCache *iconCache, QListWidgetItem *item)
78 {
79 if (!item)
80 return;
81
82 const QVariant v = item->data(Qt::DecorationPropertyRole);
83 if (v.canConvert<PropertySheetIconValue>())
84 item->setIcon(iconCache->icon(qvariant_cast<PropertySheetIconValue>(v)));
85 }
86
87 void reloadTableItem(DesignerIconCache *iconCache, QTableWidgetItem *item)
88 {
89 if (!item)
90 return;
91
92 const QVariant v = item->data(Qt::DecorationPropertyRole);
93 if (v.canConvert<PropertySheetIconValue>())
94 item->setIcon(iconCache->icon(qvariant_cast<PropertySheetIconValue>(v)));
95 }
96
97 void reloadIconResources(DesignerIconCache *iconCache, QObject *object)
98 {
99 if (QListWidget *listWidget = qobject_cast<QListWidget *>(object)) {
100 for (int i = 0; i < listWidget->count(); i++)
101 reloadListItem(iconCache, listWidget->item(i));
102 } else if (QComboBox *comboBox = qobject_cast<QComboBox *>(object)) {
103 for (int i = 0; i < comboBox->count(); i++) {
104 const QVariant v = comboBox->itemData(i, Qt::DecorationPropertyRole);
105 if (v.canConvert<PropertySheetIconValue>()) {
106 QIcon icon = iconCache->icon(qvariant_cast<PropertySheetIconValue>(v));
107 comboBox->setItemIcon(i, icon);
108 comboBox->setItemData(i, icon);
109 }
110 }
111 } else if (QTreeWidget *treeWidget = qobject_cast<QTreeWidget *>(object)) {
112 reloadTreeItem(iconCache, treeWidget->headerItem());
113 QQueue<QTreeWidgetItem *> itemsQueue;
114 for (int i = 0; i < treeWidget->topLevelItemCount(); i++)
115 itemsQueue.enqueue(treeWidget->topLevelItem(i));
116 while (!itemsQueue.isEmpty()) {
117 QTreeWidgetItem *item = itemsQueue.dequeue();
118 for (int i = 0; i < item->childCount(); i++)
119 itemsQueue.enqueue(item->child(i));
120 reloadTreeItem(iconCache, item);
121 }
122 } else if (QTableWidget *tableWidget = qobject_cast<QTableWidget *>(object)) {
123 const int columnCount = tableWidget->columnCount();
124 const int rowCount = tableWidget->rowCount();
125 for (int c = 0; c < columnCount; c++)
126 reloadTableItem(iconCache, tableWidget->horizontalHeaderItem(c));
127 for (int r = 0; r < rowCount; r++)
128 reloadTableItem(iconCache, tableWidget->verticalHeaderItem(r));
129 for (int c = 0; c < columnCount; c++)
130 for (int r = 0; r < rowCount; r++)
131 reloadTableItem(iconCache, tableWidget->item(r, c));
132 }
133 }
134
135 // ------------- DesignerMetaEnum
140
141
143 {
144 // find value
145 bool valueOk;
147 if (ok)
148 *ok = valueOk;
149
150 if (!valueOk)
151 return item;
152
155 return qualifiedItem;
156 }
157
159 {
160 return QCoreApplication::translate("DesignerMetaEnum",
161 "%1 is not a valid enumeration value of '%2'.")
162 .arg(value).arg(enumName());
163 }
164
166 {
167 return QCoreApplication::translate("DesignerMetaEnum",
168 "'%1' could not be converted to an enumeration value of type '%2'.")
169 .arg(s, enumName());
170 }
171 // -------------- DesignerMetaFlags
177
179 {
181 const uint v = static_cast<uint>(ivalue);
182 for (auto it = keyToValueMap().begin(), end = keyToValueMap().end(); it != end; ++it) {
183 const uint itemValue = it->second;
184 // Check for equality first as flag values can be 0 or -1, too. Takes preference over a bitwise flag
185 if (v == itemValue) {
186 rc.clear();
188 return rc;
189 }
190 // Do not add 0-flags (None-flags)
191 if (itemValue)
192 if ((v & itemValue) == itemValue)
194 }
195 return rc;
196 }
197
198
200 {
202 if (flagIds.isEmpty())
203 return QString();
204
205 QString rc;
206 for (const auto &id : flagIds) {
207 if (!rc.isEmpty())
208 rc += u'|';
210 }
211 return rc;
212 }
213
214
215 int DesignerMetaFlags::parseFlags(const QString &s, bool *ok) const
216 {
217 if (s.isEmpty()) {
218 if (ok)
219 *ok = true;
220 return 0;
221 }
222 uint flags = 0;
223 bool valueOk = true;
224 const auto keys = QStringView{s}.split(u'|');
225 for (const auto &key : keys) {
227 if (!valueOk) {
228 flags = 0;
229 break;
230 }
231 flags |= flagValue;
232 }
233 if (ok)
234 *ok = valueOk;
235 return static_cast<int>(flags);
236 }
237
239 {
240 return QCoreApplication::translate("DesignerMetaFlags",
241 "'%1' could not be converted to a flag value of type '%2'.")
242 .arg(s, enumName());
243 }
244
245 // ---------- PropertySheetEnumValue
246
252
254
255 // ---------------- PropertySheetFlagValue
261
263
264 // ---------------- PropertySheetPixmapValue
268
270
277
279 {
280 return m_path;
281 }
282
284 {
285 if (m_path == path)
286 return;
287 m_path = path;
288 }
289
290 // ---------- PropertySheetIconValue
291
298
304
309
311
314
317
318} // namespace qdesigner_internal
319
320namespace qdesigner_internal {
321
322 size_t qHash(const PropertySheetIconValue &p, size_t seed) noexcept
323 {
324 // qHash for paths making use of the existing QPair hash functions.
325 const auto *d = p.m_data.constData();
326 return qHashMulti(seed, d->m_paths, d->m_themeEnum, d->m_theme);
327 }
328
329 bool comparesEqual(const PropertySheetIconValue &lhs,
330 const PropertySheetIconValue &rhs) noexcept
331 {
332 const auto *lhsd = lhs.m_data.constData();
333 const auto *rhsd = rhs.m_data.constData();
334 return lhsd == rhsd
335 || (lhsd->m_themeEnum == rhsd->m_themeEnum
336 && lhsd->m_theme == rhsd->m_theme && lhsd->m_paths == rhsd->m_paths);
337 }
338
340 {
341 return m_data->m_themeEnum == -1 && m_data->m_theme.isEmpty()
342 && m_data->m_paths.isEmpty();
343 }
344
346 {
347 return m_data->m_theme;
348 }
349
351 {
352 m_data->m_theme = t;
353 }
354
356 {
357 return m_data->m_themeEnum;
358 }
359
361 {
363 }
364
370
379
381 {
382 const auto it = m_cache.constFind(value);
383 if (it != m_cache.constEnd())
384 return it.value();
385
388 return pix;
389 }
390
392 {
393 m_cache.clear();
394 }
395
400
402 {
403 const auto it = m_cache.constFind(value);
404 if (it != m_cache.constEnd())
405 return it.value();
406
407 // Match on the theme first if it is available.
408 if (value.themeEnum() != -1) {
409 const QIcon themeIcon = QIcon::fromTheme(static_cast<QIcon::ThemeIcon>(value.themeEnum()));
411 return themeIcon;
412 }
413 if (!value.theme().isEmpty()) {
414 const QString theme = value.theme();
415 if (QIcon::hasThemeIcon(theme)) {
418 return themeIcon;
419 }
420 }
421
422 QIcon icon;
424 for (auto it = paths.constBegin(), cend = paths.constEnd(); it != cend; ++it) {
425 const auto pair = it.key();
427 }
429 return icon;
430 }
431
433 {
434 m_cache.clear();
435 }
436
443
446
450
452 {
453 return m_value;
454 }
455
457 {
458 m_value = value;
459 }
460
468
470 {
471 return m_value;
472 }
473
478
480
481
486
491
493 {
494 return m_value;
495 }
496
502
507
513
518
519 /* IconSubPropertyMask: Assign each icon sub-property (pixmaps for the
520 * various states/modes and the theme) a flag bit (see QFont) so that they
521 * can be handled individually when assigning property values to
522 * multiselections in the set-property-commands (that is, do not clobber
523 * other subproperties when assigning just one).
524 * Provide back-and-forth mapping functions for the icon states. */
525
538
539 static inline uint iconStateToSubPropertyFlag(QIcon::Mode mode, QIcon::State state)
540 {
541 switch (mode) {
542 case QIcon::Disabled:
543 return state == QIcon::On ? DisabledOnIconMask : DisabledOffIconMask;
544 case QIcon::Active:
545 return state == QIcon::On ? ActiveOnIconMask : ActiveOffIconMask;
546 case QIcon::Selected:
547 return state == QIcon::On ? SelectedOnIconMask : SelectedOffIconMask;
548 case QIcon::Normal:
549 break;
550 }
551 return state == QIcon::On ? NormalOnIconMask : NormalOffIconMask;
552 }
553
554 static inline std::pair<QIcon::Mode, QIcon::State> subPropertyFlagToIconModeState(unsigned flag)
555 {
556 switch (flag) {
557 case NormalOnIconMask:
558 return {QIcon::Normal, QIcon::On};
559 case DisabledOffIconMask:
560 return {QIcon::Disabled, QIcon::Off};
561 case DisabledOnIconMask:
562 return {QIcon::Disabled, QIcon::On};
563 case ActiveOffIconMask:
564 return {QIcon::Active, QIcon::Off};
565 case ActiveOnIconMask:
566 return {QIcon::Active, QIcon::On};
567 case SelectedOffIconMask:
568 return {QIcon::Selected, QIcon::Off};
569 case SelectedOnIconMask:
570 return {QIcon::Selected, QIcon::On};
572 default:
573 break;
574 }
575 return {QIcon::Normal, QIcon::Off};
576 }
577
579 {
580 uint flags = 0;
581 for (auto it = m_data->m_paths.constBegin(), cend = m_data->m_paths.constEnd(); it != cend; ++it)
583 if (!m_data->m_theme.isEmpty())
585 if (m_data->m_themeEnum != -1)
587 return flags;
588 }
589
591 {
592 uint diffMask = mask() | other.mask();
593 for (int i = 0; i < 8; i++) {
594 const uint flag = 1 << i;
595 if (diffMask & flag) { // if state is set in both icons, compare the values
598 diffMask &= ~flag;
599 }
600 }
601 if ((diffMask & ThemeIconMask) && theme() == other.theme())
605
606 return diffMask;
607 }
608
615
623
625 {
626 for (int i = 0; i < 8; i++) {
627 uint flag = 1 << i;
628 if (mask & flag) {
631 }
632 }
633 if (mask & ThemeIconMask)
637 }
638
643
645 {
647 debug.nospace();
648 debug.noquote();
649 debug << "PropertySheetIconValue(mask=0x" << Qt::hex << p.mask() << Qt::dec << ", ";
650 if (p.themeEnum() != -1)
651 debug << "theme=" << p.themeEnum() << ", ";
652 if (!p.theme().isEmpty())
653 debug << "XDG theme=\"" << p.theme() << "\", ";
654
656 for (auto it = paths.constBegin(), cend = paths.constEnd(); it != cend; ++it) {
657 debug << " mode=" << it.key().first << ",state=" << it.key().second
658 << ", \"" << it.value().path() << '"';
659 }
660 debug << ')';
661 return debug;
662 }
663
675
677 {
678 QAction *action = nullptr;
681 if (!action) {
682 const auto actions = taskMenu->taskActions();
683 if (!actions.isEmpty())
684 action = actions.first();
685 }
686 }
687 if (!action) {
689 core->extensionManager()->extension(managedWidget, u"QDesignerInternalTaskMenuExtension"_s))) {
691 if (!action) {
692 const auto actions = taskMenu->taskActions();
693 if (!actions.isEmpty())
694 action = actions.first();
695 }
696 }
697 }
698 return action;
699 }
700
701 QDESIGNER_SHARED_EXPORT bool runUIC(const QString &fileName, UicLanguage language,
702 QByteArray& ba, QString &errorMessage)
703 {
704 QProcess uic;
705 QStringList arguments;
706 static constexpr auto uicBinary =
707 QOperatingSystemVersion::currentType() != QOperatingSystemVersion::Windows
708 ? "/uic"_L1 : "/uic.exe"_L1;
709 QString binary = [] {
710 const QStringList paths = QLibraryInfo::paths(QLibraryInfo::LibraryExecutablesPath);
711 for (const QString &path : paths) {
712 const QString candidate = path + uicBinary;
713 if (QFile::exists(candidate))
714 return candidate;
715 }
716 return QString();
717 }();
718 // In a PySide6 installation, there is no libexec directory; uic.exe is
719 // in the main wheel directory next to designer.exe.
720 if (binary.isEmpty())
721 binary = QCoreApplication::applicationDirPath() + uicBinary;
722 if (!QFileInfo::exists(binary)) {
723 errorMessage = QApplication::translate("Designer", "%1 does not exist.").
724 arg(QDir::toNativeSeparators(binary));
725 return false;
726 }
727
728 switch (language) {
729 case UicLanguage::Cpp:
730 break;
731 case UicLanguage::Python:
732 arguments << u"-g"_s << u"python"_s;
733 break;
734 }
735 arguments << fileName;
736
737 uic.start(binary, arguments);
738
739 if (!uic.waitForStarted()) {
740 errorMessage = QApplication::translate("Designer", "Unable to launch %1: %2").
741 arg(QDir::toNativeSeparators(binary), uic.errorString());
742 return false;
743 }
744 if (!uic.waitForFinished()) {
745 errorMessage = QApplication::translate("Designer", "%1 timed out.").arg(binary);
746 return false;
747 }
748 if (uic.exitCode()) {
749 errorMessage = QString::fromLatin1(uic.readAllStandardError());
750 return false;
751 }
752 ba = uic.readAllStandardOutput();
753 return true;
754 }
755
757 {
759
760 Q_ASSERT(qname.isEmpty() == false);
761
762
763 if (qname.size() > 1 && qname.at(1).isUpper()) {
764 const QChar first = qname.at(0);
765 if (first == u'Q' || first == u'K')
766 qname.remove(0, 1);
767 }
768
769 const qsizetype len = qname.size();
770 for (qsizetype i = 0; i < len && qname.at(i).isUpper(); ++i)
771 qname[i] = qname.at(i).toLower();
772
773 return qname;
774 }
775
776 // --------------- UpdateBlocker
784
786 {
787 if (m_enabled)
789 }
790
791// from qpalette.cpp
792quint64 paletteResolveMask(QPalette::ColorGroup colorGroup,
793 QPalette::ColorRole colorRole)
794{
795 if (colorRole == QPalette::Accent)
796 colorRole = QPalette::NoRole; // See qtbase/17c589df94a2245ee92d45839c2cba73566d7310
797 const auto offset = quint64(QPalette::NColorRoles - 1) * quint64(colorGroup);
798 const auto bitPos = quint64(colorRole) + offset;
799 return 1ull << bitPos;
800}
801
802quint64 paletteResolveMask(QPalette::ColorRole colorRole)
803{
804 return paletteResolveMask(QPalette::Active, colorRole)
805 | paletteResolveMask(QPalette::Inactive, colorRole)
806 | paletteResolveMask(QPalette::Disabled, colorRole);
807}
808
809} // namespace qdesigner_internal
810
811QT_END_NAMESPACE
Combined button and popup list for selecting options.
Auxiliary methods to store/retrieve settings.
void reloadListItem(DesignerIconCache *iconCache, QListWidgetItem *item)
static std::pair< QIcon::Mode, QIcon::State > subPropertyFlagToIconModeState(unsigned flag)
size_t qHash(const PropertySheetIconValue &p, size_t seed) noexcept
static uint iconStateToSubPropertyFlag(QIcon::Mode mode, QIcon::State state)
void reloadTableItem(DesignerIconCache *iconCache, QTableWidgetItem *item)
void reloadTreeItem(DesignerIconCache *iconCache, QTreeWidgetItem *item)
bool comparesEqual(const DeviceProfile &lhs, const DeviceProfile &rhs) noexcept
#define QDESIGNER_SHARED_EXPORT