From cc2f9aaa518a6851308babd90b0fd189964b8194 Mon Sep 17 00:00:00 2001
From: Ansgar Philippsen <ansgar.philippsen@gmail.com>
Date: Tue, 19 Jul 2011 22:04:13 -0400
Subject: [PATCH] added Reset to gfx.Entity, plus some other minor interface
 tweaks

---
 modules/gfx/pymod/__init__.py                 | 80 +++++++++++++++++++
 modules/gfx/pymod/export_entity.cc            | 41 ++++++++--
 modules/gfx/src/entity.cc                     | 46 ++++++++++-
 modules/gfx/src/entity.hh                     | 28 ++++++-
 modules/gfx/tests/test_gfx.py                 | 14 ++++
 .../base/pymod/export_query_view_wrapper.cc   |  1 +
 modules/mol/base/src/query_view_wrapper.hh    | 16 +++-
 7 files changed, 213 insertions(+), 13 deletions(-)

diff --git a/modules/gfx/pymod/__init__.py b/modules/gfx/pymod/__init__.py
index 54995ff50..ab6f3d27b 100644
--- a/modules/gfx/pymod/__init__.py
+++ b/modules/gfx/pymod/__init__.py
@@ -249,3 +249,83 @@ PrimList.AddLine=_primlist_add_line
 PrimList.AddSphere=_primlist_add_sphere
 PrimList.AddCyl=_primlist_add_cyl
 PrimList.AddText=_primlist_add_text
+
+# entity reset
+
+def _entity_reset(self,*args,**kwargs):
+  import ost.mol as mol
+  eh=None
+  ev=None
+  qr=None
+  qf=None
+  for a in args:
+    if isinstance(a,mol.Query):
+      if qr:
+        raise TypeError("Reset: more than one query string given")
+      qr=a
+    elif isinstance(a,mol.EntityHandle):
+      if eh:
+        raise TypeError("Reset: more than one entity handle given")
+      eh=a
+    elif isinstance(a,mol.EntityView):
+      if ev:
+        raise TypeError("Reset: more than one entity view given")
+      ev=a
+    elif isinstance(a,str):
+      if qr:
+        raise TypeError("Reset: more than one query string given")
+      qr=mol.Query(a)
+    elif isinstance(a,int):
+      if qf:
+        raise TypeError("Reset: more than one QueryFlags given")
+      qf=a
+    else:
+      raise TypeError("Reset: unknown option of type '%s' given"%type(a))
+
+  for key,val in kwargs.iteritems():
+    if key=="entity":
+      if not isinstance(val,mol.EntityHandle):
+        raise TypeError("Reset: expected mol.EntityHandle for 'entity' option")
+      if eh:
+        raise TypeError("Reset: more than one entity handle given")
+      eh=val
+    elif key=="view":
+      if not isinstance(val,mol.EntityView):
+        raise TypeError("Reset: expected mol.EntityView for 'view' option")
+      if ev:
+        raise TypeError("Reset: more than one entity view given")
+      ev=val
+    elif key=="query":
+      if isinstance(val,mol.Query):
+        pass
+      elif isinstance(val,str):
+        val=mol.Query(val)
+      else:
+        raise TypeError("Reset: expected mol.Query or string for 'query' option")
+      if qr:
+        raise TypeError("Reset: more than one query string given")
+      qr=val
+    elif key=="query_flags":
+      if not isinstance(val,int):
+        raise TypeError("Reset: expected integer for 'query_flags' option")
+      if qf:
+        raise TypeError("Reset: more than one query flags given")
+      qf=val
+    else:
+      raise TypeError("Reset: unknown key '%s'"%key)
+        
+  if eh and ev:
+    raise TypeError("Reset: entity and view are mutually exclusive options")
+
+  if ev:
+    self._reset4(ev)
+  else:
+    if not eh:
+      eh = self.query_view.entity
+    if not qr:
+      qr = self.query_view.query
+    if not qf:
+      qf = self.query_view.GetFlags()
+    self._reset3(eh,qr,qf)
+
+Entity.Reset=_entity_reset
diff --git a/modules/gfx/pymod/export_entity.cc b/modules/gfx/pymod/export_entity.cc
index dd999dcbc..0767825bd 100644
--- a/modules/gfx/pymod/export_entity.cc
+++ b/modules/gfx/pymod/export_entity.cc
@@ -266,14 +266,28 @@ RenderOptionsPtr ent_cpk_opts(Entity* ent)
   return ent->GetOptions(RenderMode::CPK);
 }
 
