Salome HOME
Merge from V6_4_BR 05/12/2011
[modules/smesh.git] / src / SMESH / SMESH_subMesh.cxx
index f90f792da4374bd169af4f2d9bd06402ded22acb..73bd794f52a9ed8944e0ae67de0653fd22ce4fda 100644 (file)
@@ -1,30 +1,29 @@
-//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2011  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
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 //
-//  This library is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU Lesser General Public
-//  License as published by the Free Software Foundation; either
-//  version 2.1 of the License.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License.
 //
-//  This library is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-//  Lesser General Public License for more details.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
 //
-//  You should have received a copy of the GNU Lesser General Public
-//  License along with this library; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-//
-//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 
 //  SMESH SMESH : implementaion of SMESH idl descriptions
 //  File   : SMESH_subMesh.cxx
 //  Author : Paul RASCLE, EDF
 //  Module : SMESH
-//
+
 #include "SMESH_subMesh.hxx"
 
 #include "SMESH_Algo.hxx"
@@ -38,6 +37,8 @@
 #include "SMDS_SetIterator.hxx"
 #include "SMDSAbs_ElementType.hxx"
 
+#include <Basics_OCCTVersion.hxx>
+
 #include "utilities.h"
 #include "OpUtil.hxx"
 #include "Basics_Utils.hxx"
@@ -173,6 +174,17 @@ SMESH_subMesh *SMESH_subMesh::GetFirstToCompute()
   return 0;                     // nothing to compute
 }
 
