tools/designer/src/lib/shared/qdesigner_propertysheet.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /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 <formbuilderextra_p.h>
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerWidgetDataBaseInterface>
+
+#include <QtCore/QDebug>
+
+#include <QtGui/QLayout>
+#include <QtGui/QDockWidget>
+#include <QtGui/QDialog>
+#include <QtGui/QLabel>
+#include <QtGui/QGroupBox>
+#include <QtGui/QStyle>
+#include <QtGui/QApplication>
+#include <QtGui/QToolBar>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMenuBar>
+
+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<QDesignerFormEditorInterface*>(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<QWidget *>(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<QString, QString> ScopeNameKey;
+    typedef QMap<ScopeNameKey, qdesigner_internal::DesignerMetaEnum> 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<QString, QString> ScopeNameKey;
+    typedef QMap<ScopeNameKey, qdesigner_internal::DesignerMetaFlags> 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<int, Info> InfoHash;
+    InfoHash m_info;
+    QHash<int, QVariant> m_fakeProperties;
+    QHash<int, QVariant> m_addProperties;
+    QHash<QString, int> m_addIndex;
+    QHash<int, QVariant> m_resourceProperties; // only PropertySheetPixmapValue snd PropertySheetIconValue here
+    QHash<int, qdesigner_internal::PropertySheetStringValue> m_stringProperties; // only PropertySheetStringValue
+    QHash<int, qdesigner_internal::PropertySheetKeySequenceValue> m_keySequenceProperties; // only PropertySheetKeySequenceValue
+
+    const bool m_canHaveLayoutAttributes;
+
+    // Variables used for caching the layout, access via layout().
+    QPointer<QObject> m_object;
+    mutable QPointer<QLayout> m_lastLayout;
+    mutable QDesignerPropertySheetExtension *m_lastLayoutPropertySheet;
+    mutable bool m_LastLayoutByDesigner;
+
+    qdesigner_internal::DesignerPixmapCache *m_pixmapCache;
+    qdesigner_internal::DesignerIconCache *m_iconCache;
+    QPointer<qdesigner_internal::FormWindowBase> 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<qdesigner_internal::PropertySheetPixmapValue>(v))
+        return qVariantFromValue(qdesigner_internal::PropertySheetPixmapValue());
+    if (qVariantCanConvert<qdesigner_internal::PropertySheetIconValue>(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<qdesigner_internal::PropertySheetPixmapValue>(value) && qVariantCanConvert<qdesigner_internal::PropertySheetPixmapValue>(v))
+        || (qVariantCanConvert<qdesigner_internal::PropertySheetIconValue>(value) && qVariantCanConvert<qdesigner_internal::PropertySheetIconValue>(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<QWidget*>(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<QDesignerPropertySheetExtension*>(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<QDesignerPropertySheet::PropertyType, QString> 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<const QLayout *>(o))
+        return ObjectLayout;
+
+    if (!o->isWidgetType())
+        return ObjectNone;
+
+    if (qobject_cast<const QLayoutWidget *>(o))
+        return ObjectLayoutWidget;
+
+    if (qobject_cast<const QLabel*>(o))
+        return ObjectLabel;
+
+    if (o->inherits("Q3GroupBox"))
+        return ObjectQ3GroupBox;
+
+    return ObjectNone;
+}
+
+QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyTypeFromName(const QString &name)
+{
+    typedef QHash<QString, PropertyType> 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<qdesigner_internal::FormWindowBase *>(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; index<count(); ++index) {
+        const QDesignerMetaPropertyInterface *p = d->m_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<const QToolBar *>(d->m_object)) { // prevent toolbars from being dragged off
+            createFakeProperty(QLatin1String("floatable"), QVariant(true));
+        } else {
+            if (qobject_cast<const QMenuBar *>(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<const QMainWindow *>(d->m_object))
+            createFakeProperty(QLatin1String("unifiedTitleAndToolBarOnMac"), false);
+    }
+
+    if (qobject_cast<const QDialog*>(object)) {
+        createFakeProperty(QLatin1String("modal"));
+    }
+    if (qobject_cast<const QDockWidget*>(object)) {
+        createFakeProperty(QLatin1String("floating"));
+    }
+
+    typedef QList<QByteArray> 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<QKeySequence>(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<qdesigner_internal::PropertySheetEnumValue>(value))
+        return qvariant_cast<qdesigner_internal::PropertySheetEnumValue>(value).value;
+
+    if (qVariantCanConvert<qdesigner_internal::PropertySheetFlagValue>(value))
+        return qvariant_cast<qdesigner_internal::PropertySheetFlagValue>(value).value;
+
+    if (qVariantCanConvert<qdesigner_internal::PropertySheetStringValue>(value))
+        return qVariantValue<qdesigner_internal::PropertySheetStringValue>(value).value();
+
+    if (qVariantCanConvert<qdesigner_internal::PropertySheetKeySequenceValue>(value))
+        return qVariantValue<qdesigner_internal::PropertySheetKeySequenceValue>(value).value();
+
+    if (qVariantCanConvert<qdesigner_internal::PropertySheetPixmapValue>(value)) {
+        const QString path = qVariantValue<qdesigner_internal::PropertySheetPixmapValue>(value).path();
+        if (path.isEmpty())
+            return defaultResourceProperty(index);
+        if (d->m_pixmapCache) {
+            return d->m_pixmapCache->pixmap(qvariant_cast<qdesigner_internal::PropertySheetPixmapValue>(value));
+        }
+    }
+
+    if (qVariantCanConvert<qdesigner_internal::PropertySheetIconValue>(value)) {
+        const int pathCount = qVariantValue<qdesigner_internal::PropertySheetIconValue>(value).paths().count();
+        if (pathCount == 0)
+            return defaultResourceProperty(index);
+        if (d->m_iconCache)
+            return d->m_iconCache->icon(qvariant_cast<qdesigner_internal::PropertySheetIconValue>(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<qdesigner_internal::PropertySheetFlagValue>(value) || qVariantCanConvert<qdesigner_internal::PropertySheetEnumValue>(value)) {
+        v = value;
+    } else if (qVariantCanConvert<qdesigner_internal::PropertySheetFlagValue>(v)) {
+        qdesigner_internal::PropertySheetFlagValue f = qvariant_cast<qdesigner_internal::PropertySheetFlagValue>(v);
+        f.value = value.toInt();
+        qVariantSetValue(v, f);
+        Q_ASSERT(value.type() == QVariant::Int);
+    } else if (qVariantCanConvert<qdesigner_internal::PropertySheetEnumValue>(v)) {
+        qdesigner_internal::PropertySheetEnumValue e = qvariant_cast<qdesigner_internal::PropertySheetEnumValue>(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<QLabel *>(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<qdesigner_internal::PropertySheetStringValue>(value));
+            if (d->isKeySequenceProperty(index))
+                d->setKeySequenceProperty(index, qVariantValue<qdesigner_internal::PropertySheetKeySequenceValue>(value));
+            d->m_object->setProperty(propertyName(index).toUtf8(), resolvePropertyValue(index, value));
+            if (d->m_object->isWidgetType()) {
+                QWidget *w = qobject_cast<QWidget *>(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<qdesigner_internal::PropertySheetStringValue>(value));
+        if (d->isKeySequenceProperty(index))
+            d->setKeySequenceProperty(index, qVariantValue<qdesigner_internal::PropertySheetKeySequenceValue>(value));
+        const QDesignerMetaPropertyInterface *p = d->m_meta->property(index);
+        p->write(d->m_object, resolvePropertyValue(index, value));
+        if (qobject_cast<QGroupBox *>(d->m_object) && propertyType(index) == PropertyCheckable) {
+            const int idx = indexOf(QLatin1String("focusPolicy"));
+            if (!isChanged(idx)) {
+                qdesigner_internal::PropertySheetEnumValue e = qVariantValue<qdesigner_internal::PropertySheetEnumValue>(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<const QWidget *>(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<QWidget*>(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<QWidget *>(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<QObject*, QObject*> ExtensionMap;
+    ExtensionMap m_extensions;
+    typedef QHash<QObject*, bool> 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<QDesignerAbstractPropertySheetFactory*>(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<QObject*, QObject*> 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