From 759effd51141b0577b241a99b276247f19e4517e Mon Sep 17 00:00:00 2001
From: Marco Biasini <marco.biasini@unibas.ch>
Date: Fri, 11 Feb 2011 07:12:16 +0100
Subject: [PATCH] teach the scene win to properly build a hierarchy of scene
 nodes.

This fixes BZDNG-83.
---
 cmake_support/OST.cmake                       |   2 +-
 modules/gfx/pymod/export_gfx_node.cc          |   4 +-
 modules/gfx/src/gfx_node.cc                   |  71 ++++++--
 modules/gfx/src/gfx_node.hh                   |  18 +-
 modules/gfx/tests/CMakeLists.txt              |   1 +
 modules/gfx/tests/test_gfx_node.cc            | 166 ++++++++++++++++++
 .../src/scene_win/current_selection_node.cc   |   2 +-
 modules/gui/src/scene_win/custom_part_node.cc |   2 +-
 modules/gui/src/scene_win/entity_node.cc      |   3 +-
 modules/gui/src/scene_win/entity_part_node.cc |   9 +-
 modules/gui/src/scene_win/gfx_scene_node.cc   |   2 +-
 modules/gui/src/scene_win/label_node.cc       |   2 +-
 modules/gui/src/scene_win/render_mode_node.cc |   2 +-
 .../gui/src/scene_win/render_modes_node.cc    |   2 +-
 modules/gui/src/scene_win/scene_win.cc        |   3 +-
 modules/gui/src/scene_win/scene_win.hh        |   8 +-
 modules/gui/src/scene_win/scene_win_model.cc  | 107 +++++++----
 modules/gui/src/scene_win/scene_win_model.hh  |   3 +-
 .../src/sequence_viewer/sequence_viewer.cc    |  16 +-
 19 files changed, 349 insertions(+), 74 deletions(-)
 create mode 100644 modules/gfx/tests/test_gfx_node.cc

diff --git a/cmake_support/OST.cmake b/cmake_support/OST.cmake
index ed57c7400..10ec36703 100644
--- a/cmake_support/OST.cmake
+++ b/cmake_support/OST.cmake
@@ -531,7 +531,7 @@ macro(ost_unittest MODULE SOURCE_FILES)
         target_link_libraries(${_test_name} ${BOOST_UNIT_TEST_LIBRARIES}
                             "ost_${MODULE}")
         add_custom_target("${_test_name}_run"
-                        COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} || echo 
+                        COMMAND OST_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} || echo 
                         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                         COMMENT "running checks for module ${MODULE}"
                         DEPENDS ${_test_name})
diff --git a/modules/gfx/pymod/export_gfx_node.cc b/modules/gfx/pymod/export_gfx_node.cc
index b7791e8e6..07195c100 100644
--- a/modules/gfx/pymod/export_gfx_node.cc
+++ b/modules/gfx/pymod/export_gfx_node.cc
@@ -31,7 +31,8 @@ void export_GfxNode()
   void (GfxNode::* node_rem2)(GfxNodeP) = &GfxNode::Remove;
   void (GfxNode::* node_rem3)(const String&) = &GfxNode::Remove;
 
-  class_<GfxNode, boost::noncopyable>("GfxNode",no_init)
+  class_<GfxNode, GfxNodeP, 
+         boost::noncopyable>("GfxNode", init<const String&>())
     .def("GetName",&GfxNode::GetName)
     .def("Hide",&GfxNode::Hide)
     .def("Show",&GfxNode::Show)
@@ -43,5 +44,4 @@ void export_GfxNode()
     .def("Remove",node_rem2)
     .def("Remove",node_rem3)
     ;
-  register_ptr_to_python<GfxNodeP>();
 }
diff --git a/modules/gfx/src/gfx_node.cc b/modules/gfx/src/gfx_node.cc
index d4ba1d117..76a513dc7 100644
--- a/modules/gfx/src/gfx_node.cc
+++ b/modules/gfx/src/gfx_node.cc
@@ -101,45 +101,94 @@ void GfxNode::Rename(const String& name)
   Scene::Instance().ObjectChanged(name_);
 }
 
