Salome HOME
Merging with WPdev
[modules/smesh.git] / src / SMESH / SMESH_subMesh.cxx
index a2c73ac6dbe793d38b1725d89d872fed4a9971e7..7c290171fca60a2daee8f0edbf82a36b68806d7e 100644 (file)
@@ -17,7 +17,7 @@
 //  License along with this library; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-//  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
+//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 //
 //
@@ -26,8 +26,9 @@
 //  Module : SMESH
 //  $Header$
 
-using namespace std;
 #include "SMESH_subMesh.hxx"
+
+#include "SMESH_subMeshEventListener.hxx"
 #include "SMESH_Gen.hxx"
 #include "SMESH_Mesh.hxx"
 #include "SMESH_Hypothesis.hxx"
@@ -186,22 +187,30 @@ bool SMESH_subMesh::SubMeshesComputed()
   //MESSAGE("SMESH_subMesh::SubMeshesComputed");
   const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
 
+  int myDim = SMESH_Gen::GetShapeDim( _subShape );
+  int dimToCheck = myDim - 1;
   bool subMeshesComputed = true;
   map < int, SMESH_subMesh * >::const_iterator itsub;
   for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
   {
     SMESH_subMesh *sm = (*itsub).second;
+    const TopoDS_Shape & ss = sm->GetSubShape();
+    // MSV 07.04.2006: restrict checking to myDim-1 only. Ex., there is no sense
+    // in checking of existence of edges if the algo needs only faces. Moreover,
+    // degenerated edges may have no submesh, as after computing NETGEN_2D.
+    int dim = SMESH_Gen::GetShapeDim( ss );
+    if (dim < dimToCheck)
+      continue;
     SMESHDS_SubMesh * ds = sm->GetSubMeshDS();
     // PAL10974.
     // There are some tricks with compute states, e.g. Penta_3D leaves
     // one face with READY_TO_COMPUTE state in order to be able to
     // recompute 3D when a locale triangle hypo changes (see PAL7428).
     // So we check if mesh is really present
-    //bool computeOk = (sm->GetComputeState() == COMPUTE_OK);
-    bool computeOk = ( ds && ( ds->GetNodes()->more() || ds->GetElements()->more() ));
+    bool computeOk = (sm->GetComputeState() == COMPUTE_OK ||
+                      (ds && ( ds->GetNodes()->more() || ds->GetElements()->more() )));
     if (!computeOk)
     {
-      const TopoDS_Shape & ss = sm->GetSubShape();
       int type = ss.ShapeType();
 
       subMeshesComputed = false;
@@ -460,7 +469,7 @@ bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) cons
 
 //=======================================================================
 //function : IsApplicableHypotesis
-//purpose  : 
+//purpose  :
 //=======================================================================
 
 bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis,
@@ -472,11 +481,20 @@ bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis,
 
   // hypothesis
   switch ( theShapeType ) {
-  case TopAbs_EDGE: 
-  case TopAbs_FACE: 
-  case TopAbs_SHELL:
+  case TopAbs_EDGE:
+  case TopAbs_FACE:
   case TopAbs_SOLID:
     return SMESH_Gen::GetShapeDim( theShapeType ) == theHypothesis->GetDim();
+
+  case TopAbs_SHELL:
+    // Special case for algorithms, building 2D mesh on a whole shell.
+    // Before this fix there was a problem after restoring from study,
+    // because in that case algorithm is assigned before hypothesis
+    // (on shell in problem case) and hypothesis is checked on faces
+    // (because it is 2D), where we have NO_ALGO state.
+    // Now 2D hypothesis is also applicable to shells.
+    return (theHypothesis->GetDim() == 2 || theHypothesis->GetDim() == 3);
+
 //   case TopAbs_WIRE:
 //   case TopAbs_COMPSOLID:
 //   case TopAbs_COMPOUND:
@@ -515,8 +533,8 @@ SMESH_Hypothesis::Hypothesis_Status
       return SMESH_Hypothesis::HYP_OK;
   }
 
-  SMESH_Gen* gen =_father->GetGen();
-//  bool ret = false;
+  SMESH_Gen* gen   =_father->GetGen();
+  SMESH_Algo* algo = 0;
   int oldAlgoState = _algoState;
   bool modifiedHyp = false;  // if set to true, force event MODIF_ALGO_STATE
                              // in ComputeStateEngine
@@ -634,6 +652,19 @@ SMESH_Hypothesis::Hypothesis_Status
         ret = SMESH_Hypothesis::HYP_CONCURENT;
       }
     } // Serve Propagation of 1D hypothesis
