Salome HOME
0022238: Study dump produced by SMESH refers to undefined variable names
[modules/smesh.git] / src / SMESH_I / SMESH_2smeshpy.cxx
index 91f6e7effd1d6482db1de829fd9aaa67fac89d1d..b0a202b5ef2d7a07f93e8a745a9a50bd9eeea470 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 //
 #include "SMESH_2smeshpy.hxx"
 
-#include "utilities.h"
 #include "SMESH_PythonDump.hxx"
 #include "SMESH_NoteBook.hxx"
 #include "SMESH_Filter_i.hxx"
 
+#include <SALOMEDS_wrap.hxx>
+#include <utilities.h>
+
 #include <Resource_DataMapOfAsciiStringAsciiString.hxx>
 #include <Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString.hxx>
 
@@ -124,6 +126,31 @@ namespace {
     }
   };
 
+  //================================================================================
+  /*!
+   * \brief Map of TCollection_AsciiString initialized by C array of C strings.
+   *        Odd items of the C array are map keys, and even items are values
+   */
+  //================================================================================
+
+  struct TStringMap: public map<TCollection_AsciiString,TCollection_AsciiString>
+  {
+    /*!
+     * \brief Filling. The last string must be ""
+     */
+    void Insert(const char* names_values[]) {
+      for ( int i = 0; names_values[i][0] ; i += 2 )
+        insert( make_pair( (char*) names_values[i], names_values[i+1] ));
+    }
+    /*!
+     * \brief Check if a string is in
+     */
+    TCollection_AsciiString Value(const TCollection_AsciiString& name ) {
+      map< _AString, _AString >::iterator it = find( name );
+      return it == end() ? "" : it->second;
+    }
+  };
+
   //================================================================================
   /*!
    * \brief Returns a mesh by object
@@ -152,7 +179,33 @@ namespace {
 
   void CheckObjectPresence( const Handle(_pyCommand)& cmd, set<_pyID> & presentObjects)
   {
-    for ( int iArg = cmd->GetNbArgs(); iArg; --iArg )
+    // either comment or erase a command including NotPublishedObjectName()
+    if ( cmd->GetString().Location( TPythonDump::NotPublishedObjectName(), 1, cmd->Length() ))
+    {
+      bool isResultPublished = false;
+      for ( int i = 0; i < cmd->GetNbResultValues(); i++ )
+      {
+        _pyID objID = cmd->GetResultValue( i+1 );
+        if ( cmd->IsStudyEntry( objID ))
+          isResultPublished = (! theGen->IsNotPublished( objID ));
+        theGen->ObjectCreationRemoved( objID ); // objID.SetName( name ) is not needed
+      }
+      if ( isResultPublished )
+        cmd->Comment();
+      else
+        cmd->Clear();
+      return;
+    }
+    // check if an Object was created in the script
+    _AString comment;
+    const _pyID& obj = cmd->GetObject();
+    if ( !obj.IsEmpty() && cmd->IsStudyEntry( obj ) && !presentObjects.count( obj ))
+    {
+      comment = "not created Object";
+      theGen->ObjectCreationRemoved( obj );
+    }
+    // check if a command has not created args
+    for ( int iArg = cmd->GetNbArgs(); iArg && comment.IsEmpty(); --iArg )
     {
       const _pyID& arg = cmd->GetArg( iArg );
       if ( arg.IsEmpty() || arg.Value( 1 ) == '"' || arg.Value( 1 ) == '\'' )
@@ -162,25 +215,29 @@ namespace {
       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;
+          comment += *id + " has not been yet created";
+          break;
         }
     }
-    const _pyID& obj = cmd->GetObject();
-    if ( !obj.IsEmpty() && cmd->IsStudyEntry( obj ) && !presentObjects.count( obj ))
+    // treat result objects
+    const _pyID& result = cmd->GetResultValue();
+    if ( !result.IsEmpty() && result.Value( 1 ) != '"' && result.Value( 1 ) != '\'' )
+    {
+      list< _pyID > idList = cmd->GetStudyEntries( result );
+      list< _pyID >::iterator id = idList.begin();
+      for ( ; id != idList.end(); ++id )
+        if ( comment.IsEmpty() )
+          presentObjects.insert( *id );
+        else
+          theGen->ObjectCreationRemoved( *id ); // objID.SetName( name ) is not needed
+    }
+    // comment the command
+    if ( !comment.IsEmpty() )
     {
       cmd->Comment();
-      cmd->GetString() += " ### not created object" ;
+      cmd->GetString() += " ### ";
+      cmd->GetString() += comment;
     }
-    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 );
   }
 
   //================================================================================
@@ -229,6 +286,10 @@ namespace {
     //   - FT_EqualVolumes          = 17
     // v 6.6.0: FT_Undefined == 44, new items:
     //   - FT_BallDiameter          = 37
+    // v 6.7.1: FT_Undefined == 45, new items:
+    //   - FT_EntityType            = 36
+    // v 7.3.0: FT_Undefined == 46, new items:
+    //   - FT_ConnectedElements     = 39
     //
     // It's necessary to continue recording this history and to fill
     // undef2newItems (see below) accordingly.
@@ -246,8 +307,11 @@ namespace {
         undef2newItems[ 39 ].assign( items, items+6 ); }
       { int items[] = { 14, 15, 16, 17 };
         undef2newItems[ 43 ].assign( items, items+4 ); }
-      { int items[] = { 37 };
-        undef2newItems[ 44 ].assign( items, items+1 ); }
+      undef2newItems[ 44 ].push_back( 37 );
+      undef2newItems[ 45 ].push_back( 36 );
+      undef2newItems[ 46 ].push_back( 39 );
+
+      ASSERT( undef2newItems.rbegin()->first == SMESH::FT_Undefined );
     }
 
     int iType     = Type.IntegerValue();
@@ -283,17 +347,103 @@ namespace {
       BinaryOp = TCollection_AsciiString( iBinaryOp );
     }
   }
+
+  //================================================================================
+  /*!
+   * \brief Replaces "SMESH.PointStruct(x,y,z)" and "SMESH.DirStruct( SMESH.PointStruct(x,y,z))"
+   *        arguments of a given command by a list "[x,y,z]" if the list is accesible
+   *        type of argument.
+   */
+  //================================================================================
+
+  void StructToList( Handle( _pyCommand)& theCommand )
+  {
+    static TStringSet methodsAcceptingList;
+    if ( methodsAcceptingList.empty() ) {
+      const char * methodNames[] = {
+        "GetCriterion","Reorient2D","ExtrusionSweep","ExtrusionSweepMakeGroups0D",
+        "ExtrusionSweepMakeGroups","ExtrusionSweep0D",
+        "AdvancedExtrusion","AdvancedExtrusionMakeGroups",
+        "ExtrusionSweepObject","ExtrusionSweepObject0DMakeGroups",
+        "ExtrusionSweepObjectMakeGroups","ExtrusionSweepObject0D",
+        "ExtrusionSweepObject1D","ExtrusionSweepObject1DMakeGroups",
+        "ExtrusionSweepObject2D","ExtrusionSweepObject2DMakeGroups",
+        "Translate","TranslateMakeGroups","TranslateMakeMesh",
+        "TranslateObject","TranslateObjectMakeGroups", "TranslateObjectMakeMesh"
+        ,"" }; // <- mark of the end
+      methodsAcceptingList.Insert( methodNames );
+    }
+    if ( methodsAcceptingList.Contains( theCommand->GetMethod() ))
+    {
+      for ( int i = theCommand->GetNbArgs(); i > 0; --i )
+      {
+        const _AString & arg = theCommand->GetArg( i );
+        if ( arg.Search( "SMESH.PointStruct" ) == 1 ||
+             arg.Search( "SMESH.DirStruct"   ) == 1 )
+        {
+          Handle(_pyCommand) workCmd = new _pyCommand( arg );
+          if ( workCmd->GetNbArgs() == 1 ) // SMESH.DirStruct( SMESH.PointStruct(x,y,z))
+          {
+            workCmd = new _pyCommand( workCmd->GetArg( 1 ) );
+          }
+          if ( workCmd->GetNbArgs() == 3 ) // SMESH.PointStruct(x,y,z)
+          {
+            _AString newArg = "[ ";
+            newArg += ( workCmd->GetArg( 1 ) + ", " +
+                        workCmd->GetArg( 2 ) + ", " +
+                        workCmd->GetArg( 3 ) + " ]");
+            theCommand->SetArg( i, newArg );
+          }
+        }
+      }
+    }
+  }
+  //================================================================================
+  /*!
+   * \brief Replaces "mesh.GetIDSource([id1,id2])" argument of a given command by
+   *        a list "[id1,id2]" if the list is an accesible type of argument.
+   */
+  //================================================================================
+
+  void GetIDSourceToList( Handle( _pyCommand)& theCommand )
+  {
+    static TStringSet methodsAcceptingList;
+    if ( methodsAcceptingList.empty() ) {
+      const char * methodNames[] = {
+        "ExportPartToMED","ExportPartToDAT","ExportPartToUNV","ExportPartToSTL",
+        "ExportCGNS","ExportGMF",
+        "Create0DElementsOnAllNodes","Reorient2D","QuadTo4Tri",
+        "ScaleMakeGroups","Scale","ScaleMakeMesh",
+        "FindCoincidentNodesOnPartBut","DoubleElements"
+        ,"" }; // <- mark of the end
+      methodsAcceptingList.Insert( methodNames );
+    }
+    if ( methodsAcceptingList.Contains( theCommand->GetMethod() ))
+    {
+      for ( int i = theCommand->GetNbArgs(); i > 0; --i )
+      {
+        _pyCommand argCmd( theCommand->GetArg( i ));
+        if ( argCmd.GetMethod() == "GetIDSource" &&
+             argCmd.GetNbArgs() == 2 )
+        {
+          theCommand->SetArg( i, argCmd.GetArg( 1 ));
+        }
+      }
+    }
+  }
 }
 
 //================================================================================
 /*!
- * \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
+ * \brief Convert a python script using commands of smeshBuilder.py
+ *  \param theScript - Input script
+ *  \param theEntry2AccessorMethod - returns method names to access to
+ *         objects wrapped with python class
+ *  \param theObjectNames - names of objects
+ *  \param theRemovedObjIDs - entries of objects whose created commands were removed
+ *  \param theHistoricalDump - true means to keep all commands, false means
+ *         to exclude commands relating to objects removed from study
+ *  \retval TCollection_AsciiString - Convertion result
  */
 //================================================================================
 
