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 {
designerWarning(const QString & message)60     QDESIGNER_SHARED_EXPORT void designerWarning(const QString &message)
61     {
62         qWarning("Designer: %s", qPrintable(message));
63     }
64 
reloadTreeItem(DesignerIconCache * iconCache,QTreeWidgetItem * item)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 
reloadListItem(DesignerIconCache * iconCache,QListWidgetItem * item)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 
reloadTableItem(DesignerIconCache * iconCache,QTableWidgetItem * item)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 
reloadIconResources(DesignerIconCache * iconCache,QObject * object)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
DesignerMetaEnum(const QString & name,const QString & scope,const QString & separator)136     DesignerMetaEnum::DesignerMetaEnum(const QString &name, const QString &scope, const QString &separator) :
137         MetaEnum<int>(name, scope, separator)
138     {
139     }
140 
141 
toString(int value,SerializationMode sm,bool * ok) const142     QString DesignerMetaEnum::toString(int value, SerializationMode sm, bool *ok) const
143     {
144         // find value
145         bool valueOk;
146         const QString item = valueToKey(value, &valueOk);
147         if (ok)
148             *ok = valueOk;
149 
150         if (!valueOk || sm == NameOnly)
151             return item;
152 
153         QString qualifiedItem;
154         appendQualifiedName(item,  qualifiedItem);
155         return qualifiedItem;
156     }
157 
messageToStringFailed(int value) const158     QString DesignerMetaEnum::messageToStringFailed(int value) const
159     {
160         return QCoreApplication::translate("DesignerMetaEnum",
161                                            "%1 is not a valid enumeration value of '%2'.")
162                                            .arg(value).arg(name());
163     }
164 
messageParseFailed(const QString & s) const165     QString DesignerMetaEnum::messageParseFailed(const QString &s) const
166     {
167         return QCoreApplication::translate("DesignerMetaEnum",
168                                            "'%1' could not be converted to an enumeration value of type '%2'.")
169                                            .arg(s, name());
170     }
171     // -------------- DesignerMetaFlags
DesignerMetaFlags(const QString & name,const QString & scope,const QString & separator)172     DesignerMetaFlags::DesignerMetaFlags(const QString &name, const QString &scope, const QString &separator) :
173        MetaEnum<uint>(name, scope, separator)
174     {
175     }
176 
flags(int ivalue) const177     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(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(it.key());
193         }
194         return rc;
195     }
196 
197 
toString(int value,SerializationMode sm) const198     QString DesignerMetaFlags::toString(int value, SerializationMode sm) const
199     {
200         const QStringList flagIds = flags(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(*it, rc);
212             else
213                 rc += *it;
214         }
215         return rc;
216     }
217 
218 
parseFlags(const QString & s,bool * ok) const219     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(QString(QLatin1Char('|')));
229         for (auto it = keys.constBegin(), cend = keys.constEnd(); it != cend; ++it) {
230             const uint flagValue = keyToValue(*it, &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 
messageParseFailed(const QString & s) const242     QString DesignerMetaFlags::messageParseFailed(const QString &s) const
243     {
244         return QCoreApplication::translate("DesignerMetaFlags",
245                                            "'%1' could not be converted to a flag value of type '%2'.")
246                                            .arg(s, name());
247     }
248 
249     // ---------- PropertySheetEnumValue
250 
PropertySheetEnumValue(int v,const DesignerMetaEnum & me)251     PropertySheetEnumValue::PropertySheetEnumValue(int v, const DesignerMetaEnum &me) :
252        value(v),
253        metaEnum(me)
254     {
255     }
256 
257     PropertySheetEnumValue::PropertySheetEnumValue() = default;
258 
259     // ---------------- PropertySheetFlagValue
PropertySheetFlagValue(int v,const DesignerMetaFlags & mf)260     PropertySheetFlagValue::PropertySheetFlagValue(int v, const DesignerMetaFlags &mf) :
261         value(v),
262         metaFlags(mf)
263     {
264     }
265 
266     PropertySheetFlagValue::PropertySheetFlagValue() = default;
267 
268     // ---------------- PropertySheetPixmapValue
PropertySheetPixmapValue(const QString & path)269     PropertySheetPixmapValue::PropertySheetPixmapValue(const QString &path) : m_path(path)
270     {
271     }
272 
273     PropertySheetPixmapValue::PropertySheetPixmapValue() = default;
274 
getPixmapSource(QDesignerFormEditorInterface * core,const QString & path)275     PropertySheetPixmapValue::PixmapSource PropertySheetPixmapValue::getPixmapSource(QDesignerFormEditorInterface *core, const QString & path)
276     {
277         if (const QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension *>(core->extensionManager(), core))
278             return lang->isLanguageResource(path) ?  LanguageResourcePixmap : FilePixmap;
279         return path.startsWith(QLatin1Char(':')) ? ResourcePixmap : FilePixmap;
280     }
281 
compare(const PropertySheetPixmapValue & other) const282     int PropertySheetPixmapValue::compare(const PropertySheetPixmapValue &other) const
283     {
284         return m_path.compare(other.m_path);
285     }
286 
path() const287     QString PropertySheetPixmapValue::path() const
288     {
289         return m_path;
290     }
291 
setPath(const QString & path)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 
PropertySheetIconValue(const PropertySheetPixmapValue & pixmap)307     PropertySheetIconValue::PropertySheetIconValue(const PropertySheetPixmapValue &pixmap) :
308         m_data(new PropertySheetIconValueData)
309     {
310         setPixmap(QIcon::Normal, QIcon::Off, pixmap);
311     }
312 
PropertySheetIconValue()313     PropertySheetIconValue::PropertySheetIconValue() :
314         m_data(new PropertySheetIconValueData)
315     {
316     }
317 
318     PropertySheetIconValue::~PropertySheetIconValue() = default;
319 
PropertySheetIconValue(const PropertySheetIconValue & rhs)320     PropertySheetIconValue::PropertySheetIconValue(const PropertySheetIconValue &rhs) :
321         m_data(rhs.m_data)
322     {
323     }
324 
operator =(const PropertySheetIconValue & rhs)325     PropertySheetIconValue &PropertySheetIconValue::operator=(const PropertySheetIconValue &rhs)
326     {
327         if (this != &rhs)
328             m_data.operator=(rhs.m_data);
329         return *this;
330     }
331 
equals(const PropertySheetIconValue & rhs) const332     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 
operator <(const PropertySheetIconValue & other) const337     bool PropertySheetIconValue::operator<(const PropertySheetIconValue &other) const
338     {
339         if (const int themeCmp = m_data->m_theme.compare(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(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 
isEmpty() const363     bool PropertySheetIconValue::isEmpty() const
364     {
365         return m_data->m_theme.isEmpty() && m_data->m_paths.isEmpty();
366     }
367 
theme() const368     QString PropertySheetIconValue::theme() const
369     {
370         return m_data->m_theme;
371     }
372 
setTheme(const QString & t)373     void PropertySheetIconValue::setTheme(const QString &t)
374     {
375         m_data->m_theme = t;
376     }
377 
pixmap(QIcon::Mode mode,QIcon::State state) const378     PropertySheetPixmapValue PropertySheetIconValue::pixmap(QIcon::Mode mode, QIcon::State state) const
379     {
380         const ModeStateKey pair = qMakePair(mode, state);
381         return m_data->m_paths.value(pair);
382     }
383 
setPixmap(QIcon::Mode mode,QIcon::State state,const PropertySheetPixmapValue & pixmap)384     void PropertySheetIconValue::setPixmap(QIcon::Mode mode, QIcon::State state, const PropertySheetPixmapValue &pixmap)
385     {
386         const ModeStateKey pair = qMakePair(mode, state);
387         if (pixmap.path().isEmpty())
388             m_data->m_paths.remove(pair);
389         else
390             m_data->m_paths.insert(pair, pixmap);
391     }
392 
pixmap(const PropertySheetPixmapValue & value) const393     QPixmap DesignerPixmapCache::pixmap(const PropertySheetPixmapValue &value) const
394     {
395         QMap<PropertySheetPixmapValue, QPixmap>::const_iterator it = m_cache.constFind(value);
396         if (it != m_cache.constEnd())
397             return it.value();
398 
399         QPixmap pix = QPixmap(value.path());
400         m_cache.insert(value, pix);
401         return pix;
402     }
403 
clear()404     void DesignerPixmapCache::clear()
405     {
406         m_cache.clear();
407     }
408 
DesignerPixmapCache(QObject * parent)409     DesignerPixmapCache::DesignerPixmapCache(QObject *parent)
410         : QObject(parent)
411     {
412     }
413 
icon(const PropertySheetIconValue & value) const414     QIcon DesignerIconCache::icon(const PropertySheetIconValue &value) const
415     {
416         const auto it = m_cache.constFind(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(theme)) {
424                 const QIcon themeIcon = QIcon::fromTheme(theme);
425                 m_cache.insert(value, 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(it.value().path(), QSize(), pair.first, pair.second);
435         }
436         m_cache.insert(value, icon);
437         return icon;
438     }
439 
clear()440     void DesignerIconCache::clear()
441     {
442         m_cache.clear();
443     }
444 
DesignerIconCache(DesignerPixmapCache * pixmapCache,QObject * parent)445     DesignerIconCache::DesignerIconCache(DesignerPixmapCache *pixmapCache, QObject *parent)
446         : QObject(parent),
447         m_pixmapCache(pixmapCache)
448     {
449 
450     }
451 
PropertySheetTranslatableData(bool translatable,const QString & disambiguation,const QString & comment)452     PropertySheetTranslatableData::PropertySheetTranslatableData(bool translatable, const QString &disambiguation, const QString &comment) :
453         m_translatable(translatable), m_disambiguation(disambiguation), m_comment(comment) { }
454 
equals(const PropertySheetTranslatableData & rhs) const455     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 
PropertySheetStringValue(const QString & value,bool translatable,const QString & disambiguation,const QString & comment)463     PropertySheetStringValue::PropertySheetStringValue(const QString &value,
464                     bool translatable, const QString &disambiguation, const QString &comment) :
465         PropertySheetTranslatableData(translatable, disambiguation, comment), m_value(value) {}
466 
value() const467     QString PropertySheetStringValue::value() const
468     {
469         return m_value;
470     }
471 
setValue(const QString & value)472     void PropertySheetStringValue::setValue(const QString &value)
473     {
474         m_value = value;
475     }
476 
equals(const PropertySheetStringValue & rhs) const477     bool PropertySheetStringValue::equals(const PropertySheetStringValue &rhs) const
478     {
479         return m_value == rhs.m_value && PropertySheetTranslatableData::equals(rhs);
480     }
481 
PropertySheetStringListValue(const QStringList & value,bool translatable,const QString & disambiguation,const QString & comment)482     PropertySheetStringListValue::PropertySheetStringListValue(const QStringList &value,
483                                  bool translatable,
484                                  const QString &disambiguation,
485                                  const QString &comment) :
486         PropertySheetTranslatableData(translatable, disambiguation, comment), m_value(value)
487     {
488     }
489 
value() const490     QStringList PropertySheetStringListValue::value() const
491     {
492         return m_value;
493     }
494 
setValue(const QStringList & value)495     void PropertySheetStringListValue::setValue(const QStringList &value)
496     {
497         m_value = value;
498     }
499 
equals(const PropertySheetStringListValue & rhs) const500     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 
PropertySheetKeySequenceValue(const QKeySequence & value,bool translatable,const QString & disambiguation,const QString & comment)508     PropertySheetKeySequenceValue::PropertySheetKeySequenceValue(const QKeySequence &value,
509                     bool translatable, const QString &disambiguation, const QString &comment)
510         : PropertySheetTranslatableData(translatable, disambiguation, comment),
511           m_value(value), m_standardKey(QKeySequence::UnknownKey) {}
512 
PropertySheetKeySequenceValue(const QKeySequence::StandardKey & standardKey,bool translatable,const QString & disambiguation,const QString & comment)513     PropertySheetKeySequenceValue::PropertySheetKeySequenceValue(const QKeySequence::StandardKey &standardKey,
514                     bool translatable, const QString &disambiguation, const QString &comment)
515         : PropertySheetTranslatableData(translatable, disambiguation, comment),
516           m_value(QKeySequence(standardKey)), m_standardKey(standardKey) {}
517 
value() const518     QKeySequence PropertySheetKeySequenceValue::value() const
519     {
520         return m_value;
521     }
522 
setValue(const QKeySequence & value)523     void PropertySheetKeySequenceValue::setValue(const QKeySequence &value)
524     {
525         m_value = value;
526         m_standardKey = QKeySequence::UnknownKey;
527     }
528 
standardKey() const529     QKeySequence::StandardKey PropertySheetKeySequenceValue::standardKey() const
530     {
531         return m_standardKey;
532     }
533 
setStandardKey(const QKeySequence::StandardKey & standardKey)534     void PropertySheetKeySequenceValue::setStandardKey(const QKeySequence::StandardKey &standardKey)
535     {
536         m_value = QKeySequence(standardKey);
537         m_standardKey = standardKey;
538     }
539 
isStandardKey() const540     bool PropertySheetKeySequenceValue::isStandardKey() const
541     {
542         return m_standardKey != QKeySequence::UnknownKey;
543     }
544 
equals(const PropertySheetKeySequenceValue & rhs) const545     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 
iconStateToSubPropertyFlag(QIcon::Mode mode,QIcon::State state)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 
subPropertyFlagToIconModeState(unsigned flag)585     static inline QPair<QIcon::Mode, QIcon::State> subPropertyFlagToIconModeState(unsigned flag)
586     {
587         switch (flag) {
588         case NormalOnIconMask:
589             return qMakePair(QIcon::Normal,   QIcon::On);
590         case DisabledOffIconMask:
591             return qMakePair(QIcon::Disabled, QIcon::Off);
592         case DisabledOnIconMask:
593             return qMakePair(QIcon::Disabled, QIcon::On);
594         case ActiveOffIconMask:
595             return qMakePair(QIcon::Active,   QIcon::Off);
596         case ActiveOnIconMask:
597             return qMakePair(QIcon::Active,   QIcon::On);
598         case SelectedOffIconMask:
599             return qMakePair(QIcon::Selected, QIcon::Off);
600         case SelectedOnIconMask:
601             return qMakePair(QIcon::Selected, QIcon::On);
602         case NormalOffIconMask:
603         default:
604             break;
605         }
606         return     qMakePair(QIcon::Normal,   QIcon::Off);
607     }
608 
mask() const609     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(it.key().first, it.key().second);
614         if (!m_data->m_theme.isEmpty())
615             flags |= ThemeIconMask;
616         return flags;
617     }
618 
compare(const PropertySheetIconValue & other) const619     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(state.first, state.second) == other.pixmap(state.first, state.second))
627                     diffMask &= ~flag;
628             }
629         }
630         if ((diffMask & ThemeIconMask) && theme() == other.theme())
631             diffMask &= ~ThemeIconMask;
632         return diffMask;
633     }
634 
themed() const635     PropertySheetIconValue PropertySheetIconValue::themed() const
636     {
637         PropertySheetIconValue rc(*this);
638         rc.m_data->m_paths.clear();
639         return rc;
640     }
641 
unthemed() const642     PropertySheetIconValue PropertySheetIconValue::unthemed() const
643     {
644         PropertySheetIconValue rc(*this);
645         rc.m_data->m_theme.clear();
646         return rc;
647     }
648 
assign(const PropertySheetIconValue & other,uint mask)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(state.first, state.second, other.pixmap(state.first, state.second));
656             }
657         }
658         if (mask & ThemeIconMask)
659             setTheme(other.theme());
660     }
661 
paths() const662     const PropertySheetIconValue::ModeStateToPixmapMap &PropertySheetIconValue::paths() const
663     {
664         return m_data->m_paths;
665     }
666 
operator <<(QDebug d,const PropertySheetIconValue & p)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(), 16);
677         return d;
678     }
679 
createTextPropertyCommand(const QString & propertyName,const QString & text,QObject * object,QDesignerFormWindowInterface * fw)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, text);
689         return cmd;
690     }
691 
preferredEditAction(QDesignerFormEditorInterface * core,QWidget * managedWidget)692     QDESIGNER_SHARED_EXPORT QAction *preferredEditAction(QDesignerFormEditorInterface *core, QWidget *managedWidget)
693     {
694         QAction *action = nullptr;
695         if (const QDesignerTaskMenuExtension *taskMenu = qt_extension<QDesignerTaskMenuExtension*>(core->extensionManager(), 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 *taskMenu = qobject_cast<QDesignerTaskMenuExtension *>(
705                         core->extensionManager()->extension(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 
runUIC(const QString & fileName,UicLanguage language,QByteArray & ba,QString & errorMessage)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(binary, arguments);
733         if (!uic.waitForStarted()) {
734             errorMessage = QApplication::translate("Designer", "Unable to launch %1: %2").
735                            arg(QDir::toNativeSeparators(binary), uic.errorString());
736             return false;
737         }
738         if (!uic.waitForFinished()) {
739             errorMessage = QApplication::translate("Designer", "%1 timed out.").arg(binary);
740             return false;
741         }
742         if (uic.exitCode()) {
743             errorMessage =  QString::fromLatin1(uic.readAllStandardError());
744             return false;
745         }
746         ba = uic.readAllStandardOutput();
747         return true;
748     }
749 
qtify(const QString & name)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(1).isUpper()) {
758             const QChar first = qname.at(0);
759             if (first == QLatin1Char('Q') || first == QLatin1Char('K'))
760                 qname.remove(0, 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
UpdateBlocker(QWidget * w)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 
~UpdateBlocker()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