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