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