@@ -301,10 +451,15 @@ TCollection_AsciiString
 SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString&            theScript,
                               Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod,
                               Resource_DataMapOfAsciiStringAsciiString& theObjectNames,
+                              std::set< TCollection_AsciiString >&      theRemovedObjIDs,
                               SALOMEDS::Study_ptr&                      theStudy,
                               const bool                                theToKeepAllCommands)
 {
-  theGen = new _pyGen( theEntry2AccessorMethod, theObjectNames, theStudy, theToKeepAllCommands );
+  theGen = new _pyGen( theEntry2AccessorMethod,
+                       theObjectNames,
+                       theRemovedObjIDs,
+                       theStudy,
+                       theToKeepAllCommands );
 
   // split theScript into separate commands
 
@@ -314,9 +469,9 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString&            theScrip
   while ( from < end && ( to = theScript.Location( "\n", from, end )))
   {
     if ( to != from )
-        // cut out and store a command
-        aNoteBook->AddCommand( theScript.SubString( from, to - 1 ));
-      from = to + 1;
+      // cut out and store a command
+      aNoteBook->AddCommand( theScript.SubString( from, to - 1 ));
+    from = to + 1;
   }
 
   aNoteBook->ReplaceVariables();
@@ -385,12 +540,14 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString&            theScrip
 
 _pyGen::_pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod,
                Resource_DataMapOfAsciiStringAsciiString& theObjectNames,
+               std::set< TCollection_AsciiString >&      theRemovedObjIDs,
                SALOMEDS::Study_ptr&                      theStudy,
                const bool                                theToKeepAllCommands)
   : _pyObject( new _pyCommand( "", 0 )),
     myNbCommands( 0 ),
     myID2AccessorMethod( theEntry2AccessorMethod ),
     myObjectNames( theObjectNames ),
+    myRemovedObjIDs( theRemovedObjIDs ),
     myNbFilters( 0 ),
     myToKeepAllCommands( theToKeepAllCommands ),
     myStudy( SALOMEDS::Study::_duplicate( theStudy )),
@@ -406,7 +563,7 @@ _pyGen::_pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod
   {
     // find a GEOM entry
     _pyID geomID;
-    SALOMEDS::SComponent_var geomComp = theStudy->FindComponent("GEOM");
+    SALOMEDS::SComponent_wrap geomComp = theStudy->FindComponent("GEOM");
     if ( geomComp->_is_nil() ) return;
     CORBA::String_var entry = geomComp->GetID();
     geomID = entry.in();
@@ -431,7 +588,7 @@ _pyGen::_pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod
 
 //================================================================================
 /*!
- * \brief name of SMESH_Gen in smesh.py
+ * \brief name of SMESH_Gen in smeshBuilder.py
  */
 //================================================================================
 
@@ -469,12 +626,16 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
     PlaceSubmeshAfterItsCreation( aCommand );
   }
 
+  // Method( SMESH.PointStruct(x,y,z) -> Method( [x,y,z]
+  StructToList( aCommand );
+
   // Find an object to process theCommand
 
   // SMESH_Gen method?
   if ( objID == this->GetID() || objID == SMESH_2smeshpy::GenName())
   {
     this->Process( aCommand );
+    addFilterUser( aCommand, theGen ); // protect filters from clearing
     return aCommand;
   }
 
@@ -498,6 +659,11 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
       myObjects.insert( make_pair( subMeshID, subMesh ));
     }
 
+    // Method( mesh.GetIDSource([id1,id2]) -> Method( [id1,id2]
+    GetIDSourceToList( aCommand );
+
+    addFilterUser( aCommand, theGen ); // protect filters from clearing
+
     id_mesh->second->Process( aCommand );
     id_mesh->second->AddProcessedCmd( aCommand );
     return aCommand;
