diff -r 000000000000 -r 1918ee327afb tools/designer/src/lib/shared/qdesigner_propertysheet.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,1628 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_propertysheet_p.h" +#include "qdesigner_utils_p.h" +#include "formwindowbase_p.h" +#include "layoutinfo_p.h" +#include "qlayout_widget_p.h" +#include "qdesigner_introspection_p.h" + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#define USE_LAYOUT_SIZE_CONSTRAINT + +static const QDesignerMetaObjectInterface *propertyIntroducedBy(const QDesignerMetaObjectInterface *meta, int index) +{ + if (index >= meta->propertyOffset()) + return meta; + + if (meta->superClass()) + return propertyIntroducedBy(meta->superClass(), index); + + return 0; +} + +// Layout fake properties (prefixed by 'layout' to distinguish them from other 'margins' +// that might be around. These are forwarded to the layout sheet (after name transformation). +// +// 'layoutObjectName' is new for 4.4. It is the name of the actual layout. +// Up to 4.3, QLayoutWidget's name was displayed in the objectinspector. +// This changes with 4.4; the layout name is displayed. This means that for +// old forms, QLayoutWidget will show up as ''; however, the uic code will +// still use 'verticalLayout' (in case someone accesses it). New Layouts get autogenerated names, +// legacy forms will keep their empty names (unless someone types in a new name). +static const char *layoutObjectNameC = "layoutName"; +static const char *layoutLeftMarginC = "layoutLeftMargin"; +static const char *layoutTopMarginC = "layoutTopMargin"; +static const char *layoutRightMarginC = "layoutRightMargin"; +static const char *layoutBottomMarginC = "layoutBottomMargin"; +static const char *layoutSpacingC = "layoutSpacing"; +static const char *layoutHorizontalSpacingC = "layoutHorizontalSpacing"; +static const char *layoutVerticalSpacingC = "layoutVerticalSpacing"; +static const char *layoutSizeConstraintC = "layoutSizeConstraint"; +// form layout +static const char *layoutFieldGrowthPolicyC = "layoutFieldGrowthPolicy"; +static const char *layoutRowWrapPolicyC = "layoutRowWrapPolicy"; +static const char *layoutLabelAlignmentC = "layoutLabelAlignment"; +static const char *layoutFormAlignmentC = "layoutFormAlignment"; +// stretches +static const char *layoutboxStretchPropertyC = "layoutStretch"; +static const char *layoutGridRowStretchPropertyC = "layoutRowStretch"; +static const char *layoutGridColumnStretchPropertyC = "layoutColumnStretch"; +static const char *layoutGridRowMinimumHeightC = "layoutRowMinimumHeight"; +static const char *layoutGridColumnMinimumWidthC = "layoutColumnMinimumWidth"; + +// Find the form editor in the hierarchy. +// We know that the parent of the sheet is the extension manager +// whose parent is the core. + +static QDesignerFormEditorInterface *formEditorForObject(QObject *o) { + do { + if (QDesignerFormEditorInterface* core = qobject_cast(o)) + return core; + o = o->parent(); + } while(o); + Q_ASSERT(o); + return 0; +} + +static bool hasLayoutAttributes(QDesignerFormEditorInterface *core, QObject *object) +{ + if (!object->isWidgetType()) + return false; + + QWidget *w = qobject_cast(object); + if (const QDesignerWidgetDataBaseInterface *db = core->widgetDataBase()) { + if (db->isContainer(w)) + return true; + } + return false; +} + +// Cache DesignerMetaEnum by scope/name of a QMetaEnum +static const qdesigner_internal::DesignerMetaEnum &designerMetaEnumFor(const QDesignerMetaEnumInterface *me) +{ + typedef QPair ScopeNameKey; + typedef QMap DesignerMetaEnumCache; + static DesignerMetaEnumCache cache; + + const QString name = me->name(); + const QString scope = me->scope(); + + const ScopeNameKey key = ScopeNameKey(scope, name); + DesignerMetaEnumCache::iterator it = cache.find(key); + if (it == cache.end()) { + qdesigner_internal::DesignerMetaEnum dme = qdesigner_internal::DesignerMetaEnum(name, scope, me->separator()); + const int keyCount = me->keyCount(); + for (int i=0; i < keyCount; ++i) + dme.addKey(me->value(i), me->key(i)); + it = cache.insert(key, dme); + } + return it.value(); +} + +// Cache DesignerMetaFlags by scope/name of a QMetaEnum +static const qdesigner_internal::DesignerMetaFlags &designerMetaFlagsFor(const QDesignerMetaEnumInterface *me) +{ + typedef QPair ScopeNameKey; + typedef QMap DesignerMetaFlagsCache; + static DesignerMetaFlagsCache cache; + + const QString name = me->name(); + const QString scope = me->scope(); + + const ScopeNameKey key = ScopeNameKey(scope, name); + DesignerMetaFlagsCache::iterator it = cache.find(key); + if (it == cache.end()) { + qdesigner_internal::DesignerMetaFlags dme = qdesigner_internal::DesignerMetaFlags(name, scope, me->separator()); + const int keyCount = me->keyCount(); + for (int i=0; i < keyCount; ++i) + dme.addKey(me->value(i), me->key(i)); + it = cache.insert(key, dme); + } + return it.value(); +} + +// ------------ QDesignerMemberSheetPrivate +class QDesignerPropertySheetPrivate { +public: + typedef QDesignerPropertySheet::PropertyType PropertyType; + typedef QDesignerPropertySheet::ObjectType ObjectType; + + explicit QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent); + + bool invalidIndex(const char *functionName, int index) const; + inline int count() const { return m_meta->propertyCount() + m_addProperties.count(); } + + PropertyType propertyType(int index) const; + QString transformLayoutPropertyName(int index) const; + QLayout* layout(QDesignerPropertySheetExtension **layoutPropertySheet = 0) const; + static ObjectType objectType(const QObject *o); + + bool isReloadableProperty(int index) const; + bool isResourceProperty(int index) const; + void addResourceProperty(int index, QVariant::Type type); + QVariant resourceProperty(int index) const; + void setResourceProperty(int index, const QVariant &value); + QVariant emptyResourceProperty(int index) const; // of type PropertySheetPixmapValue / PropertySheetIconValue + QVariant defaultResourceProperty(int index) const; // of type QPixmap / QIcon (maybe it can be generalized for all types, not resource only) + + bool isStringProperty(int index) const; + void addStringProperty(int index); + qdesigner_internal::PropertySheetStringValue stringProperty(int index) const; + void setStringProperty(int index, const qdesigner_internal::PropertySheetStringValue &value); + + bool isKeySequenceProperty(int index) const; + void addKeySequenceProperty(int index); + qdesigner_internal::PropertySheetKeySequenceValue keySequenceProperty(int index) const; + void setKeySequenceProperty(int index, const qdesigner_internal::PropertySheetKeySequenceValue &value); + + enum PropertyKind { NormalProperty, FakeProperty, DynamicProperty, DefaultDynamicProperty }; + class Info { + public: + Info(); + + QString group; + QVariant defaultValue; + bool changed; + bool visible; + bool attribute; + bool reset; + PropertyType propertyType; + PropertyKind kind; + }; + + Info &ensureInfo(int index); + + QDesignerPropertySheet *q; + QDesignerFormEditorInterface *m_core; + const QDesignerMetaObjectInterface *m_meta; + const ObjectType m_objectType; + + typedef QHash InfoHash; + InfoHash m_info; + QHash m_fakeProperties; + QHash m_addProperties; + QHash m_addIndex; + QHash m_resourceProperties; // only PropertySheetPixmapValue snd PropertySheetIconValue here + QHash m_stringProperties; // only PropertySheetStringValue + QHash m_keySequenceProperties; // only PropertySheetKeySequenceValue + + const bool m_canHaveLayoutAttributes; + + // Variables used for caching the layout, access via layout(). + QPointer m_object; + mutable QPointer m_lastLayout; + mutable QDesignerPropertySheetExtension *m_lastLayoutPropertySheet; + mutable bool m_LastLayoutByDesigner; + + qdesigner_internal::DesignerPixmapCache *m_pixmapCache; + qdesigner_internal::DesignerIconCache *m_iconCache; + QPointer m_fwb; + + // Enable Qt's internal properties starting with prefix "_q_" + static bool m_internalDynamicPropertiesEnabled; +}; + +bool QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled = false; + +/* + The property is reloadable if its contents depends on resource. +*/ +bool QDesignerPropertySheetPrivate::isReloadableProperty(int index) const +{ + return isResourceProperty(index) + || propertyType(index) == QDesignerPropertySheet::PropertyStyleSheet + || q->property(index).type() == QVariant::Url; +} + +/* + Resource properties are those which: + 1) are reloadable + 2) their state is associated with a file which can be taken from resources + 3) we don't store them in Qt meta object system (because designer keeps different data structure for them) +*/ + +bool QDesignerPropertySheetPrivate::isResourceProperty(int index) const +{ + return m_resourceProperties.contains(index); +} + +void QDesignerPropertySheetPrivate::addResourceProperty(int index, QVariant::Type type) +{ + if (type == QVariant::Pixmap) + m_resourceProperties.insert(index, qVariantFromValue(qdesigner_internal::PropertySheetPixmapValue())); + else if (type == QVariant::Icon) + m_resourceProperties.insert(index, qVariantFromValue(qdesigner_internal::PropertySheetIconValue())); +} + +QVariant QDesignerPropertySheetPrivate::emptyResourceProperty(int index) const +{ + QVariant v = m_resourceProperties.value(index); + if (qVariantCanConvert(v)) + return qVariantFromValue(qdesigner_internal::PropertySheetPixmapValue()); + if (qVariantCanConvert(v)) + return qVariantFromValue(qdesigner_internal::PropertySheetIconValue()); + return v; +} + +QVariant QDesignerPropertySheetPrivate::defaultResourceProperty(int index) const +{ + return m_info.value(index).defaultValue; +} + +QVariant QDesignerPropertySheetPrivate::resourceProperty(int index) const +{ + return m_resourceProperties.value(index); +} + +void QDesignerPropertySheetPrivate::setResourceProperty(int index, const QVariant &value) +{ + Q_ASSERT(isResourceProperty(index)); + + QVariant &v = m_resourceProperties[index]; + if ((qVariantCanConvert(value) && qVariantCanConvert(v)) + || (qVariantCanConvert(value) && qVariantCanConvert(v))) + v = value; +} + +bool QDesignerPropertySheetPrivate::isStringProperty(int index) const +{ + return m_stringProperties.contains(index); +} + +void QDesignerPropertySheetPrivate::addStringProperty(int index) +{ + m_stringProperties.insert(index, qdesigner_internal::PropertySheetStringValue()); +} + +qdesigner_internal::PropertySheetStringValue QDesignerPropertySheetPrivate::stringProperty(int index) const +{ + return m_stringProperties.value(index); +} + +void QDesignerPropertySheetPrivate::setStringProperty(int index, const qdesigner_internal::PropertySheetStringValue &value) +{ + Q_ASSERT(isStringProperty(index)); + + m_stringProperties[index] = value; +} + +bool QDesignerPropertySheetPrivate::isKeySequenceProperty(int index) const +{ + return m_keySequenceProperties.contains(index); +} + +void QDesignerPropertySheetPrivate::addKeySequenceProperty(int index) +{ + m_keySequenceProperties.insert(index, qdesigner_internal::PropertySheetKeySequenceValue()); +} + +qdesigner_internal::PropertySheetKeySequenceValue QDesignerPropertySheetPrivate::keySequenceProperty(int index) const +{ + return m_keySequenceProperties.value(index); +} + +void QDesignerPropertySheetPrivate::setKeySequenceProperty(int index, const qdesigner_internal::PropertySheetKeySequenceValue &value) +{ + Q_ASSERT(isKeySequenceProperty(index)); + + m_keySequenceProperties[index] = value; +} + +QDesignerPropertySheetPrivate::Info::Info() : + changed(false), + visible(true), + attribute(false), + reset(true), + propertyType(QDesignerPropertySheet::PropertyNone), + kind(NormalProperty) +{ +} + +QDesignerPropertySheetPrivate::QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent) : + q(sheetPublic), + m_core(formEditorForObject(sheetParent)), + m_meta(m_core->introspection()->metaObject(object)), + m_objectType(QDesignerPropertySheet::objectTypeFromObject(object)), + m_canHaveLayoutAttributes(hasLayoutAttributes(m_core, object)), + m_object(object), + m_lastLayout(0), + m_lastLayoutPropertySheet(0), + m_LastLayoutByDesigner(false), + m_pixmapCache(0), + m_iconCache(0) +{ +} + +qdesigner_internal::FormWindowBase *QDesignerPropertySheet::formWindowBase() const +{ + return d->m_fwb; +} + +bool QDesignerPropertySheetPrivate::invalidIndex(const char *functionName, int index) const +{ + if (index < 0 || index >= count()) { + qWarning() << "** WARNING " << functionName << " invoked for " << m_object->objectName() << " was passed an invalid index " << index << '.'; + return true; + } + return false; +} + +QLayout* QDesignerPropertySheetPrivate::layout(QDesignerPropertySheetExtension **layoutPropertySheet) const +{ + // Return the layout and its property sheet + // only if it is managed by designer and not one created on a custom widget. + // (attempt to cache the value as this requires some hoops). + if (layoutPropertySheet) + *layoutPropertySheet = 0; + + if (!m_object->isWidgetType() || !m_canHaveLayoutAttributes) + return 0; + + QWidget *widget = qobject_cast(m_object); + QLayout *widgetLayout = qdesigner_internal::LayoutInfo::internalLayout(widget); + if (!widgetLayout) { + m_lastLayout = 0; + m_lastLayoutPropertySheet = 0; + return 0; + } + // Smart logic to avoid retrieving the meta DB from the widget every time. + if (widgetLayout != m_lastLayout) { + m_lastLayout = widgetLayout; + m_LastLayoutByDesigner = false; + m_lastLayoutPropertySheet = 0; + // Is this a layout managed by designer or some layout on a custom widget? + if (qdesigner_internal::LayoutInfo::managedLayout(m_core ,widgetLayout)) { + m_LastLayoutByDesigner = true; + m_lastLayoutPropertySheet = qt_extension(m_core->extensionManager(), m_lastLayout); + } + } + if (!m_LastLayoutByDesigner) + return 0; + + if (layoutPropertySheet) + *layoutPropertySheet = m_lastLayoutPropertySheet; + + return m_lastLayout; +} + +QDesignerPropertySheetPrivate::Info &QDesignerPropertySheetPrivate::ensureInfo(int index) +{ + InfoHash::iterator it = m_info.find(index); + if (it == m_info.end()) + it = m_info.insert(index, Info()); + return it.value(); +} + +QDesignerPropertySheet::PropertyType QDesignerPropertySheetPrivate::propertyType(int index) const +{ + const InfoHash::const_iterator it = m_info.constFind(index); + if (it == m_info.constEnd()) + return QDesignerPropertySheet::PropertyNone; + return it.value().propertyType; +} + +QString QDesignerPropertySheetPrivate::transformLayoutPropertyName(int index) const +{ + typedef QMap TypeNameMap; + static TypeNameMap typeNameMap; + if (typeNameMap.empty()) { + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutObjectName, QLatin1String("objectName")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutLeftMargin, QLatin1String("leftMargin")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutTopMargin, QLatin1String("topMargin")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutRightMargin, QLatin1String("rightMargin")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutBottomMargin, QLatin1String("bottomMargin")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutSpacing, QLatin1String("spacing")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutHorizontalSpacing, QLatin1String("horizontalSpacing")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutVerticalSpacing, QLatin1String("verticalSpacing")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutSizeConstraint, QLatin1String("sizeConstraint")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutFieldGrowthPolicy, QLatin1String("fieldGrowthPolicy")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutRowWrapPolicy, QLatin1String("rowWrapPolicy")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutLabelAlignment, QLatin1String("labelAlignment")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutFormAlignment, QLatin1String("formAlignment")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutBoxStretch, QLatin1String("stretch")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridRowStretch, QLatin1String("rowStretch")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridColumnStretch, QLatin1String("columnStretch")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridRowMinimumHeight, QLatin1String("rowMinimumHeight")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridColumnMinimumWidth, QLatin1String("columnMinimumWidth")); + } + const TypeNameMap::const_iterator it = typeNameMap.constFind(propertyType(index)); + if (it != typeNameMap.constEnd()) + return it.value(); + return QString(); +} + +// ----------- QDesignerPropertySheet + +QDesignerPropertySheet::ObjectType QDesignerPropertySheet::objectTypeFromObject(const QObject *o) +{ + if (qobject_cast(o)) + return ObjectLayout; + + if (!o->isWidgetType()) + return ObjectNone; + + if (qobject_cast(o)) + return ObjectLayoutWidget; + + if (qobject_cast(o)) + return ObjectLabel; + + if (o->inherits("Q3GroupBox")) + return ObjectQ3GroupBox; + + return ObjectNone; +} + +QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyTypeFromName(const QString &name) +{ + typedef QHash PropertyTypeHash; + static PropertyTypeHash propertyTypeHash; + if (propertyTypeHash.empty()) { + propertyTypeHash.insert(QLatin1String(layoutObjectNameC), PropertyLayoutObjectName); + propertyTypeHash.insert(QLatin1String(layoutLeftMarginC), PropertyLayoutLeftMargin); + propertyTypeHash.insert(QLatin1String(layoutTopMarginC), PropertyLayoutTopMargin); + propertyTypeHash.insert(QLatin1String(layoutRightMarginC), PropertyLayoutRightMargin); + propertyTypeHash.insert(QLatin1String(layoutBottomMarginC), PropertyLayoutBottomMargin); + propertyTypeHash.insert(QLatin1String(layoutSpacingC), PropertyLayoutSpacing); + propertyTypeHash.insert(QLatin1String(layoutHorizontalSpacingC), PropertyLayoutHorizontalSpacing); + propertyTypeHash.insert(QLatin1String(layoutVerticalSpacingC), PropertyLayoutVerticalSpacing); + propertyTypeHash.insert(QLatin1String(layoutSizeConstraintC), PropertyLayoutSizeConstraint); + propertyTypeHash.insert(QLatin1String(layoutFieldGrowthPolicyC), PropertyLayoutFieldGrowthPolicy); + propertyTypeHash.insert(QLatin1String(layoutRowWrapPolicyC), PropertyLayoutRowWrapPolicy); + propertyTypeHash.insert(QLatin1String(layoutLabelAlignmentC), PropertyLayoutLabelAlignment); + propertyTypeHash.insert(QLatin1String(layoutFormAlignmentC), PropertyLayoutFormAlignment); + propertyTypeHash.insert(QLatin1String(layoutboxStretchPropertyC), PropertyLayoutBoxStretch); + propertyTypeHash.insert(QLatin1String(layoutGridRowStretchPropertyC), PropertyLayoutGridRowStretch); + propertyTypeHash.insert(QLatin1String(layoutGridColumnStretchPropertyC), PropertyLayoutGridColumnStretch); + propertyTypeHash.insert(QLatin1String(layoutGridRowMinimumHeightC), PropertyLayoutGridRowMinimumHeight); + propertyTypeHash.insert(QLatin1String(layoutGridColumnMinimumWidthC), PropertyLayoutGridColumnMinimumWidth); + propertyTypeHash.insert(QLatin1String("buddy"), PropertyBuddy); + propertyTypeHash.insert(QLatin1String("geometry"), PropertyGeometry); + propertyTypeHash.insert(QLatin1String("checkable"), PropertyCheckable); + propertyTypeHash.insert(QLatin1String("accessibleName"), PropertyAccessibility); + propertyTypeHash.insert(QLatin1String("accessibleDescription"), PropertyAccessibility); + propertyTypeHash.insert(QLatin1String("windowTitle"), PropertyWindowTitle); + propertyTypeHash.insert(QLatin1String("windowIcon"), PropertyWindowIcon); + propertyTypeHash.insert(QLatin1String("windowFilePath"), PropertyWindowFilePath); + propertyTypeHash.insert(QLatin1String("windowOpacity"), PropertyWindowOpacity); + propertyTypeHash.insert(QLatin1String("windowIconText"), PropertyWindowIconText); + propertyTypeHash.insert(QLatin1String("windowModality"), PropertyWindowModality); + propertyTypeHash.insert(QLatin1String("windowModified"), PropertyWindowModified); + propertyTypeHash.insert(QLatin1String("styleSheet"), PropertyStyleSheet); + } + return propertyTypeHash.value(name, PropertyNone); +} + +QDesignerPropertySheet::QDesignerPropertySheet(QObject *object, QObject *parent) : + QObject(parent), + d(new QDesignerPropertySheetPrivate(this, object, parent)) +{ + typedef QDesignerPropertySheetPrivate::Info Info; + const QDesignerMetaObjectInterface *baseMeta = d->m_meta; + + while (baseMeta &&baseMeta->className().startsWith(QLatin1String("QDesigner"))) { + baseMeta = baseMeta->superClass(); + } + Q_ASSERT(baseMeta != 0); + + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(d->m_object); + d->m_fwb = qobject_cast(formWindow); + if (d->m_fwb) { + d->m_pixmapCache = d->m_fwb->pixmapCache(); + d->m_iconCache = d->m_fwb->iconCache(); + d->m_fwb->addReloadablePropertySheet(this, object); + } + + for (int index=0; indexm_meta->property(index); + const QString name = p->name(); + if (p->type() == QVariant::KeySequence) { + createFakeProperty(name); + } else { + setVisible(index, false); // use the default for `real' properties + } + + QString pgroup = baseMeta->className(); + + if (const QDesignerMetaObjectInterface *pmeta = propertyIntroducedBy(baseMeta, index)) { + pgroup = pmeta->className(); + } + + Info &info = d->ensureInfo(index); + info.group = pgroup; + info.propertyType = propertyTypeFromName(name); + + if (p->type() == QVariant::Cursor || p->type() == QVariant::Icon || p->type() == QVariant::Pixmap) { + info.defaultValue = p->read(d->m_object); + if (p->type() == QVariant::Icon || p->type() == QVariant::Pixmap) + d->addResourceProperty(index, p->type()); + } else if (p->type() == QVariant::String) { + d->addStringProperty(index); + } else if (p->type() == QVariant::KeySequence) { + d->addKeySequenceProperty(index); + } + } + + if (object->isWidgetType()) { + createFakeProperty(QLatin1String("focusPolicy")); + createFakeProperty(QLatin1String("cursor")); + createFakeProperty(QLatin1String("toolTip")); + createFakeProperty(QLatin1String("whatsThis")); + createFakeProperty(QLatin1String("acceptDrops")); + createFakeProperty(QLatin1String("dragEnabled")); + // windowModality is visible only for the main container, in which case the form windows enables it on loading + setVisible(createFakeProperty(QLatin1String("windowModality")), false); + if (qobject_cast(d->m_object)) { // prevent toolbars from being dragged off + createFakeProperty(QLatin1String("floatable"), QVariant(true)); + } else { + if (qobject_cast(d->m_object)) { + // Keep the menu bar editable in the form even if a native menu bar is used. + const bool nativeMenuBarDefault = !qApp->testAttribute(Qt::AA_DontUseNativeMenuBar); + createFakeProperty(QLatin1String("nativeMenuBar"), QVariant(nativeMenuBarDefault)); + } + } + if (d->m_canHaveLayoutAttributes) { + static const QString layoutGroup = QLatin1String("Layout"); + const char* fakeLayoutProperties[] = { + layoutObjectNameC, layoutLeftMarginC, layoutTopMarginC, layoutRightMarginC, layoutBottomMarginC, layoutSpacingC, layoutHorizontalSpacingC, layoutVerticalSpacingC, + layoutFieldGrowthPolicyC, layoutRowWrapPolicyC, layoutLabelAlignmentC, layoutFormAlignmentC, + layoutboxStretchPropertyC, layoutGridRowStretchPropertyC, layoutGridColumnStretchPropertyC, + layoutGridRowMinimumHeightC, layoutGridColumnMinimumWidthC +#ifdef USE_LAYOUT_SIZE_CONSTRAINT + , layoutSizeConstraintC +#endif + }; + const int fakeLayoutPropertyCount = sizeof(fakeLayoutProperties)/sizeof(const char*); + const int size = count(); + for (int i = 0; i < fakeLayoutPropertyCount; i++) { + createFakeProperty(QLatin1String(fakeLayoutProperties[i]), 0); + setAttribute(size + i, true); + setPropertyGroup(size + i, layoutGroup); + } + } + + if (d->m_objectType == ObjectLabel) + createFakeProperty(QLatin1String("buddy"), QVariant(QByteArray())); + /* We need to create a fake property since the property does not work + * for non-toplevel windows or on other systems than Mac and only if + * it is above a certain Mac OS version. */ + if (qobject_cast(d->m_object)) + createFakeProperty(QLatin1String("unifiedTitleAndToolBarOnMac"), false); + } + + if (qobject_cast(object)) { + createFakeProperty(QLatin1String("modal")); + } + if (qobject_cast(object)) { + createFakeProperty(QLatin1String("floating")); + } + + typedef QList ByteArrayList; + const ByteArrayList names = object->dynamicPropertyNames(); + if (!names.empty()) { + const ByteArrayList::const_iterator cend = names.constEnd(); + for (ByteArrayList::const_iterator it = names.constBegin(); it != cend; ++it) { + const char* cName = it->constData(); + const QString name = QString::fromLatin1(cName); + const int idx = addDynamicProperty(name, object->property(cName)); + if (idx != -1) + d->ensureInfo(idx).kind = QDesignerPropertySheetPrivate::DefaultDynamicProperty; + } + } +} + +QDesignerPropertySheet::~QDesignerPropertySheet() +{ + if (d->m_fwb) + d->m_fwb->removeReloadablePropertySheet(this); + delete d; +} + +QObject *QDesignerPropertySheet::object() const +{ + return d->m_object; +} + +bool QDesignerPropertySheet::dynamicPropertiesAllowed() const +{ + return true; +} + +bool QDesignerPropertySheet::canAddDynamicProperty(const QString &propName) const +{ + const int index = d->m_meta->indexOfProperty(propName); + if (index != -1) + return false; // property already exists and is not a dynamic one + if (d->m_addIndex.contains(propName)) { + const int idx = d->m_addIndex.value(propName); + if (isVisible(idx)) + return false; // dynamic property already exists + else + return true; + } + if (!QDesignerPropertySheet::internalDynamicPropertiesEnabled() && propName.startsWith(QLatin1String("_q_"))) + return false; + return true; +} + +int QDesignerPropertySheet::addDynamicProperty(const QString &propName, const QVariant &value) +{ + typedef QDesignerPropertySheetPrivate::Info Info; + if (!value.isValid()) + return -1; // property has invalid type + if (!canAddDynamicProperty(propName)) + return -1; + + QVariant v = value; + if (value.type() == QVariant::Icon) + v = qVariantFromValue(qdesigner_internal::PropertySheetIconValue()); + else if (value.type() == QVariant::Pixmap) + v = qVariantFromValue(qdesigner_internal::PropertySheetPixmapValue()); + else if (value.type() == QVariant::String) + v = qVariantFromValue(qdesigner_internal::PropertySheetStringValue()); + else if (value.type() == QVariant::KeySequence) + v = qVariantFromValue(qdesigner_internal::PropertySheetKeySequenceValue()); + + + if (d->m_addIndex.contains(propName)) { + const int idx = d->m_addIndex.value(propName); + // have to be invisible, this was checked in canAddDynamicProperty() method + setVisible(idx, true); + d->m_addProperties.insert(idx, v); + setChanged(idx, false); + const int index = d->m_meta->indexOfProperty(propName); + Info &info = d->ensureInfo(index); + info.defaultValue = value; + info.kind = QDesignerPropertySheetPrivate::DynamicProperty; + if (value.type() == QVariant::Icon || value.type() == QVariant::Pixmap) + d->addResourceProperty(idx, value.type()); + else if (value.type() == QVariant::String) + d->addStringProperty(idx); + else if (value.type() == QVariant::KeySequence) + d->addKeySequenceProperty(idx); + return idx; + } + + const int index = count(); + d->m_addIndex.insert(propName, index); + d->m_addProperties.insert(index, v); + Info &info = d->ensureInfo(index); + info.visible = true; + info.changed = false; + info.defaultValue = value; + info.kind = QDesignerPropertySheetPrivate::DynamicProperty; + setPropertyGroup(index, tr("Dynamic Properties")); + if (value.type() == QVariant::Icon || value.type() == QVariant::Pixmap) + d->addResourceProperty(index, value.type()); + else if (value.type() == QVariant::String) + d->addStringProperty(index); + else if (value.type() == QVariant::KeySequence) + d->addKeySequenceProperty(index); + return index; +} + +bool QDesignerPropertySheet::removeDynamicProperty(int index) +{ + if (!d->m_addIndex.contains(propertyName(index))) + return false; + + setVisible(index, false); + return true; +} + +bool QDesignerPropertySheet::isDynamic(int index) const +{ + if (!d->m_addProperties.contains(index)) + return false; + + switch (propertyType(index)) { + case PropertyBuddy: + if (d->m_objectType == ObjectLabel) + return false; + break; + case PropertyLayoutLeftMargin: + case PropertyLayoutTopMargin: + case PropertyLayoutRightMargin: + case PropertyLayoutBottomMargin: + case PropertyLayoutSpacing: + case PropertyLayoutHorizontalSpacing: + case PropertyLayoutVerticalSpacing: + case PropertyLayoutObjectName: + case PropertyLayoutSizeConstraint: + case PropertyLayoutFieldGrowthPolicy: + case PropertyLayoutRowWrapPolicy: + case PropertyLayoutLabelAlignment: + case PropertyLayoutFormAlignment: + case PropertyLayoutBoxStretch: + case PropertyLayoutGridRowStretch: + case PropertyLayoutGridColumnStretch: + case PropertyLayoutGridRowMinimumHeight: + case PropertyLayoutGridColumnMinimumWidth: + if (d->m_object->isWidgetType() && d->m_canHaveLayoutAttributes) + return false; + default: + break; + } + return true; +} + +bool QDesignerPropertySheet::isDynamicProperty(int index) const +{ + // Do not complain here, as an invalid index might be encountered + // if someone implements a property sheet only, omitting the dynamic sheet. + if (index < 0 || index >= count()) + return false; + return d->m_info.value(index).kind == QDesignerPropertySheetPrivate::DynamicProperty; +} + +bool QDesignerPropertySheet::isDefaultDynamicProperty(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + return d->m_info.value(index).kind == QDesignerPropertySheetPrivate::DefaultDynamicProperty; +} + +bool QDesignerPropertySheet::isResourceProperty(int index) const +{ + return d->isResourceProperty(index); +} + +QVariant QDesignerPropertySheet::defaultResourceProperty(int index) const +{ + return d->defaultResourceProperty(index); +} + +qdesigner_internal::DesignerPixmapCache *QDesignerPropertySheet::pixmapCache() const +{ + return d->m_pixmapCache; +} + +void QDesignerPropertySheet::setPixmapCache(qdesigner_internal::DesignerPixmapCache *cache) +{ + d->m_pixmapCache = cache; +} + +qdesigner_internal::DesignerIconCache *QDesignerPropertySheet::iconCache() const +{ + return d->m_iconCache; +} + +void QDesignerPropertySheet::setIconCache(qdesigner_internal::DesignerIconCache *cache) +{ + d->m_iconCache = cache; +} + +int QDesignerPropertySheet::createFakeProperty(const QString &propertyName, const QVariant &value) +{ + typedef QDesignerPropertySheetPrivate::Info Info; + // fake properties + const int index = d->m_meta->indexOfProperty(propertyName); + if (index != -1) { + if (!(d->m_meta->property(index)->attributes() & QDesignerMetaPropertyInterface::DesignableAttribute)) + return -1; + Info &info = d->ensureInfo(index); + info.visible = false; + info.kind = QDesignerPropertySheetPrivate::FakeProperty; + QVariant v = value.isValid() ? value : metaProperty(index); + if (v.type() == QVariant::String) + v = qVariantFromValue(qdesigner_internal::PropertySheetStringValue()); + if (v.type() == QVariant::KeySequence) + v = qVariantFromValue(qdesigner_internal::PropertySheetKeySequenceValue()); + d->m_fakeProperties.insert(index, v); + return index; + } + if (!value.isValid()) + return -1; + + const int newIndex = count(); + d->m_addIndex.insert(propertyName, newIndex); + d->m_addProperties.insert(newIndex, value); + Info &info = d->ensureInfo(newIndex); + info.propertyType = propertyTypeFromName(propertyName); + info.kind = QDesignerPropertySheetPrivate::FakeProperty; + return newIndex; +} + +bool QDesignerPropertySheet::isAdditionalProperty(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + return d->m_addProperties.contains(index); +} + +bool QDesignerPropertySheet::isFakeProperty(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + // additional properties must be fake + return (d->m_fakeProperties.contains(index) || isAdditionalProperty(index)); +} + +int QDesignerPropertySheet::count() const +{ + return d->count(); +} + +int QDesignerPropertySheet::indexOf(const QString &name) const +{ + int index = d->m_meta->indexOfProperty(name); + + if (index == -1) + index = d->m_addIndex.value(name, -1); + + return index; +} + +QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyType(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return PropertyNone; + return d->propertyType(index); +} + +QDesignerPropertySheet::ObjectType QDesignerPropertySheet::objectType() const +{ + return d->m_objectType; +} + +QString QDesignerPropertySheet::propertyName(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return QString(); + if (isAdditionalProperty(index)) + return d->m_addIndex.key(index); + + return d->m_meta->property(index)->name(); +} + +QString QDesignerPropertySheet::propertyGroup(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return QString(); + const QString g = d->m_info.value(index).group; + + if (!g.isEmpty()) + return g; + + if (propertyType(index) == PropertyAccessibility) + return QString::fromUtf8("Accessibility"); + + if (isAdditionalProperty(index)) + return d->m_meta->className(); + + return g; +} + +void QDesignerPropertySheet::setPropertyGroup(int index, const QString &group) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return; + d->ensureInfo(index).group = group; +} + +QVariant QDesignerPropertySheet::property(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return QVariant(); + if (isAdditionalProperty(index)) { + if (isFakeLayoutProperty(index)) { + QDesignerPropertySheetExtension *layoutPropertySheet; + if (d->layout(&layoutPropertySheet) && layoutPropertySheet) { + const QString newPropName = d->transformLayoutPropertyName(index); + if (!newPropName.isEmpty()) { + const int newIndex = layoutPropertySheet->indexOf(newPropName); + if (newIndex != -1) + return layoutPropertySheet->property(newIndex); + return QVariant(); + } + } + } + return d->m_addProperties.value(index); + } + + if (isFakeProperty(index)) { + return d->m_fakeProperties.value(index); + } + + if (d->isResourceProperty(index)) + return d->resourceProperty(index); + + if (d->isStringProperty(index)) { + QString strValue = metaProperty(index).toString(); + qdesigner_internal::PropertySheetStringValue value = d->stringProperty(index); + if (strValue != value.value()) { + value.setValue(strValue); + d->setStringProperty(index, value); // cache it + } + return qVariantFromValue(value); + } + + if (d->isKeySequenceProperty(index)) { + QKeySequence keyValue = qVariantValue(metaProperty(index)); + qdesigner_internal::PropertySheetKeySequenceValue value = d->keySequenceProperty(index); + if (keyValue != value.value()) { + value.setValue(keyValue); + d->setKeySequenceProperty(index, value); // cache it + } + return qVariantFromValue(value); + } + + return metaProperty(index); +} + +QVariant QDesignerPropertySheet::metaProperty(int index) const +{ + Q_ASSERT(!isFakeProperty(index)); + + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + QVariant v = p->read(d->m_object); + switch (p->kind()) { + case QDesignerMetaPropertyInterface::FlagKind: { + qdesigner_internal::PropertySheetFlagValue psflags = qdesigner_internal::PropertySheetFlagValue(v.toInt(), designerMetaFlagsFor(p->enumerator())); + qVariantSetValue(v, psflags); + } + break; + case QDesignerMetaPropertyInterface::EnumKind: { + qdesigner_internal::PropertySheetEnumValue pse = qdesigner_internal::PropertySheetEnumValue(v.toInt(), designerMetaEnumFor(p->enumerator())); + qVariantSetValue(v, pse); + } + break; + case QDesignerMetaPropertyInterface::OtherKind: + break; + } + return v; +} + +QVariant QDesignerPropertySheet::resolvePropertyValue(int index, const QVariant &value) const +{ + if (qVariantCanConvert(value)) + return qvariant_cast(value).value; + + if (qVariantCanConvert(value)) + return qvariant_cast(value).value; + + if (qVariantCanConvert(value)) + return qVariantValue(value).value(); + + if (qVariantCanConvert(value)) + return qVariantValue(value).value(); + + if (qVariantCanConvert(value)) { + const QString path = qVariantValue(value).path(); + if (path.isEmpty()) + return defaultResourceProperty(index); + if (d->m_pixmapCache) { + return d->m_pixmapCache->pixmap(qvariant_cast(value)); + } + } + + if (qVariantCanConvert(value)) { + const int pathCount = qVariantValue(value).paths().count(); + if (pathCount == 0) + return defaultResourceProperty(index); + if (d->m_iconCache) + return d->m_iconCache->icon(qvariant_cast(value)); + } + + return value; +} + +void QDesignerPropertySheet::setFakeProperty(int index, const QVariant &value) +{ + Q_ASSERT(isFakeProperty(index)); + + QVariant &v = d->m_fakeProperties[index]; + + // set resource properties also (if we are going to have fake resource properties) + if (qVariantCanConvert(value) || qVariantCanConvert(value)) { + v = value; + } else if (qVariantCanConvert(v)) { + qdesigner_internal::PropertySheetFlagValue f = qvariant_cast(v); + f.value = value.toInt(); + qVariantSetValue(v, f); + Q_ASSERT(value.type() == QVariant::Int); + } else if (qVariantCanConvert(v)) { + qdesigner_internal::PropertySheetEnumValue e = qvariant_cast(v); + e.value = value.toInt(); + qVariantSetValue(v, e); + Q_ASSERT(value.type() == QVariant::Int); + } else { + v = value; + } +} + +void QDesignerPropertySheet::clearFakeProperties() +{ + d->m_fakeProperties.clear(); +} + +// Buddy needs to be byte array, else uic won't work +static QVariant toByteArray(const QVariant &value) { + if (value.type() == QVariant::ByteArray) + return value; + const QByteArray ba = value.toString().toUtf8(); + return QVariant(ba); +} + +void QDesignerPropertySheet::setProperty(int index, const QVariant &value) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return; + if (isAdditionalProperty(index)) { + if (d->m_objectType == ObjectLabel && propertyType(index) == PropertyBuddy) { + QFormBuilderExtra::applyBuddy(value.toString(), QFormBuilderExtra::BuddyApplyVisibleOnly, qobject_cast(d->m_object)); + d->m_addProperties[index] = toByteArray(value); + return; + } + + if (isFakeLayoutProperty(index)) { + QDesignerPropertySheetExtension *layoutPropertySheet; + if (d->layout(&layoutPropertySheet) && layoutPropertySheet) { + const QString newPropName = d->transformLayoutPropertyName(index); + if (!newPropName.isEmpty()) { + const int newIndex = layoutPropertySheet->indexOf(newPropName); + if (newIndex != -1) + layoutPropertySheet->setProperty(newIndex, value); + } + } + } + + if (isDynamicProperty(index)) { + if (d->isResourceProperty(index)) + d->setResourceProperty(index, value); + if (d->isStringProperty(index)) + d->setStringProperty(index, qVariantValue(value)); + if (d->isKeySequenceProperty(index)) + d->setKeySequenceProperty(index, qVariantValue(value)); + d->m_object->setProperty(propertyName(index).toUtf8(), resolvePropertyValue(index, value)); + if (d->m_object->isWidgetType()) { + QWidget *w = qobject_cast(d->m_object); + w->setStyleSheet(w->styleSheet()); + } + } + d->m_addProperties[index] = value; + } else if (isFakeProperty(index)) { + setFakeProperty(index, value); + } else { + if (d->isResourceProperty(index)) + d->setResourceProperty(index, value); + if (d->isStringProperty(index)) + d->setStringProperty(index, qVariantValue(value)); + if (d->isKeySequenceProperty(index)) + d->setKeySequenceProperty(index, qVariantValue(value)); + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + p->write(d->m_object, resolvePropertyValue(index, value)); + if (qobject_cast(d->m_object) && propertyType(index) == PropertyCheckable) { + const int idx = indexOf(QLatin1String("focusPolicy")); + if (!isChanged(idx)) { + qdesigner_internal::PropertySheetEnumValue e = qVariantValue(property(idx)); + if (value.toBool()) { + const QDesignerMetaPropertyInterface *p = d->m_meta->property(idx); + p->write(d->m_object, Qt::NoFocus); + e.value = Qt::StrongFocus; + QVariant v; + qVariantSetValue(v, e); + setFakeProperty(idx, v); + } else { + e.value = Qt::NoFocus; + QVariant v; + qVariantSetValue(v, e); + setFakeProperty(idx, v); + } + } + } + } +} + +bool QDesignerPropertySheet::hasReset(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + if (isAdditionalProperty(index)) + return d->m_info.value(index).reset; + return true; +} + +bool QDesignerPropertySheet::reset(int index) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + if (d->isStringProperty(index)) + setProperty(index, qVariantFromValue(qdesigner_internal::PropertySheetStringValue())); + if (d->isKeySequenceProperty(index)) + setProperty(index, qVariantFromValue(qdesigner_internal::PropertySheetKeySequenceValue())); + if (d->isResourceProperty(index)) { + setProperty(index, d->emptyResourceProperty(index)); + return true; + } else if (isDynamic(index)) { + const QString propName = propertyName(index); + const QVariant oldValue = d->m_addProperties.value(index); + const QVariant newValue = d->m_info.value(index).defaultValue; + if (oldValue == newValue) + return true; + d->m_object->setProperty(propName.toUtf8(), newValue); + d->m_addProperties[index] = newValue; + return true; + } else if (!d->m_info.value(index).defaultValue.isNull()) { + setProperty(index, d->m_info.value(index).defaultValue); + return true; + } + if (isAdditionalProperty(index)) { + const PropertyType pType = propertyType(index); + if (d->m_objectType == ObjectLabel && pType == PropertyBuddy) { + setProperty(index, QVariant(QByteArray())); + return true; + } + if (isFakeLayoutProperty(index)) { + // special properties + switch (pType) { + case PropertyLayoutObjectName: + setProperty(index, QString()); + return true; + case PropertyLayoutSizeConstraint: + setProperty(index, QVariant(QLayout::SetDefaultConstraint)); + return true; + case PropertyLayoutBoxStretch: + case PropertyLayoutGridRowStretch: + case PropertyLayoutGridColumnStretch: + case PropertyLayoutGridRowMinimumHeight: + case PropertyLayoutGridColumnMinimumWidth: + case PropertyLayoutFieldGrowthPolicy: + case PropertyLayoutRowWrapPolicy: + case PropertyLayoutLabelAlignment: + case PropertyLayoutFormAlignment: { + QDesignerPropertySheetExtension *layoutPropertySheet; + if (d->layout(&layoutPropertySheet) && layoutPropertySheet) + return layoutPropertySheet->reset(layoutPropertySheet->indexOf(d->transformLayoutPropertyName(index))); + } + break; + default: + break; + } + // special margins + int value = -1; + switch (d->m_objectType) { + case ObjectQ3GroupBox: { + const QWidget *w = qobject_cast(d->m_object); + switch (pType) { + case PropertyLayoutLeftMargin: + value = w->style()->pixelMetric(QStyle::PM_LayoutLeftMargin); + break; + case PropertyLayoutTopMargin: + value = w->style()->pixelMetric(QStyle::PM_LayoutTopMargin); + break; + case PropertyLayoutRightMargin: + value = w->style()->pixelMetric(QStyle::PM_LayoutRightMargin); + break; + case PropertyLayoutBottomMargin: + value = w->style()->pixelMetric(QStyle::PM_LayoutBottomMargin); + break; + case PropertyLayoutSpacing: + case PropertyLayoutHorizontalSpacing: + case PropertyLayoutVerticalSpacing: + value = -1; + break; + default: + break; + } + } + break; + case ObjectLayoutWidget: + if (pType == PropertyLayoutLeftMargin || + pType == PropertyLayoutTopMargin || + pType == PropertyLayoutRightMargin || + pType == PropertyLayoutBottomMargin) + value = 0; + break; + default: + break; + } + setProperty(index, value); + return true; + } + return false; + } else if (isFakeProperty(index)) { + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + const bool result = p->reset(d->m_object); + d->m_fakeProperties[index] = p->read(d->m_object); + return result; + } else if (propertyType(index) == PropertyGeometry && d->m_object->isWidgetType()) { + if (QWidget *w = qobject_cast(d->m_object)) { + QWidget *widget = w; + if (qdesigner_internal::Utils::isCentralWidget(d->m_fwb, widget) && d->m_fwb->parentWidget()) + widget = d->m_fwb->parentWidget(); + + if (widget != w && widget->parentWidget()) { + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + widget->parentWidget()->adjustSize(); + } + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + widget->adjustSize(); + return true; + } + } + // ### TODO: reset for fake properties. + + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + return p->reset(d->m_object); +} + +bool QDesignerPropertySheet::isChanged(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + if (isAdditionalProperty(index)) { + if (isFakeLayoutProperty(index)) { + QDesignerPropertySheetExtension *layoutPropertySheet; + if (d->layout(&layoutPropertySheet) && layoutPropertySheet) { + const QString newPropName = d->transformLayoutPropertyName(index); + if (!newPropName.isEmpty()) { + const int newIndex = layoutPropertySheet->indexOf(newPropName); + if (newIndex != -1) + return layoutPropertySheet->isChanged(newIndex); + return false; + } + } + } + } + return d->m_info.value(index).changed; +} + +void QDesignerPropertySheet::setChanged(int index, bool changed) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return; + if (isAdditionalProperty(index)) { + if (isFakeLayoutProperty(index)) { + QDesignerPropertySheetExtension *layoutPropertySheet; + if (d->layout(&layoutPropertySheet) && layoutPropertySheet) { + const QString newPropName = d->transformLayoutPropertyName(index); + if (!newPropName.isEmpty()) { + const int newIndex = layoutPropertySheet->indexOf(newPropName); + if (newIndex != -1) + layoutPropertySheet->setChanged(newIndex, changed); + } + } + } + } + if (d->isReloadableProperty(index)) { + if (d->m_fwb) { + if (changed) + d->m_fwb->addReloadableProperty(this, index); + else + d->m_fwb->removeReloadableProperty(this, index); + } + } + d->ensureInfo(index).changed = changed; +} + +bool QDesignerPropertySheet::isFakeLayoutProperty(int index) const +{ + if (!isAdditionalProperty(index)) + return false; + + switch (propertyType(index)) { + case PropertyLayoutObjectName: + case PropertyLayoutSizeConstraint: + return true; + case PropertyLayoutLeftMargin: + case PropertyLayoutTopMargin: + case PropertyLayoutRightMargin: + case PropertyLayoutBottomMargin: + case PropertyLayoutSpacing: + case PropertyLayoutHorizontalSpacing: + case PropertyLayoutVerticalSpacing: + case PropertyLayoutFieldGrowthPolicy: + case PropertyLayoutRowWrapPolicy: + case PropertyLayoutLabelAlignment: + case PropertyLayoutFormAlignment: + case PropertyLayoutBoxStretch: + case PropertyLayoutGridRowStretch: + case PropertyLayoutGridColumnStretch: + case PropertyLayoutGridRowMinimumHeight: + case PropertyLayoutGridColumnMinimumWidth: + return d->m_canHaveLayoutAttributes; + default: + break; + } + return false; +} + +// Determine the "designable" state of a property. Properties, which have +// a per-object boolean test function that returns false are shown in +// disabled state ("checked" depending on "checkable", etc.) +// Properties, which are generally not designable independent +// of the object are not shown at all. +enum DesignableState { PropertyIsDesignable, + // Object has a Designable test function that returns false. + PropertyOfObjectNotDesignable, + PropertyNotDesignable }; + +static inline DesignableState designableState(const QDesignerMetaPropertyInterface *p, const QObject *object) +{ + if (p->attributes(object) & QDesignerMetaPropertyInterface::DesignableAttribute) + return PropertyIsDesignable; + return (p->attributes() & QDesignerMetaPropertyInterface::DesignableAttribute) ? + PropertyOfObjectNotDesignable : PropertyNotDesignable; +} + +bool QDesignerPropertySheet::isVisible(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + + const PropertyType type = propertyType(index); + if (isAdditionalProperty(index)) { + if (isFakeLayoutProperty(index) && d->m_object->isWidgetType()) { + const QLayout *currentLayout = d->layout(); + if (!currentLayout) + return false; + const int visibleMask = qdesigner_internal::LayoutProperties::visibleProperties(currentLayout); + switch (type) { + case PropertyLayoutSpacing: + return visibleMask & qdesigner_internal::LayoutProperties::SpacingProperty; + case PropertyLayoutHorizontalSpacing: + case PropertyLayoutVerticalSpacing: + return visibleMask & qdesigner_internal::LayoutProperties::HorizSpacingProperty; + case PropertyLayoutFieldGrowthPolicy: + return visibleMask & qdesigner_internal::LayoutProperties::FieldGrowthPolicyProperty; + case PropertyLayoutRowWrapPolicy: + return visibleMask & qdesigner_internal::LayoutProperties::RowWrapPolicyProperty; + case PropertyLayoutLabelAlignment: + return visibleMask & qdesigner_internal::LayoutProperties::LabelAlignmentProperty; + case PropertyLayoutFormAlignment: + return visibleMask & qdesigner_internal::LayoutProperties::FormAlignmentProperty; + case PropertyLayoutBoxStretch: + return visibleMask & qdesigner_internal::LayoutProperties::BoxStretchProperty; + case PropertyLayoutGridRowStretch: + return visibleMask & qdesigner_internal::LayoutProperties::GridRowStretchProperty; + case PropertyLayoutGridColumnStretch: + return visibleMask & qdesigner_internal::LayoutProperties::GridColumnStretchProperty; + case PropertyLayoutGridRowMinimumHeight: + return visibleMask & qdesigner_internal::LayoutProperties::GridRowMinimumHeightProperty; + case PropertyLayoutGridColumnMinimumWidth: + return visibleMask & qdesigner_internal::LayoutProperties::GridColumnMinimumWidthProperty; + default: + break; + } + return true; + } + return d->m_info.value(index).visible; + } + + if (isFakeProperty(index)) { + if (type == PropertyWindowModality) // Hidden for child widgets + return d->m_info.value(index).visible; + return true; + } + + const bool visible = d->m_info.value(index).visible; + switch (type) { + case PropertyWindowTitle: + case PropertyWindowIcon: + case PropertyWindowFilePath: + case PropertyWindowOpacity: + case PropertyWindowIconText: + case PropertyWindowModified: + return visible; + default: + if (visible) + return true; + break; + } + + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + if (!(p->accessFlags() & QDesignerMetaPropertyInterface::WriteAccess)) + return false; + + // Enabled handling: Hide only statically not designable properties + return designableState(p, d->m_object) != PropertyNotDesignable; +} + +void QDesignerPropertySheet::setVisible(int index, bool visible) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return; + d->ensureInfo(index).visible = visible; +} + +bool QDesignerPropertySheet::isEnabled(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + if (isAdditionalProperty(index)) + return true; + + if (isFakeProperty(index)) + return true; + + // Grey out geometry of laid-out widgets (including splitter) + if (propertyType(index) == PropertyGeometry && d->m_object->isWidgetType()) { + bool isManaged; + const qdesigner_internal::LayoutInfo::Type lt = qdesigner_internal::LayoutInfo::laidoutWidgetType(d->m_core, qobject_cast(d->m_object), &isManaged); + return !isManaged || lt == qdesigner_internal::LayoutInfo::NoLayout; + } + + if (d->m_info.value(index).visible == true) // Sun CC 5.5 oddity, wants true + return true; + + // Enable setting of properties for statically non-designable properties + // as this might be done via TaskMenu/Cursor::setProperty. Note that those + // properties are not visible. + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + return (p->accessFlags() & QDesignerMetaPropertyInterface::WriteAccess) && + designableState(p, d->m_object) != PropertyOfObjectNotDesignable; +} + +bool QDesignerPropertySheet::isAttribute(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + if (isAdditionalProperty(index)) + return d->m_info.value(index).attribute; + + if (isFakeProperty(index)) + return false; + + return d->m_info.value(index).attribute; +} + +void QDesignerPropertySheet::setAttribute(int index, bool attribute) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return; + d->ensureInfo(index).attribute = attribute; +} + +QDesignerFormEditorInterface *QDesignerPropertySheet::core() const +{ + return d->m_core; +} + +bool QDesignerPropertySheet::internalDynamicPropertiesEnabled() +{ + return QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled; +} + +void QDesignerPropertySheet::setInternalDynamicPropertiesEnabled(bool v) +{ + QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled = v; +} + +// ---------- QDesignerAbstractPropertySheetFactory + +struct QDesignerAbstractPropertySheetFactory::PropertySheetFactoryPrivate { + PropertySheetFactoryPrivate(); + const QString m_propertySheetId; + const QString m_dynamicPropertySheetId; + + typedef QMap ExtensionMap; + ExtensionMap m_extensions; + typedef QHash ExtendedSet; + ExtendedSet m_extended; +}; + +QDesignerAbstractPropertySheetFactory::PropertySheetFactoryPrivate::PropertySheetFactoryPrivate() : + m_propertySheetId(Q_TYPEID(QDesignerPropertySheetExtension)), + m_dynamicPropertySheetId(Q_TYPEID(QDesignerDynamicPropertySheetExtension)) +{ +} + +// ---------- QDesignerAbstractPropertySheetFactory + + +QDesignerAbstractPropertySheetFactory::QDesignerAbstractPropertySheetFactory(QExtensionManager *parent) : + QExtensionFactory(parent), + m_impl(new PropertySheetFactoryPrivate) +{ +} + +QDesignerAbstractPropertySheetFactory::~QDesignerAbstractPropertySheetFactory() +{ + delete m_impl; +} + +QObject *QDesignerAbstractPropertySheetFactory::extension(QObject *object, const QString &iid) const +{ + typedef PropertySheetFactoryPrivate::ExtensionMap ExtensionMap; + if (!object) + return 0; + + if (iid != m_impl->m_propertySheetId && iid != m_impl->m_dynamicPropertySheetId) + return 0; + + ExtensionMap::iterator it = m_impl->m_extensions.find(object); + if (it == m_impl->m_extensions.end()) { + if (QObject *ext = createPropertySheet(object, const_cast(this))) { + connect(ext, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); + it = m_impl->m_extensions.insert(object, ext); + } + } + + if (!m_impl->m_extended.contains(object)) { + connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); + m_impl->m_extended.insert(object, true); + } + + if (it == m_impl->m_extensions.end()) + return 0; + + return it.value(); +} + +void QDesignerAbstractPropertySheetFactory::objectDestroyed(QObject *object) +{ + QMutableMapIterator it(m_impl->m_extensions); + while (it.hasNext()) { + it.next(); + + QObject *o = it.key(); + if (o == object || object == it.value()) { + it.remove(); + } + } + + m_impl->m_extended.remove(object); +} + +QT_END_NAMESPACE