Salome HOME
0021375: EDF 1671 SMESH: Dump study of current state
[modules/smesh.git] / src / SMESH_I / SMESH_2smeshpy.cxx
index 2d5ee24f1031f8ead9562b5fccb35c59a7fdc5b8..c8fe9b6abea9ba8dbc92ee6e5c43778a3611ac2a 100644 (file)
 #include "SMESH_Filter_i.hxx"
 
 #include <Resource_DataMapOfAsciiStringAsciiString.hxx>
+#include <Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString.hxx>
 
 #include "SMESH_Gen_i.hxx"
-/* SALOME headers that include CORBA headers that include windows.h 
+/* SALOME headers that include CORBA headers that include windows.h
  * that defines GetObject symbol as GetObjectA should stand before SALOME headers
  * that declare methods named GetObject - to apply the same rules of GetObject renaming
  * and thus to avoid mess with GetObject symbol on Windows */
@@ -112,6 +113,65 @@ namespace {
       return find( name ) != end();
     }
   };
+
+  //================================================================================
+  /*!
+   * \brief Returns a mesh by object
+   */
+  //================================================================================
+
+  Handle(_pyMesh) ObjectToMesh( const Handle( _pyObject )& obj )
+  {
+    if ( !obj.IsNull() )
+    {
+      if ( obj->IsKind( STANDARD_TYPE( _pyMesh )))
+        return Handle(_pyMesh)::DownCast( obj );
+      else if ( obj->IsKind( STANDARD_TYPE( _pySubMesh )))
+        return Handle(_pySubMesh)::DownCast( obj )->GetMesh();
+      else if ( obj->IsKind( STANDARD_TYPE( _pyGroup )))
+        return Handle(_pyGroup)::DownCast( obj )->GetMesh();
+    }
+    return Handle(_pyMesh)();
+  }
+
+  //================================================================================
+  /*!
+   * \brief Check if objects used as args have been created by previous commands
+   */
+  //================================================================================
+
+  void CheckObjectPresence( const Handle(_pyCommand)& cmd, set<_pyID> & presentObjects)
+  {
+    for ( int iArg = cmd->GetNbArgs(); iArg; --iArg )
+    {
+      const _pyID& arg = cmd->GetArg( iArg );
+      if ( arg.IsEmpty() || arg.Value( 1 ) == '"' || arg.Value( 1 ) == '\'' )
+        continue;
+      list< _pyID > idList = cmd->GetStudyEntries( arg );
+      list< _pyID >::iterator id = idList.begin();
+      for ( ; id != idList.end(); ++id )
+        if ( !theGen->IsGeomObject( *id ) && !presentObjects.count( *id ))
+        {
+          cmd->Comment();
+          cmd->GetString() += " ### " ;
+          cmd->GetString() += *id + " has not been yet created";
+          return;
+        }
+    }
+    const _pyID& obj = cmd->GetObject();
+    if ( !obj.IsEmpty() && cmd->IsStudyEntry( obj ) && !presentObjects.count( obj ))
+    {
+      cmd->Comment();
+      cmd->GetString() += " ### not created object" ;
+    }
+    const _pyID& result = cmd->GetResultValue();
+    if ( result.IsEmpty() || result.Value( 1 ) == '"' || result.Value( 1 ) == '\'' )
+      return;
+    list< _pyID > idList = cmd->GetStudyEntries( result );
+    list< _pyID >::iterator id = idList.begin();
+    for ( ; id != idList.end(); ++id )
+      presentObjects.insert( *id );
+  }
 }
 
 //================================================================================
@@ -119,22 +179,26 @@ namespace {
  * \brief Convert python script using commands of smesh.py
   * \param theScript - Input script
   * \retval TCollection_AsciiString - Convertion result
+  * \param theToKeepAllCommands - to keep all commands or
+  *        to exclude commands relating to objects removed from study
   *
   * Class SMESH_2smeshpy declared in SMESH_PythonDump.hxx
  */
 //================================================================================
 
 TCollection_AsciiString
-SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString& theScript,
+SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString&            theScript,
                               Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod,
-                              Resource_DataMapOfAsciiStringAsciiString& theObjectNames)
+                              Resource_DataMapOfAsciiStringAsciiString& theObjectNames,
+                              SALOMEDS::Study_ptr&                      theStudy,
+                              const bool                                theToKeepAllCommands)
 {
-  theGen = new _pyGen( theEntry2AccessorMethod, theObjectNames );
+  theGen = new _pyGen( theEntry2AccessorMethod, theObjectNames, theStudy, theToKeepAllCommands );
 
   // split theScript into separate commands
 
   SMESH_NoteBook * aNoteBook = new SMESH_NoteBook();
-  
+
   int from = 1, end = theScript.Length(), to;
   while ( from < end && ( to = theScript.Location( "\n", from, end )))
   {
@@ -143,13 +207,13 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString& theScript,
         aNoteBook->AddCommand( theScript.SubString( from, to - 1 ));
       from = to + 1;
   }
-  
+
   aNoteBook->ReplaceVariables();
 
   TCollection_AsciiString aNoteScript = aNoteBook->GetResultScript();
   delete aNoteBook;
   aNoteBook = 0;
-  
+
   // split theScript into separate commands
   from = 1, end = aNoteScript.Length();
   while ( from < end && ( to = aNoteScript.Location( "\n", from, end )))
@@ -166,6 +230,9 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString& theScript,
   MESSAGE_BEGIN ( std::endl << " ######## RESULT ######## " << std::endl<< std::endl );
 #endif
 
+  // clean commmands of removed objects depending on myIsPublished flag
+  theGen->ClearCommands();
+
   // reorder commands after conversion
   list< Handle(_pyCommand) >::iterator cmd;
   bool orderChanges;
@@ -175,21 +242,25 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString& theScript,
       if ( (*cmd)->SetDependentCmdsAfter() )
         orderChanges = true;
   } while ( orderChanges );
-  
+
   // concat commands back into a script
-  TCollection_AsciiString aScript;
+  TCollection_AsciiString aScript, aPrevCmd;
+  set<_pyID> createdObjects;
   for ( cmd = theGen->GetCommands().begin(); cmd != theGen->GetCommands().end(); ++cmd )
   {
 #ifdef DUMP_CONVERSION
     MESSAGE_ADD ( "## COM " << (*cmd)->GetOrderNb() << ": "<< (*cmd)->GetString() << std::endl );
 #endif
-    if ( !(*cmd)->IsEmpty() ) {
+    if ( !(*cmd)->IsEmpty() && aPrevCmd != (*cmd)->GetString()) {
+      CheckObjectPresence( *cmd, createdObjects );
+      aPrevCmd = (*cmd)->GetString();
       aScript += "\n";
-      aScript += (*cmd)->GetString();
+      aScript += aPrevCmd;
     }
   }
   aScript += "\n";
 
+  theGen->Free();
   theGen.Nullify();
 
   return aScript;
@@ -202,15 +273,49 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString& theScript,
 //================================================================================
 
 _pyGen::_pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod,
-               Resource_DataMapOfAsciiStringAsciiString& theObjectNames)
-  : _pyObject( new _pyCommand( TPythonDump::SMESHGenName(), 0 )),
+               Resource_DataMapOfAsciiStringAsciiString& theObjectNames,
+               SALOMEDS::Study_ptr&                      theStudy,
+               const bool                                theToKeepAllCommands)
+  : _pyObject( new _pyCommand( "", 0 )),
     myNbCommands( 0 ),
     myID2AccessorMethod( theEntry2AccessorMethod ),
     myObjectNames( theObjectNames ),
-    myNbFilters( 0 )
+    myNbFilters( 0 ),
+    myToKeepAllCommands( theToKeepAllCommands ),
+    myStudy( SALOMEDS::Study::_duplicate( theStudy )),
+    myGeomIDNb(0), myGeomIDIndex(-1)
 {
   // make that GetID() to return TPythonDump::SMESHGenName()
+  GetCreationCmd()->Clear();
+  GetCreationCmd()->GetString() = TPythonDump::SMESHGenName();
   GetCreationCmd()->GetString() += "=";
+
+  // Find 1st digit of study entry by which a GEOM object differs from a SMESH object
+  if ( !theObjectNames.IsEmpty() && !CORBA::is_nil( theStudy ))
+  {
+    // find a GEOM entry
+    _pyID geomID;
+    SALOMEDS::SComponent_var geomComp = theStudy->FindComponent("GEOM");
+    if ( geomComp->_is_nil() ) return;
+    CORBA::String_var entry = geomComp->GetID();
+    geomID = entry.in();
+
+    // find a SMESH entry
+    _pyID smeshID;
+    Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString e2n( theObjectNames );
+    for ( ; e2n.More() && smeshID.IsEmpty(); e2n.Next() )
+      if ( _pyCommand::IsStudyEntry( e2n.Key() ))
+        smeshID = e2n.Key();
+
+    // find 1st difference between smeshID and geomID
+    if ( !geomID.IsEmpty() && !smeshID.IsEmpty() )
+      for ( int i = 1; i <= geomID.Length() && i <= smeshID.Length(); ++i )
+        if ( geomID.Value( i ) != smeshID.Value( i ))
+        {
+          myGeomIDNb = geomID.Value( i );
+          myGeomIDIndex = i;
+        }
+  }
 }
 
 //================================================================================
@@ -241,7 +346,7 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
   MESSAGE ( "## COM " << myNbCommands << ": "<< aCommand->GetString() );
 #endif
 
-  _pyID objID = aCommand->GetObject();
+  const _pyID& objID = aCommand->GetObject();
 
   if ( objID.IsEmpty() )
     return aCommand;
@@ -249,7 +354,8 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
   // Find an object to process theCommand
 
   // SMESH_Gen method?