@@ -507,6 +673,11 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
   map< _pyID, Handle(_pyMeshEditor) >::iterator id_editor = myMeshEditors.find( objID );
   if ( id_editor != myMeshEditors.end() )
   {
+    // Method( mesh.GetIDSource([id1,id2]) -> Method( [id1,id2]
+    GetIDSourceToList( aCommand );
+
+    addFilterUser( aCommand, theGen ); // protect filters from clearing
+
     const TCollection_AsciiString& method = aCommand->GetMethod();
 
     // some commands of SMESH_MeshEditor create meshes and groups
@@ -533,10 +704,14 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
       groups = aCommand->GetResultValue(2);
     else if ( method == "MakeBoundaryElements")
       groups = aCommand->GetResultValue(3);
+    else if ( method == "Create0DElementsOnAllNodes" &&
+              aCommand->GetArg(2).Length() > 2 ) // group name != ''
+      groups = aCommand->GetResultValue();
 
     id_editor->second->Process( aCommand );
     id_editor->second->AddProcessedCmd( aCommand );
 
+    // create meshes
     if ( !meshID.IsEmpty() &&
          !myMeshes.count( meshID ) &&
          aCommand->IsStudyEntry( meshID ))
@@ -547,6 +722,7 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
       aCommand->Clear();
       aCommand->GetString() = processedCommand; // discard changes made by _pyMesh
     }
+    // create groups
     if ( !groups.IsEmpty() )
     {
       if ( !aCommand->IsStudyEntry( meshID ))
@@ -628,7 +804,7 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
     // 1    2       3         4            5           6       7        8         9             10
     // in order to avoid the problem of type mismatch of long and FunctorType
     const TCollection_AsciiString
-      SMESH("SMESH."), dfltFunctor = "SMESH.FT_Undefined", dftlTol = "1e-07", dftlPreci = "-1";
+      SMESH("SMESH."), dfltFunctor("SMESH.FT_Undefined"), dfltTol("1e-07"), dfltPreci("-1");
     TCollection_AsciiString
       Type          = aCommand->GetArg(1),  // long
       Compare       = aCommand->GetArg(2),  // long
@@ -646,6 +822,9 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
     UnaryOp  = SMESH + SMESH::FunctorTypeToString( SMESH::FunctorType( UnaryOp.IntegerValue() ));
     BinaryOp = SMESH + SMESH::FunctorTypeToString( SMESH::FunctorType( BinaryOp.IntegerValue() ));
 
+    if ( Compare == "SMESH.FT_EqualTo" )
+      Compare = "'='";
+
     aCommand->RemoveArgs();
     aCommand->SetObject( SMESH_2smeshpy::GenName() );
     aCommand->SetMethod( "GetCriterion" );
@@ -654,19 +833,36 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
     aCommand->SetArg( 2, Type );
     aCommand->SetArg( 3, Compare );
 
-    if ( Type == "SMESH.FT_ElemGeomType" && Threshold.IsIntegerValue() )
+    if ( Threshold.IsIntegerValue() )
     {
-      // set SMESH.GeometryType instead of a numerical Threshold
-      const char* types[SMESH::Geom_BALL+1] = {
-        "Geom_POINT", "Geom_EDGE", "Geom_TRIANGLE", "Geom_QUADRANGLE", "Geom_POLYGON",
-        "Geom_TETRA", "Geom_PYRAMID", "Geom_HEXA", "Geom_PENTA", "Geom_HEXAGONAL_PRISM",
-        "Geom_POLYHEDRA", "Geom_BALL"
-      };
       int iGeom = Threshold.IntegerValue();
-      if ( -1 < iGeom && iGeom < SMESH::Geom_POLYHEDRA+1 )
-        Threshold = SMESH + types[ iGeom ];
+      if ( Type == "SMESH.FT_ElemGeomType" )
+      {
+        // set SMESH.GeometryType instead of a numerical Threshold
+        const char* types[SMESH::Geom_BALL+1] = {
+          "Geom_POINT", "Geom_EDGE", "Geom_TRIANGLE", "Geom_QUADRANGLE", "Geom_POLYGON",
+          "Geom_TETRA", "Geom_PYRAMID", "Geom_HEXA", "Geom_PENTA", "Geom_HEXAGONAL_PRISM",
+          "Geom_POLYHEDRA", "Geom_BALL" };
+        if ( -1 < iGeom && iGeom < SMESH::Geom_POLYHEDRA+1 )
+          Threshold = SMESH + types[ iGeom ];
+      }
+      if (Type == "SMESH.FT_EntityType")
+      {
+        // set SMESH.EntityType instead of a numerical Threshold
+        const char* types[SMESH::Entity_Ball+1] = {
+          "Entity_Node", "Entity_0D", "Entity_Edge", "Entity_Quad_Edge",
+          "Entity_Triangle", "Entity_Quad_Triangle", "Entity_BiQuad_Triangle",
+          "Entity_Quadrangle", "Entity_Quad_Quadrangle", "Entity_BiQuad_Quadrangle",
+          "Entity_Polygon", "Entity_Quad_Polygon", "Entity_Tetra", "Entity_Quad_Tetra",
+          "Entity_Pyramid", "Entity_Quad_Pyramid",
+          "Entity_Hexa", "Entity_Quad_Hexa", "Entity_TriQuad_Hexa",
+          "Entity_Penta", "Entity_Quad_Penta", "Entity_Hexagonal_Prism",
+          "Entity_Polyhedra", "Entity_Quad_Polyhedra", "Entity_Ball" };
+        if ( -1 < iGeom && iGeom < SMESH::Entity_Quad_Polyhedra+1 )
+          Threshold = SMESH + types[ iGeom ];
+      }
     }
-    if ( ThresholdID.Length() != 2 && ThresholdStr.Length() != 2) // not '' or ""
+    if ( ThresholdID.Length() != 2 ) // neither '' nor ""
       aCommand->SetArg( 4, ThresholdID.SubString( 2, ThresholdID.Length()-1 )); // shape entry
     else if ( ThresholdStr.Length() != 2 )
       aCommand->SetArg( 4, ThresholdStr );
@@ -676,7 +872,7 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
       aCommand->SetArg( 4, Threshold );
     // find the last not default arg
     int lastDefault = 8;
-    if ( Tolerance == dftlTol ) {
+    if ( Tolerance == dfltTol ) {
       lastDefault = 7;
       if ( BinaryOp == dfltFunctor ) {
         lastDefault = 6;
@@ -687,7 +883,7 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
     if ( 5 < lastDefault ) aCommand->SetArg( 5, UnaryOp );
     if ( 6 < lastDefault ) aCommand->SetArg( 6, BinaryOp );
     if ( 7 < lastDefault ) aCommand->SetArg( 7, Tolerance );
-    if ( Precision != dftlPreci )
+    if ( Precision != dfltPreci )
     {
       TCollection_AsciiString crit = aCommand->GetResultValue();
       aCommand->GetString() += "; ";
@@ -723,22 +919,32 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
   }
   if ( method == "CreateMeshesFromUNV" ||
        method == "CreateMeshesFromSTL" ||
-       method == "CreateMeshesFromCGNS" ||
-       method == "CopyMesh" )
+       method == "CopyMesh" ) // command result is a mesh
   {
     Handle(_pyMesh) mesh = new _pyMesh( theCommand, theCommand->GetResultValue() );
     myMeshes.insert( make_pair( mesh->GetID(), mesh ));
     return;
   }
-  if( method == "CreateMeshesFromMED" || method == "CreateMeshesFromSAUV")
+  if( method == "CreateMeshesFromMED" ||
+      method == "CreateMeshesFromSAUV"||
+      method == "CreateMeshesFromCGNS" ||
+      method == "CreateMeshesFromGMF" ) // command result is ( [mesh1,mesh2], status )
   {
-    for(int ind = 0;ind<theCommand->GetNbResultValues();ind++)
+    for ( int ind = 0; ind < theCommand->GetNbResultValues(); ind++ )
     {
       _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 ));
     }
+    if ( method == "CreateMeshesFromGMF" )
+    {
+      // CreateMeshesFromGMF( theFileName, theMakeRequiredGroups ) ->
+      // CreateMeshesFromGMF( theFileName )
+      _AString file = theCommand->GetArg(1);
+      theCommand->RemoveArgs();
+      theCommand->SetArg( 1, file );
+    }
   }
 
   // CreateHypothesis()
@@ -786,7 +992,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
     }
   }
 