+bool GfxNode::IsAttachedToScene() const
+{
+  GfxNodeP root=Scene::Instance().GetRootNode();
+  if (root==this->shared_from_this()) { return true; }
+  GfxNodeP parent=this->GetParent();
+  while (parent) {
+    if (parent==root) {
+      return true;
+    }
+    parent=parent->GetParent();
+  }
+  return false;
+}
+
 void GfxNode::Add(GfxObjP obj)
 {
-  node_vector_.push_back(obj);
-  Scene::Instance().NodeAdded(obj);
+  GfxNodeP node=obj;
+  this->Add(obj);
 }
 
 void GfxNode::Remove(GfxObjP obj)
 {
-  GfxNodeVector::iterator it = find (node_vector_.begin(), node_vector_.end(), obj);
+  GfxNodeVector::iterator it = find(node_vector_.begin(), 
+                                    node_vector_.end(), obj);
   if(it!=node_vector_.end()) {
     node_vector_.erase(it);
+    obj->parent_.reset();
+    if (this->IsAttachedToScene()) {
+      Scene::Instance().NotifyObservers(bind(&SceneObserver::NodeRemoved, 
+                                             _1, obj));
+    }    
   }
+
 }
+
 using boost::bind;
+
+
 void GfxNode::RemoveAll()
 {
-  GfxNodeVector v=node_vector_;
-  node_vector_.clear();
-  for (GfxNodeVector::iterator i=v.begin(), e=v.end(); i!=e; ++i) {
-    if (GfxObjP o=dyn_cast<GfxObj>(*i)) {
-      Scene::Instance().NotifyObservers(bind(&SceneObserver::NodeRemoved, _1, o));
-    }
+  bool attached=this->IsAttachedToScene();
+  for (GfxNodeVector::iterator i=node_vector_.begin(), 
+       e=node_vector_.end(); i!=e; ++i) {
+    (*i)->parent_.reset();
+    if (!attached) 
+      continue;
+    Scene::Instance().NotifyObservers(bind(&SceneObserver::NodeRemoved, 
+                                           _1, *i));
   }
+  node_vector_.clear();
 }
 
 void GfxNode::Add(GfxNodeP node)
 {
   node_vector_.push_back(node);
-  Scene::Instance().NodeAdded(node);    
+  if (!node->parent_.expired()) {
+    node->GetParent()->Remove(node);
+  }
+  node->parent_=this->shared_from_this();
+  if (this->IsAttachedToScene()) {
+    Scene::Instance().NodeAdded(node);
+  }
 }
 
 void GfxNode::Remove(GfxNodeP node)
 {
-  GfxNodeVector::iterator it = find (node_vector_.begin(), node_vector_.end(), node);
+  GfxNodeVector::iterator it=std::find(node_vector_.begin(), 
+                                       node_vector_.end(), node);
   if(it!=node_vector_.end()) {
+    node->parent_=GfxNodeP();
     node_vector_.erase(it);
   }
+  if (this->IsAttachedToScene()) {
+    Scene::Instance().NotifyObservers(bind(&SceneObserver::NodeRemoved, 
+                                           _1, node));
+  }
+}
+
+gfx::GfxNodeP GfxNode::GetParent() const
+{
+  if (parent_.expired()) {
+    return gfx::GfxNodeP();
+  }
+  return parent_.lock();
 }
 
+
+
 void GfxNode::Remove(const String& name)
 {
   GfxNodeVector::iterator node;
diff --git a/modules/gfx/src/gfx_node.hh b/modules/gfx/src/gfx_node.hh
index 4f3ceaf1f..9bec738a5 100644
--- a/modules/gfx/src/gfx_node.hh
+++ b/modules/gfx/src/gfx_node.hh
@@ -98,15 +98,25 @@ class DLLEXPORT_OST_GFX GfxNode: public boost::enable_shared_from_this<GfxNode>
   bool IsVisible() const;
 
   virtual void ContextSwitch();
-
+  
+  /// \brief whether the node (or one of it's parents) has been added to the
+  ///    scene
+  bool IsAttachedToScene() const;
+  
+  
+  gfx::GfxNodeP GetParent() const;
+  
+  const GfxNodeVector& GetChildren() const { return node_vector_; }
+  GfxNodeVector& GetChildren() { return node_vector_; }
  private:
   GfxNode(const GfxNode& o);
   GfxNode& operator=(const GfxNode&);
 
 
-  String name_;
-  bool show_;
-  GfxNodeVector node_vector_;
+  String                   name_;
+  bool                     show_;
+  GfxNodeVector            node_vector_;
+  boost::weak_ptr<GfxNode> parent_;
 };
 
 }}
