From 01eece3d8474ebaa898812876cbb8fad4a7ae3da Mon Sep 17 00:00:00 2001
From: Marco Bubke <marco.bubke@nokia.com>
Date: Wed, 13 Jul 2011 17:53:14 +0200
Subject: [PATCH] QmlDesigner: Fix state switching

Task-number: QTCREATORBUG-4062

Change-Id: I2a04c5a04ef40390772fe46f587bc60c02a4bab1
Reviewed-on: http://codereview.qt.nokia.com/1605
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Thomas Hartmann <Thomas.Hartmann@nokia.com>
---
 .../instances/qt4rendernodeinstanceserver.cpp |  8 +++++
 .../instances/qt4rendernodeinstanceserver.h   |  1 +
 .../designercore/include/abstractview.h       |  4 ++-
 .../designercore/include/nodeinstanceview.h   |  5 +--
 .../designercore/include/qmlstate.h           |  2 --
 .../instances/nodeinstanceview.cpp            | 33 +++++++++++++-----
 .../designercore/model/abstractview.cpp       |  8 ++++-
 .../qmldesigner/designercore/model/model.cpp  |  7 ++++
 .../qmldesigner/designercore/model/model_p.h  |  4 +++
 .../designercore/model/qmlmodelview.cpp       | 34 ++-----------------
 .../designercore/model/qmlstate.cpp           | 10 +++---
 11 files changed, 64 insertions(+), 52 deletions(-)

diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet/instances/qt4rendernodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qmlpuppet/instances/qt4rendernodeinstanceserver.cpp
index 12a7a5d1d62..b6661ef331d 100644
--- a/share/qtcreator/qml/qmlpuppet/qmlpuppet/instances/qt4rendernodeinstanceserver.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet/instances/qt4rendernodeinstanceserver.cpp
@@ -187,5 +187,13 @@ void Qt4RenderNodeInstanceServer::completeComponent(const CompleteComponentComma
 
     nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(instanceList));
 }
+void Qt4RenderNodeInstanceServer::changeState(const ChangeStateCommand &command)
+{
+    Qt4NodeInstanceServer::changeState(command);
 
+    foreach (QGraphicsItem *item, declarativeView()->items()) {
+        item->update();
+        QGraphicsItemPrivate::get(item)->notifyBoundingRectChanged = 1;
+    }
+}
 } // namespace QmlDesigner
diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet/instances/qt4rendernodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qmlpuppet/instances/qt4rendernodeinstanceserver.h
index dde4056a65e..98a6d83a1d4 100644
--- a/share/qtcreator/qml/qmlpuppet/qmlpuppet/instances/qt4rendernodeinstanceserver.h
+++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet/instances/qt4rendernodeinstanceserver.h
@@ -46,6 +46,7 @@ public:
     void createScene(const CreateSceneCommand &command);
     void clearScene(const ClearSceneCommand &command);
     void completeComponent(const CompleteComponentCommand &command);
+    void changeState(const ChangeStateCommand &command);
 
 protected:
     void collectItemChangesAndSendChangeCommands();
diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h
index 45b2a064d67..27c2b06af31 100644
--- a/src/plugins/qmldesigner/designercore/include/abstractview.h
+++ b/src/plugins/qmldesigner/designercore/include/abstractview.h
@@ -122,7 +122,6 @@ public:
     void emitRewriterBeginTransaction();
     void emitRewriterEndTransaction();
     void emitInstanceToken(const QString &token, int number, const QVector<ModelNode> &nodeVector);
-    void emitActualStateChanged(const ModelNode &node);
 
     void sendTokenToInstances(const QString &token, int number, const QVector<ModelNode> &nodeVector);
 
@@ -178,6 +177,9 @@ public:
     NodeInstanceView *nodeInstanceView() const;
     RewriterView *rewriterView() const;
 
+    void setAcutalStateNode(const ModelNode &node);
+    ModelNode actualStateNode() const;
+
     void resetView();
 
 protected:
diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
index 053da698e22..e4b1ba6e8b0 100644
--- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
+++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
@@ -130,8 +130,6 @@ public:
 
     NodeInstance activeStateInstance() const;
 
-    void activateState(const NodeInstance &instance);
-    void activateBaseState();
 
     void valuesChanged(const ValuesChangedCommand &command);
     void pixmapChanged(const PixmapChangedCommand &command);
@@ -151,6 +149,9 @@ signals:
     void qmlPuppetCrashed();
 
 private: // functions
+    void activateState(const NodeInstance &instance);
+    void activateBaseState();
+
     NodeInstance rootNodeInstance() const;
 
     NodeInstance loadNode(const ModelNode &node);
diff --git a/src/plugins/qmldesigner/designercore/include/qmlstate.h b/src/plugins/qmldesigner/designercore/include/qmlstate.h
index 897fa61ebf7..ea8226ec9ed 100644
--- a/src/plugins/qmldesigner/designercore/include/qmlstate.h
+++ b/src/plugins/qmldesigner/designercore/include/qmlstate.h
@@ -77,8 +77,6 @@ protected:
     void addChangeSetIfNotExists(const ModelNode &node);
     static QmlModelState createBaseState(const QmlModelView *view);
 
