Commit 5d3e4bac authored by Marco Bubke's avatar Marco Bubke Committed by Kai Koehne

Improve performance of State property changes

This patch is eliminating the switch from the state the base state and back if a property is changed.
 For that it is updating the internal caching values in QDeclarativeState.

Reviewed-by: Thomas Hartmann
parent d89d2db0
......@@ -43,9 +43,9 @@ FormEditorGraphicsView::FormEditorGraphicsView(QWidget *parent) :
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
setResizeAnchor(QGraphicsView::AnchorViewCenter);
// setCacheMode(QGraphicsView::CacheNone);
setCacheMode(QGraphicsView::CacheBackground);
setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
// setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
// setCacheMode(QGraphicsView::CacheBackground);
// setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
setRenderHint(QPainter::Antialiasing, false);
setFrameShape(QFrame::NoFrame);
......
......@@ -329,8 +329,10 @@ void FormEditorScene::reparentItem(const QmlItemNode &node, const QmlItemNode &n
Q_ASSERT(hasItemForQmlItemNode(newParent));
FormEditorItem *item = itemForQmlItemNode(node);
FormEditorItem *parentItem = itemForQmlItemNode(newParent);
item->setParentItem(parentItem);
item->setParent(parentItem);
if (item->parentItem() != parentItem) {
item->setParentItem(parentItem);
item->update();
}
}
FormEditorItem* FormEditorScene::rootFormEditorItem() const
......
......@@ -58,6 +58,8 @@ class WidgetQueryView;
namespace Internal {
class ObjectNodeInstance;
class QmlGraphicsItemNodeInstance;
class QmlPropertyChangesNodeInstance;
class QmlStateNodeInstance;
}
class CORESHARED_EXPORT NodeInstance
......@@ -71,6 +73,9 @@ class CORESHARED_EXPORT NodeInstance
friend CORESHARED_EXPORT class NodeMetaInfo;
friend class QmlDesigner::Internal::QmlGraphicsItemNodeInstance;
friend class QmlDesigner::Internal::ObjectNodeInstance;
friend class QmlDesigner::Internal::QmlPropertyChangesNodeInstance;
friend class QmlDesigner::Internal::QmlStateNodeInstance;
public:
NodeInstance();
~NodeInstance();
......@@ -82,7 +87,7 @@ public:
NodeInstance parent() const;
bool hasParent() const;
ModelNode modelNode() const;
void setModelNode(const ModelNode &node);
bool isTopLevel() const;
......@@ -119,13 +124,9 @@ public:
void makeInvalid();
bool hasContent() const;
const QObject *testHandle() const;
bool isWrappingThisObject(QObject *object) const;
void setPropertyVariant(const QString &name, const QVariant &value);
void setPropertyDynamicVariant(const QString &name, const QString &typeName, const QVariant &value);
void setPropertyBinding(const QString &name, const QString &expression);
void setPropertyDynamicBinding(const QString &name, const QString &typeName, const QString &expression);
QVariant resetVariant(const QString &name) const;
bool hasAnchor(const QString &name) const;
bool isAnchoredBy() const;
......@@ -133,22 +134,35 @@ public:
int penWidth() const;
void activateState();
void deactivateState();
void refreshState();
static void registerDeclarativeTypes();
private: // functions
NodeInstance(const QSharedPointer<Internal::ObjectNodeInstance> &abstractInstance);
void setModelNode(const ModelNode &node);
void setPropertyVariant(const QString &name, const QVariant &value);
void setPropertyDynamicVariant(const QString &name, const QString &typeName, const QVariant &value);
void setPropertyBinding(const QString &name, const QString &expression);
void setPropertyDynamicBinding(const QString &name, const QString &typeName, const QString &expression);
void resetProperty(const QString &name);
void activateState();
void deactivateState();
void refreshState();
bool updateStateVariant(const NodeInstance &target, const QString &propertyName, const QVariant &value);
bool updateStateBinding(const NodeInstance &target, const QString &propertyName, const QString &expression);
bool resetStateProperty(const NodeInstance &target, const QString &propertyName, const QVariant &resetValue);
static NodeInstance create(NodeInstanceView *nodeInstanceView, const ModelNode &node, QObject *objectToBeWrapped);
static NodeInstance create(NodeInstanceView *nodeInstanceView, const NodeMetaInfo &metaInfo, QDeclarativeContext *context);
void setDeleteHeldInstance(bool deleteInstance);
void reparent(const NodeInstance &oldParentInstance, const QString &oldParentProperty, const NodeInstance &newParentInstance, const QString &newParentProperty);
void resetProperty(const QString &name);
void setId(const QString &id);
......
......@@ -51,6 +51,7 @@ namespace QmlDesigner {
namespace Internal {
class ChildrenChangeEventFilter;
class QmlStateNodeInstance;
}
class CORESHARED_EXPORT NodeInstanceView : public AbstractView
......@@ -59,6 +60,7 @@ class CORESHARED_EXPORT NodeInstanceView : public AbstractView
friend class NodeInstance;
friend class Internal::ObjectNodeInstance;
friend class Internal::QmlStateNodeInstance;
public:
typedef QWeakPointer<NodeInstanceView> Pointer;
......@@ -116,6 +118,11 @@ public:
void setBlockStatePropertyChanges(bool block);
NodeInstance activeStateInstance() const;
void activateState(const NodeInstance &instance);
void activateBaseState();
signals:
void instanceRemoved(const NodeInstance &nodeInstance);
......@@ -138,8 +145,16 @@ private: // functions
Internal::ChildrenChangeEventFilter *childrenChangeEventFilter();
void removeInstanceAndSubInstances(const ModelNode &node);
void setInstancePropertyVariant(const VariantProperty &property);
void setInstancePropertyBinding(const BindingProperty &property);
void resetInstanceProperty(const AbstractProperty &property);
void setStateInstance(const NodeInstance &stateInstance);
void clearStateInstance();
private: //variables
NodeInstance m_rootNodeInstance;
NodeInstance m_activeStateInstance;
QScopedPointer<QGraphicsView> m_graphicsView;
QHash<ModelNode, NodeInstance> m_nodeInstanceHash;
......
......@@ -369,6 +369,7 @@ QRectF NodeInstance::boundingRect() const
void NodeInstance::setPropertyVariant(const QString &name, const QVariant &value)
{
m_nodeInstance->setPropertyVariant(name, value);
}
void NodeInstance::setPropertyDynamicVariant(const QString &name, const QString &typeName, const QVariant &value)
......@@ -485,9 +486,9 @@ bool operator==(const NodeInstance &first, const NodeInstance &second)
return first.m_nodeInstance.data() == second.m_nodeInstance.data();
}
const QObject *NodeInstance::testHandle() const
bool NodeInstance::isWrappingThisObject(QObject *object) const
{
return internalObject();
return internalObject() && internalObject() == object;
}
/*!
......@@ -606,9 +607,24 @@ void NodeInstance::deactivateState()
m_nodeInstance->deactivateState();
}
void NodeInstance::refreshState()
bool NodeInstance::updateStateVariant(const NodeInstance &target, const QString &propertyName, const QVariant &value)
{
return m_nodeInstance->updateStateVariant(target, propertyName, value);
}
bool NodeInstance::updateStateBinding(const NodeInstance &target, const QString &propertyName, const QString &expression)
{
return m_nodeInstance->updateStateBinding(target, propertyName, expression);
}
QVariant NodeInstance::resetVariant(const QString &propertyName) const
{
return m_nodeInstance->resetValue(propertyName);
}
bool NodeInstance::resetStateProperty(const NodeInstance &target, const QString &propertyName, const QVariant &resetValue)
{
m_nodeInstance->refreshState();
return m_nodeInstance->resetStateProperty(target, propertyName, resetValue);
}
/*!
......
......@@ -13,6 +13,7 @@ namespace Internal {
NodeInstanceSignalSpy::NodeInstanceSignalSpy() :
QObject()
{
blockSignals(true);
}
void NodeInstanceSignalSpy::setObjectNodeInstance(const ObjectNodeInstance::Pointer &nodeInstance)
......
......@@ -83,8 +83,8 @@ namespace QmlDesigner {
The class will be rendered offscreen if not set otherwise.
\param Parent of this object. If this parent is deleted this instance is
deleted too.
\param Parent of this object. If this parent is d this instance is
d too.
\see ~NodeInstanceView setRenderOffScreen
*/
......@@ -173,10 +173,7 @@ void NodeInstanceView::nodeRemoved(const ModelNode &/*removedNode*/, const NodeA
void NodeInstanceView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList)
{
foreach (const AbstractProperty &property, propertyList) {
if (hasInstanceForNode(property.parentModelNode())) { // TODO ugly workaround
NodeInstance instance = instanceForNode(property.parentModelNode());
instance.resetProperty(property.name());
}
resetInstanceProperty(property);
if (property.isNodeAbstractProperty()) {
foreach (const ModelNode &subNode, property.toNodeAbstractProperty().allSubNodes())
......@@ -189,6 +186,93 @@ void NodeInstanceView::propertiesRemoved(const QList<AbstractProperty>& /*proper
{
}
void NodeInstanceView::resetInstanceProperty(const AbstractProperty &property)
{
if (hasInstanceForNode(property.parentModelNode())) { // TODO ugly workaround
NodeInstance instance = instanceForNode(property.parentModelNode());
Q_ASSERT(instance.isValid());
const QString name = property.name();
if (activeStateInstance().isValid()) {
bool statePropertyWasReseted = activeStateInstance().resetStateProperty(instance, name, instance.resetVariant(name));
if (!statePropertyWasReseted)
instance.resetProperty(name);
} else {
instance.resetProperty(name);
}
}
}
void NodeInstanceView::setInstancePropertyBinding(const BindingProperty &property)
{
NodeInstance instance = instanceForNode(property.parentModelNode());
const QString name = property.name();
const QString expression = property.expression();
if (activeStateInstance().isValid()) {
bool stateBindingWasUpdated = activeStateInstance().updateStateBinding(instance, name, expression);
if (!stateBindingWasUpdated) {
if (property.isDynamic())
instance.setPropertyDynamicBinding(name, property.dynamicTypeName(), expression);
else
instance.setPropertyBinding(name, expression);
}
} else {
if (property.isDynamic())
instance.setPropertyDynamicBinding(name, property.dynamicTypeName(), expression);
else
instance.setPropertyBinding(name, expression);
}
if (property.parentModelNode().isRootNode()
&& (name == "width" || name == "height")) {
QGraphicsObject *rootGraphicsObject = qobject_cast<QGraphicsObject*>(instance.internalObject());
if (rootGraphicsObject) {
m_graphicsView->setSceneRect(rootGraphicsObject->boundingRect());
}
}
instance.paintUpdate();
}
void NodeInstanceView::setInstancePropertyVariant(const VariantProperty &property)
{
NodeInstance instance = instanceForNode(property.parentModelNode());
const QString name = property.name();
const QVariant value = property.value();
if (activeStateInstance().isValid()) {
bool stateValueWasUpdated = activeStateInstance().updateStateVariant(instance, name, value);
if (!stateValueWasUpdated) {
if (property.isDynamic())
instance.setPropertyDynamicVariant(name, property.dynamicTypeName(), value);
else
instance.setPropertyVariant(name, value);
}
} else { //base state
if (property.isDynamic())
instance.setPropertyDynamicVariant(name, property.dynamicTypeName(), value);
else
instance.setPropertyVariant(name, value);
}
if (property.parentModelNode().isRootNode()
&& (name == "width" || name == "height")) {
QGraphicsObject *rootGraphicsObject = qobject_cast<QGraphicsObject*>(instance.internalObject());
if (rootGraphicsObject) {
m_graphicsView->setSceneRect(rootGraphicsObject->boundingRect());
}
}
instance.paintUpdate();
}
void NodeInstanceView::removeInstanceAndSubInstances(const ModelNode &node)
{
foreach(const ModelNode &subNode, node.allSubModelNodes()) {
......@@ -213,22 +297,8 @@ void NodeInstanceView::rootNodeTypeChanged(const QString &/*type*/, int /*majorV
void NodeInstanceView::bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags /*propertyChange*/)
{
foreach (const BindingProperty &property, propertyList) {
NodeInstance instance = instanceForNode(property.parentModelNode());
if (property.isDynamic())
instance.setPropertyDynamicBinding(property.name(), property.dynamicTypeName(), property.expression());
else
instance.setPropertyBinding(property.name(), property.expression());
if (property.parentModelNode().isRootNode()
&& (property.name() == "width" || property.name() == "height")) {
QGraphicsObject *rootGraphicsObject = qobject_cast<QGraphicsObject*>(instance.internalObject());
m_graphicsView->setSceneRect(rootGraphicsObject->boundingRect());
}
instance.paintUpdate();
}
foreach (const BindingProperty &property, propertyList)
setInstancePropertyBinding(property);
}
/*! \brief Notifing the view that a AbstractProperty value was changed to a ModelNode.
......@@ -244,24 +314,8 @@ void NodeInstanceView::bindingPropertiesChanged(const QList<BindingProperty>& pr
void NodeInstanceView::variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags /*propertyChange*/)
{
foreach (const VariantProperty &property, propertyList) {
NodeInstance instance = instanceForNode(property.parentModelNode());
if (property.isDynamic())
instance.setPropertyDynamicVariant(property.name(), property.dynamicTypeName(), property.value());
else
instance.setPropertyVariant(property.name(), property.value());
if (property.parentModelNode().isRootNode()
&& (property.name() == "width" || property.name() == "height")) {
QGraphicsObject *rootGraphicsObject = qobject_cast<QGraphicsObject*>(instance.internalObject());
if (rootGraphicsObject) {
m_graphicsView->setSceneRect(rootGraphicsObject->boundingRect());
}
}
instance.paintUpdate();
}
foreach (const VariantProperty &property, propertyList)
setInstancePropertyVariant(property);
}
/*! \brief Notifing the view that a ModelNode has a new Parent.
......@@ -361,7 +415,7 @@ void NodeInstanceView::removeAllInstanceNodeRelationships()
{
// prevent destroyed() signals calling back
//first delete the root object
//first the root object
if (rootNodeInstance().internalObject())
rootNodeInstance().internalObject()->disconnect();
......@@ -502,7 +556,7 @@ void NodeInstanceView::removeInstanceNodeRelationship(const ModelNode &node)
void NodeInstanceView::notifyPropertyChange(const ModelNode &node, const QString &propertyName)
{
if (m_blockStatePropertyChanges && propertyName == "state")
if (m_blockStatePropertyChanges)
return;
if (qmlModelView()) {
......@@ -526,6 +580,21 @@ void NodeInstanceView::setBlockStatePropertyChanges(bool block)
m_blockStatePropertyChanges = block;
}
void NodeInstanceView::setStateInstance(const NodeInstance &stateInstance)
{
m_activeStateInstance = stateInstance;
}
void NodeInstanceView::clearStateInstance()
{
m_activeStateInstance = NodeInstance();
}
NodeInstance NodeInstanceView::activeStateInstance() const
{
return m_activeStateInstance;
}
void NodeInstanceView::emitParentChanged(QObject *child)
{
if (hasInstanceForObject(child)) {
......@@ -552,6 +621,18 @@ NodeInstance NodeInstanceView::loadNode(const ModelNode &node, QObject *objectTo
return instance;
}
void NodeInstanceView::activateState(const NodeInstance &instance)
{
NodeInstance stateInstance(instance);
stateInstance.activateState();
}
void NodeInstanceView::activateBaseState()
{
if (activeStateInstance().isValid())
activeStateInstance().deactivateState();
}
void NodeInstanceView::removeRecursiveChildRelationship(const ModelNode &removedNode)
{
foreach (const ModelNode &childNode, removedNode.allDirectSubModelNodes())
......
......@@ -121,11 +121,7 @@ void ObjectNodeInstance::destroy()
ModelNode parentNode = parentProperty.parentModelNode();
if (parentNode.isValid() && nodeInstanceView()->hasInstanceForNode(parentNode)) {
NodeInstance parentInstance = nodeInstanceView()->instanceForNode(parentNode);
if (parentInstance.isQmlGraphicsItem() && isChildrenProperty(parentProperty.name())) {
specialRemoveParentForQmlGraphicsItemChildren(object());
} else {
removeFromOldProperty(object(), parentInstance.internalObject(), parentProperty.name());
}
reparent(parentInstance, parentProperty.name(), NodeInstance() , QString());
}
}
......@@ -330,9 +326,23 @@ static QVariant objectToVariant(QObject *object)
return QVariant::fromValue(object);
}
static void removeObjectFromList(const QDeclarativeProperty & /*metaProperty*/, QObject * /*object*/, QDeclarativeEngine * /*engine*/)
static void removeObjectFromList(const QDeclarativeProperty &metaProperty, QObject *objectToBeRemoved, QDeclarativeEngine * engine)
{
// ### Very few QML lists ever responded to removes
QDeclarativeListReference listReference(metaProperty.object(), metaProperty.name().toLatin1(), engine);
int count = listReference.count();
QObjectList objectList;
for(int i = 0; i < count; i ++) {
QObject *listItem = listReference.at(i);
if (listItem != objectToBeRemoved)
objectList.append(listItem);
}
listReference.clear();
foreach(QObject *object, objectList)
listReference.append(object);
}
void ObjectNodeInstance::removeFromOldProperty(QObject *object, QObject *oldParent, const QString &oldParentProperty)
......@@ -394,7 +404,6 @@ void ObjectNodeInstance::reparent(const NodeInstance &oldParentInstance, const Q
void ObjectNodeInstance::setPropertyVariant(const QString &name, const QVariant &value)
{
QDeclarativeProperty QDeclarativeProperty(object(), name, context());
QDeclarativeProperty.write(value);
}
......@@ -579,10 +588,6 @@ void ObjectNodeInstance::deactivateState()
{
}
void ObjectNodeInstance::refreshState()
{
}
QStringList propertyNameForWritableProperties(QObject *object, const QString &baseName = QString())
{
QStringList propertyNameList;
......@@ -695,6 +700,21 @@ void ObjectNodeInstance::refreshBindings(QDeclarativeContext *context)
context->setContextProperty(QString("__dummy_%1").arg(i++), true);
}
bool ObjectNodeInstance::updateStateVariant(const NodeInstance &/*target*/, const QString &/*propertyName*/, const QVariant &/*value*/)
{
return false;
}
bool ObjectNodeInstance::updateStateBinding(const NodeInstance &/*target*/, const QString &/*propertyName*/, const QString &/*expression*/)
{
return false;
}
bool ObjectNodeInstance::resetStateProperty(const NodeInstance &/*target*/, const QString &/*propertyName*/, const QVariant &/*resetValue*/)
{
return false;
}
}
}
......@@ -102,7 +102,7 @@ public:
virtual QObject *parent() const;
void reparent(const NodeInstance &oldParentInstance, const QString &oldParentProperty, const NodeInstance &newParentInstance, const QString &newParentProperty);
virtual void reparent(const NodeInstance &oldParentInstance, const QString &oldParentProperty, const NodeInstance &newParentInstance, const QString &newParentProperty);
void setId(const QString &id);
......@@ -155,7 +155,6 @@ public:
virtual void activateState();
virtual void deactivateState();
virtual void refreshState();
void populateResetValueHash();
QVariant resetValue(const QString &propertyName) const;
......@@ -166,6 +165,10 @@ public:
QDeclarativeContext *context() const;
virtual bool updateStateVariant(const NodeInstance &target, const QString &propertyName, const QVariant &value);
virtual bool updateStateBinding(const NodeInstance &target, const QString &propertyName, const QString &expression);
virtual bool resetStateProperty(const NodeInstance &target, const QString &propertyName, const QVariant &resetValue);
protected:
static QObject* createObject(const NodeMetaInfo &metaInfo, QDeclarativeContext *context);
......
......@@ -33,6 +33,11 @@
#include "objectnodeinstance.h"
#include <private/qdeclarativestateoperations_p.h>
#include <QPair>
#include <QWeakPointer>
class QDeclarativeProperty;
namespace QmlDesigner {
namespace Internal {
......@@ -44,35 +49,70 @@ class QmlPropertyChangesNodeInstance;
class QmlPropertyChangesObject : public QDeclarativeStateOperation
{
Q_OBJECT
Q_PROPERTY(QObject *target READ object WRITE setObject)
Q_PROPERTY(QObject *target READ targetObject WRITE setTargetObject)
Q_PROPERTY(bool restoreEntryValues READ restoreEntryValues WRITE setRestoreEntryValues)
Q_PROPERTY(bool explicit READ isExplicit WRITE setIsExplicit)
typedef QPair<QString, QWeakPointer<QDeclarativeBinding> > ExpressionPair;
public:
QObject *object() const { return m_targetObject.data(); }
void setObject(QObject *object) {m_targetObject = object; }
~QmlPropertyChangesObject();
QObject *targetObject() const;
void setTargetObject(QObject *object);
bool restoreEntryValues() const { return m_restoreEntryValues; }
void setRestoreEntryValues(bool restore) { m_restoreEntryValues = restore; }
bool restoreEntryValues() const;
void setRestoreEntryValues(bool restore);
bool isExplicit() const { return m_isExplicit; }
void setIsExplicit(bool isExplicit) { m_isExplicit = isExplicit; }
bool isExplicit() const;
void setIsExplicit(bool isExplicit);
virtual ActionList actions();
private:
friend class QmlPropertyChangesNodeInstance;
void setVariantValue(const QString &name, const QVariant & value);
void setExpression(const QString &name, const QString &expression);
void removeVariantValue(const QString &name);
void removeExpression(const QString &name);
void resetProperty(const QString &name);
QVariant variantValue(const QString &name) const;
QString expression(const QString &name) const;
bool hasVariantValue(const QString &name) const;
bool hasExpression(const QString &name) const;
QmlPropertyChangesObject();
QDeclarativeProperty metaProperty(const QString &property);
bool updateStateVariant(const QString &propertyName, const QVariant &value);
bool updateStateBinding(const QString &propertyName, const QString &expression);
bool resetStateProperty(const QString &propertyName, const QVariant &resetValue);
QDeclarativeState *state() const;
void updateRevertValueAndBinding(const QString &name);