diff --git a/modules/gfx/tests/CMakeLists.txt b/modules/gfx/tests/CMakeLists.txt
index eff4ec11f..227b9ff8d 100644
--- a/modules/gfx/tests/CMakeLists.txt
+++ b/modules/gfx/tests/CMakeLists.txt
@@ -1,5 +1,6 @@
 set(OST_GFX_UNIT_TESTS
   tests.cc
+  test_gfx_node.cc
 )
 if (ENABLE_IMG)
   list(APPEND OST_GFX_UNIT_TESTS test_map_octree.cc)
diff --git a/modules/gfx/tests/test_gfx_node.cc b/modules/gfx/tests/test_gfx_node.cc
new file mode 100644
index 000000000..361b9a2f2
--- /dev/null
+++ b/modules/gfx/tests/test_gfx_node.cc
@@ -0,0 +1,166 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2010 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+/*
+  Author: Marco Biasini
+ */
+#include <ost/string_ref.hh>
+#include <ost/platform.hh>
+#include <ost/gfx/gfx_node.hh>
+#include <ost/gfx/gfx_object.hh>
+#include <ost/gfx/scene.hh>
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+
+
+using boost::unit_test_framework::test_suite;
+using namespace ost;
+using namespace ost::gfx;
+
+// small RAII class to setup environment for unit tests. even though we don't
+// use any of the rendering functionality, we still need to initialize an 
+// offscreen buffer on mac to avoid segfaults.
+struct GfxTestEnv {
+  GfxTestEnv()
+  {
+    // we know OST_ROOT is set for unit tests
+    SetPrefixPath(getenv("OST_ROOT"));
+    Scene::Instance().StartOffscreenMode(100, 100);
+  }
+  
+  ~GfxTestEnv()
+  {
+    Scene::Instance().StopOffscreenMode();
+  }
+
+};
+
+
+struct Observer : public SceneObserver {
+  Observer(): added_count(0),removed_count(0) {}
+  
+  virtual void NodeAdded(const GfxNodeP& node)
+  {
+    added_count+=1;
+  }
+  
+  virtual void NodeRemoved(const GfxNodeP& node)
+  {
+    removed_count+=1;
+  }
+  
+  int added_count;
+  int removed_count;
+};
+
+BOOST_AUTO_TEST_SUITE(gfx_node)
+
+BOOST_AUTO_TEST_CASE(gfx_node_add) 
+{
+  GfxNodeP n1(new GfxNode("1"));
+  BOOST_CHECK_EQUAL(n1->GetParent(), GfxNodeP());
+  BOOST_CHECK_EQUAL(n1->GetChildCount(), 0);
+  GfxNodeP n2(new GfxNode("2"));
+  n1->Add(n2);
+  BOOST_CHECK_EQUAL(n1->GetParent(), GfxNodeP());
+  BOOST_CHECK_EQUAL(n1->GetChildCount(), 1);   
+  BOOST_CHECK_EQUAL(n2->GetParent(), n1);
+  BOOST_CHECK_EQUAL(n2->GetChildCount(), 0);
+  
+  // "move" node 2 from 1 to 3
+  GfxNodeP n3(new GfxNode("3"));
+  n3->Add(n2);
+  BOOST_CHECK_EQUAL(n1->GetChildCount(), 0);
+  BOOST_CHECK_EQUAL(n2->GetParent(), n3);
+  BOOST_CHECK_EQUAL(n3->GetChildCount(), 1);
+}
+
+
+BOOST_AUTO_TEST_CASE(gfx_node_remove) 
+{
+  GfxNodeP n1(new GfxNode("1"));
+  BOOST_CHECK_EQUAL(n1->GetParent(), GfxNodeP());
+  BOOST_CHECK_EQUAL(n1->GetChildCount(), 0);
+  GfxNodeP n2(new GfxNode("2"));
+  n1->Add(n2);
+  n1->Remove(n2);
+  BOOST_CHECK_EQUAL(n1->GetChildCount(), 0);
+  BOOST_CHECK_EQUAL(n2->GetParent(), GfxNodeP());
+}
+
+BOOST_AUTO_TEST_CASE(gfx_node_remove_all) 
+{
+  GfxNodeP n1(new GfxNode("1"));
+  BOOST_CHECK_EQUAL(n1->GetParent(), GfxNodeP());
+  BOOST_CHECK_EQUAL(n1->GetChildCount(), 0);
+  GfxNodeP n2(new GfxNode("2"));
+  GfxNodeP n3(new GfxNode("3"));
+  GfxNodeP n4(new GfxNode("4"));
+  n1->Add(n2);
+  n1->Add(n3);
+  n1->Add(n4);
+  n1->RemoveAll();
+  BOOST_CHECK_EQUAL(n1->GetChildCount(), 0);
+  BOOST_CHECK_EQUAL(n2->GetParent(), GfxNodeP());
+}
+
+BOOST_AUTO_TEST_CASE(is_attached_to_scene) 
+{
+  GfxTestEnv env;
+  Scene::Instance().RemoveAll();  
+  GfxNodeP n1(new GfxNode("1"));
+  GfxNodeP n2(new GfxNode("2"));
+  n1->Add(n2);
+  BOOST_CHECK(!n1->IsAttachedToScene());
+  BOOST_CHECK(!n2->IsAttachedToScene());
+  
+  Scene::Instance().Add(n1);
+  BOOST_CHECK(n1->IsAttachedToScene());
+  BOOST_CHECK(n2->IsAttachedToScene());
+  
+  // root node is always connected to scene!
+  BOOST_CHECK(Scene::Instance().GetRootNode()->IsAttachedToScene());
+}
+
+BOOST_AUTO_TEST_CASE(observe_added_removed)
+{
+  GfxTestEnv env;
+  Observer o1;
+  Scene::Instance().RemoveAll();
+  Scene::Instance().AttachObserver(&o1);
+  GfxNodeP n1(new GfxNode("1"));
+  GfxNodeP n2(new GfxNode("2"));
+  GfxNodeP n3(new GfxNode("3"));
+  n1->Add(n2);
+  BOOST_CHECK_EQUAL(o1.added_count, 0);
+  BOOST_CHECK_EQUAL(o1.removed_count, 0);
+  Scene::Instance().Add(n1);
+  BOOST_CHECK_EQUAL(o1.added_count, 1);
+  BOOST_CHECK_EQUAL(o1.removed_count, 0);
+  n2->Add(n3);
+  BOOST_CHECK_EQUAL(o1.added_count, 2);
+  BOOST_CHECK_EQUAL(o1.removed_count, 0);
+  n2->Remove(n3);
+  BOOST_CHECK_EQUAL(o1.added_count, 2);
+  BOOST_CHECK_EQUAL(o1.removed_count, 1);
+}
+
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/gui/src/scene_win/current_selection_node.cc b/modules/gui/src/scene_win/current_selection_node.cc
index 9de4397a4..6f7eeddaa 100644
--- a/modules/gui/src/scene_win/current_selection_node.cc
+++ b/modules/gui/src/scene_win/current_selection_node.cc
@@ -19,7 +19,7 @@
 
 #include <ost/gui/gosty_app.hh>
 #include <ost/mol/query_view_wrapper.hh>