-  // objects erasing creation command if no more it's commands invoked:
+  // objects erasing creation command if no more its commands invoked:
   // SMESH_Pattern, FilterManager
   if ( method == "GetPattern" ||
        method == "CreateFilterManager" ||
@@ -817,7 +1023,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
 
   // Replace name of SMESH_Gen
 
-  // names of SMESH_Gen methods fully equal to methods defined in smesh.py
+  // names of SMESH_Gen methods fully equal to methods defined in smeshBuilder.py
   static TStringSet smeshpyMethods;
   if ( smeshpyMethods.empty() ) {
     const char * names[] =
@@ -830,7 +1036,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
     // smeshgen.Method() --> smesh.Method()
     theCommand->SetObject( SMESH_2smeshpy::SmeshpyName() );
   else
-    // smeshgen.Method() --> smesh.smesh.Method()
+    // smeshgen.Method() --> smesh.Method()
     theCommand->SetObject( SMESH_2smeshpy::GenName() );
 }
 
@@ -883,7 +1089,7 @@ void _pyGen::Flush()
   for ( hyp = myHypos.begin(); hyp != myHypos.end(); ++hyp )
     if ( !hyp->IsNull() ) {
       (*hyp)->Flush();
-      // smeshgen.CreateHypothesis() --> smesh.smesh.CreateHypothesis()
+      // smeshgen.CreateHypothesis() --> smesh.CreateHypothesis()
       if ( !(*hyp)->IsWrapped() )
         (*hyp)->GetCreationCmd()->SetObject( SMESH_2smeshpy::GenName() );
     }
@@ -1150,6 +1356,35 @@ void _pyGen::setNeighbourCommand( Handle(_pyCommand)& theCmd,
     (*pos)->SetOrderNb( i++ );
 }
 
+//================================================================================
+/*!
+ * \brief Call _pyFilter.AddUser() if a filter is used as a command arg
+ */
+//================================================================================
+
+void _pyGen::addFilterUser( Handle(_pyCommand)& theCommand, const Handle(_pyObject)& user )
+{
+  const char filterPrefix[] = "aFilter0x";
+  if ( theCommand->GetString().Search( filterPrefix ) < 1 )
+    return;
+
+  for ( int i = theCommand->GetNbArgs(); i > 0; --i )
+  {
+    const _AString & arg = theCommand->GetArg( i );
+    // NOT TREATED CASE: arg == "[something, aFilter0x36a2f60]"
+    if ( arg.Search( filterPrefix ) != 1 )
+      continue;
+
+    Handle(_pyFilter) filter = Handle(_pyFilter)::DownCast( FindObject( arg ));
+    if ( !filter.IsNull() )
+    {
+      filter->AddUser( user );
+      if ( !filter->GetNewID().IsEmpty() )
+        theCommand->SetArg( i, filter->GetNewID() );
+    }
+  }
+}
+
 //================================================================================
 /*!
  * \brief Set command be last in list of commands
@@ -1297,7 +1532,7 @@ bool _pyGen::IsNotPublished(const _pyID& theObjID) const
   // 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() );
+    SALOMEDS::SObject_wrap so = myStudy->FindObjectID( theObjID.ToCString() );
     if ( so->_is_nil() ) return true;
     CORBA::Object_var obj = so->GetObject();
     return CORBA::is_nil( obj );
@@ -1305,6 +1540,19 @@ bool _pyGen::IsNotPublished(const _pyID& theObjID) const
   return true; // SMESH object not in study
 }
 
+//================================================================================
+/*!
+ * \brief Add an object to myRemovedObjIDs that leads to that SetName() for
+ *        this object is not dumped
+ *  \param [in] theObjID - entry of the object whose creation command was eliminated
+ */
+//================================================================================
+
+void _pyGen::ObjectCreationRemoved(const _pyID& theObjID)
+{
+  myRemovedObjIDs.insert( theObjID );
+}
+
 //================================================================================
 /*!
  * \brief Return reader of  hypotheses of plugins
@@ -1504,11 +1752,76 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
     theGen->AddObject( group );
   }
   // ----------------------------------------------------------------------
+  // update list of groups
+  else if ( method == "GetGroups" )
+  {
+    bool allGroupsRemoved = true;
+    TCollection_AsciiString grIDs = theCommand->GetResultValue();
+    list< _pyID >          idList = theCommand->GetStudyEntries( grIDs );
+    list< _pyID >::iterator  grID = idList.begin();
+    const int nbGroupsBefore = myGroups.size();
+    Handle(_pyObject) obj;
+    for ( ; grID != idList.end(); ++grID )
+    {
+      obj = theGen->FindObject( *grID );
+      if ( obj.IsNull() )
+      {
+        Handle(_pyGroup) group = new _pyGroup( theCommand, *grID );
+        theGen->AddObject( group );
+        myGroups.push_back( group );
+        obj = group;
+      }
+      if ( !obj->CanClear() )
+        allGroupsRemoved = false;
+    }
+    if ( nbGroupsBefore == myGroups.size() ) // no new _pyGroup created
+      obj->AddProcessedCmd( theCommand ); // to clear theCommand if all groups are removed
+
+    if ( !allGroupsRemoved && !theGen->IsToKeepAllCommands() )
+    {
+      // check if the preceding command is Compute();
+      // if GetGroups() is just after Compute(), this can mean that the groups
+      // were created by some algorithm and hence Compute() should not be discarded
+      std::list< Handle(_pyCommand) >& cmdList = theGen->GetCommands();
+      std::list< Handle(_pyCommand) >::iterator cmd = cmdList.begin();
+      while ( (*cmd)->GetMethod() == "GetGroups" )
+        ++cmd;
+      if ( myLastComputeCmd == (*cmd))
+        // protect last Compute() from clearing by the next Compute()
+        myLastComputeCmd.Nullify();
+    }
+  }
+  // ----------------------------------------------------------------------
+  // notify a group about full removal
+  else if ( method == "RemoveGroupWithContents" ||
+            method == "RemoveGroup")
+  {
+    if ( !theGen->IsToKeepAllCommands() ) { // snapshot mode
+      const _pyID groupID = theCommand->GetArg( 1 );
+      Handle(_pyGroup) grp = Handle(_pyGroup)::DownCast( theGen->FindObject( groupID ));
+      if ( !grp.IsNull() )
+      {
+        if ( method == "RemoveGroupWithContents" )
+          grp->RemovedWithContents();
+        // to clear RemoveGroup() if the group creation is cleared
+        grp->AddProcessedCmd( theCommand );
+      }
+    }
+  }
+  // ----------------------------------------------------------------------
   else if ( theCommand->MethodStartsFrom( "Export" ))
   {
-    if ( method == "ExportToMED" ||   // ExportToMED()  --> ExportMED()
-         method == "ExportToMEDX" ) { // ExportToMEDX() --> ExportMED()
+    if ( method == "ExportToMED" ||  // ExportToMED()  --> ExportMED()
+         method == "ExportToMEDX" )  // ExportToMEDX() --> ExportMED()
+    {
       theCommand->SetMethod( "ExportMED" );
+      if ( theCommand->GetNbArgs() == 5 )
+      {
+        // ExportToMEDX(...,autoDimension) -> ExportToMEDX(...,meshPart=None,autoDimension)
+        _AString autoDimension = theCommand->GetArg( 5 );
+        theCommand->SetArg( 5, "None" );
+        theCommand->SetArg( 6, autoDimension );
+      }
     }
     else if ( method == "ExportCGNS" )
     { // ExportCGNS(part, ...) -> ExportCGNS(..., part)
@@ -1518,6 +1831,14 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
         theCommand->SetArg( i-1, theCommand->GetArg( i ));
       theCommand->SetArg( nbArgs, partID );
     }
+    else if ( method == "ExportGMF" )
+    { // ExportGMF(part,file,bool) -> ExportCGNS(file, part)
+      _pyID partID  = theCommand->GetArg( 1 );
+      _AString file = theCommand->GetArg( 2 );
+      theCommand->RemoveArgs();
+      theCommand->SetArg( 1, file );
+      theCommand->SetArg( 2, partID );
+    }
     else if ( theCommand->MethodStartsFrom( "ExportPartTo" ))
     { // ExportPartTo*(part, ...) -> Export*(..., part)
       //
@@ -1525,9 +1846,9 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
       TCollection_AsciiString newMethod = method;
       newMethod.Remove( 7, 6 );
       theCommand->SetMethod( newMethod );
-      // make the 1st arg be the last one
+      // make the 1st arg be the last one (or last but one for ExportMED())
       _pyID partID = theCommand->GetArg( 1 );
-      int nbArgs = theCommand->GetNbArgs();
+      int nbArgs = theCommand->GetNbArgs() - (newMethod == "ExportMED");
       for ( int i = 2; i <= nbArgs; ++i )
         theCommand->SetArg( i-1, theCommand->GetArg( i ));
       theCommand->SetArg( nbArgs, partID );
@@ -1541,26 +1862,42 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
   {
     _pyID hypID  = theCommand->GetArg( 2 );
     _pyID geomID = theCommand->GetArg( 1 );
+    bool isLocal = ( geomID != GetGeom() );
 
     // check if this mesh still has corresponding addition command
-    bool hasAddCmd = false;
-    list< Handle(_pyCommand) >::iterator cmd = myAddHypCmds.begin();
-    while ( cmd != myAddHypCmds.end() )
+    Handle(_pyCommand) addCmd;
+    list< Handle(_pyCommand) >::iterator cmd;
+    list< Handle(_pyCommand) >* addCmds[2] = { &myAddHypCmds, &myNotConvertedAddHypCmds };
+    for ( int i = 0; i < 2; ++i )
     {
-      // AddHypothesis(geom, hyp)
-      if ( hypID  == (*cmd)->GetArg( 2 ) &&
-           geomID == (*cmd)->GetArg( 1 )) { // erase both (add and remove) commands
-        theCommand->Clear();
-        (*cmd)->Clear();
-        cmd = myAddHypCmds.erase( cmd );
-        hasAddCmd = true;
-      }
-      else {
-        ++cmd;
+      list< Handle(_pyCommand )> & addHypCmds = *(addCmds[i]);
+      for ( cmd = addHypCmds.begin(); cmd != addHypCmds.end(); )
+      {
+        bool sameHyp = true;
+        if ( hypID != (*cmd)->GetArg( 1 ) && hypID != (*cmd)->GetArg( 2 ))
+          sameHyp = false; // other hyp
+        if ( (*cmd)->GetNbArgs() == 2 &&
+             geomID != (*cmd)->GetArg( 1 ) && geomID != (*cmd)->GetArg( 2 ))
+          sameHyp = false; // other geom
+        if ( (*cmd)->GetNbArgs() == 1 && isLocal )
+          sameHyp = false; // other geom
+        if ( sameHyp )
+        {
+          addCmd = *cmd;
+          cmd    = addHypCmds.erase( cmd );
+          if ( !theGen->IsToKeepAllCommands() ) {
+            addCmd->Clear();
+            theCommand->Clear();
+          }
+        }
+        else
+        {
+          ++cmd;
+        }
       }
     }
     Handle(_pyHypothesis) hyp = theGen->FindHyp( hypID );
-    if ( ! hasAddCmd && hypID.Length() != 0 ) { // hypo addition already wrapped
+    if ( !theCommand->IsEmpty() && !hypID.IsEmpty() ) {
       // RemoveHypothesis(geom, hyp) --> RemoveHypothesis( hyp, geom=0 )
       _pyID geom = theCommand->GetArg( 1 );
       theCommand->RemoveArgs();
@@ -1588,23 +1925,6 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
         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 );
-      }
-    }
-  }
   // add accessor method if necessary
   else
   {
@@ -1742,6 +2062,7 @@ void _pyMesh::Flush()
       addCmd->SetArg( 1, algoID );
       if ( isLocalAlgo )
         addCmd->SetArg( 2, geom );
+      myNotConvertedAddHypCmds.push_back( addCmd );
     }
   }
 
@@ -1762,6 +2083,7 @@ void _pyMesh::Flush()
       addCmd->SetArg( 1, hypID );
       if ( geom != GetGeom() )
         addCmd->SetArg( 2, geom );
+      myNotConvertedAddHypCmds.push_back( addCmd );
     }
   }
 
@@ -1863,7 +2185,7 @@ void _pyMesh::ClearCommands()
 
 void _pyMesh::addFatherMesh( const _pyID& meshID )
 {
-  if ( !meshID.IsEmpty() )
+  if ( !meshID.IsEmpty() && meshID != GetID() )
     addFatherMesh( Handle(_pyMesh)::DownCast( theGen->FindObject( meshID )));
 }
 
@@ -1875,7 +2197,7 @@ void _pyMesh::addFatherMesh( const _pyID& meshID )
 
 void _pyMesh::addFatherMesh( const Handle(_pyMesh)& mesh )
 {
-  if ( !mesh.IsNull() )
+  if ( !mesh.IsNull() && mesh->GetID() != GetID() )
   {
     //myFatherMeshes.push_back( mesh );
     mesh->myChildMeshes.push_back( this );
@@ -1911,51 +2233,88 @@ _pyMeshEditor::_pyMeshEditor(const Handle(_pyCommand)& theCreationCmd):
 
 void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
 {
-  // names of SMESH_MeshEditor methods fully equal to methods of python class Mesh, so
-  // commands calling this methods are converted to calls of methods of Mesh
+  // Names of SMESH_MeshEditor methods fully equal to methods of the python class Mesh, so
+  // commands calling these methods are converted to calls of Mesh methods without
+  // additional modifs, only object is changed from MeshEditor to Mesh.
   static TStringSet sameMethods;
   if ( sameMethods.empty() ) {
     const char * names[] = {
-      "RemoveElements","RemoveNodes","RemoveOrphanNodes","AddNode","Add0DElement","AddEdge","AddFace","AddPolygonalFace","AddBall",
-      "AddVolume","AddPolyhedralVolume","AddPolyhedralVolumeByFaces","MoveNode", "MoveClosestNodeToPoint",
-      "InverseDiag","DeleteDiag","Reorient","ReorientObject","TriToQuad","SplitQuad","SplitQuadObject",
+      "RemoveElements","RemoveNodes","RemoveOrphanNodes",
+      "AddNode","Add0DElement","AddEdge","AddFace","AddPolygonalFace","AddBall",
+      "AddVolume","AddPolyhedralVolume","AddPolyhedralVolumeByFaces",
+      "MoveNode", "MoveClosestNodeToPoint",
+      "InverseDiag","DeleteDiag","Reorient","ReorientObject",
+      "TriToQuad","TriToQuadObject", "QuadTo4Tri", "SplitQuad","SplitQuadObject",
       "BestSplit","Smooth","SmoothObject","SmoothParametric","SmoothParametricObject",
       "ConvertToQuadratic","ConvertFromQuadratic","RenumberNodes","RenumberElements",
       "RotationSweep","RotationSweepObject","RotationSweepObject1D","RotationSweepObject2D",
-      "ExtrusionSweep","AdvancedExtrusion","ExtrusionSweepObject","ExtrusionSweepObject1D","ExtrusionSweepObject2D",
-      "ExtrusionAlongPath","ExtrusionAlongPathObject","ExtrusionAlongPathX",
-      "ExtrusionAlongPathObject1D","ExtrusionAlongPathObject2D",
+      "ExtrusionSweep","AdvancedExtrusion","ExtrusionSweepObject","ExtrusionSweepObject1D",
+      "ExtrusionSweepObject2D","ExtrusionAlongPath","ExtrusionAlongPathObject",
+      "ExtrusionAlongPathX","ExtrusionAlongPathObject1D","ExtrusionAlongPathObject2D",
       "Mirror","MirrorObject","Translate","TranslateObject","Rotate","RotateObject",
-      "FindCoincidentNodes",/*"FindCoincidentNodesOnPart",*/"MergeNodes","FindEqualElements",
+      "FindCoincidentNodes","MergeNodes","FindEqualElements",
       "MergeElements","MergeEqualElements","SewFreeBorders","SewConformFreeBorders",
       "SewBorderToSide","SewSideElements","ChangeElemNodes","GetLastCreatedNodes",
       "GetLastCreatedElems",
-      "MirrorMakeMesh","MirrorObjectMakeMesh","TranslateMakeMesh",
-      "TranslateObjectMakeMesh","RotateMakeMesh","RotateObjectMakeMesh","MakeBoundaryMesh",
-      "MakeBoundaryElements", "SplitVolumesIntoTetra"
+      "MirrorMakeMesh","MirrorObjectMakeMesh","TranslateMakeMesh","TranslateObjectMakeMesh",
+      "Scale","ScaleMakeMesh","RotateMakeMesh","RotateObjectMakeMesh","MakeBoundaryMesh",
+      "MakeBoundaryElements", "SplitVolumesIntoTetra",
+      "DoubleElements","DoubleNodes","DoubleNode","DoubleNodeGroup","DoubleNodeGroups",
+      "DoubleNodeElem","DoubleNodeElemInRegion","DoubleNodeElemGroup",
+      "DoubleNodeElemGroupInRegion","DoubleNodeElemGroups","DoubleNodeElemGroupsInRegion",
+      "DoubleNodesOnGroupBoundaries","CreateFlatElementsOnFacesGroups","CreateHoleSkin"
       ,"" }; // <- mark of the end
     sameMethods.Insert( names );
   }
 
