source: trunk/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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