-
+#include <ost/gui/scene_win/scene_win_model.hh>
 #include <ost/gfx/scene.hh>
 #include <ost/gfx/gfx_node.hh>
 
diff --git a/modules/gui/src/scene_win/custom_part_node.cc b/modules/gui/src/scene_win/custom_part_node.cc
index 18c9d9972..e18e6d62c 100644
--- a/modules/gui/src/scene_win/custom_part_node.cc
+++ b/modules/gui/src/scene_win/custom_part_node.cc
@@ -20,7 +20,7 @@
 #include "custom_part_node.hh"
 
 #include "entity_part_node.hh"
-
+#include <ost/gui/scene_win/scene_win_model.hh>
 #include <ost/gfx/entity.hh>
 #include <ost/gfx/gfx_node.hh>
 
diff --git a/modules/gui/src/scene_win/entity_node.cc b/modules/gui/src/scene_win/entity_node.cc
index 3aa51c81c..4f49dcc96 100644
--- a/modules/gui/src/scene_win/entity_node.cc
+++ b/modules/gui/src/scene_win/entity_node.cc
@@ -25,7 +25,7 @@
 #include <ost/mol/view_type_fw.hh>
 
 #include <ost/gui/scene_win/scene_win.hh>
-
+#include <ost/gui/scene_win/scene_win_model.hh>
 #include "current_selection_node.hh"
 #include "entity_part_node.hh"
 #include "label_node.hh"
