/**************************************************************************** ** ** Copyright (C) 2012 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE #define USE_LAYOUT_SIZE_CONSTRAINT static const QDesignerMetaObjectInterface *propertyIntroducedBy(const QDesignerMetaObjectInterface *meta, int index) { if (index >= meta->propertyOffset()) return meta; if (meta->superClass()) return propertyIntroducedBy(meta->superClass(), index); return 0; } // Layout fake properties (prefixed by 'layout' to distinguish them from other 'margins' // that might be around. These are forwarded to the layout sheet (after name transformation). // // 'layoutObjectName' is new for 4.4. It is the name of the actual layout. // Up to 4.3, QLayoutWidget's name was displayed in the objectinspector. // This changes with 4.4; the layout name is displayed. This means that for // old forms, QLayoutWidget will show up as ''; however, the uic code will // still use 'verticalLayout' (in case someone accesses it). New Layouts get autogenerated names, // legacy forms will keep their empty names (unless someone types in a new name). static const char *layoutObjectNameC = "layoutName"; static const char *layoutLeftMarginC = "layoutLeftMargin"; static const char *layoutTopMarginC = "layoutTopMargin"; static const char *layoutRightMarginC = "layoutRightMargin"; static const char *layoutBottomMarginC = "layoutBottomMargin"; static const char *layoutSpacingC = "layoutSpacing"; static const char *layoutHorizontalSpacingC = "layoutHorizontalSpacing"; static const char *layoutVerticalSpacingC = "layoutVerticalSpacing"; static const char *layoutSizeConstraintC = "layoutSizeConstraint"; // form layout static const char *layoutFieldGrowthPolicyC = "layoutFieldGrowthPolicy"; static const char *layoutRowWrapPolicyC = "layoutRowWrapPolicy"; static const char *layoutLabelAlignmentC = "layoutLabelAlignment"; static const char *layoutFormAlignmentC = "layoutFormAlignment"; // stretches static const char *layoutboxStretchPropertyC = "layoutStretch"; static const char *layoutGridRowStretchPropertyC = "layoutRowStretch"; static const char *layoutGridColumnStretchPropertyC = "layoutColumnStretch"; static const char *layoutGridRowMinimumHeightC = "layoutRowMinimumHeight"; static const char *layoutGridColumnMinimumWidthC = "layoutColumnMinimumWidth"; // Find the form editor in the hierarchy. // We know that the parent of the sheet is the extension manager // whose parent is the core. static QDesignerFormEditorInterface *formEditorForObject(QObject *o) { do { if (QDesignerFormEditorInterface* core = qobject_cast(o)) return core; o = o->parent(); } while(o); Q_ASSERT(o); return 0; } static bool hasLayoutAttributes(QDesignerFormEditorInterface *core, QObject *object) { if (!object->isWidgetType()) return false; QWidget *w = qobject_cast(object); if (const QDesignerWidgetDataBaseInterface *db = core->widgetDataBase()) { if (db->isContainer(w)) return true; } return false; } // Cache DesignerMetaEnum by scope/name of a QMetaEnum static const qdesigner_internal::DesignerMetaEnum &designerMetaEnumFor(const QDesignerMetaEnumInterface *me) { typedef QPair ScopeNameKey; typedef QMap DesignerMetaEnumCache; static DesignerMetaEnumCache cache; const QString name = me->name(); const QString scope = me->scope(); const ScopeNameKey key = ScopeNameKey(scope, name); DesignerMetaEnumCache::iterator it = cache.find(key); if (it == cache.end()) { qdesigner_internal::DesignerMetaEnum dme = qdesigner_internal::DesignerMetaEnum(name, scope, me->separator()); const int keyCount = me->keyCount(); for (int i=0; i < keyCount; ++i) dme.addKey(me->value(i), me->key(i)); it = cache.insert(key, dme); } return it.value(); } // Cache DesignerMetaFlags by scope/name of a QMetaEnum static const qdesigner_internal::DesignerMetaFlags &designerMetaFlagsFor(const QDesignerMetaEnumInterface *me) { typedef QPair ScopeNameKey; typedef QMap DesignerMetaFlagsCache; static DesignerMetaFlagsCache cache; const QString name = me->name(); const QString scope = me->scope(); const ScopeNameKey key = ScopeNameKey(scope, name); DesignerMetaFlagsCache::iterator it = cache.find(key); if (it == cache.end()) { qdesigner_internal::DesignerMetaFlags dme = qdesigner_internal::DesignerMetaFlags(name, scope, me->separator()); const int keyCount = me->keyCount(); for (int i=0; i < keyCount; ++i) dme.addKey(me->value(i), me->key(i)); it = cache.insert(key, dme); } return it.value(); } // ------------ QDesignerMemberSheetPrivate class QDesignerPropertySheetPrivate { public: typedef QDesignerPropertySheet::PropertyType PropertyType; typedef QDesignerPropertySheet::ObjectType ObjectType; explicit QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent); bool invalidIndex(const char *functionName, int index) const; inline int count() const { return m_meta->propertyCount() + m_addProperties.count(); } PropertyType propertyType(int index) const; QString transformLayoutPropertyName(int index) const; QLayout* layout(QDesignerPropertySheetExtension **layoutPropertySheet = 0) const; static ObjectType objectType(const QObject *o); bool isReloadableProperty(int index) const; bool isResourceProperty(int index) const; void addResourceProperty(int index, QVariant::Type type); QVariant resourceProperty(int index) const; void setResourceProperty(int index, const QVariant &value); QVariant emptyResourceProperty(int index) const; // of type PropertySheetPixmapValue / PropertySheetIconValue QVariant defaultResourceProperty(int index) const; // of type QPixmap / QIcon (maybe it can be generalized for all types, not resource only) bool isStringProperty(int index) const; void addStringProperty(int index); qdesigner_internal::PropertySheetStringValue stringProperty(int index) const; void setStringProperty(int index, const qdesigner_internal::PropertySheetStringValue &value); bool isStringListProperty(int index) const; void addStringListProperty(int index); qdesigner_internal::PropertySheetStringListValue stringListProperty(int index) const; void setStringListProperty(int index, const qdesigner_internal::PropertySheetStringListValue &value); bool isKeySequenceProperty(int index) const; void addKeySequenceProperty(int index); qdesigner_internal::PropertySheetKeySequenceValue keySequenceProperty(int index) const; void setKeySequenceProperty(int index, const qdesigner_internal::PropertySheetKeySequenceValue &value); enum PropertyKind { NormalProperty, FakeProperty, DynamicProperty, DefaultDynamicProperty }; class Info { public: Info(); QString group; QVariant defaultValue; bool changed; bool visible; bool attribute; bool reset; PropertyType propertyType; PropertyKind kind; }; Info &ensureInfo(int index); QDesignerPropertySheet *q; QDesignerFormEditorInterface *m_core; const QDesignerMetaObjectInterface *m_meta; const ObjectType m_objectType; typedef QHash InfoHash; InfoHash m_info; QHash m_fakeProperties; QHash m_addProperties; QHash m_addIndex; QHash m_resourceProperties; // only PropertySheetPixmapValue snd PropertySheetIconValue here QHash m_stringProperties; // only PropertySheetStringValue QHash m_stringListProperties; // only PropertySheetStringListValue QHash m_keySequenceProperties; // only PropertySheetKeySequenceValue const bool m_canHaveLayoutAttributes; // Variables used for caching the layout, access via layout(). QPointer m_object; mutable QPointer m_lastLayout; mutable QDesignerPropertySheetExtension *m_lastLayoutPropertySheet; mutable bool m_LastLayoutByDesigner; qdesigner_internal::DesignerPixmapCache *m_pixmapCache; qdesigner_internal::DesignerIconCache *m_iconCache; QPointer m_fwb; // Enable Qt's internal properties starting with prefix "_q_" static bool m_internalDynamicPropertiesEnabled; }; bool QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled = false; /* The property is reloadable if its contents depends on resource. */ bool QDesignerPropertySheetPrivate::isReloadableProperty(int index) const { return isResourceProperty(index) || propertyType(index) == QDesignerPropertySheet::PropertyStyleSheet || 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, QVariant::fromValue(qdesigner_internal::PropertySheetPixmapValue())); else if (type == QVariant::Icon) m_resourceProperties.insert(index, QVariant::fromValue(qdesigner_internal::PropertySheetIconValue())); } QVariant QDesignerPropertySheetPrivate::emptyResourceProperty(int index) const { QVariant v = m_resourceProperties.value(index); if (v.canConvert()) return QVariant::fromValue(qdesigner_internal::PropertySheetPixmapValue()); if (v.canConvert()) return QVariant::fromValue(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 ((value.canConvert() && v.canConvert()) || (value.canConvert() && v.canConvert())) 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::isStringListProperty(int index) const { return m_stringListProperties.contains(index); } void QDesignerPropertySheetPrivate::addStringListProperty(int index) { m_stringListProperties.insert(index, qdesigner_internal::PropertySheetStringListValue()); } qdesigner_internal::PropertySheetStringListValue QDesignerPropertySheetPrivate::stringListProperty(int index) const { return m_stringListProperties.value(index); } void QDesignerPropertySheetPrivate::setStringListProperty(int index, const qdesigner_internal::PropertySheetStringListValue &value) { Q_ASSERT(isStringListProperty(index)); m_stringListProperties[index] = value; } bool QDesignerPropertySheetPrivate::isKeySequenceProperty(int index) const { return m_keySequenceProperties.contains(index); } void QDesignerPropertySheetPrivate::addKeySequenceProperty(int index) { m_keySequenceProperties.insert(index, qdesigner_internal::PropertySheetKeySequenceValue()); } qdesigner_internal::PropertySheetKeySequenceValue QDesignerPropertySheetPrivate::keySequenceProperty(int index) const { return m_keySequenceProperties.value(index); } void QDesignerPropertySheetPrivate::setKeySequenceProperty(int index, const qdesigner_internal::PropertySheetKeySequenceValue &value) { Q_ASSERT(isKeySequenceProperty(index)); m_keySequenceProperties[index] = value; } QDesignerPropertySheetPrivate::Info::Info() : changed(false), visible(true), attribute(false), reset(true), propertyType(QDesignerPropertySheet::PropertyNone), kind(NormalProperty) { } QDesignerPropertySheetPrivate::QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent) : q(sheetPublic), m_core(formEditorForObject(sheetParent)), m_meta(m_core->introspection()->metaObject(object)), m_objectType(QDesignerPropertySheet::objectTypeFromObject(object)), m_canHaveLayoutAttributes(hasLayoutAttributes(m_core, object)), m_object(object), m_lastLayout(0), m_lastLayoutPropertySheet(0), m_LastLayoutByDesigner(false), m_pixmapCache(0), m_iconCache(0) { } qdesigner_internal::FormWindowBase *QDesignerPropertySheet::formWindowBase() const { return d->m_fwb; } bool QDesignerPropertySheetPrivate::invalidIndex(const char *functionName, int index) const { if (index < 0 || index >= count()) { qWarning() << "** WARNING " << functionName << " invoked for " << m_object->objectName() << " was passed an invalid index " << index << '.'; return true; } return false; } QLayout* QDesignerPropertySheetPrivate::layout(QDesignerPropertySheetExtension **layoutPropertySheet) const { // Return the layout and its property sheet // only if it is managed by designer and not one created on a custom widget. // (attempt to cache the value as this requires some hoops). if (layoutPropertySheet) *layoutPropertySheet = 0; if (!m_object->isWidgetType() || !m_canHaveLayoutAttributes) return 0; QWidget *widget = qobject_cast(m_object); QLayout *widgetLayout = qdesigner_internal::LayoutInfo::internalLayout(widget); if (!widgetLayout) { m_lastLayout = 0; m_lastLayoutPropertySheet = 0; return 0; } // Smart logic to avoid retrieving the meta DB from the widget every time. if (widgetLayout != m_lastLayout) { m_lastLayout = widgetLayout; m_LastLayoutByDesigner = false; m_lastLayoutPropertySheet = 0; // Is this a layout managed by designer or some layout on a custom widget? if (qdesigner_internal::LayoutInfo::managedLayout(m_core ,widgetLayout)) { m_LastLayoutByDesigner = true; m_lastLayoutPropertySheet = qt_extension(m_core->extensionManager(), m_lastLayout); } } if (!m_LastLayoutByDesigner) return 0; if (layoutPropertySheet) *layoutPropertySheet = m_lastLayoutPropertySheet; return m_lastLayout; } QDesignerPropertySheetPrivate::Info &QDesignerPropertySheetPrivate::ensureInfo(int index) { InfoHash::iterator it = m_info.find(index); if (it == m_info.end()) it = m_info.insert(index, Info()); return it.value(); } QDesignerPropertySheet::PropertyType QDesignerPropertySheetPrivate::propertyType(int index) const { const InfoHash::const_iterator it = m_info.constFind(index); if (it == m_info.constEnd()) return QDesignerPropertySheet::PropertyNone; return it.value().propertyType; } QString QDesignerPropertySheetPrivate::transformLayoutPropertyName(int index) const { typedef QMap TypeNameMap; static TypeNameMap typeNameMap; if (typeNameMap.empty()) { typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutObjectName, QStringLiteral("objectName")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutLeftMargin, QStringLiteral("leftMargin")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutTopMargin, QStringLiteral("topMargin")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutRightMargin, QStringLiteral("rightMargin")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutBottomMargin, QStringLiteral("bottomMargin")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutSpacing, QStringLiteral("spacing")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutHorizontalSpacing, QStringLiteral("horizontalSpacing")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutVerticalSpacing, QStringLiteral("verticalSpacing")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutSizeConstraint, QStringLiteral("sizeConstraint")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutFieldGrowthPolicy, QStringLiteral("fieldGrowthPolicy")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutRowWrapPolicy, QStringLiteral("rowWrapPolicy")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutLabelAlignment, QStringLiteral("labelAlignment")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutFormAlignment, QStringLiteral("formAlignment")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutBoxStretch, QStringLiteral("stretch")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridRowStretch, QStringLiteral("rowStretch")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridColumnStretch, QStringLiteral("columnStretch")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridRowMinimumHeight, QStringLiteral("rowMinimumHeight")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridColumnMinimumWidth, QStringLiteral("columnMinimumWidth")); } const TypeNameMap::const_iterator it = typeNameMap.constFind(propertyType(index)); if (it != typeNameMap.constEnd()) return it.value(); return QString(); } // ----------- QDesignerPropertySheet QDesignerPropertySheet::ObjectType QDesignerPropertySheet::objectTypeFromObject(const QObject *o) { if (qobject_cast(o)) return ObjectLayout; if (!o->isWidgetType()) return ObjectNone; if (qobject_cast(o)) return ObjectLayoutWidget; if (qobject_cast(o)) return ObjectLabel; return ObjectNone; } QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyTypeFromName(const QString &name) { typedef QHash PropertyTypeHash; static PropertyTypeHash propertyTypeHash; if (propertyTypeHash.empty()) { propertyTypeHash.insert(QLatin1String(layoutObjectNameC), PropertyLayoutObjectName); propertyTypeHash.insert(QLatin1String(layoutLeftMarginC), PropertyLayoutLeftMargin); propertyTypeHash.insert(QLatin1String(layoutTopMarginC), PropertyLayoutTopMargin); propertyTypeHash.insert(QLatin1String(layoutRightMarginC), PropertyLayoutRightMargin); propertyTypeHash.insert(QLatin1String(layoutBottomMarginC), PropertyLayoutBottomMargin); propertyTypeHash.insert(QLatin1String(layoutSpacingC), PropertyLayoutSpacing); propertyTypeHash.insert(QLatin1String(layoutHorizontalSpacingC), PropertyLayoutHorizontalSpacing); propertyTypeHash.insert(QLatin1String(layoutVerticalSpacingC), PropertyLayoutVerticalSpacing); propertyTypeHash.insert(QLatin1String(layoutSizeConstraintC), PropertyLayoutSizeConstraint); propertyTypeHash.insert(QLatin1String(layoutFieldGrowthPolicyC), PropertyLayoutFieldGrowthPolicy); propertyTypeHash.insert(QLatin1String(layoutRowWrapPolicyC), PropertyLayoutRowWrapPolicy); propertyTypeHash.insert(QLatin1String(layoutLabelAlignmentC), PropertyLayoutLabelAlignment); propertyTypeHash.insert(QLatin1String(layoutFormAlignmentC), PropertyLayoutFormAlignment); propertyTypeHash.insert(QLatin1String(layoutboxStretchPropertyC), PropertyLayoutBoxStretch); propertyTypeHash.insert(QLatin1String(layoutGridRowStretchPropertyC), PropertyLayoutGridRowStretch); propertyTypeHash.insert(QLatin1String(layoutGridColumnStretchPropertyC), PropertyLayoutGridColumnStretch); propertyTypeHash.insert(QLatin1String(layoutGridRowMinimumHeightC), PropertyLayoutGridRowMinimumHeight); propertyTypeHash.insert(QLatin1String(layoutGridColumnMinimumWidthC), PropertyLayoutGridColumnMinimumWidth); propertyTypeHash.insert(QStringLiteral("buddy"), PropertyBuddy); propertyTypeHash.insert(QStringLiteral("geometry"), PropertyGeometry); propertyTypeHash.insert(QStringLiteral("checkable"), PropertyCheckable); propertyTypeHash.insert(QStringLiteral("accessibleName"), PropertyAccessibility); propertyTypeHash.insert(QStringLiteral("accessibleDescription"), PropertyAccessibility); propertyTypeHash.insert(QStringLiteral("windowTitle"), PropertyWindowTitle); propertyTypeHash.insert(QStringLiteral("windowIcon"), PropertyWindowIcon); propertyTypeHash.insert(QStringLiteral("windowFilePath"), PropertyWindowFilePath); propertyTypeHash.insert(QStringLiteral("windowOpacity"), PropertyWindowOpacity); propertyTypeHash.insert(QStringLiteral("windowIconText"), PropertyWindowIconText); propertyTypeHash.insert(QStringLiteral("windowModality"), PropertyWindowModality); propertyTypeHash.insert(QStringLiteral("windowModified"), PropertyWindowModified); propertyTypeHash.insert(QStringLiteral("styleSheet"), PropertyStyleSheet); propertyTypeHash.insert(QStringLiteral("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(QStringLiteral("QDesigner"))) { baseMeta = baseMeta->superClass(); } Q_ASSERT(baseMeta != 0); QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(d->m_object); d->m_fwb = qobject_cast(formWindow); if (d->m_fwb) { d->m_pixmapCache = d->m_fwb->pixmapCache(); d->m_iconCache = d->m_fwb->iconCache(); d->m_fwb->addReloadablePropertySheet(this, object); } for (int index=0; indexm_meta->property(index); const QString name = p->name(); if (p->type() == QVariant::KeySequence) { createFakeProperty(name); } else { setVisible(index, false); // use the default for `real' properties } QString pgroup = baseMeta->className(); if (const QDesignerMetaObjectInterface *pmeta = propertyIntroducedBy(baseMeta, index)) { pgroup = pmeta->className(); } Info &info = d->ensureInfo(index); info.group = pgroup; info.propertyType = propertyTypeFromName(name); const QVariant::Type type = p->type(); switch (type) { case QVariant::Cursor: case QVariant::Icon: case QVariant::Pixmap: info.defaultValue = p->read(d->m_object); if (type == QVariant::Icon || type == QVariant::Pixmap) d->addResourceProperty(index, type); break; case QVariant::String: d->addStringProperty(index); break; case QVariant::StringList: d->addStringListProperty(index); break; case QVariant::KeySequence: d->addKeySequenceProperty(index); break; default: break; } } if (object->isWidgetType()) { createFakeProperty(QStringLiteral("focusPolicy")); createFakeProperty(QStringLiteral("cursor")); createFakeProperty(QStringLiteral("toolTip")); createFakeProperty(QStringLiteral("whatsThis")); createFakeProperty(QStringLiteral("acceptDrops")); createFakeProperty(QStringLiteral("dragEnabled")); // windowModality/Opacity is visible only for the main container, in which case the form windows enables it on loading setVisible(createFakeProperty(QStringLiteral("windowModality")), false); setVisible(createFakeProperty(QStringLiteral("windowOpacity"), double(1.0)), false); if (qobject_cast(d->m_object)) { // prevent toolbars from being dragged off createFakeProperty(QStringLiteral("floatable"), QVariant(true)); } else { if (qobject_cast(d->m_object)) { // Keep the menu bar editable in the form even if a native menu bar is used. const bool nativeMenuBarDefault = !qApp->testAttribute(Qt::AA_DontUseNativeMenuBar); createFakeProperty(QStringLiteral("nativeMenuBar"), QVariant(nativeMenuBarDefault)); } } if (d->m_canHaveLayoutAttributes) { static const QString layoutGroup = QStringLiteral("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(QStringLiteral("buddy"), QVariant(QByteArray())); /* We need to create a fake property since the property does not work * for non-toplevel windows or on other systems than Mac and only if * it is above a certain Mac OS version. */ if (qobject_cast(d->m_object)) createFakeProperty(QStringLiteral("unifiedTitleAndToolBarOnMac"), false); } if (qobject_cast(object)) { createFakeProperty(QStringLiteral("modal")); } if (qobject_cast(object)) { createFakeProperty(QStringLiteral("floating")); } typedef QList ByteArrayList; const ByteArrayList names = object->dynamicPropertyNames(); if (!names.empty()) { const ByteArrayList::const_iterator cend = names.constEnd(); for (ByteArrayList::const_iterator it = names.constBegin(); it != cend; ++it) { const char* cName = it->constData(); const QString name = QString::fromLatin1(cName); const int idx = addDynamicProperty(name, object->property(cName)); if (idx != -1) d->ensureInfo(idx).kind = QDesignerPropertySheetPrivate::DefaultDynamicProperty; } } } QDesignerPropertySheet::~QDesignerPropertySheet() { if (d->m_fwb) d->m_fwb->removeReloadablePropertySheet(this); delete d; } QObject *QDesignerPropertySheet::object() const { return d->m_object; } bool QDesignerPropertySheet::dynamicPropertiesAllowed() const { return true; } bool QDesignerPropertySheet::canAddDynamicProperty(const QString &propName) const { // used internally if (propName == QStringLiteral("database") || propName == QStringLiteral("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(QStringLiteral("_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 = QVariant::fromValue(qdesigner_internal::PropertySheetIconValue()); else if (value.type() == QVariant::Pixmap) v = QVariant::fromValue(qdesigner_internal::PropertySheetPixmapValue()); else if (value.type() == QVariant::String) v = QVariant::fromValue(qdesigner_internal::PropertySheetStringValue(value.toString())); else if (value.type() == QVariant::StringList) v = QVariant::fromValue(qdesigner_internal::PropertySheetStringListValue(value.toStringList())); else if (value.type() == QVariant::KeySequence) { const QKeySequence keySequence = qvariant_cast(value); v = QVariant::fromValue(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")); switch (value.type()) { case QVariant::Icon: case QVariant::Pixmap: d->addResourceProperty(index, value.type()); break; case QVariant::String: d->addStringProperty(index); break; case QVariant::StringList: d->addStringListProperty(index); break; case QVariant::KeySequence: d->addKeySequenceProperty(index); break; default: break; } 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 = QVariant::fromValue(qdesigner_internal::PropertySheetStringValue()); if (v.type() == QVariant::StringList) v = QVariant::fromValue(qdesigner_internal::PropertySheetStringListValue()); if (v.type() == QVariant::KeySequence) v = QVariant::fromValue(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 QVariant::fromValue(value); } if (d->isStringListProperty(index)) { const QStringList listValue = metaProperty(index).toStringList(); qdesigner_internal::PropertySheetStringListValue value = d->stringListProperty(index); if (listValue != value.value()) { value.setValue(listValue); d->setStringListProperty(index, value); // cache it } return QVariant::fromValue(value); } if (d->isKeySequenceProperty(index)) { QKeySequence keyValue = qvariant_cast(metaProperty(index)); qdesigner_internal::PropertySheetKeySequenceValue value = d->keySequenceProperty(index); if (keyValue != value.value()) { value.setValue(keyValue); d->setKeySequenceProperty(index, value); // cache it } return QVariant::fromValue(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())); v.setValue(psflags); } break; case QDesignerMetaPropertyInterface::EnumKind: { qdesigner_internal::PropertySheetEnumValue pse = qdesigner_internal::PropertySheetEnumValue(v.toInt(), designerMetaEnumFor(p->enumerator())); v.setValue(pse); } break; case QDesignerMetaPropertyInterface::OtherKind: break; } return v; } QVariant QDesignerPropertySheet::resolvePropertyValue(int index, const QVariant &value) const { if (value.canConvert()) return qvariant_cast(value).value; if (value.canConvert()) return qvariant_cast(value).value; if (value.canConvert()) return qvariant_cast(value).value(); if (value.canConvert()) return qvariant_cast(value).value(); if (value.canConvert()) return qvariant_cast(value).value(); if (value.canConvert()) { const QString path = qvariant_cast(value).path(); if (path.isEmpty()) return defaultResourceProperty(index); if (d->m_pixmapCache) { return d->m_pixmapCache->pixmap(qvariant_cast(value)); } } if (value.canConvert()) { const unsigned mask = qvariant_cast(value).mask(); if (mask == 0) return defaultResourceProperty(index); if (d->m_iconCache) return d->m_iconCache->icon(qvariant_cast(value)); } return value; } void QDesignerPropertySheet::setFakeProperty(int index, const QVariant &value) { Q_ASSERT(isFakeProperty(index)); QVariant &v = d->m_fakeProperties[index]; // set resource properties also (if we are going to have fake resource properties) if (value.canConvert() || value.canConvert()) { v = value; } else if (v.canConvert()) { qdesigner_internal::PropertySheetFlagValue f = qvariant_cast(v); f.value = value.toInt(); v.setValue(f); Q_ASSERT(value.type() == QVariant::Int); } else if (v.canConvert()) { qdesigner_internal::PropertySheetEnumValue e = qvariant_cast(v); e.value = value.toInt(); v.setValue(e); Q_ASSERT(value.type() == QVariant::Int); } else { v = value; } } void QDesignerPropertySheet::clearFakeProperties() { d->m_fakeProperties.clear(); } // Buddy needs to be byte array, else uic won't work static QVariant toByteArray(const QVariant &value) { if (value.type() == QVariant::ByteArray) return value; const QByteArray ba = value.toString().toUtf8(); return QVariant(ba); } void QDesignerPropertySheet::setProperty(int index, const QVariant &value) { if (d->invalidIndex(Q_FUNC_INFO, index)) return; if (isAdditionalProperty(index)) { if (d->m_objectType == ObjectLabel && propertyType(index) == PropertyBuddy) { QFormBuilderExtra::applyBuddy(value.toString(), QFormBuilderExtra::BuddyApplyVisibleOnly, qobject_cast(d->m_object)); d->m_addProperties[index] = toByteArray(value); return; } if (isFakeLayoutProperty(index)) { QDesignerPropertySheetExtension *layoutPropertySheet; if (d->layout(&layoutPropertySheet) && layoutPropertySheet) { const QString newPropName = d->transformLayoutPropertyName(index); if (!newPropName.isEmpty()) { const int newIndex = layoutPropertySheet->indexOf(newPropName); if (newIndex != -1) layoutPropertySheet->setProperty(newIndex, value); } } } if (isDynamicProperty(index) || isDefaultDynamicProperty(index)) { if (d->isResourceProperty(index)) d->setResourceProperty(index, value); if (d->isStringProperty(index)) d->setStringProperty(index, qvariant_cast(value)); if (d->isStringListProperty(index)) d->setStringListProperty(index, qvariant_cast(value)); if (d->isKeySequenceProperty(index)) d->setKeySequenceProperty(index, qvariant_cast(value)); d->m_object->setProperty(propertyName(index).toUtf8(), resolvePropertyValue(index, value)); if (d->m_object->isWidgetType()) { QWidget *w = qobject_cast(d->m_object); w->setStyleSheet(w->styleSheet()); } } d->m_addProperties[index] = value; } else if (isFakeProperty(index)) { setFakeProperty(index, value); } else { if (d->isResourceProperty(index)) d->setResourceProperty(index, value); if (d->isStringProperty(index)) d->setStringProperty(index, qvariant_cast(value)); if (d->isStringListProperty(index)) d->setStringListProperty(index, qvariant_cast(value)); if (d->isKeySequenceProperty(index)) d->setKeySequenceProperty(index, qvariant_cast(value)); const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); p->write(d->m_object, resolvePropertyValue(index, value)); if (qobject_cast(d->m_object) && propertyType(index) == PropertyCheckable) { const int idx = indexOf(QStringLiteral("focusPolicy")); if (!isChanged(idx)) { qdesigner_internal::PropertySheetEnumValue e = qvariant_cast(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; v.setValue(e); setFakeProperty(idx, v); } else { e.value = Qt::NoFocus; QVariant v; v.setValue(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)) { qdesigner_internal::PropertySheetStringValue value; // Main container: Reset to stored class name as not to change the file names generated by uic. if (propertyName(index) == QStringLiteral("objectName")) { const QVariant classNameDefaultV = d->m_object->property("_q_classname"); if (classNameDefaultV.isValid()) value.setValue(classNameDefaultV.toString()); } setProperty(index, QVariant::fromValue(value)); return true; } if (d->isStringListProperty(index)) setProperty(index, QVariant::fromValue(qdesigner_internal::PropertySheetStringListValue())); if (d->isKeySequenceProperty(index)) setProperty(index, QVariant::fromValue(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 = QVariant::fromValue(qdesigner_internal::PropertySheetStringValue(newValue.toString())); } else if (d->isStringListProperty(index)) { newValue = QVariant::fromValue(qdesigner_internal::PropertySheetStringListValue(newValue.toStringList())); } else if (d->isKeySequenceProperty(index)) { const QKeySequence keySequence = qvariant_cast(newValue); newValue = QVariant::fromValue(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 ObjectLayoutWidget: if (pType == PropertyLayoutLeftMargin || pType == PropertyLayoutTopMargin || pType == PropertyLayoutRightMargin || pType == PropertyLayoutBottomMargin) value = 0; break; default: break; } setProperty(index, value); return true; } return false; } else if (isFakeProperty(index)) { const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); const bool result = p->reset(d->m_object); d->m_fakeProperties[index] = p->read(d->m_object); return result; } else if (propertyType(index) == PropertyGeometry && d->m_object->isWidgetType()) { if (QWidget *w = qobject_cast(d->m_object)) { QWidget *widget = w; if (qdesigner_internal::Utils::isCentralWidget(d->m_fwb, widget) && d->m_fwb->parentWidget()) widget = d->m_fwb->parentWidget(); if (widget != w && widget->parentWidget()) { QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); widget->parentWidget()->adjustSize(); } QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); widget->adjustSize(); return true; } } // ### TODO: reset for fake properties. const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); return p->reset(d->m_object); } bool QDesignerPropertySheet::isChanged(int index) const { if (d->invalidIndex(Q_FUNC_INFO, index)) return false; if (isAdditionalProperty(index)) { if (isFakeLayoutProperty(index)) { QDesignerPropertySheetExtension *layoutPropertySheet; if (d->layout(&layoutPropertySheet) && layoutPropertySheet) { const QString newPropName = d->transformLayoutPropertyName(index); if (!newPropName.isEmpty()) { const int newIndex = layoutPropertySheet->indexOf(newPropName); if (newIndex != -1) return layoutPropertySheet->isChanged(newIndex); return false; } } } } return d->m_info.value(index).changed; } void QDesignerPropertySheet::setChanged(int index, bool changed) { if (d->invalidIndex(Q_FUNC_INFO, index)) return; if (isAdditionalProperty(index)) { if (isFakeLayoutProperty(index)) { QDesignerPropertySheetExtension *layoutPropertySheet; if (d->layout(&layoutPropertySheet) && layoutPropertySheet) { const QString newPropName = d->transformLayoutPropertyName(index); if (!newPropName.isEmpty()) { const int newIndex = layoutPropertySheet->indexOf(newPropName); if (newIndex != -1) layoutPropertySheet->setChanged(newIndex, changed); } } } } if (d->isReloadableProperty(index)) { if (d->m_fwb) { if (changed) d->m_fwb->addReloadableProperty(this, index); else d->m_fwb->removeReloadableProperty(this, index); } } d->ensureInfo(index).changed = changed; } bool QDesignerPropertySheet::isFakeLayoutProperty(int index) const { if (!isAdditionalProperty(index)) return false; switch (propertyType(index)) { case PropertyLayoutObjectName: case PropertyLayoutSizeConstraint: return true; case PropertyLayoutLeftMargin: case PropertyLayoutTopMargin: case PropertyLayoutRightMargin: case PropertyLayoutBottomMargin: case PropertyLayoutSpacing: case PropertyLayoutHorizontalSpacing: case PropertyLayoutVerticalSpacing: case PropertyLayoutFieldGrowthPolicy: case PropertyLayoutRowWrapPolicy: case PropertyLayoutLabelAlignment: case PropertyLayoutFormAlignment: case PropertyLayoutBoxStretch: case PropertyLayoutGridRowStretch: case PropertyLayoutGridColumnStretch: case PropertyLayoutGridRowMinimumHeight: case PropertyLayoutGridColumnMinimumWidth: return d->m_canHaveLayoutAttributes; default: break; } return false; } // Determine the "designable" state of a property. Properties, which have // a per-object boolean test function that returns false are shown in // disabled state ("checked" depending on "checkable", etc.) // Properties, which are generally not designable independent // of the object are not shown at all. enum DesignableState { PropertyIsDesignable, // Object has a Designable test function that returns false. PropertyOfObjectNotDesignable, PropertyNotDesignable }; static inline DesignableState designableState(const QDesignerMetaPropertyInterface *p, const QObject *object) { if (p->attributes(object) & QDesignerMetaPropertyInterface::DesignableAttribute) return PropertyIsDesignable; return (p->attributes() & QDesignerMetaPropertyInterface::DesignableAttribute) ? PropertyOfObjectNotDesignable : PropertyNotDesignable; } bool QDesignerPropertySheet::isVisible(int index) const { if (d->invalidIndex(Q_FUNC_INFO, index)) return false; const PropertyType type = propertyType(index); if (isAdditionalProperty(index)) { if (isFakeLayoutProperty(index) && d->m_object->isWidgetType()) { const QLayout *currentLayout = d->layout(); if (!currentLayout) return false; const int visibleMask = qdesigner_internal::LayoutProperties::visibleProperties(currentLayout); switch (type) { case PropertyLayoutSpacing: return visibleMask & qdesigner_internal::LayoutProperties::SpacingProperty; case PropertyLayoutHorizontalSpacing: case PropertyLayoutVerticalSpacing: return visibleMask & qdesigner_internal::LayoutProperties::HorizSpacingProperty; case PropertyLayoutFieldGrowthPolicy: return visibleMask & qdesigner_internal::LayoutProperties::FieldGrowthPolicyProperty; case PropertyLayoutRowWrapPolicy: return visibleMask & qdesigner_internal::LayoutProperties::RowWrapPolicyProperty; case PropertyLayoutLabelAlignment: return visibleMask & qdesigner_internal::LayoutProperties::LabelAlignmentProperty; case PropertyLayoutFormAlignment: return visibleMask & qdesigner_internal::LayoutProperties::FormAlignmentProperty; case PropertyLayoutBoxStretch: return visibleMask & qdesigner_internal::LayoutProperties::BoxStretchProperty; case PropertyLayoutGridRowStretch: return visibleMask & qdesigner_internal::LayoutProperties::GridRowStretchProperty; case PropertyLayoutGridColumnStretch: return visibleMask & qdesigner_internal::LayoutProperties::GridColumnStretchProperty; case PropertyLayoutGridRowMinimumHeight: return visibleMask & qdesigner_internal::LayoutProperties::GridRowMinimumHeightProperty; case PropertyLayoutGridColumnMinimumWidth: return visibleMask & qdesigner_internal::LayoutProperties::GridColumnMinimumWidthProperty; default: break; } return true; } return d->m_info.value(index).visible; } if (isFakeProperty(index)) { 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(d->m_object), &isManaged); return !isManaged || lt == qdesigner_internal::LayoutInfo::NoLayout; } if (d->m_info.value(index).visible == true) // Sun CC 5.5 oddity, wants true return true; // Enable setting of properties for statically non-designable properties // as this might be done via TaskMenu/Cursor::setProperty. Note that those // properties are not visible. const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); return (p->accessFlags() & QDesignerMetaPropertyInterface::WriteAccess) && designableState(p, d->m_object) != PropertyOfObjectNotDesignable; } bool QDesignerPropertySheet::isAttribute(int index) const { if (d->invalidIndex(Q_FUNC_INFO, index)) return false; if (isAdditionalProperty(index)) return d->m_info.value(index).attribute; if (isFakeProperty(index)) return false; return d->m_info.value(index).attribute; } void QDesignerPropertySheet::setAttribute(int index, bool attribute) { if (d->invalidIndex(Q_FUNC_INFO, index)) return; d->ensureInfo(index).attribute = attribute; } QDesignerFormEditorInterface *QDesignerPropertySheet::core() const { return d->m_core; } bool QDesignerPropertySheet::internalDynamicPropertiesEnabled() { return QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled; } void QDesignerPropertySheet::setInternalDynamicPropertiesEnabled(bool v) { QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled = v; } // ---------- QDesignerAbstractPropertySheetFactory struct QDesignerAbstractPropertySheetFactory::PropertySheetFactoryPrivate { PropertySheetFactoryPrivate(); const QString m_propertySheetId; const QString m_dynamicPropertySheetId; typedef QMap ExtensionMap; ExtensionMap m_extensions; typedef QHash ExtendedSet; ExtendedSet m_extended; }; QDesignerAbstractPropertySheetFactory::PropertySheetFactoryPrivate::PropertySheetFactoryPrivate() : m_propertySheetId(Q_TYPEID(QDesignerPropertySheetExtension)), m_dynamicPropertySheetId(Q_TYPEID(QDesignerDynamicPropertySheetExtension)) { } // ---------- QDesignerAbstractPropertySheetFactory QDesignerAbstractPropertySheetFactory::QDesignerAbstractPropertySheetFactory(QExtensionManager *parent) : QExtensionFactory(parent), m_impl(new PropertySheetFactoryPrivate) { } QDesignerAbstractPropertySheetFactory::~QDesignerAbstractPropertySheetFactory() { delete m_impl; } QObject *QDesignerAbstractPropertySheetFactory::extension(QObject *object, const QString &iid) const { typedef PropertySheetFactoryPrivate::ExtensionMap ExtensionMap; if (!object) return 0; if (iid != m_impl->m_propertySheetId && iid != m_impl->m_dynamicPropertySheetId) return 0; ExtensionMap::iterator it = m_impl->m_extensions.find(object); if (it == m_impl->m_extensions.end()) { if (QObject *ext = createPropertySheet(object, const_cast(this))) { connect(ext, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); it = m_impl->m_extensions.insert(object, ext); } } if (!m_impl->m_extended.contains(object)) { connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); m_impl->m_extended.insert(object, true); } if (it == m_impl->m_extensions.end()) return 0; return it.value(); } void QDesignerAbstractPropertySheetFactory::objectDestroyed(QObject *object) { QMutableMapIterator it(m_impl->m_extensions); while (it.hasNext()) { it.next(); QObject *o = it.key(); if (o == object || object == it.value()) { it.remove(); } } m_impl->m_extended.remove(object); } QT_END_NAMESPACE