From a54bdf3dc7c077a5fd7e6fac95d8048ef1f7257f Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 19 May 2015 16:11:35 +0200 Subject: [PATCH] QmlPuppet: Introduce DesignerCustomObjectData This class holds the additional data we use to annotate QObject. At the moment we store the default values and bindings there. I also moved the code to populate and read the hashes into that class. Change-Id: Ib5e4b5291cfd2bf5555a896bf42578d07f2c6253 Reviewed-by: Tim Jenssen --- .../instances/objectnodeinstance.cpp | 87 +------ .../qml2puppet/instances/objectnodeinstance.h | 6 +- .../designercustomobjectdata.cpp | 225 ++++++++++++++++++ .../qmlprivategate/designercustomobjectdata.h | 84 +++++++ .../qmlprivategate/qmlprivategate.cpp | 26 ++ .../qmlpuppet/qmlprivategate/qmlprivategate.h | 7 + .../qmlprivategate/qmlprivategate.pri | 6 +- 7 files changed, 353 insertions(+), 88 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/qmlprivategate/designercustomobjectdata.cpp create mode 100644 share/qtcreator/qml/qmlpuppet/qmlprivategate/designercustomobjectdata.h diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp index 565b33f46a9..e7999b9b976 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp @@ -529,68 +529,14 @@ void ObjectNodeInstance::refreshProperty(const PropertyName &name) property.write(oldValue); } -bool ObjectNodeInstance::hasBindingForProperty(const PropertyName &name, bool *hasChanged) const +bool ObjectNodeInstance::hasBindingForProperty(const PropertyName &propertyName, bool *hasChanged) const { - if (QmlPrivateGate::isPropertyBlackListed(name)) - return false; - - QQmlProperty property(object(), name, context()); - - bool hasBinding = QQmlPropertyPrivate::binding(property); - - if (hasChanged) { - *hasChanged = hasBinding != m_hasBindingHash.value(name, false); - if (*hasChanged) - m_hasBindingHash.insert(name, hasBinding); - } - - return QQmlPropertyPrivate::binding(property); + return QmlPrivateGate::hasBindingForProperty(object(), propertyName, hasChanged); } void ObjectNodeInstance::doResetProperty(const PropertyName &propertyName) { - QQmlProperty property(object(), propertyName, context()); - - if (!property.isValid()) - return; - - QVariant oldValue = property.read(); - if (oldValue.type() == QVariant::Url) { - QUrl url = oldValue.toUrl(); - QString path = url.toLocalFile(); - if (QFileInfo(path).exists() && nodeInstanceServer()) - nodeInstanceServer()->removeFilePropertyFromFileSystemWatcher(object(), propertyName, path); - } - - - QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(property); - if (binding && !(hasValidResetBinding(propertyName) && resetBinding(propertyName) == binding)) { - binding->setEnabled(false, 0); - binding->destroy(); - } - - - if (hasValidResetBinding(propertyName)) { - QQmlAbstractBinding *binding = resetBinding(propertyName); - QQmlPropertyPrivate::setBinding(property, binding, QQmlPropertyPrivate::DontRemoveBinding); - binding->update(); - } else if (property.isResettable()) { - property.reset(); - } else if (property.propertyTypeCategory() == QQmlProperty::List) { - QQmlListReference list = qvariant_cast(property.read()); - - if (!QmlPrivateGate::hasFullImplementedListInterface(list)) { - qWarning() << "Property list interface not fully implemented for Class " << property.property().typeName() << " in property " << property.name() << "!"; - return; - } - - list.clear(); - } else if (property.isWritable()) { - if (property.read() == resetValue(propertyName)) - return; - - property.write(resetValue(propertyName)); - } + QmlPrivateGate::doResetProperty(object(), propertyName); } QVariant ObjectNodeInstance::property(const PropertyName &name) const @@ -860,38 +806,17 @@ void ObjectNodeInstance::deactivateState() void ObjectNodeInstance::populateResetHashes() { - PropertyNameList propertyNameList = QmlPrivateGate::propertyNameListForWritableProperties(object()); - - foreach (const PropertyName &propertyName, propertyNameList) { - QQmlProperty property(object(), propertyName, QQmlEngine::contextForObject(object())); - - QQmlAbstractBinding::Pointer binding = QQmlAbstractBinding::getPointer(QQmlPropertyPrivate::binding(property)); - if (binding) { - m_resetBindingHash.insert(propertyName, binding); - } else if (property.isWritable()) { - m_resetValueHash.insert(propertyName, property.read()); - } - } - - m_resetValueHash.insert("Layout.rowSpan", 1); - m_resetValueHash.insert("Layout.columnSpan", 1); - m_resetValueHash.insert("Layout.fillHeight", false); - m_resetValueHash.insert("Layout.fillWidth", false); -} - -QQmlAbstractBinding *ObjectNodeInstance::resetBinding(const PropertyName &propertyName) const -{ - return m_resetBindingHash.value(propertyName).data(); + QmlPrivateGate::registerCustomData(object(), context()); } bool ObjectNodeInstance::hasValidResetBinding(const PropertyName &propertyName) const { - return m_resetBindingHash.contains(propertyName) && m_resetBindingHash.value(propertyName).data(); + return QmlPrivateGate::hasValidResetBinding(object(), propertyName); } QVariant ObjectNodeInstance::resetValue(const PropertyName &propertyName) const { - return m_resetValueHash.value(propertyName); + return QmlPrivateGate::getResetValue(object(), propertyName); } QImage ObjectNodeInstance::renderImage() const diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h index d469ea67793..61f947f9922 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h @@ -150,7 +150,6 @@ public: void populateResetHashes(); bool hasValidResetBinding(const PropertyName &propertyName) const; - QQmlAbstractBinding *resetBinding(const PropertyName &propertyName) const; QVariant resetValue(const PropertyName &propertyName) const; QObject *object() const; @@ -163,7 +162,7 @@ public: void setInLayoutable(bool isInLayoutable); virtual void refreshLayoutable(); - bool hasBindingForProperty(const PropertyName &name, bool *hasChanged = 0) const; + bool hasBindingForProperty(const PropertyName &propertyName, bool *hasChanged = 0) const; QQmlContext *context() const; QQmlEngine *engine() const; @@ -199,9 +198,6 @@ protected: static QVariant enumationValue(const Enumeration &enumeration); private: - QHash m_resetValueHash; - QHash > m_resetBindingHash; - mutable QHash m_hasBindingHash; QString m_id; QPointer m_nodeInstanceServer; diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/designercustomobjectdata.cpp b/share/qtcreator/qml/qmlpuppet/qmlprivategate/designercustomobjectdata.cpp new file mode 100644 index 00000000000..8888b12a6ec --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/designercustomobjectdata.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "designercustomobjectdata.h" + +#include + +#include +#include + +#include + +namespace QmlDesigner { + +namespace Internal { + +namespace QmlPrivateGate { + +QHash m_objectToDataHash; + +DesignerCustomObjectData::DesignerCustomObjectData(QObject *object, QQmlContext *context) + : m_object(object) + , m_context(context) +{ + if (object) + populateResetHashes(); + m_objectToDataHash.insert(object, this); + QObject::connect(object, &QObject::destroyed, [=] { + m_objectToDataHash.remove(object); + delete this; + }); +} + +void DesignerCustomObjectData::registerData(QObject *object, QQmlContext *context) +{ + new DesignerCustomObjectData(object, context); +} + +DesignerCustomObjectData *DesignerCustomObjectData::get(QObject *object) +{ + return m_objectToDataHash.value(object); +} + +QVariant DesignerCustomObjectData::getResetValue(QObject *object, const PropertyName &propertyName) +{ + DesignerCustomObjectData* data = get(object); + + if (data) + return data->getResetValue(propertyName); + + return QVariant(); +} + +void DesignerCustomObjectData::doResetProperty(QObject *object, const PropertyName &propertyName) +{ + DesignerCustomObjectData* data = get(object); + + if (data) + data->doResetProperty(propertyName); +} + +bool DesignerCustomObjectData::hasValidResetBinding(QObject *object, const PropertyName &propertyName) +{ + DesignerCustomObjectData* data = get(object); + + if (data) + return data->hasValidResetBinding(propertyName); + + return false; +} + +bool DesignerCustomObjectData::hasBindingForProperty(QObject *object, const PropertyName &propertyName, bool *hasChanged) +{ + DesignerCustomObjectData* data = get(object); + + if (data) + return data->hasBindingForProperty(propertyName, hasChanged); + + return false; +} + +void DesignerCustomObjectData::populateResetHashes() +{ + PropertyNameList propertyNameList = QmlPrivateGate::propertyNameListForWritableProperties(object()); + + foreach (const PropertyName &propertyName, propertyNameList) { + QQmlProperty property(object(), propertyName, QQmlEngine::contextForObject(object())); + + QQmlAbstractBinding::Pointer binding = QQmlAbstractBinding::getPointer(QQmlPropertyPrivate::binding(property)); + if (binding) { + m_resetBindingHash.insert(propertyName, binding); + } else if (property.isWritable()) { + m_resetValueHash.insert(propertyName, property.read()); + } + } + + m_resetValueHash.insert("Layout.rowSpan", 1); + m_resetValueHash.insert("Layout.columnSpan", 1); + m_resetValueHash.insert("Layout.fillHeight", false); + m_resetValueHash.insert("Layout.fillWidth", false); +} + +QQmlContext *DesignerCustomObjectData::context() const +{ + return m_context; +} + +QObject *DesignerCustomObjectData::object() const +{ + return m_object; +} + +QVariant DesignerCustomObjectData::getResetValue(const PropertyName &propertyName) const +{ + return m_resetValueHash.value(propertyName); +} + +void DesignerCustomObjectData::doResetProperty(const PropertyName &propertyName) +{ + QQmlProperty property(object(), propertyName, context()); + + if (!property.isValid()) + return; + + QVariant oldValue = property.read(); + if (oldValue.type() == QVariant::Url) { + QUrl url = oldValue.toUrl(); + QString path = url.toLocalFile(); + /* ### TODO + if (QFileInfo(path).exists() && nodeInstanceServer()) + nodeInstanceServer()->removeFilePropertyFromFileSystemWatcher(object(), propertyName, path); + */ + } + + + QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(property); + if (binding && !(hasValidResetBinding(propertyName) && getResetBinding(propertyName) == binding)) { + binding->setEnabled(false, 0); + binding->destroy(); + } + + + if (hasValidResetBinding(propertyName)) { + QQmlAbstractBinding *binding = getResetBinding(propertyName); + QQmlPropertyPrivate::setBinding(property, binding, QQmlPropertyPrivate::DontRemoveBinding); + binding->update(); + } else if (property.isResettable()) { + property.reset(); + } else if (property.propertyTypeCategory() == QQmlProperty::List) { + QQmlListReference list = qvariant_cast(property.read()); + + if (!QmlPrivateGate::hasFullImplementedListInterface(list)) { + qWarning() << "Property list interface not fully implemented for Class " << property.property().typeName() << " in property " << property.name() << "!"; + return; + } + + list.clear(); + } else if (property.isWritable()) { + if (property.read() == getResetValue(propertyName)) + return; + + property.write(getResetValue(propertyName)); + } +} + +bool DesignerCustomObjectData::hasValidResetBinding(const PropertyName &propertyName) const +{ + return m_resetBindingHash.contains(propertyName) && m_resetBindingHash.value(propertyName).data(); +} + +QQmlAbstractBinding *DesignerCustomObjectData::getResetBinding(const PropertyName &propertyName) const +{ + return m_resetBindingHash.value(propertyName).data(); +} + +bool DesignerCustomObjectData::hasBindingForProperty(const PropertyName &propertyName, bool *hasChanged) const +{ + if (QmlPrivateGate::isPropertyBlackListed(propertyName)) + return false; + + QQmlProperty property(object(), propertyName, context()); + + bool hasBinding = QQmlPropertyPrivate::binding(property); + + if (hasChanged) { + *hasChanged = hasBinding != m_hasBindingHash.value(propertyName, false); + if (*hasChanged) + m_hasBindingHash.insert(propertyName, hasBinding); + } + + return QQmlPropertyPrivate::binding(property); +} + + +} // namespace QmlPrivateGate +} // namespace Internal +} // namespace QmlDesigner + diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/designercustomobjectdata.h b/share/qtcreator/qml/qmlpuppet/qmlprivategate/designercustomobjectdata.h new file mode 100644 index 00000000000..add0a896918 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/designercustomobjectdata.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef DESIGNERCUSTOMOBJECTDATA_H +#define DESIGNERCUSTOMOBJECTDATA_H + +#include "nodeinstanceglobal.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QQmlAbstractBinding; +class QQmlContext; +QT_END_NAMESPACE + +namespace QmlDesigner { + +namespace Internal { + +namespace QmlPrivateGate { + +class DesignerCustomObjectData +{ +public: + static void registerData(QObject *object, QQmlContext *context); + static DesignerCustomObjectData *get(QObject *object); + static QVariant getResetValue(QObject *object, const PropertyName &propertyName); + static void doResetProperty(QObject *object, const PropertyName &propertyName); + static bool hasValidResetBinding(QObject *object, const PropertyName &propertyName); + static bool hasBindingForProperty(QObject *object, const PropertyName &propertyName, bool *hasChanged); + +private: + DesignerCustomObjectData(QObject *object, QQmlContext *context); + void populateResetHashes(); + QObject *object() const; + QQmlContext *context() const; + QVariant getResetValue(const PropertyName &propertyName) const; + void doResetProperty(const PropertyName &propertyName); + bool hasValidResetBinding(const PropertyName &propertyName) const; + QQmlAbstractBinding *getResetBinding(const PropertyName &propertyName) const; + bool hasBindingForProperty(const PropertyName &propertyName, bool *hasChanged) const; + + QObject *m_object; + QQmlContext *m_context; + QHash m_resetValueHash; + QHash > m_resetBindingHash; + mutable QHash m_hasBindingHash; + +}; + +} // namespace QmlPrivateGate +} // namespace Internal +} // namespace QmlDesigner + +#endif // DESIGNERCUSTOMOBJECTDATA_H diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp index e7f922b26f4..931f83787ed 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp +++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.cpp @@ -31,6 +31,7 @@ #include "qmlprivategate.h" #include "metaobject.h" +#include "designercustomobjectdata.h" #include @@ -446,6 +447,31 @@ bool hasFullImplementedListInterface(const QQmlListReference &list) return list.isValid() && list.canCount() && list.canAt() && list.canAppend() && list.canClear(); } +void registerCustomData(QObject *object, QQmlContext *context) +{ + DesignerCustomObjectData::registerData(object, context); +} + +QVariant getResetValue(QObject *object, const PropertyName &propertyName) +{ + return DesignerCustomObjectData::getResetValue(object, propertyName); +} + +void doResetProperty(QObject *object, const PropertyName &propertyName) +{ + DesignerCustomObjectData::doResetProperty(object, propertyName); +} + +bool hasValidResetBinding(QObject *object, const PropertyName &propertyName) +{ + return DesignerCustomObjectData::hasValidResetBinding(object, propertyName); +} + +bool hasBindingForProperty(QObject *object, const PropertyName &propertyName, bool *hasChanged) +{ + return DesignerCustomObjectData::hasBindingForProperty(object, propertyName, hasChanged); +} + ComponentCompleteDisabler::ComponentCompleteDisabler() { DesignerSupport::disableComponentComplete(); diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.h b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.h index 31d79ef3767..d2172ee595c 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.h +++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.h @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -78,6 +79,12 @@ public: QObjectList *inspectedObjects = 0); bool hasFullImplementedListInterface(const QQmlListReference &list); + void registerCustomData(QObject *object, QQmlContext *context); + QVariant getResetValue(QObject *object, const PropertyName &propertyName); + void doResetProperty(QObject *object, const PropertyName &propertyName); + bool hasValidResetBinding(QObject *object, const PropertyName &propertyName); + bool hasBindingForProperty(QObject *object, const PropertyName &propertyName, bool *hasChanged); + } // namespace QmlPrivateGate } // namespace Internal } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.pri b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.pri index 8ce1220b2dd..89b61e260d5 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.pri +++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate.pri @@ -2,9 +2,11 @@ INCLUDEPATH += $$PWD/ HEADERS += \ $$PWD/qmlprivategate.h \ - $$PWD/metaobject.h + $$PWD/metaobject.h \ + $$PWD/designercustomobjectdata.h SOURCES += \ $$PWD/qmlprivategate.cpp \ - $$PWD/metaobject.cpp + $$PWD/metaobject.cpp \ + $$PWD/designercustomobjectdata.cpp