-  // names of SMESH_MeshEditor methods which differ from methods of class Mesh
+  // names of SMESH_MeshEditor commands in which only a method name must be replaced
+  TStringMap diffMethods;
+  if ( diffMethods.empty() ) {
+    const char * orig2newName[] = {
+      // original name --------------> new name
+      "ExtrusionAlongPathObjX"      , "ExtrusionAlongPathX",
+      "FindCoincidentNodesOnPartBut", "FindCoincidentNodesOnPart",
+      "ConvertToQuadraticObject"    , "ConvertToQuadratic",
+      "ConvertFromQuadraticObject"  , "ConvertFromQuadratic",
+      "Create0DElementsOnAllNodes"  , "Add0DElementsToAllNodes",
+      ""};// <- mark of the end
+    diffMethods.Insert( orig2newName );
+  }
+
+  // names of SMESH_MeshEditor methods which differ from methods of Mesh class
   // only by last two arguments
   static TStringSet diffLastTwoArgsMethods;
   if (diffLastTwoArgsMethods.empty() ) {
     const char * names[] = {
       "MirrorMakeGroups","MirrorObjectMakeGroups",
-      "TranslateMakeGroups","TranslateObjectMakeGroups",
+      "TranslateMakeGroups","TranslateObjectMakeGroups","ScaleMakeGroups",
       "RotateMakeGroups","RotateObjectMakeGroups",
       ""};// <- mark of the end
     diffLastTwoArgsMethods.Insert( names );
   }
 
