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 | |
4 | #include "qdesigner_utils_p.h" |
5 | #include "qdesigner_propertycommand_p.h" |
6 | #include "abstractformbuilder.h" |
7 | #include "formwindowbase_p.h" |
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/qdir.h> |
17 | #include <QtCore/qprocess.h> |
18 | #include <QtCore/qlibraryinfo.h> |
19 | #include <QtCore/qdebug.h> |
20 | #include <QtCore/qqueue.h> |
21 | #include <QtCore/qshareddata.h> |
22 | #include <QtCore/qstandardpaths.h> |
23 | |
24 | #include <QtWidgets/qapplication.h> |
25 | #include <QtGui/qicon.h> |
26 | #include <QtGui/qpalette.h> |
27 | #include <QtGui/qpixmap.h> |
28 | #include <QtWidgets/qlistwidget.h> |
29 | #include <QtWidgets/qtreewidget.h> |
30 | #include <QtWidgets/qtablewidget.h> |
31 | #include <QtWidgets/qcombobox.h> |
32 | |
33 | QT_BEGIN_NAMESPACE |
34 | |
35 | using namespace Qt::StringLiterals; |
36 | |
37 | namespace qdesigner_internal |
38 | { |
39 | // ### FIXME Qt 8: Remove (QTBUG-96005) |
40 | QString legacyDataDirectory() |
41 | { |
42 | return QDir::homePath() + u"/.designer"_s ; |
43 | } |
44 | |
45 | QString dataDirectory() |
46 | { |
47 | #if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) |
48 | return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) |
49 | + u'/' + QCoreApplication::organizationName() + u"/Designer"_s ; |
50 | #else |
51 | return legacyDataDirectory(); |
52 | #endif |
53 | } |
54 | |
55 | |
56 | QDESIGNER_SHARED_EXPORT void designerWarning(const QString &message) |
57 | { |
58 | qWarning(msg: "Designer: %s" , qPrintable(message)); |
59 | } |
60 | |
61 | void reloadTreeItem(DesignerIconCache *iconCache, QTreeWidgetItem *item) |
62 | { |
63 | if (!item) |
64 | return; |
65 | |
66 | for (int c = 0; c < item->columnCount(); c++) { |
67 | const QVariant v = item->data(column: c, role: Qt::DecorationPropertyRole); |
68 | if (v.canConvert<PropertySheetIconValue>()) |
69 | item->setIcon(column: c, aicon: iconCache->icon(value: qvariant_cast<PropertySheetIconValue>(v))); |
70 | } |
71 | } |
72 | |
73 | void reloadListItem(DesignerIconCache *iconCache, QListWidgetItem *item) |
74 | { |
75 | if (!item) |
76 | return; |
77 | |
78 | const QVariant v = item->data(role: Qt::DecorationPropertyRole); |
79 | if (v.canConvert<PropertySheetIconValue>()) |
80 | item->setIcon(iconCache->icon(value: qvariant_cast<PropertySheetIconValue>(v))); |
81 | } |
82 | |
83 | void reloadTableItem(DesignerIconCache *iconCache, QTableWidgetItem *item) |
84 | { |
85 | if (!item) |
86 | return; |
87 | |
88 | const QVariant v = item->data(role: Qt::DecorationPropertyRole); |
89 | if (v.canConvert<PropertySheetIconValue>()) |
90 | item->setIcon(iconCache->icon(value: qvariant_cast<PropertySheetIconValue>(v))); |
91 | } |
92 | |
93 | void reloadIconResources(DesignerIconCache *iconCache, QObject *object) |
94 | { |
95 | if (QListWidget *listWidget = qobject_cast<QListWidget *>(object)) { |
96 | for (int i = 0; i < listWidget->count(); i++) |
97 | reloadListItem(iconCache, item: listWidget->item(row: i)); |
98 | } else if (QComboBox *comboBox = qobject_cast<QComboBox *>(object)) { |
99 | for (int i = 0; i < comboBox->count(); i++) { |
100 | const QVariant v = comboBox->itemData(index: i, role: Qt::DecorationPropertyRole); |
101 | if (v.canConvert<PropertySheetIconValue>()) { |
102 | QIcon icon = iconCache->icon(value: qvariant_cast<PropertySheetIconValue>(v)); |
103 | comboBox->setItemIcon(index: i, icon); |
104 | comboBox->setItemData(index: i, value: icon); |
105 | } |
106 | } |
107 | } else if (QTreeWidget *treeWidget = qobject_cast<QTreeWidget *>(object)) { |
108 | reloadTreeItem(iconCache, item: treeWidget->headerItem()); |
109 | QQueue<QTreeWidgetItem *> itemsQueue; |
110 | for (int i = 0; i < treeWidget->topLevelItemCount(); i++) |
111 | itemsQueue.enqueue(t: treeWidget->topLevelItem(index: i)); |
112 | while (!itemsQueue.isEmpty()) { |
113 | QTreeWidgetItem *item = itemsQueue.dequeue(); |
114 | for (int i = 0; i < item->childCount(); i++) |
115 | itemsQueue.enqueue(t: item->child(index: i)); |
116 | reloadTreeItem(iconCache, item); |
117 | } |
118 | } else if (QTableWidget *tableWidget = qobject_cast<QTableWidget *>(object)) { |
119 | const int columnCount = tableWidget->columnCount(); |
120 | const int rowCount = tableWidget->rowCount(); |
121 | for (int c = 0; c < columnCount; c++) |
122 | reloadTableItem(iconCache, item: tableWidget->horizontalHeaderItem(column: c)); |
123 | for (int r = 0; r < rowCount; r++) |
124 | reloadTableItem(iconCache, item: tableWidget->verticalHeaderItem(row: r)); |
125 | for (int c = 0; c < columnCount; c++) |
126 | for (int r = 0; r < rowCount; r++) |
127 | reloadTableItem(iconCache, item: tableWidget->item(row: r, column: c)); |
128 | } |
129 | } |
130 | |
131 | // ------------- DesignerMetaEnum |
132 | DesignerMetaEnum::DesignerMetaEnum(const QString &name, const QString &scope, const QString &separator) : |
133 | MetaEnum<int>(name, scope, separator) |
134 | { |
135 | } |
136 | |
137 | |
138 | QString DesignerMetaEnum::toString(int value, SerializationMode sm, bool *ok) const |
139 | { |
140 | // find value |
141 | bool valueOk; |
142 | const QString item = valueToKey(value, ok: &valueOk); |
143 | if (ok) |
144 | *ok = valueOk; |
145 | |
146 | if (!valueOk || sm == NameOnly) |
147 | return item; |
148 | |
149 | QString qualifiedItem; |
150 | appendQualifiedName(key: item, target&: qualifiedItem); |
151 | return qualifiedItem; |
152 | } |
153 | |
154 | QString DesignerMetaEnum::messageToStringFailed(int value) const |
155 | { |
156 | return QCoreApplication::translate(context: "DesignerMetaEnum" , |
157 | key: "%1 is not a valid enumeration value of '%2'." ) |
158 | .arg(a: value).arg(a: name()); |
159 | } |
160 | |
161 | QString DesignerMetaEnum::messageParseFailed(const QString &s) const |
162 | { |
163 | return QCoreApplication::translate(context: "DesignerMetaEnum" , |
164 | key: "'%1' could not be converted to an enumeration value of type '%2'." ) |
165 | .arg(args: s, args: name()); |
166 | } |
167 | // -------------- DesignerMetaFlags |
168 | DesignerMetaFlags::DesignerMetaFlags(const QString &name, const QString &scope, const QString &separator) : |
169 | MetaEnum<uint>(name, scope, separator) |
170 | { |
171 | } |
172 | |
173 | QStringList DesignerMetaFlags::flags(int ivalue) const |
174 | { |
175 | QStringList rc; |
176 | const uint v = static_cast<uint>(ivalue); |
177 | for (auto it = keyToValueMap().constBegin(), cend = keyToValueMap().constEnd(); it != cend; ++it ) { |
178 | const uint itemValue = it.value(); |
179 | // Check for equality first as flag values can be 0 or -1, too. Takes preference over a bitwise flag |
180 | if (v == itemValue) { |
181 | rc.clear(); |
182 | rc.push_back(t: it.key()); |
183 | return rc; |
184 | } |
185 | // Do not add 0-flags (None-flags) |
186 | if (itemValue) |
187 | if ((v & itemValue) == itemValue) |
188 | rc.push_back(t: it.key()); |
189 | } |
190 | return rc; |
191 | } |
192 | |
193 | |
194 | QString DesignerMetaFlags::toString(int value, SerializationMode sm) const |
195 | { |
196 | const QStringList flagIds = flags(ivalue: value); |
197 | if (flagIds.isEmpty()) |
198 | return QString(); |
199 | |
200 | QString rc; |
201 | for (const auto &id : flagIds) { |
202 | if (!rc.isEmpty()) |
203 | rc += u'|'; |
204 | if (sm == FullyQualified) |
205 | appendQualifiedName(key: id, target&: rc); |
206 | else |
207 | rc += id; |
208 | } |
209 | return rc; |
210 | } |
211 | |
212 | |
213 | int DesignerMetaFlags::parseFlags(const QString &s, bool *ok) const |
214 | { |
215 | if (s.isEmpty()) { |
216 | if (ok) |
217 | *ok = true; |
218 | return 0; |
219 | } |
220 | uint flags = 0; |
221 | bool valueOk = true; |
222 | const QStringList keys = s.split(sep: u'|'); |
223 | for (const QString &key : keys) { |
224 | const uint flagValue = keyToValue(key, ok: &valueOk); |
225 | if (!valueOk) { |
226 | flags = 0; |
227 | break; |
228 | } |
229 | flags |= flagValue; |
230 | } |
231 | if (ok) |
232 | *ok = valueOk; |
233 | return static_cast<int>(flags); |
234 | } |
235 | |
236 | QString DesignerMetaFlags::messageParseFailed(const QString &s) const |
237 | { |
238 | return QCoreApplication::translate(context: "DesignerMetaFlags" , |
239 | key: "'%1' could not be converted to a flag value of type '%2'." ) |
240 | .arg(args: s, args: name()); |
241 | } |
242 | |
243 | // ---------- PropertySheetEnumValue |
244 | |
245 | PropertySheetEnumValue::PropertySheetEnumValue(int v, const DesignerMetaEnum &me) : |
246 | value(v), |
247 | metaEnum(me) |
248 | { |
249 | } |
250 | |
251 | PropertySheetEnumValue::PropertySheetEnumValue() = default; |
252 | |
253 | // ---------------- PropertySheetFlagValue |
254 | PropertySheetFlagValue::PropertySheetFlagValue(int v, const DesignerMetaFlags &mf) : |
255 | value(v), |
256 | metaFlags(mf) |
257 | { |
258 | } |
259 | |
260 | PropertySheetFlagValue::PropertySheetFlagValue() = default; |
261 | |
262 | // ---------------- PropertySheetPixmapValue |
263 | PropertySheetPixmapValue::PropertySheetPixmapValue(const QString &path) : m_path(path) |
264 | { |
265 | } |
266 | |
267 | PropertySheetPixmapValue::PropertySheetPixmapValue() = default; |
268 | |
269 | PropertySheetPixmapValue::PixmapSource PropertySheetPixmapValue::getPixmapSource(QDesignerFormEditorInterface *core, const QString & path) |
270 | { |
271 | if (const QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension *>(manager: core->extensionManager(), object: core)) |
272 | return lang->isLanguageResource(path) ? LanguageResourcePixmap : FilePixmap; |
273 | return path.startsWith(c: u':') ? ResourcePixmap : FilePixmap; |
274 | } |
275 | |
276 | int PropertySheetPixmapValue::compare(const PropertySheetPixmapValue &other) const |
277 | { |
278 | return m_path.compare(s: other.m_path); |
279 | } |
280 | |
281 | QString PropertySheetPixmapValue::path() const |
282 | { |
283 | return m_path; |
284 | } |
285 | |
286 | void PropertySheetPixmapValue::setPath(const QString &path) |
287 | { |
288 | if (m_path == path) |
289 | return; |
290 | m_path = path; |
291 | } |
292 | |
293 | // ---------- PropertySheetIconValue |
294 | |
295 | class PropertySheetIconValueData : public QSharedData { |
296 | public: |
297 | PropertySheetIconValue::ModeStateToPixmapMap m_paths; |
298 | QString m_theme; |
299 | }; |
300 | |
301 | PropertySheetIconValue::PropertySheetIconValue(const PropertySheetPixmapValue &pixmap) : |
302 | m_data(new PropertySheetIconValueData) |
303 | { |
304 | setPixmap(mode: QIcon::Normal, state: QIcon::Off, path: pixmap); |
305 | } |
306 | |
307 | PropertySheetIconValue::PropertySheetIconValue() : |
308 | m_data(new PropertySheetIconValueData) |
309 | { |
310 | } |
311 | |
312 | PropertySheetIconValue::~PropertySheetIconValue() = default; |
313 | |
314 | PropertySheetIconValue::PropertySheetIconValue(const PropertySheetIconValue &rhs) : |
315 | m_data(rhs.m_data) |
316 | { |
317 | } |
318 | |
319 | PropertySheetIconValue &PropertySheetIconValue::operator=(const PropertySheetIconValue &rhs) |
320 | { |
321 | if (this != &rhs) |
322 | m_data.operator=(o: rhs.m_data); |
323 | return *this; |
324 | } |
325 | |
326 | bool PropertySheetIconValue::equals(const PropertySheetIconValue &rhs) const |
327 | { |
328 | return m_data->m_theme == rhs.m_data->m_theme && m_data->m_paths == rhs.m_data->m_paths; |
329 | } |
330 | |
331 | bool PropertySheetIconValue::operator<(const PropertySheetIconValue &other) const |
332 | { |
333 | if (const int themeCmp = m_data->m_theme.compare(s: other.m_data->m_theme)) |
334 | return themeCmp < 0; |
335 | auto itThis = m_data->m_paths.cbegin(); |
336 | auto itThisEnd = m_data->m_paths.cend(); |
337 | auto itOther = other.m_data->m_paths.cbegin(); |
338 | auto itOtherEnd = other.m_data->m_paths.cend(); |
339 | while (itThis != itThisEnd && itOther != itOtherEnd) { |
340 | const ModeStateKey thisPair = itThis.key(); |
341 | const ModeStateKey otherPair = itOther.key(); |
342 | if (thisPair < otherPair) |
343 | return true; |
344 | if (otherPair < thisPair) |
345 | return false; |
346 | const int crc = itThis.value().compare(other: itOther.value()); |
347 | if (crc < 0) |
348 | return true; |
349 | if (crc > 0) |
350 | return false; |
351 | ++itThis; |
352 | ++itOther; |
353 | } |
354 | return itOther != itOtherEnd; |
355 | } |
356 | |
357 | bool PropertySheetIconValue::isEmpty() const |
358 | { |
359 | return m_data->m_theme.isEmpty() && m_data->m_paths.isEmpty(); |
360 | } |
361 | |
362 | QString PropertySheetIconValue::theme() const |
363 | { |
364 | return m_data->m_theme; |
365 | } |
366 | |
367 | void PropertySheetIconValue::setTheme(const QString &t) |
368 | { |
369 | m_data->m_theme = t; |
370 | } |
371 | |
372 | PropertySheetPixmapValue PropertySheetIconValue::pixmap(QIcon::Mode mode, QIcon::State state) const |
373 | { |
374 | const ModeStateKey pair = qMakePair(value1&: mode, value2&: state); |
375 | return m_data->m_paths.value(key: pair); |
376 | } |
377 | |
378 | void PropertySheetIconValue::setPixmap(QIcon::Mode mode, QIcon::State state, const PropertySheetPixmapValue &pixmap) |
379 | { |
380 | const ModeStateKey pair = qMakePair(value1&: mode, value2&: state); |
381 | if (pixmap.path().isEmpty()) |
382 | m_data->m_paths.remove(key: pair); |
383 | else |
384 | m_data->m_paths.insert(key: pair, value: pixmap); |
385 | } |
386 | |
387 | QPixmap DesignerPixmapCache::pixmap(const PropertySheetPixmapValue &value) const |
388 | { |
389 | const auto it = m_cache.constFind(key: value); |
390 | if (it != m_cache.constEnd()) |
391 | return it.value(); |
392 | |
393 | QPixmap pix = QPixmap(value.path()); |
394 | m_cache.insert(key: value, value: pix); |
395 | return pix; |
396 | } |
397 | |
398 | void DesignerPixmapCache::clear() |
399 | { |
400 | m_cache.clear(); |
401 | } |
402 | |
403 | DesignerPixmapCache::DesignerPixmapCache(QObject *parent) |
404 | : QObject(parent) |
405 | { |
406 | } |
407 | |
408 | QIcon DesignerIconCache::icon(const PropertySheetIconValue &value) const |
409 | { |
410 | const auto it = m_cache.constFind(key: value); |
411 | if (it != m_cache.constEnd()) |
412 | return it.value(); |
413 | |
414 | // Match on the theme first if it is available. |
415 | if (!value.theme().isEmpty()) { |
416 | const QString theme = value.theme(); |
417 | if (QIcon::hasThemeIcon(name: theme)) { |
418 | const QIcon themeIcon = QIcon::fromTheme(name: theme); |
419 | m_cache.insert(key: value, value: themeIcon); |
420 | return themeIcon; |
421 | } |
422 | } |
423 | |
424 | QIcon icon; |
425 | const PropertySheetIconValue::ModeStateToPixmapMap &paths = value.paths(); |
426 | for (auto it = paths.constBegin(), cend = paths.constEnd(); it != cend; ++it) { |
427 | const auto pair = it.key(); |
428 | icon.addFile(fileName: it.value().path(), size: QSize(), mode: pair.first, state: pair.second); |
429 | } |
430 | m_cache.insert(key: value, value: icon); |
431 | return icon; |
432 | } |
433 | |
434 | void DesignerIconCache::clear() |
435 | { |
436 | m_cache.clear(); |
437 | } |
438 | |
439 | DesignerIconCache::DesignerIconCache(DesignerPixmapCache *pixmapCache, QObject *parent) |
440 | : QObject(parent), |
441 | m_pixmapCache(pixmapCache) |
442 | { |
443 | |
444 | } |
445 | |
446 | PropertySheetTranslatableData::PropertySheetTranslatableData(bool translatable, const QString &disambiguation, const QString &) : |
447 | m_translatable(translatable), m_disambiguation(disambiguation), m_comment(comment) { } |
448 | |
449 | bool PropertySheetTranslatableData::equals(const PropertySheetTranslatableData &rhs) const |
450 | { |
451 | return m_translatable == rhs.m_translatable |
452 | && m_disambiguation == rhs.m_disambiguation |
453 | && m_comment == rhs.m_comment |
454 | && m_id == rhs.m_id; |
455 | } |
456 | |
457 | PropertySheetStringValue::PropertySheetStringValue(const QString &value, |
458 | bool translatable, const QString &disambiguation, const QString &) : |
459 | PropertySheetTranslatableData(translatable, disambiguation, comment), m_value(value) {} |
460 | |
461 | QString PropertySheetStringValue::value() const |
462 | { |
463 | return m_value; |
464 | } |
465 | |
466 | void PropertySheetStringValue::setValue(const QString &value) |
467 | { |
468 | m_value = value; |
469 | } |
470 | |
471 | bool PropertySheetStringValue::equals(const PropertySheetStringValue &rhs) const |
472 | { |
473 | return m_value == rhs.m_value && PropertySheetTranslatableData::equals(rhs); |
474 | } |
475 | |
476 | PropertySheetStringListValue::PropertySheetStringListValue(const QStringList &value, |
477 | bool translatable, |
478 | const QString &disambiguation, |
479 | const QString &) : |
480 | PropertySheetTranslatableData(translatable, disambiguation, comment), m_value(value) |
481 | { |
482 | } |
483 | |
484 | QStringList PropertySheetStringListValue::value() const |
485 | { |
486 | return m_value; |
487 | } |
488 | |
489 | void PropertySheetStringListValue::setValue(const QStringList &value) |
490 | { |
491 | m_value = value; |
492 | } |
493 | |
494 | bool PropertySheetStringListValue::equals(const PropertySheetStringListValue &rhs) const |
495 | { |
496 | return m_value == rhs.m_value && PropertySheetTranslatableData::equals(rhs); |
497 | } |
498 | |
499 | QStringList m_value; |
500 | |
501 | |
502 | PropertySheetKeySequenceValue::PropertySheetKeySequenceValue(const QKeySequence &value, |
503 | bool translatable, const QString &disambiguation, const QString &) |
504 | : PropertySheetTranslatableData(translatable, disambiguation, comment), |
505 | m_value(value), m_standardKey(QKeySequence::UnknownKey) {} |
506 | |
507 | PropertySheetKeySequenceValue::PropertySheetKeySequenceValue(const QKeySequence::StandardKey &standardKey, |
508 | bool translatable, const QString &disambiguation, const QString &) |
509 | : PropertySheetTranslatableData(translatable, disambiguation, comment), |
510 | m_value(QKeySequence(standardKey)), m_standardKey(standardKey) {} |
511 | |
512 | QKeySequence PropertySheetKeySequenceValue::value() const |
513 | { |
514 | return m_value; |
515 | } |
516 | |
517 | void PropertySheetKeySequenceValue::setValue(const QKeySequence &value) |
518 | { |
519 | m_value = value; |
520 | m_standardKey = QKeySequence::UnknownKey; |
521 | } |
522 | |
523 | QKeySequence::StandardKey PropertySheetKeySequenceValue::standardKey() const |
524 | { |
525 | return m_standardKey; |
526 | } |
527 | |
528 | void PropertySheetKeySequenceValue::setStandardKey(const QKeySequence::StandardKey &standardKey) |
529 | { |
530 | m_value = QKeySequence(standardKey); |
531 | m_standardKey = standardKey; |
532 | } |
533 | |
534 | bool PropertySheetKeySequenceValue::isStandardKey() const |
535 | { |
536 | return m_standardKey != QKeySequence::UnknownKey; |
537 | } |
538 | |
539 | bool PropertySheetKeySequenceValue::equals(const PropertySheetKeySequenceValue &rhs) const |
540 | { |
541 | return m_value == rhs.m_value && m_standardKey == rhs.m_standardKey |
542 | && PropertySheetTranslatableData::equals(rhs); |
543 | } |
544 | |
545 | /* IconSubPropertyMask: Assign each icon sub-property (pixmaps for the |
546 | * various states/modes and the theme) a flag bit (see QFont) so that they |
547 | * can be handled individually when assigning property values to |
548 | * multiselections in the set-property-commands (that is, do not clobber |
549 | * other subproperties when assigning just one). |
550 | * Provide back-and-forth mapping functions for the icon states. */ |
551 | |
552 | enum IconSubPropertyMask { |
553 | NormalOffIconMask = 0x01, |
554 | NormalOnIconMask = 0x02, |
555 | DisabledOffIconMask = 0x04, |
556 | DisabledOnIconMask = 0x08, |
557 | ActiveOffIconMask = 0x10, |
558 | ActiveOnIconMask = 0x20, |
559 | SelectedOffIconMask = 0x40, |
560 | SelectedOnIconMask = 0x80, |
561 | ThemeIconMask = 0x10000 |
562 | }; |
563 | |
564 | static inline uint iconStateToSubPropertyFlag(QIcon::Mode mode, QIcon::State state) |
565 | { |
566 | switch (mode) { |
567 | case QIcon::Disabled: |
568 | return state == QIcon::On ? DisabledOnIconMask : DisabledOffIconMask; |
569 | case QIcon::Active: |
570 | return state == QIcon::On ? ActiveOnIconMask : ActiveOffIconMask; |
571 | case QIcon::Selected: |
572 | return state == QIcon::On ? SelectedOnIconMask : SelectedOffIconMask; |
573 | case QIcon::Normal: |
574 | break; |
575 | } |
576 | return state == QIcon::On ? NormalOnIconMask : NormalOffIconMask; |
577 | } |
578 | |
579 | static inline QPair<QIcon::Mode, QIcon::State> subPropertyFlagToIconModeState(unsigned flag) |
580 | { |
581 | switch (flag) { |
582 | case NormalOnIconMask: |
583 | return qMakePair(value1: QIcon::Normal, value2: QIcon::On); |
584 | case DisabledOffIconMask: |
585 | return qMakePair(value1: QIcon::Disabled, value2: QIcon::Off); |
586 | case DisabledOnIconMask: |
587 | return qMakePair(value1: QIcon::Disabled, value2: QIcon::On); |
588 | case ActiveOffIconMask: |
589 | return qMakePair(value1: QIcon::Active, value2: QIcon::Off); |
590 | case ActiveOnIconMask: |
591 | return qMakePair(value1: QIcon::Active, value2: QIcon::On); |
592 | case SelectedOffIconMask: |
593 | return qMakePair(value1: QIcon::Selected, value2: QIcon::Off); |
594 | case SelectedOnIconMask: |
595 | return qMakePair(value1: QIcon::Selected, value2: QIcon::On); |
596 | case NormalOffIconMask: |
597 | default: |
598 | break; |
599 | } |
600 | return qMakePair(value1: QIcon::Normal, value2: QIcon::Off); |
601 | } |
602 | |
603 | uint PropertySheetIconValue::mask() const |
604 | { |
605 | uint flags = 0; |
606 | for (auto it = m_data->m_paths.constBegin(), cend = m_data->m_paths.constEnd(); it != cend; ++it) |
607 | flags |= iconStateToSubPropertyFlag(mode: it.key().first, state: it.key().second); |
608 | if (!m_data->m_theme.isEmpty()) |
609 | flags |= ThemeIconMask; |
610 | return flags; |
611 | } |
612 | |
613 | uint PropertySheetIconValue::compare(const PropertySheetIconValue &other) const |
614 | { |
615 | uint diffMask = mask() | other.mask(); |
616 | for (int i = 0; i < 8; i++) { |
617 | const uint flag = 1 << i; |
618 | if (diffMask & flag) { // if state is set in both icons, compare the values |
619 | const QPair<QIcon::Mode, QIcon::State> state = subPropertyFlagToIconModeState(flag); |
620 | if (pixmap(mode: state.first, state: state.second) == other.pixmap(mode: state.first, state: state.second)) |
621 | diffMask &= ~flag; |
622 | } |
623 | } |
624 | if ((diffMask & ThemeIconMask) && theme() == other.theme()) |
625 | diffMask &= ~ThemeIconMask; |
626 | return diffMask; |
627 | } |
628 | |
629 | PropertySheetIconValue PropertySheetIconValue::themed() const |
630 | { |
631 | PropertySheetIconValue rc(*this); |
632 | rc.m_data->m_paths.clear(); |
633 | return rc; |
634 | } |
635 | |
636 | PropertySheetIconValue PropertySheetIconValue::unthemed() const |
637 | { |
638 | PropertySheetIconValue rc(*this); |
639 | rc.m_data->m_theme.clear(); |
640 | return rc; |
641 | } |
642 | |
643 | void PropertySheetIconValue::assign(const PropertySheetIconValue &other, uint mask) |
644 | { |
645 | for (int i = 0; i < 8; i++) { |
646 | uint flag = 1 << i; |
647 | if (mask & flag) { |
648 | const ModeStateKey state = subPropertyFlagToIconModeState(flag); |
649 | setPixmap(mode: state.first, state: state.second, pixmap: other.pixmap(mode: state.first, state: state.second)); |
650 | } |
651 | } |
652 | if (mask & ThemeIconMask) |
653 | setTheme(other.theme()); |
654 | } |
655 | |
656 | const PropertySheetIconValue::ModeStateToPixmapMap &PropertySheetIconValue::paths() const |
657 | { |
658 | return m_data->m_paths; |
659 | } |
660 | |
661 | QDESIGNER_SHARED_EXPORT QDebug operator<<(QDebug d, const PropertySheetIconValue &p) |
662 | { |
663 | QDebug nospace = d.nospace(); |
664 | nospace << "PropertySheetIconValue theme='" << p.theme() << "' " ; |
665 | |
666 | const PropertySheetIconValue::ModeStateToPixmapMap &paths = p.paths(); |
667 | for (auto it = paths.constBegin(), cend = paths.constEnd(); it != cend; ++it) |
668 | nospace << " mode=" << it.key().first << ",state=" << it.key().second |
669 | << ",'" << it.value().path() << '\''; |
670 | nospace << " mask=0x" << QString::number(p.mask(), base: 16); |
671 | return d; |
672 | } |
673 | |
674 | QDESIGNER_SHARED_EXPORT QDesignerFormWindowCommand *createTextPropertyCommand(const QString &propertyName, const QString &text, QObject *object, QDesignerFormWindowInterface *fw) |
675 | { |
676 | if (text.isEmpty()) { |
677 | ResetPropertyCommand *cmd = new ResetPropertyCommand(fw); |
678 | cmd->init(object, propertyName); |
679 | return cmd; |
680 | } |
681 | SetPropertyCommand *cmd = new SetPropertyCommand(fw); |
682 | cmd->init(object, propertyName, newValue: text); |
683 | return cmd; |
684 | } |
685 | |
686 | QDESIGNER_SHARED_EXPORT QAction *preferredEditAction(QDesignerFormEditorInterface *core, QWidget *managedWidget) |
687 | { |
688 | QAction *action = nullptr; |
689 | if (const QDesignerTaskMenuExtension * = qt_extension<QDesignerTaskMenuExtension*>(manager: core->extensionManager(), object: managedWidget)) { |
690 | action = taskMenu->preferredEditAction(); |
691 | if (!action) { |
692 | const auto actions = taskMenu->taskActions(); |
693 | if (!actions.isEmpty()) |
694 | action = actions.first(); |
695 | } |
696 | } |
697 | if (!action) { |
698 | if (const auto * = qobject_cast<QDesignerTaskMenuExtension *>( |
699 | object: core->extensionManager()->extension(object: managedWidget, iid: u"QDesignerInternalTaskMenuExtension"_s ))) { |
700 | action = taskMenu->preferredEditAction(); |
701 | if (!action) { |
702 | const auto actions = taskMenu->taskActions(); |
703 | if (!actions.isEmpty()) |
704 | action = actions.first(); |
705 | } |
706 | } |
707 | } |
708 | return action; |
709 | } |
710 | |
711 | QDESIGNER_SHARED_EXPORT bool runUIC(const QString &fileName, UicLanguage language, |
712 | QByteArray& ba, QString &errorMessage) |
713 | { |
714 | QProcess uic; |
715 | QStringList arguments; |
716 | QString binary = QLibraryInfo::path(p: QLibraryInfo::LibraryExecutablesPath) + "/uic"_L1 ; |
717 | switch (language) { |
718 | case UicLanguage::Cpp: |
719 | break; |
720 | case UicLanguage::Python: |
721 | arguments << u"-g"_s << u"python"_s ; |
722 | break; |
723 | } |
724 | arguments << fileName; |
725 | |
726 | uic.start(program: binary, arguments); |
727 | if (!uic.waitForStarted()) { |
728 | errorMessage = QApplication::translate(context: "Designer" , key: "Unable to launch %1: %2" ). |
729 | arg(args: QDir::toNativeSeparators(pathName: binary), args: uic.errorString()); |
730 | return false; |
731 | } |
732 | if (!uic.waitForFinished()) { |
733 | errorMessage = QApplication::translate(context: "Designer" , key: "%1 timed out." ).arg(a: binary); |
734 | return false; |
735 | } |
736 | if (uic.exitCode()) { |
737 | errorMessage = QString::fromLatin1(ba: uic.readAllStandardError()); |
738 | return false; |
739 | } |
740 | ba = uic.readAllStandardOutput(); |
741 | return true; |
742 | } |
743 | |
744 | QDESIGNER_SHARED_EXPORT QString qtify(const QString &name) |
745 | { |
746 | QString qname = name; |
747 | |
748 | Q_ASSERT(qname.isEmpty() == false); |
749 | |
750 | |
751 | if (qname.size() > 1 && qname.at(i: 1).isUpper()) { |
752 | const QChar first = qname.at(i: 0); |
753 | if (first == u'Q' || first == u'K') |
754 | qname.remove(i: 0, len: 1); |
755 | } |
756 | |
757 | const qsizetype len = qname.size(); |
758 | for (qsizetype i = 0; i < len && qname.at(i).isUpper(); ++i) |
759 | qname[i] = qname.at(i).toLower(); |
760 | |
761 | return qname; |
762 | } |
763 | |
764 | // --------------- UpdateBlocker |
765 | UpdateBlocker::UpdateBlocker(QWidget *w) : |
766 | m_widget(w), |
767 | m_enabled(w->updatesEnabled() && w->isVisible()) |
768 | { |
769 | if (m_enabled) |
770 | m_widget->setUpdatesEnabled(false); |
771 | } |
772 | |
773 | UpdateBlocker::~UpdateBlocker() |
774 | { |
775 | if (m_enabled) |
776 | m_widget->setUpdatesEnabled(true); |
777 | } |
778 | |
779 | // from qpalette.cpp |
780 | quint64 paletteResolveMask(QPalette::ColorGroup colorGroup, |
781 | QPalette::ColorRole colorRole) |
782 | { |
783 | if (colorRole == QPalette::Accent) |
784 | colorRole = QPalette::NoRole; // See qtbase/17c589df94a2245ee92d45839c2cba73566d7310 |
785 | const auto offset = quint64(QPalette::NColorRoles - 1) * quint64(colorGroup); |
786 | const auto bitPos = quint64(colorRole) + offset; |
787 | return 1ull << bitPos; |
788 | } |
789 | |
790 | quint64 paletteResolveMask(QPalette::ColorRole colorRole) |
791 | { |
792 | return paletteResolveMask(colorGroup: QPalette::Active, colorRole) |
793 | | paletteResolveMask(colorGroup: QPalette::Inactive, colorRole) |
794 | | paletteResolveMask(colorGroup: QPalette::Disabled, colorRole); |
795 | } |
796 | |
797 | } // namespace qdesigner_internal |
798 | |
799 | QT_END_NAMESPACE |
800 | |