| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 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$ |
| ** GNU Lesser General Public License Usage |
| ** 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. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $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 |
| || propertyType(index) == QDesignerPropertySheet::PropertyText |
| || 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); |
| propertyTypeHash.insert(QLatin1String("text"), PropertyText); |
| } |
| 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/Opacity is visible only for the main container, in which case the form windows enables it on loading |
| setVisible(createFakeProperty(QLatin1String("windowModality")), false); |
| setVisible(createFakeProperty(QLatin1String("windowOpacity"), double(1.0)), 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 |
| { |
| // used internally |
| if (propName == QLatin1String("database") || |
| propName == QLatin1String("buttonGroupId")) |
| return false; |
| 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(value.toString())); |
| else if (value.type() == QVariant::KeySequence) { |
| const QKeySequence keySequence = qVariantValue<QKeySequence>(value); |
| v = qVariantFromValue(qdesigner_internal::PropertySheetKeySequenceValue(keySequence)); |
| } |
| |
| 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) || isDefaultDynamicProperty(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 defaultValue = d->m_info.value(index).defaultValue; |
| QVariant newValue = defaultValue; |
| if (d->isStringProperty(index)) { |
| newValue = qVariantFromValue(qdesigner_internal::PropertySheetStringValue(newValue.toString())); |
| } else if (d->isKeySequenceProperty(index)) { |
| const QKeySequence keySequence = qVariantValue<QKeySequence>(newValue); |
| newValue = qVariantFromValue(qdesigner_internal::PropertySheetKeySequenceValue(keySequence)); |
| } |
| if (oldValue == newValue) |
| return true; |
| d->m_object->setProperty(propName.toUtf8(), defaultValue); |
| 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)) { |
| switch (type) { |
| case PropertyWindowModality: // Hidden for child widgets |
| case PropertyWindowOpacity: |
| return d->m_info.value(index).visible; |
| default: |
| break; |
| } |
| 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 |