-  if ( objID == this->GetID() || objID == SMESH_2smeshpy::GenName()) {
+  if ( objID == this->GetID() || objID == SMESH_2smeshpy::GenName())
+  {
     this->Process( aCommand );
     return aCommand;
   }
@@ -258,21 +364,24 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
   map< _pyID, Handle(_pyMesh) >::iterator id_mesh = myMeshes.find( objID );
   if ( id_mesh != myMeshes.end() )
   {
+    //id_mesh->second->AddProcessedCmd( aCommand );
+
     // check for mesh editor object
     if ( aCommand->GetMethod() == "GetMeshEditor" ) { // MeshEditor creation
       _pyID editorID = aCommand->GetResultValue();
       Handle(_pyMeshEditor) editor = new _pyMeshEditor( aCommand );
       myMeshEditors.insert( make_pair( editorID, editor ));
       return aCommand;
-    } 
+    }
     // check for SubMesh objects
     else if ( aCommand->GetMethod() == "GetSubMesh" ) { // SubMesh creation
       _pyID subMeshID = aCommand->GetResultValue();
       Handle(_pySubMesh) subMesh = new _pySubMesh( aCommand );
       myObjects.insert( make_pair( subMeshID, subMesh ));
     }
-    
+
     id_mesh->second->Process( aCommand );
+    id_mesh->second->AddProcessedCmd( aCommand );
     return aCommand;
   }
 
@@ -280,30 +389,68 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
   map< _pyID, Handle(_pyMeshEditor) >::iterator id_editor = myMeshEditors.find( objID );
   if ( id_editor != myMeshEditors.end() )
   {
+    const TCollection_AsciiString& method = aCommand->GetMethod();
+
+    // some commands of SMESH_MeshEditor create meshes and groups
+    _pyID meshID, groups;
+    if ( method.Search("MakeMesh") != -1 )
+      meshID = aCommand->GetResultValue();
+    else if ( method == "MakeBoundaryMesh")
+      meshID = aCommand->GetResultValue(1);
+    else if ( method == "MakeBoundaryElements")
+      meshID = aCommand->GetResultValue(2);
+
+    if ( method.Search("MakeGroups") != -1  ||
+         method == "ExtrusionAlongPathX"    ||
+         method == "ExtrusionAlongPathObjX" ||
+         method == "DoubleNodeGroupNew"     ||
+         method == "DoubleNodeGroupsNew"    ||
+         method == "DoubleNodeElemGroupNew" ||
+         method == "DoubleNodeElemGroupsNew" )
+      groups = aCommand->GetResultValue();
+    else if ( method == "MakeBoundaryMesh" )
+      groups = aCommand->GetResultValue(2);
+    else if ( method == "MakeBoundaryElements")
+      groups = aCommand->GetResultValue(3);
+
     id_editor->second->Process( aCommand );
-    TCollection_AsciiString processedCommand = aCommand->GetString();
-    // some commands of SMESH_MeshEditor create meshes
-    if ( aCommand->GetMethod().Search("MakeMesh") != -1 ) {
-      Handle(_pyMesh) mesh = new _pyMesh( aCommand, aCommand->GetResultValue() );
+    id_editor->second->AddProcessedCmd( aCommand );
+
+    if ( !meshID.IsEmpty() &&
+         !myMeshes.count( meshID ) &&
+         aCommand->IsStudyEntry( meshID ))
+    {
+      TCollection_AsciiString processedCommand = aCommand->GetString();
+      Handle(_pyMesh) mesh = new _pyMesh( aCommand, meshID );
+      myMeshes.insert( make_pair( meshID, mesh ));
+      aCommand->Clear();
       aCommand->GetString() = processedCommand; // discard changes made by _pyMesh
-      myMeshes.insert( make_pair( mesh->GetID(), mesh ));
     }
-    if ( aCommand->GetMethod() == "MakeBoundaryMesh") {
-      _pyID meshID = aCommand->GetResultValue(0);
-      if ( !myMeshes.count( meshID ) )
-      {
-        Handle(_pyMesh) mesh = new _pyMesh( aCommand, meshID );
-        aCommand->GetString() = processedCommand; // discard changes made by _pyMesh
-        myMeshes.insert( make_pair( meshID, mesh ));
-      }
+    if ( !groups.IsEmpty() )
+    {
+      if ( !aCommand->IsStudyEntry( meshID ))
+        meshID = id_editor->second->GetMesh();
+      Handle(_pyMesh) mesh = myMeshes[ meshID ];
+
+      list< _pyID > idList = aCommand->GetStudyEntries( groups );
+      list< _pyID >::iterator grID = idList.begin();
+      for ( ; grID != idList.end(); ++grID )
+        if ( !myObjects.count( *grID ))
+        {
+          Handle(_pyGroup) group = new _pyGroup( aCommand, *grID );
+          AddObject( group );
+          if ( !mesh.IsNull() ) mesh->AddGroup( group );
+        }
     }
     return aCommand;
-  }
+  } // SMESH_MeshEditor methods
+
   // SMESH_Hypothesis method?
   list< Handle(_pyHypothesis) >::iterator hyp = myHypos.begin();
   for ( ; hyp != myHypos.end(); ++hyp )
     if ( !(*hyp)->IsAlgo() && objID == (*hyp)->GetID() ) {
       (*hyp)->Process( aCommand );
+      (*hyp)->AddProcessedCmd( aCommand );
       return aCommand;
     }
 
@@ -325,6 +472,7 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
   map< _pyID, Handle(_pyObject) >::iterator id_obj = myObjects.find( objID );
   if ( id_obj != myObjects.end() ) {
     id_obj->second->Process( aCommand );
+    id_obj->second->AddProcessedCmd( aCommand );
     return aCommand;
   }
 
@@ -389,13 +537,16 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
       // set SMESH.GeometryType instead of a numerical Threshold
       const char* types[SMESH::Geom_POLYHEDRA+1] = {
         "Geom_POINT", "Geom_EDGE", "Geom_TRIANGLE", "Geom_QUADRANGLE", "Geom_POLYGON",
-        "Geom_TETRA", "Geom_PYRAMID", "Geom_HEXA", "Geom_PENTA", "Geom_POLYHEDRA"
+        "Geom_TETRA", "Geom_PYRAMID", "Geom_HEXA", "Geom_PENTA", "Geom_HEXAGONAL_PRISM",
+        "Geom_POLYHEDRA"
       };
       int iGeom = Threshold.IntegerValue();
       if ( -1 < iGeom && iGeom < SMESH::Geom_POLYHEDRA+1 )
         Threshold = SMESH + types[ iGeom ];
     }
-    if ( ThresholdStr.Length() != 2 ) // not '' or ""
+    if ( ThresholdID.Length() != 2 && ThresholdStr.Length() != 2) // not '' or ""
+      aCommand->SetArg( 4, ThresholdID.SubString( 2, ThresholdID.Length()-1 )); // shape entry
+    else if ( ThresholdStr.Length() != 2 )
       aCommand->SetArg( 4, ThresholdStr );
     else if ( ThresholdID.Length() != 2 )
       aCommand->SetArg( 4, ThresholdID );
@@ -461,8 +612,10 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
   {
     for(int ind = 0;ind<theCommand->GetNbResultValues();ind++)
     {
-      Handle(_pyMesh) mesh = new _pyMesh( theCommand, theCommand->GetResultValue(ind));
-      myMeshes.insert( make_pair( theCommand->GetResultValue(ind), mesh ));
+      const _pyID& meshID = theCommand->GetResultValue(ind+1);
+      if ( !theCommand->IsStudyEntry( meshID ) ) continue;
+      Handle(_pyMesh) mesh = new _pyMesh( theCommand, theCommand->GetResultValue(ind+1));
+      myMeshes.insert( make_pair( mesh->GetID(), mesh ));
     }
   }
 
@@ -490,7 +643,8 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
     if ( id_mesh != myMeshes.end() ) {
       theCommand->SetObject( meshID );
       theCommand->RemoveArgs();
-      id_mesh->second->Flush();
+      id_mesh->second->Process( theCommand );
+      id_mesh->second->AddProcessedCmd( theCommand );
       return;
     }
   }
@@ -505,6 +659,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
       _pyID geom = theCommand->GetArg( 2 );
       theCommand->RemoveArgs();
       theCommand->SetArg( 1, geom );
+      id_mesh->second->AddProcessedCmd( theCommand );
       return;
     }
   }
@@ -518,9 +673,8 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
     if ( !myObjects.insert( make_pair( obj->GetID(), obj )).second )
       theCommand->Clear(); // already created
   }
-
   // Concatenate( [mesh1, ...], ... )
