qt_demoe/third/designer/lib/shared/qdesigner_propertysheet.cpp

1649 lines
65 KiB
C++

/****************************************************************************
**
** Copyright (C) 2010 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$
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qdesigner_propertysheet_p.h"
#include "qdesigner_utils_p.h"
#include "formwindowbase_p.h"
#include "layoutinfo_p.h"
#include "qlayout_widget_p.h"
#include "qdesigner_introspection_p.h"
#include <formbuilderextra_p.h>
#include <QtDesigner/QDesignerFormWindowInterface>
#include <QtDesigner/QDesignerFormEditorInterface>
#include <QtDesigner/QDesignerWidgetDataBaseInterface>
#include <QtCore/QDebug>
#include <QtGui/QLayout>
#include <QtGui/QDockWidget>
#include <QtGui/QDialog>
#include <QtGui/QLabel>
#include <QtGui/QGroupBox>
#include <QtGui/QStyle>
#include <QtGui/QApplication>
#include <QtGui/QToolBar>
#include <QtGui/QMainWindow>
#include <QtGui/QMenuBar>
QT_BEGIN_NAMESPACE
#define USE_LAYOUT_SIZE_CONSTRAINT
static const QDesignerMetaObjectInterface *propertyIntroducedBy(const QDesignerMetaObjectInterface *meta, int index)
{
if (index >= meta->propertyOffset())
return meta;
if (meta->superClass())
return propertyIntroducedBy(meta->superClass(), index);
return 0;
}
// Layout fake properties (prefixed by 'layout' to distinguish them from other 'margins'
// that might be around. These are forwarded to the layout sheet (after name transformation).
//
// 'layoutObjectName' is new for 4.4. It is the name of the actual layout.
// Up to 4.3, QLayoutWidget's name was displayed in the objectinspector.
// This changes with 4.4; the layout name is displayed. This means that for
// old forms, QLayoutWidget will show up as ''; however, the uic code will
// still use 'verticalLayout' (in case someone accesses it). New Layouts get autogenerated names,
// legacy forms will keep their empty names (unless someone types in a new name).
static const char *layoutObjectNameC = "layoutName";
static const char *layoutLeftMarginC = "layoutLeftMargin";
static const char *layoutTopMarginC = "layoutTopMargin";
static const char *layoutRightMarginC = "layoutRightMargin";
static const char *layoutBottomMarginC = "layoutBottomMargin";
static const char *layoutSpacingC = "layoutSpacing";
static const char *layoutHorizontalSpacingC = "layoutHorizontalSpacing";
static const char *layoutVerticalSpacingC = "layoutVerticalSpacing";
static const char *layoutSizeConstraintC = "layoutSizeConstraint";
// form layout
static const char *layoutFieldGrowthPolicyC = "layoutFieldGrowthPolicy";
static const char *layoutRowWrapPolicyC = "layoutRowWrapPolicy";
static const char *layoutLabelAlignmentC = "layoutLabelAlignment";
static const char *layoutFormAlignmentC = "layoutFormAlignment";
// stretches
static const char *layoutboxStretchPropertyC = "layoutStretch";
static const char *layoutGridRowStretchPropertyC = "layoutRowStretch";
static const char *layoutGridColumnStretchPropertyC = "layoutColumnStretch";
static const char *layoutGridRowMinimumHeightC = "layoutRowMinimumHeight";
static const char *layoutGridColumnMinimumWidthC = "layoutColumnMinimumWidth";
// Find the form editor in the hierarchy.
// We know that the parent of the sheet is the extension manager
// whose parent is the core.
static QDesignerFormEditorInterface *formEditorForObject(QObject *o) {
do {
if (QDesignerFormEditorInterface* core = qobject_cast<QDesignerFormEditorInterface*>(o))
return core;
o = o->parent();
} while(o);
Q_ASSERT(o);
return 0;
}
static bool hasLayoutAttributes(QDesignerFormEditorInterface *core, QObject *object)
{
if (!object->isWidgetType())
return false;
QWidget *w = qobject_cast<QWidget *>(object);
if (const QDesignerWidgetDataBaseInterface *db = core->widgetDataBase()) {
if (db->isContainer(w))
return true;
}
return false;
}
// Cache DesignerMetaEnum by scope/name of a QMetaEnum
static const qdesigner_internal::DesignerMetaEnum &designerMetaEnumFor(const QDesignerMetaEnumInterface *me)
{
typedef QPair<QString, QString> ScopeNameKey;
typedef QMap<ScopeNameKey, qdesigner_internal::DesignerMetaEnum> DesignerMetaEnumCache;
static DesignerMetaEnumCache cache;
const QString name = me->name();
const QString scope = me->scope();
const ScopeNameKey key = ScopeNameKey(scope, name);
DesignerMetaEnumCache::iterator it = cache.find(key);
if (it == cache.end()) {
qdesigner_internal::DesignerMetaEnum dme = qdesigner_internal::DesignerMetaEnum(name, scope, me->separator());
const int keyCount = me->keyCount();
for (int i=0; i < keyCount; ++i)
dme.addKey(me->value(i), me->key(i));
it = cache.insert(key, dme);
}
return it.value();
}
// Cache DesignerMetaFlags by scope/name of a QMetaEnum
static const qdesigner_internal::DesignerMetaFlags &designerMetaFlagsFor(const QDesignerMetaEnumInterface *me)
{
typedef QPair<QString, QString> ScopeNameKey;
typedef QMap<ScopeNameKey, qdesigner_internal::DesignerMetaFlags> DesignerMetaFlagsCache;
static DesignerMetaFlagsCache cache;
const QString name = me->name();
const QString scope = me->scope();
const ScopeNameKey key = ScopeNameKey(scope, name);
DesignerMetaFlagsCache::iterator it = cache.find(key);
if (it == cache.end()) {
qdesigner_internal::DesignerMetaFlags dme = qdesigner_internal::DesignerMetaFlags(name, scope, me->separator());
const int keyCount = me->keyCount();
for (int i=0; i < keyCount; ++i)
dme.addKey(me->value(i), me->key(i));
it = cache.insert(key, dme);
}
return it.value();
}
// ------------ QDesignerMemberSheetPrivate
class QDesignerPropertySheetPrivate {
public:
typedef QDesignerPropertySheet::PropertyType PropertyType;
typedef QDesignerPropertySheet::ObjectType ObjectType;
explicit QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent);
bool invalidIndex(const char *functionName, int index) const;
inline int count() const { return m_meta->propertyCount() + m_addProperties.count(); }
PropertyType propertyType(int index) const;
QString transformLayoutPropertyName(int index) const;
QLayout* layout(QDesignerPropertySheetExtension **layoutPropertySheet = 0) const;
static ObjectType objectType(const QObject *o);
bool isReloadableProperty(int index) const;
bool isResourceProperty(int index) const;
void addResourceProperty(int index, QVariant::Type type);
QVariant resourceProperty(int index) const;
void setResourceProperty(int index, const QVariant &value);
QVariant emptyResourceProperty(int index) const; // of type PropertySheetPixmapValue / PropertySheetIconValue
QVariant defaultResourceProperty(int index) const; // of type QPixmap / QIcon (maybe it can be generalized for all types, not resource only)
bool isStringProperty(int index) const;
void addStringProperty(int index);
qdesigner_internal::PropertySheetStringValue stringProperty(int index) const;
void setStringProperty(int index, const qdesigner_internal::PropertySheetStringValue &value);
bool isKeySequenceProperty(int index) const;
void addKeySequenceProperty(int index);
qdesigner_internal::PropertySheetKeySequenceValue keySequenceProperty(int index) const;
void setKeySequenceProperty(int index, const qdesigner_internal::PropertySheetKeySequenceValue &value);
enum PropertyKind { NormalProperty, FakeProperty, DynamicProperty, DefaultDynamicProperty };
class Info {
public:
Info();
QString group;
QVariant defaultValue;
bool changed;
bool visible;
bool attribute;
bool reset;
PropertyType propertyType;
PropertyKind kind;
};
Info &ensureInfo(int index);
QDesignerPropertySheet *q;
QDesignerFormEditorInterface *m_core;
const QDesignerMetaObjectInterface *m_meta;
const ObjectType m_objectType;
typedef QHash<int, Info> InfoHash;
InfoHash m_info;
QHash<int, QVariant> m_fakeProperties;
QHash<int, QVariant> m_addProperties;
QHash<QString, int> m_addIndex;
QHash<int, QVariant> m_resourceProperties; // only PropertySheetPixmapValue snd PropertySheetIconValue here
QHash<int, qdesigner_internal::PropertySheetStringValue> m_stringProperties; // only PropertySheetStringValue
QHash<int, qdesigner_internal::PropertySheetKeySequenceValue> m_keySequenceProperties; // only PropertySheetKeySequenceValue
const bool m_canHaveLayoutAttributes;
// Variables used for caching the layout, access via layout().
QPointer<QObject> m_object;
mutable QPointer<QLayout> m_lastLayout;
mutable QDesignerPropertySheetExtension *m_lastLayoutPropertySheet;
mutable bool m_LastLayoutByDesigner;
qdesigner_internal::DesignerPixmapCache *m_pixmapCache;
qdesigner_internal::DesignerIconCache *m_iconCache;
QPointer<qdesigner_internal::FormWindowBase> m_fwb;
// Enable Qt's internal properties starting with prefix "_q_"
static bool m_internalDynamicPropertiesEnabled;
};
bool QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled = false;
/*
The property is reloadable if its contents depends on resource.
*/
bool QDesignerPropertySheetPrivate::isReloadableProperty(int index) const
{
return isResourceProperty(index)
|| propertyType(index) == QDesignerPropertySheet::PropertyStyleSheet
|| 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