+  // only a method name is to change?
   const TCollection_AsciiString & method = theCommand->GetMethod();
   bool isPyMeshMethod = sameMethods.Contains( method );
   if ( !isPyMeshMethod )
   {
-    //Replace SMESH_MeshEditor "MakeGroups" functions by the Mesh
-    //functions with the flag "theMakeGroups = True" like:
-    //SMESH_MeshEditor.CmdMakeGroups => Mesh.Cmd(...,True)
+    TCollection_AsciiString newMethod = diffMethods.Value( method );
+    if (( isPyMeshMethod = ( newMethod.Length() > 0 )))
+      theCommand->SetMethod( newMethod );
+  }
+  // ConvertToBiQuadratic(...) -> ConvertToQuadratic(...,True)
+  if ( !isPyMeshMethod && (method == "ConvertToBiQuadratic" || method == "ConvertToBiQuadraticObject") )
+  {
+    isPyMeshMethod = true;
+    theCommand->SetMethod( method.SubString( 1, 9) + method.SubString( 12, method.Length()));
+    theCommand->SetArg( theCommand->GetNbArgs() + 1, "True" );
+  }
+
+  if ( !isPyMeshMethod )
+  {
+    // Replace SMESH_MeshEditor "*MakeGroups" functions by the Mesh
+    // functions with the flag "theMakeGroups = True" like:
+    // SMESH_MeshEditor.CmdMakeGroups => Mesh.Cmd(...,True)
     int pos = method.Search("MakeGroups");
     if( pos != -1)
     {
@@ -1980,7 +2339,7 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
     }
   }
 