-  if ( method == "Concatenate" || method == "ConcatenateWithGroups")
+  else if ( method == "Concatenate" || method == "ConcatenateWithGroups")
   {
     if ( method == "ConcatenateWithGroups" ) {
       theCommand->SetMethod( "Concatenate" );
@@ -530,6 +684,14 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
     myMeshes.insert( make_pair( mesh->GetID(), mesh ));
     AddMeshAccessorMethod( theCommand );
   }
+  else if ( method == "SetName" ) // SetName(obj,name)
+  {
+    // store theCommand as one of object commands to erase it along with the object
+    const _pyID& objID = theCommand->GetArg( 1 );
+    Handle(_pyObject) obj = FindObject( objID );
+    if ( !obj.IsNull() )
+      obj->AddProcessedCmd( theCommand );
+  }
 
   // Replace name of SMESH_Gen
 
@@ -558,16 +720,36 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
 
 void _pyGen::Flush()
 {
-  // create empty command
+  // create an empty command
   myLastCommand = new _pyCommand();
 
-  map< _pyID, Handle(_pyMesh) >::iterator id_mesh = myMeshes.begin();
-  for ( ; id_mesh != myMeshes.end(); ++id_mesh )
+  map< _pyID, Handle(_pyMesh) >::iterator id_mesh;
+  map< _pyID, Handle(_pyObject) >::iterator id_obj;
+  list< Handle(_pyHypothesis) >::iterator hyp;
+
+  if ( IsToKeepAllCommands() ) // historical dump
+  {
+    // set myIsPublished = true to all objects
+    for ( id_mesh = myMeshes.begin(); id_mesh != myMeshes.end(); ++id_mesh )
+      id_mesh->second->SetRemovedFromStudy( false );
+    for ( hyp = myHypos.begin(); hyp != myHypos.end(); ++hyp )
+      (*hyp)->SetRemovedFromStudy( false );
+    for ( id_obj = myObjects.begin(); id_obj != myObjects.end(); ++id_obj )
+      id_obj->second->SetRemovedFromStudy( false );
+  }
+  // set myIsPublished = false to all objects depending on
+  // meshes built on a removed geometry
+  for ( id_mesh = myMeshes.begin(); id_mesh != myMeshes.end(); ++id_mesh )
+    if ( id_mesh->second->IsNotGeomPublished() )
+      id_mesh->second->SetRemovedFromStudy( true );
+
+  // Flush meshes
+  for ( id_mesh = myMeshes.begin(); id_mesh != myMeshes.end(); ++id_mesh )
     if ( ! id_mesh->second.IsNull() )
       id_mesh->second->Flush();
 
-  list< Handle(_pyHypothesis) >::iterator hyp = myHypos.begin();
-  for ( ; hyp != myHypos.end(); ++hyp )
+  // Flush hyps
+  for ( hyp = myHypos.begin(); hyp != myHypos.end(); ++hyp )
     if ( !hyp->IsNull() ) {
       (*hyp)->Flush();
       // smeshgen.CreateHypothesis() --> smesh.smesh.CreateHypothesis()
@@ -575,8 +757,8 @@ void _pyGen::Flush()
         (*hyp)->GetCreationCmd()->SetObject( SMESH_2smeshpy::GenName() );
     }
 
-  map< _pyID, Handle(_pyObject) >::iterator id_obj = myObjects.begin();
-  for ( ; id_obj != myObjects.end(); ++id_obj )
+  // Flush other objects
+  for ( id_obj = myObjects.begin(); id_obj != myObjects.end(); ++id_obj )
     if ( ! id_obj->second.IsNull() )
       id_obj->second->Flush();
 
@@ -584,6 +766,60 @@ void _pyGen::Flush()
   myCommands.push_back( myLastCommand );
 }
 
+//================================================================================
+/*!
+ * \brief Clean commmands of removed objects depending on myIsPublished flag
+ */
+//================================================================================
+
+void _pyGen::ClearCommands()
+{
+  map< _pyID, Handle(_pyMesh) >::iterator id_mesh = myMeshes.begin();
+  for ( ; id_mesh != myMeshes.end(); ++id_mesh )
+    id_mesh->second->ClearCommands();
+
+  list< Handle(_pyHypothesis) >::iterator hyp = myHypos.begin();
+  for ( ; hyp != myHypos.end(); ++hyp )
+    if ( !hyp->IsNull() )
+      (*hyp)->ClearCommands();
+
+  map< _pyID, Handle(_pyObject) >::iterator id_obj = myObjects.begin();
+  for ( ; id_obj != myObjects.end(); ++id_obj )
+    id_obj->second->ClearCommands();
+}
+
+//================================================================================
+/*!
+ * \brief Release mutual handles of objects
+ */
+//================================================================================
+
+void _pyGen::Free()
+{
+  map< _pyID, Handle(_pyMesh) >::iterator id_mesh = myMeshes.begin();
+  for ( ; id_mesh != myMeshes.end(); ++id_mesh )
+    id_mesh->second->Free();
+  myMeshes.clear();
+
+  map< _pyID, Handle(_pyMeshEditor) >::iterator id_ed = myMeshEditors.begin();
+  for ( ; id_ed != myMeshEditors.end(); ++id_ed )
+    id_ed->second->Free();
+  myMeshEditors.clear();
+
+  map< _pyID, Handle(_pyObject) >::iterator id_obj = myObjects.begin();
+  for ( ; id_obj != myObjects.end(); ++id_obj )
+    id_obj->second->Free();
+  myObjects.clear();
+
+  list< Handle(_pyHypothesis) >::iterator hyp = myHypos.begin();
+  for ( ; hyp != myHypos.end(); ++hyp )
+    if ( !hyp->IsNull() )
+      (*hyp)->Free();
+  myHypos.clear();
+
+  myFile2ExportedMesh.clear();
+}
+
 //================================================================================
 /*!
  * \brief Add access method to mesh that is an argument
@@ -810,7 +1046,16 @@ _pyID _pyGen::GenerateNewID( const _pyID& theID )
 
 void _pyGen::AddObject( Handle(_pyObject)& theObj )
 {
-  myObjects.insert( make_pair( theObj->GetID(), theObj ));
+  if ( theObj.IsNull() ) return;
+
+  if ( theObj->IsKind( STANDARD_TYPE( _pyMesh )))
+    myMeshes.insert( make_pair( theObj->GetID(), Handle(_pyMesh)::DownCast( theObj )));
+
+  else if ( theObj->IsKind( STANDARD_TYPE( _pyMeshEditor )))
+    myMeshEditors.insert( make_pair( theObj->GetID(), Handle(_pyMeshEditor)::DownCast( theObj )));
+
+  else
+    myObjects.insert( make_pair( theObj->GetID(), theObj ));
 }
 
 //================================================================================
@@ -821,106 +1066,139 @@ void _pyGen::AddObject( Handle(_pyObject)& theObj )
 
 Handle(_pyObject) _pyGen::FindObject( const _pyID& theObjID )  const
 {
-  std::map< _pyID, Handle(_pyObject) >::const_iterator id_obj = myObjects.find( theObjID );
-  return ( id_obj == myObjects.end() ) ? Handle(_pyObject)() : id_obj->second;
+  {
+    map< _pyID, Handle(_pyObject) >::const_iterator id_obj = myObjects.find( theObjID );
+    if ( id_obj != myObjects.end() )
+      return id_obj->second;
+  }
+  {
+    map< _pyID, Handle(_pyMesh) >::const_iterator id_obj = myMeshes.find( theObjID );
+    if ( id_obj != myMeshes.end() )
+      return id_obj->second;
+  }
+  // {
+  //   map< _pyID, Handle(_pyMeshEditor) >::const_iterator id_obj = myMeshEditors.find( theObjID );
+  //   if ( id_obj != myMeshEditors.end() )
+  //     return id_obj->second;
+  // }
+  return Handle(_pyObject)();
 }
-  
+
 //================================================================================
 /*!
- * \brief Find out type of geom group
-  * \param grpID - The geom group entry
-  * \retval int - The type
+ * \brief Check if a study entry is under GEOM component
  */
 //================================================================================
 
-// static bool sameGroupType( const _pyID&                   grpID,
-//                            const TCollection_AsciiString& theType)
-// {
-//   // define group type as smesh.Mesh.Group() does
-//   int type = -1;
-//   SALOMEDS::Study_var study = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy();
-//   SALOMEDS::SObject_var aSObj = study->FindObjectID( grpID.ToCString() );
-//   if ( !aSObj->_is_nil() ) {
-//     GEOM::GEOM_Object_var aGeomObj = GEOM::GEOM_Object::_narrow( aSObj->GetObject() );
-//     if ( !aGeomObj->_is_nil() ) {
-//       switch ( aGeomObj->GetShapeType() ) {
-//       case GEOM::VERTEX: type = SMESH::NODE; break;
-//       case GEOM::EDGE:   type = SMESH::EDGE; break;
-//       case GEOM::FACE:   type = SMESH::FACE; break;
-//       case GEOM::SOLID:
-//       case GEOM::SHELL:  type = SMESH::VOLUME; break;
-//       case GEOM::COMPOUND: {
-//         GEOM::GEOM_Gen_ptr aGeomGen = SMESH_Gen_i::GetSMESHGen()->GetGeomEngine();
-//         if ( !aGeomGen->_is_nil() ) {
-//           GEOM::GEOM_IGroupOperations_var aGrpOp =
-//             aGeomGen->GetIGroupOperations( study->StudyId() );
-//           if ( !aGrpOp->_is_nil() ) {
-//             switch ( aGrpOp->GetType( aGeomObj )) {
-//             case TopAbs_VERTEX: type = SMESH::NODE; break;
-//             case TopAbs_EDGE:   type = SMESH::EDGE; break;
-//             case TopAbs_FACE:   type = SMESH::FACE; break;
-//             case TopAbs_SOLID:  type = SMESH::VOLUME; break;
-//             default:;
-//             }
-//           }
-//         }
-//       }
-//       default:;
-//       }
-//     }
-//   }
-//   if ( type < 0 ) {
-//     MESSAGE("Type of the group " << grpID << " not found");
-//     return false;
-//   }
-//   if ( theType.IsIntegerValue() )
-//     return type == theType.IntegerValue();
-
-//   switch ( type ) {
-//   case SMESH::NODE:   return theType.Location( "NODE", 1, theType.Length() );
-//   case SMESH::EDGE:   return theType.Location( "EDGE", 1, theType.Length() );
-//   case SMESH::FACE:   return theType.Location( "FACE", 1, theType.Length() );
-//   case SMESH::VOLUME: return theType.Location( "VOLUME", 1, theType.Length() );
-//   default:;
-//   }
-//   return false;
-// }
+bool _pyGen::IsGeomObject(const _pyID& theObjID) const
+{
+  if ( myGeomIDNb )
+  {
+    return ( myGeomIDIndex <= theObjID.Length() &&
+             int( theObjID.Value( myGeomIDIndex )) == myGeomIDNb);
+  }
+  return false;
+}
 
 //================================================================================
 /*!
- * \brief
-  * \param theCreationCmd -
+ * \brief Returns true if an object is not present in a study
+ */
+//================================================================================
+
+bool _pyGen::IsNotPublished(const _pyID& theObjID) const
+{
+  if ( theObjID.IsEmpty() ) return false;
+
+  if ( myObjectNames.IsBound( theObjID ))
+    return false; // SMESH object is in study
+
+  // either the SMESH object is not in study or it is a GEOM object
+  if ( IsGeomObject( theObjID ))
+  {
+    SALOMEDS::SObject_var so = myStudy->FindObjectID( theObjID.ToCString() );
+    if ( so->_is_nil() ) return true;
+    CORBA::Object_var obj = so->GetObject();
+    return CORBA::is_nil( obj );
+  }
+  return true; // SMESH object not in study
+}
+
+//================================================================================
+/*!
+ * \brief Mesh created by SMESH_Gen
  */
 //================================================================================
 
 _pyMesh::_pyMesh(const Handle(_pyCommand) theCreationCmd)
-  : _pyObject(theCreationCmd), myHasEditor(false)
+  : _pyObject( theCreationCmd ), myGeomNotInStudy( false )
 {
-  // convert my creation command
+  if ( theCreationCmd->GetMethod() == "CreateMesh" && theGen->IsNotPublished( GetGeom() ))
+    myGeomNotInStudy = true;
+
+  // convert my creation command --> smeshpy.Mesh(...)
   Handle(_pyCommand) creationCmd = GetCreationCmd();
-  //TCollection_AsciiString str = creationCmd->GetMethod();
-//   if(str != "CreateMeshesFromUNV" &&
-//      str != "CreateMeshesFromMED" &&
-//      str != "CreateMeshesFromSTL")
   creationCmd->SetObject( SMESH_2smeshpy::SmeshpyName() );
   creationCmd->SetMethod( "Mesh" );
-
-  theGen->SetAccessorMethod( GetID(), "GetMesh()" );
+  theGen->SetAccessorMethod( GetID(), _pyMesh::AccessorMethod() );
 }
 
 //================================================================================
 /*!
- * \brief
-  * \param theCreationCmd -
+ * \brief Mesh created by SMESH_MeshEditor
  */
 //================================================================================
-_pyMesh::_pyMesh(const Handle(_pyCommand) theCreationCmd, const TCollection_AsciiString& id):
-  _pyObject(theCreationCmd), myHasEditor(false)
+
+_pyMesh::_pyMesh(const Handle(_pyCommand) theCreationCmd, const _pyID& meshId):
+  _pyObject(theCreationCmd,meshId), myGeomNotInStudy(false )
 {
+  if ( theCreationCmd->MethodStartsFrom( "CreateMeshesFrom" ))
+  {
+    // this mesh depends on the exported mesh
+    const TCollection_AsciiString& file = theCreationCmd->GetArg( 1 );
+    if ( !file.IsEmpty() )
+    {
+      ExportedMeshData& exportData = theGen->FindExportedMesh( file );
+      addFatherMesh( exportData.myMesh );
+      if ( !exportData.myLastComputeCmd.IsNull() )
+      {
+        // restore cleared Compute() by which the exported mesh was generated
+        exportData.myLastComputeCmd->GetString() = exportData.myLastComputeCmdString;
+        // protect that Compute() cmd from clearing
+        if ( exportData.myMesh->myLastComputeCmd == exportData.myLastComputeCmd )
+          exportData.myMesh->myLastComputeCmd.Nullify();
+      }
+    }
+  }
+  else if ( theCreationCmd->MethodStartsFrom( "Concatenate" ))
+  {
+    // this mesh depends on concatenated meshes
+    const TCollection_AsciiString& meshIDs = theCreationCmd->GetArg( 1 );
+    list< _pyID > idList = theCreationCmd->GetStudyEntries( meshIDs );
+    list< _pyID >::iterator meshID = idList.begin();
+    for ( ; meshID != idList.end(); ++meshID )
+      addFatherMesh( *meshID );
+  }
+  else if ( theCreationCmd->GetMethod() == "CopyMesh" )
+  {
+    // this mesh depends on a copied IdSource
+    const _pyID& objID = theCreationCmd->GetArg( 1 );
+    addFatherMesh( objID );
+  }
+  else if ( theCreationCmd->GetMethod().Search("MakeMesh") != -1 ||
+            theCreationCmd->GetMethod() == "MakeBoundaryMesh" ||
+            theCreationCmd->GetMethod() == "MakeBoundaryElements" )
+  {
+    // this mesh depends on a source mesh
+    // (theCreationCmd is already Process()ed by _pyMeshEditor)
+    const _pyID& meshID = theCreationCmd->GetObject();
+    addFatherMesh( meshID );
+  }
+    
   // convert my creation command
   Handle(_pyCommand) creationCmd = GetCreationCmd();
   creationCmd->SetObject( SMESH_2smeshpy::SmeshpyName() );
-  theGen->SetAccessorMethod( id, "GetMesh()" );
+  theGen->SetAccessorMethod( meshId, _pyMesh::AccessorMethod() );
 }
 
 //================================================================================
@@ -945,15 +1223,75 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
   //     --> in Mesh.ExportMED( f, auto_groups, version )
   // 5. etc
 
-  const TCollection_AsciiString method = theCommand->GetMethod();
+  const TCollection_AsciiString& method = theCommand->GetMethod();
   // ----------------------------------------------------------------------
-  if ( method == "GetSubMesh" ) { // collect submeshes of the mesh
+  if ( method == "Compute" ) // in snapshot mode, clear the previous Compute()
+  {
+    if ( !theGen->IsToKeepAllCommands() ) // !historical
+    {
+      list< Handle(_pyHypothesis) >::iterator hyp;
+      if ( !myLastComputeCmd.IsNull() )
+      {
+        for ( hyp = myHypos.begin(); hyp != myHypos.end(); ++hyp )
+          (*hyp)->ComputeDiscarded( myLastComputeCmd );
+
+        myLastComputeCmd->Clear();
+      }
+      myLastComputeCmd = theCommand;
+
+      for ( hyp = myHypos.begin(); hyp != myHypos.end(); ++hyp )
+        (*hyp)->MeshComputed( myLastComputeCmd );
+    }
+    Flush();
+  }
+  // ----------------------------------------------------------------------
+  else if ( method == "Clear" ) // in snapshot mode, clear all previous commands
+  {
+    if ( !theGen->IsToKeepAllCommands() ) // !historical
+    {
+      int untilCmdNb =
+        myChildMeshes.empty() ? 0 : myChildMeshes.back()->GetCreationCmd()->GetOrderNb();
+      // list< Handle(_pyCommand) >::reverse_iterator cmd = myProcessedCmds.rbegin();
+      // for ( ; cmd != myProcessedCmds.rend() && (*cmd)->GetOrderNb() > untilCmdNb; ++cmd )
+      //   (*cmd)->Clear();
+      if ( !myLastComputeCmd.IsNull() )
+      {
+        list< Handle(_pyHypothesis) >::iterator hyp;
+        for ( hyp = myHypos.begin(); hyp != myHypos.end(); ++hyp )
+          (*hyp)->ComputeDiscarded( myLastComputeCmd );
+
+        myLastComputeCmd->Clear();
+      }
+
+      list< Handle(_pyMeshEditor)>::iterator e = myEditors.begin();
+      for ( ; e != myEditors.end(); ++e )
+      {
+        list< Handle(_pyCommand)>& cmds = (*e)->GetProcessedCmds();
+        list< Handle(_pyCommand) >::reverse_iterator cmd = cmds.rbegin();
+        for ( ; cmd != cmds.rend() && (*cmd)->GetOrderNb() > untilCmdNb; ++cmd )
+          if ( !(*cmd)->IsEmpty() )
+          {
+            if ( (*cmd)->GetStudyEntries( (*cmd)->GetResultValue() ).empty() ) // no object created
+              (*cmd)->Clear();
+          }
+      }
+      myLastComputeCmd = theCommand; // to clear Clear() the same way as Compute()
+    }
+  }
+  // ----------------------------------------------------------------------
+  else if ( method == "GetSubMesh" ) { // collect submeshes of the mesh
     Handle(_pySubMesh) subMesh = theGen->FindSubMesh( theCommand->GetResultValue() );
     if ( !subMesh.IsNull() ) {
       subMesh->SetCreator( this );
       mySubmeshes.push_back( subMesh );
     }
   }
+  else if ( method == "RemoveSubMesh" ) { // move submesh creation before its removal
+    Handle(_pySubMesh) subMesh = theGen->FindSubMesh( theCommand->GetArg(1) );
+    if ( !subMesh.IsNull() )
+      subMesh->Process( theCommand );
+    AddMeshAccess( theCommand );
+  }
   // ----------------------------------------------------------------------
   else if ( method == "AddHypothesis" ) { // mesh.AddHypothesis(geom, HYPO )
     myAddHypCmds.push_back( theCommand );
@@ -967,6 +1305,14 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
     }
   }
   // ----------------------------------------------------------------------
+  else if ( method == "CreateGroup" ) // CreateGroup() --> CreateEmptyGroup()
+  {
+    theCommand->SetMethod( "CreateEmptyGroup" );
+    Handle(_pyGroup) group = new _pyGroup( theCommand );
+    myGroups.push_back( group );
+    theGen->AddObject( group );
+  }
+  // ----------------------------------------------------------------------
   else if ( method == "CreateGroupFromGEOM" ) {// (type, name, grp)
     _pyID grp = theCommand->GetArg( 3 );
     // VSR 24/12/2010. PAL21106: always use GroupOnGeom() function on dump
@@ -986,64 +1332,59 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
       theCommand->SetArg( 2, name );
       theCommand->SetArg( 3, type );
     //}
+    Handle(_pyGroup) group = new _pyGroup( theCommand );
+    myGroups.push_back( group );
+    theGen->AddObject( group );
   }
   // ----------------------------------------------------------------------
   else if ( method == "CreateGroupFromFilter" ) // --> GroupOnFilter()
   {
     theCommand->SetMethod( "GroupOnFilter" );
     Handle(_pyGroup) group = new _pyGroup( theCommand );
+    myGroups.push_back( group );
     theGen->AddObject( group );
 
     // GroupOnFilter(typ, name, aFilter0x4743dc0 -> aFilter_1)
     _pyID filterID = theCommand->GetArg(3);
-    Handle(_pyObject) filter = theGen->FindObject( filterID );
-    if ( !filter.IsNull() && filter->IsKind(STANDARD_TYPE(_pyFilter)))
-      filter->Process( theCommand );
-  }
-  // ----------------------------------------------------------------------
-  else if ( method == "GetIdsFromFilter" )
-  {
-    // GetIdsFromFilter( aFilter0x4743dc0) -> GetIdsFromFilter( aFilter_1)
-    _pyID filterID = theCommand->GetArg(1);
-    Handle(_pyObject) filter = theGen->FindObject( filterID );
-    if ( !filter.IsNull() && filter->IsKind(STANDARD_TYPE(_pyFilter)))
+    Handle(_pyFilter) filter = Handle(_pyFilter)::DownCast( theGen->FindObject( filterID ));
+    if ( !filter.IsNull())
+    {
       filter->Process( theCommand );
+      filter->AddUser( group );
+    }
   }
   // ----------------------------------------------------------------------
-  else if ( method == "CreateGroup" ) // CreateGroup() --> CreateEmptyGroup()
+  else if ( theCommand->MethodStartsFrom( "Export" ))
   {
-    theCommand->SetMethod( "CreateEmptyGroup" );
-    Handle(_pyGroup) group = new _pyGroup( theCommand );
-    theGen->AddObject( group );
-  }
-  // ----------------------------------------------------------------------
-  else if ( method == "ExportToMED" ||   // ExportToMED()  --> ExportMED()
-            method == "ExportToMEDX" ) { // ExportToMEDX() --> ExportMED()
-    theCommand->SetMethod( "ExportMED" );
-  }
-  // ----------------------------------------------------------------------
-  else if ( method == "ExportCGNS" )
-  { // ExportCGNS(part, ...) -> ExportCGNS(..., part)
-    _pyID partID = theCommand->GetArg( 1 );
-    int nbArgs = theCommand->GetNbArgs();
-    for ( int i = 2; i <= nbArgs; ++i )
-      theCommand->SetArg( i-1, theCommand->GetArg( i ));
-    theCommand->SetArg( nbArgs, partID );
-  }
-  // ----------------------------------------------------------------------
-  else if ( method.Location( "ExportPartTo", 1, method.Length() ) == 1 )
-  { // ExportPartTo*(part, ...) -> Export*(..., part)
-    //
-    // remove "PartTo" from the method
-    TCollection_AsciiString newMethod = method;
-    newMethod.Remove( 7, 6 );
-    theCommand->SetMethod( newMethod );
-    // make the 1st arg be the last one
-    _pyID partID = theCommand->GetArg( 1 );
-    int nbArgs = theCommand->GetNbArgs();
-    for ( int i = 2; i <= nbArgs; ++i )
-      theCommand->SetArg( i-1, theCommand->GetArg( i ));
-    theCommand->SetArg( nbArgs, partID );
+    if ( method == "ExportToMED" ||   // ExportToMED()  --> ExportMED()
+         method == "ExportToMEDX" ) { // ExportToMEDX() --> ExportMED()
+      theCommand->SetMethod( "ExportMED" );
+    }
+    else if ( method == "ExportCGNS" )
+    { // ExportCGNS(part, ...) -> ExportCGNS(..., part)
+      _pyID partID = theCommand->GetArg( 1 );
+      int nbArgs = theCommand->GetNbArgs();
+      for ( int i = 2; i <= nbArgs; ++i )
+        theCommand->SetArg( i-1, theCommand->GetArg( i ));
+      theCommand->SetArg( nbArgs, partID );
+    }
+    else if ( theCommand->MethodStartsFrom( "ExportPartTo" ))
+    { // ExportPartTo*(part, ...) -> Export*(..., part)
+      //
+      // remove "PartTo" from the method
+      TCollection_AsciiString newMethod = method;
+      newMethod.Remove( 7, 6 );
+      theCommand->SetMethod( newMethod );
+      // make the 1st arg be the last one
+      _pyID partID = theCommand->GetArg( 1 );
+      int nbArgs = theCommand->GetNbArgs();
+      for ( int i = 2; i <= nbArgs; ++i )
+        theCommand->SetArg( i-1, theCommand->GetArg( i ));
+      theCommand->SetArg( nbArgs, partID );
+    }
+    // remember file name
+    theGen->AddExportedMesh( theCommand->GetArg( 1 ),
+                             ExportedMeshData( this, myLastComputeCmd ));
   }
   // ----------------------------------------------------------------------
   else if ( method == "RemoveHypothesis" ) // (geom, hyp)
@@ -1079,25 +1420,36 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
     myHypos.remove( hyp );
   }
   // check for SubMesh order commands
