Salome HOME
Another fix like previous one.
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_VTKUtils.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // SMESH SMESHGUI : GUI for SMESH component
23 // File   : SMESHGUI_VTKUtils.cxx
24 // Author : Open CASCADE S.A.S.
25 // SMESH includes
26 //
27 #include "SMESHGUI_VTKUtils.h"
28
29 #include "SMESHGUI.h"
30 #include "SMESHGUI_Utils.h"
31 #include "SMESHGUI_Filter.h"
32
33 #include <SMESH_Actor.h>
34 #include <SMESH_ActorUtils.h>
35 #include <SMESH_ObjectDef.h>
36 #include <SMDS_Mesh.hxx>
37
38 // SALOME GUI includes
39 #include <SUIT_Desktop.h>
40 #include <SUIT_Session.h>
41 #include <SUIT_MessageBox.h>
42 #include <SUIT_ViewManager.h>
43 #include <SUIT_ResourceMgr.h>
44
45 #include <SALOME_ListIO.hxx>
46 #include <SALOME_ListIteratorOfListIO.hxx>
47
48 #include <SVTK_Selector.h>
49 #include <SVTK_ViewModel.h>
50 #include <SVTK_ViewWindow.h>
51
52 #include <VTKViewer_Algorithm.h>
53
54 #include <LightApp_SelectionMgr.h>
55 #include <SalomeApp_Application.h>
56 #include <SalomeApp_Study.h>
57
58 // SALOME KERNEL includes
59 #include <utilities.h>
60
61 // IDL includes
62 #include <SALOMEconfig.h>
63 #include CORBA_CLIENT_HEADER(SMESH_Mesh)
64 #include CORBA_CLIENT_HEADER(SMESH_Group)
65
66 // VTK includes
67 #include <vtkRenderer.h>
68 #include <vtkActorCollection.h>
69 #include <vtkUnstructuredGrid.h>
70
71 // OCCT includes
72 #include <TColStd_IndexedMapOfInteger.hxx>
73 #include <Standard_ErrorHandler.hxx>
74
75 namespace SMESH
76 {
77   typedef std::map<TKeyOfVisualObj,TVisualObjPtr> TVisualObjCont;
78   static TVisualObjCont VISUAL_OBJ_CONT;
79
80   //=============================================================================
81   /*!
82    * \brief Allocate some memory at construction and release it at destruction.
83    * Is used to be able to continue working after mesh generation or visualization
84    * break due to lack of memory
85    */
86   //=============================================================================
87
88   struct MemoryReserve
89   {
90     char* myBuf;
91     MemoryReserve(): myBuf( new char[1024*1024*1] ){} // 1M
92     void Free() { if (myBuf) { delete [] myBuf; myBuf = 0; }}
93     ~MemoryReserve() { Free(); }
94   };
95   static MemoryReserve* theVISU_MemoryReserve = new MemoryReserve;
96
97   //================================================================================
98   /*!
99    * \brief Remove VisualObj and its actor from all views
100    */
101   //================================================================================
102
103   void RemoveVisualObjectWithActors( const char* theEntry )
104   {
105     SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>
106       ( SUIT_Session::session()->activeApplication() );
107     SUIT_ViewManager* aViewManager =
108       app ? app->getViewManager(SVTK_Viewer::Type(), true) : 0;
109     if ( aViewManager ) {
110       QVector<SUIT_ViewWindow*> views = aViewManager->getViews();
111       for ( int iV = 0; iV < views.count(); ++iV ) {
112         if ( SMESH_Actor* actor = FindActorByEntry( views[iV], theEntry)) {
113           if(SVTK_ViewWindow* vtkWnd = GetVtkViewWindow(views[iV]))
114             vtkWnd->RemoveActor(actor);
115           actor->Delete();
116         }
117       }
118       int aStudyId = aViewManager->study()->id();
119       TVisualObjCont::key_type aKey(aStudyId,theEntry);
120       TVisualObjCont::iterator anIter = VISUAL_OBJ_CONT.find(aKey);
121       if(anIter != VISUAL_OBJ_CONT.end()) {
122         // for unknown reason, object destructor is not called, so clear object manually
123         anIter->second->GetUnstructuredGrid()->SetCells(0,0,0);
124         anIter->second->GetUnstructuredGrid()->SetPoints(0);
125       }
126       VISUAL_OBJ_CONT.erase(aKey);
127     }
128   }
129   //================================================================================
130   /*!
131    * \brief Remove all VisualObjs and their actors from all views
132    */
133   //================================================================================
134
135   void RemoveAllObjectsWithActors()
136   {
137     SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>
138       ( SUIT_Session::session()->activeApplication() );
139     if (!app) return;
140     ViewManagerList viewMgrs = app->viewManagers();
141     for ( int iM = 0; iM < viewMgrs.count(); ++iM ) {
142       SUIT_ViewManager* aViewManager = viewMgrs.at( iM );
143       if ( aViewManager && aViewManager->getType() == SVTK_Viewer::Type()) {
144         QVector<SUIT_ViewWindow*> views = aViewManager->getViews();
145         for ( int iV = 0; iV < views.count(); ++iV ) {
146           if(SVTK_ViewWindow* vtkWnd = GetVtkViewWindow(views[iV])) {
147             vtkRenderer *aRenderer = vtkWnd->getRenderer();
148             VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
149             vtkActorCollection *actors = aCopy.GetActors();
150             for (int i = 0; i < actors->GetNumberOfItems(); ++i ) {
151               // size of actors changes inside the loop
152               if (SMESH_Actor *actor = dynamic_cast<SMESH_Actor*>(actors->GetItemAsObject(i)))
153               {
154                 vtkWnd->RemoveActor(actor);
155                 actor->Delete();
156               }
157             }
158           }
159         }
160       }
161     }
162     TVisualObjCont::iterator anIter = VISUAL_OBJ_CONT.begin();
163     for ( ; anIter != VISUAL_OBJ_CONT.end(); ++anIter ) {
164       // for unknown reason, object destructor is not called, so clear object manually
165       anIter->second->GetUnstructuredGrid()->SetCells(0,0,0);
166       anIter->second->GetUnstructuredGrid()->SetPoints(0);
167     }
168     VISUAL_OBJ_CONT.clear();
169   }
170
171   //================================================================================
172   /*!
173    * \brief Remove all VisualObjs of a study
174    */
175   //================================================================================
176
177   void RemoveVisuData(int studyID)
178   {
179     SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>
180       ( SUIT_Session::session()->activeApplication() );
181     if (!app) return;
182     ViewManagerList viewMgrs = app->viewManagers();
183     for ( int iM = 0; iM < viewMgrs.count(); ++iM ) {
184       SUIT_ViewManager* aViewManager = viewMgrs.at( iM );
185       if ( aViewManager && aViewManager->getType() == SVTK_Viewer::Type() &&
186            aViewManager->study()->id() == studyID ) {
187         QVector<SUIT_ViewWindow*> views = aViewManager->getViews();
188         for ( int iV = 0; iV < views.count(); ++iV ) {
189           if(SVTK_ViewWindow* vtkWnd = GetVtkViewWindow(views[iV])) {
190             vtkRenderer *aRenderer = vtkWnd->getRenderer();
191             VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
192             vtkActorCollection *actors = aCopy.GetActors();
193             for (int i = 0; i < actors->GetNumberOfItems(); ++i ) {
194               // size of actors changes inside the loop
195               if(SMESH_Actor *actor = dynamic_cast<SMESH_Actor*>(actors->GetItemAsObject(i)))
196               {
197                 vtkWnd->RemoveActor(actor);
198                 actor->Delete();
199               }
200             }
201           }
202         }
203       }
204     }
205     TVisualObjCont::iterator anIter = VISUAL_OBJ_CONT.begin();
206     for ( ; anIter != VISUAL_OBJ_CONT.end(); ++anIter ) {
207       int curId = anIter->first.first;
208       if ( curId == studyID ) {
209         // for unknown reason, object destructor is not called, so clear object manually
210         anIter->second->GetUnstructuredGrid()->SetCells(0,0,0);
211         anIter->second->GetUnstructuredGrid()->SetPoints(0);
212         VISUAL_OBJ_CONT.erase( anIter-- );  // dercement occures before erase()
213       }
214     }
215   }
216
217   //================================================================================
218   /*!
219    * \brief Notify the user on problems during visualization
220    */
221   //================================================================================
222
223   void OnVisuException()
224   {
225     try {
226 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
227       OCC_CATCH_SIGNALS;
228 #endif
229       // PAL16774 (Crash after display of many groups). Salome sometimes crashes just
230       // after or at showing this message, so we do an additional check of available memory
231 //       char* buf = new char[100*1024];
232 //       delete [] buf;
233       SUIT_MessageBox::warning(SMESHGUI::desktop(), QObject::tr("SMESH_WRN_WARNING"),
234                                QObject::tr("SMESH_VISU_PROBLEM"));
235     } catch (...) {
236       // no more memory at all: last resort
237       MESSAGE_BEGIN ( "SMESHGUI_VTKUtils::OnVisuException(), exception even at showing a message!!!" <<
238                       std::endl << "Try to remove all visual data..." );
239       if (theVISU_MemoryReserve) {
240         delete theVISU_MemoryReserve;
241         theVISU_MemoryReserve = 0;
242       }
243       RemoveAllObjectsWithActors();
244       SUIT_MessageBox::warning(SMESHGUI::desktop(), QObject::tr("SMESH_WRN_WARNING"),
245                                QObject::tr("SMESH_VISU_PROBLEM_CLEAR"));
246       MESSAGE_END ( "...done" );
247     }
248   }
249   //================================================================================
250   /*!
251    * \brief Returns an updated visual object
252    */
253   //================================================================================
254
255   TVisualObjPtr GetVisualObj(int theStudyId, const char* theEntry){
256     TVisualObjPtr aVisualObj;
257     TVisualObjCont::key_type aKey(theStudyId,theEntry);
258     try{
259 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
260       OCC_CATCH_SIGNALS;
261 #endif
262       TVisualObjCont::iterator anIter = VISUAL_OBJ_CONT.find(aKey);
263       if(anIter != VISUAL_OBJ_CONT.end()){
264         aVisualObj = anIter->second;
265       }else{
266         SalomeApp_Application* app =
267           dynamic_cast<SalomeApp_Application*>( SMESHGUI::activeStudy()->application() );
268         _PTR(Study) aStudy = SMESHGUI::activeStudy()->studyDS();
269         _PTR(SObject) aSObj = aStudy->FindObjectID(theEntry);
270         if(aSObj){
271           _PTR(GenericAttribute) anAttr;
272           if(aSObj->FindAttribute(anAttr,"AttributeIOR")){
273             _PTR(AttributeIOR) anIOR = anAttr;
274             CORBA::String_var aVal = anIOR->Value().c_str();
275             CORBA::Object_var anObj = app->orb()->string_to_object( aVal.in() );
276             if(!CORBA::is_nil(anObj)){
277               //Try narrow to SMESH_Mesh interface
278               SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow(anObj);
279               if(!aMesh->_is_nil()){
280                 aVisualObj.reset(new SMESH_MeshObj(aMesh));
281                 TVisualObjCont::value_type aValue(aKey,aVisualObj);
282                 VISUAL_OBJ_CONT.insert(aValue);
283               }
284               //Try narrow to SMESH_Group interface
285               SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow(anObj);
286               if(!aGroup->_is_nil()){
287                 _PTR(SObject) aFatherSObj = aSObj->GetFather();
288                 if(!aFatherSObj) return aVisualObj;
289                 aFatherSObj = aFatherSObj->GetFather();
290                 if(!aFatherSObj) return aVisualObj;
291                 CORBA::String_var anEntry = aFatherSObj->GetID().c_str();
292                 TVisualObjPtr aVisObj = GetVisualObj(theStudyId,anEntry.in());
293                 if(SMESH_MeshObj* aMeshObj = dynamic_cast<SMESH_MeshObj*>(aVisObj.get())){
294                   aVisualObj.reset(new SMESH_GroupObj(aGroup,aMeshObj));
295                   TVisualObjCont::value_type aValue(aKey,aVisualObj);
296                   VISUAL_OBJ_CONT.insert(aValue);
297                 }
298               }
299               //Try narrow to SMESH_subMesh interface
300               SMESH::SMESH_subMesh_var aSubMesh = SMESH::SMESH_subMesh::_narrow(anObj);
301               if(!aSubMesh->_is_nil()){
302                 _PTR(SObject) aFatherSObj = aSObj->GetFather();
303                 if(!aFatherSObj) return aVisualObj;
304                 aFatherSObj = aFatherSObj->GetFather();
305                 if(!aFatherSObj) return aVisualObj;
306                 CORBA::String_var anEntry = aFatherSObj->GetID().c_str();
307                 TVisualObjPtr aVisObj = GetVisualObj(theStudyId,anEntry.in());
308                 if(SMESH_MeshObj* aMeshObj = dynamic_cast<SMESH_MeshObj*>(aVisObj.get())){
309                   aVisualObj.reset(new SMESH_subMeshObj(aSubMesh,aMeshObj));
310                   TVisualObjCont::value_type aValue(aKey,aVisualObj);
311                   VISUAL_OBJ_CONT.insert(aValue);
312                 }
313               }
314             }
315           }
316         }
317       }
318     }catch(...){
319       INFOS("GetMeshObj - There is no SMESH_Mesh object for the SALOMEDS::Strudy and Entry!!!");
320       return TVisualObjPtr();
321     }
322     // Update object
323     bool objModified = false;
324     if ( aVisualObj ) {
325       try {
326 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
327         OCC_CATCH_SIGNALS;
328 #endif
329         objModified = aVisualObj->Update();
330       }
331       catch (...) {
332 #ifdef _DEBUG_
333         MESSAGE ( "Exception in SMESHGUI_VTKUtils::GetVisualObj()" );
334 #endif
335         RemoveVisualObjectWithActors( theEntry ); // remove this object
336         OnVisuException();
337         aVisualObj.reset();
338       }
339     }
340
341     if ( objModified ) {
342       // PAL16631. Mesurements showed that to show aVisualObj in SHADING(default) mode,
343       // ~10 times more memory is used than it occupies.
344       // Warn the user if there is less free memory than 30 sizes of a grid
345       // TODO: estimate memory usage in other modes and take current mode into account
346       int freeMB = SMDS_Mesh::CheckMemory(true);
347       int usedMB = aVisualObj->GetUnstructuredGrid()->GetActualMemorySize() / 1024;
348       if ( freeMB > 0 && usedMB * 30 > freeMB ) {
349 #ifdef _DEBUG_
350         MESSAGE ( "SMESHGUI_VTKUtils::GetVisualObj(), freeMB=" << freeMB
351                << ", usedMB=" << usedMB );
352 #endif
353         bool continu = false;
354         if ( usedMB * 10 > freeMB )
355           // even dont try to show
356           SUIT_MessageBox::warning(SMESHGUI::desktop(), QObject::tr("SMESH_WRN_WARNING"),
357                                    QObject::tr("SMESH_NO_MESH_VISUALIZATION"));
358         else
359           // there is a chance to succeed
360           continu = SUIT_MessageBox::warning
361             (SMESHGUI::desktop(),
362              QObject::tr("SMESH_WRN_WARNING"),
363              QObject::tr("SMESH_CONTINUE_MESH_VISUALIZATION"),
364              SUIT_MessageBox::Yes | SUIT_MessageBox::No, 
365              SUIT_MessageBox::Yes ) == SUIT_MessageBox::Yes;
366         if ( !continu ) {
367           // remove the corresponding actors from all views
368           RemoveVisualObjectWithActors( theEntry );
369           aVisualObj.reset();
370         }
371       }
372     }
373
374     return aVisualObj;
375   }
376
377
378   /*! Return active view window, if it instantiates SVTK_ViewWindow class,
379    *  overwise find or create corresponding view window, make it active and return it.
380    *  \note Active VVTK_ViewWindow can be returned, because it inherits SVTK_ViewWindow.
381    */
382   SVTK_ViewWindow* GetViewWindow (const SalomeApp_Module* theModule,
383                                   bool createIfNotFound)
384   {
385     SalomeApp_Application* anApp;
386     if (theModule)
387       anApp = theModule->getApp();
388     else
389       anApp = dynamic_cast<SalomeApp_Application*>
390         (SUIT_Session::session()->activeApplication());
391
392     if (anApp) {
393       if (SVTK_ViewWindow* aView = dynamic_cast<SVTK_ViewWindow*>(anApp->desktop()->activeWindow()))
394         return aView;
395
396       SUIT_ViewManager* aViewManager =
397         anApp->getViewManager(SVTK_Viewer::Type(), createIfNotFound);
398       if (aViewManager) {
399         if (SUIT_ViewWindow* aViewWindow = aViewManager->getActiveView()) {
400           if (SVTK_ViewWindow* aView = dynamic_cast<SVTK_ViewWindow*>(aViewWindow)) {
401             aViewWindow->raise();
402             aViewWindow->setFocus();
403             return aView;
404           }
405         }
406       }
407     }
408     return NULL;
409   }
410
411   SVTK_ViewWindow* FindVtkViewWindow (SUIT_ViewManager* theMgr,
412                                       SUIT_ViewWindow * theWindow)
413   {
414     if( !theMgr )
415       return NULL;
416
417     QVector<SUIT_ViewWindow*> views = theMgr->getViews();
418     if( views.contains( theWindow ) )
419       return GetVtkViewWindow( theWindow );
420     else
421       return NULL;
422   }
423
424   SVTK_ViewWindow* GetVtkViewWindow(SUIT_ViewWindow* theWindow){
425     return dynamic_cast<SVTK_ViewWindow*>(theWindow);
426   }
427
428 /*  SUIT_ViewWindow* GetActiveWindow()
429   {
430     SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
431     if( !app )
432       return NULL;
433     SUIT_ViewManager* mgr = app->activeViewManager();
434     if( mgr )
435       return mgr->getActiveView();
436     else
437       return NULL;
438   }*/
439
440   SVTK_ViewWindow* GetCurrentVtkView(){
441     return GetVtkViewWindow( GetActiveWindow() );
442   }
443
444
445   void RepaintCurrentView()
446   {
447     if (SVTK_ViewWindow* wnd = GetCurrentVtkView())
448     {
449       try {
450 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
451         OCC_CATCH_SIGNALS;
452 #endif
453         wnd->getRenderer()->Render();
454         wnd->Repaint(false);
455       }
456       catch (...) {
457 #ifdef _DEBUG_
458         MESSAGE ( "Exception in SMESHGUI_VTKUtils::RepaintCurrentView()" );
459 #endif
460         OnVisuException();
461       }
462     }
463   }
464
465   void RepaintViewWindow(SVTK_ViewWindow* theWindow)
466   {
467     try {
468 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
469       OCC_CATCH_SIGNALS;
470 #endif
471       theWindow->getRenderer()->Render();
472       theWindow->Repaint();
473     }
474     catch (...) {
475 #ifdef _DEBUG_
476       MESSAGE ( "Exception in SMESHGUI_VTKUtils::RepaintViewWindow(SVTK_ViewWindow*)" );
477 #endif
478       OnVisuException();
479     }
480   }
481
482   void RenderViewWindow(SVTK_ViewWindow* theWindow)
483   {
484     try {
485 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
486       OCC_CATCH_SIGNALS;
487 #endif
488       theWindow->getRenderer()->Render();
489       theWindow->Repaint();
490     }
491     catch (...) {
492 #ifdef _DEBUG_
493       MESSAGE ( "Exception in SMESHGUI_VTKUtils::RenderViewWindow(SVTK_ViewWindow*)" );
494 #endif
495       OnVisuException();
496     }
497   }
498
499   void FitAll(){
500     if(SVTK_ViewWindow* wnd = GetCurrentVtkView() ){
501       try {
502 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
503         OCC_CATCH_SIGNALS;
504 #endif
505         wnd->onFitAll();
506         wnd->Repaint();
507       }
508       catch (...) {
509 #ifdef _DEBUG_
510         MESSAGE ( "Exception in SMESHGUI_VTKUtils::FitAll()" );
511 #endif
512         OnVisuException();
513       }
514     }
515   }
516
517
518   SMESH_Actor* FindActorByEntry(SUIT_ViewWindow *theWindow,
519                                 const char* theEntry)
520   {
521     if(SVTK_ViewWindow* aViewWindow = GetVtkViewWindow(theWindow)){
522       vtkRenderer *aRenderer = aViewWindow->getRenderer();
523       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
524       vtkActorCollection *aCollection = aCopy.GetActors();
525       aCollection->InitTraversal();
526       while(vtkActor *anAct = aCollection->GetNextActor()){
527         if(SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)){
528           if(anActor->hasIO()){
529             Handle(SALOME_InteractiveObject) anIO = anActor->getIO();
530             if(anIO->hasEntry() && strcmp(anIO->getEntry(),theEntry) == 0){
531               return anActor;
532             }
533           }
534         }
535       }
536     }
537     return NULL;
538   }
539
540
541   SMESH_Actor* FindActorByEntry(const char* theEntry){
542     return FindActorByEntry(GetActiveWindow(),theEntry);
543   }
544
545
546   SMESH_Actor* FindActorByObject(CORBA::Object_ptr theObject){
547     SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
548     if( !app )
549       return NULL;
550
551     if(!CORBA::is_nil(theObject)){
552       _PTR(Study) aStudy = GetActiveStudyDocument();
553       CORBA::String_var anIOR = app->orb()->object_to_string( theObject );
554       _PTR(SObject) aSObject = aStudy->FindObjectIOR(anIOR.in());
555       if(aSObject){
556         CORBA::String_var anEntry = aSObject->GetID().c_str();
557         return FindActorByEntry(anEntry.in());
558       }
559     }
560     return NULL;
561   }
562
563
564   SMESH_Actor* CreateActor(_PTR(Study) theStudy,
565                            const char* theEntry,
566                            int theIsClear)
567   {
568     SMESH_Actor *anActor = NULL;
569     CORBA::Long anId = theStudy->StudyId();
570     if(TVisualObjPtr aVisualObj = GetVisualObj(anId,theEntry)){
571       _PTR(SObject) aSObj = theStudy->FindObjectID(theEntry);
572       if(aSObj){
573         _PTR(GenericAttribute) anAttr;
574         if(aSObj->FindAttribute(anAttr,"AttributeName")){
575           _PTR(AttributeName) aName = anAttr;
576           std::string aNameVal = aName->Value();
577           anActor = SMESH_Actor::New(aVisualObj,theEntry,aNameVal.c_str(),theIsClear);
578         }
579
580         SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow( SMESH::SObjectToObject( aSObj ));
581         if(!CORBA::is_nil(aGroup))
582         {
583           SALOMEDS::Color aColor = aGroup->GetColor();
584           if( !( aColor.R > 0 || aColor.G > 0 || aColor.B > 0 ) )
585           {
586             int r = 0, g = 0, b = 0;
587             SMESH::GetColor( "SMESH", "fill_color", r, g, b, QColor( 0, 170, 255 ) );
588             aColor.R = (float)r / 255.0;
589             aColor.G = (float)g / 255.0;
590             aColor.B = (float)b / 255.0;
591             aGroup->SetColor( aColor );
592           }
593           if( aGroup->GetType() == SMESH::NODE )
594             anActor->SetNodeColor( aColor.R, aColor.G, aColor.B );
595           else if( aGroup->GetType() == SMESH::EDGE )
596             anActor->SetEdgeColor( aColor.R, aColor.G, aColor.B );
597           else
598             anActor->SetSufaceColor( aColor.R, aColor.G, aColor.B );
599         }
600       }
601     }
602     return anActor;
603   }
604
605
606   void DisplayActor( SUIT_ViewWindow *theWnd, SMESH_Actor* theActor){
607     if(SVTK_ViewWindow* vtkWnd = GetVtkViewWindow(theWnd)){
608       try {
609 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
610         OCC_CATCH_SIGNALS;
611 #endif
612         vtkWnd->AddActor(theActor);
613         vtkWnd->Repaint();
614       }
615       catch (...) {
616 #ifdef _DEBUG_
617         MESSAGE ( "Exception in SMESHGUI_VTKUtils::DisplayActor()" );
618 #endif
619         OnVisuException();
620       }
621     }
622   }
623
624
625   void RemoveActor( SUIT_ViewWindow *theWnd, SMESH_Actor* theActor){
626     if(SVTK_ViewWindow* vtkWnd = GetVtkViewWindow(theWnd)){
627       vtkWnd->RemoveActor(theActor);
628       if(theActor->hasIO()){
629         Handle(SALOME_InteractiveObject) anIO = theActor->getIO();
630         if(anIO->hasEntry()){
631           std::string anEntry = anIO->getEntry();
632           SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( vtkWnd->getViewManager()->study() );
633           int aStudyId = aStudy->id();
634           TVisualObjCont::key_type aKey(aStudyId,anEntry);
635           VISUAL_OBJ_CONT.erase(aKey);
636         }
637       }
638       theActor->Delete();
639       vtkWnd->Repaint();
640     }
641   }
642
643   //================================================================================
644   /*!
645    * \brief Return true if there are no SMESH actors in a view
646    */
647   //================================================================================
648
649   bool noSmeshActors(SUIT_ViewWindow *theWnd)
650   {
651     if(SVTK_ViewWindow* aViewWindow = GetVtkViewWindow(theWnd)) {
652       vtkRenderer *aRenderer = aViewWindow->getRenderer();
653       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
654       vtkActorCollection *aCollection = aCopy.GetActors();
655       aCollection->InitTraversal();
656       while(vtkActor *anAct = aCollection->GetNextActor())
657         if(dynamic_cast<SMESH_Actor*>(anAct))
658           return false;
659     }
660     return true;
661   }
662
663   bool UpdateView(SUIT_ViewWindow *theWnd, EDisplaing theAction, const char* theEntry)
664   {
665     bool OK = false;
666     SVTK_ViewWindow* aViewWnd = GetVtkViewWindow(theWnd);
667     if (!aViewWnd)
668       return OK;
669
670     {
671       OK = true;
672       vtkRenderer *aRenderer = aViewWnd->getRenderer();
673       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
674       vtkActorCollection *aCollection = aCopy.GetActors();
675       aCollection->InitTraversal();
676
677       switch (theAction) {
678       case eDisplayAll: {
679         while (vtkActor *anAct = aCollection->GetNextActor()) {
680           if (SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)) {
681             anActor->SetVisibility(true);
682           }
683         }
684         break;
685       }
686       case eDisplayOnly:
687       case eEraseAll: {
688         while (vtkActor *anAct = aCollection->GetNextActor()) {
689           if (SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)) {
690             anActor->SetVisibility(false);
691           }
692         }
693       }
694       default: {
695         if (SMESH_Actor *anActor = FindActorByEntry(theWnd,theEntry)) {
696           switch (theAction) {
697             case eDisplay:
698             case eDisplayOnly:
699               anActor->SetVisibility(true);
700               if (theAction == eDisplayOnly) aRenderer->ResetCameraClippingRange();
701               break;
702             case eErase:
703               anActor->SetVisibility(false);
704               break;
705           }
706         } else {
707           switch (theAction) {
708           case eDisplay:
709           case eDisplayOnly:
710             {
711               SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>(theWnd->getViewManager()->study());
712               _PTR(Study) aDocument = aStudy->studyDS();
713               // Pass non-visual objects (hypotheses, etc.), return true in this case
714               CORBA::Long anId = aDocument->StudyId();
715               if (TVisualObjPtr aVisualObj = GetVisualObj(anId,theEntry))
716               {
717                 if ((anActor = CreateActor(aDocument,theEntry,true))) {
718                   bool needFitAll = noSmeshActors(theWnd); // fit for the first object only
719                   DisplayActor(theWnd,anActor);
720                   // FitAll(); - PAL16770(Display of a group performs an automatic fit all)
721                   if (needFitAll) FitAll();
722                 } else {
723                   OK = false;
724                 }
725               }
726               break;
727             }
728           }
729         }
730       }
731       }
732     }
733     return OK;
734   }
735
736
737   bool UpdateView(EDisplaing theAction, const char* theEntry){
738     SalomeApp_Study* aStudy = dynamic_cast< SalomeApp_Study* >( GetActiveStudy() );
739     SalomeApp_Application* app = dynamic_cast< SalomeApp_Application* >( aStudy->application() );
740     SUIT_ViewWindow *aWnd = app->activeViewManager()->getActiveView();
741     return UpdateView(aWnd,theAction,theEntry);
742   }
743
744   void UpdateView(){
745     if(SVTK_ViewWindow* aWnd = SMESH::GetCurrentVtkView()){
746       LightApp_SelectionMgr* mgr = SMESHGUI::selectionMgr();
747       SALOME_ListIO selected; mgr->selectedObjects( selected );
748
749       if( selected.Extent() == 0){
750         vtkRenderer* aRenderer = aWnd->getRenderer();
751         VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
752         vtkActorCollection *aCollection = aCopy.GetActors();
753         aCollection->InitTraversal();
754         while(vtkActor *anAct = aCollection->GetNextActor()){
755           if(SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)){
756             if(anActor->hasIO())
757               if (!Update(anActor->getIO(),anActor->GetVisibility()))
758                 break; // avoid multiple warinings if visu failed
759           }
760         }
761       }else{
762         SALOME_ListIteratorOfListIO anIter( selected );
763         for( ; anIter.More(); anIter.Next()){
764           Handle(SALOME_InteractiveObject) anIO = anIter.Value();
765           if ( !Update(anIO,true) )
766             break; // avoid multiple warinings if visu failed
767         }
768       }
769       RepaintCurrentView();
770     }
771   }
772
773
774   bool Update(const Handle(SALOME_InteractiveObject)& theIO, bool theDisplay)
775   {
776     _PTR(Study) aStudy = GetActiveStudyDocument();
777     CORBA::Long anId = aStudy->StudyId();
778     if ( TVisualObjPtr aVisualObj = SMESH::GetVisualObj(anId,theIO->getEntry())) {
779       if ( theDisplay )
780         UpdateView(SMESH::eDisplay,theIO->getEntry());
781       return true;
782     }
783     return false;
784   }
785
786
787   void UpdateSelectionProp( SMESHGUI* theModule ) {
788     if( !theModule )
789       return;
790
791     SalomeApp_Application* app = dynamic_cast< SalomeApp_Application* >( theModule->application() );
792     if( !app )
793     {
794       MESSAGE( "UpdateSelectionProp: Application is null" );
795       return;
796     }
797
798     SUIT_ViewManager* vm = app->activeViewManager();
799     if( !vm )
800     {
801       MESSAGE( "UpdateSelectionProp: View manager is null" );
802       return;
803     }
804
805     QVector<SUIT_ViewWindow*> views = vm->getViews();
806
807     SUIT_ResourceMgr* mgr = SMESH::GetResourceMgr( theModule );
808     if( !mgr )
809     {
810       MESSAGE( "UpdateSelectionProp: Resource manager is null" );
811       return;
812     }
813
814     QColor aHiColor = mgr->colorValue( "SMESH", "selection_object_color", Qt::white ),
815            aSelColor = mgr->colorValue( "SMESH", "selection_element_color", Qt::yellow ),
816            aPreColor = mgr->colorValue( "SMESH", "highlight_color", Qt::cyan );
817
818     int SW = mgr->integerValue( "SMESH", "selection_width", 5 ),
819         PW = mgr->integerValue( "SMESH", "highlight_width", 5 );
820
821     // adjust highlight_width to the width of mesh entities
822     int aPointSize  = mgr->integerValue("SMESH", "node_size", 3);
823     int aElem0DSize = mgr->integerValue("SMESH", "elem0d_size", 5);
824     int aLineWidth  = mgr->integerValue("SMESH", "element_width", 1);
825     int maxSize = aPointSize;
826     if (aElem0DSize > maxSize) maxSize = aElem0DSize;
827     if (aLineWidth > maxSize) maxSize = aLineWidth;
828     if (PW < maxSize + 2) PW = maxSize + 2;
829
830     double SP1 = mgr->doubleValue( "SMESH", "selection_precision_node", 0.025 ),
831            SP2 = mgr->doubleValue( "SMESH", "selection_precision_element", 0.001 ),
832            SP3 = mgr->doubleValue( "SMESH", "selection_precision_object", 0.025 );
833
834     for ( int i=0, n=views.count(); i<n; i++ ){
835       // update VTK viewer properties
836       if(SVTK_ViewWindow* aVtkView = GetVtkViewWindow( views[i] )){
837         // mesh element selection
838         aVtkView->SetSelectionProp(aSelColor.red()/255.,
839                                    aSelColor.green()/255.,
840                                    aSelColor.blue()/255.,
841                                    SW );
842         // tolerances
843         aVtkView->SetSelectionTolerance(SP1, SP2, SP3);
844
845         // pre-selection
846         aVtkView->SetPreselectionProp(aPreColor.red()/255.,
847                                       aPreColor.green()/255.,
848                                       aPreColor.blue()/255.,
849                                       PW);
850         // update actors
851         vtkRenderer* aRenderer = aVtkView->getRenderer();
852         VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
853         vtkActorCollection *aCollection = aCopy.GetActors();
854         aCollection->InitTraversal();
855         while(vtkActor *anAct = aCollection->GetNextActor()){
856           if(SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)){
857             anActor->SetHighlightColor(aHiColor.red()/255.,
858                                        aHiColor.green()/255.,
859                                        aHiColor.blue()/255.);
860             anActor->SetPreHighlightColor(aPreColor.red()/255.,
861                                           aPreColor.green()/255.,
862                                           aPreColor.blue()/255.);
863           }
864         }
865       }
866     }
867   }
868
869
870   //----------------------------------------------------------------------------
871   SVTK_Selector*
872   GetSelector(SUIT_ViewWindow *theWindow)
873   {
874     if(SVTK_ViewWindow* aWnd = GetVtkViewWindow(theWindow))
875       return aWnd->GetSelector();
876
877     return NULL;
878   }
879
880   void SetFilter(const Handle(VTKViewer_Filter)& theFilter,
881                  SVTK_Selector* theSelector)
882   {
883     if (theSelector)
884       theSelector->SetFilter(theFilter);
885   }
886
887   Handle(VTKViewer_Filter) GetFilter(int theId, SVTK_Selector* theSelector)
888   {
889     return theSelector->GetFilter(theId);
890   }
891
892   bool IsFilterPresent(int theId, SVTK_Selector* theSelector)
893   {
894     return theSelector->IsFilterPresent(theId);
895   }
896
897   void RemoveFilter(int theId, SVTK_Selector* theSelector)
898   {
899     theSelector->RemoveFilter(theId);
900   }
901
902   void RemoveFilters(SVTK_Selector* theSelector)
903   {
904     for ( int id = SMESH::NodeFilter; theSelector && id < SMESH::LastFilter; id++ )
905       theSelector->RemoveFilter( id );
906   }
907
908   bool IsValid(SALOME_Actor* theActor, int theCellId,
909                SVTK_Selector* theSelector)
910   {
911     return theSelector->IsValid(theActor,theCellId);
912   }
913
914
915   //----------------------------------------------------------------------------
916   void SetPointRepresentation(bool theIsVisible){
917     if(SVTK_ViewWindow* aViewWindow = GetCurrentVtkView()){
918       vtkRenderer *aRenderer = aViewWindow->getRenderer();
919       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
920       vtkActorCollection *aCollection = aCopy.GetActors();
921       aCollection->InitTraversal();
922       while(vtkActor *anAct = aCollection->GetNextActor()){
923         if(SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct)){
924           if(anActor->GetVisibility()){
925             anActor->SetPointRepresentation(theIsVisible);
926           }
927         }
928       }
929       RepaintCurrentView();
930     }
931   }
932
933
934   void SetPickable(SMESH_Actor* theActor){
935     if(SVTK_ViewWindow* aWnd = GetCurrentVtkView()){
936       int anIsAllPickable = (theActor == NULL);
937       vtkRenderer *aRenderer = aWnd->getRenderer();
938       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
939       vtkActorCollection *aCollection = aCopy.GetActors();
940       aCollection->InitTraversal();
941       while(vtkActor *anAct = aCollection->GetNextActor()){
942         if(SALOME_Actor *anActor = dynamic_cast<SALOME_Actor*>(anAct)){
943           if(anActor->GetVisibility()){
944             anActor->SetPickable(anIsAllPickable);
945           }
946         }
947       }
948       if(theActor)
949         theActor->SetPickable(!anIsAllPickable);
950       RepaintCurrentView();
951     }
952   }
953
954
955   //----------------------------------------------------------------------------
956   int GetNameOfSelectedNodes(SVTK_Selector* theSelector,
957                              const Handle(SALOME_InteractiveObject)& theIO,
958                              QString& theName)
959   {
960     theName = "";
961     TColStd_IndexedMapOfInteger aMapIndex;
962     theSelector->GetIndex(theIO,aMapIndex);
963
964     for(int i = 1; i <= aMapIndex.Extent(); i++)
965       theName += QString(" %1").arg(aMapIndex(i));
966
967     return aMapIndex.Extent();
968   }
969
970   int GetNameOfSelectedElements(SVTK_Selector* theSelector,
971                                 const Handle(SALOME_InteractiveObject)& theIO,
972                                 QString& theName)
973   {
974     theName = "";
975     TColStd_IndexedMapOfInteger aMapIndex;
976     theSelector->GetIndex(theIO,aMapIndex);
977
978     typedef std::set<int> TIdContainer;
979     TIdContainer anIdContainer;
980     for( int i = 1; i <= aMapIndex.Extent(); i++)
981       anIdContainer.insert(aMapIndex(i));
982
983     TIdContainer::const_iterator anIter = anIdContainer.begin();
984     for( ; anIter != anIdContainer.end(); anIter++)
985       theName += QString(" %1").arg(*anIter);
986
987     return aMapIndex.Extent();
988   }
989
990
991   int GetEdgeNodes(SVTK_Selector* theSelector,
992                    const TVisualObjPtr& theVisualObject,
993                    int& theId1,
994                    int& theId2)
995   {
996     const SALOME_ListIO& selected = theSelector->StoredIObjects();
997
998     if ( selected.Extent() != 1 )
999       return -1;
1000
1001     Handle(SALOME_InteractiveObject) anIO = selected.First();
1002     if ( anIO.IsNull() || !anIO->hasEntry() )
1003       return -1;
1004
1005     TColStd_IndexedMapOfInteger aMapIndex;
1006     theSelector->GetIndex( anIO, aMapIndex );
1007     if ( aMapIndex.Extent() != 2 )
1008       return -1;
1009
1010     int anObjId = -1, anEdgeNum = -1;
1011     for ( int i = 1; i <= aMapIndex.Extent(); i++ ) {
1012       int aVal = aMapIndex( i );
1013       if ( aVal > 0 )
1014         anObjId = aVal;
1015       else
1016         anEdgeNum = abs( aVal ) - 1;
1017     }
1018
1019     if ( anObjId == -1 || anEdgeNum == -1 )
1020       return -1;
1021
1022     return theVisualObject->GetEdgeNodes( anObjId, anEdgeNum, theId1, theId2 ) ? 1 : -1;
1023   }
1024
1025   //----------------------------------------------------------------------------
1026   int GetNameOfSelectedNodes(LightApp_SelectionMgr *theMgr,
1027                              const Handle(SALOME_InteractiveObject)& theIO,
1028                              QString& theName)
1029   {
1030     theName = "";
1031     if(theIO->hasEntry()){
1032       if(FindActorByEntry(theIO->getEntry())){
1033         TColStd_IndexedMapOfInteger aMapIndex;
1034         theMgr->GetIndexes(theIO,aMapIndex);
1035         for(int i = 1; i <= aMapIndex.Extent(); i++){
1036           theName += QString(" %1").arg(aMapIndex(i));
1037         }
1038         return aMapIndex.Extent();
1039       }
1040     }
1041     return -1;
1042   }
1043
1044   int GetNameOfSelectedNodes(LightApp_SelectionMgr *theMgr, QString& theName){
1045     theName = "";
1046     SALOME_ListIO selected; theMgr->selectedObjects( selected );
1047     if(selected.Extent() == 1){
1048       Handle(SALOME_InteractiveObject) anIO = selected.First();
1049       return GetNameOfSelectedNodes(theMgr,anIO,theName);
1050     }
1051     return -1;
1052   }
1053
1054
1055   int GetNameOfSelectedElements(LightApp_SelectionMgr *theMgr,
1056                                 const Handle(SALOME_InteractiveObject)& theIO,
1057                                 QString& theName)
1058   {
1059     theName = "";
1060     if(theIO->hasEntry()){
1061       if(FindActorByEntry(theIO->getEntry())){
1062         TColStd_IndexedMapOfInteger aMapIndex;
1063         theMgr->GetIndexes(theIO,aMapIndex);
1064         typedef std::set<int> TIdContainer;
1065         TIdContainer anIdContainer;
1066         for( int i = 1; i <= aMapIndex.Extent(); i++)
1067           anIdContainer.insert(aMapIndex(i));
1068         TIdContainer::const_iterator anIter = anIdContainer.begin();
1069         for( ; anIter != anIdContainer.end(); anIter++){
1070           theName += QString(" %1").arg(*anIter);
1071         }
1072         return aMapIndex.Extent();
1073       }
1074     }
1075     return -1;
1076   }
1077
1078
1079   int GetNameOfSelectedElements(LightApp_SelectionMgr *theMgr, QString& theName)
1080   {
1081     theName = "";
1082     SALOME_ListIO selected; theMgr->selectedObjects( selected );
1083
1084     if( selected.Extent() == 1){
1085       Handle(SALOME_InteractiveObject) anIO = selected.First();
1086       return GetNameOfSelectedElements(theMgr,anIO,theName);
1087     }
1088     return -1;
1089   }
1090
1091   int GetSelected(LightApp_SelectionMgr*       theMgr,
1092                   TColStd_IndexedMapOfInteger& theMap,
1093                   const bool                   theIsElement)
1094   {
1095     theMap.Clear();
1096     SALOME_ListIO selected; theMgr->selectedObjects( selected );
1097
1098     if ( selected.Extent() == 1 )
1099     {
1100       Handle(SALOME_InteractiveObject) anIO = selected.First();
1101       if ( anIO->hasEntry() ) {
1102         theMgr->GetIndexes( anIO, theMap );
1103       }
1104     }
1105     return theMap.Extent();
1106   }
1107
1108
1109   int GetEdgeNodes( LightApp_SelectionMgr* theMgr, int& theId1, int& theId2 )
1110   {
1111     SALOME_ListIO selected; theMgr->selectedObjects( selected );
1112
1113     if ( selected.Extent() != 1 )
1114       return -1;
1115
1116     Handle(SALOME_InteractiveObject) anIO = selected.First();
1117     if ( anIO.IsNull() || !anIO->hasEntry() )
1118       return -1;
1119
1120     SMESH_Actor *anActor = SMESH::FindActorByEntry( anIO->getEntry() );
1121     if ( anActor == 0 )
1122       return -1;
1123
1124     TColStd_IndexedMapOfInteger aMapIndex;
1125     theMgr->GetIndexes( anIO, aMapIndex );
1126     if ( aMapIndex.Extent() != 2 )
1127       return -1;
1128
1129     int anObjId = -1, anEdgeNum = -1;
1130     for ( int i = 1; i <= aMapIndex.Extent(); i++ ) {
1131       int aVal = aMapIndex( i );
1132       if ( aVal > 0 )
1133         anObjId = aVal;
1134       else
1135         anEdgeNum = abs( aVal );
1136     }
1137
1138     if ( anObjId == -1 || anEdgeNum == -1 )
1139       return -1;
1140
1141     return anActor->GetObject()->GetEdgeNodes( anObjId, anEdgeNum, theId1, theId2 ) ? 1 : -1;
1142   }
1143
1144   void SetControlsPrecision( const long theVal )
1145   {
1146     if( SVTK_ViewWindow* aWnd = SMESH::GetCurrentVtkView() )
1147     {
1148       vtkRenderer *aRenderer = aWnd->getRenderer();
1149       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
1150       vtkActorCollection *aCollection = aCopy.GetActors();
1151       aCollection->InitTraversal();
1152
1153       while ( vtkActor *anAct = aCollection->GetNextActor())
1154       {
1155         if ( SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>( anAct ) )
1156         {
1157           anActor->SetControlsPrecision( theVal );
1158           anActor->SetControlMode( anActor->GetControlMode() );
1159         }
1160       }
1161
1162     }
1163   }
1164 } // end of namespace SMESH