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