-  // ExtrusionSweep0D() -> ExtrusionSweep()
+  // ExtrusionSweep0D()       -> ExtrusionSweep()
   // ExtrusionSweepObject0D() -> ExtrusionSweepObject()
   if ( !isPyMeshMethod && ( method == "ExtrusionSweep0D"  ||
                             method == "ExtrusionSweepObject0D" ))
@@ -1990,19 +2349,7 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
     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")
-  {
-    isPyMeshMethod = true;
-    theCommand->SetMethod("ExtrusionAlongPathX");
-  }
 
-  // set "FindCoincidentNodesOnPart()" instead of "FindCoincidentNodesOnPartBut()"
-  if ( !isPyMeshMethod && method == "FindCoincidentNodesOnPartBut")
-  {
-    isPyMeshMethod = true;
-    theCommand->SetMethod("FindCoincidentNodesOnPart");
-  }
   // DoubleNode...New(...) -> DoubleNode...(...,True)
   if ( !isPyMeshMethod && ( method == "DoubleNodeElemGroupNew"  ||
                             method == "DoubleNodeElemGroupsNew" ||
@@ -2027,14 +2374,6 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
       theCommand->SetResultValue( groupID );
     }
   }
-  // ConvertToQuadraticObject(bool,obj) -> ConvertToQuadratic(bool,obj)
-  // ConvertFromQuadraticObject(obj) -> ConvertFromQuadratic(obj)
-  if ( !isPyMeshMethod && ( method == "ConvertToQuadraticObject" ||
-                            method == "ConvertFromQuadraticObject" ))
-  {
-    isPyMeshMethod = true;
-    theCommand->SetMethod( method.SubString( 1, method.Length()-6));
-  }
   // FindAmongElementsByPoint(meshPart, x, y, z, elementType) ->
   // FindElementsByPoint(x, y, z, elementType, meshPart)
   if ( !isPyMeshMethod && method == "FindAmongElementsByPoint" )
@@ -2065,10 +2404,15 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
       theCommand->SetArg( 3, face );
   }
 