-  else if ( theCommand->GetMethod() == "GetMeshOrder" ||
-            theCommand->GetMethod() == "SetMeshOrder" )
+  else if ( method == "GetMeshOrder" || method == "SetMeshOrder" )
   {
     // make commands GetSubMesh() returning sub-meshes be before using sub-meshes
     // by GetMeshOrder() and SetMeshOrder(), since by defalut GetSubMesh()
     // commands are moved at the end of the script
-    const bool isArg = theCommand->GetMethod() == "SetMeshOrder";
-    const TCollection_AsciiString& cmdStr = theCommand->GetString();
-    int begPos = (/*isArg ? cmdStr.Search( "(" ) :*/ cmdStr.Search( "[" )) + 1;
-    int endPos = (isArg ? cmdStr.Search( ")" ) : cmdStr.Search( "=" )) - 1;
-    if ( begPos != -1 && begPos < endPos && endPos <= cmdStr.Length() ) {
-      TCollection_AsciiString aSubStr = cmdStr.SubString( begPos, endPos );
-      Standard_Integer index = 1;
-      TCollection_AsciiString anIDStr = aSubStr.Token("\t ,[]", index++);
-      while ( !anIDStr.IsEmpty() ) {
-        Handle(_pySubMesh) subMesh = theGen->FindSubMesh( anIDStr );
-        if ( !subMesh.IsNull() )
-          subMesh->Process( theCommand ); // it moves GetSubMesh() before theCommand
-        anIDStr = aSubStr.Token("\t ,[]", index++);
+    TCollection_AsciiString subIDs =
+      ( method == "SetMeshOrder" ) ? theCommand->GetArg(1) : theCommand->GetResultValue();
+    list< _pyID > idList = theCommand->GetStudyEntries( subIDs );
+    list< _pyID >::iterator subID = idList.begin();
+    for ( ; subID != idList.end(); ++subID )
+    {
+      Handle(_pySubMesh) subMesh = theGen->FindSubMesh( *subID );
+      if ( !subMesh.IsNull() )
+        subMesh->Process( theCommand ); // it moves GetSubMesh() before theCommand
+    }
+  }
+  // update list of groups
+  else if ( method == "GetGroups" )
+  {
+    TCollection_AsciiString grIDs = theCommand->GetResultValue();
+    list< _pyID > idList = theCommand->GetStudyEntries( grIDs );
+    list< _pyID >::iterator grID = idList.begin();
+    for ( ; grID != idList.end(); ++grID )
+    {
+      Handle(_pyObject) obj = theGen->FindObject( *grID );
+      if ( obj.IsNull() )
+      {
+        Handle(_pyGroup) group = new _pyGroup( theCommand, *grID );
+        theGen->AddObject( group );
+        myGroups.push_back( group );
       }
     }
   }
@@ -1151,6 +1503,23 @@ bool _pyMesh::NeedMeshAccess( const Handle(_pyCommand)& theCommand )
 
 void _pyMesh::Flush()
 {
+  {
+    // get the meshes this mesh depends on via hypotheses
+    list< Handle(_pyMesh) > fatherMeshes;
+    list< Handle(_pyHypothesis) >::iterator hyp = myHypos.begin();
+    for ( ; hyp != myHypos.end(); ++hyp )
+      if ( ! (*hyp)->GetReferredMeshesAndGeom( fatherMeshes ))
+        myGeomNotInStudy = true;
+
+    list< Handle(_pyMesh) >::iterator m = fatherMeshes.begin();
+    for ( ; m != fatherMeshes.end(); ++m )
+      addFatherMesh( *m );
+    // if ( removedGeom )
+    //     SetRemovedFromStudy(); // as reffered geometry not in study
+  }
+  if ( myGeomNotInStudy )
+    return;
+
   list < Handle(_pyCommand) >::iterator cmd;
 
   // try to convert algo addition like this:
@@ -1167,7 +1536,7 @@ void _pyMesh::Flush()
     // check and create new algorithm instance if it is already wrapped
     if ( algo->IsWrapped() ) {
       _pyID localAlgoID = theGen->GenerateNewID( algoID );
-      TCollection_AsciiString aNewCmdStr = localAlgoID +
+      TCollection_AsciiString aNewCmdStr = addCmd->GetIndentation() + localAlgoID +
         TCollection_AsciiString( " = " ) + theGen->GetID() +
         TCollection_AsciiString( ".CreateHypothesis( \"" ) + algo->GetAlgoType() +
         TCollection_AsciiString( "\" )" );
@@ -1180,6 +1549,10 @@ void _pyMesh::Flush()
         algo = newAlgo;
         // set algorithm creation
         theGen->SetCommandBefore( newCmd, addCmd );
+        myHypos.push_back( newAlgo );
+        if ( !myLastComputeCmd.IsNull() &&
+             newCmd->GetOrderNb() == myLastComputeCmd->GetOrderNb() + 1)
+          newAlgo->MeshComputed( myLastComputeCmd );
       }
       else
         newCmd->Clear();
@@ -1190,7 +1563,7 @@ void _pyMesh::Flush()
     // try to convert
     if ( algo->Addition2Creation( addCmd, this->GetID() )) // OK
     {
-      // wrapped algo is created atfer mesh creation
+      // wrapped algo is created after mesh creation
       GetCreationCmd()->AddDependantCmd( addCmd );
 
       if ( isLocalAlgo ) {
@@ -1240,21 +1613,126 @@ void _pyMesh::Flush()
     }
   }
 
-  // sm = mesh.GetSubMesh(geom, name) --> sm = mesh.GetMesh().GetSubMesh(geom, name)
-//   for ( cmd = mySubmeshes.begin(); cmd != mySubmeshes.end(); ++cmd ) {
-//     Handle(_pyCommand) subCmd = *cmd;
-//     if ( subCmd->GetNbArgs() > 0 )
-//       AddMeshAccess( subCmd );
-//   }
   myAddHypCmds.clear();
   mySubmeshes.clear();
 
   // flush hypotheses
   list< Handle(_pyHypothesis) >::iterator hyp = myHypos.begin();
-  for ( ; hyp != myHypos.end(); ++hyp )
+  for ( hyp = myHypos.begin(); hyp != myHypos.end(); ++hyp )
     (*hyp)->Flush();
 }
 
+//================================================================================
+/*!
+ * \brief Sets myIsPublished of me and of all objects depending on me.
+ */
+//================================================================================
+
+void _pyMesh::SetRemovedFromStudy(const bool isRemoved)
+{
+  _pyObject::SetRemovedFromStudy(isRemoved);
+
+  list< Handle(_pySubMesh) >::iterator sm = mySubmeshes.begin();
+  for ( ; sm != mySubmeshes.end(); ++sm )
+    (*sm)->SetRemovedFromStudy(isRemoved);
+
+  list< Handle(_pyGroup) >::iterator gr = myGroups.begin();
+  for ( ; gr != myGroups.end(); ++gr )
+    (*gr)->SetRemovedFromStudy(isRemoved);
+
+  list< Handle(_pyMesh) >::iterator m = myChildMeshes.begin();
+  for ( ; m != myChildMeshes.end(); ++m )
+    (*m)->SetRemovedFromStudy(isRemoved);
+
+  list< Handle(_pyMeshEditor)>::iterator e = myEditors.begin();
+  for ( ; e != myEditors.end(); ++e )
+    (*e)->SetRemovedFromStudy(isRemoved);
+}
+
+//================================================================================
+/*!
+ * \brief Return true if none of myChildMeshes is in study
+ */
+//================================================================================
+
+bool _pyMesh::CanClear()
+{
+  if ( IsInStudy() )
+    return false;
+
+  list< Handle(_pyMesh) >::iterator m = myChildMeshes.begin();
+  for ( ; m != myChildMeshes.end(); ++m )
+    if ( !(*m)->CanClear() )
+      return false;
+
+  return true;
+}
+
+//================================================================================
+/*!
+ * \brief Clear my commands and commands of mesh editor
+ */
+//================================================================================
+
+void _pyMesh::ClearCommands()
+{
+  if ( !CanClear() )
+  {
+    if ( !IsInStudy() )
+    {
+      // mark all sub-objects as not removed, except child meshes
+      list< Handle(_pyMesh) > children;
+      children.swap( myChildMeshes );
+      SetRemovedFromStudy( false );
+      children.swap( myChildMeshes );
+    }
+    return;
+  }
+  _pyObject::ClearCommands();
+
+  list< Handle(_pySubMesh) >::iterator sm = mySubmeshes.begin();
+  for ( ; sm != mySubmeshes.end(); ++sm )
+    (*sm)->ClearCommands();
+  
+  list< Handle(_pyGroup) >::iterator gr = myGroups.begin();
+  for ( ; gr != myGroups.end(); ++gr )
+    (*gr)->ClearCommands();
+
+  list< Handle(_pyMeshEditor)>::iterator e = myEditors.begin();
+  for ( ; e != myEditors.end(); ++e )
+    (*e)->ClearCommands();
+}
+
+//================================================================================
+/*!
+ * \brief Add a father mesh by ID
+ */
+//================================================================================
+
+void _pyMesh::addFatherMesh( const _pyID& meshID )
+{
+  if ( !meshID.IsEmpty() )
+    addFatherMesh( Handle(_pyMesh)::DownCast( theGen->FindObject( meshID )));
+}
+
+//================================================================================
+/*!
+ * \brief Add a father mesh
+ */
+//================================================================================
+
+void _pyMesh::addFatherMesh( const Handle(_pyMesh)& mesh )
+{
+  if ( !mesh.IsNull() )
+  {
+    //myFatherMeshes.push_back( mesh );
+    mesh->myChildMeshes.push_back( this );
+
+    // protect last Compute() from clearing by the next Compute()
+    mesh->myLastComputeCmd.Nullify();
+  }
+}
+
 //================================================================================
 /*!
  * \brief MeshEditor convert its commands to ones of mesh
@@ -1267,6 +1745,10 @@ _pyMeshEditor::_pyMeshEditor(const Handle(_pyCommand)& theCreationCmd):
   myMesh = theCreationCmd->GetObject();
   myCreationCmdStr = theCreationCmd->GetString();
   theCreationCmd->Clear();
+
+  Handle(_pyMesh) mesh = ObjectToMesh( theGen->FindObject( myMesh ));
+  if ( !mesh.IsNull() )
+    mesh->AddEditor( this );
 }
 
 //================================================================================
@@ -1326,19 +1808,36 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
     if( pos != -1)
     {
       isPyMeshMethod = true;
+      bool is0DmethId  = ( method == "ExtrusionSweepMakeGroups0D" );
+      bool is0DmethObj = ( method == "ExtrusionSweepObject0DMakeGroups");
 
       // 1. Remove "MakeGroups" from the Command
       TCollection_AsciiString aMethod = theCommand->GetMethod();
       int nbArgsToAdd = diffLastTwoArgsMethods.Contains(aMethod) ? 2 : 1;
+      
+      if(is0DmethObj)
+        pos = pos-2;  //Remove "0D" from the Command too
       aMethod.Trunc(pos-1);
       theCommand->SetMethod(aMethod);
 
       // 2. And add last "True" argument(s)
       while(nbArgsToAdd--)
         theCommand->SetArg(theCommand->GetNbArgs()+1,"True");
+      if( is0DmethId || is0DmethObj )
+        theCommand->SetArg(theCommand->GetNbArgs()+1,"True");
     }
   }
 
+  // ExtrusionSweep0D() -> ExtrusionSweep()
+  // ExtrusionSweepObject0D() -> ExtrusionSweepObject()
+  if ( !isPyMeshMethod && ( method == "ExtrusionSweep0D"  ||
+                            method == "ExtrusionSweepObject0D" ))
+  {
+    isPyMeshMethod=true;
+    theCommand->SetMethod( method.SubString( 1, method.Length()-2));
+    theCommand->SetArg(theCommand->GetNbArgs()+1,"False");  //sets flag "MakeGroups = False"
+    theCommand->SetArg(theCommand->GetNbArgs()+1,"True");  //sets flag "IsNode = True"
+  }
   // set "ExtrusionAlongPathX()" instead of "ExtrusionAlongPathObjX()"
   if ( !isPyMeshMethod && method == "ExtrusionAlongPathObjX")
   {
@@ -1411,6 +1910,18 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
   }
 }
 
+//================================================================================
+/*!
+ * \brief Return true if my mesh can be removed
+ */
+//================================================================================
+
+bool _pyMeshEditor::CanClear()
+{
+  Handle(_pyMesh) mesh = ObjectToMesh( theGen->FindObject( myMesh ));
+  return mesh.IsNull() ? true : mesh->CanClear();
+}
+
 //================================================================================
 /*!
  * \brief _pyHypothesis constructor
@@ -1616,7 +2127,7 @@ Handle(_pyHypothesis) _pyHypothesis::NewHypothesis( const Handle(_pyCommand)& th
     hyp->SetConvMethodAndType( "Parameters", "GHS3D_3D");
   }
   // Hexa_3D ---------
-  else if ( hypType == "BLSURF" ) {
+  else if ( hypType == "Hexa_3D" ) {
     algo->SetConvMethodAndType( "Hexahedron", hypType.ToCString());
   }
   // Repetitive Projection_1D ---------
@@ -1639,6 +2150,7 @@ Handle(_pyHypothesis) _pyHypothesis::NewHypothesis( const Handle(_pyCommand)& th
   }
   else if ( hypType == "ProjectionSource2D" ) {
     hyp->SetConvMethodAndType( "SourceFace", "Projection_2D");
+    hyp->SetConvMethodAndType( "SourceFace", "Projection_1D2D");
     hyp->AddArgMethod( "SetSourceFace");
     hyp->AddArgMethod( "SetSourceMesh");
     hyp->AddArgMethod( "SetVertexAssociation", 4 );
@@ -1683,6 +2195,24 @@ Handle(_pyHypothesis) _pyHypothesis::NewHypothesis( const Handle(_pyCommand)& th
   return algo->IsValid() ? algo : hyp;
 }
 
+//================================================================================
+/*!
+ * \brief Returns true if addition of this hypothesis to a given mesh can be
+ *        wrapped into hypothesis creation
+ */
+//================================================================================
+
+bool _pyHypothesis::IsWrappable(const _pyID& theMesh) const
+{
+  if ( !myIsWrapped && myMesh == theMesh && IsInStudy() )
+  {
+    Handle(_pyObject) pyMesh = theGen->FindObject( myMesh );
+    if ( !pyMesh.IsNull() && pyMesh->IsInStudy() )
+      return true;
+  }
+  return false;
+}
+
 //================================================================================
 /*!
  * \brief Convert the command adding a hypothesis to mesh into a smesh command
@@ -1758,6 +2288,8 @@ bool _pyHypothesis::Addition2Creation( const Handle(_pyCommand)& theCmd,
 void _pyHypothesis::Process( const Handle(_pyCommand)& theCommand)
 {
   ASSERT( !myIsAlgo );
+  if ( !theGen->IsToKeepAllCommands() )
+    rememberCmdOfParameter( theCommand );
   // set args
   int nbArgs = 0;
   for ( int i = 1; i <= myArgMethods.Length(); ++i ) {
@@ -1782,9 +2314,8 @@ void _pyHypothesis::Process( const Handle(_pyCommand)& theCommand)
 
 void _pyHypothesis::Flush()
 {
-  if ( IsWrapped() ) {
-  }
-  else {
+  if ( !IsAlgo() )
+  {
     list < Handle(_pyCommand) >::iterator cmd = myArgCommands.begin();
     for ( ; cmd != myArgCommands.end(); ++cmd ) {
       // Add access to a wrapped mesh
@@ -1846,6 +2377,227 @@ void _pyHypothesis::Assign( const Handle(_pyHypothesis)& theOther,
   myUnknownCommands = theOther->myUnknownCommands;
 }
 
+//================================================================================
+/*!
+ * \brief Analyze my erasability depending on myReferredObjs
+ */
+//================================================================================
+
+bool _pyHypothesis::CanClear()
+{
+  if ( IsInStudy() )
+  {
+    list< Handle(_pyObject) >::iterator obj = myReferredObjs.begin();
+    for ( ; obj != myReferredObjs.end(); ++obj )
+      if ( (*obj)->CanClear() )
+        return true;
+    return false;
+  }
+  return true;
+}
+
+//================================================================================
+/*!
+ * \brief Clear my commands depending on usage by meshes
+ */
+//================================================================================
+
+void _pyHypothesis::ClearCommands()
+{
+  // if ( !theGen->IsToKeepAllCommands() )
+  // {
+  //   bool isUsed = false;
+  //   int lastComputeOrder = 0;
+  //   list<Handle(_pyCommand) >::iterator cmd = myComputeCmds.begin();
+  //   for ( ; cmd != myComputeCmds.end(); ++cmd )
+  //     if ( ! (*cmd)->IsEmpty() )
+  //     {
+  //       isUsed = true;
+  //       if ( (*cmd)->GetOrderNb() > lastComputeOrder )
+  //         lastComputeOrder = (*cmd)->GetOrderNb();
+  //     }
+  //   if ( !isUsed )
+  //   {
+  //     SetRemovedFromStudy( true );
+  //   }
+  //   else
+  //   {
+  //     // clear my commands invoked after lastComputeOrder
+  //     // map<TCollection_AsciiString, list< Handle(_pyCommand) > >::iterator m2c;
+  //     // for ( m2c = myMeth2Commands.begin(); m2c != myMeth2Commands.end(); ++m2c )
+  //     // {
+  //     //   list< Handle(_pyCommand)> & cmds = m2c->second;
+  //     //   if ( !cmds.empty() && cmds.back()->GetOrderNb() > lastComputeOrder )
+  //     //     cmds.back()->Clear();
+  //     // }
+  //   }
+  // }
+  _pyObject::ClearCommands();
+}
+
+//================================================================================
+/*!
+ * \brief Find arguments that are objects like mesh, group, geometry
+ *  \param meshes - referred meshes (directly or indirrectly)
+ *  \retval bool - false if a referred geometry is not in the study
+ */
+//================================================================================
+
+bool _pyHypothesis::GetReferredMeshesAndGeom( list< Handle(_pyMesh) >& meshes )
+{
+  if ( IsAlgo() ) return true;
+
+  bool geomPublished = true;
+  TColStd_SequenceOfAsciiString args; args = myArgs;
+
+  list<Handle(_pyCommand)>::iterator cmd = myUnknownCommands.begin();
+  for ( ; cmd != myUnknownCommands.end(); ++cmd ) {
+    for ( int nb = (*cmd)->GetNbArgs(); nb; --nb )
+      args.Append( (*cmd)->GetArg( nb ));
+  }
+
+  for ( int i = 1; i <= args.Length(); ++i )
+  {
+    list< _pyID > idList = _pyCommand::GetStudyEntries( args( i ));
+    list< _pyID >::iterator id = idList.begin();
+    for ( ; id != idList.end(); ++id )
+    {
+      Handle(_pyObject) obj = theGen->FindObject( *id );
+      if ( obj.IsNull() )
+      {
+        if ( theGen->IsGeomObject( *id ) && theGen->IsNotPublished( *id ))
+          geomPublished = false;
+      }
+      else
+      {
+        myReferredObjs.push_back( obj );
+        Handle(_pyMesh) mesh = ObjectToMesh( obj );
+        if ( !mesh.IsNull() )
+          meshes.push_back( mesh );
+      }
+    }
+  }
+  return geomPublished;
+}
+
+//================================================================================
+/*!
+ * \brief Remember theCommand setting a parameter
+ */
+//================================================================================
+
+void _pyHypothesis::rememberCmdOfParameter( const Handle(_pyCommand) & theCommand )
+{
+  // parameters are discriminated by method name
+  TCollection_AsciiString method = theCommand->GetMethod();
+
+  // discriminate commands setting different parameters via one method
+  // by passing parameter names like e.g. SetOption("size", "0.2")
+  if ( theCommand->GetString().FirstLocationInSet( "'\"", 1, theCommand->Length() ) &&
+       theCommand->GetNbArgs() > 1 )
+  {
+    // mangle method by appending a 1st textual arg (what if it's a variable name?!!!)
+    for ( int iArg = 1; iArg <= theCommand->GetNbArgs(); ++iArg )
+    {
+      const TCollection_AsciiString& arg = theCommand->GetArg( iArg );
+      if ( arg.Value(1) != '\"' && arg.Value(1) != '\'' ) continue;
+      if ( !isalpha( arg.Value(2))) continue;
+      method += arg;
+      break;
+    }
+  }
+  // parameters are discriminated by method name
+  list< Handle(_pyCommand)>& cmds = myMeth2Commands[ theCommand->GetMethod() ];
+  if ( !cmds.empty() && !isCmdUsedForCompute( cmds.back() ))
+  {
+    cmds.back()->Clear(); // previous parameter value has not been used
+    cmds.back() = theCommand;
+  }
+  else
+  {
+    cmds.push_back( theCommand );
+  }
+}
+
+//================================================================================
+/*!
+ * \brief Return true if a setting parameter command ha been used to compute mesh
+ */
+//================================================================================
+
+bool _pyHypothesis::isCmdUsedForCompute( const Handle(_pyCommand) & cmd,
+                                         _pyCommand::TAddr          avoidComputeAddr ) const
+{
+  bool isUsed = false;
+  map< _pyCommand::TAddr, list<Handle(_pyCommand) > >::const_iterator addr2cmds =
+    myComputeAddr2Cmds.begin();
+  for ( ; addr2cmds != myComputeAddr2Cmds.end() && !isUsed; ++addr2cmds )
+  {
+    if ( addr2cmds->first == avoidComputeAddr ) continue;
+    const list<Handle(_pyCommand)> & cmds = addr2cmds->second;
+    isUsed = ( std::find( cmds.begin(), cmds.end(), cmd ) != cmds.end() );
+  }
+  return isUsed;
+}
+
+//================================================================================
+/*!
+ * \brief Save commands setting parameters as they are used for a mesh computation
+ */
+//================================================================================
+
+void _pyHypothesis::MeshComputed( const Handle(_pyCommand)& theComputeCmd )
+{
+  myComputeCmds.push_back( theComputeCmd );
+  list<Handle(_pyCommand)>& savedCmds = myComputeAddr2Cmds[ theComputeCmd->GetAddress() ];
+
+  map<TCollection_AsciiString, list< Handle(_pyCommand) > >::iterator m2c;
+  for ( m2c = myMeth2Commands.begin(); m2c != myMeth2Commands.end(); ++m2c )
+    savedCmds.push_back( m2c->second.back() );
+}
+
+//================================================================================
+/*!
+ * \brief Clear commands setting parameters as a mesh computed using them is cleared
+ */
+//================================================================================
+
+void _pyHypothesis::ComputeDiscarded( const Handle(_pyCommand)& theComputeCmd )
+{
+  list<Handle(_pyCommand)>& savedCmds = myComputeAddr2Cmds[ theComputeCmd->GetAddress() ];
+
+  list<Handle(_pyCommand)>::iterator cmd = savedCmds.begin();
+  for ( ; cmd != savedCmds.end(); ++cmd )
+  {
+    // check if a cmd has been used to compute another mesh
+    if ( isCmdUsedForCompute( *cmd, theComputeCmd->GetAddress() ))
+      continue;
+    // check if a cmd is a sole command setting its parameter;
+    // don't use method name for search as it can change
+    map<TCollection_AsciiString, list<Handle(_pyCommand)> >::iterator
+      m2cmds = myMeth2Commands.begin();
+    for ( ; m2cmds != myMeth2Commands.end(); ++m2cmds )
+    {
+      list< Handle(_pyCommand)>& cmds = m2cmds->second;
+      list< Handle(_pyCommand)>::iterator cmdIt = std::find( cmds.begin(), cmds.end(), *cmd );
+      if ( cmdIt != cmds.end() )
+      {
+        if ( cmds.back() != *cmd )
+        {
+          cmds.erase( cmdIt );
+          (*cmd)->Clear();
+        }
+        break;
+      }
+    }
+  }
+  myComputeAddr2Cmds.erase( theComputeCmd->GetAddress() );
+}
+// void _pyHypothesis::ComputeSaved( const Handle(_pyCommand)& theComputeCommand )
+// {
+// }
+
+
 //================================================================================
 /*!
  * \brief Remember hypothesis parameter values
@@ -1883,13 +2635,14 @@ void _pyComplexParamHypo::Process( const Handle(_pyCommand)& theCommand)
         myArgs( iArg ) += "]";
       }
       myArgCommands.push_back( theCommand );
+      rememberCmdOfParameter( theCommand );
       return;
     }
   }
 
   if( theCommand->GetMethod() == "SetLength" )
   {
-    // NOW it becomes OBSOLETE
+    // NOW it is OBSOLETE
     // ex: hyp.SetLength(start, 1)
     //     hyp.SetLength(end,   0)
     ASSERT(( theCommand->GetArg( 2 ).IsIntegerValue() ));
@@ -2245,12 +2998,20 @@ const TCollection_AsciiString & _pyCommand::GetResultValue()
 {
   if ( GetBegPos( RESULT_IND ) == UNKNOWN )
   {
-    int begPos = myString.Location( "=", 1, Length() );
-    if ( begPos )
-      myRes = GetWord( myString, begPos, false );
-    else
-      begPos = EMPTY;
-    SetBegPos( RESULT_IND, begPos );
+    SetBegPos( RESULT_IND, EMPTY );
+    int begPos, endPos = myString.Location( "=", 1, Length() );
+    if ( endPos )
+    {
+      begPos = 1;
+      while ( begPos < endPos && isspace( myString.Value( begPos ))) ++begPos;
+      if ( begPos < endPos )
+      {
+        SetBegPos( RESULT_IND, begPos );
+        --endPos;
+        while ( begPos < endPos && isspace( myString.Value( endPos ))) --endPos;
+        myRes = myString.SubString( begPos, endPos );
+      }
+    }
   }
   return myRes;
 }
@@ -2402,7 +3163,7 @@ const TCollection_AsciiString & _pyCommand::GetArg( int index )
     // we are at or before '(', skip it if present
     if ( pos > 0 ) {
       while ( pos <= Length() && myString.Value( pos ) != '(' ) ++pos;
-      if ( myString.Value( pos ) != '(' )
+      if ( pos > Length() )
         pos = 0;
     }
     if ( pos < 1 ) {
@@ -2523,10 +3284,11 @@ TCollection_AsciiString _pyCommand::GetWord( const TCollection_AsciiString & the
       return theEmptyString; // no word found
     beg = end - 1;
     char endChar = theString.Value( end );
-    if ( endChar == '"' || endChar == '\'' ) {
+    if ( endChar == '"' || endChar == '\'' || endChar == ']') {
+      char begChar = ( endChar == ']' ) ? '[' : endChar;
       // beg is at the corresponding quoting mark
       while ( beg > 1 &&
-              ( theString.Value( beg ) != endChar || theString.Value( beg-1 ) == '\\'))
+              ( theString.Value( beg ) != begChar || theString.Value( beg-1 ) == '\\'))
         --beg;
     }
     else {
@@ -2540,6 +3302,52 @@ TCollection_AsciiString _pyCommand::GetWord( const TCollection_AsciiString & the
   return theString.SubString( beg, end );
 }
 
+//================================================================================
+/*!
+ * \brief Returns true if the string looks like a study entry
+ */
+//================================================================================
+
+bool _pyCommand::IsStudyEntry( const TCollection_AsciiString& str )
+{
+  if ( str.Length() < 5 ) return false;
+
+  int nbColons = 0, isColon;
+  for ( int i = 1; i <= str.Length(); ++i )
+  {
+    char c = str.Value(i);
+    if (!( isColon = (c == ':')) && ( c < '0' || c > '9' ))
+      return false;
+    nbColons += isColon;
+  }
+  return nbColons > 2 && str.Length()-nbColons > 2;
+}
+
+//================================================================================
+/*!
+ * \brief Finds entries in a sting
+ */
+//================================================================================
+
+std::list< _pyID > _pyCommand::GetStudyEntries( const TCollection_AsciiString& str )
+{
+  std::list< _pyID > resList;
+  int pos = 0;
+  while ( ++pos <= str.Length() )
+  {
+    if ( !isdigit( str.Value( pos ))) continue;
+    if ( pos != 1 && ( isalpha( str.Value( pos-1 ) || str.Value( pos-1 ) == ':'))) continue;
+
+    int end = pos;
+    while ( ++end <= str.Length() && ( isdigit( str.Value( end )) || str.Value( end ) == ':' ));
+    _pyID entry = str.SubString( pos, end-1 );
+    pos = end;
+    if ( IsStudyEntry( entry ))
+      resList.push_back( entry );
+  }
+  return resList;
+}
+
 //================================================================================
 /*!
  * \brief Look for position where not space char is
@@ -2661,6 +3469,30 @@ void _pyCommand::RemoveArgs()
     myBegPos.Remove( ARG1_IND, myBegPos.Length() );
 }
 
+//================================================================================
+/*!
+ * \brief Comment a python command
+ */
+//================================================================================
+
+void _pyCommand::Comment()
+{
+  if ( IsEmpty() ) return;
+
+  int i = 1;
+  while ( i <= Length() && isspace( myString.Value(i) )) ++i;
+  if ( i <= Length() )
+  {
+    myString.Insert( i, "#" );
+    for ( int iPart = 0; iPart < myBegPos.Length(); ++iPart )
+    {
+      int begPos = GetBegPos( iPart );
+      if ( begPos != UNKNOWN )
+        SetBegPos( iPart, begPos + 1 );
+    }
+  }
+}
+
 //================================================================================
 /*!
  * \brief Set dependent commands after this one
@@ -2726,6 +3558,49 @@ bool _pyCommand::AddAccessorMethod( _pyID theObjectID, const char* theAcsMethod
   return added;
 }
 
+//================================================================================
+/*!
+ * \brief Creates pyObject
+ */
+//================================================================================
+
+_pyObject::_pyObject(const Handle(_pyCommand)& theCreationCmd, const _pyID& theID)
+  : myID(theID), myCreationCmd(theCreationCmd), myIsPublished(false)
+{
+  setID( theID );
+}
+
+//================================================================================
+/*!
+ * \brief Set up myID and myIsPublished
+ */
+//================================================================================
+
+void _pyObject::setID(const _pyID& theID)
+{
+  myID = theID;
+  myIsPublished = !theGen->IsNotPublished( GetID() );
+}
+
+//================================================================================
+/*!
+ * \brief Clear myCreationCmd and myProcessedCmds
+ */
+//================================================================================
+
+void _pyObject::ClearCommands()
+{
+  if ( !CanClear() )
+    return;
+
+  if ( !myCreationCmd.IsNull() )
+    myCreationCmd->Clear();
+
+  list< Handle(_pyCommand) >::iterator cmd = myProcessedCmds.begin();
+  for ( ; cmd != myProcessedCmds.end(); ++cmd )
+    (*cmd)->Clear();
+}
+
 //================================================================================
 /*!
  * \brief Return method name giving access to an interaface object wrapped by python class
@@ -2763,6 +3638,18 @@ void _pySelfEraser::Flush()
     GetCreationCmd()->Clear();
 }
 
+//================================================================================
+/*!
+ * \brief _pySubMesh constructor
+ */
+//================================================================================
+
+_pySubMesh::_pySubMesh(const Handle(_pyCommand)& theCreationCmd):
+  _pyObject(theCreationCmd)
+{
+  myMesh = ObjectToMesh( theGen->FindObject( theCreationCmd->GetObject() ));
+}
+
 //================================================================================
 /*!
  * \brief count invoked commands
@@ -2777,7 +3664,7 @@ void _pySubMesh::Process( const Handle(_pyCommand)& theCommand )
 
 //================================================================================
 /*!
- * \brief Clear creation command if no commands invoked
+ * \brief Move creation command depending on invoked commands
  */
 //================================================================================
 
@@ -2802,12 +3689,13 @@ void _pyGroup::Process( const Handle(_pyCommand)& theCommand)
   // group = mesh.CreateEmptyGroup( elemType, groupName )
   // aFilter.SetMesh(mesh)
   // nbAdd = group.AddFrom( aFilter )
+  Handle(_pyFilter) filter;
   if ( theCommand->GetMethod() == "AddFrom" )
   {
     _pyID idSource = theCommand->GetArg(1);
     // check if idSource is a filter
-    Handle(_pyObject) filter = theGen->FindObject( idSource );
-    if ( filter.IsNull() || !filter->IsKind(STANDARD_TYPE(_pyFilter)))
+    filter = Handle(_pyFilter)::DownCast( theGen->FindObject( idSource ));
+    if ( filter.IsNull() )
       return;
     // find aFilter.SetMesh(mesh) to clear it, it should be just before theCommand
     list< Handle(_pyCommand) >::reverse_iterator cmdIt = theGen->GetCommands().rbegin();
@@ -2816,7 +3704,7 @@ void _pyGroup::Process( const Handle(_pyCommand)& theCommand)
     {
       const Handle(_pyCommand)& setMeshCmd = *(++cmdIt);
       if ((setMeshCmd->GetObject() == idSource ||
-           setMeshCmd->GetObject() == Handle(_pyFilter)::DownCast(filter)->GetNewID() )
+           setMeshCmd->GetObject() == filter->GetNewID() )
           &&
           setMeshCmd->GetMethod() == "SetMesh")
       {
@@ -2838,10 +3726,13 @@ void _pyGroup::Process( const Handle(_pyCommand)& theCommand)
   {
     // set new name of a filter
     _pyID filterID = theCommand->GetArg(1);
-    Handle(_pyObject) filter = theGen->FindObject( filterID );
+    filter = Handle(_pyFilter)::DownCast( theGen->FindObject( filterID ));
     if ( !filter.IsNull() )
       filter->Process( theCommand );
   }
+
+  if ( !filter.IsNull() )
+    filter->AddUser( this );
 }
 
 //================================================================================
@@ -2885,7 +3776,7 @@ void _pyFilter::Process( const Handle(_pyCommand)& theCommand)
   // Convert the following set of commands into smesh.GetFilterFromCriteria(criteria)
   // aFilter0x2aaab0487080 = aFilterManager.CreateFilter()
   // aFilter0x2aaab0487080.SetCriteria(aCriteria)
-  if ( GetNbCalls() == 0 && // none method was called before SetCriteria()
+  if ( GetNbCalls() == 1 && // none method was called before this SetCriteria() call
        theCommand->GetMethod() == "SetCriteria")
   {
     // aFilter.SetCriteria(aCriteria) ->
@@ -2917,3 +3808,19 @@ void _pyFilter::Flush()
   if ( !myNewID.IsEmpty() && !GetCreationCmd()->IsEmpty() )
     GetCreationCmd()->SetResultValue( myNewID );
 }
+
+//================================================================================
+/*!
+ * \brief Return true if all my users can be cleared
+ */
+//================================================================================
+
+bool _pyFilter::CanClear()
+{
+  list< Handle(_pyObject) >::iterator obj = myUsers.begin();
+  for ( ; obj != myUsers.end(); ++obj )
+    if ( !(*obj)->CanClear() )
+      return false;
+
+  return true;
+}