From 924d9a9f669013048c008cd6c5ceb8227c772e3b Mon Sep 17 00:00:00 2001
From: Mirko Waechter <mirko.waechter@kit.edu>
Date: Sun, 14 Aug 2016 15:24:00 +0200
Subject: [PATCH] fix #11

---
 .../StatechartViewerPlugin/model/State.cpp    | 33 +++++++++++
 .../StatechartViewerPlugin/model/State.h      |  1 +
 .../StatechartViewerPlugin/view/StateItem.cpp | 59 +++++++++++++++++--
 .../StatechartViewerPlugin/view/StateItem.h   |  2 +
 4 files changed, 90 insertions(+), 5 deletions(-)

diff --git a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/model/State.cpp b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/model/State.cpp
index 49a2c1a9..35393ba8 100644
--- a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/model/State.cpp
+++ b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/model/State.cpp
@@ -1108,6 +1108,39 @@ TransitionPtr statechartmodel::State::findTransition(const QString& eventName, c
     return TransitionPtr();
 }
 
+bool State::hasDescendant(StatePtr sC) const
+{
+    if (!sC)
+    {
+        return false;
+    }
+
+    for (auto it = substates.begin(); it != substates.end(); it++)
+    {
+        statechartmodel::StateInstancePtr state = (it.value());
+        if (!state)
+        {
+            continue;
+        }
+        if (!state->getStateClass())
+        {
+            continue;
+        }
+
+        if (state->getStateClass()->getUUID() == sC->getUUID())
+        {
+            return true;
+        }
+
+        if (state->getStateClass()->hasDescendant(sC))
+        {
+            return true;
+        }
+    }
+    return false;
+
+}
+
 QString statechartmodel::State::StateTypeToString(eStateType type)
 {
     switch (type)
diff --git a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/model/State.h b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/model/State.h
index eb43413d..0f9316b6 100644
--- a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/model/State.h
+++ b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/model/State.h
@@ -134,6 +134,7 @@ namespace armarx
             TransitionCPtr getStartTransition() const;
             TransitionPtr findTransition(TransitionCPtr t) const;
             TransitionPtr findTransition(const QString& eventName, const QString& transitionSourceName, const QString& transitionDestinationName) const;
+            bool hasDescendant(statechartmodel::StatePtr state) const;
 
             static QString StateTypeToString(eStateType type);
             void connectToSubclasses();
diff --git a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/view/StateItem.cpp b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/view/StateItem.cpp
index ed8c6980..a88cff19 100644
--- a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/view/StateItem.cpp
+++ b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/view/StateItem.cpp
@@ -735,7 +735,6 @@ namespace armarx
         else
         {
             event->setDropAction(Qt::IgnoreAction);
-
         }
 
         event->accept();
@@ -757,7 +756,7 @@ namespace armarx
         }
 
         const AbstractStateMimeData* data =  qobject_cast<const AbstractStateMimeData*>(event->mimeData());
-
+        bool accept = true;
         if (data && state && state->getStateClass() && data->getState()
             && (state->getType() == eNormalState || state->getType() == eRemoteState))
         {
@@ -771,9 +770,15 @@ namespace armarx
                 i++;
             }
 
-            if (data->getState()->getType() == eDynamicRemoteState && !data->isInSameGroup(state->getStateClass()))
+            if (hasAncestor(data->getState()) || data->getState()->hasDescendant(state->getStateClass()))
+            {
+                QMessageBox::warning(event->source(), "State drag'n'drop error", "State cycle detected - you must not insert a state which is also a parent state of the current state");
+                accept = false;
+            }
+            else if (data->getState()->getType() == eDynamicRemoteState && !data->isInSameGroup(state->getStateClass()))
             {
                 QMessageBox::warning(event->source(), "State drag'n'drop error", "Dynamic Remote States can only be added in the same group.");
+                accept = false;
             }
             else if (data->isInSameGroup(state->getStateClass()))
             {
@@ -793,20 +798,64 @@ namespace armarx
             else
             {
                 QMessageBox::warning(event->source(), "State drag'n'drop error", "Only public states can be added as a Remote State.");
+                accept = false;
             }
 
+
+        }
+        else
+        {
+            accept = false;
+        }
+
+
+        if (accept)
+        {
             event->setDropAction(Qt::LinkAction);
-            event->acceptProposedAction();
+            event->accept();
         }
         else
         {
             event->setDropAction(Qt::IgnoreAction);
-            event->acceptProposedAction();
+            event->accept();
         }
     }
 
+    bool StateItem::hasAncestor(statechartmodel::StatePtr sC) const
+    {
+        if (!sC)
+        {
+            return false;
+        }
 
+        StateItem* state = qgraphicsitem_cast<StateItem*>(parentItem());
+        if (!state)
+        {
+            return false;
+        }
+        if (!state->getStateInstance() || !state->getStateInstance()->getStateClass())
+        {
+            return false;
+        }
 
+        if (state->getStateInstance()->getStateClass()->getUUID() == sC->getUUID())
+        {
+            return true;
+        }
+
+        return state->hasAncestor(sC);
+    }
+
+    bool StateItem::hasDescendant(statechartmodel::StatePtr sC) const
+    {
+        if (!sC || !state->getStateClass())
+        {
+            return false;
+        }
+        return state->getStateClass()->hasDescendant(sC);
+
+
+    }
 }
 
 
diff --git a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/view/StateItem.h b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/view/StateItem.h
index d63ea34d..2c2b2625 100644
--- a/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/view/StateItem.h
+++ b/source/ArmarXGui/gui-plugins/StatechartViewerPlugin/view/StateItem.h
@@ -75,6 +75,8 @@ namespace armarx
 
         QString getInstanceName() const;
 
+        bool hasAncestor(statechartmodel::StatePtr state) const;
+        bool hasDescendant(statechartmodel::StatePtr state) const;
     signals:
         void stateItemResized(QSizeF newSize);
         void stateItemMoved(QPointF newPosition);
-- 
GitLab