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