+//================================================================================
+/*!
+ * \brief Returns a current algorithm
+ */
+//================================================================================
+
+SMESH_Algo* SMESH_subMesh::GetAlgo() const
+{
+  return _father->GetGen()->GetAlgo(*_father, _subShape);
+}
+
 //================================================================================
 /*!
  * \brief Allow algo->Compute() if a subshape of lower dim is meshed but
@@ -509,12 +521,13 @@ bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) cons
 {
   int aHypDim   = theHypothesis->GetDim();
   int aShapeDim = SMESH_Gen::GetShapeDim(_subShape);
-  if (aHypDim == 3 && aShapeDim == 3) {
-    // check case of open shell
-    //if (_subShape.ShapeType() == TopAbs_SHELL && !_subShape.Closed())
-    if (_subShape.ShapeType() == TopAbs_SHELL && !BRep_Tool::IsClosed(_subShape))
-      return false;
-  }
+  // issue 21106. Forbid 3D mesh on the SHELL
+  // if (aHypDim == 3 && aShapeDim == 3) {
+  //   // check case of open shell
+  //   //if (_subShape.ShapeType() == TopAbs_SHELL && !_subShape.Closed())
+  //   if (_subShape.ShapeType() == TopAbs_SHELL && !BRep_Tool::IsClosed(_subShape))
+  //     return false;
+  // }
   if ( aHypDim <= aShapeDim )
     return true;
 
@@ -530,8 +543,14 @@ bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis,
                                           const TopAbs_ShapeEnum  theShapeType)
 {
   if ( theHypothesis->GetType() > SMESHDS_Hypothesis::PARAM_ALGO)
+  {
     // algorithm
-    return ( theHypothesis->GetShapeType() & (1<< theShapeType));
+    if ( theHypothesis->GetShapeType() & (1<< theShapeType))
+      // issue 21106. Forbid 3D mesh on the SHELL
+      return !( theHypothesis->GetDim() == 3 && theShapeType == TopAbs_SHELL );
+    else
+      return false;
+  }
 
   // hypothesis
   switch ( theShapeType ) {
@@ -578,7 +597,7 @@ SMESH_Hypothesis::Hypothesis_Status
   SMESH_Hypothesis::Hypothesis_Status aux_ret, ret = SMESH_Hypothesis::HYP_OK;
 
   SMESHDS_Mesh* meshDS =_father->GetMeshDS();
-  SMESH_Gen*    gen    =_father->GetGen();
+  //SMESH_Gen*    gen    =_father->GetGen();
   SMESH_Algo*   algo   = 0;
 
   if (_subShape.ShapeType() == TopAbs_VERTEX )
@@ -595,7 +614,7 @@ SMESH_Hypothesis::Hypothesis_Status
       if ( event != REMOVE_FATHER_ALGO )
       {
         _algoState = NO_ALGO;
-        algo = gen->GetAlgo(*_father, _subShape);
+        algo = GetAlgo();
         if ( algo ) {
           _algoState = MISSING_HYP;
           if ( event == REMOVE_FATHER_HYP ||
@@ -688,7 +707,7 @@ SMESH_Hypothesis::Hypothesis_Status
     case ADD_HYP:
       break;
     case ADD_ALGO: {
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       ASSERT(algo);
       if (algo->CheckHypothesis((*_father),_subShape, aux_ret))
         SetAlgoState(HYP_OK);
@@ -705,7 +724,7 @@ SMESH_Hypothesis::Hypothesis_Status
     case ADD_FATHER_HYP:
       break;
     case ADD_FATHER_ALGO: {    // Algo just added in father
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       ASSERT(algo);
       if ( algo == anHyp ) {
         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret))
@@ -718,7 +737,7 @@ SMESH_Hypothesis::Hypothesis_Status
     case REMOVE_FATHER_HYP:
       break;
     case REMOVE_FATHER_ALGO: {
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if (algo)
       {
         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
@@ -741,7 +760,7 @@ SMESH_Hypothesis::Hypothesis_Status
     switch (event)
     {
     case ADD_HYP: {
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, ret ))
         SetAlgoState(HYP_OK);
@@ -755,7 +774,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case ADD_ALGO: {           //already existing algo : on father ?
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))// ignore hyp status
         SetAlgoState(HYP_OK);
@@ -770,7 +789,7 @@ SMESH_Hypothesis::Hypothesis_Status
     case REMOVE_HYP:
       break;
     case REMOVE_ALGO: {        // perhaps a father algo applies ?
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if (algo == NULL)  // no more algo applying on subShape...
       {
         SetAlgoState(NO_ALGO);
@@ -786,7 +805,7 @@ SMESH_Hypothesis::Hypothesis_Status
     }
     case MODIF_HYP: // assigned hypothesis value may become good
     case ADD_FATHER_HYP: {
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
         SetAlgoState(HYP_OK);
@@ -795,7 +814,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case ADD_FATHER_ALGO: { // new father algo
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       ASSERT( algo );
       if ( algo == anHyp ) {
         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
@@ -808,7 +827,7 @@ SMESH_Hypothesis::Hypothesis_Status
     case REMOVE_FATHER_HYP:    // nothing to do
       break;
     case REMOVE_FATHER_ALGO: {
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if (algo == NULL)  // no more applying algo on father
       {
         SetAlgoState(NO_ALGO);
@@ -834,7 +853,7 @@ SMESH_Hypothesis::Hypothesis_Status
     switch (event)
     {
     case ADD_HYP: {
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       ASSERT(algo);
       if (!algo->CheckHypothesis((*_father),_subShape, ret ))
       {
@@ -857,7 +876,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case ADD_ALGO: {           //already existing algo : on father ?
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
         // check if algo changes
         SMESH_HypoFilter f;
@@ -874,7 +893,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case REMOVE_HYP: {
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
         SetAlgoState(HYP_OK);
@@ -884,7 +903,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case REMOVE_ALGO: {         // perhaps a father algo applies ?
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if (algo == NULL)   // no more algo applying on subShape...
       {
         SetAlgoState(NO_ALGO);
@@ -903,7 +922,7 @@ SMESH_Hypothesis::Hypothesis_Status
     }
     case MODIF_HYP: // hypothesis value may become bad
     case ADD_FATHER_HYP: {  // new father hypothesis ?
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
       {
@@ -915,7 +934,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case ADD_FATHER_ALGO: {
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if ( algo == anHyp ) { // a new algo on father
         if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
           // check if algo changes
@@ -934,7 +953,7 @@ SMESH_Hypothesis::Hypothesis_Status
       break;
     }
     case REMOVE_FATHER_HYP: {
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       ASSERT(algo);
       if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
         // is there the same local hyp or maybe a new father algo applied?
@@ -952,7 +971,7 @@ SMESH_Hypothesis::Hypothesis_Status
       if (!algo->NeedDescretBoundary())
         needFullClean = true;
 
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if (algo == NULL)  // no more applying algo on father
       {
         SetAlgoState(NO_ALGO);
@@ -1280,7 +1299,7 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
     switch (event)
     {
     case MODIF_ALGO_STATE:
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if (algo && !algo->NeedDescretBoundary())
         CleanDependsOn(); // clean sub-meshes with event CLEAN
       if ( _algoState == HYP_OK )
@@ -1288,6 +1307,10 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
       break;
     case COMPUTE:               // nothing to do
       break;
+#ifdef WITH_SMESH_CANCEL_COMPUTE
+    case COMPUTE_CANCELED:               // nothing to do
+      break;
+#endif
     case CLEAN:
       CleanDependants();
       RemoveSubMeshElementsAndNodes();
@@ -1316,7 +1339,7 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
     {
     case MODIF_ALGO_STATE:
       _computeState = NOT_READY;
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if (algo)
       {
         if (!algo->NeedDescretBoundary())
@@ -1327,7 +1350,7 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
       break;
     case COMPUTE:
       {
-        algo = gen->GetAlgo((*_father), _subShape);
+        algo = GetAlgo();
         ASSERT(algo);
         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
         if (!ret)
@@ -1364,7 +1387,7 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
         _computeState = FAILED_TO_COMPUTE;
         _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
         try {
-#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
+#if OCC_VERSION_LARGE > 0x06010000
           OCC_CATCH_SIGNALS;
 #endif
           algo->InitComputeError();
@@ -1385,6 +1408,11 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
           if ( !_computeError || ( !ret && _computeError->IsOK() ) ) // algo can set _computeError of submesh
             _computeError = algo->GetComputeError();
         }
+        catch ( ::SMESH_ComputeError& comperr ) {
+          cout << " SMESH_ComputeError caught" << endl;
+          if ( !_computeError ) _computeError = SMESH_ComputeError::New();
+          *_computeError = comperr;
+        }
         catch ( std::bad_alloc& exc ) {
           MESSAGE("std::bad_alloc thrown inside algo->Compute()");
           if ( _computeError ) {
@@ -1452,18 +1480,22 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
             }
           }
         }
-        if (ret)
+        if (ret && _computeError && _computeError->myName != COMPERR_WARNING )
         {
           _computeError.reset();
         }
         UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
       }
       break;
+#ifdef WITH_SMESH_CANCEL_COMPUTE
+    case COMPUTE_CANCELED:               // nothing to do
+      break;
+#endif
     case CLEAN:
       CleanDependants();
       RemoveSubMeshElementsAndNodes();
       _computeState = NOT_READY;
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if (algo)
       {
         ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
@@ -1480,7 +1512,7 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
       // happen after retrieval from a file
       ComputeStateEngine( CHECK_COMPUTE_STATE );
       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
-      algo = gen->GetAlgo(*_father, _subShape);
+      algo = GetAlgo();
       if (algo) algo->SubmeshRestored( this );
       break;
     case MESH_ENTITY_REMOVED:
@@ -1502,12 +1534,16 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
     {
     case MODIF_ALGO_STATE:
       ComputeStateEngine( CLEAN );
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if (algo && !algo->NeedDescretBoundary())
         CleanDependsOn(); // clean sub-meshes with event CLEAN
       break;
     case COMPUTE:               // nothing to do
       break;
+#ifdef WITH_SMESH_CANCEL_COMPUTE
+    case COMPUTE_CANCELED:               // nothing to do
+      break;
+#endif
     case CLEAN:
       CleanDependants();  // clean sub-meshes, dependant on this one, with event CLEAN
       RemoveSubMeshElementsAndNodes();
@@ -1520,7 +1556,7 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
     case SUBMESH_RESTORED:
       ComputeStateEngine( CHECK_COMPUTE_STATE );
       ComputeSubMeshStateEngine( SUBMESH_RESTORED );
-      algo = gen->GetAlgo(*_father, _subShape);
+      algo = GetAlgo();
       if (algo) algo->SubmeshRestored( this );
       break;
     case MESH_ENTITY_REMOVED:
@@ -1550,7 +1586,7 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
     case MODIF_ALGO_STATE:
       if ( !IsEmpty() )
         ComputeStateEngine( CLEAN );
-      algo = gen->GetAlgo((*_father), _subShape);
+      algo = GetAlgo();
       if (algo && !algo->NeedDescretBoundary())
         CleanDependsOn(); // clean sub-meshes with event CLEAN
       if (_algoState == HYP_OK)
@@ -1560,6 +1596,14 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
       break;
     case COMPUTE:      // nothing to do
       break;
+#ifdef WITH_SMESH_CANCEL_COMPUTE
+    case COMPUTE_CANCELED:
+      {
+        algo = GetAlgo();
+        algo->CancelCompute();
+      }
+      break;
+#endif
     case CLEAN:
       CleanDependants(); // submeshes dependent on me should be cleaned as well
       RemoveSubMeshElementsAndNodes();
@@ -1621,11 +1665,11 @@ bool SMESH_subMesh::Evaluate(MapShapeNbElems& aResMap)
     return ret;
   }
 
-  SMESH_Gen *gen = _father->GetGen();
+  //SMESH_Gen *gen = _father->GetGen();
   SMESH_Algo *algo = 0;
   SMESH_Hypothesis::Hypothesis_Status hyp_status;
 
-  algo = gen->GetAlgo((*_father), _subShape);
+  algo = GetAlgo();
   if(algo && !aResMap.count(this) )
   {
     ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
@@ -1700,6 +1744,7 @@ bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& t
     // Check my state
     if ( !_computeError || _computeError->IsOK() )
     {
+      // no error description is set to this sub-mesh, check if any mesh is computed
       _computeState = IsMeshComputed() ? COMPUTE_OK : FAILED_TO_COMPUTE;
     }
     else
@@ -1717,67 +1762,16 @@ bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& t
       if ( _computeError->myComment.size() > 0 )
         text << " \"" << _computeError->myComment << "\"";
 
-#ifdef _DEBUG_
-      MESSAGE_BEGIN ( text );
-      // Show vertices location of a failed shape
-      TopTools_IndexedMapOfShape vMap;
-      TopExp::MapShapes( _subShape, TopAbs_VERTEX, vMap );
-      MESSAGE_ADD ( "Subshape vertices " << ( vMap.Extent()>10 ? "(first 10):" : ":") );
-      for ( int iv = 1; iv <= vMap.Extent() && iv < 11; ++iv ) {
-        gp_Pnt P( BRep_Tool::Pnt( TopoDS::Vertex( vMap( iv ) )));
-        MESSAGE_ADD ( "#" << _father->GetMeshDS()->ShapeToIndex( vMap( iv )) << " "
-                   << P.X() << " " << P.Y() << " " << P.Z() << " " );
-      }
-#else
       INFOS( text );
-#endif
-      _computeState = FAILED_TO_COMPUTE;
-      noErrors = false;
-    }
-  }
-  return noErrors;
-}
 
-//=======================================================================
-//function : ApplyToCollection
-//purpose  : Apply theAlgo to all subshapes in theCollection
-//=======================================================================
-
-bool SMESH_subMesh::ApplyToCollection (SMESH_Algo*         theAlgo,
-                                       const TopoDS_Shape& theCollection)
-{
-  MESSAGE("SMESH_subMesh::ApplyToCollection");
-  ASSERT ( !theAlgo->NeedDescretBoundary() );
+      _computeState = _computeError->IsKO() ? FAILED_TO_COMPUTE : COMPUTE_OK;
 
-  if ( _computeError )
-    _computeError->myName = COMPERR_OK;
-
-  bool ok = theAlgo->Compute( *_father, theCollection );
-
-  // set _computeState of subshapes
-  TopExp_Explorer anExplorer( theCollection, _subShape.ShapeType() );
-  for ( ; anExplorer.More(); anExplorer.Next() )
-  {
-    if ( SMESH_subMesh* subMesh = _father->GetSubMeshContaining( anExplorer.Current() ))
-    {
-      bool localOK = subMesh->CheckComputeError( theAlgo );
-      if ( !ok && localOK && !subMesh->IsMeshComputed() )
-      {
-        subMesh->_computeError = theAlgo->GetComputeError();
-        if ( subMesh->_computeError->IsOK() )
-          _computeError = SMESH_ComputeError::New(COMPERR_ALGO_FAILED);
-        localOK = CheckComputeError( theAlgo );
-      }
-      if ( localOK )
-        subMesh->UpdateDependantsState( SUBMESH_COMPUTED );
-      subMesh->UpdateSubMeshState( localOK ? COMPUTE_OK : FAILED_TO_COMPUTE );
+      noErrors = false;
     }
   }
-
-  return true;
+  return noErrors;
 }
 
-
 //=======================================================================
 //function : UpdateSubMeshState
 //purpose  :
@@ -1840,7 +1834,8 @@ void SMESH_subMesh::CleanDependants()
       // will erase mesh on other shapes in a compound
       if ( ancestor.ShapeType() >= TopAbs_SOLID ) {
         SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor);
-        if (aSubMesh)
+        if (aSubMesh &&
+            !aSubMesh->IsEmpty() ) // prevent infinite CLEAN via event lesteners
           aSubMesh->ComputeStateEngine(CLEAN);
       }
     }
@@ -2068,8 +2063,6 @@ EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener)
  * \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
  */
 //================================================================================
@@ -2080,7 +2073,17 @@ void SMESH_subMesh::NotifyListenersOnEvent( const int         event,
 {
   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 );
+  {
+    std::pair< EventListener*, EventListenerData* > li_da = *l_d; /* copy to enable removal
+                                                                     of a listener from
+                                                                     myEventListeners by
+                                                                     its ProcessEvent() */
+    if ( li_da.first->myBusySM.insert( this ).second )
+    {
+      li_da.first->ProcessEvent( event, eventType, this, li_da.second, hyp );
+      li_da.first->myBusySM.erase( this );
+    }
+  }
 }
 
 //================================================================================