-void set_query1(Entity* e, const mol::Query& q)
+void set_query(Entity* e, object o)
 {
-  e->SetQuery(q);
-}
+  LOG_WARNING("SetQuery is deprecated, use source property instead");
 
-void set_query2(Entity* e, const std::string& q)
-{
-  e->SetQuery(mol::Query(q));
+  if(o==object()) {
+    e->SetQuery(mol::Query());
+    return;
+  }
+
+  extract<String> str(o);
+  if(str.check()) {
+    e->SetQuery(mol::Query(str()));
+    return;
+  }
+
+  extract<mol::Query> qry(o);
+  if(qry.check()) {
+    e->SetQuery(qry());
+    return;
+  }
+
+  throw Error("expected string or mol::Query as parameter");
 }
 
 RenderOptionsPtr ent_ltrace_opts(Entity* ent)
@@ -302,10 +316,19 @@ void set_selection(Entity* ent, object sel)
 
 void export_Entity()
 {
+  void (Entity::*reset1)(const mol::EntityHandle&) = &Entity::Reset;
+  void (Entity::*reset2)(const mol::EntityHandle&, const mol::Query&) = &Entity::Reset;
+  void (Entity::*reset3)(const mol::EntityHandle&, const mol::Query&, mol::QueryFlags) = &Entity::Reset;
+  void (Entity::*reset4)(const mol::EntityView&) = &Entity::Reset;
+
   class_<Entity, boost::shared_ptr<Entity>, bases<GfxObj>, boost::noncopyable>("Entity", init<const String&, const mol:: EntityHandle&, optional<const mol:: Query&, mol::QueryFlags> >())
     .def(init<const String&, RenderMode::Type, const mol::EntityHandle&, optional<const mol::Query&, mol::QueryFlags> >())
     .def(init<const String&, const mol::EntityView&>())
     .def(init<const String&, RenderMode::Type, const mol::EntityView&>())
+    .def("_reset1",reset1)
+    .def("_reset2",reset2)
+    .def("_reset3",reset3)
+    .def("_reset4",reset4)
     .def("SetColor",ent_set_color1)
     .def("SetColor",ent_set_color2)
     .def("SetDetailColor", &Entity::SetDetailColor, arg("sel")=String(""))
@@ -322,8 +345,10 @@ void export_Entity()
                   &set_selection)
     .def("GetView", &Entity::GetView)
     .def("UpdateView", &Entity::UpdateView)
-    .def("SetQuery", set_query1)
-    .def("SetQuery", set_query2)
+    .def("SetQuery", set_query)
+    .def("SetQueryView",&Entity::SetQueryView)
+    .def("GetQueryView",&Entity::GetQueryView)
+    .add_property("query_view",&Entity::GetQueryView,&Entity::SetQueryView)
     .def("GetRenderModeName", &Entity::GetRenderModeName)
     .def("GetNotEmptyRenderModes", &Entity::GetNotEmptyRenderModes)
     .def("SetRenderMode", set_rm1, (arg("mode"), arg("view"), arg("keep")=false))
diff --git a/modules/gfx/src/entity.cc b/modules/gfx/src/entity.cc
index b961134f3..b5f0f6b75 100644
--- a/modules/gfx/src/entity.cc
+++ b/modules/gfx/src/entity.cc
@@ -758,7 +758,6 @@ void Entity::SetDetailColor(const Color& col, const String& selection)
   this->Apply(cop);
 }
 
