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

source code of qttools/src/designer/src/lib/shared/qdesigner_propertysheet.cpp