]> SALOME platform Git repositories - modules/paravis.git/blob - src/PVGUI/PVGUI_Module.cxx
Salome HOME
c7a6f540ecdb7abccf21b4c175322004543d5c08
[modules/paravis.git] / src / PVGUI / PVGUI_Module.cxx
1 // PARAVIS : ParaView wrapper SALOME module
2 //
3 // Copyright (C) 2010-2014  CEA/DEN, EDF R&D
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 //
19 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 //
21 // File   : PVGUI_Module.cxx
22
23 #include <Standard_math.hxx>  // E.A. must be included before Python.h to fix compilation on windows
24 #ifdef HAVE_FINITE
25 #undef HAVE_FINITE            // VSR: avoid compilation warning on Linux : "HAVE_FINITE" redefined
26 #endif
27 #include <vtkPython.h> // Python first
28 #include "PVGUI_Module.h"
29
30 #ifdef PARAVIS_WITH_FULL_CORBA
31 # include "PARAVIS_Gen_i.hh"
32 #endif
33
34 #include CORBA_SERVER_HEADER(SALOME_ModuleCatalog)
35 #include CORBA_SERVER_HEADER(SALOMEDS)
36
37 #include "PVGUI_ViewModel.h"
38 #include "PVGUI_ViewManager.h"
39 #include "PVGUI_ViewWindow.h"
40 #include "PVGUI_Tools.h"
41 #include "PVGUI_ParaViewSettingsPane.h"
42 #include "PVGUI_OutputWindowAdapter.h"
43 #include "PVGUI_Behaviors.h"
44
45 // SALOME Includes
46 #include <SUIT_DataBrowser.h>
47 #include <SUIT_Desktop.h>
48 #include <SUIT_MessageBox.h>
49 #include <SUIT_ResourceMgr.h>
50 #include <SUIT_Session.h>
51 #include <SUIT_OverrideCursor.h>
52 #include <SUIT_ExceptionHandler.h>
53
54 #include <SALOME_LifeCycleCORBA.hxx>
55 #include <SALOMEDS_SObject.hxx>
56
57 #include <LightApp_SelectionMgr.h>
58 #include <LightApp_NameDlg.h>
59 #include <SalomeApp_Application.h>
60 #include <SalomeApp_Study.h>
61 #include <SALOME_ListIO.hxx>
62 #include <SALOMEDS_Tool.hxx>
63 #include <Utils_ORB_INIT.hxx>
64 #include <Utils_SINGLETON.hxx>
65
66 #include <QtxActionMenuMgr.h>
67 #include <QtxActionToolMgr.h>
68
69 #include <PARAVIS_version.h>
70
71 // External includes
72 #include <sstream>
73
74 #include <QAction>
75 #include <QApplication>
76 #include <QCursor>
77 #include <QDir>
78 #include <QFile>
79 #include <QFileInfo>
80 #include <QIcon>
81 #include <QInputDialog>
82 #include <QMenu>
83 #include <QStatusBar>
84 #include <QString>
85 #include <QStringList>
86 #include <QTimer>
87 #include <QToolBar>
88 #include <QTextStream>
89 #include <QShortcut>
90 #include <QDockWidget>
91 #include <QHelpEngine>
92
93 // Paraview includes
94 #include <vtkPVConfig.h>  // for symbol PARAVIEW_VERSION
95 #include <vtkProcessModule.h>
96 #include <vtkPVSession.h>
97 #include <vtkPVProgressHandler.h>
98 #include <vtkOutputWindow.h>
99 #include <vtkEventQtSlotConnect.h>
100 #include <vtkNew.h>
101 #include <vtkSMProxy.h>
102 #include <vtkSmartPointer.h>
103 #include <vtkSMSession.h>
104 #include <vtkSMTrace.h>
105 #include <vtkSMSessionProxyManager.h>
106 #include <vtkSMParaViewPipelineController.h>
107
108 #include <pqApplicationCore.h>
109 //#include <pqPVApplicationCore.h>
110 #include <pqActiveView.h>
111 #include <pqObjectBuilder.h>
112 #include <pqOptions.h>
113 #include <pqSettings.h>
114 #include <pqServer.h>
115 #include <pqUndoStack.h>
116 #include <pqTabbedMultiViewWidget.h>
117 #include <pqActiveObjects.h>
118 #include <pqHelpReaction.h>
119 #include <pqPluginManager.h>
120 #include <pqPythonDialog.h>
121 #include <pqPythonManager.h>
122 #include <pqLoadDataReaction.h>
123 #include <pqPythonScriptEditor.h>
124 #include <pqDataRepresentation.h>
125 #include <pqDisplayColorWidget.h>
126 #include <pqColorToolbar.h>
127 #include <pqScalarBarVisibilityReaction.h>
128 #include <pqServerResource.h>
129 #include <pqServerConnectReaction.h>
130 #include <pqServerDisconnectReaction.h>
131
132 //----------------------------------------------------------------------------
133 PVGUI_Module* ParavisModule = 0;
134
135 /*!
136   \mainpage
137
138   <h2>Building and installing PARAVIS</h2>
139   As any other SALOME module, PARAVIS requires PARAVIS_ROOT_DIR environment variable to be set to PARAVIS
140   installation directory.
141   Other variables needed for correct detection of ParaView location:
142   \li PVHOME - points at the ParaView installation directory tree
143   \li PVVERSION - number of ParaView version
144
145   It also requires common SALOME environment including GUI_ROOT_DIR and other prerequsites.
146
147
148   PARAVIS module can be launched using the following commands:
149   \li Full SALOME configuration
150   \code
151   runSalome --modules="PARAVIS"
152   \endcode
153
154   <h2>ParaView GUI integration</h2>
155   <h3>ParaView GUI integration overview</h3>
156
157   The main idea is to reuse ParaView GUI internal logic as much as possible, providing a layer 
158   between it and SALOME GUI that hides the following SALOME GUI implementation details from ParaView:
159
160   \li SALOME GUI executable and Qt event loop
161   \li SALOME GUI desktop
162   \li Dock windows areas
163   \li SALOME menu and toolbar managers
164
165   Major part of the integration is implemented in PVGUI_Module class.
166
167   <h3>ParaView client initalization</h3>
168
169   ParaView client initalization is performed when an instance of PVGUI_Module class has been created 
170   and \link PVGUI_Module::initialize() PVGUI_Module::initialize()\endlink method is called by SALOME GUI.
171   The actual client start-up is done in \link PVGUI_Module::pvInit() PVGUI_Module::pvInit()\endlink method. 
172   
173
174   <h3>Multi-view manager</h3>
175
176   SALOME GUI requires that each kind of view be implemnted with help of (at least) three classes. For ParaView multi-view manager 
177   these are:
178
179   \li PVGUI_ViewManager - view manager class
180   \li PVGUI_Viewer      - view model class
181   \li PVGUI_ViewWindow  - view window class that acts as a parent for %pqViewManager
182
183   Single instances of PVGUI_ViewManager and PVGUI_ViewWindow classes are created by \link PVGUI_Module::showView() 
184   PVGUI_Module::showView()\endlink method upon the first PARAVIS module activation. The same method hides the multi-view manager 
185   when the module is deactivated (the user switches to another module or a study is closed). 
186   A special trick is used to make PVGUI_ViewWindow the parent of %pqViewManager widget. It is created initally by %pqMainWindowCore
187   with the desktop as a parent, so when it is shown PVGUI_ViewWindow instance is passed to its setParent() method. In  
188   \link PVGUI_ViewWindow::~PVGUI_ViewWindow() PVGUI_ViewWindow::~PVGUI_ViewWindow()\endlink the parent is nullified to avoid deletion
189   of %pqViewManager widget that would break %pqMainWindowCore class.
190
191   <h3>ParaView plugins</h3>
192   ParaView server and client plugins are managed by %pqMainWindowCore slots that has full access to PARAVIS menus and toolbars. 
193   As a result they appears automatically in PARAVIS menus and toolbars if loaded successfully.
194 */
195
196 /*!
197   \class PVGUI_Module
198   \brief Implementation 
199          SALOME module wrapping ParaView GUI.
200 */
201
202 /*!
203   Clean up function; used to stop ParaView progress events when
204   exception is caught by global exception handler.
205 */
206 void paravisCleanUp()
207 {
208   if ( pqApplicationCore::instance() ) {
209     pqServer* s = pqApplicationCore::instance()->getActiveServer();
210     if ( s ) s->session()->GetProgressHandler()->CleanupPendingProgress();
211   }
212 }
213
214 /*!
215   \brief Constructor. Sets the default name for the module.
216 */
217 PVGUI_Module::PVGUI_Module()
218   : SalomeApp_Module( "PARAVIS" ),
219     mySelectionControlsTb( -1 ),
220     mySourcesMenuId( -1 ),
221     myFiltersMenuId( -1 ),
222     myMacrosMenuId(-1),
223     myToolbarsMenuId(-1),
224     myRecentMenuId(-1),
225     myOldMsgHandler(0),
226     myTraceWindow(0),
227     myStateCounter(0),
228     myInitTimer(0),
229     myPushTraceTimer(0)
230 {
231 #ifdef HAS_PV_DOC
232   Q_INIT_RESOURCE( PVGUI );
233 #endif
234   ParavisModule = this;
235
236   // Clear old copies of embedded macros files
237   QString aDestPath = QString( "%1/.config/%2/Macros" ).arg( QDir::homePath() ).arg( QApplication::applicationName() );
238   QStringList aFilter;
239   aFilter << "*.py";
240
241   QDir aDestDir(aDestPath);
242   QStringList aDestFiles = aDestDir.entryList(aFilter, QDir::Files);
243   foreach (QString aMacrosPath, getEmbeddedMacrosList()) {
244     QString aMacrosName = QFileInfo(aMacrosPath).fileName();
245     if (aDestFiles.contains(aMacrosName)) {
246       aDestDir.remove(aMacrosName);
247     }
248   }
249 }
250
251 /*!
252   \brief Destructor.
253 */
254 PVGUI_Module::~PVGUI_Module()
255 {
256   if (myPushTraceTimer)
257     delete myPushTraceTimer;
258   if (myInitTimer)
259     delete myInitTimer;
260   // Disconnect from server
261   pqServer* server = pqActiveObjects::instance().activeServer();
262   if (server && server->isRemote())
263     {
264       MESSAGE("~PVGUI_Module(): Disconnecting from remote server ...");
265       pqServerDisconnectReaction::disconnectFromServer();
266     }
267 }
268
269 PARAVIS_ORB::PARAVIS_Gen_var PVGUI_Module::GetEngine()
270 {
271   return PVGUI_ViewerModel::GetEngine();
272 }
273
274 /*!
275   \brief Initialize module. Creates menus, prepares context menu, etc.
276   \param app SALOME GUI application instance
277 */
278 void PVGUI_Module::initialize( CAM_Application* app )
279 {
280   SalomeApp_Module::initialize( app );
281
282   // Create ParaViS actions
283   createActions();
284   // Create ParaViS menus
285   createMenus();
286
287   // Uncomment to debug ParaView initialization
288   // "aa" used instead of "i" as GDB doesn't like "i" variables :)
289   /*
290   int aa = 1;
291   while( aa ){
292     aa = aa;
293   }
294   */
295   
296   // Initialize ParaView client
297   pvInit();
298
299   // Create GUI elements (menus, toolbars, dock widgets)
300   SalomeApp_Application* anApp = getApp();
301   SUIT_Desktop* aDesktop = anApp->desktop();
302
303   // Remember current state of desktop toolbars
304   QList<QToolBar*> foreignToolbars = aDesktop->findChildren<QToolBar*>();
305
306   setupDockWidgets();
307
308   pvCreateActions();
309   pvCreateToolBars();
310   pvCreateMenus();
311
312   QList<QDockWidget*> activeDocks = aDesktop->findChildren<QDockWidget*>();
313   QList<QMenu*> activeMenus = aDesktop->findChildren<QMenu*>();
314
315   PVGUI_Behaviors * behav = new PVGUI_Behaviors(this);
316   behav->instanciateAllBehaviors(aDesktop);
317
318   // Setup quick-launch shortcuts.
319   QShortcut *ctrlSpace = new QShortcut(Qt::CTRL + Qt::Key_Space, aDesktop);
320   QObject::connect(ctrlSpace, SIGNAL(activated()),
321     pqApplicationCore::instance(), SLOT(quickLaunch()));
322
323   // Find Plugin Dock Widgets
324   QList<QDockWidget*> currentDocks = aDesktop->findChildren<QDockWidget*>();
325   QList<QDockWidget*>::iterator i;
326   for (i = currentDocks.begin(); i != currentDocks.end(); ++i) {
327     if(!activeDocks.contains(*i)) {
328       myDockWidgets[*i] = false; // hidden by default
329       (*i)->hide();
330     }
331   }
332
333     // Find Plugin Menus
334     // [ABN] TODO: fix this - triggers a SEGFAULT at deactivation() time.
335 //    QList<QMenu*> currentMenus = aDesktop->findChildren<QMenu*>();
336 //    QList<QMenu*>::iterator im;
337 //    for (im = currentMenus.begin(); im != currentMenus.end(); ++im) {
338 //      if(!activeMenus.contains(*im)) {
339 //          QString s = (*im)->title();
340 //          std::cout << " MENU "<<  s.toStdString() << std::endl;
341 //          myMenus.append(*im);
342 //      }
343 //    }
344
345   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
346   QString aPath = resMgr->stringValue("resources", "PARAVIS", QString());
347   if (!aPath.isNull()) {
348     MyCoreApp->loadConfiguration(aPath + QDir::separator() + "ParaViewFilters.xml");
349     MyCoreApp->loadConfiguration(aPath + QDir::separator() + "ParaViewReaders.xml");
350     MyCoreApp->loadConfiguration(aPath + QDir::separator() + "ParaViewSources.xml");
351     MyCoreApp->loadConfiguration(aPath + QDir::separator() + "ParaViewWriters.xml");
352   }
353
354   // Force creation of the PARAVIS engine
355   GetEngine();
356   updateObjBrowser();
357
358   // Find created toolbars
359   QCoreApplication::processEvents();
360
361   QList<QToolBar*> allToolbars = aDesktop->findChildren<QToolBar*>();
362   foreach(QToolBar* aBar, allToolbars) {
363     if (!foreignToolbars.contains(aBar)) {
364       myToolbars[aBar] = true;
365       myToolbarBreaks[aBar] = false;
366       aBar->setVisible(false);
367       aBar->toggleViewAction()->setVisible(false);
368     }
369   }
370
371   updateMacros();
372  
373   SUIT_ResourceMgr* aResourceMgr = SUIT_Session::session()->resourceMgr();
374   bool isStop = aResourceMgr->booleanValue( "PARAVIS", "stop_trace", false );
375   if(!isStop)
376     {
377       // Start a timer to schedule asap:
378       //  - the connection to the server
379       //  - the trace start
380       myInitTimer = new QTimer(aDesktop);
381       QObject::connect(myInitTimer, SIGNAL(timeout()), this, SLOT(onInitTimer()) );
382       myInitTimer->setSingleShot(true);
383       myInitTimer->start(0);
384
385       // Another timer to regularly push the trace onto the engine:
386       myPushTraceTimer = new QTimer(aDesktop);
387       QObject::connect(myPushTraceTimer, SIGNAL(timeout()), this, SLOT(onPushTraceTimer()) );
388       myPushTraceTimer->setSingleShot(false);
389       myPushTraceTimer->start(500);
390     }
391
392   this->VTKConnect = vtkEventQtSlotConnect::New();
393   
394   vtkProcessModule* pm = vtkProcessModule::GetProcessModule();
395   if(pm) {
396     vtkPVSession* pvs = dynamic_cast<vtkPVSession*>(pm->GetSession());
397     if(pvs) {
398       vtkPVProgressHandler* ph = pvs->GetProgressHandler();
399       if(ph) {
400           this->VTKConnect->Connect(ph, vtkCommand::StartEvent,
401                                     this, SLOT(onStartProgress()));
402           this->VTKConnect->Connect(ph, vtkCommand::EndEvent,
403                                     this, SLOT(onEndProgress()));
404       }
405     }
406   }
407 }
408
409 void PVGUI_Module::onStartProgress()
410 {
411   QApplication::setOverrideCursor(Qt::WaitCursor);
412 }
413
414 void PVGUI_Module::onEndProgress()
415 {
416   QApplication::restoreOverrideCursor();
417 }
418
419 void PVGUI_Module::onDataRepresentationUpdated() {
420   SalomeApp_Study* activeStudy = dynamic_cast<SalomeApp_Study*>(application()->activeStudy());
421   if(!activeStudy) return;
422   
423   activeStudy->Modified();
424 }
425
426 /*!
427   \brief Initialisation timer event - fired only once, after the GUI loop is ready.
428   See creation in initialize().
429 */
430 void PVGUI_Module::onInitTimer()
431 {
432 #ifndef PARAVIS_WITH_FULL_CORBA
433   connectToExternalPVServer();
434 #endif
435   startTrace();
436 }
437   
438 /*!
439   \brief Get list of embedded macros files
440 */
441 QStringList PVGUI_Module::getEmbeddedMacrosList()
442 {
443   QString aRootDir = getenv("PARAVIS_ROOT_DIR");
444
445   QString aSourcePath = aRootDir + "/bin/salome/Macro";
446
447   QStringList aFilter;
448   aFilter << "*.py";
449
450   QDir aSourceDir(aSourcePath);
451   QStringList aSourceFiles = aSourceDir.entryList(aFilter, QDir::Files);
452   QStringList aFullPathSourceFiles;
453   foreach (QString aMacrosName, aSourceFiles) {
454     aFullPathSourceFiles << aSourceDir.absoluteFilePath(aMacrosName);
455   }
456   return aFullPathSourceFiles;
457 }
458
459 void PVGUI_Module::updateMacros()
460 {
461   pqPythonManager* aPythonManager = pqPVApplicationCore::instance()->pythonManager();
462   if(!aPythonManager)  {
463     return;
464   }
465   
466   foreach (QString aStr, getEmbeddedMacrosList()) {
467     aPythonManager->addMacro(aStr);
468   }
469 }
470
471
472 /*!
473   \brief Get list of compliant dockable GUI elements
474   \param m map to be filled in ("type":"default_position")
475 */
476 void PVGUI_Module::windows( QMap<int, int>& m ) const
477 {
478   m.insert( LightApp_Application::WT_ObjectBrowser, Qt::LeftDockWidgetArea );
479   m.insert( LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea );
480   // ParaView diagnostic output redirected here
481   m.insert( LightApp_Application::WT_LogWindow, Qt::BottomDockWidgetArea );
482 }
483
484 /*!
485   \brief Shows (toShow = true) or hides ParaView view window
486 */
487 void PVGUI_Module::showView( bool toShow )
488 {
489   PVGUI_ViewManager
490   SalomeApp_Application* anApp = getApp();
491   PVGUI_ViewManager* viewMgr =
492     dynamic_cast<PVGUI_ViewManager*>( anApp->getViewManager( PVGUI_Viewer::Type(), false ) );
493   if ( !viewMgr ) {
494     viewMgr = new PVGUI_ViewManager( anApp->activeStudy(), anApp->desktop() );
495     anApp->addViewManager( viewMgr );
496     connect( viewMgr, SIGNAL( lastViewClosed( SUIT_ViewManager* ) ),
497              anApp, SLOT( onCloseView( SUIT_ViewManager* ) ) );
498   }
499
500   PVGUI_ViewWindow* pvWnd = dynamic_cast<PVGUI_ViewWindow*>( viewMgr->getActiveView() );
501   if ( !pvWnd ) {
502     pvWnd = dynamic_cast<PVGUI_ViewWindow*>( viewMgr->createViewWindow() );
503   }
504
505   pvWnd->setShown( toShow );
506   if ( toShow ) pvWnd->setFocus();
507 }
508
509 /*!
510   \brief Slot to show help for proxy.
511 */
512 void PVGUI_Module::showHelpForProxy( const QString& groupname, const QString& proxyname )
513 {
514   pqHelpReaction::showProxyHelp(groupname, proxyname);
515 }
516
517
518 /*!
519   \brief Slot to show the waiting state.
520 */
521 void PVGUI_Module::onPreAccept()
522 {
523   getApp()->desktop()->statusBar()->showMessage(tr("STB_PREACCEPT"));
524   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
525 }
526
527 /*!
528   \brief Slot to show the ready state.
529 */
530 void PVGUI_Module::onPostAccept()
531 {
532   getApp()->desktop()->statusBar()->showMessage(tr("STB_POSTACCEPT"), 2000);
533   QTimer::singleShot(0, this, SLOT(endWaitCursor()));
534 }
535
536 /*!
537   \brief Slot to switch off wait cursor.
538 */
539 void PVGUI_Module::endWaitCursor()
540 {
541   QApplication::restoreOverrideCursor();
542 }
543
544 static void ParavisMessageOutput(QtMsgType type, const char *msg)
545 {
546   switch(type)
547     {
548   case QtDebugMsg:
549     vtkOutputWindow::GetInstance()->DisplayText(msg);
550     break;
551   case QtWarningMsg:
552     vtkOutputWindow::GetInstance()->DisplayErrorText(msg);
553     break;
554   case QtCriticalMsg:
555     vtkOutputWindow::GetInstance()->DisplayErrorText(msg);
556     break;
557   case QtFatalMsg:
558     vtkOutputWindow::GetInstance()->DisplayErrorText(msg);
559     break;
560     }
561 }
562
563 /*!
564   \brief Activate module.
565   \param study current study
566   \return \c true if activaion is done successfully or 0 to prevent
567   activation on error
568 */
569 bool PVGUI_Module::activateModule( SUIT_Study* study )
570 {
571   myOldMsgHandler = qInstallMsgHandler(ParavisMessageOutput);
572   
573   SUIT_ExceptionHandler::addCleanUpRoutine( paravisCleanUp );
574
575   storeCommonWindowsState();
576
577   bool isDone = SalomeApp_Module::activateModule( study );
578   if ( !isDone ) return false;
579
580   showView( true );
581   if ( mySourcesMenuId != -1 ) menuMgr()->show(mySourcesMenuId);
582   if ( myFiltersMenuId != -1 ) menuMgr()->show(myFiltersMenuId);
583   if ( myFiltersMenuId != -1 ) menuMgr()->show(myMacrosMenuId);
584   if ( myFiltersMenuId != -1 ) menuMgr()->show(myToolbarsMenuId);
585   setMenuShown( true );
586   setToolShown( true );
587
588   restoreDockWidgetsState();
589
590   QMenu* aMenu = menuMgr()->findMenu( myRecentMenuId );
591   if(aMenu) {
592     QList<QAction*> anActns = aMenu->actions();
593     for (int i = 0; i < anActns.size(); ++i) {
594       QAction* a = anActns.at(i);
595       if(a)
596         a->setVisible(true);
597     }
598   }
599
600   QList<QMenu*>::iterator it;
601   for (it = myMenus.begin(); it != myMenus.end(); ++it) {
602     QAction* a = (*it)->menuAction();
603     if(a)
604       a->setVisible(true);
605   }
606
607   if ( myRecentMenuId != -1 ) menuMgr()->show(myRecentMenuId);
608
609 //  ClientFindOrCreateParavisComponent(PARAVIS::GetCStudy(this));
610
611   return isDone;
612 }
613
614
615 /*!
616   \brief Deactivate module.
617   \param study current study
618   \return \c true if deactivaion is done successfully or 0 to prevent
619   deactivation on error
620 */
621 bool PVGUI_Module::deactivateModule( SUIT_Study* study )
622 {
623   MESSAGE("PARAVIS deactivation ...")
624
625   QMenu* aMenu = menuMgr()->findMenu( myRecentMenuId );
626   if(aMenu) {
627     QList<QAction*> anActns = aMenu->actions();
628     for (int i = 0; i < anActns.size(); ++i) {
629       QAction* a = anActns.at(i);
630       if(a)
631         a->setVisible(false);
632     }
633   }
634
635   QList<QMenu*>::iterator it;
636   for (it = myMenus.begin(); it != myMenus.end(); ++it) {
637     QAction* a = (*it)->menuAction();
638     if(a)
639       a->setVisible(false);
640   }
641
642   QList<QDockWidget*> aStreamingViews = application()->desktop()->findChildren<QDockWidget*>("pqStreamingControls");
643   foreach(QDockWidget* aView, aStreamingViews) {
644     if (!myDockWidgets.contains(aView))
645       myDockWidgets[aView] = aView->isVisible();
646   }
647
648   /*if (pqImplementation::helpWindow) {
649     pqImplementation::helpWindow->hide();
650     }*/
651   showView( false );
652   // hide menus
653   menuMgr()->hide(myRecentMenuId);
654   menuMgr()->hide(mySourcesMenuId);
655   menuMgr()->hide(myFiltersMenuId);
656   menuMgr()->hide(myMacrosMenuId);
657   menuMgr()->hide(myToolbarsMenuId);
658   setMenuShown( false );
659   setToolShown( false );
660
661   saveDockWidgetsState();
662
663   SUIT_ExceptionHandler::removeCleanUpRoutine( paravisCleanUp );
664
665   if (myOldMsgHandler)
666     qInstallMsgHandler(myOldMsgHandler);
667
668   restoreCommonWindowsState();
669   
670   return SalomeApp_Module::deactivateModule( study );
671 }
672
673
674 /*!
675   \brief Called when application is closed.
676
677   Process finalize application functionality from ParaView in order to save server settings
678   and nullify application pointer if the application is being closed.
679
680   \param theApp application
681 */
682 void PVGUI_Module::onApplicationClosed( SUIT_Application* theApp )
683 {
684   pqApplicationCore::instance()->settings()->sync();
685   int aAppsNb = SUIT_Session::session()->applications().size();
686   if (aAppsNb == 1) {
687     deleteTemporaryFiles();
688     MyCoreApp->deleteLater();
689   }
690   CAM_Module::onApplicationClosed(theApp);
691 }
692
693
694 /*!
695   \brief Deletes temporary files created during import operation from VISU
696 */
697 void PVGUI_Module::deleteTemporaryFiles()
698 {
699   foreach(QString aFile, myTemporaryFiles) {
700     if (QFile::exists(aFile)) {
701       QFile::remove(aFile);
702     }
703   }
704 }
705
706
707 /*!
708   \brief Called when study is closed.
709
710   Removes data model from the \a study.
711
712   \param study study being closed
713 */
714 void PVGUI_Module::studyClosed(SUIT_Study* study)
715 {
716   clearParaviewState();
717
718   SalomeApp_Module::studyClosed(study);
719 }
720
721 /*!
722   \brief Called when study is opened.
723 */
724 void PVGUI_Module::onModelOpened()
725 {
726   _PTR(Study) studyDS = PARAVIS::GetCStudy(this);
727   if(!studyDS) {
728     return;
729   }
730   
731   _PTR(SComponent) paravisComp = 
732     studyDS->FindComponent(GetEngine()->ComponentDataType());
733   if(!paravisComp) {
734     return;
735   }
736
737   _PTR(ChildIterator) anIter(studyDS->NewChildIterator(paravisComp));
738   for (; anIter->More(); anIter->Next()) {
739     _PTR(SObject) aSObj = anIter->Value();
740     _PTR(GenericAttribute) anAttr;
741     if (!aSObj->FindAttribute(anAttr, "AttributeLocalID")) {
742       continue;
743     }
744     _PTR(AttributeLocalID) anID(anAttr);
745     if (anID->Value() == PVSTATEID) {
746       myStateCounter++;
747     }
748   }
749 }
750
751 /*!
752   \brief Returns IOR of current engine
753 */
754 QString PVGUI_Module::engineIOR() const
755 {
756   CORBA::String_var anIOR = GetEngine()->GetIOR();
757   return QString(anIOR.in());
758 }
759
760 /*!
761   \brief Open file of format supported by ParaView
762 */
763 void PVGUI_Module::openFile(const char* theName)
764 {
765   QStringList aFiles;
766   aFiles<<theName;
767   pqLoadDataReaction::loadData(aFiles);
768 }
769
770 /**!
771  * Start trace invoking the newly introduced C++ API (PV 4.2)
772  * (inspired from pqTraceReaction::start())
773  */
774 void PVGUI_Module::startTrace()
775 {
776   vtkSMSessionProxyManager* pxm = pqActiveObjects::instance().activeServer()->proxyManager();
777
778   vtkSmartPointer<vtkSMProxy> proxy;
779   proxy.TakeReference(pxm->NewProxy("pythontracing", "PythonTraceOptions"));
780   if (proxy)
781     {
782       vtkNew<vtkSMParaViewPipelineController> controller;
783       controller->InitializeProxy(proxy);
784     }
785   vtkSMTrace* trace = vtkSMTrace::StartTrace();
786   if (proxy)
787     {
788       // Set manually the properties entered via the dialog box poping-up when requiring
789       // a trace start in PV4.2 (trace options)
790       trace->SetPropertiesToTraceOnCreate(vtkSMTrace::RECORD_USER_MODIFIED_PROPERTIES);
791       trace->SetFullyTraceSupplementalProxies(false);
792     }
793 }
794
795 void PVGUI_Module::stopTrace()
796 {
797   vtkSMTrace::StopTrace();
798 }
799
800 void PVGUI_Module::executeScript(const char *script)
801 {
802 #ifndef WNT
803   pqPythonManager* manager = qobject_cast<pqPythonManager*>(
804                              pqApplicationCore::instance()->manager("PYTHON_MANAGER"));
805   if (manager)  {
806     pqPythonDialog* pyDiag = manager->pythonShellDialog();
807     if (pyDiag) {
808       pyDiag->runString(script);  
809       }
810     }
811 #endif
812 }
813
814 ///**
815 // *  Debug function printing out the given interpreter's execution context
816 // */
817 //void printInterpContext(PyInterp_Interp * interp )
818 //{
819 //  // Extract __smtraceString from interpreter's context
820 //  const PyObject* ctxt = interp->getExecutionContext();
821 //
822 //  PyObject* lst = PyDict_Keys((PyObject *)ctxt);
823 //  Py_ssize_t siz = PyList_GET_SIZE(lst);
824 //  for (Py_ssize_t i = 0; i < siz; i++)
825 //    {
826 //      PyObject * elem = PyList_GetItem(lst, i);
827 //      if (PyString_Check(elem))
828 //        {
829 //          std::cout << "At pos:" << i << ", " << PyString_AsString(elem) << std::endl;
830 //        }
831 //      else
832 //        std::cout << "At pos:" << i << ", not a string!" << std::endl;
833 //    }
834 //  Py_XDECREF(lst);
835 //}
836
837 /*!
838   \brief Returns trace string
839 */
840 static const QString MYReplaceStr("paraview.simple");
841 static const QString MYReplaceImportStr("except: from pvsimple import *");
842 QString PVGUI_Module::getTraceString()
843 {
844   vtkSMTrace *tracer = vtkSMTrace::GetActiveTracer();
845   if (!tracer) // trace is not started
846     return QString("");
847
848   QString traceString(tracer->GetCurrentTrace());
849
850   // Replace import "paraview.simple" by "pvsimple"
851   if ((!traceString.isNull()) && traceString.length() != 0) {
852     int aPos = traceString.indexOf(MYReplaceStr);
853     while (aPos != -1) {
854       traceString = traceString.replace(aPos, MYReplaceStr.length(), "pvsimple");
855       aPos = traceString.indexOf(MYReplaceStr, aPos);
856     }
857     int aImportPos = traceString.indexOf(MYReplaceImportStr);
858     if(aImportPos != -1)
859       {
860       traceString = traceString.replace(aImportPos, MYReplaceImportStr.length(), "except:\n  import pvsimple\n  from pvsimple import *");
861       }
862   }
863
864   return traceString;
865 }
866
867 /*!
868   \brief Saves trace string to disk file
869 */
870 void PVGUI_Module::saveTrace(const char* theName)
871 {
872   QFile file(theName);
873   if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
874     MESSAGE( "Could not open file:" << theName );
875     return;
876   }
877   QTextStream out(&file);
878   out << getTraceString();
879   file.close();
880 }
881
882 /*!
883   \brief Saves ParaView state to a disk file
884 */
885 void PVGUI_Module::saveParaviewState(const char* theFileName)
886 {
887   pqApplicationCore::instance()->saveState(theFileName);
888 }
889
890 /*!
891   \brief Delete all objects for Paraview Pipeline Browser
892 */
893 void PVGUI_Module::clearParaviewState()
894 {
895   QAction* deleteAllAction = action(DeleteAllId);
896   if (deleteAllAction) {
897     deleteAllAction->activate(QAction::Trigger);
898   }
899 }
900
901 /*!
902   \brief Restores ParaView state from a disk file
903
904   If toClear == true, the current ojects will be deleted
905 */
906 void PVGUI_Module::loadParaviewState(const char* theFileName)
907 {
908   pqApplicationCore::instance()->loadState(theFileName, getActiveServer());
909 }
910
911 /*!
912   \brief Returns current active ParaView server
913 */
914 pqServer* PVGUI_Module::getActiveServer()
915 {
916   return pqApplicationCore::instance()->getActiveServer();
917 }
918
919
920 /*!
921   \brief Creates PARAVIS preference pane 
922 */
923 void PVGUI_Module::createPreferences()
924 {
925   // Paraview settings tab
926   int aParaViewSettingsTab = addPreference( tr( "TIT_PVIEWSETTINGS" ) );
927   int aPanel = addPreference(QString(), aParaViewSettingsTab, LightApp_Preferences::UserDefined, "PARAVIS", "");
928   setPreferenceProperty(aPanel, "content", (qint64)(new PVGUI_ParaViewSettingsPane()));
929
930   // Paravis settings tab
931   int aParaVisSettingsTab = addPreference( tr( "TIT_PVISSETTINGS" ) );
932   addPreference( tr( "PREF_STOP_TRACE" ), aParaVisSettingsTab, LightApp_Preferences::Bool, "PARAVIS", "stop_trace");
933
934   int aSaveType = addPreference(tr( "PREF_SAVE_TYPE_LBL" ), aParaVisSettingsTab,
935                                 LightApp_Preferences::Selector,
936                                 "PARAVIS", "savestate_type");
937   QList<QVariant> aIndices;
938   QStringList aStrings;
939   aIndices<<0<<1<<2;
940   aStrings<<tr("PREF_SAVE_TYPE_0");
941   aStrings<<tr("PREF_SAVE_TYPE_1");
942   aStrings<<tr("PREF_SAVE_TYPE_2");
943   setPreferenceProperty(aSaveType, "strings", aStrings);
944   setPreferenceProperty(aSaveType, "indexes", aIndices);
945 }
946
947 /*!
948   \brief Creates ParaViS context menu popup
949 */
950 void PVGUI_Module::contextMenuPopup(const QString& theClient, QMenu* theMenu, QString& theTitle)
951 {
952   SalomeApp_Module::contextMenuPopup(theClient, theMenu, theTitle);
953   
954   // Check if we are in Object Browser
955   SUIT_DataBrowser* ob = getApp()->objectBrowser();
956   bool isOBClient = (ob && theClient == ob->popupClientType());
957   if (!isOBClient) {
958     return;
959   }
960
961   // Get list of selected objects
962   LightApp_SelectionMgr* aSelectionMgr = getApp()->selectionMgr();
963   SALOME_ListIO aListIO;
964   aSelectionMgr->selectedObjects(aListIO);
965   if (aListIO.Extent() == 1 && aListIO.First()->hasEntry()) {
966     QString entry = QString(aListIO.First()->getEntry());
967     
968     // Get active study
969     SalomeApp_Study* activeStudy = 
970       dynamic_cast<SalomeApp_Study*>(getApp()->activeStudy());
971     if(!activeStudy) {
972       return;
973     }
974
975     // Get SALOMEDS client study 
976     _PTR(Study) studyDS = activeStudy->studyDS();
977     if(!studyDS) {
978       return;
979     }
980
981     QString paravisDataType(GetEngine()->ComponentDataType());
982     if(activeStudy && activeStudy->isComponent(entry) && 
983        activeStudy->componentDataType(entry) == paravisDataType) {
984       // ParaViS module object
985       theMenu->addSeparator();
986       theMenu->addAction(action(SaveStatePopupId));
987     }
988     else {
989       // Try to get state object
990       _PTR(SObject) stateSObj = 
991           studyDS->FindObjectID(entry.toLatin1().constData());
992       if (!stateSObj) {
993           return;
994       }
995       
996       // Check local id
997       _PTR(GenericAttribute) anAttr;
998       if (!stateSObj->FindAttribute(anAttr, "AttributeLocalID")) {
999           return;
1000       }
1001
1002       _PTR(AttributeLocalID) anID(anAttr);
1003       
1004       if (anID->Value() == PVSTATEID) {
1005         // Paraview state object
1006         theMenu->addSeparator();
1007         theMenu->addAction(action(AddStatePopupId));
1008         theMenu->addAction(action(CleanAndAddStatePopupId));
1009         theMenu->addSeparator();
1010         theMenu->addAction(action(ParaVisRenameId));
1011         theMenu->addAction(action(ParaVisDeleteId));
1012       }
1013     }
1014   }
1015 }
1016
1017 /*!
1018   \brief. Show ParaView python trace.
1019 */
1020 void PVGUI_Module::onShowTrace()
1021 {
1022   if (!myTraceWindow) {
1023     myTraceWindow = new pqPythonScriptEditor(getApp()->desktop());
1024   }
1025   myTraceWindow->setText(getTraceString());
1026   myTraceWindow->show();
1027   myTraceWindow->raise();
1028   myTraceWindow->activateWindow();
1029 }
1030
1031
1032 /*!
1033   \brief. Re-initialize ParaView python trace.
1034 */
1035 void PVGUI_Module::onRestartTrace()
1036 {
1037   stopTrace();
1038   startTrace();
1039 }
1040
1041 /*!
1042   \brief Show ParaView view.
1043 */
1044 void PVGUI_Module::onNewParaViewWindow()
1045 {
1046   showView(true);
1047 }
1048
1049 /*!
1050   \brief Save state under the module root object.
1051 */
1052 void PVGUI_Module::onSaveMultiState()
1053 {
1054   // Create state study object
1055   
1056   // Get SALOMEDS client study
1057   _PTR(Study) studyDS = PARAVIS::GetCStudy(this);
1058   if(!studyDS) {
1059     return;
1060   }
1061   
1062   _PTR(SComponent) paravisComp = 
1063     studyDS->FindComponent(GetEngine()->ComponentDataType());
1064   if(!paravisComp) {
1065     return;
1066   }
1067
1068   // Unlock the study if it is locked
1069   bool isLocked = studyDS->GetProperties()->IsLocked();
1070   if (isLocked) {
1071     studyDS->GetProperties()->SetLocked(false);
1072   }
1073   
1074   QString stateName = tr("SAVED_PARAVIEW_STATE_NAME") + 
1075     QString::number(myStateCounter + 1);
1076
1077   _PTR(StudyBuilder) studyBuilder = studyDS->NewBuilder();
1078   _PTR(SObject) newSObj = studyBuilder->NewObject(paravisComp);
1079
1080   // Set name
1081   _PTR(GenericAttribute) anAttr;
1082   anAttr = studyBuilder->FindOrCreateAttribute(newSObj, "AttributeName");
1083   _PTR(AttributeName) nameAttr(anAttr);
1084   
1085   nameAttr->SetValue(stateName.toLatin1().constData());
1086
1087   // Set local id
1088   anAttr = studyBuilder->FindOrCreateAttribute(newSObj, "AttributeLocalID");
1089   _PTR(AttributeLocalID) localIdAttr(anAttr);
1090   
1091   localIdAttr->SetValue(PVSTATEID);
1092
1093   // Set file name
1094   QString stateEntry = QString::fromStdString(newSObj->GetID());
1095  
1096   // File name for state saving
1097   QString tmpDir = QString::fromStdString(SALOMEDS_Tool::GetTmpDir());
1098   QString fileName = QString("%1_paravisstate:%2").arg(tmpDir, stateEntry);
1099
1100   anAttr = studyBuilder->FindOrCreateAttribute(newSObj, "AttributeString");
1101   _PTR(AttributeString) stringAttr(anAttr);
1102   
1103   stringAttr->SetValue(fileName.toLatin1().constData());
1104
1105   // Lock the study back if necessary
1106   if (isLocked) {
1107     studyDS->GetProperties()->SetLocked(true);
1108   }
1109   
1110   // Save state
1111   saveParaviewState(fileName.toLatin1().constData());
1112   myTemporaryFiles.append(fileName);
1113   
1114   // Increment the counter
1115   myStateCounter++;
1116
1117   updateObjBrowser();
1118 }
1119
1120 /*!
1121   \brief Restore the selected state by merging with the current one.
1122 */
1123 void PVGUI_Module::onAddState()
1124 {
1125   loadSelectedState(false);
1126 }
1127
1128 /*!
1129   \brief Clean the current state and restore the selected one.
1130 */
1131 void PVGUI_Module::onCleanAddState()
1132 {
1133   loadSelectedState(true);
1134 }
1135
1136 /*!
1137   \brief Rename the selected object.
1138 */
1139 void PVGUI_Module::onRename()
1140 {
1141   LightApp_SelectionMgr* aSelectionMgr = getApp()->selectionMgr();
1142   SALOME_ListIO aListIO;
1143   aSelectionMgr->selectedObjects(aListIO);
1144   
1145   if (aListIO.Extent() == 1 && aListIO.First()->hasEntry()) {
1146     std::string entry = aListIO.First()->getEntry();
1147     
1148     // Get SALOMEDS client study 
1149     _PTR(Study) studyDS = PARAVIS::GetCStudy(this);
1150     if(!studyDS) {
1151       return;
1152     }
1153     
1154     // Unlock the study if it is locked
1155     bool isLocked = studyDS->GetProperties()->IsLocked();
1156     if (isLocked) {
1157       studyDS->GetProperties()->SetLocked(false);
1158     }
1159     
1160     // Rename the selected state object
1161     _PTR(SObject) stateSObj = studyDS->FindObjectID(entry);
1162     if (!stateSObj) {
1163       return;
1164     }
1165     
1166     _PTR(GenericAttribute) anAttr;
1167     if (stateSObj->FindAttribute(anAttr, "AttributeName")) {
1168       _PTR(AttributeName) nameAttr (anAttr);
1169       QString newName = 
1170           LightApp_NameDlg::getName(getApp()->desktop(), nameAttr->Value().c_str());
1171       if (!newName.isEmpty()) {
1172         nameAttr->SetValue(newName.toLatin1().constData());
1173         aListIO.First()->setName(newName.toLatin1().constData());
1174       }
1175     }
1176     
1177     // Lock the study back if necessary
1178     if (isLocked) {
1179       studyDS->GetProperties()->SetLocked(true);
1180     }
1181     
1182     // Update object browser
1183     updateObjBrowser();
1184     
1185   }
1186 }
1187
1188 /*!
1189   \brief Delete the selected objects.
1190 */
1191 void PVGUI_Module::onDelete()
1192 {
1193   LightApp_SelectionMgr* aSelectionMgr = getApp()->selectionMgr();
1194   SALOME_ListIO aListIO;
1195   aSelectionMgr->selectedObjects(aListIO);
1196   
1197   if (aListIO.Extent() == 1 && aListIO.First()->hasEntry()) {
1198     std::string entry = aListIO.First()->getEntry();
1199     
1200     // Get SALOMEDS client study 
1201     _PTR(Study) studyDS = PARAVIS::GetCStudy(this);
1202     if(!studyDS) {
1203       return;
1204     }
1205     
1206     // Unlock the study if it is locked
1207     bool isLocked = studyDS->GetProperties()->IsLocked();
1208     if (isLocked) {
1209       studyDS->GetProperties()->SetLocked(false);
1210     }
1211     
1212     // Remove the selected state from the study
1213     _PTR(StudyBuilder) studyBuilder = studyDS->NewBuilder();
1214     _PTR(SObject) stateSObj = studyDS->FindObjectID(entry);
1215     studyBuilder->RemoveObject(stateSObj);
1216     
1217     // Lock the study back if necessary
1218     if (isLocked) {
1219       studyDS->GetProperties()->SetLocked(true);
1220     }
1221     
1222     // Update object browser
1223     updateObjBrowser();
1224   }
1225 }
1226
1227 void PVGUI_Module::onPushTraceTimer()
1228 {
1229 //  MESSAGE("onPushTraceTimer(): Pushing trace to engine...");
1230   GetEngine()->PutPythonTraceStringToEngine(getTraceString().toStdString().c_str());
1231 }
1232
1233 /*!
1234   \brief Discover help project files from the resources.
1235   \return name of the help file. 
1236 */
1237 QString PVGUI_Module::getHelpFileName() {
1238   QString aPVHome(getenv("PVHOME"));
1239   if (aPVHome.isNull()) {
1240     qWarning("Wariable PVHOME is not defined");
1241     return QString();
1242   }
1243   QChar aSep = QDir::separator();
1244   //PARAVIEW_VERSION from the vtkPVConfig.h file
1245   QString aFileName =  aPVHome + aSep + "share" + aSep + "doc" + aSep + "paraview-"+ PARAVIEW_VERSION + aSep + "paraview.qch";
1246   return aFileName;
1247 }
1248
1249
1250 /*!
1251   \brief Load selected paraview state
1252
1253   If toClear == true, the current state will be cleared
1254 */
1255 void PVGUI_Module::loadSelectedState(bool toClear)
1256 {
1257   QString fileName;
1258
1259   LightApp_SelectionMgr* aSelectionMgr = getApp()->selectionMgr();
1260   SALOME_ListIO aListIO;
1261   aSelectionMgr->selectedObjects(aListIO);
1262   
1263   if (aListIO.Extent() == 1 && aListIO.First()->hasEntry()) {
1264     std::string entry = aListIO.First()->getEntry();
1265     
1266     // Get SALOMEDS client study 
1267     _PTR(Study) studyDS = PARAVIS::GetCStudy(this);
1268     if(!studyDS) {
1269       return;
1270     }
1271
1272     // Check local id
1273     _PTR(SObject) stateSObj = studyDS->FindObjectID(entry);
1274     _PTR(GenericAttribute) anAttr;
1275     if (!stateSObj->FindAttribute(anAttr, "AttributeLocalID")) {
1276       return;
1277     }
1278     _PTR(AttributeLocalID) anID(anAttr);
1279     if (!anID->Value() == PVSTATEID) {
1280       return;
1281     }
1282
1283     // Get state file name
1284     if (stateSObj->FindAttribute(anAttr, "AttributeString")) {
1285       _PTR(AttributeString) aStringAttr(anAttr);
1286       QString stringValue(aStringAttr->Value().c_str());
1287
1288       if (QFile::exists(stringValue)) {
1289           fileName = stringValue;
1290       }
1291     }
1292   }
1293   
1294   if (!fileName.isEmpty()) {
1295     if (toClear) {
1296       clearParaviewState();
1297     }
1298
1299     loadParaviewState(fileName.toLatin1().constData());
1300   } 
1301   else {
1302     SUIT_MessageBox::critical(getApp()->desktop(),
1303                               tr("ERR_ERROR"),
1304                               tr("ERR_STATE_CANNOT_BE_RESTORED"));
1305   }
1306 }
1307
1308 /*!
1309   \fn CAM_Module* createModule();
1310   \brief Export module instance (factory function).
1311   \return new created instance of the module
1312 */
1313
1314 #ifdef WNT
1315 #define PVGUI_EXPORT __declspec(dllexport)
1316 #else   // WNT
1317 #define PVGUI_EXPORT
1318 #endif  // WNT
1319
1320 extern "C" {
1321
1322   bool flag = false;
1323   PVGUI_EXPORT CAM_Module* createModule() {
1324     return new PVGUI_Module();
1325   }
1326   
1327   PVGUI_EXPORT char* getModuleVersion() {
1328     return (char*)PARAVIS_VERSION_STR;
1329   }
1330 }