-/// \brief set selection
 void Entity::SetSelection(const mol::EntityView& view)
 {
   if (!view.IsValid()) {
@@ -902,6 +901,51 @@ void Entity::SetQuery(const mol::Query& q)
   Rebuild();
 }
 
+void Entity::Reset(const mol::EntityHandle& eh)
+{
+  qv_=mol::QueryViewWrapper(qv_.GetQuery(),qv_.GetFlags(),eh);
+  update_view_=true;
+  Rebuild();
+}
+
+void Entity::Reset(const mol::EntityHandle& eh, const mol::Query& q)
+{
+  qv_=mol::QueryViewWrapper(q,qv_.GetFlags(),eh);
+  update_view_=true;
+  Rebuild();
+}
+
+void Entity::Reset(const mol::EntityHandle& eh, const mol::Query& q, mol::QueryFlags f)
+{
+  qv_=mol::QueryViewWrapper(q,f,eh);
+  update_view_=true;
+  Rebuild();
+}
+
+void Entity::Reset(const mol::EntityView& ev)
+{
+  qv_=mol::QueryViewWrapper(ev);
+  update_view_=true;
+  Rebuild();
+}
+
+void Entity::SetQueryView(const mol::QueryViewWrapper& qv)
+{
+  qv_=qv;
+  update_view_=true;
+  Rebuild();
+}
+
+mol::QueryViewWrapper Entity::GetQueryView() const
+{
+  return qv_;
+}
+
+mol::EntityHandle Entity::GetEntity() const
+{
+  return qv_.GetEntity();
+}
+
 void Entity::ColorBy(const String& prop,
                      const Color& c1, const Color& c2,
                      mol::Prop::Level level)
diff --git a/modules/gfx/src/entity.hh b/modules/gfx/src/entity.hh
index 49cca7a78..7e6d595fa 100644
--- a/modules/gfx/src/entity.hh
+++ b/modules/gfx/src/entity.hh
@@ -150,6 +150,18 @@ public:
   virtual void SetOutlineExpandFactor(float f);
   virtual void SetOutlineExpandColor(const Color& c);
 
+  /// \brief resets used entity handle
+  /// replaces underlying entity, keeps query and flags intact
+  void Reset(const mol::EntityHandle& eh);
+  /// \brief resets used entity handle and query
+  /// replaces underlying entity and query, keeps flags intact
+  void Reset(const mol::EntityHandle& eh, const mol::Query& q);
+  /// \brief resets used entity handle, query and flags
+  /// this has the same effect as the ctor call with the same parameters
+  void Reset(const mol::EntityHandle& eh, const mol::Query& q, mol::QueryFlags flags);
+  /// \brief resets entity view
+  /// this as the same effect as the ctor call with the same parameters
+  void Reset(const mol::EntityView& ev);
   /// \brief rebuild graphical object (see ctor comments)
   /*
     the naming here is misleading - this method WON'T be called upon FlagRebuild
@@ -188,13 +200,23 @@ public:
   /// \brief get view
   mol::EntityView GetView() const;
 
+  /// \brief set a new query to use (deprecated)
+  /// this will re-create the object based on the given selection
   void SetQuery(const mol::Query& q);
 
-  // turn blur on or off
+  /// return internally used query view
+  mol::QueryViewWrapper GetQueryView() const;
+  /// set new query view, rebuilding object
+  void SetQueryView(const mol::QueryViewWrapper& qv);
+
+  /// return underlying entity
+  mol::EntityHandle GetEntity() const;
+
+  // turn blur on or off (experimental feature)
   void SetBlur(bool f);
-  // set atom positions as n-1 for blur
+  // set atom positions as n-1 for blur (experimental feature)
   void BlurSnapshot();
-  // blur transparency falloffs
+  // blur transparency falloffs (experimental feature)
   void SetBlurFactors(float bf1,float bf2);
 
   /// \brief set selection
diff --git a/modules/gfx/tests/test_gfx.py b/modules/gfx/tests/test_gfx.py
index ff0d32d9a..b6911eee1 100644
--- a/modules/gfx/tests/test_gfx.py
+++ b/modules/gfx/tests/test_gfx.py
@@ -2,8 +2,10 @@ import unittest
 if __name__== '__main__':
   import sys
   sys.path.insert(0,"../../../stage/lib64/openstructure/")
+  sys.path.insert(0,"../../../stage/lib/openstructure/")
 
 import ost
+import ost.mol as mol
 import ost.gfx as gfx
 import ost.geom as geom
 
@@ -15,6 +17,18 @@ class TestGfx(unittest.TestCase):
     self.test_gradient()
     self.test_color()
     self.test_primlist()
+    self.test_entity_reset()
+
+  def test_entity_reset(self):
+    eh=mol.CreateEntity()
+    eh2=mol.CreateEntity()
+    go=gfx.Entity("foo",eh)
+    go.Reset(eh)
+    go.Reset("rnum=1")
+    go.Reset(entity=eh2)
+    go.Reset(eh.Select("rnum=2"))
+    go.Reset(eh,"rnum=3",mol.MATCH_RESIDUES)
+    go.Reset("rnum=4",eh2)
 
   def test_gradient(self):
     gs=[gfx.Gradient(),
diff --git a/modules/mol/base/pymod/export_query_view_wrapper.cc b/modules/mol/base/pymod/export_query_view_wrapper.cc
index f84fa6c0e..f16c0c3cd 100644
--- a/modules/mol/base/pymod/export_query_view_wrapper.cc
+++ b/modules/mol/base/pymod/export_query_view_wrapper.cc
@@ -45,6 +45,7 @@ void export_QueryViewWrapper()
     .def("GetFlags", &QueryViewWrapper::GetFlags)
     .def("SetFlags", &QueryViewWrapper::SetFlags)
     .add_property("entity_view", &QueryViewWrapper::GetEntityView)
+    .add_property("entity", &QueryViewWrapper::GetEntity)
     .add_property("query", make_function(&QueryViewWrapper::GetQuery
         ,return_value_policy<copy_const_reference>()))
   ;
diff --git a/modules/mol/base/src/query_view_wrapper.hh b/modules/mol/base/src/query_view_wrapper.hh
index fd6b5b4a0..7b2418431 100644
--- a/modules/mol/base/src/query_view_wrapper.hh
+++ b/modules/mol/base/src/query_view_wrapper.hh
@@ -27,6 +27,9 @@
 
 namespace ost { namespace mol {
 
+/*!
+  helper class to manage relationship between entity, query and view
+*/
 class DLLEXPORT_OST_MOL QueryViewWrapper {
 public:
   explicit QueryViewWrapper(const EntityHandle& entity_handle);
@@ -36,16 +39,27 @@ public:
   QueryViewWrapper(const Query& query, const EntityView& view = mol::EntityView());
   QueryViewWrapper(const Query& query, QueryFlags flags, const EntityHandle& handle);
   QueryViewWrapper(const Query& query, QueryFlags flags, const EntityView& view = mol::EntityView());
-  EntityView GetEntityView() const;
+
+  /// returns true if view will be recalculated from query
   bool DependsOnQuery() const;
   bool IsDataValid() const;
 
+  /// regenerates current view based on internal state
+  EntityView GetEntityView() const;
+
+  /// explicitely sets current query
   void SetQuery(const Query& query);
+  /// retrieve current query
   const Query& GetQuery() const;
 
+  /// set query flags to be used internally for the Select statement
   void SetFlags(QueryFlags flags);
+  /// returns internally used query flags
   QueryFlags GetFlags() const;
 
+  /// return underlying handle
+  EntityHandle GetEntity() const {return view_set_ ? entity_view_.GetHandle() : entity_handle_;}
+
 private:
   bool view_set_;
   EntityHandle entity_handle_;
-- 
GitLab