-private:
-    bool m_isBaseState;
 };
 
 } //QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
index b21add18e2b..241663e7088 100644
--- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
@@ -172,6 +172,13 @@ void NodeInstanceView::modelAttached(Model *model)
 
     if (!isSkippedRootNode(rootModelNode()))
         nodeInstanceServer()->createScene(createCreateSceneCommand());
+
+    ModelNode stateNode = actualStateNode();
+    if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0)) {
+        NodeInstance newStateInstance = instanceForNode(stateNode);
+        activateState(newStateInstance);
+    }
+
 }
 
 void NodeInstanceView::modelAboutToBeDetached(Model * model)
@@ -210,6 +217,12 @@ void NodeInstanceView::restartProcess()
 
         if (!isSkippedRootNode(rootModelNode()))
             nodeInstanceServer()->createScene(createCreateSceneCommand());
+
+        ModelNode stateNode = actualStateNode();
+        if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0)) {
+            NodeInstance newStateInstance = instanceForNode(stateNode);
+            activateState(newStateInstance);
+        }
     }
 }
 
@@ -539,8 +552,15 @@ void NodeInstanceView::rewriterEndTransaction()
 
 }
 
-void NodeInstanceView::actualStateChanged(const ModelNode &/*node*/)
+void NodeInstanceView::actualStateChanged(const ModelNode &node)
 {
+    NodeInstance newStateInstance = instanceForNode(node);
+
+    if (newStateInstance.isValid() && node.metaInfo().isSubclassOf("QtQuick.State", 1, 0)) {
+        nodeInstanceView()->activateState(newStateInstance);
+    } else {
+        nodeInstanceView()->activateBaseState();
+    }
 }
 
 
@@ -693,16 +713,11 @@ NodeInstance NodeInstanceView::loadNode(const ModelNode &node)
 void NodeInstanceView::activateState(const NodeInstance &instance)
 {
     nodeInstanceServer()->changeState(ChangeStateCommand(instance.instanceId()));
-//    activateBaseState();
-//    NodeInstance stateInstance(instance);
-//    stateInstance.activateState();
 }
 
 void NodeInstanceView::activateBaseState()
 {
     nodeInstanceServer()->changeState(ChangeStateCommand(-1));
-//    if (activeStateInstance().isValid())
-//        activeStateInstance().deactivateState();
 }
 
 void NodeInstanceView::removeRecursiveChildRelationship(const ModelNode &removedNode)
@@ -1103,8 +1118,10 @@ QImage NodeInstanceView::statePreviewImage(const ModelNode &stateNode) const
 
 void NodeInstanceView::setPathToQt(const QString &pathToQt)
 {
-    m_pathToQt = pathToQt;
-    restartProcess();
+    if (m_pathToQt != pathToQt) {
+        m_pathToQt = pathToQt;
+        restartProcess();
+    }
 }
 
 void NodeInstanceView::statePreviewImagesChanged(const StatePreviewImageChangedCommand &command)
diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
index b8f589b6694..1c3cd7be182 100644
--- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
@@ -447,8 +447,9 @@ void AbstractView::emitRewriterEndTransaction()
         model()->m_d->notifyRewriterEndTransaction();
 }
 
-void AbstractView::emitActualStateChanged(const ModelNode &node)
+void AbstractView::setAcutalStateNode(const ModelNode &node)
 {
+    Internal::WriteLocker locker(m_model.data());
     if (model())
         model()->m_d->notifyActualStateChanged(node);
 }
@@ -460,4 +461,9 @@ void AbstractView::changeRootNodeType(const QString &type, int majorVersion, int
     m_model.data()->m_d->changeRootNodeType(type, majorVersion, minorVersion);
 }
 
+ModelNode AbstractView::actualStateNode() const
+{
+    return ModelNode(m_model.data()->m_d->actualStateNode(), m_model.data(), const_cast<AbstractView*>(this));
+}
+
 } // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp
index 938026c3f9f..72e8585f7d4 100644
--- a/src/plugins/qmldesigner/designercore/model/model.cpp
+++ b/src/plugins/qmldesigner/designercore/model/model.cpp
@@ -605,6 +605,8 @@ void ModelPrivate::notifyActualStateChanged(const ModelNode &node)
     bool resetModel = false;
     QString description;
 
+    m_acutalStateNode = node.internalNode();
+
     try {
         if (rewriterView())
             rewriterView()->actualStateChanged(ModelNode(node.internalNode(), model(), rewriterView()));
@@ -1638,6 +1640,11 @@ bool ModelPrivate::isWriteLocked() const
     return m_writeLock;
 }
 
+InternalNode::Pointer ModelPrivate::actualStateNode() const
+{
+    return m_acutalStateNode;
+}
+
 
 WriteLocker::WriteLocker(ModelPrivate *model)
     : m_model(model)
diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h
index bc6ff14564e..c0f49cc427f 100644
--- a/src/plugins/qmldesigner/designercore/model/model_p.h
+++ b/src/plugins/qmldesigner/designercore/model/model_p.h
@@ -218,6 +218,8 @@ public:
     void setNodeInstanceView(NodeInstanceView *nodeInstanceView);
     NodeInstanceView *nodeInstanceView() const;
 
+    InternalNodePointer actualStateNode() const;
+
 private: //functions
     void removePropertyWithoutNotification(const InternalPropertyPointer &property);
     void removeAllSubNodes(const InternalNodePointer &node);
@@ -237,6 +239,8 @@ private:
     QHash<QString,InternalNodePointer> m_idNodeHash;
     QHash<qint32, InternalNodePointer> m_internalIdNodeHash;
     QSet<InternalNodePointer> m_nodeSet;
+    InternalNodePointer m_acutalStateNode;
+
 
     InternalNodePointer m_rootInternalNode;
 
diff --git a/src/plugins/qmldesigner/designercore/model/qmlmodelview.cpp b/src/plugins/qmldesigner/designercore/model/qmlmodelview.cpp
index a6d3a934d3b..97f1047615f 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlmodelview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlmodelview.cpp
@@ -63,12 +63,12 @@ void QmlModelView::setCurrentState(const QmlModelState &state)
     if (!state.isValid())
         return;
 
-    emitActualStateChanged(state.modelNode());
+    setAcutalStateNode(state.modelNode());
 }
 
 QmlModelState QmlModelView::currentState() const
 {
-    return m_state;
+    return QmlModelState(actualStateNode());
 }
 
 QmlModelState QmlModelView::baseState() const
@@ -334,14 +334,10 @@ bool QmlModelView::hasInstanceForModelNode(const ModelNode &modelNode)
 void QmlModelView::modelAttached(Model *model)
 {
     AbstractView::modelAttached(model);
-    m_state = QmlModelState();
-    m_state = baseState();
-    Q_ASSERT(m_state.isBaseState());
 }
 
 void QmlModelView::modelAboutToBeDetached(Model *model)
 {
-    m_state = QmlModelState();
     AbstractView::modelAboutToBeDetached(model);
 }
 
@@ -452,10 +448,6 @@ void QmlModelView::actualStateChanged(const ModelNode &node)
     if (!newState.isValid())
         newState = baseState();
 
-    activateState(newState);
-
-    m_state = newState;
-
     if (newState != oldState)
         stateChanged(newState, oldState);
 
@@ -476,28 +468,6 @@ void QmlModelView::nodeInstancePropertyChanged(const ModelNode &node, const QStr
         otherPropertyChanged(qmlObjectNode, propertyName);
 }
 
-void QmlModelView::activateState(const QmlModelState &state)
-{
-    if (!state.isValid())
-        return;
-
-    if (m_state == state)
-        return;    
-
-    m_state = state; //This is hacky. m_state should be controlled by the instances
-                     //### todo: If the state thumbnail code gets refactored.
-                     //          this is not necessary anymore.
-
-
-    NodeInstance newStateInstance = instanceForModelNode(state.modelNode());
-
-    if (state.isBaseState()) {
-        nodeInstanceView()->activateBaseState();
-    } else {
-        nodeInstanceView()->activateState(newStateInstance);
-    }
-}
-
 void QmlModelView::transformChanged(const QmlObjectNode &/*qmlObjectNode*/, const QString &/*propertyName*/)
 {
 }
diff --git a/src/plugins/qmldesigner/designercore/model/qmlstate.cpp b/src/plugins/qmldesigner/designercore/model/qmlstate.cpp
index 51d79cdd026..94e0ca22e85 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlstate.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlstate.cpp
@@ -42,14 +42,12 @@
 namespace QmlDesigner {
 
 QmlModelState::QmlModelState()
-   : QmlModelNodeFacade(),
-     m_isBaseState(false)
+   : QmlModelNodeFacade()
 {
 }
 
 QmlModelState::QmlModelState(const ModelNode &modelNode)
-        : QmlModelNodeFacade(modelNode),
-        m_isBaseState(false)
+        : QmlModelNodeFacade(modelNode)
 {
 }
 
@@ -268,7 +266,7 @@ void QmlModelState::destroy()
 
 bool QmlModelState::isBaseState() const
 {
-    return m_isBaseState && modelNode().isRootNode();
+    return !modelNode().isValid() || modelNode().isRootNode();
 }
 
 QmlModelState QmlModelState::duplicate(const QString &name) const
@@ -308,7 +306,7 @@ QmlModelStateGroup QmlModelState::stateGroup() const
 QmlModelState QmlModelState::createBaseState(const QmlModelView *view)
 {
     QmlModelState fxState(view->rootModelNode());
-    fxState.m_isBaseState = true;
+
     return fxState;
 }
 
-- 
GitLab