-  // meshes made by *MakeMesh() methods are not wrapped by _pyMesh,
-  // so let _pyMesh care of it (TMP?)
-  //     if ( theCommand->GetMethod().Search("MakeMesh") != -1 )
-  //       _pyMesh( new _pyCommand( theCommand->GetString(), 0 )); // for theGen->SetAccessorMethod()
+  if ( method == "QuadToTri" || method == "QuadToTriObject" )
+  {
+    isPyMeshMethod = true;
+    int crit_arg = theCommand->GetNbArgs();
+    const _AString& crit = theCommand->GetArg(crit_arg);
+    if (crit.Search("MaxElementLength2D") != -1)
+      theCommand->SetArg(crit_arg, "");
+  }
+
   if ( isPyMeshMethod )
   {
     theCommand->SetObject( myMesh );
@@ -2076,7 +2420,7 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
   else
   {
     // editor creation command is needed only if any editor function is called
-    theGen->AddMeshAccessorMethod( theCommand ); // for *Object()
+    theGen->AddMeshAccessorMethod( theCommand ); // for *Object() methods
     if ( !myCreationCmdStr.IsEmpty() ) {
       GetCreationCmd()->GetString() = myCreationCmdStr;
       myCreationCmdStr.Clear();
@@ -2888,18 +3232,23 @@ void _pyNumberOfSegmentsHyp::Flush()
   list<Handle(_pyCommand)>::reverse_iterator cmd = myUnusedCommands.rbegin();
   int distrTypeNb = 0;
   for ( ; !distrTypeNb && cmd != myUnusedCommands.rend(); ++cmd )
-    if ( (*cmd)->GetMethod() == "SetDistrType" )
-      distrTypeNb = (*cmd)->GetOrderNb();
-    else if (IsWrapped() && (*cmd)->GetMethod() == "SetObjectEntry" )
+    if ( (*cmd)->GetMethod() == "SetDistrType" ) {
+      if ( cmd != myUnusedCommands.rbegin() )
+        distrTypeNb = (*cmd)->GetOrderNb();
+    }
+    else if (IsWrapped() && (*cmd)->GetMethod() == "SetObjectEntry" ) {
       (*cmd)->Clear();
-
+    }
   // clear commands before the last SetDistrType()
   list<Handle(_pyCommand)> * cmds[2] = { &myArgCommands, &myUnusedCommands };
+  set< int > treatedCmdNbs; // avoid treating same cmd twice
   for ( int i = 0; i < 2; ++i ) {
     set<TCollection_AsciiString> uniqueMethods;
     list<Handle(_pyCommand)> & cmdList = *cmds[i];
     for ( cmd = cmdList.rbegin(); cmd != cmdList.rend(); ++cmd )
     {
+      if ( !treatedCmdNbs.insert( (*cmd)->GetOrderNb() ).second )
+        continue;// avoid treating same cmd twice
       bool clear = ( (*cmd)->GetOrderNb() < distrTypeNb );
       const TCollection_AsciiString& method = (*cmd)->GetMethod();
       if ( !clear || method == "SetNumberOfSegments" ) {
@@ -3003,6 +3352,7 @@ int _pyCommand::GetBegPos( int thePartIndex )
     return EMPTY;
   if ( myBegPos.Length() < thePartIndex )
     return UNKNOWN;
+  ASSERT( thePartIndex > 0 );
   return myBegPos( thePartIndex );
 }
 
@@ -3018,6 +3368,7 @@ void _pyCommand::SetBegPos( int thePartIndex, int thePosition )
 {
   while ( myBegPos.Length() < thePartIndex )
     myBegPos.Append( UNKNOWN );
+  ASSERT( thePartIndex > 0 );
   myBegPos( thePartIndex ) = thePosition;
 }
 
@@ -3070,22 +3421,21 @@ const TCollection_AsciiString & _pyCommand::GetResultValue()
 //================================================================================
 /*!
  * \brief Return number of python command result value ResultValue = Obj.Meth()
-  * \retval const int
  */
 //================================================================================
 
-const int _pyCommand::GetNbResultValues()
+int _pyCommand::GetNbResultValues()
 {
+  int nb     = 0;
   int begPos = 1;
-  int Nb=0;
   int endPos = myString.Location( "=", 1, Length() );
-  TCollection_AsciiString str = "";
-  while ( begPos < endPos) {
-    str = GetWord( myString, begPos, true );
+  while ( begPos < endPos )
+  {
+    _AString str = GetWord( myString, begPos, true );
     begPos = begPos+ str.Length();
-    Nb++;
+    nb++;
   }
-  return (Nb-1);
+  return (nb-1);
 }
 
 
@@ -3148,19 +3498,22 @@ const TCollection_AsciiString & _pyCommand::GetObject()
         begPos = 1;
     }
     myObj = GetWord( myString, begPos, true );
-    // check if object is complex,
-    // so far consider case like "smesh.smesh.Method()"
-    if ( int bracketPos = myString.Location( "(", begPos, Length() )) {
-      //if ( bracketPos==0 ) bracketPos = Length();
-      int dotPos = begPos+myObj.Length();
-      while ( dotPos+1 < bracketPos ) {
-        if ( int pos = myString.Location( ".", dotPos+1, bracketPos ))
-          dotPos = pos;
-        else
-          break;
+    if ( begPos != EMPTY )
+    {
+      // check if object is complex,
+      // so far consider case like "smesh.Method()"
+      if ( int bracketPos = myString.Location( "(", begPos, Length() )) {
+        //if ( bracketPos==0 ) bracketPos = Length();
+        int dotPos = begPos+myObj.Length();
+        while ( dotPos+1 < bracketPos ) {
+          if ( int pos = myString.Location( ".", dotPos+1, bracketPos ))
+            dotPos = pos;
+          else
+            break;
+        }
+        if ( dotPos > begPos+myObj.Length() )
+          myObj = myString.SubString( begPos, dotPos-1 );
       }
-      if ( dotPos > begPos+myObj.Length() )
-        myObj = myString.SubString( begPos, dotPos-1 );
     }
     // 1st word after '=' is an object
     // else // no method -> no object
@@ -3523,7 +3876,7 @@ void _pyCommand::SetArg( int index, const TCollection_AsciiString& theArg)
 
 void _pyCommand::RemoveArgs()
 {
-  if ( int pos = myString.Location( '(', 1, Length() ))
+  if ( int pos = myString.Location( '(', Max( 1, GetBegPos( METHOD_IND )), Length() ))
     myString.Trunc( pos );
   myString += ")";
   myArgs.Clear();
@@ -3546,11 +3899,11 @@ void _pyCommand::Comment()
   if ( i <= Length() )
   {
     myString.Insert( i, "#" );
-    for ( int iPart = 0; iPart < myBegPos.Length(); ++iPart )
+    for ( int iPart = 1; iPart <= myBegPos.Length(); ++iPart )
     {
-      int begPos = GetBegPos( iPart );
+      int begPos = GetBegPos( iPart + 1 );
       if ( begPos != UNKNOWN )
-        SetBegPos( iPart, begPos + 1 );
+        SetBegPos( iPart + 1, begPos + 1 );
     }
   }
 }
@@ -3696,7 +4049,16 @@ _pyID _pyObject::FatherID(const _pyID & childID)
 
 void _pySelfEraser::Flush()
 {
-  if ( GetNbCalls() == 0 )
+  int nbCalls = GetNbCalls();
+  if ( nbCalls > 0 )
+  {
+    // ignore cleared commands
+    std::list< Handle(_pyCommand) >& cmds = GetProcessedCmds();
+    std::list< Handle(_pyCommand) >::const_iterator cmd = cmds.begin();
+    for ( ; cmd != cmds.end(); ++cmd )
+      nbCalls -= (*cmd)->IsEmpty();
+  }
+  if ( nbCalls < 1 )
     GetCreationCmd()->Clear();
 }
 
@@ -3748,7 +4110,7 @@ bool _pySubMesh::CanBeArgOfMethod(const _AString& theMethodName)
       "TranslateObjectMakeGroups","TranslateObjectMakeMesh","ScaleMakeGroups","ScaleMakeMesh",
       "RotateObject","RotateObjectMakeGroups","RotateObjectMakeMesh","FindCoincidentNodesOnPart",
       "FindCoincidentNodesOnPartBut","FindEqualElements","FindAmongElementsByPoint",
-      "MakeBoundaryMesh",
+      "MakeBoundaryMesh","Create0DElementsOnAllNodes",
       "" }; // <- mark of end
     methods.Insert( names );
   }
@@ -3838,6 +4200,10 @@ _pyGroup::_pyGroup(const Handle(_pyCommand)& theCreationCmd, const _pyID & id)
     }
     myFilter = filter;
   }
+  else if ( method == "GetGroups" )
+  {
+    myCanClearCreationCmd = ( theCreationCmd->GetNbResultValues() == 1 );
+  }
   else
   {
     // theCreationCmd does something else apart from creation of this group
@@ -3846,6 +4212,60 @@ _pyGroup::_pyGroup(const Handle(_pyCommand)& theCreationCmd, const _pyID & id)
   }
 }
 
+//================================================================================
+/*!
+ * \brief Check if "[ group1, group2 ] = mesh.GetGroups()" creation command 
+ *        can be cleared
+ */
+//================================================================================
+
+bool _pyGroup::CanClear()
+{
+  if ( IsInStudy() )
+    return false;
+
+  if ( !myCanClearCreationCmd && myCreationCmd->GetMethod() == "GetGroups" )
+  {
+    TCollection_AsciiString grIDs = myCreationCmd->GetResultValue();
+    list< _pyID >          idList = myCreationCmd->GetStudyEntries( grIDs );
+    list< _pyID >::iterator  grID = idList.begin();
+    if ( GetID() == *grID )
+    {
+      myCanClearCreationCmd = true;
+      list< Handle(_pyGroup ) > groups;
+      for ( ; grID != idList.end(); ++grID )
+      {
+        Handle(_pyGroup) group = Handle(_pyGroup)::DownCast( theGen->FindObject( *grID ));
+        if ( group.IsNull() ) continue;
+        groups.push_back( group );
+        if ( group->IsInStudy() )
+          myCanClearCreationCmd = false;
+      }
+      // set myCanClearCreationCmd == true to all groups
+      list< Handle(_pyGroup ) >::iterator group = groups.begin();
+      for ( ; group != groups.end(); ++group )
+        (*group)->myCanClearCreationCmd = myCanClearCreationCmd;
+    }
+  }
+
+  return myCanClearCreationCmd;
+}
+
+//================================================================================
+/*!
+ * \brief set myCanClearCreationCmd = true if the main action of the creation
+ *        command is discarded
+ */
+//================================================================================
+
+void _pyGroup::RemovedWithContents()
+{
+  // this code would be appropriate if Add0DElementsToAllNodes() returned only new nodes
+  // via a created group
+  //if ( GetCreationCmd()->GetMethod() == "Add0DElementsToAllNodes")
+  // myCanClearCreationCmd = true;
+}
+
 //================================================================================
 /*!
  * \brief To convert creation of a group by filter
@@ -3923,8 +4343,6 @@ void _pyGroup::Process( const Handle(_pyCommand)& theCommand)
 //================================================================================
 /*!
  * \brief Prevent clearing "DoubleNode...() command if a group created by it is removed
- * 
- * 
  */
 //================================================================================