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