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_propertysheet_p.h"
30 #include "qdesigner_utils_p.h"
31 #include "formwindowbase_p.h"
32 #include "layoutinfo_p.h"
33 #include "qlayout_widget_p.h"
34 #include "qdesigner_introspection_p.h"
35 
36 #include <QtDesigner/private/formbuilderextra_p.h>
37 
38 #include <QtDesigner/abstractformwindow.h>
39 #include <QtDesigner/abstractformeditor.h>
40 #include <QtDesigner/abstractwidgetdatabase.h>
41 
42 #include <QtCore/qdebug.h>
43 
44 #include <QtWidgets/qlayout.h>
45 #include <QtWidgets/qdockwidget.h>
46 #include <QtWidgets/qdialog.h>
47 #include <QtWidgets/qgroupbox.h>
48 #include <QtWidgets/qlabel.h>
49 #include <QtWidgets/qgroupbox.h>
50 #include <QtWidgets/qstyle.h>
51 #include <QtWidgets/qabstractbutton.h>
52 #include <QtWidgets/qaction.h>
53 #include <QtWidgets/qapplication.h>
54 #include <QtWidgets/qtoolbar.h>
55 #include <QtWidgets/qmainwindow.h>
56 #include <QtWidgets/qmenubar.h>
57 
58 QT_BEGIN_NAMESPACE
59 
60 #define USE_LAYOUT_SIZE_CONSTRAINT
61 
propertyIntroducedBy(const QDesignerMetaObjectInterface * meta,int index)62 static const QDesignerMetaObjectInterface *propertyIntroducedBy(const QDesignerMetaObjectInterface *meta, int index)
63 {
64     if (index >= meta->propertyOffset())
65         return meta;
66 
67     if (meta->superClass())
68         return propertyIntroducedBy(meta->superClass(), index);
69 
70     return nullptr;
71 }
72 
73 // Layout fake properties (prefixed by 'layout' to distinguish them from other 'margins'
74 // that might be around. These are forwarded to the layout sheet (after name transformation).
75 //
76 // 'layoutObjectName' is new for 4.4. It is the name of the actual layout.
77 // Up to 4.3, QLayoutWidget's name was displayed in the objectinspector.
78 // This changes with 4.4; the layout name is displayed. This means that for
79 // old forms, QLayoutWidget will show up as ''; however, the uic code will
80 // still use 'verticalLayout' (in case someone accesses it). New Layouts get autogenerated names,
81 // legacy forms will keep their empty names (unless someone types in a new name).
82 static const char *layoutObjectNameC = "layoutName";
83 static const char *layoutLeftMarginC = "layoutLeftMargin";
84 static const char *layoutTopMarginC = "layoutTopMargin";
85 static const char *layoutRightMarginC = "layoutRightMargin";
86 static const char *layoutBottomMarginC = "layoutBottomMargin";
87 static const char *layoutSpacingC = "layoutSpacing";
88 static const char *layoutHorizontalSpacingC = "layoutHorizontalSpacing";
89 static const char *layoutVerticalSpacingC = "layoutVerticalSpacing";
90 static const char *layoutSizeConstraintC = "layoutSizeConstraint";
91 // form layout
92 static const char *layoutFieldGrowthPolicyC = "layoutFieldGrowthPolicy";
93 static const char *layoutRowWrapPolicyC = "layoutRowWrapPolicy";
94 static const char *layoutLabelAlignmentC = "layoutLabelAlignment";
95 static const char *layoutFormAlignmentC = "layoutFormAlignment";
96 // stretches
97 static const char *layoutboxStretchPropertyC = "layoutStretch";
98 static const char *layoutGridRowStretchPropertyC = "layoutRowStretch";
99 static const char *layoutGridColumnStretchPropertyC = "layoutColumnStretch";
100 static const char *layoutGridRowMinimumHeightC = "layoutRowMinimumHeight";
101 static const char *layoutGridColumnMinimumWidthC = "layoutColumnMinimumWidth";
102 
103 // Find the form editor in the hierarchy.
104 // We know that the parent of the sheet is the extension manager
105 // whose parent is the core.
106 
formEditorForObject(QObject * o)107 static QDesignerFormEditorInterface *formEditorForObject(QObject *o) {
108     do {
109         if (QDesignerFormEditorInterface* core = qobject_cast<QDesignerFormEditorInterface*>(o))
110             return core;
111         o = o->parent();
112     } while(o);
113     Q_ASSERT(o);
114     return nullptr;
115 }
116 
hasLayoutAttributes(QDesignerFormEditorInterface * core,QObject * object)117 static bool hasLayoutAttributes(QDesignerFormEditorInterface *core, QObject *object)
118 {
119     if (!object->isWidgetType())
120         return false;
121 
122     QWidget *w =  qobject_cast<QWidget *>(object);
123     if (const QDesignerWidgetDataBaseInterface *db = core->widgetDataBase()) {
124         if (db->isContainer(w))
125             return true;
126     }
127     return false;
128 }
129 
130 // Cache DesignerMetaEnum by scope/name of a  QMetaEnum
designerMetaEnumFor(const QDesignerMetaEnumInterface * me)131 static const qdesigner_internal::DesignerMetaEnum &designerMetaEnumFor(const QDesignerMetaEnumInterface *me)
132 {
133     using ScopeNameKey = QPair<QString, QString>;
134     using DesignerMetaEnumCache = QMap<ScopeNameKey, qdesigner_internal::DesignerMetaEnum>;
135     static DesignerMetaEnumCache cache;
136 
137     const QString name = me->name();
138     const QString scope = me->scope();
139 
140     const ScopeNameKey key = ScopeNameKey(scope, name);
141     DesignerMetaEnumCache::iterator it = cache.find(key);
142     if (it == cache.end()) {
143         qdesigner_internal::DesignerMetaEnum dme = qdesigner_internal::DesignerMetaEnum(name, scope, me->separator());
144         const int keyCount = me->keyCount();
145         for (int i=0; i < keyCount; ++i)
146             dme.addKey(me->value(i), me->key(i));
147         it = cache.insert(key, dme);
148     }
149     return it.value();
150 }
151 
152 // Cache DesignerMetaFlags by scope/name of a  QMetaEnum
designerMetaFlagsFor(const QDesignerMetaEnumInterface * me)153 static const qdesigner_internal::DesignerMetaFlags &designerMetaFlagsFor(const QDesignerMetaEnumInterface *me)
154 {
155     using ScopeNameKey = QPair<QString, QString>;
156     using DesignerMetaFlagsCache = QMap<ScopeNameKey, qdesigner_internal::DesignerMetaFlags>;
157     static DesignerMetaFlagsCache cache;
158 
159     const QString name = me->name();
160     const QString scope = me->scope();
161 
162     const ScopeNameKey key = ScopeNameKey(scope, name);
163     DesignerMetaFlagsCache::iterator it = cache.find(key);
164     if (it == cache.end()) {
165         qdesigner_internal::DesignerMetaFlags dme = qdesigner_internal::DesignerMetaFlags(name, scope, me->separator());
166         const int keyCount = me->keyCount();
167         for (int i=0; i < keyCount; ++i)
168             dme.addKey(me->value(i), me->key(i));
169         it = cache.insert(key, dme);
170     }
171     return it.value();
172 }
173 
174 // ------------ QDesignerMemberSheetPrivate
175 class QDesignerPropertySheetPrivate {
176 public:
177     using PropertyType = QDesignerPropertySheet::PropertyType;
178     using ObjectType = QDesignerPropertySheet::ObjectType;
179     using ObjectFlags = QDesignerPropertySheet::ObjectFlags;
180 
181     explicit QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent);
182 
183     bool invalidIndex(const char *functionName, int index) const;
count() const184     inline int count() const { return m_meta->propertyCount() + m_addProperties.count(); }
185 
186     PropertyType propertyType(int index) const;
187     QString transformLayoutPropertyName(int index) const;
188     QLayout* layout(QDesignerPropertySheetExtension **layoutPropertySheet = nullptr) const;
189     static ObjectType objectType(const QObject *o);
190 
191     bool isReloadableProperty(int index) const;
192     bool isResourceProperty(int index) const;
193     void addResourceProperty(int index, QVariant::Type type);
194     QVariant resourceProperty(int index) const;
195     void setResourceProperty(int index, const QVariant &value);
196     QVariant emptyResourceProperty(int index) const; // of type PropertySheetPixmapValue / PropertySheetIconValue
197     QVariant defaultResourceProperty(int index) const; // of type QPixmap / QIcon (maybe it can be generalized for all types, not resource only)
198 
199     bool isStringProperty(int index) const;
200     void addStringProperty(int index);
201     qdesigner_internal::PropertySheetStringValue stringProperty(int index) const;
202     void setStringProperty(int index, const qdesigner_internal::PropertySheetStringValue &value);
203     bool isStringListProperty(int index) const;
204     void addStringListProperty(int index);
205     qdesigner_internal::PropertySheetStringListValue stringListProperty(int index) const;
206     void setStringListProperty(int index, const qdesigner_internal::PropertySheetStringListValue &value);
207 
208     bool isKeySequenceProperty(int index) const;
209     void addKeySequenceProperty(int index);
210     qdesigner_internal::PropertySheetKeySequenceValue keySequenceProperty(int index) const;
211     void setKeySequenceProperty(int index, const qdesigner_internal::PropertySheetKeySequenceValue &value);
212 
213     enum PropertyKind { NormalProperty, FakeProperty, DynamicProperty, DefaultDynamicProperty };
214     class Info {
215     public:
216         Info() = default;
217 
218         QString group;
219         QVariant defaultValue;
220         bool changed = false;
221         bool visible = true;
222         bool attribute = false;
223         bool reset = true;
224         PropertyType propertyType = QDesignerPropertySheet::PropertyNone;
225         PropertyKind kind = NormalProperty;
226     };
227 
228     Info &ensureInfo(int index);
229 
230     QDesignerPropertySheet *q;
231     QDesignerFormEditorInterface *m_core;
232     const QDesignerMetaObjectInterface *m_meta;
233     const ObjectType m_objectType;
234     const ObjectFlags m_objectFlags;
235 
236     using InfoHash = QHash<int, Info>;
237     InfoHash m_info;
238     QHash<int, QVariant> m_fakeProperties;
239     QHash<int, QVariant> m_addProperties;
240     QHash<QString, int> m_addIndex;
241     QHash<int, QVariant> m_resourceProperties; // only PropertySheetPixmapValue snd PropertySheetIconValue here
242     QHash<int, qdesigner_internal::PropertySheetStringValue> m_stringProperties; // only PropertySheetStringValue
243     QHash<int, qdesigner_internal::PropertySheetStringListValue> m_stringListProperties; // only PropertySheetStringListValue
244     QHash<int, qdesigner_internal::PropertySheetKeySequenceValue> m_keySequenceProperties; // only PropertySheetKeySequenceValue
245 
246     const bool m_canHaveLayoutAttributes;
247 
248     // Variables used for caching the layout, access via layout().
249     QPointer<QObject> m_object;
250     mutable QPointer<QLayout> m_lastLayout;
251     mutable QDesignerPropertySheetExtension *m_lastLayoutPropertySheet;
252     mutable bool m_LastLayoutByDesigner;
253 
254     qdesigner_internal::DesignerPixmapCache *m_pixmapCache;
255     qdesigner_internal::DesignerIconCache *m_iconCache;
256     QPointer<qdesigner_internal::FormWindowBase> m_fwb;
257 
258     // Enable Qt's internal properties starting with prefix "_q_"
259     static bool m_internalDynamicPropertiesEnabled;
260 };
261 
262 bool QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled = false;
263 
264 /*
265     The property is reloadable if its contents depends on resource.
266 */
isReloadableProperty(int index) const267 bool QDesignerPropertySheetPrivate::isReloadableProperty(int index) const
268 {
269     return isResourceProperty(index)
270            || propertyType(index) == QDesignerPropertySheet::PropertyStyleSheet
271            || propertyType(index) == QDesignerPropertySheet::PropertyText
272            || q->property(index).type() == QVariant::Url;
273 }
274 
275 /*
276     Resource properties are those which:
277         1) are reloadable
278         2) their state is associated with a file which can be taken from resources
279         3) we don't store them in Qt meta object system (because designer keeps different data structure for them)
280 */
281 
isResourceProperty(int index) const282 bool QDesignerPropertySheetPrivate::isResourceProperty(int index) const
283 {
284     return m_resourceProperties.contains(index);
285 }
286 
addResourceProperty(int index,QVariant::Type type)287 void QDesignerPropertySheetPrivate::addResourceProperty(int index, QVariant::Type type)
288 {
289     if (type == QVariant::Pixmap)
290         m_resourceProperties.insert(index, QVariant::fromValue(qdesigner_internal::PropertySheetPixmapValue()));
291     else if (type == QVariant::Icon)
292         m_resourceProperties.insert(index, QVariant::fromValue(qdesigner_internal::PropertySheetIconValue()));
293 }
294 
emptyResourceProperty(int index) const295 QVariant QDesignerPropertySheetPrivate::emptyResourceProperty(int index) const
296 {
297     QVariant v = m_resourceProperties.value(index);
298     if (v.canConvert<qdesigner_internal::PropertySheetPixmapValue>())
299         return QVariant::fromValue(qdesigner_internal::PropertySheetPixmapValue());
300     if (v.canConvert<qdesigner_internal::PropertySheetIconValue>())
301         return QVariant::fromValue(qdesigner_internal::PropertySheetIconValue());
302     return v;
303 }
304 
defaultResourceProperty(int index) const305 QVariant QDesignerPropertySheetPrivate::defaultResourceProperty(int index) const
306 {
307     return m_info.value(index).defaultValue;
308 }
309 
resourceProperty(int index) const310 QVariant QDesignerPropertySheetPrivate::resourceProperty(int index) const
311 {
312     return m_resourceProperties.value(index);
313 }
314 
setResourceProperty(int index,const QVariant & value)315 void QDesignerPropertySheetPrivate::setResourceProperty(int index, const QVariant &value)
316 {
317     Q_ASSERT(isResourceProperty(index));
318 
319     QVariant &v = m_resourceProperties[index];
320     if ((value.canConvert<qdesigner_internal::PropertySheetPixmapValue>() && v.canConvert<qdesigner_internal::PropertySheetPixmapValue>())
321         || (value.canConvert<qdesigner_internal::PropertySheetIconValue>() && v.canConvert<qdesigner_internal::PropertySheetIconValue>()))
322         v = value;
323 }
324 
isStringProperty(int index) const325 bool QDesignerPropertySheetPrivate::isStringProperty(int index) const
326 {
327     return m_stringProperties.contains(index);
328 }
329 
addStringProperty(int index)330 void QDesignerPropertySheetPrivate::addStringProperty(int index)
331 {
332     m_stringProperties.insert(index, qdesigner_internal::PropertySheetStringValue());
333 }
334 
stringProperty(int index) const335 qdesigner_internal::PropertySheetStringValue QDesignerPropertySheetPrivate::stringProperty(int index) const
336 {
337     return m_stringProperties.value(index);
338 }
339 
setStringProperty(int index,const qdesigner_internal::PropertySheetStringValue & value)340 void QDesignerPropertySheetPrivate::setStringProperty(int index, const qdesigner_internal::PropertySheetStringValue &value)
341 {
342     Q_ASSERT(isStringProperty(index));
343 
344     m_stringProperties[index] = value;
345 }
346 
isStringListProperty(int index) const347 bool QDesignerPropertySheetPrivate::isStringListProperty(int index) const
348 {
349     return m_stringListProperties.contains(index);
350 }
351 
addStringListProperty(int index)352 void QDesignerPropertySheetPrivate::addStringListProperty(int index)
353 {
354     m_stringListProperties.insert(index, qdesigner_internal::PropertySheetStringListValue());
355 }
356 
stringListProperty(int index) const357 qdesigner_internal::PropertySheetStringListValue QDesignerPropertySheetPrivate::stringListProperty(int index) const
358 {
359     return m_stringListProperties.value(index);
360 }
361 
setStringListProperty(int index,const qdesigner_internal::PropertySheetStringListValue & value)362 void QDesignerPropertySheetPrivate::setStringListProperty(int index, const qdesigner_internal::PropertySheetStringListValue &value)
363 {
364     Q_ASSERT(isStringListProperty(index));
365 
366     m_stringListProperties[index] = value;
367 }
368 
isKeySequenceProperty(int index) const369 bool QDesignerPropertySheetPrivate::isKeySequenceProperty(int index) const
370 {
371     return m_keySequenceProperties.contains(index);
372 }
373 
addKeySequenceProperty(int index)374 void QDesignerPropertySheetPrivate::addKeySequenceProperty(int index)
375 {
376     m_keySequenceProperties.insert(index, qdesigner_internal::PropertySheetKeySequenceValue());
377 }
378 
keySequenceProperty(int index) const379 qdesigner_internal::PropertySheetKeySequenceValue QDesignerPropertySheetPrivate::keySequenceProperty(int index) const
380 {
381     return m_keySequenceProperties.value(index);
382 }
383 
setKeySequenceProperty(int index,const qdesigner_internal::PropertySheetKeySequenceValue & value)384 void QDesignerPropertySheetPrivate::setKeySequenceProperty(int index, const qdesigner_internal::PropertySheetKeySequenceValue &value)
385 {
386     Q_ASSERT(isKeySequenceProperty(index));
387 
388     m_keySequenceProperties[index] = value;
389 }
390 
QDesignerPropertySheetPrivate(QDesignerPropertySheet * sheetPublic,QObject * object,QObject * sheetParent)391 QDesignerPropertySheetPrivate::QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent) :
392     q(sheetPublic),
393     m_core(formEditorForObject(sheetParent)),
394     m_meta(m_core->introspection()->metaObject(object)),
395     m_objectType(QDesignerPropertySheet::objectTypeFromObject(object)),
396     m_objectFlags(QDesignerPropertySheet::objectFlagsFromObject(object)),
397     m_canHaveLayoutAttributes(hasLayoutAttributes(m_core, object)),
398     m_object(object),
399     m_lastLayout(nullptr),
400     m_lastLayoutPropertySheet(nullptr),
401     m_LastLayoutByDesigner(false),
402     m_pixmapCache(nullptr),
403     m_iconCache(nullptr)
404 {
405 }
406 
formWindowBase() const407 qdesigner_internal::FormWindowBase *QDesignerPropertySheet::formWindowBase() const
408 {
409     return d->m_fwb;
410 }
411 
invalidIndex(const char * functionName,int index) const412 bool QDesignerPropertySheetPrivate::invalidIndex(const char *functionName, int index) const
413 {
414     if (index < 0 || index >= count()) {
415         qWarning() <<  "** WARNING " << functionName << " invoked for " << m_object->objectName() << " was  passed an invalid index " << index << '.';
416         return true;
417     }
418     return false;
419 }
420 
layout(QDesignerPropertySheetExtension ** layoutPropertySheet) const421 QLayout* QDesignerPropertySheetPrivate::layout(QDesignerPropertySheetExtension **layoutPropertySheet) const
422 {
423     // Return the layout and its property sheet
424     // only if it is managed by designer and not one created on a custom widget.
425     // (attempt to cache the value as this requires some hoops).
426     if (layoutPropertySheet)
427         *layoutPropertySheet = nullptr;
428 
429     if (!m_object->isWidgetType() || !m_canHaveLayoutAttributes)
430         return nullptr;
431 
432     QWidget *widget = qobject_cast<QWidget*>(m_object);
433     QLayout *widgetLayout = qdesigner_internal::LayoutInfo::internalLayout(widget);
434     if (!widgetLayout) {
435         m_lastLayout = nullptr;
436         m_lastLayoutPropertySheet = nullptr;
437         return nullptr;
438     }
439     // Smart logic to avoid retrieving the meta DB from the widget every time.
440     if (widgetLayout != m_lastLayout) {
441         m_lastLayout = widgetLayout;
442         m_LastLayoutByDesigner = false;
443         m_lastLayoutPropertySheet = nullptr;
444         // Is this a layout managed by designer or some layout on a custom widget?
445         if (qdesigner_internal::LayoutInfo::managedLayout(m_core ,widgetLayout)) {
446             m_LastLayoutByDesigner = true;
447             m_lastLayoutPropertySheet = qt_extension<QDesignerPropertySheetExtension*>(m_core->extensionManager(), m_lastLayout);
448         }
449     }
450     if (!m_LastLayoutByDesigner)
451         return nullptr;
452 
453     if (layoutPropertySheet)
454         *layoutPropertySheet = m_lastLayoutPropertySheet;
455 
456     return  m_lastLayout;
457 }
458 
ensureInfo(int index)459 QDesignerPropertySheetPrivate::Info &QDesignerPropertySheetPrivate::ensureInfo(int index)
460 {
461     InfoHash::iterator it = m_info.find(index);
462     if (it == m_info.end())
463         it = m_info.insert(index, Info());
464     return it.value();
465 }
466 
propertyType(int index) const467 QDesignerPropertySheet::PropertyType QDesignerPropertySheetPrivate::propertyType(int index) const
468 {
469     const InfoHash::const_iterator it = m_info.constFind(index);
470     if (it == m_info.constEnd())
471         return QDesignerPropertySheet::PropertyNone;
472     return it.value().propertyType;
473 }
474 
transformLayoutPropertyName(int index) const475 QString QDesignerPropertySheetPrivate::transformLayoutPropertyName(int index) const
476 {
477     using TypeNameMap = QMap<QDesignerPropertySheet::PropertyType, QString>;
478     static TypeNameMap typeNameMap;
479     if (typeNameMap.isEmpty()) {
480         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutObjectName, QStringLiteral("objectName"));
481         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutLeftMargin, QStringLiteral("leftMargin"));
482         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutTopMargin, QStringLiteral("topMargin"));
483         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutRightMargin, QStringLiteral("rightMargin"));
484         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutBottomMargin, QStringLiteral("bottomMargin"));
485         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutSpacing, QStringLiteral("spacing"));
486         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutHorizontalSpacing, QStringLiteral("horizontalSpacing"));
487         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutVerticalSpacing, QStringLiteral("verticalSpacing"));
488         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutSizeConstraint, QStringLiteral("sizeConstraint"));
489         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutFieldGrowthPolicy, QStringLiteral("fieldGrowthPolicy"));
490         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutRowWrapPolicy, QStringLiteral("rowWrapPolicy"));
491         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutLabelAlignment, QStringLiteral("labelAlignment"));
492         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutFormAlignment, QStringLiteral("formAlignment"));
493         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutBoxStretch, QStringLiteral("stretch"));
494         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridRowStretch, QStringLiteral("rowStretch"));
495         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridColumnStretch, QStringLiteral("columnStretch"));
496         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridRowMinimumHeight, QStringLiteral("rowMinimumHeight"));
497         typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridColumnMinimumWidth, QStringLiteral("columnMinimumWidth"));
498     }
499     const TypeNameMap::const_iterator it = typeNameMap.constFind(propertyType(index));
500     if (it != typeNameMap.constEnd())
501         return it.value();
502     return QString();
503 }
504 
505 // ----------- QDesignerPropertySheet
506 
objectTypeFromObject(const QObject * o)507 QDesignerPropertySheet::ObjectType QDesignerPropertySheet::objectTypeFromObject(const QObject *o)
508 {
509     if (qobject_cast<const QLayout *>(o))
510         return ObjectLayout;
511 
512     if (!o->isWidgetType())
513         return ObjectNone;
514 
515     if (qobject_cast<const QLayoutWidget *>(o))
516         return ObjectLayoutWidget;
517 
518     if (qobject_cast<const QLabel*>(o))
519         return ObjectLabel;
520 
521     return ObjectNone;
522 }
523 
objectFlagsFromObject(const QObject * o)524 QDesignerPropertySheet::ObjectFlags QDesignerPropertySheet::objectFlagsFromObject(const QObject *o)
525 {
526     ObjectFlags result;
527     if ((o->isWidgetType() && (qobject_cast<const QAbstractButton *>(o)
528                                || qobject_cast<const QGroupBox *>(o)))
529         || qobject_cast<const QAction *>(o)) {
530         result |= CheckableProperty;
531     }
532     return result;
533 }
534 
propertyTypeFromName(const QString & name)535 QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyTypeFromName(const QString &name)
536 {
537     typedef QHash<QString, PropertyType> PropertyTypeHash;
538     static PropertyTypeHash propertyTypeHash;
539     if (propertyTypeHash.isEmpty()) {
540         propertyTypeHash.insert(QLatin1String(layoutObjectNameC),         PropertyLayoutObjectName);
541         propertyTypeHash.insert(QLatin1String(layoutLeftMarginC),         PropertyLayoutLeftMargin);
542         propertyTypeHash.insert(QLatin1String(layoutTopMarginC),          PropertyLayoutTopMargin);
543         propertyTypeHash.insert(QLatin1String(layoutRightMarginC),        PropertyLayoutRightMargin);
544         propertyTypeHash.insert(QLatin1String(layoutBottomMarginC),       PropertyLayoutBottomMargin);
545         propertyTypeHash.insert(QLatin1String(layoutSpacingC),            PropertyLayoutSpacing);
546         propertyTypeHash.insert(QLatin1String(layoutHorizontalSpacingC),  PropertyLayoutHorizontalSpacing);
547         propertyTypeHash.insert(QLatin1String(layoutVerticalSpacingC),    PropertyLayoutVerticalSpacing);
548         propertyTypeHash.insert(QLatin1String(layoutSizeConstraintC),     PropertyLayoutSizeConstraint);
549         propertyTypeHash.insert(QLatin1String(layoutFieldGrowthPolicyC),  PropertyLayoutFieldGrowthPolicy);
550         propertyTypeHash.insert(QLatin1String(layoutRowWrapPolicyC),      PropertyLayoutRowWrapPolicy);
551         propertyTypeHash.insert(QLatin1String(layoutLabelAlignmentC),     PropertyLayoutLabelAlignment);
552         propertyTypeHash.insert(QLatin1String(layoutFormAlignmentC),      PropertyLayoutFormAlignment);
553         propertyTypeHash.insert(QLatin1String(layoutboxStretchPropertyC), PropertyLayoutBoxStretch);
554         propertyTypeHash.insert(QLatin1String(layoutGridRowStretchPropertyC),    PropertyLayoutGridRowStretch);
555         propertyTypeHash.insert(QLatin1String(layoutGridColumnStretchPropertyC), PropertyLayoutGridColumnStretch);
556         propertyTypeHash.insert(QLatin1String(layoutGridRowMinimumHeightC),      PropertyLayoutGridRowMinimumHeight);
557         propertyTypeHash.insert(QLatin1String(layoutGridColumnMinimumWidthC),    PropertyLayoutGridColumnMinimumWidth);
558         propertyTypeHash.insert(QStringLiteral("buddy"),                   PropertyBuddy);
559         propertyTypeHash.insert(QStringLiteral("geometry"),                PropertyGeometry);
560         propertyTypeHash.insert(QStringLiteral("checked"),                 PropertyChecked);
561         propertyTypeHash.insert(QStringLiteral("checkable"),               PropertyCheckable);
562         propertyTypeHash.insert(QStringLiteral("accessibleName"),          PropertyAccessibility);
563         propertyTypeHash.insert(QStringLiteral("accessibleDescription"),   PropertyAccessibility);
564         propertyTypeHash.insert(QStringLiteral("windowTitle"),             PropertyWindowTitle);
565         propertyTypeHash.insert(QStringLiteral("windowIcon"),              PropertyWindowIcon);
566         propertyTypeHash.insert(QStringLiteral("windowFilePath"),          PropertyWindowFilePath);
567         propertyTypeHash.insert(QStringLiteral("windowOpacity"),           PropertyWindowOpacity);
568         propertyTypeHash.insert(QStringLiteral("windowIconText"),          PropertyWindowIconText);
569         propertyTypeHash.insert(QStringLiteral("windowModality"),          PropertyWindowModality);
570         propertyTypeHash.insert(QStringLiteral("windowModified"),          PropertyWindowModified);
571         propertyTypeHash.insert(QStringLiteral("styleSheet"),              PropertyStyleSheet);
572         propertyTypeHash.insert(QStringLiteral("text"),                    PropertyText);
573     }
574     return propertyTypeHash.value(name, PropertyNone);
575 }
576 
QDesignerPropertySheet(QObject * object,QObject * parent)577 QDesignerPropertySheet::QDesignerPropertySheet(QObject *object, QObject *parent) :
578     QObject(parent),
579     d(new QDesignerPropertySheetPrivate(this, object, parent))
580 {
581     using Info = QDesignerPropertySheetPrivate::Info;
582     const QDesignerMetaObjectInterface *baseMeta = d->m_meta;
583 
584     while (baseMeta &&baseMeta->className().startsWith(QStringLiteral("QDesigner"))) {
585         baseMeta = baseMeta->superClass();
586     }
587     Q_ASSERT(baseMeta != nullptr);
588 
589     QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(d->m_object);
590     d->m_fwb = qobject_cast<qdesigner_internal::FormWindowBase *>(formWindow);
591     if (d->m_fwb) {
592         d->m_pixmapCache = d->m_fwb->pixmapCache();
593         d->m_iconCache = d->m_fwb->iconCache();
594         d->m_fwb->addReloadablePropertySheet(this, object);
595     }
596 
597     for (int index=0; index<count(); ++index) {
598         const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
599         const QString name = p->name();
600         if (p->type() == QVariant::KeySequence) {
601             createFakeProperty(name);
602         } else {
603             setVisible(index, false); // use the default for `real' properties
604         }
605 
606         QString pgroup = baseMeta->className();
607 
608         if (const QDesignerMetaObjectInterface *pmeta = propertyIntroducedBy(baseMeta, index)) {
609             pgroup = pmeta->className();
610         }
611 
612         Info &info = d->ensureInfo(index);
613         info.group = pgroup;
614         info.propertyType = propertyTypeFromName(name);
615 
616         const QVariant::Type type = p->type();
617         switch (type) {
618         case QVariant::Cursor:
619         case QVariant::Icon:
620         case QVariant::Pixmap:
621             info.defaultValue = p->read(d->m_object);
622             if (type == QVariant::Icon || type == QVariant::Pixmap)
623                 d->addResourceProperty(index, type);
624             break;
625         case QVariant::String:
626             d->addStringProperty(index);
627             break;
628         case QVariant::StringList:
629             d->addStringListProperty(index);
630             break;
631         case QVariant::KeySequence:
632             d->addKeySequenceProperty(index);
633             break;
634         default:
635             break;
636         }
637     }
638 
639     if (object->isWidgetType()) {
640         createFakeProperty(QStringLiteral("focusPolicy"));
641         createFakeProperty(QStringLiteral("cursor"));
642         createFakeProperty(QStringLiteral("toolTip"));
643         createFakeProperty(QStringLiteral("whatsThis"));
644         createFakeProperty(QStringLiteral("acceptDrops"));
645         createFakeProperty(QStringLiteral("dragEnabled"));
646         // windowModality/Opacity is visible only for the main container, in which case the form windows enables it on loading
647         setVisible(createFakeProperty(QStringLiteral("windowModality")), false);
648         setVisible(createFakeProperty(QStringLiteral("windowOpacity"), double(1.0)), false);
649         if (qobject_cast<const QToolBar *>(d->m_object)) { // prevent toolbars from being dragged off
650             createFakeProperty(QStringLiteral("floatable"), QVariant(true));
651         } else {
652             if (qobject_cast<const QMenuBar *>(d->m_object)) {
653                 // Keep the menu bar editable in the form even if a native menu bar is used.
654                 const bool nativeMenuBarDefault =
655                     !QCoreApplication::testAttribute(Qt::AA_DontUseNativeMenuBar);
656                 createFakeProperty(QStringLiteral("nativeMenuBar"), QVariant(nativeMenuBarDefault));
657             }
658         }
659         if (d->m_canHaveLayoutAttributes) {
660             static const QString layoutGroup = QStringLiteral("Layout");
661             const char* fakeLayoutProperties[] = {
662                 layoutObjectNameC, layoutLeftMarginC, layoutTopMarginC, layoutRightMarginC, layoutBottomMarginC, layoutSpacingC, layoutHorizontalSpacingC, layoutVerticalSpacingC,
663                 layoutFieldGrowthPolicyC, layoutRowWrapPolicyC, layoutLabelAlignmentC, layoutFormAlignmentC,
664                 layoutboxStretchPropertyC, layoutGridRowStretchPropertyC, layoutGridColumnStretchPropertyC,
665                 layoutGridRowMinimumHeightC, layoutGridColumnMinimumWidthC
666 #ifdef USE_LAYOUT_SIZE_CONSTRAINT
667                 , layoutSizeConstraintC
668 #endif
669             };
670             const int fakeLayoutPropertyCount = sizeof(fakeLayoutProperties)/sizeof(const char*);
671             const int size = count();
672             for (int i = 0; i < fakeLayoutPropertyCount; i++) {
673                 createFakeProperty(QLatin1String(fakeLayoutProperties[i]), 0);
674                 setAttribute(size  + i, true);
675                 setPropertyGroup(size  + i, layoutGroup);
676             }
677         }
678 
679         if (d->m_objectType == ObjectLabel)
680             createFakeProperty(QStringLiteral("buddy"), QVariant(QByteArray()));
681         /* We need to create a fake property since the property does not work
682          * for non-toplevel windows or on other systems than Mac and only if
683          * it is above a certain Mac OS version. */
684         if (qobject_cast<const QMainWindow *>(d->m_object))
685             createFakeProperty(QStringLiteral("unifiedTitleAndToolBarOnMac"), false);
686     }
687 
688     if (qobject_cast<const QDialog*>(object)) {
689         createFakeProperty(QStringLiteral("modal"));
690     }
691     if (qobject_cast<const QDockWidget*>(object)) {
692         createFakeProperty(QStringLiteral("floating"));
693     }
694 
695     using ByteArrayList = QList<QByteArray>;
696     const ByteArrayList names = object->dynamicPropertyNames();
697     if (!names.isEmpty()) {
698         const ByteArrayList::const_iterator cend =  names.constEnd();
699         for (ByteArrayList::const_iterator it = names.constBegin(); it != cend; ++it) {
700             const char* cName = it->constData();
701             const QString name = QString::fromLatin1(cName);
702             const int idx = addDynamicProperty(name, object->property(cName));
703             if (idx != -1)
704                 d->ensureInfo(idx).kind = QDesignerPropertySheetPrivate::DefaultDynamicProperty;
705         }
706     }
707 }
708 
~QDesignerPropertySheet()709 QDesignerPropertySheet::~QDesignerPropertySheet()
710 {
711     delete d;
712 }
713 
object() const714 QObject *QDesignerPropertySheet::object() const
715 {
716     return d->m_object;
717 }
718 
dynamicPropertiesAllowed() const719 bool QDesignerPropertySheet::dynamicPropertiesAllowed() const
720 {
721     return true;
722 }
723 
canAddDynamicProperty(const QString & propName) const724 bool QDesignerPropertySheet::canAddDynamicProperty(const QString &propName) const
725 {
726     // used internally
727     if (propName == QStringLiteral("database") ||
728         propName == QStringLiteral("buttonGroupId"))
729         return false;
730     const int index = d->m_meta->indexOfProperty(propName);
731     if (index != -1)
732         return false; // property already exists and is not a dynamic one
733     if (d->m_addIndex.contains(propName)) {
734         const int idx = d->m_addIndex.value(propName);
735         return !isVisible(idx); // dynamic property already exists
736     }
737     return QDesignerPropertySheet::internalDynamicPropertiesEnabled()
738         || !propName.startsWith(QStringLiteral("_q_"));
739 }
740 
addDynamicProperty(const QString & propName,const QVariant & value)741 int QDesignerPropertySheet::addDynamicProperty(const QString &propName, const QVariant &value)
742 {
743     using Info = QDesignerPropertySheetPrivate::Info;
744     if (!value.isValid())
745         return -1; // property has invalid type
746     if (!canAddDynamicProperty(propName))
747         return -1;
748 
749     QVariant v = value;
750     if (value.type() == QVariant::Icon)
751         v = QVariant::fromValue(qdesigner_internal::PropertySheetIconValue());
752     else if (value.type() == QVariant::Pixmap)
753         v = QVariant::fromValue(qdesigner_internal::PropertySheetPixmapValue());
754     else if (value.type() == QVariant::String)
755         v = QVariant::fromValue(qdesigner_internal::PropertySheetStringValue(value.toString()));
756     else if (value.type() == QVariant::StringList)
757         v = QVariant::fromValue(qdesigner_internal::PropertySheetStringListValue(value.toStringList()));
758     else if (value.type() == QVariant::KeySequence) {
759         const QKeySequence keySequence = qvariant_cast<QKeySequence>(value);
760         v = QVariant::fromValue(qdesigner_internal::PropertySheetKeySequenceValue(keySequence));
761     }
762 
763     if (d->m_addIndex.contains(propName)) {
764         const int idx = d->m_addIndex.value(propName);
765         // have to be invisible, this was checked in canAddDynamicProperty() method
766         setVisible(idx, true);
767         d->m_addProperties.insert(idx, v);
768         setChanged(idx, false);
769         const int index = d->m_meta->indexOfProperty(propName);
770         Info &info = d->ensureInfo(index);
771         info.defaultValue = value;
772         info.kind = QDesignerPropertySheetPrivate::DynamicProperty;
773         if (value.type() == QVariant::Icon || value.type() == QVariant::Pixmap)
774             d->addResourceProperty(idx, value.type());
775         else if (value.type() == QVariant::String)
776             d->addStringProperty(idx);
777         else if (value.type() == QVariant::KeySequence)
778             d->addKeySequenceProperty(idx);
779         return idx;
780     }
781 
782     const int index = count();
783     d->m_addIndex.insert(propName, index);
784     d->m_addProperties.insert(index, v);
785     Info &info = d->ensureInfo(index);
786     info.visible = true;
787     info.changed = false;
788     info.defaultValue = value;
789     info.kind = QDesignerPropertySheetPrivate::DynamicProperty;
790     setPropertyGroup(index, tr("Dynamic Properties"));
791     switch (value.type()) {
792     case QVariant::Icon:
793     case QVariant::Pixmap:
794         d->addResourceProperty(index, value.type());
795         break;
796     case QVariant::String:
797         d->addStringProperty(index);
798         break;
799     case QVariant::StringList:
800         d->addStringListProperty(index);
801         break;
802     case QVariant::KeySequence:
803         d->addKeySequenceProperty(index);
804         break;
805     default:
806         break;
807     }
808     return index;
809 }
810 
removeDynamicProperty(int index)811 bool QDesignerPropertySheet::removeDynamicProperty(int index)
812 {
813     if (!d->m_addIndex.contains(propertyName(index)))
814         return false;
815 
816     setVisible(index, false);
817     return true;
818 }
819 
isDynamic(int index) const820 bool QDesignerPropertySheet::isDynamic(int index) const
821 {
822     if (!d->m_addProperties.contains(index))
823         return false;
824 
825     switch (propertyType(index)) {
826     case PropertyBuddy:
827         if (d->m_objectType == ObjectLabel)
828             return false;
829         break;
830     case PropertyLayoutLeftMargin:
831     case PropertyLayoutTopMargin:
832     case PropertyLayoutRightMargin:
833     case PropertyLayoutBottomMargin:
834     case PropertyLayoutSpacing:
835     case PropertyLayoutHorizontalSpacing:
836     case PropertyLayoutVerticalSpacing:
837     case PropertyLayoutObjectName:
838     case PropertyLayoutSizeConstraint:
839     case PropertyLayoutFieldGrowthPolicy:
840     case PropertyLayoutRowWrapPolicy:
841     case PropertyLayoutLabelAlignment:
842     case PropertyLayoutFormAlignment:
843     case PropertyLayoutBoxStretch:
844     case PropertyLayoutGridRowStretch:
845     case PropertyLayoutGridColumnStretch:
846     case PropertyLayoutGridRowMinimumHeight:
847     case PropertyLayoutGridColumnMinimumWidth:
848         if (d->m_object->isWidgetType() && d->m_canHaveLayoutAttributes)
849             return false;
850     default:
851         break;
852     }
853     return true;
854 }
855 
isDynamicProperty(int index) const856 bool QDesignerPropertySheet::isDynamicProperty(int index) const
857 {
858     // Do not complain here, as an invalid index might be encountered
859     // if someone implements a property sheet only, omitting the dynamic sheet.
860     if (index < 0 || index >= count())
861         return false;
862     return d->m_info.value(index).kind == QDesignerPropertySheetPrivate::DynamicProperty;
863 }
864 
isDefaultDynamicProperty(int index) const865 bool QDesignerPropertySheet::isDefaultDynamicProperty(int index) const
866 {
867     if (d->invalidIndex(Q_FUNC_INFO, index))
868         return false;
869     return d->m_info.value(index).kind == QDesignerPropertySheetPrivate::DefaultDynamicProperty;
870 }
871 
isResourceProperty(int index) const872 bool QDesignerPropertySheet::isResourceProperty(int index) const
873 {
874     return d->isResourceProperty(index);
875 }
876 
defaultResourceProperty(int index) const877 QVariant QDesignerPropertySheet::defaultResourceProperty(int index) const
878 {
879     return d->defaultResourceProperty(index);
880 }
881 
pixmapCache() const882 qdesigner_internal::DesignerPixmapCache *QDesignerPropertySheet::pixmapCache() const
883 {
884     return d->m_pixmapCache;
885 }
886 
setPixmapCache(qdesigner_internal::DesignerPixmapCache * cache)887 void QDesignerPropertySheet::setPixmapCache(qdesigner_internal::DesignerPixmapCache *cache)
888 {
889     d->m_pixmapCache = cache;
890 }
891 
iconCache() const892 qdesigner_internal::DesignerIconCache *QDesignerPropertySheet::iconCache() const
893 {
894     return d->m_iconCache;
895 }
896 
setIconCache(qdesigner_internal::DesignerIconCache * cache)897 void QDesignerPropertySheet::setIconCache(qdesigner_internal::DesignerIconCache *cache)
898 {
899     d->m_iconCache = cache;
900 }
901 
createFakeProperty(const QString & propertyName,const QVariant & value)902 int QDesignerPropertySheet::createFakeProperty(const QString &propertyName, const QVariant &value)
903 {
904     using Info = QDesignerPropertySheetPrivate::Info;
905     // fake properties
906     const int index = d->m_meta->indexOfProperty(propertyName);
907     if (index != -1) {
908         if (!(d->m_meta->property(index)->attributes() & QDesignerMetaPropertyInterface::DesignableAttribute))
909             return -1;
910         Info &info = d->ensureInfo(index);
911         info.visible = false;
912         info.kind = QDesignerPropertySheetPrivate::FakeProperty;
913         QVariant v = value.isValid() ? value : metaProperty(index);
914         if (v.type() == QVariant::String)
915             v = QVariant::fromValue(qdesigner_internal::PropertySheetStringValue());
916         if (v.type() == QVariant::StringList)
917             v = QVariant::fromValue(qdesigner_internal::PropertySheetStringListValue());
918         if (v.type() == QVariant::KeySequence)
919             v = QVariant::fromValue(qdesigner_internal::PropertySheetKeySequenceValue());
920         d->m_fakeProperties.insert(index, v);
921         return index;
922     }
923     if (!value.isValid())
924         return -1;
925 
926     const int newIndex = count();
927     d->m_addIndex.insert(propertyName, newIndex);
928     d->m_addProperties.insert(newIndex, value);
929     Info &info = d->ensureInfo(newIndex);
930     info.propertyType = propertyTypeFromName(propertyName);
931     info.kind = QDesignerPropertySheetPrivate::FakeProperty;
932     return newIndex;
933 }
934 
isAdditionalProperty(int index) const935 bool QDesignerPropertySheet::isAdditionalProperty(int index) const
936 {
937     if (d->invalidIndex(Q_FUNC_INFO, index))
938         return false;
939     return d->m_addProperties.contains(index);
940 }
941 
isFakeProperty(int index) const942 bool QDesignerPropertySheet::isFakeProperty(int index) const
943 {
944     if (d->invalidIndex(Q_FUNC_INFO, index))
945         return false;
946     // additional properties must be fake
947     return (d->m_fakeProperties.contains(index) || isAdditionalProperty(index));
948 }
949 
count() const950 int QDesignerPropertySheet::count() const
951 {
952     return d->count();
953 }
954 
indexOf(const QString & name) const955 int QDesignerPropertySheet::indexOf(const QString &name) const
956 {
957     int index = d->m_meta->indexOfProperty(name);
958 
959     if (index == -1)
960         index = d->m_addIndex.value(name, -1);
961 
962     return index;
963 }
964 
propertyType(int index) const965 QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyType(int index) const
966 {
967     if (d->invalidIndex(Q_FUNC_INFO, index))
968         return PropertyNone;
969     return d->propertyType(index);
970 }
971 
objectType() const972 QDesignerPropertySheet::ObjectType QDesignerPropertySheet::objectType() const
973 {
974     return d->m_objectType;
975 }
976 
propertyName(int index) const977 QString QDesignerPropertySheet::propertyName(int index) const
978 {
979     if (d->invalidIndex(Q_FUNC_INFO, index))
980         return QString();
981     if (isAdditionalProperty(index))
982         return d->m_addIndex.key(index);
983 
984     return d->m_meta->property(index)->name();
985 }
986 
propertyGroup(int index) const987 QString QDesignerPropertySheet::propertyGroup(int index) const
988 {
989     if (d->invalidIndex(Q_FUNC_INFO, index))
990         return QString();
991     const QString g = d->m_info.value(index).group;
992 
993     if (!g.isEmpty())
994         return g;
995 
996     if (propertyType(index) == PropertyAccessibility)
997         return QString::fromUtf8("Accessibility");
998 
999     if (isAdditionalProperty(index))
1000         return d->m_meta->className();
1001 
1002     return g;
1003 }
1004 
setPropertyGroup(int index,const QString & group)1005 void QDesignerPropertySheet::setPropertyGroup(int index, const QString &group)
1006 {
1007     if (d->invalidIndex(Q_FUNC_INFO, index))
1008         return;
1009     d->ensureInfo(index).group = group;
1010 }
1011 
property(int index) const1012 QVariant QDesignerPropertySheet::property(int index) const
1013 {
1014     if (d->invalidIndex(Q_FUNC_INFO, index))
1015         return QVariant();
1016     if (isAdditionalProperty(index)) {
1017         if (isFakeLayoutProperty(index)) {
1018             QDesignerPropertySheetExtension *layoutPropertySheet;
1019             if (d->layout(&layoutPropertySheet) && layoutPropertySheet) {
1020                 const QString newPropName = d->transformLayoutPropertyName(index);
1021                 if (!newPropName.isEmpty()) {
1022                     const int newIndex = layoutPropertySheet->indexOf(newPropName);
1023                     if (newIndex != -1)
1024                         return layoutPropertySheet->property(newIndex);
1025                     return QVariant();
1026                 }
1027             }
1028         }
1029         return d->m_addProperties.value(index);
1030     }
1031 
1032     if (isFakeProperty(index)) {
1033         return d->m_fakeProperties.value(index);
1034     }
1035 
1036     if (d->isResourceProperty(index))
1037         return d->resourceProperty(index);
1038 
1039     if (d->isStringProperty(index)) {
1040         QString strValue = metaProperty(index).toString();
1041         qdesigner_internal::PropertySheetStringValue value = d->stringProperty(index);
1042         if (strValue != value.value()) {
1043             value.setValue(strValue);
1044             d->setStringProperty(index, value); // cache it
1045         }
1046         return QVariant::fromValue(value);
1047     }
1048 
1049     if (d->isStringListProperty(index)) {
1050         const QStringList listValue = metaProperty(index).toStringList();
1051         qdesigner_internal::PropertySheetStringListValue value = d->stringListProperty(index);
1052         if (listValue != value.value()) {
1053             value.setValue(listValue);
1054             d->setStringListProperty(index, value); // cache it
1055         }
1056         return QVariant::fromValue(value);
1057     }
1058 
1059     if (d->isKeySequenceProperty(index)) {
1060         QKeySequence keyValue = qvariant_cast<QKeySequence>(metaProperty(index));
1061         qdesigner_internal::PropertySheetKeySequenceValue value = d->keySequenceProperty(index);
1062         if (keyValue != value.value()) {
1063             value.setValue(keyValue);
1064             d->setKeySequenceProperty(index, value); // cache it
1065         }
1066         return QVariant::fromValue(value);
1067     }
1068 
1069     return metaProperty(index);
1070 }
1071 
metaProperty(int index) const1072 QVariant QDesignerPropertySheet::metaProperty(int index) const
1073 {
1074     Q_ASSERT(!isFakeProperty(index));
1075 
1076     const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
1077     QVariant v = p->read(d->m_object);
1078     switch (p->kind()) {
1079     case QDesignerMetaPropertyInterface::FlagKind: {
1080         qdesigner_internal::PropertySheetFlagValue psflags = qdesigner_internal::PropertySheetFlagValue(v.toInt(), designerMetaFlagsFor(p->enumerator()));
1081         v.setValue(psflags);
1082     }
1083         break;
1084     case QDesignerMetaPropertyInterface::EnumKind: {
1085         qdesigner_internal::PropertySheetEnumValue pse = qdesigner_internal::PropertySheetEnumValue(v.toInt(), designerMetaEnumFor(p->enumerator()));
1086         v.setValue(pse);
1087     }
1088         break;
1089     case QDesignerMetaPropertyInterface::OtherKind:
1090         break;
1091     }
1092     return v;
1093 }
1094 
resolvePropertyValue(int index,const QVariant & value) const1095 QVariant QDesignerPropertySheet::resolvePropertyValue(int index, const QVariant &value) const
1096 {
1097     if (value.canConvert<qdesigner_internal::PropertySheetEnumValue>())
1098         return qvariant_cast<qdesigner_internal::PropertySheetEnumValue>(value).value;
1099 
1100     if (value.canConvert<qdesigner_internal::PropertySheetFlagValue>())
1101         return qvariant_cast<qdesigner_internal::PropertySheetFlagValue>(value).value;
1102 
1103     if (value.canConvert<qdesigner_internal::PropertySheetStringValue>())
1104         return qvariant_cast<qdesigner_internal::PropertySheetStringValue>(value).value();
1105 
1106     if (value.canConvert<qdesigner_internal::PropertySheetStringListValue>())
1107         return qvariant_cast<qdesigner_internal::PropertySheetStringListValue>(value).value();
1108 
1109     if (value.canConvert<qdesigner_internal::PropertySheetKeySequenceValue>())
1110         return QVariant::fromValue(qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(value).value());
1111 
1112     if (value.canConvert<qdesigner_internal::PropertySheetPixmapValue>()) {
1113         const QString path = qvariant_cast<qdesigner_internal::PropertySheetPixmapValue>(value).path();
1114         if (path.isEmpty())
1115             return defaultResourceProperty(index);
1116         if (d->m_pixmapCache) {
1117             return d->m_pixmapCache->pixmap(qvariant_cast<qdesigner_internal::PropertySheetPixmapValue>(value));
1118         }
1119     }
1120 
1121     if (value.canConvert<qdesigner_internal::PropertySheetIconValue>()) {
1122         const unsigned mask = qvariant_cast<qdesigner_internal::PropertySheetIconValue>(value).mask();
1123         if (mask == 0)
1124             return defaultResourceProperty(index);
1125         if (d->m_iconCache)
1126             return d->m_iconCache->icon(qvariant_cast<qdesigner_internal::PropertySheetIconValue>(value));
1127     }
1128 
1129     return value;
1130 }
1131 
setFakeProperty(int index,const QVariant & value)1132 void QDesignerPropertySheet::setFakeProperty(int index, const QVariant &value)
1133 {
1134     Q_ASSERT(isFakeProperty(index));
1135 
1136     QVariant &v = d->m_fakeProperties[index];
1137 
1138     // set resource properties also (if we are going to have fake resource properties)
1139     if (value.canConvert<qdesigner_internal::PropertySheetFlagValue>() || value.canConvert<qdesigner_internal::PropertySheetEnumValue>()) {
1140         v = value;
1141     } else if (v.canConvert<qdesigner_internal::PropertySheetFlagValue>()) {
1142         qdesigner_internal::PropertySheetFlagValue f = qvariant_cast<qdesigner_internal::PropertySheetFlagValue>(v);
1143         f.value = value.toInt();
1144         v.setValue(f);
1145         Q_ASSERT(value.type() == QVariant::Int);
1146     } else if (v.canConvert<qdesigner_internal::PropertySheetEnumValue>()) {
1147         qdesigner_internal::PropertySheetEnumValue e = qvariant_cast<qdesigner_internal::PropertySheetEnumValue>(v);
1148         e.value = value.toInt();
1149         v.setValue(e);
1150         Q_ASSERT(value.type() == QVariant::Int);
1151     } else {
1152         v = value;
1153     }
1154 }
1155 
clearFakeProperties()1156 void QDesignerPropertySheet::clearFakeProperties()
1157 {
1158     d->m_fakeProperties.clear();
1159 }
1160 
1161 // Buddy needs to be byte array, else uic won't work
toByteArray(const QVariant & value)1162 static QVariant toByteArray(const QVariant &value) {
1163     if (value.type() == QVariant::ByteArray)
1164         return value;
1165     const QByteArray ba = value.toString().toUtf8();
1166     return QVariant(ba);
1167 }
1168 
setProperty(int index,const QVariant & value)1169 void QDesignerPropertySheet::setProperty(int index, const QVariant &value)
1170 {
1171     if (d->invalidIndex(Q_FUNC_INFO, index))
1172         return;
1173     if (isAdditionalProperty(index)) {
1174         if (d->m_objectType == ObjectLabel && propertyType(index) == PropertyBuddy) {
1175             QFormBuilderExtra::applyBuddy(value.toString(), QFormBuilderExtra::BuddyApplyVisibleOnly, qobject_cast<QLabel *>(d->m_object));
1176             d->m_addProperties[index] = toByteArray(value);
1177             return;
1178         }
1179 
1180         if (isFakeLayoutProperty(index)) {
1181             QDesignerPropertySheetExtension *layoutPropertySheet;
1182             if (d->layout(&layoutPropertySheet) && layoutPropertySheet) {
1183                 const QString newPropName = d->transformLayoutPropertyName(index);
1184                 if (!newPropName.isEmpty()) {
1185                     const int newIndex = layoutPropertySheet->indexOf(newPropName);
1186                     if (newIndex != -1)
1187                         layoutPropertySheet->setProperty(newIndex, value);
1188                 }
1189             }
1190         }
1191 
1192         if (isDynamicProperty(index) || isDefaultDynamicProperty(index)) {
1193             if (d->isResourceProperty(index))
1194                 d->setResourceProperty(index, value);
1195             if (d->isStringProperty(index))
1196                 d->setStringProperty(index, qvariant_cast<qdesigner_internal::PropertySheetStringValue>(value));
1197             if (d->isStringListProperty(index))
1198                 d->setStringListProperty(index, qvariant_cast<qdesigner_internal::PropertySheetStringListValue>(value));
1199             if (d->isKeySequenceProperty(index))
1200                 d->setKeySequenceProperty(index, qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(value));
1201             d->m_object->setProperty(propertyName(index).toUtf8(), resolvePropertyValue(index, value));
1202             if (d->m_object->isWidgetType()) {
1203                 QWidget *w = qobject_cast<QWidget *>(d->m_object);
1204                 w->setStyleSheet(w->styleSheet());
1205             }
1206         }
1207         d->m_addProperties[index] = value;
1208     } else if (isFakeProperty(index)) {
1209         setFakeProperty(index, value);
1210     } else {
1211         if (d->isResourceProperty(index))
1212             d->setResourceProperty(index, value);
1213         if (d->isStringProperty(index))
1214             d->setStringProperty(index, qvariant_cast<qdesigner_internal::PropertySheetStringValue>(value));
1215         if (d->isStringListProperty(index))
1216             d->setStringListProperty(index, qvariant_cast<qdesigner_internal::PropertySheetStringListValue>(value));
1217         if (d->isKeySequenceProperty(index))
1218             d->setKeySequenceProperty(index, qvariant_cast<qdesigner_internal::PropertySheetKeySequenceValue>(value));
1219         const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
1220         p->write(d->m_object, resolvePropertyValue(index, value));
1221         if (qobject_cast<QGroupBox *>(d->m_object) && propertyType(index) == PropertyCheckable) {
1222             const int idx = indexOf(QStringLiteral("focusPolicy"));
1223             if (!isChanged(idx)) {
1224                 qdesigner_internal::PropertySheetEnumValue e = qvariant_cast<qdesigner_internal::PropertySheetEnumValue>(property(idx));
1225                 if (value.toBool()) {
1226                     const QDesignerMetaPropertyInterface *p = d->m_meta->property(idx);
1227                     p->write(d->m_object, Qt::NoFocus);
1228                     e.value = Qt::StrongFocus;
1229                     QVariant v;
1230                     v.setValue(e);
1231                     setFakeProperty(idx, v);
1232                 } else {
1233                     e.value = Qt::NoFocus;
1234                     QVariant v;
1235                     v.setValue(e);
1236                     setFakeProperty(idx, v);
1237                 }
1238             }
1239         }
1240     }
1241 }
1242 
hasReset(int index) const1243 bool QDesignerPropertySheet::hasReset(int index) const
1244 {
1245     if (d->invalidIndex(Q_FUNC_INFO, index))
1246         return false;
1247     if (isAdditionalProperty(index))
1248         return d->m_info.value(index).reset;
1249     return true;
1250 }
1251 
reset(int index)1252 bool QDesignerPropertySheet::reset(int index)
1253 {
1254     if (d->invalidIndex(Q_FUNC_INFO, index))
1255         return false;
1256     if (d->isStringProperty(index)) {
1257         qdesigner_internal::PropertySheetStringValue value;
1258         // Main container: Reset to stored class name as not to change the file names generated by uic.
1259         if (propertyName(index) == QStringLiteral("objectName")) {
1260             const QVariant classNameDefaultV = d->m_object->property("_q_classname");
1261             if (classNameDefaultV.isValid())
1262                 value.setValue(classNameDefaultV.toString());
1263         } else if (!isAdditionalProperty(index)) {
1264             const QDesignerMetaPropertyInterface *property = d->m_meta->property(index);
1265             if ((property->accessFlags() & QDesignerMetaPropertyInterface::ResetAccess) && property->reset(d->m_object))
1266                 value.setValue(property->read(d->m_object).toString());
1267             else
1268                 return false;
1269         }
1270         setProperty(index, QVariant::fromValue(value));
1271         return true;
1272     }
1273     if (d->isStringListProperty(index))
1274         setProperty(index, QVariant::fromValue(qdesigner_internal::PropertySheetStringListValue()));
1275     if (d->isKeySequenceProperty(index))
1276         setProperty(index, QVariant::fromValue(qdesigner_internal::PropertySheetKeySequenceValue()));
1277     if (d->isResourceProperty(index)) {
1278         setProperty(index, d->emptyResourceProperty(index));
1279         return true;
1280     }
1281     if (isDynamic(index)) {
1282         const QString propName = propertyName(index);
1283         const QVariant oldValue = d->m_addProperties.value(index);
1284         const QVariant defaultValue = d->m_info.value(index).defaultValue;
1285         QVariant newValue = defaultValue;
1286         if (d->isStringProperty(index)) {
1287             newValue = QVariant::fromValue(qdesigner_internal::PropertySheetStringValue(newValue.toString()));
1288         } else if (d->isStringListProperty(index)) {
1289             newValue = QVariant::fromValue(qdesigner_internal::PropertySheetStringListValue(newValue.toStringList()));
1290         } else if (d->isKeySequenceProperty(index)) {
1291             const QKeySequence keySequence = qvariant_cast<QKeySequence>(newValue);
1292             newValue = QVariant::fromValue(qdesigner_internal::PropertySheetKeySequenceValue(keySequence));
1293         }
1294         if (oldValue == newValue)
1295             return true;
1296         d->m_object->setProperty(propName.toUtf8(), defaultValue);
1297         d->m_addProperties[index] = newValue;
1298         return true;
1299     } else if (!d->m_info.value(index).defaultValue.isNull()) {
1300         setProperty(index, d->m_info.value(index).defaultValue);
1301         return true;
1302     }
1303     if (isAdditionalProperty(index)) {
1304         const PropertyType pType = propertyType(index);
1305         if (d->m_objectType == ObjectLabel && pType == PropertyBuddy) {
1306             setProperty(index, QVariant(QByteArray()));
1307             return true;
1308         }
1309         if (isFakeLayoutProperty(index)) {
1310            // special properties
1311            switch (pType) {
1312            case PropertyLayoutObjectName:
1313               setProperty(index, QString());
1314               return true;
1315            case PropertyLayoutSizeConstraint:
1316               setProperty(index, QVariant(QLayout::SetDefaultConstraint));
1317               return true;
1318            case PropertyLayoutBoxStretch:
1319            case PropertyLayoutGridRowStretch:
1320            case PropertyLayoutGridColumnStretch:
1321            case PropertyLayoutGridRowMinimumHeight:
1322            case PropertyLayoutGridColumnMinimumWidth:
1323            case PropertyLayoutFieldGrowthPolicy:
1324            case PropertyLayoutRowWrapPolicy:
1325            case PropertyLayoutLabelAlignment:
1326            case PropertyLayoutFormAlignment: {
1327                QDesignerPropertySheetExtension *layoutPropertySheet;
1328                if (d->layout(&layoutPropertySheet) && layoutPropertySheet)
1329                    return layoutPropertySheet->reset(layoutPropertySheet->indexOf(d->transformLayoutPropertyName(index)));
1330            }
1331                break;
1332            default:
1333               break;
1334            }
1335            // special margins
1336             int value = -1;
1337             switch (d->m_objectType) {
1338             case ObjectLayoutWidget:
1339                 if (pType == PropertyLayoutLeftMargin ||
1340                         pType == PropertyLayoutTopMargin ||
1341                         pType == PropertyLayoutRightMargin ||
1342                         pType == PropertyLayoutBottomMargin)
1343                     value = 0;
1344                 break;
1345             default:
1346                 break;
1347             }
1348             setProperty(index, value);
1349             return true;
1350         }
1351         return false;
1352     }
1353     if (isFakeProperty(index)) {
1354         const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
1355         const bool result = p->reset(d->m_object);
1356         d->m_fakeProperties[index] = p->read(d->m_object);
1357         return result;
1358     }
1359     if (propertyType(index) == PropertyGeometry && d->m_object->isWidgetType()) {
1360         if (QWidget *w = qobject_cast<QWidget*>(d->m_object)) {
1361             QWidget *widget = w;
1362             if (qdesigner_internal::Utils::isCentralWidget(d->m_fwb, widget) && d->m_fwb->parentWidget())
1363                 widget = d->m_fwb->parentWidget();
1364 
1365             if (widget != w && widget->parentWidget()) {
1366                 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1367                 widget->parentWidget()->adjustSize();
1368             }
1369             QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1370             widget->adjustSize();
1371             return true;
1372         }
1373     }
1374     // ### TODO: reset for fake properties.
1375 
1376     const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
1377     return p->reset(d->m_object);
1378 }
1379 
isChanged(int index) const1380 bool QDesignerPropertySheet::isChanged(int index) const
1381 {
1382     if (d->invalidIndex(Q_FUNC_INFO, index))
1383         return false;
1384     if (isAdditionalProperty(index)) {
1385         if (isFakeLayoutProperty(index)) {
1386             QDesignerPropertySheetExtension *layoutPropertySheet;
1387             if (d->layout(&layoutPropertySheet) && layoutPropertySheet) {
1388                 const QString newPropName = d->transformLayoutPropertyName(index);
1389                 if (!newPropName.isEmpty()) {
1390                     const int newIndex = layoutPropertySheet->indexOf(newPropName);
1391                     if (newIndex != -1)
1392                         return layoutPropertySheet->isChanged(newIndex);
1393                     return false;
1394                 }
1395             }
1396         }
1397     }
1398     return d->m_info.value(index).changed;
1399 }
1400 
setChanged(int index,bool changed)1401 void QDesignerPropertySheet::setChanged(int index, bool changed)
1402 {
1403     if (d->invalidIndex(Q_FUNC_INFO, index))
1404         return;
1405     if (isAdditionalProperty(index)) {
1406         if (isFakeLayoutProperty(index)) {
1407             QDesignerPropertySheetExtension *layoutPropertySheet;
1408             if (d->layout(&layoutPropertySheet) && layoutPropertySheet) {
1409                 const QString newPropName = d->transformLayoutPropertyName(index);
1410                 if (!newPropName.isEmpty()) {
1411                     const int newIndex = layoutPropertySheet->indexOf(newPropName);
1412                     if (newIndex != -1)
1413                         layoutPropertySheet->setChanged(newIndex, changed);
1414                 }
1415             }
1416         }
1417     }
1418     if (d->isReloadableProperty(index)) {
1419         if (d->m_fwb) {
1420             if (changed)
1421                 d->m_fwb->addReloadableProperty(this, index);
1422             else
1423                 d->m_fwb->removeReloadableProperty(this, index);
1424         }
1425     }
1426     d->ensureInfo(index).changed = changed;
1427 }
1428 
isFakeLayoutProperty(int index) const1429 bool QDesignerPropertySheet::isFakeLayoutProperty(int index) const
1430 {
1431     if (!isAdditionalProperty(index))
1432         return false;
1433 
1434     switch (propertyType(index)) {
1435     case PropertyLayoutObjectName:
1436     case PropertyLayoutSizeConstraint:
1437         return true;
1438     case PropertyLayoutLeftMargin:
1439     case PropertyLayoutTopMargin:
1440     case PropertyLayoutRightMargin:
1441     case PropertyLayoutBottomMargin:
1442     case PropertyLayoutSpacing:
1443     case PropertyLayoutHorizontalSpacing:
1444     case PropertyLayoutVerticalSpacing:
1445     case PropertyLayoutFieldGrowthPolicy:
1446     case PropertyLayoutRowWrapPolicy:
1447     case PropertyLayoutLabelAlignment:
1448     case PropertyLayoutFormAlignment:
1449     case PropertyLayoutBoxStretch:
1450     case PropertyLayoutGridRowStretch:
1451     case PropertyLayoutGridColumnStretch:
1452     case PropertyLayoutGridRowMinimumHeight:
1453     case PropertyLayoutGridColumnMinimumWidth:
1454         return d->m_canHaveLayoutAttributes;
1455     default:
1456         break;
1457     }
1458     return false;
1459 }
1460 
1461 // Determine the "designable" state of a property. Properties, which have
1462 // a per-object boolean test function that returns false are shown in
1463 // disabled state ("checked" depending on "checkable", etc.)
1464 // Properties, which are generally not designable independent
1465 // of the object are not shown at all.
1466 enum DesignableState { PropertyIsDesignable,
1467                        // Object has a Designable test function that returns false.
1468                        PropertyOfObjectNotDesignable,
1469                        PropertyNotDesignable };
1470 
designableState(const QDesignerMetaPropertyInterface * p,const QObject * object)1471 static inline DesignableState designableState(const QDesignerMetaPropertyInterface *p, const QObject *object)
1472 {
1473     if (p->attributes(object) & QDesignerMetaPropertyInterface::DesignableAttribute)
1474         return PropertyIsDesignable;
1475     return (p->attributes() & QDesignerMetaPropertyInterface::DesignableAttribute) ?
1476             PropertyOfObjectNotDesignable : PropertyNotDesignable;
1477 }
1478 
isVisible(int index) const1479 bool QDesignerPropertySheet::isVisible(int index) const
1480 {
1481     if (d->invalidIndex(Q_FUNC_INFO, index))
1482         return false;
1483 
1484     const PropertyType type = propertyType(index);
1485     if (isAdditionalProperty(index)) {
1486         if (isFakeLayoutProperty(index) && d->m_object->isWidgetType()) {
1487             const QLayout *currentLayout = d->layout();
1488             if (!currentLayout)
1489                 return false;
1490             const int visibleMask = qdesigner_internal::LayoutProperties::visibleProperties(currentLayout);
1491             switch (type) {
1492             case  PropertyLayoutSpacing:
1493                 return visibleMask & qdesigner_internal::LayoutProperties::SpacingProperty;
1494             case PropertyLayoutHorizontalSpacing:
1495             case PropertyLayoutVerticalSpacing:
1496                 return visibleMask & qdesigner_internal::LayoutProperties::HorizSpacingProperty;
1497             case PropertyLayoutFieldGrowthPolicy:
1498                 return visibleMask & qdesigner_internal::LayoutProperties::FieldGrowthPolicyProperty;
1499             case PropertyLayoutRowWrapPolicy:
1500                 return visibleMask & qdesigner_internal::LayoutProperties::RowWrapPolicyProperty;
1501             case PropertyLayoutLabelAlignment:
1502                 return visibleMask & qdesigner_internal::LayoutProperties::LabelAlignmentProperty;
1503             case PropertyLayoutFormAlignment:
1504                 return visibleMask & qdesigner_internal::LayoutProperties::FormAlignmentProperty;
1505             case PropertyLayoutBoxStretch:
1506                 return visibleMask & qdesigner_internal::LayoutProperties::BoxStretchProperty;
1507             case PropertyLayoutGridRowStretch:
1508                 return visibleMask & qdesigner_internal::LayoutProperties::GridRowStretchProperty;
1509             case PropertyLayoutGridColumnStretch:
1510                 return visibleMask & qdesigner_internal::LayoutProperties::GridColumnStretchProperty;
1511             case PropertyLayoutGridRowMinimumHeight:
1512                 return visibleMask & qdesigner_internal::LayoutProperties::GridRowMinimumHeightProperty;
1513             case PropertyLayoutGridColumnMinimumWidth:
1514                 return visibleMask & qdesigner_internal::LayoutProperties::GridColumnMinimumWidthProperty;
1515             default:
1516                 break;
1517             }
1518             return true;
1519         }
1520         return d->m_info.value(index).visible;
1521     }
1522 
1523     if (isFakeProperty(index)) {
1524         switch (type) {
1525         case PropertyWindowModality: // Hidden for child widgets
1526         case PropertyWindowOpacity:
1527             return d->m_info.value(index).visible;
1528         default:
1529             break;
1530         }
1531         return true;
1532     }
1533 
1534     const bool visible = d->m_info.value(index).visible;
1535     switch (type) {
1536     case PropertyWindowTitle:
1537     case PropertyWindowIcon:
1538     case PropertyWindowFilePath:
1539     case PropertyWindowOpacity:
1540     case PropertyWindowIconText:
1541     case PropertyWindowModified:
1542         return visible;
1543     default:
1544         if (visible)
1545             return true;
1546         break;
1547     }
1548 
1549     const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
1550     if  (!(p->accessFlags() & QDesignerMetaPropertyInterface::WriteAccess))
1551          return false;
1552 
1553     // Enabled handling: Hide only statically not designable properties
1554     return designableState(p, d->m_object) != PropertyNotDesignable;
1555 }
1556 
setVisible(int index,bool visible)1557 void QDesignerPropertySheet::setVisible(int index, bool visible)
1558 {
1559     if (d->invalidIndex(Q_FUNC_INFO, index))
1560         return;
1561     d->ensureInfo(index).visible = visible;
1562 }
1563 
isEnabled(int index) const1564 bool QDesignerPropertySheet::isEnabled(int index) const
1565 {
1566     if (d->invalidIndex(Q_FUNC_INFO, index))
1567         return false;
1568     if (isAdditionalProperty(index))
1569         return true;
1570 
1571     if (isFakeProperty(index))
1572         return true;
1573 
1574     // Grey out geometry of laid-out widgets (including splitter)
1575     if (propertyType(index) == PropertyGeometry && d->m_object->isWidgetType()) {
1576         bool isManaged;
1577         const qdesigner_internal::LayoutInfo::Type lt = qdesigner_internal::LayoutInfo::laidoutWidgetType(d->m_core, qobject_cast<QWidget *>(d->m_object), &isManaged);
1578         return !isManaged || lt == qdesigner_internal::LayoutInfo::NoLayout;
1579     }
1580 
1581     if (d->m_info.value(index).visible)
1582         return true;
1583 
1584     // Enable setting of properties for statically non-designable properties
1585     // as this might be done via TaskMenu/Cursor::setProperty. Note that those
1586     // properties are not visible.
1587     const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
1588     if (!p->accessFlags().testFlag(QDesignerMetaPropertyInterface::WriteAccess))
1589         return false;
1590 
1591     if (designableState(p, d->m_object) == PropertyOfObjectNotDesignable)
1592         return false;
1593 
1594     const PropertyType type = propertyType(index);
1595     if (type == PropertyChecked && d->m_objectFlags.testFlag(CheckableProperty))
1596         return d->m_object->property("checkable").toBool();
1597     return true;
1598 }
1599 
isAttribute(int index) const1600 bool QDesignerPropertySheet::isAttribute(int index) const
1601 {
1602     if (d->invalidIndex(Q_FUNC_INFO, index))
1603         return false;
1604     if (isAdditionalProperty(index))
1605         return d->m_info.value(index).attribute;
1606 
1607     if (isFakeProperty(index))
1608         return false;
1609 
1610     return d->m_info.value(index).attribute;
1611 }
1612 
setAttribute(int index,bool attribute)1613 void QDesignerPropertySheet::setAttribute(int index, bool attribute)
1614 {
1615     if (d->invalidIndex(Q_FUNC_INFO, index))
1616         return;
1617     d->ensureInfo(index).attribute = attribute;
1618 }
1619 
core() const1620 QDesignerFormEditorInterface *QDesignerPropertySheet::core() const
1621 {
1622     return d->m_core;
1623 }
1624 
internalDynamicPropertiesEnabled()1625 bool QDesignerPropertySheet::internalDynamicPropertiesEnabled()
1626 {
1627     return QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled;
1628 }
1629 
setInternalDynamicPropertiesEnabled(bool v)1630 void QDesignerPropertySheet::setInternalDynamicPropertiesEnabled(bool v)
1631 {
1632     QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled = v;
1633 }
1634 
1635 // ---------- QDesignerAbstractPropertySheetFactory
1636 
1637 struct QDesignerAbstractPropertySheetFactory::PropertySheetFactoryPrivate {
1638     PropertySheetFactoryPrivate();
1639     const QString m_propertySheetId;
1640     const QString m_dynamicPropertySheetId;
1641 
1642     using ExtensionMap = QMap<QObject*, QObject*>;
1643     ExtensionMap m_extensions;
1644 };
1645 
PropertySheetFactoryPrivate()1646 QDesignerAbstractPropertySheetFactory::PropertySheetFactoryPrivate::PropertySheetFactoryPrivate() :
1647     m_propertySheetId(Q_TYPEID(QDesignerPropertySheetExtension)),
1648     m_dynamicPropertySheetId(Q_TYPEID(QDesignerDynamicPropertySheetExtension))
1649 {
1650 }
1651 
1652 // ---------- QDesignerAbstractPropertySheetFactory
1653 
1654 
QDesignerAbstractPropertySheetFactory(QExtensionManager * parent)1655 QDesignerAbstractPropertySheetFactory::QDesignerAbstractPropertySheetFactory(QExtensionManager *parent) :
1656     QExtensionFactory(parent),
1657     m_impl(new PropertySheetFactoryPrivate)
1658 {
1659 }
1660 
~QDesignerAbstractPropertySheetFactory()1661 QDesignerAbstractPropertySheetFactory::~QDesignerAbstractPropertySheetFactory()
1662 {
1663     delete m_impl;
1664 }
1665 
extension(QObject * object,const QString & iid) const1666 QObject *QDesignerAbstractPropertySheetFactory::extension(QObject *object, const QString &iid) const
1667 {
1668     if (!object)
1669         return nullptr;
1670 
1671     if (iid != m_impl->m_propertySheetId && iid != m_impl->m_dynamicPropertySheetId)
1672         return nullptr;
1673 
1674     QObject *ext = m_impl->m_extensions.value(object, 0);
1675     if (!ext && (ext = createPropertySheet(object, const_cast<QDesignerAbstractPropertySheetFactory*>(this)))) {
1676         connect(ext, &QObject::destroyed, this, &QDesignerAbstractPropertySheetFactory::objectDestroyed);
1677         connect(object, &QObject::destroyed, this, &QDesignerAbstractPropertySheetFactory::objectDestroyed);
1678         m_impl->m_extensions.insert(object, ext);
1679     }
1680 
1681     return ext;
1682 }
1683 
objectDestroyed(QObject * object)1684 void QDesignerAbstractPropertySheetFactory::objectDestroyed(QObject *object)
1685 {
1686     for (auto it = m_impl->m_extensions.begin(), end = m_impl->m_extensions.end(); it != end; /*erasing*/) {
1687         if (it.key() == object || it.value() == object) {
1688             if (it.key() == object) {
1689                 QObject *ext = it.value();
1690                 disconnect(ext, &QObject::destroyed, this, &QDesignerAbstractPropertySheetFactory::objectDestroyed);
1691                 delete ext;
1692             }
1693             it = m_impl->m_extensions.erase(it);
1694         } else {
1695             ++it;
1696         }
1697     }
1698 }
1699 
1700 QT_END_NAMESPACE
1701