+    else // event == REMOVE_ALGO
+    {
+      algo = dynamic_cast<SMESH_Algo*> (anHyp);
+      if (!algo->NeedDescretBoundary())
+      {
+        // clean all mesh in the tree of the current submesh;
+        // we must perform it now because later
+        // we will have no information about the type of the removed algo
+        CleanDependants();
+       ComputeStateEngine( CLEAN );
+        CleanDependsOn();
+      }
+    }
   }
 
   // ------------------
@@ -652,10 +683,14 @@ SMESH_Hypothesis::Hypothesis_Status
     case ADD_HYP:
       break;
     case ADD_ALGO: {
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       ASSERT(algo);
       if (algo->CheckHypothesis((*_father),_subShape, aux_ret))
         SetAlgoState(HYP_OK);
+      else if ( algo->IsStatusFatal( aux_ret )) {
+        _meshDS->RemoveHypothesis(_subShape, anHyp);
+        ret = aux_ret;
+      }
       else
         SetAlgoState(MISSING_HYP);
       break;
@@ -667,7 +702,7 @@ SMESH_Hypothesis::Hypothesis_Status
     case ADD_FATHER_HYP:
       break;
     case ADD_FATHER_ALGO: {    // Algo just added in father
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       ASSERT(algo);
       if ( algo == anHyp ) {
         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret))
@@ -680,7 +715,7 @@ SMESH_Hypothesis::Hypothesis_Status
     case REMOVE_FATHER_HYP:
       break;
     case REMOVE_FATHER_ALGO: {
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       if (algo)
       {
         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
@@ -702,7 +737,7 @@ SMESH_Hypothesis::Hypothesis_Status
     switch (event)
     {
     case ADD_HYP: {
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, ret ))
         SetAlgoState(HYP_OK);
@@ -716,10 +751,14 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case ADD_ALGO: {           //already existing algo : on father ?
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))// ignore hyp status
         SetAlgoState(HYP_OK);
+      else if ( algo->IsStatusFatal( aux_ret )) {
+        _meshDS->RemoveHypothesis(_subShape, anHyp);
+        ret = aux_ret;
+      }
       else
         SetAlgoState(MISSING_HYP);
       break;
@@ -727,7 +766,7 @@ SMESH_Hypothesis::Hypothesis_Status
     case REMOVE_HYP:
       break;
     case REMOVE_ALGO: {        // perhaps a father algo applies ?
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       if (algo == NULL)  // no more algo applying on subShape...
       {
         SetAlgoState(NO_ALGO);
@@ -742,16 +781,16 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case ADD_FATHER_HYP: {
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
         SetAlgoState(HYP_OK);
       else
         SetAlgoState(MISSING_HYP);
-    }
       break;
+    }
     case ADD_FATHER_ALGO: { // new father algo
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       ASSERT( algo );
       if ( algo == anHyp ) {
         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
@@ -764,7 +803,7 @@ SMESH_Hypothesis::Hypothesis_Status
     case REMOVE_FATHER_HYP:    // nothing to do
       break;
     case REMOVE_FATHER_ALGO: {
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       if (algo == NULL)  // no more applying algo on father
       {
         SetAlgoState(NO_ALGO);
@@ -790,7 +829,7 @@ SMESH_Hypothesis::Hypothesis_Status
     switch (event)
     {
     case ADD_HYP: {
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       ASSERT(algo);
       if (!algo->CheckHypothesis((*_father),_subShape, ret ))
       {
@@ -813,7 +852,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case ADD_ALGO: {           //already existing algo : on father ?
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
         // check if algo changes
         SMESH_HypoFilter f;
@@ -821,7 +860,7 @@ SMESH_Hypothesis::Hypothesis_Status
         f.And(    SMESH_HypoFilter::IsApplicableTo( _subShape ));
         f.AndNot( SMESH_HypoFilter::Is( algo ));
         const SMESH_Hypothesis * prevAlgo = _father->GetHypothesis( _subShape, f, true );
-        if (prevAlgo && 
+        if (prevAlgo &&
             string(algo->GetName()) != string(prevAlgo->GetName()) )
           modifiedHyp = true;
       }
@@ -830,7 +869,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case REMOVE_HYP: {
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
         SetAlgoState(HYP_OK);
@@ -840,7 +879,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case REMOVE_ALGO: {         // perhaps a father algo applies ?
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       if (algo == NULL)   // no more algo applying on subShape...
       {
         SetAlgoState(NO_ALGO);
@@ -858,7 +897,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case ADD_FATHER_HYP: {  // new father hypothesis ?
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
       {
@@ -870,7 +909,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case ADD_FATHER_ALGO: {
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       if ( algo == anHyp ) { // a new algo on father
         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
           // check if algo changes
@@ -879,7 +918,7 @@ SMESH_Hypothesis::Hypothesis_Status
           f.And(    SMESH_HypoFilter::IsApplicableTo( _subShape ));
           f.AndNot( SMESH_HypoFilter::Is( algo ));
           const SMESH_Hypothesis* prevAlgo = _father->GetHypothesis( _subShape, f, true );
-          if (prevAlgo && 
+          if (prevAlgo &&
               string(algo->GetName()) != string(prevAlgo->GetName()) )
             modifiedHyp = true;
         }
@@ -889,7 +928,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case REMOVE_FATHER_HYP: {
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
         // is there the same local hyp or maybe a new father algo applied?
@@ -901,7 +940,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case REMOVE_FATHER_ALGO: {
-      SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+      algo = gen->GetAlgo((*_father), _subShape);
       if (algo == NULL)  // no more applying algo on father
       {
         SetAlgoState(NO_ALGO);
@@ -931,7 +970,16 @@ SMESH_Hypothesis::Hypothesis_Status
     break;
   }
 
-  if ((_algoState != oldAlgoState) || modifiedHyp)
+  if ( _algoState != oldAlgoState )
+  {
+    if (_algoState == HYP_OK )
+      algo->SetEventListener( this );
+    if ( oldAlgoState == HYP_OK )
+      DeleteOwnListeners();
+  }
+  NotifyListenersOnEvent( event, ALGO_EVENT, anHyp );
+
+  if (_algoState != oldAlgoState || modifiedHyp)
     ComputeStateEngine(MODIF_ALGO_STATE);
 
   return ret;
@@ -1038,9 +1086,6 @@ SMESH_Hypothesis::Hypothesis_Status
 void SMESH_subMesh::CleanDependsOn()
 {
   //MESSAGE("SMESH_subMesh::CleanDependsOn");
-  // **** parcourir les ancetres dans l'ordre de dépendance
-
-  ComputeStateEngine(CLEAN);
 
   const map < int, SMESH_subMesh * >&dependson = DependsOn();
   map < int, SMESH_subMesh * >::const_iterator its;
@@ -1160,6 +1205,7 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
   SMESH_Algo *algo = 0;
   bool ret = true;
   SMESH_Hypothesis::Hypothesis_Status hyp_status;
+  algo_state oldAlgoState = (algo_state) GetAlgoState();
 
   switch (_computeState)
   {
@@ -1169,13 +1215,21 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
   case NOT_READY:
     switch (event)
     {
-    case MODIF_HYP:            // nothing to do
-      break;
+    case MODIF_HYP:
     case MODIF_ALGO_STATE:
-      if (_algoState == HYP_OK)
+      algo = gen->GetAlgo((*_father), _subShape);
+      if (algo && !algo->NeedDescretBoundary())
+        CleanDependsOn(); // clean sub-meshes with event CLEAN
+      if (algo)
       {
-        _computeState = READY_TO_COMPUTE;
+        ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
+        if (ret)
+          _computeState = READY_TO_COMPUTE;
       }
+      if ( _computeState == READY_TO_COMPUTE )
+          SetAlgoState(HYP_OK);
+      else
+          SetAlgoState(MISSING_HYP);
       break;
     case COMPUTE:              // nothing to do
       break;
@@ -1205,16 +1259,21 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
   case READY_TO_COMPUTE:
     switch (event)
     {
-    case MODIF_HYP:            // nothing to do
-      break;
+    case MODIF_HYP:
     case MODIF_ALGO_STATE:
-      _computeState = NOT_READY;
       algo = gen->GetAlgo((*_father), _subShape);
+      if (algo && !algo->NeedDescretBoundary())
+        CleanDependsOn(); // clean sub-meshes with event CLEAN
+      _computeState = NOT_READY;
       if (algo)
       {
         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
-        if (ret)
+        if (ret) {
+          SetAlgoState(HYP_OK); // it might be KO if BAD_PARAM_VALUE
           _computeState = READY_TO_COMPUTE;
+        }
+        else
+          SetAlgoState(MISSING_HYP);
       }
       break;
     case COMPUTE:
@@ -1226,6 +1285,7 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
         {
           MESSAGE("***** verify compute state *****");
           _computeState = NOT_READY;
+          SetAlgoState(MISSING_HYP);
           break;
         }
         // check submeshes needed
@@ -1240,25 +1300,33 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
         // compute
         CleanDependants();
         RemoveSubMeshElementsAndNodes();
-        try {
-          if (!algo->NeedDescretBoundary() && !algo->OnlyUnaryInput())
-            ret = ApplyToCollection( algo, GetCollection( gen, algo ) );
-          else
-            ret = algo->Compute((*_father), _subShape);
-        }
-        catch (Standard_Failure) {
-          MESSAGE( "Exception in algo->Compute() ");
-          ret = false;
-        }
+       {
+         try {
+#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
+            OCC_CATCH_SIGNALS;
+#endif
+           if (!algo->NeedDescretBoundary() && !algo->OnlyUnaryInput())
+             ret = ApplyToCollection( algo, GetCollection( gen, algo ) );
+           else
+             ret = algo->Compute((*_father), _subShape);
+         }
+         catch (Standard_Failure) {
+           MESSAGE( "Exception in algo->Compute() ");
+           ret = false;
+         }
+       }
         if (!ret)
         {
           MESSAGE("problem in algo execution: failed to compute");
+          // release ALGO from responsibilty of partially built mesh
+          RemoveSubMeshElementsAndNodes();
           _computeState = FAILED_TO_COMPUTE;
           if (!algo->NeedDescretBoundary())
             UpdateSubMeshState( FAILED_TO_COMPUTE );
 
 #ifdef _DEBUG_
           // Show vertices location of a failed shape
+          cout << algo->GetName() << " failed on shape with the following vertices:" << endl;
           TopTools_IndexedMapOfShape vMap;
           TopExp::MapShapes( _subShape, TopAbs_VERTEX, vMap );
           for ( int iv = 1; iv <= vMap.Extent(); ++iv ) {
@@ -1287,6 +1355,8 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
         if (ret)
           _computeState = READY_TO_COMPUTE;
+        else
+          SetAlgoState(MISSING_HYP);
       }
       break;
     case SUBMESH_COMPUTED:      // nothing to do
@@ -1333,6 +1403,8 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
         if (ret)
           _computeState = READY_TO_COMPUTE;
+        else
+          SetAlgoState(MISSING_HYP);
       }
       break;
     case SUBMESH_COMPUTED:      // nothing to do
@@ -1418,6 +1490,15 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
     break;
   }
 
+  if ( _algoState != oldAlgoState || event == MODIF_HYP )
+  {
+    if ( oldAlgoState == HYP_OK )
+      DeleteOwnListeners();
+    if (_algoState == HYP_OK && algo )
+      algo->SetEventListener( this );
+  }
+  NotifyListenersOnEvent( event, COMPUTE_EVENT );
+
   //SCRUTE(_computeState);
   return ret;
 }
@@ -1586,11 +1667,9 @@ bool SMESH_subMesh::IsMeshComputed() const
       TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
       for ( ; exp.More(); exp.Next() )
       {
-        SMESHDS_SubMesh * subMeshDS = _meshDS->MeshElements( exp.Current() );
-        if ( subMeshDS != NULL &&
-            (subMeshDS->GetElements()->more() || subMeshDS->GetNodes()->more())) {
+        SMESHDS_SubMesh * smDS = _meshDS->MeshElements( exp.Current() );
+        if ( smDS && ( smDS->NbElements() || smDS->NbNodes()))
           return true;
-        }
       }
     }
     else
@@ -1713,3 +1792,150 @@ SMESH_Hypothesis::Hypothesis_Status
   }
   return SMESH_Hypothesis::HYP_OK;
 }
+
+//================================================================================
+/*!
+ * \brief Sets an event listener and its data to a submesh
+ * \param listener - the listener to store
+ * \param data - the listener data to store
+ * \param where - the submesh to store the listener and it's data
+ * \param deleteListener - if true then the listener will be deleted as
+ *        it is removed from where submesh
+ * 
+ * It remembers the submesh where it puts the listener in order to delete
+ * them when HYP_OK algo_state is lost
+ * After being set, event listener is notified on each event of where submesh.
+ */
+//================================================================================
+
+void SMESH_subMesh::SetEventListener(EventListener*     listener,
+                                     EventListenerData* data,
+                                     SMESH_subMesh*     where)
+{
+  if ( listener && where ) {
+    where->SetEventListener( listener, data );
+    myOwnListeners.push_back( make_pair( where, listener ));
+  }
+}
+
+//================================================================================
+/*!
+ * \brief Sets an event listener and its data to a submesh
+ * \param listener - the listener to store
+ * \param data - the listener data to store
+ * 
+ * After being set, event listener is notified on each event of a submesh.
+ */
+//================================================================================
+
+void SMESH_subMesh::SetEventListener(EventListener* listener, EventListenerData* data)
+{
+  myEventListeners.insert( make_pair( listener, data ));
+}
+
+//================================================================================
+/*!
+ * \brief Return an event listener data
+ * \param listener - the listener whose data is
+ * \retval EventListenerData* - found data, maybe NULL
+ */
+//================================================================================
+
+EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const
+{
+  map< EventListener*, EventListenerData* >::const_iterator l_d =
+    myEventListeners.find( listener );
+  if ( l_d != myEventListeners.end() )
+    return l_d->second;
+  return 0;
+}
+
+//================================================================================
+/*!
+ * \brief Notify stored event listeners on the occured event
+ * \param event - algo_event or compute_event itself
+ * \param eventType - algo_event or compute_event
+ * \param subMesh - the submesh where the event occures
+ * \param data - listener data stored in the subMesh
+ * \param hyp - hypothesis, if eventType is algo_event
+ */
+//================================================================================
+
+void SMESH_subMesh::NotifyListenersOnEvent( const int         event,
+                                            const event_type  eventType,
+                                            SMESH_Hypothesis* hyp)
+{
+  map< EventListener*, EventListenerData* >::iterator l_d = myEventListeners.begin();
+  for ( ; l_d != myEventListeners.end(); ++l_d )
+    l_d->first->ProcessEvent( event, eventType, this, l_d->second, hyp );
+}
+
+//================================================================================
+/*!
+ * \brief Unregister the listener and delete listener's data
+ * \param listener - the event listener
+ */
+//================================================================================
+
+void SMESH_subMesh::DeleteEventListener(EventListener* listener)
+{
+  map< EventListener*, EventListenerData* >::iterator l_d =
+    myEventListeners.find( listener );
+  if ( l_d != myEventListeners.end() ) {
+    if ( l_d->first->IsDeletable() ) delete l_d->first;
+    if ( l_d->second->IsDeletable() ) delete l_d->second;
+    myEventListeners.erase( l_d );
+  }
+}
+
+//================================================================================
+/*!
+ * \brief Delete event listeners depending on algo of this submesh
+ */
+//================================================================================
+
+void SMESH_subMesh::DeleteOwnListeners()
+{
+  list< pair< SMESH_subMesh*, EventListener* > >::iterator sm_l;
+  for ( sm_l = myOwnListeners.begin(); sm_l != myOwnListeners.end(); ++sm_l)
+    sm_l->first->DeleteEventListener( sm_l->second );
+  myOwnListeners.clear();
+}
+
+//================================================================================
+/*!
+ * \brief Do something on a certain event
+ * \param event - algo_event or compute_event itself
+ * \param eventType - algo_event or compute_event
+ * \param subMesh - the submesh where the event occures
+ * \param data - listener data stored in the subMesh
+ * \param hyp - hypothesis, if eventType is algo_event
+ * 
+ * The base implementation translates CLEAN event to the subMesh
+ * stored in listener data. Also it sends SUBMESH_COMPUTED event in case of
+ * successful COMPUTE event.
+ */
+//================================================================================
+
+void SMESH_subMeshEventListener::ProcessEvent(const int          event,
+                                              const int          eventType,
+                                              SMESH_subMesh*     subMesh,
+                                              EventListenerData* data,
+                                              SMESH_Hypothesis*  /*hyp*/)
+{
+  if ( data && !data->mySubMeshes.empty() &&
+       eventType == SMESH_subMesh::COMPUTE_EVENT)
+  {
+    ASSERT( data->mySubMeshes.front() != subMesh );
+    switch ( event ) {
+    case SMESH_subMesh::CLEAN:
+      data->mySubMeshes.front()->ComputeStateEngine( event );
+      break;
+    case SMESH_subMesh::COMPUTE:
+      if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
+        data->mySubMeshes.front()->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
+      break;
+    default:;
+    }
+  }
+}