@@ -43,7 +43,6 @@ EntityNode::EntityNode(gfx::EntityP& entity, SceneNode* parent):
     GfxSceneNode(entity,parent),custom_view_(NULL){
   SceneWinModel* model = GostyApp::Instance()->GetSceneWin()->GetModel();
   model->AddNode(parent, this);
-
   new RenderModesNode(entity, this);
 
   SceneNode* chain_node = new LabelNode("Chains",this);
diff --git a/modules/gui/src/scene_win/entity_part_node.cc b/modules/gui/src/scene_win/entity_part_node.cc
index da8867d8b..bc1fb5a9f 100644
--- a/modules/gui/src/scene_win/entity_part_node.cc
+++ b/modules/gui/src/scene_win/entity_part_node.cc
@@ -18,14 +18,19 @@
 //------------------------------------------------------------------------------
 
 #include "entity_part_node.hh"
-
+#include <ost/gui/scene_win/scene_win_model.hh>
 #include <ost/gfx/entity.hh>
 #include <ost/gfx/gfx_node.hh>
 
 #include <QFont>
 namespace ost { namespace gui {
 
-EntityPartNode::EntityPartNode(QString name, gfx::EntityP entity, mol::QueryViewWrapper part, SceneNode* parent):SceneNode(parent),name_(name),entity_(entity),query_view_(part),visible_(true){
+EntityPartNode::EntityPartNode(QString name, gfx::EntityP entity, 
+                               mol::QueryViewWrapper part, 
+                               SceneNode* parent):
+  SceneNode(parent),name_(name),entity_(entity),
+  query_view_(part),visible_(true)
+{
 }
 
 QVariant EntityPartNode::GetData(int column, int role){
diff --git a/modules/gui/src/scene_win/gfx_scene_node.cc b/modules/gui/src/scene_win/gfx_scene_node.cc
index 191007aee..048cee446 100644
--- a/modules/gui/src/scene_win/gfx_scene_node.cc
+++ b/modules/gui/src/scene_win/gfx_scene_node.cc
@@ -18,7 +18,7 @@
 //------------------------------------------------------------------------------
 
 #include "gfx_scene_node.hh"
-
+#include <ost/gui/scene_win/scene_win_model.hh>
 #include <ost/gfx/scene.hh>
 #include <ost/gfx/gfx_node.hh>
 
diff --git a/modules/gui/src/scene_win/label_node.cc b/modules/gui/src/scene_win/label_node.cc
index 8a01e6aec..f6d2d72f5 100644
--- a/modules/gui/src/scene_win/label_node.cc
+++ b/modules/gui/src/scene_win/label_node.cc
@@ -21,7 +21,7 @@
 
 #include <ost/gfx/entity.hh>
 #include <ost/gfx/gfx_node.hh>
-
+#include <ost/gui/scene_win/scene_win_model.hh>
 #include <QFont>
 namespace ost { namespace gui {
 
diff --git a/modules/gui/src/scene_win/render_mode_node.cc b/modules/gui/src/scene_win/render_mode_node.cc
index 88e67dea8..de6bc6fe6 100644
--- a/modules/gui/src/scene_win/render_mode_node.cc
+++ b/modules/gui/src/scene_win/render_mode_node.cc
@@ -18,7 +18,7 @@
 //------------------------------------------------------------------------------
 
 #include <ost/mol/query_view_wrapper.hh>
-
+#include <ost/gui/scene_win/scene_win_model.hh>
 #include "render_mode_node.hh"
 
 #include <QFont>
diff --git a/modules/gui/src/scene_win/render_modes_node.cc b/modules/gui/src/scene_win/render_modes_node.cc
index a343490b8..611cc3561 100644
--- a/modules/gui/src/scene_win/render_modes_node.cc
+++ b/modules/gui/src/scene_win/render_modes_node.cc
@@ -24,7 +24,7 @@
 #include <ost/gfx/gfx_node.hh>
 
 #include <ost/gui/scene_win/scene_win.hh>
-
+#include <ost/gui/scene_win/scene_win_model.hh>
 #include "render_modes_node.hh"
 #include "render_mode_node.hh"
 #include <QFont>
diff --git a/modules/gui/src/scene_win/scene_win.cc b/modules/gui/src/scene_win/scene_win.cc
index ba685c3f6..e398f9678 100644
--- a/modules/gui/src/scene_win/scene_win.cc
+++ b/modules/gui/src/scene_win/scene_win.cc
@@ -23,7 +23,8 @@
 #include <ost/gui/gosty_app.hh>
 #include <ost/gui/widget_registry.hh>
 #include <ost/gui/scene_selection.hh>
-
+#include <ost/gui/scene_win/scene_win_model.hh>
+#include <ost/gui/scene_win/context_menu.hh>
 #include "scene_win.hh"
 
 #include <QVBoxLayout>
diff --git a/modules/gui/src/scene_win/scene_win.hh b/modules/gui/src/scene_win/scene_win.hh
index 612198db6..c0f16a5dc 100644
--- a/modules/gui/src/scene_win/scene_win.hh
+++ b/modules/gui/src/scene_win/scene_win.hh
@@ -23,20 +23,24 @@
 #include <ost/mol/query_view_wrapper.hh>
 
 #include <ost/gfx/gfx_node_fw.hh>
+#include <ost/gfx/entity.hh>
 
 #include <ost/gui/module_config.hh>
 #include <ost/gui/widget.hh>
-#include <ost/gui/scene_win/scene_win_model.hh>
-#include <ost/gui/scene_win/context_menu.hh>
 
 #include <QTreeView>
 #include <QItemSelection>
+
+
 /*
   Authors: Marco Biasini, Ansgar Philippsen, Stefan Scheuber
 */
 
 namespace ost { namespace gui {
 
+class SceneWinModel;
+class ContextMenu;
+
 // the display window for all graphical objects
 class DLLEXPORT_OST_GUI SceneWin: public Widget
 {
diff --git a/modules/gui/src/scene_win/scene_win_model.cc b/modules/gui/src/scene_win/scene_win_model.cc
index 9e7542b08..6c833ba48 100644
--- a/modules/gui/src/scene_win/scene_win_model.cc
+++ b/modules/gui/src/scene_win/scene_win_model.cc
@@ -35,6 +35,7 @@
 
 #include <QSize>
 #include <QFont>
+#include <QDebug>
 
 namespace ost { namespace gui {
 
@@ -105,19 +106,22 @@ gfx::EntityP SceneWinModel::GetEntityOfViews(QModelIndexList indexes){
   return entity;
 }
 
-void SceneWinModel::Update(){
+void SceneWinModel::Update()
+{
   emit this->dataChanged(QModelIndex(),QModelIndex());
 }
 
-QModelIndex SceneWinModel::index(int row, int col, const QModelIndex& parent) const
+QModelIndex SceneWinModel::index(int row, int col, 
+                                 const QModelIndex& parent) const
 {
   SceneNode* parent_node = GetItem(parent);
 
   SceneNode* child_node = parent_node->GetChild(row);
-  if (child_node)
-      return createIndex(row, col, child_node);
-  else
-      return QModelIndex();
+  if (child_node) {
+    return createIndex(row, col, child_node);
+  } else {
+    return QModelIndex();    
+  }
 }
 
 QModelIndex SceneWinModel::parent(const QModelIndex& index) const
@@ -231,24 +235,36 @@ QMimeData* SceneWinModel::mimeData(const QModelIndexList &indexes) const
 void SceneWinModel::NodeAdded(const gfx::GfxNodeP& node)
 {
   gfx::EntityP e=boost::dynamic_pointer_cast<gfx::Entity>(node);
-  if(e){
-    new EntityNode(e,scene_node_);
+  SceneNode* parent_node=this->FindGfxNode(node->GetParent());
+  if (parent_node==NULL) {
+    parent_node=scene_node_;
+  }
+  if (e) {
+    EntityNode* ent_node=new EntityNode(e,parent_node);
+    node_map_[node.get()]=ent_node;
   }
   else{
-    SceneNode* scene_node = new GfxSceneNode(node, scene_node_);
-    this->AddNode(scene_node_,scene_node);
+    SceneNode* scene_node = new GfxSceneNode(node, parent_node);
+    node_map_[node.get()]=scene_node;
+    this->AddNode(parent_node, scene_node);
+    for (gfx::GfxNodeVector::const_iterator i=node->GetChildren().begin(),
+         e=node->GetChildren().end(); i!=e; ++i) {
+      this->NodeAdded(*i);
+    }
   }
 }
 
 void SceneWinModel::NodeRemoved(const gfx::GfxNodeP& node)
 {
   SceneNode* scene_node = this->FindGfxNode(node);
-  if(scene_node->GetParent()){
+  if(scene_node && scene_node->GetParent()){
+    node_map_.remove(node.get());
     this->RemoveNode(scene_node);
   }
 }
 
-void SceneWinModel::SelectionChanged(const gfx::GfxObjP& obj, const mol::EntityView& sel)
+void SceneWinModel::SelectionChanged(const gfx::GfxObjP& obj, 
+                                     const mol::EntityView& sel)
 {
 }
 
@@ -268,8 +284,9 @@ SceneNode* SceneWinModel::GetItem(const QModelIndex &index) const
   return root_node_;
 }
 
-bool SceneWinModel::AddNode(SceneNode* parent, SceneNode* child){
-  QModelIndex parent_index = GetIndexOf(parent);
+bool SceneWinModel::AddNode(SceneNode* parent, SceneNode* child)
+{
+  QModelIndex parent_index=this->GetIndexOf(parent);
   if(parent_index.isValid()){
     int row = parent->GetChildCount();
     this->beginInsertRows(parent_index,row,row);
@@ -280,11 +297,12 @@ bool SceneWinModel::AddNode(SceneNode* parent, SceneNode* child){
   return false;
 }
 
-bool SceneWinModel::RemoveNode(SceneNode* node){
-  QModelIndex index = GetIndexOf(node);
-  SceneNode* parent = node->GetParent();
+bool SceneWinModel::RemoveNode(SceneNode* node)
+{
+  QModelIndex index=this->GetIndexOf(node);
+  SceneNode* parent=node->GetParent();
   if(parent && index.isValid()){
-    QModelIndex parent_index = GetIndexOf(parent);
+    QModelIndex parent_index =this->GetIndexOf(parent);
     int row = node->GetRow();
     this->beginRemoveRows(parent_index,row,row);
     parent->RemoveChild(node);
@@ -295,26 +313,45 @@ bool SceneWinModel::RemoveNode(SceneNode* node){
 }
 
 
-void SceneWinModel::AttachRenderModeObserver(RenderModesNode* node){
+void SceneWinModel::AttachRenderModeObserver(RenderModesNode* node)
+{
   render_observers_.insert(node->GetGfxNode(),node);
 }
 
-void SceneWinModel::DetachRenderModeObserver(RenderModesNode* node){
+void SceneWinModel::DetachRenderModeObserver(RenderModesNode* node)
+{
   if(render_observers_.contains(node->GetGfxNode())){
     render_observers_.remove(node->GetGfxNode());
   }
 }
 
-QModelIndex SceneWinModel::GetIndexOf(SceneNode* node, int column){
-  return GetIndex(node,index(0,0,QModelIndex()),column);
+QModelIndex SceneWinModel::GetIndexOf(SceneNode* node, int column) 
+{
+  std::vector<SceneNode*> trace;
+  SceneNode* parent=node->GetParent();
+  while (parent) {
+    trace.push_back(parent);
+    parent=parent->GetParent();
+    
+  }
+  if (!trace.empty()) {
+    trace.pop_back();
+  }
+  QModelIndex parent_index=this->index(0, 0, QModelIndex());
+  for (std::vector<SceneNode*>::reverse_iterator i=trace.rbegin(), 
+       e=trace.rend(); i!=e; ++i) {
+    SceneNode* cur=*i;
+    parent_index=this->GetIndex(cur, parent_index, 0);
+  }
+  return this->GetIndex(node, parent_index, column);
 }
 
-QModelIndex SceneWinModel::GetIndex(SceneNode* node, QModelIndex parent, int column){
+QModelIndex SceneWinModel::GetIndex(SceneNode* node, QModelIndex parent, 
+                                    int column) {
   if(parent.isValid()){
     SceneNode* parent_node =reinterpret_cast<SceneNode*>(parent.internalPointer());
-    if(parent_node == node)return parent;
-    int i=parent_node->GetChildCount()-1;
-    while(i>=0){
+    if (parent_node == node) return parent;
+    for (int i=parent_node->GetChildCount()-1; i>=0; --i) {
       SceneNode* child = parent_node->GetChild(i);
       if(child == node){
         if(column<child->GetColumnCount())
@@ -326,24 +363,18 @@ QModelIndex SceneWinModel::GetIndex(SceneNode* node, QModelIndex parent, int col
       if (found.isValid()) {
         return found;
       }
-      i--;
     }
   }
   return QModelIndex();
 }
 
-SceneNode* SceneWinModel::FindGfxNode(gfx::GfxNodeP node) const{
-  int i=0;
-  while(i<scene_node_->GetChildCount()){
-    GfxSceneNode* gfx_scene_node = qobject_cast<GfxSceneNode*>(scene_node_->GetChild(i));
-    if(gfx_scene_node && node==gfx_scene_node->GetGfxNode()){
-      return gfx_scene_node;
-    }
-    else{
-      i++;
-    }
+SceneNode* SceneWinModel::FindGfxNode(gfx::GfxNodeP node) 
+{
+  QMap<gfx::GfxNode*, SceneNode*>::iterator i=node_map_.find(node.get());
+  if (i!=node_map_.end()) {
+    return i.value();
   }
-  return root_node_;
+  return NULL;
 }
 
 }} // ns
diff --git a/modules/gui/src/scene_win/scene_win_model.hh b/modules/gui/src/scene_win/scene_win_model.hh
index 060b14881..fbcee3d4b 100644
--- a/modules/gui/src/scene_win/scene_win_model.hh
+++ b/modules/gui/src/scene_win/scene_win_model.hh
@@ -59,7 +59,7 @@ public:
 
   SceneNode* GetItem(const QModelIndex &index) const;
 
-  SceneNode* FindGfxNode(gfx::GfxNodeP node) const;
+  SceneNode* FindGfxNode(gfx::GfxNodeP node);
 
 
   bool AddNode(SceneNode* parent, SceneNode* child);
@@ -107,6 +107,7 @@ private:
   SceneNode* scene_node_;
 
   QMap<gfx::GfxNodeP, RenderModesNode*> render_observers_;
+  QMap<gfx::GfxNode*, SceneNode*>       node_map_;
 };
 
 }}
diff --git a/modules/gui/src/sequence_viewer/sequence_viewer.cc b/modules/gui/src/sequence_viewer/sequence_viewer.cc
index 888a87597..82f3892ba 100644
--- a/modules/gui/src/sequence_viewer/sequence_viewer.cc
+++ b/modules/gui/src/sequence_viewer/sequence_viewer.cc
@@ -67,13 +67,21 @@ public:
 
 OST_REGISTER_WIDGET(SequenceViewer, SequenceViewerFactory);
 
+struct NodeParentPair {
+  NodeParentPair(gfx::GfxNodeP n, gfx::GfxNodeP p): node(n), parent(p) {}
+  
+  gfx::GfxNodeP node;
+  gfx::GfxNodeP parent;
+};
+
 struct GetNodesVisitor: public gfx::GfxNodeVisitor {
+
   GetNodesVisitor(): nodes_() {}
   virtual void VisitObject(gfx::GfxObj* o, const Stack& st) {
-    nodes_.push_back(o->shared_from_this());
+    nodes_.push_back(o->shared_from_this());    
   }
-  gfx::NodePtrList nodes_;
-  gfx::NodePtrList GetNodes(){return nodes_;}
+  gfx::GfxNodeVector nodes_;
+  gfx::GfxNodeVector GetNodes() {return nodes_; }
 };
 
 SequenceViewer::SequenceViewer(bool stand_alone, bool observe_scene,
@@ -101,7 +109,7 @@ SequenceViewer::SequenceViewer(bool stand_alone, bool observe_scene,
     gfx::GfxNodeP root_node = gfx::Scene::Instance().GetRootNode();
     GetNodesVisitor gnv;
     gfx::Scene::Instance().Apply(gnv);
-    gfx::NodePtrList list = gnv.GetNodes();
+    gfx::GfxNodeVector list=gnv.GetNodes();
     for(unsigned int i=0; i<list.size();i++){
       this->NodeAdded(list[i]);
     }    
-- 
GitLab