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
8
9#include <QtDesigner/abstractformeditor.h>
10#include <QtDesigner/abstractformwindow.h>
11#include <QtDesigner/abstractresourcebrowser.h>
12#include <QtDesigner/abstractlanguage.h>
13#include <QtDesigner/taskmenu.h>
14#include <QtDesigner/qextensionmanager.h>
15
16#include <QtCore/qcoreapplication.h>
17#include <QtCore/qdir.h>
18#include <QtCore/qfileinfo.h>
19#include <QtCore/qoperatingsystemversion.h>
20#include <QtCore/qprocess.h>
21#include <QtCore/qlibraryinfo.h>
22#include <QtCore/qdebug.h>
23#include <QtCore/qqueue.h>
24#include <QtCore/qshareddata.h>
25#include <QtCore/qstandardpaths.h>
26
27#include <QtWidgets/qapplication.h>
28#include <QtGui/qicon.h>
29#include <QtGui/qpalette.h>
30#include <QtGui/qpixmap.h>
31#include <QtWidgets/qlistwidget.h>
32#include <QtWidgets/qtreewidget.h>
33#include <QtWidgets/qtablewidget.h>
34#include <QtWidgets/qcombobox.h>
35
37
38using namespace Qt::StringLiterals;
39
40namespace qdesigner_internal
41{
42 // ### FIXME Qt 8: Remove (QTBUG-96005)
43 QString legacyDataDirectory()
44 {
45 return QDir::homePath() + u"/.designer"_s;
46 }
47
48 QString dataDirectory()
49 {
50#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
51 return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
52 + u'/' + QCoreApplication::organizationName() + u"/Designer"_s;
53#else
54 return legacyDataDirectory();
55#endif
56 }
57
58
59 QDESIGNER_SHARED_EXPORT void designerWarning(const QString &message)
60 {
61 qWarning("Designer: %s", qPrintable(message));
62 }
63
64 void reloadTreeItem(DesignerIconCache *iconCache, QTreeWidgetItem *item)
65 {
66 if (!item)
67 return;
68
69 for (int c = 0; c < item->columnCount(); c++) {
70 const QVariant v = item->data(c, Qt::DecorationPropertyRole);
71 if (v.canConvert<PropertySheetIconValue>())
72 item->setIcon(c, iconCache->icon(qvariant_cast<PropertySheetIconValue>(v)));
73 }
74 }
75
76 void reloadListItem(DesignerIconCache *iconCache, QListWidgetItem *item)
77 {
78 if (!item)
79 return;
80
81 const QVariant v = item->data(Qt::DecorationPropertyRole);
82 if (v.canConvert<PropertySheetIconValue>())
83 item->setIcon(iconCache->icon(qvariant_cast<PropertySheetIconValue>(v)));
84 }
85
86 void reloadTableItem(DesignerIconCache *iconCache, QTableWidgetItem *item)
87 {
88 if (!item)
89 return;
90
91 const QVariant v = item->data(Qt::DecorationPropertyRole);
92 if (v.canConvert<PropertySheetIconValue>())
93 item->setIcon(iconCache->icon(qvariant_cast<PropertySheetIconValue>(v)));
94 }
95
96 void reloadIconResources(DesignerIconCache *iconCache, QObject *object)
97 {
98 if (QListWidget *listWidget = qobject_cast<QListWidget *>(object)) {
99 for (int i = 0; i < listWidget->count(); i++)
100 reloadListItem(iconCache, listWidget->item(i));
101 } else if (QComboBox *comboBox = qobject_cast<QComboBox *>(object)) {
102 for (int i = 0; i < comboBox->count(); i++) {
103 const QVariant v = comboBox->itemData(i, Qt::DecorationPropertyRole);
104 if (v.canConvert<PropertySheetIconValue>()) {
105 QIcon icon = iconCache->icon(qvariant_cast<PropertySheetIconValue>(v));
106 comboBox->setItemIcon(i, icon);
107 comboBox->setItemData(i, icon);
108 }
109 }
110 } else if (QTreeWidget *treeWidget = qobject_cast<QTreeWidget *>(object)) {
111 reloadTreeItem(iconCache, treeWidget->headerItem());
112 QQueue<QTreeWidgetItem *> itemsQueue;
113 for (int i = 0; i < treeWidget->topLevelItemCount(); i++)
114 itemsQueue.enqueue(treeWidget->topLevelItem(i));
115 while (!itemsQueue.isEmpty()) {
116 QTreeWidgetItem *item = itemsQueue.dequeue();
117 for (int i = 0; i < item->childCount(); i++)
118 itemsQueue.enqueue(item->child(i));
119 reloadTreeItem(iconCache, item);
120 }
121 } else if (QTableWidget *tableWidget = qobject_cast<QTableWidget *>(object)) {
122 const int columnCount = tableWidget->columnCount();
123 const int rowCount = tableWidget->rowCount();
124 for (int c = 0; c < columnCount; c++)
125 reloadTableItem(iconCache, tableWidget->horizontalHeaderItem(c));
126 for (int r = 0; r < rowCount; r++)
127 reloadTableItem(iconCache, tableWidget->verticalHeaderItem(r));
128 for (int c = 0; c < columnCount; c++)
129 for (int r = 0; r < rowCount; r++)
130 reloadTableItem(iconCache, tableWidget->item(r, c));
131 }
132 }
133
134 // ------------- DesignerMetaEnum
139
140
142 {
143 // find value
144 bool valueOk;
146 if (ok)
147 *ok = valueOk;
148
149 if (!valueOk)
150 return item;
151
154 return qualifiedItem;
155 }
156
158 {
159 return QCoreApplication::translate("DesignerMetaEnum",
160 "%1 is not a valid enumeration value of '%2'.")
161 .arg(value).arg(enumName());
162 }
163
165 {
166 return QCoreApplication::translate("DesignerMetaEnum",
167 "'%1' could not be converted to an enumeration value of type '%2'.")
168 .arg(s, enumName());
169 }
170 // -------------- DesignerMetaFlags
176
178 {
180 const uint v = static_cast<uint>(ivalue);
181 for (auto it = keyToValueMap().begin(), end = keyToValueMap().end(); it != end; ++it) {
182 const uint itemValue = it->second;
183 // Check for equality first as flag values can be 0 or -1, too. Takes preference over a bitwise flag
184 if (v == itemValue) {
185 rc.clear();
187 return rc;
188 }
189 // Do not add 0-flags (None-flags)
190 if (itemValue)
191 if ((v & itemValue) == itemValue)
193 }
194 return rc;
195 }
196
197
199 {
201 if (flagIds.isEmpty())
202 return QString();
203
204 QString rc;
205 for (const auto &id : flagIds) {
206 if (!rc.isEmpty())
207 rc += u'|';
209 }
210 return rc;
211 }
212
213
214 int DesignerMetaFlags::parseFlags(const QString &s, bool *ok) const
215 {
216 if (s.isEmpty()) {
217 if (ok)
218 *ok = true;
219 return 0;
220 }
221 uint flags = 0;
222 bool valueOk = true;
223 const auto keys = QStringView{s}.split(u'|');
224 for (const auto &key : keys) {
226 if (!valueOk) {
227 flags = 0;
228 break;
229 }
230 flags |= flagValue;
231 }
232 if (ok)
233 *ok = valueOk;
234 return static_cast<int>(flags);
235 }
236
238 {
239 return QCoreApplication::translate("DesignerMetaFlags",
240 "'%1' could not be converted to a flag value of type '%2'.")
241 .arg(s, enumName());
242 }
243
244 // ---------- PropertySheetEnumValue
245
251
253
254 // ---------------- PropertySheetFlagValue
260
262
263 // ---------------- PropertySheetPixmapValue
267
269
276
278 {
279 return m_path;
280 }
281
283 {
284 if (m_path == path)
285 return;
286 m_path = path;
287 }
288
289 // ---------- PropertySheetIconValue
290
297
303
308
310
313
316
317} // namespace qdesigner_internal
318
319namespace qdesigner_internal {
320
321 size_t qHash(const PropertySheetIconValue &p, size_t seed) noexcept
322 {
323 // qHash for paths making use of the existing QPair hash functions.
324 const auto *d = p.m_data.constData();
325 return qHashMulti(seed, d->m_paths, d->m_themeEnum, d->m_theme);
326 }
327
328 bool comparesEqual(const PropertySheetIconValue &lhs,
329 const PropertySheetIconValue &rhs) noexcept
330 {
331 const auto *lhsd = lhs.m_data.constData();
332 const auto *rhsd = rhs.m_data.constData();
333 return lhsd == rhsd
334 || (lhsd->m_themeEnum == rhsd->m_themeEnum
335 && lhsd->m_theme == rhsd->m_theme && lhsd->m_paths == rhsd->m_paths);
336 }
337
339 {
340 return m_data->m_themeEnum == -1 && m_data->m_theme.isEmpty()
341 && m_data->m_paths.isEmpty();
342 }
343
345 {
346 return m_data->m_theme;
347 }
348
350 {
351 m_data->m_theme = t;
352 }
353
355 {
356 return m_data->m_themeEnum;
357 }
358
360 {
362 }
363
369
378
380 {
381 const auto it = m_cache.constFind(value);
382 if (it != m_cache.constEnd())
383 return it.value();
384
387 return pix;
388 }
389
391 {
392 m_cache.clear();
393 }
394
399
401 {
402 const auto it = m_cache.constFind(value);
403 if (it != m_cache.constEnd())
404 return it.value();
405
406 // Match on the theme first if it is available.
407 if (value.themeEnum() != -1) {
408 const QIcon themeIcon = QIcon::fromTheme(static_cast<QIcon::ThemeIcon>(value.themeEnum()));
410 return themeIcon;
411 }
412 if (!value.theme().isEmpty()) {
413 const QString theme = value.theme();
414 if (QIcon::hasThemeIcon(theme)) {
417 return themeIcon;
418 }
419 }
420
421 QIcon icon;
423 for (auto it = paths.constBegin(), cend = paths.constEnd(); it != cend; ++it) {
424 const auto pair = it.key();
426 }
428 return icon;
429 }
430
432 {
433 m_cache.clear();
434 }
435
442
445
449
451 {
452 return m_value;
453 }
454
456 {
457 m_value = value;
458 }
459
467
469 {
470 return m_value;
471 }
472
477
479
480
485
490
492 {
493 return m_value;
494 }
495
501
506
512
517
518 /* IconSubPropertyMask: Assign each icon sub-property (pixmaps for the
519 * various states/modes and the theme) a flag bit (see QFont) so that they
520 * can be handled individually when assigning property values to
521 * multiselections in the set-property-commands (that is, do not clobber
522 * other subproperties when assigning just one).
523 * Provide back-and-forth mapping functions for the icon states. */
524
537
538 static inline uint iconStateToSubPropertyFlag(QIcon::Mode mode, QIcon::State state)
539 {
540 switch (mode) {
541 case QIcon::Disabled:
542 return state == QIcon::On ? DisabledOnIconMask : DisabledOffIconMask;
543 case QIcon::Active:
544 return state == QIcon::On ? ActiveOnIconMask : ActiveOffIconMask;
545 case QIcon::Selected:
546 return state == QIcon::On ? SelectedOnIconMask : SelectedOffIconMask;
547 case QIcon::Normal:
548 break;
549 }
550 return state == QIcon::On ? NormalOnIconMask : NormalOffIconMask;
551 }
552
553 static inline std::pair<QIcon::Mode, QIcon::State> subPropertyFlagToIconModeState(unsigned flag)
554 {
555 switch (flag) {
556 case NormalOnIconMask:
557 return {QIcon::Normal, QIcon::On};
558 case DisabledOffIconMask:
559 return {QIcon::Disabled, QIcon::Off};
560 case DisabledOnIconMask:
561 return {QIcon::Disabled, QIcon::On};
562 case ActiveOffIconMask:
563 return {QIcon::Active, QIcon::Off};
564 case ActiveOnIconMask:
565 return {QIcon::Active, QIcon::On};
566 case SelectedOffIconMask:
567 return {QIcon::Selected, QIcon::Off};
568 case SelectedOnIconMask:
569 return {QIcon::Selected, QIcon::On};
571 default:
572 break;
573 }
574 return {QIcon::Normal, QIcon::Off};
575 }
576
578 {
579 uint flags = 0;
580 for (auto it = m_data->m_paths.constBegin(), cend = m_data->m_paths.constEnd(); it != cend; ++it)
582 if (!m_data->m_theme.isEmpty())
584 if (m_data->m_themeEnum != -1)
586 return flags;
587 }
588
590 {
591 uint diffMask = mask() | other.mask();
592 for (int i = 0; i < 8; i++) {
593 const uint flag = 1 << i;
594 if (diffMask & flag) { // if state is set in both icons, compare the values
597 diffMask &= ~flag;
598 }
599 }
600 if ((diffMask & ThemeIconMask) && theme() == other.theme())
604
605 return diffMask;
606 }
607
614
622
624 {
625 for (int i = 0; i < 8; i++) {
626 uint flag = 1 << i;
627 if (mask & flag) {
630 }
631 }
632 if (mask & ThemeIconMask)
636 }
637
642
644 {
646 debug.nospace();
647 debug.noquote();
648 debug << "PropertySheetIconValue(mask=0x" << Qt::hex << p.mask() << Qt::dec << ", ";
649 if (p.themeEnum() != -1)
650 debug << "theme=" << p.themeEnum() << ", ";
651 if (!p.theme().isEmpty())
652 debug << "XDG theme=\"" << p.theme() << "\", ";
653
655 for (auto it = paths.constBegin(), cend = paths.constEnd(); it != cend; ++it) {
656 debug << " mode=" << it.key().first << ",state=" << it.key().second
657 << ", \"" << it.value().path() << '"';
658 }
659 debug << ')';
660 return debug;
661 }
662
674
676 {
677 QAction *action = nullptr;
680 if (!action) {
681 const auto actions = taskMenu->taskActions();
682 if (!actions.isEmpty())
683 action = actions.first();
684 }
685 }
686 if (!action) {
688 core->extensionManager()->extension(managedWidget, u"QDesignerInternalTaskMenuExtension"_s))) {
690 if (!action) {
691 const auto actions = taskMenu->taskActions();
692 if (!actions.isEmpty())
693 action = actions.first();
694 }
695 }
696 }
697 return action;
698 }
699
700 QDESIGNER_SHARED_EXPORT bool runUIC(const QString &fileName, UicLanguage language,
701 QByteArray& ba, QString &errorMessage)
702 {
703 QProcess uic;
704 QStringList arguments;
705 static constexpr auto uicBinary =
706 QOperatingSystemVersion::currentType() != QOperatingSystemVersion::Windows
707 ? "/uic"_L1 : "/uic.exe"_L1;
708 QString binary = QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath) + uicBinary;
709 // In a PySide6 installation, there is no libexec directory; uic.exe is
710 // in the main wheel directory next to designer.exe.
711 if (!QFileInfo::exists(binary))
712 binary = QCoreApplication::applicationDirPath() + uicBinary;
713 if (!QFileInfo::exists(binary)) {
714 errorMessage = QApplication::translate("Designer", "%1 does not exist.").
715 arg(QDir::toNativeSeparators(binary));
716 return false;
717 }
718
719 switch (language) {
720 case UicLanguage::Cpp:
721 break;
722 case UicLanguage::Python:
723 arguments << u"-g"_s << u"python"_s;
724 break;
725 }
726 arguments << fileName;
727
728 uic.start(binary, arguments);
729 if (!uic.waitForStarted()) {
730 errorMessage = QApplication::translate("Designer", "Unable to launch %1: %2").
731 arg(QDir::toNativeSeparators(binary), uic.errorString());
732 return false;
733 }
734 if (!uic.waitForFinished()) {
735 errorMessage = QApplication::translate("Designer", "%1 timed out.").arg(binary);
736 return false;
737 }
738 if (uic.exitCode()) {
739 errorMessage = QString::fromLatin1(uic.readAllStandardError());
740 return false;
741 }
742 ba = uic.readAllStandardOutput();
743 return true;
744 }
745
747 {
749
750 Q_ASSERT(qname.isEmpty() == false);
751
752
753 if (qname.size() > 1 && qname.at(1).isUpper()) {
754 const QChar first = qname.at(0);
755 if (first == u'Q' || first == u'K')
756 qname.remove(0, 1);
757 }
758
759 const qsizetype len = qname.size();
760 for (qsizetype i = 0; i < len && qname.at(i).isUpper(); ++i)
761 qname[i] = qname.at(i).toLower();
762
763 return qname;
764 }
765
766 // --------------- UpdateBlocker
774
776 {
777 if (m_enabled)
779 }
780
781// from qpalette.cpp
782quint64 paletteResolveMask(QPalette::ColorGroup colorGroup,
783 QPalette::ColorRole colorRole)
784{
785 if (colorRole == QPalette::Accent)
786 colorRole = QPalette::NoRole; // See qtbase/17c589df94a2245ee92d45839c2cba73566d7310
787 const auto offset = quint64(QPalette::NColorRoles - 1) * quint64(colorGroup);
788 const auto bitPos = quint64(colorRole) + offset;
789 return 1ull << bitPos;
790}
791
792quint64 paletteResolveMask(QPalette::ColorRole colorRole)
793{
794 return paletteResolveMask(QPalette::Active, colorRole)
795 | paletteResolveMask(QPalette::Inactive, colorRole)
796 | paletteResolveMask(QPalette::Disabled, colorRole);
797}
798
799} // namespace qdesigner_internal
800
801QT_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)
QDESIGNER_SHARED_EXPORT QDebug operator<<(QDebug, const PropertySheetIconValue &)
void reloadTreeItem(DesignerIconCache *iconCache, QTreeWidgetItem *item)
bool comparesEqual(const DeviceProfile &lhs, const DeviceProfile &rhs) noexcept
#define QDESIGNER_SHARED_EXPORT