Salome HOME
a016d4ab83124e69fede871cac8532c74f2b1025
[modules/paravis.git] / src / PVGUI / PVGUI_Module.cxx
1 // PARAVIS : ParaView wrapper SALOME module
2 //
3 // Copyright (C) 2010-2023  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 #define PARAVIS_MODULE_NAME "PARAVIS"
24
25 #include <Standard_math.hxx>  // E.A. must be included before Python.h to fix compilation on windows
26 #ifdef HAVE_FINITE
27 #undef HAVE_FINITE            // VSR: avoid compilation warning on Linux : "HAVE_FINITE" redefined
28 #endif
29 #include <vtkPython.h> // Python first
30
31 #include "PVGUI_Module.h"
32
33 #include "PVViewer_ViewManager.h"
34 #include "PVViewer_Core.h"
35 #include "PVViewer_ViewWindow.h"
36 #include "PVViewer_ViewModel.h"
37 #include "PVGUI_ParaViewSettingsPane.h"
38 #include "PVViewer_GUIElements.h"
39 #include "PVServer_ServiceWrapper.h"
40 #include "PVGUI_DataModel.h"
41
42 // SALOME Includes
43 #include <utilities.h>
44 #include <SUIT_DataBrowser.h>
45 #include <SUIT_Desktop.h>
46 #include <SUIT_MessageBox.h>
47 #include <SUIT_ResourceMgr.h>
48 #include <SUIT_Session.h>
49 #include <SUIT_OverrideCursor.h>
50 #include <SUIT_ExceptionHandler.h>
51
52 #include <LightApp_SelectionMgr.h>
53 #include <LightApp_NameDlg.h>
54 #include <LightApp_Application.h>
55 #include <LightApp_Study.h>
56 #include <SALOME_ListIO.hxx>
57
58 #include <QtxActionMenuMgr.h>
59 #include <QtxActionToolMgr.h>
60
61 #include <PARAVIS_version.h>
62
63 // External includes
64 #include <sstream>
65
66 #include <QAction>
67 #include <QApplication>
68 #include <QCursor>
69 #include <QDir>
70 #include <QFile>
71 #include <QFileInfo>
72 #include <QIcon>
73 #include <QInputDialog>
74 #include <QMenu>
75 #include <QStatusBar>
76 #include <QString>
77 #include <QStringList>
78 #include <QTimer>
79 #include <QToolBar>
80 #include <QTextStream>
81 #include <QShortcut>
82 #include <QDockWidget>
83 #include <QHelpEngine>
84
85 // Paraview includes
86 #include <vtkPVVersion.h>  // for symbol PARAVIEW_VERSION
87 #include <vtkProcessModule.h>
88 #include <vtkPVSession.h>
89 #include <vtkPVProgressHandler.h>
90 #include <vtkEventQtSlotConnect.h>
91 #include <vtkNew.h>
92 #include <vtkSMProxy.h>
93 #include <vtkSmartPointer.h>
94 #include <vtkSMSession.h>
95 #include <vtkSMTrace.h>
96 #include <vtkSMSessionProxyManager.h>
97 #include <vtkSMParaViewPipelineController.h>
98 #include <vtkSmartPyObject.h>
99
100 #include <pqApplicationCore.h>
101 #include <pqPVApplicationCore.h>
102 #include <pqObjectBuilder.h>
103 #include <pqOptions.h>
104 #include <pqSettings.h>
105 #include <pqServer.h>
106 #include <pqUndoStack.h>
107 #include <pqTabbedMultiViewWidget.h>
108 #include <pqActiveObjects.h>
109 #include <pqHelpReaction.h>
110 #include <pqPluginManager.h>
111 //#include <pqPythonDialog.h>
112 #include <pqPythonManager.h>
113 #include <pqLoadDataReaction.h>
114 #include <pqPythonScriptEditor.h>
115 #include <pqDataRepresentation.h>
116 #include <pqDisplayColorWidget.h>
117 #include <pqColorToolbar.h>
118 #include <pqScalarBarVisibilityReaction.h>
119 #include <pqServerResource.h>
120 #include <pqServerConnectReaction.h>
121 #include <pqPluginManager.h>
122 #include <pqVCRToolbar.h>
123 #include <pqAnimationScene.h>
124 #include <pqServerManagerModel.h>
125 #include <pqAnimationTimeToolbar.h>
126 #include <pqPipelineBrowserWidget.h>
127 #include <pqCoreUtilities.h>
128 #include <pqLoadStateReaction.h>
129
130 #if PY_VERSION_HEX < 0x03050000
131 static char*
132 Py_EncodeLocale(const wchar_t *arg, size_t *size)
133 {
134         return _Py_wchar2char(arg, size);
135 }
136 static wchar_t*
137 Py_DecodeLocale(const char *arg, size_t *size)
138 {
139         return _Py_char2wchar(arg, size);
140 }
141 #endif
142
143 //----------------------------------------------------------------------------
144 PVGUI_Module* ParavisModule = 0;
145
146 /*!
147   \mainpage
148   This is the doxygen documentation of the ParaVis module.
149   If you are looking for general information about the structure of the module, you should
150   take a look at the <a href="../index.html">Sphinx documentation</a> first.
151
152   The integration of ParaView into SALOME is split in two parts:
153   \li the PVViewer in the GUI module (folder *src/PVViewer*)
154   \li the ParaVis module itself (the pages you are currently browsing)
155 */
156
157 /*!
158   \class PVGUI_Module
159   \brief Implementation 
160          SALOME module wrapping ParaView GUI.
161 */
162
163 /*!
164   \brief Clean up function
165
166   Used to stop ParaView progress events when
167   exception is caught by global exception handler.
168 */
169 void paravisCleanUp()
170 {
171   if ( pqApplicationCore::instance() ) {
172     pqServer* s = pqApplicationCore::instance()->getActiveServer();
173     if ( s ) s->session()->GetProgressHandler()->CleanupPendingProgress();
174   }
175 }
176
177 /*!
178   \brief Constructor. Sets the default name for the module.
179 */
180 PVGUI_Module::PVGUI_Module()
181   : LightApp_Module( PARAVIS_MODULE_NAME ),
182     mySourcesMenuId( -1 ),
183     myFiltersMenuId( -1 ),
184     myMacrosMenuId(-1),
185     myRecentMenuId(-1),
186     myCatalystMenuId(-1),
187     myOldMsgHandler(0),
188     myTraceWindow(0),
189     myInitTimer(0),
190     myGuiElements(0)
191 {
192 #ifdef HAS_PV_DOC
193   Q_INIT_RESOURCE( PVGUI );
194 #endif
195   ParavisModule = this;
196 }
197
198 /*!
199   \brief Destructor.
200 */
201 PVGUI_Module::~PVGUI_Module()
202 {
203   if (myInitTimer)
204     delete myInitTimer;
205 }
206
207 /*!
208   \brief Retrieve the PVSERVER CORBA engine.
209   This uses the Python wrapper provided
210   by the PVViewer code in GUI (class PVViewer_EngineWrapper).
211   \sa GetCPPEngine()
212 */
213 PVServer_ServiceWrapper* PVGUI_Module::GetEngine()
214 {
215   return PVServer_ServiceWrapper::GetInstance();
216 }
217
218 /*!
219   \brief Create data model.
220   \return module specific data model
221 */
222 CAM_DataModel* PVGUI_Module::createDataModel()
223 {
224   return new PVGUI_DataModel( this );
225 }
226
227 /*!
228   \brief Get the ParaView application singleton.
229 */
230 pqPVApplicationCore* PVGUI_Module::GetPVApplication()
231 {
232   return PVViewer_Core::GetPVApplication();
233 }
234
235 /*!
236   \brief Initialize module. Creates menus, prepares context menu, etc.
237   \param app SALOME GUI application instance
238 */
239 void PVGUI_Module::initialize( CAM_Application* app )
240 {
241   LightApp_Module::initialize( app );
242
243   // Uncomment to debug ParaView initialization
244   // "aa" used instead of "i" as GDB doesn't like "i" variables :)
245   /*
246   int aa = 1;
247   while( aa ){
248     aa = aa;
249   }
250   */
251
252   LightApp_Application* anApp = getApp();
253   SUIT_Desktop* aDesktop = anApp->desktop();
254
255   // Remember current state of desktop toolbars
256   QList<QToolBar*> foreignToolbars = aDesktop->findChildren<QToolBar*>();
257
258   // Initialize ParaView client and associated behaviors
259   // and connect to externally launched pvserver
260   PVViewer_Core::ParaviewInitApp();
261
262   // Clear old copies of embedded macros files
263   //QString aDestPath = QString( "%1/.config/%2/Macros" ).arg( QDir::homePath() ).arg( QApplication::applicationName() );
264   QString aDestPath = pqCoreUtilities::getParaViewUserDirectory() + "/Macros";
265   QStringList aFilter;
266   aFilter << "*.py";
267
268   QDir aDestDir(aDestPath);
269   QStringList aDestFiles = aDestDir.entryList(aFilter, QDir::Files);
270   foreach(QString aMacrosPath, getEmbeddedMacrosList()) {
271           QString aMacrosName = QFileInfo(aMacrosPath).fileName();
272           if (aDestFiles.contains(aMacrosName)) {
273                   aDestDir.remove(aMacrosName);
274           }
275   }
276
277   myGuiElements = PVViewer_GUIElements::GetInstance(aDesktop);
278
279
280   // [ABN]: careful with the order of the GUI element creation, the loading of the configuration
281   // and the connection to the server. This order is very sensitive if one wants to make
282   // sure all menus, etc ... are correctly populated.
283   // Reference points are: ParaViewMainWindow.cxx and branded_paraview_initializer.cxx.in
284   setupDockWidgets();
285
286   pvCreateActions();
287   pvCreateMenus();
288   pvCreateToolBars();
289
290   PVViewer_Core::ParaviewInitBehaviors(true, aDesktop);
291
292   QList<QDockWidget*> activeDocks = aDesktop->findChildren<QDockWidget*>();
293   QList<QMenu*> activeMenus = aDesktop->findChildren<QMenu*>();
294
295   // Setup quick-launch shortcuts.
296   QShortcut *ctrlSpace = new QShortcut(Qt::CTRL + Qt::Key_Space, aDesktop);
297   QObject::connect(ctrlSpace, SIGNAL(activated()),
298     pqApplicationCore::instance(), SLOT(quickLaunch()));
299
300   // Find Plugin Dock Widgets
301   QList<QDockWidget*> currentDocks = aDesktop->findChildren<QDockWidget*>();
302   QList<QDockWidget*>::iterator i;
303   for (i = currentDocks.begin(); i != currentDocks.end(); ++i) {
304     if(!activeDocks.contains(*i)) {
305       myDockWidgets[*i] = false; // hidden by default
306       (*i)->hide();
307     }
308   }
309
310     // Find Plugin Menus
311     // [ABN] TODO: fix this - triggers a SEGFAULT at deactivation() time.
312 //    QList<QMenu*> currentMenus = aDesktop->findChildren<QMenu*>();
313 //    QList<QMenu*>::iterator im;
314 //    for (im = currentMenus.begin(); im != currentMenus.end(); ++im) {
315 //      if(!activeMenus.contains(*im)) {
316 //          QString s = (*im)->title();
317 //          std::cout << " MENU "<<  s.toStdString() << std::endl;
318 //          myMenus.append(*im);
319 //      }
320 //    }
321
322   // Connect after toolbar creation, etc ... as some activations of the toolbars is triggered
323   // by the ServerConnection event:
324   const QString configPath(PVViewer_ViewManager::GetPVConfigPath());
325   PVViewer_Core::ParaviewLoadConfigurations(configPath, true);
326   PVViewer_ViewManager::ConnectToExternalPVServer(aDesktop);
327   updateObjBrowser();
328
329   // Find created toolbars
330   QCoreApplication::processEvents();
331
332   // process PVViewer toolbars (might be added by PVViewer created BEFORE activating ParaVis)
333   QList<QToolBar*> pvToolbars = myGuiElements->getToolbars();
334   foreach(QToolBar* aBar, pvToolbars) {
335     if (!myToolbars.contains(aBar)) {
336       myToolbars[aBar] = true;
337       myToolbarBreaks[aBar] = false;
338       aBar->setVisible(false);
339       aBar->toggleViewAction()->setVisible(false);
340     }
341   }
342
343   // process other toolbars (possibly added by Paraview)
344   QList<QToolBar*> allToolbars = aDesktop->findChildren<QToolBar*>();
345   foreach(QToolBar* aBar, allToolbars) {
346     if (!foreignToolbars.contains(aBar) && !myToolbars.contains(aBar)) {
347       myToolbars[aBar] = true;
348       myToolbarBreaks[aBar] = false;
349       aBar->setVisible(false);
350       aBar->toggleViewAction()->setVisible(false);
351     }
352   }
353
354   updateMacros();
355  
356   SUIT_ResourceMgr* aResourceMgr = SUIT_Session::session()->resourceMgr();
357   bool isStop = aResourceMgr->booleanValue( PARAVIS_MODULE_NAME, "stop_trace", false );
358   if(!isStop)
359     {
360       // Start a timer to schedule asap:
361       //  - the trace start
362       myInitTimer = new QTimer(aDesktop);
363       QObject::connect(myInitTimer, SIGNAL(timeout()), this, SLOT(onInitTimer()) );
364       myInitTimer->setSingleShot(true);
365       myInitTimer->start(0);
366     }
367
368   this->VTKConnect = vtkEventQtSlotConnect::New();
369   
370   vtkProcessModule* pm = vtkProcessModule::GetProcessModule();
371   if(pm) {
372     vtkPVSession* pvs = dynamic_cast<vtkPVSession*>(pm->GetSession());
373     if(pvs) {
374       vtkPVProgressHandler* ph = pvs->GetProgressHandler();
375       if(ph) {
376           this->VTKConnect->Connect(ph, vtkCommand::StartEvent,
377                                     this, SLOT(onStartProgress()));
378           this->VTKConnect->Connect(ph, vtkCommand::EndEvent,
379                                     this, SLOT(onEndProgress()));
380       }
381     }
382   }
383   connect( application(), SIGNAL( appClosed() ), this, SLOT( onStopTrace() ) );
384 }
385
386 /*!
387  * \brief Slot called when the progress bar starts.
388  */
389 void PVGUI_Module::onStartProgress()
390 {
391   // VSR 19/03/2015, issue 0023025
392   // next line is commented: it is bad idea to show wait cursor on ANY vtk event
393   // moreover, it does not work when running pvserver with --multi-client mode
394   //QApplication::setOverrideCursor(Qt::WaitCursor);
395 }
396
397 /*!
398  * \brief Slot called when the progress bar is done.
399  */
400 void PVGUI_Module::onEndProgress()
401 {
402   // VSR 19/03/2015, issue 0023025
403   // next line is commented: it is bad idea to show wait cursor on ANY vtk event
404   // moreover, it does not work when running pvserver with --multi-client mode
405   //QApplication::restoreOverrideCursor();
406 }
407
408 void PVGUI_Module::onDataRepresentationUpdated() {
409   LightApp_Study* activeStudy = dynamic_cast<LightApp_Study*>(application()->activeStudy());
410   if(!activeStudy) return;
411   
412   activeStudy->Modified();
413 }
414
415 /*!
416   \brief Initialisation timer event - Starts up the Python trace
417 */
418 void PVGUI_Module::onInitTimer()
419 {
420   startTrace();
421 }
422   
423 /*!
424   \brief Get list of embedded macros files
425 */
426 QStringList PVGUI_Module::getEmbeddedMacrosList()
427 {
428   QString aRootDir = getenv("PARAVIS_ROOT_DIR");
429
430   QString aSourcePath = aRootDir + "/bin/salome/Macro";
431
432   QStringList aFilter;
433   aFilter << "*.py";
434
435   QDir aSourceDir(aSourcePath);
436   QStringList aSourceFiles = aSourceDir.entryList(aFilter, QDir::Files);
437   QStringList aFullPathSourceFiles;
438   foreach (QString aMacrosName, aSourceFiles) {
439     aFullPathSourceFiles << aSourceDir.absoluteFilePath(aMacrosName);
440   }
441   return aFullPathSourceFiles;
442 }
443
444 /*!
445   \brief Update the list of embedded macros
446 */
447 void PVGUI_Module::updateMacros()
448 {
449   pqPythonManager* aPythonManager = pqPVApplicationCore::instance()->pythonManager();
450   if(!aPythonManager)  {
451     return;
452   }
453   
454   foreach (QString aStr, getEmbeddedMacrosList()) {
455     aPythonManager->addMacro(aStr);
456   }
457 }
458
459
460 /*!
461   \brief Get list of compliant dockable GUI elements
462   \param m map to be filled in ("type":"default_position")
463 */
464 void PVGUI_Module::windows( QMap<int, int>& m ) const
465 {
466   m.insert( LightApp_Application::WT_ObjectBrowser, Qt::LeftDockWidgetArea );
467 #ifndef DISABLE_PYCONSOLE
468   m.insert( LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea );
469 #endif
470   // ParaView diagnostic output redirected here
471   m.insert( LightApp_Application::WT_LogWindow, Qt::BottomDockWidgetArea );
472 }
473
474 /*!
475   \brief Shows (toShow = true) or hides ParaView view window
476 */
477 void PVGUI_Module::showView( bool toShow )
478 {
479   // VSR: TODO: all below is not needed, if we use standard approach
480   // that consists in implementing viewManagers() function properly
481   // This should be done after we decide what to do with Log window.
482   LightApp_Application* anApp = getApp();
483   PVViewer_ViewManager* viewMgr =
484     dynamic_cast<PVViewer_ViewManager*>( anApp->getViewManager( PVViewer_Viewer::Type(), false ) );
485   if ( !viewMgr ) {
486     viewMgr = new PVViewer_ViewManager( anApp->activeStudy(), anApp->desktop() );
487     anApp->addViewManager( viewMgr );
488     connect( viewMgr, SIGNAL( lastViewClosed( SUIT_ViewManager* ) ),
489              anApp, SLOT( onCloseView( SUIT_ViewManager* ) ) );
490   }
491
492   PVViewer_ViewWindow* pvWnd = dynamic_cast<PVViewer_ViewWindow*>( viewMgr->getActiveView() );
493   if ( !pvWnd ) {
494     pvWnd = dynamic_cast<PVViewer_ViewWindow*>( viewMgr->createViewWindow() );
495     // this also connects to the pvserver and instantiates relevant PV behaviors
496   }
497
498   pvWnd->setVisible( toShow );
499   if ( toShow ) pvWnd->setFocus();
500 }
501
502 /*!
503   \brief Slot to show help for proxy.
504 */
505 void PVGUI_Module::showHelpForProxy( const QString& groupname, const QString& proxyname )
506 {
507   pqHelpReaction::showProxyHelp(groupname, proxyname);
508 }
509
510 /*!
511   \brief Slot to show the waiting state.
512 */
513 void PVGUI_Module::onPreAccept()
514 {
515   getApp()->desktop()->statusBar()->showMessage(tr("STB_PREACCEPT"));
516   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
517 }
518
519 /*!
520   \brief Slot to show the ready state.
521 */
522 void PVGUI_Module::onPostAccept()
523 {
524   getApp()->desktop()->statusBar()->showMessage(tr("STB_POSTACCEPT"), 2000);
525   QTimer::singleShot(0, this, SLOT(endWaitCursor()));
526 }
527
528 /*!
529   \brief Slot to switch off wait cursor.
530 */
531 void PVGUI_Module::endWaitCursor()
532 {
533   QApplication::restoreOverrideCursor();
534 }
535
536 /*!
537   \brief Activate module.
538   \param study current study
539   \return \c true if activaion is done successfully or 0 to prevent
540   activation on error
541 */
542 bool PVGUI_Module::activateModule( SUIT_Study* study )
543 {
544   SUIT_ExceptionHandler::addCleanUpRoutine( paravisCleanUp );
545
546   storeCommonWindowsState();
547
548   bool isDone = LightApp_Module::activateModule( study );
549   if ( !isDone ) return false;
550
551   showView( true );
552   if ( mySourcesMenuId != -1 ) menuMgr()->show(mySourcesMenuId);
553   if ( myFiltersMenuId != -1 ) menuMgr()->show(myFiltersMenuId);
554   if ( myMacrosMenuId != -1 ) menuMgr()->show(myMacrosMenuId);
555   if ( myCatalystMenuId != -1 ) menuMgr()->show(myCatalystMenuId);
556
557   // Update the various menus with the content pre-loaded in myGuiElements
558 //  QMenu* srcMenu = menuMgr()->findMenu( mySourcesMenuId );
559 //  myGuiElements->updateSourcesMenu(srcMenu);
560 //  QMenu* filtMenu = menuMgr()->findMenu( myFiltersMenuId );
561 //  myGuiElements->updateFiltersMenu(filtMenu);
562 //  QMenu* macMenu = menuMgr()->findMenu( myMacrosMenuId );
563 //  myGuiElements->updateMacrosMenu(macMenu);
564
565   setMenuShown( true );
566   setToolShown( true );
567
568   restoreDockWidgetsState();
569
570   QMenu* aMenu = menuMgr()->findMenu( myRecentMenuId );
571   if(aMenu) {
572     QList<QAction*> anActns = aMenu->actions();
573     for (int i = 0; i < anActns.size(); ++i) {
574       QAction* a = anActns.at(i);
575       if(a)
576         a->setVisible(true);
577     }
578   }
579
580   QList<QMenu*>::iterator it;
581   for (it = myMenus.begin(); it != myMenus.end(); ++it) {
582     QAction* a = (*it)->menuAction();
583     if(a)
584       a->setVisible(true);
585   }
586
587   if ( myRecentMenuId != -1 ) menuMgr()->show(myRecentMenuId);
588
589   // VSR 18/10/2018 - 0023170: Workaround to re-select current index after module activation
590   QItemSelectionModel* selection_model = myGuiElements->getPipelineBrowserWidget()->getSelectionModel();
591   QModelIndex idx = selection_model->currentIndex();
592   selection_model->clearCurrentIndex();
593   selection_model->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
594
595   return isDone;
596 }
597
598
599 /*!
600   \brief Deactivate module.
601   \param study current study
602   \return \c true if deactivaion is done successfully or 0 to prevent
603   deactivation on error
604 */
605 bool PVGUI_Module::deactivateModule( SUIT_Study* study )
606 {
607   MESSAGE("PARAVIS deactivation ...");
608
609   QMenu* aMenu = menuMgr()->findMenu( myRecentMenuId );
610   if(aMenu) {
611     QList<QAction*> anActns = aMenu->actions();
612     for (int i = 0; i < anActns.size(); ++i) {
613       QAction* a = anActns.at(i);
614       if(a)
615         a->setVisible(false);
616     }
617   }
618
619   QList<QMenu*>::iterator it;
620   for (it = myMenus.begin(); it != myMenus.end(); ++it) {
621     QAction* a = (*it)->menuAction();
622     if(a)
623       a->setVisible(false);
624   }
625
626   QList<QDockWidget*> aStreamingViews = application()->desktop()->findChildren<QDockWidget*>("pqStreamingControls");
627   foreach(QDockWidget* aView, aStreamingViews) {
628     if (!myDockWidgets.contains(aView))
629       myDockWidgets[aView] = aView->isVisible();
630   }
631
632   /*if (pqImplementation::helpWindow) {
633     pqImplementation::helpWindow->hide();
634     }*/
635   // hide menus
636   menuMgr()->hide(myRecentMenuId);
637   menuMgr()->hide(mySourcesMenuId);
638   menuMgr()->hide(myFiltersMenuId);
639   menuMgr()->hide(myMacrosMenuId);
640   menuMgr()->hide(myCatalystMenuId);
641   setMenuShown( false );
642   setToolShown( false );
643
644   saveDockWidgetsState();
645
646   SUIT_ExceptionHandler::removeCleanUpRoutine( paravisCleanUp );
647
648   if (myOldMsgHandler)
649     qInstallMessageHandler(myOldMsgHandler);
650
651   restoreCommonWindowsState();
652   
653   return LightApp_Module::deactivateModule( study );
654 }
655
656
657 /*!
658   \brief Called when application is closed.
659
660   Process finalize application functionality from ParaView in order to save server settings
661   and nullify application pointer if the application is being closed.
662
663   \param theApp application
664 */
665 void PVGUI_Module::onApplicationClosed( SUIT_Application* theApp )
666 {
667   PVViewer_Core::ParaviewCleanup();
668   CAM_Module::onApplicationClosed(theApp);
669 }
670
671 /*!
672   \brief Called when study is closed.
673
674   Removes data model from the \a study.
675
676   \param study study being closed
677 */
678 void PVGUI_Module::studyClosed(SUIT_Study* study)
679 {
680   showView(false); // VSR: this seems to be not needed (all views are automatically closed)
681   clearParaviewState();
682   //Re-start trace 
683   onRestartTrace();
684
685   LightApp_Module::studyClosed(study);
686 }
687
688 /*!
689   \brief Open file of format supported by ParaView
690 */
691 void PVGUI_Module::openFile( const char* theName )
692 {
693   QStringList aFiles;
694   aFiles << theName;
695   pqLoadDataReaction::loadData( aFiles );
696 }
697
698 /*!
699   \brief Starts Python trace.
700  
701   Start trace invoking the newly introduced C++ API (PV 4.2)
702   (inspired from pqTraceReaction::start())
703 */
704 void PVGUI_Module::startTrace()
705 {
706   vtkSMSessionProxyManager* pxm = pqActiveObjects::instance().activeServer()->proxyManager();
707
708   vtkSmartPointer<vtkSMProxy> proxy;
709   proxy.TakeReference( pxm->NewProxy( "pythontracing", "PythonTraceOptions" ) );
710   if ( proxy ) {
711     vtkNew<vtkSMParaViewPipelineController> controller;
712     controller->InitializeProxy( proxy );
713   }
714   vtkSMTrace* trace = vtkSMTrace::StartTrace();
715   if ( proxy ) {
716     // Set manually the properties entered via the dialog box poping-up when requiring
717     // a trace start in PV4.2 (trace options)
718     SUIT_ResourceMgr* aResourceMgr = SUIT_Session::session()->resourceMgr();
719     int type = aResourceMgr->integerValue( PARAVIS_MODULE_NAME, "tracestate_type", 2 );
720     trace->SetPropertiesToTraceOnCreate( type );
721     trace->SetFullyTraceSupplementalProxies( false );
722   }
723 }
724
725 /*!
726   \brief Stops Python trace.
727 */
728 void PVGUI_Module::stopTrace()
729 {
730   vtkSMTrace::StopTrace();
731 }
732
733 /*!
734   \brief Execute a Python script.
735 */
736 void PVGUI_Module::executeScript( const char* script )
737 {
738   // ???
739   // Not sure this is the right fix, but the PYTHON_MANAGER has a function named
740   // executeScript() which seems to do what the runScript on pyShellDialog() class
741   // was doing.
742 #ifndef WNT
743   pqPythonManager* manager =
744     qobject_cast<pqPythonManager*>(pqApplicationCore::instance()->manager("PYTHON_MANAGER"));
745
746   if ( manager )  {
747     manager->executeScript(script);
748   }
749 #endif
750   /*
751 #ifndef WNT
752   pqPythonManager* manager = qobject_cast<pqPythonManager*>(
753                              pqApplicationCore::instance()->manager( "PYTHON_MANAGER" ) );
754   if ( manager )  {
755     pqPythonDialog* pyDiag = manager->pythonShellDialog();
756     if ( pyDiag ) {
757       pyDiag->runString(script);  
758     }
759   }
760 #endif
761   */
762 }
763
764 ///**
765 // *  Debug function printing out the given interpreter's execution context
766 // */
767 //void printInterpContext(PyInterp_Interp * interp )
768 //{
769 //  // Extract __smtraceString from interpreter's context
770 //  const PyObject* ctxt = interp->getExecutionContext();
771 //
772 //  PyObject* lst = PyDict_Keys((PyObject *)ctxt);
773 //  Py_ssize_t siz = PyList_GET_SIZE(lst);
774 //  for (Py_ssize_t i = 0; i < siz; i++)
775 //    {
776 //      PyObject * elem = PyList_GetItem(lst, i);
777 //      if (PyString_Check(elem))
778 //        {
779 //          std::cout << "At pos:" << i << ", " << Py_EncodeLocale(PyUnicode_AS_UNICODE(elem), NULL) << std::endl;
780 //        }
781 //      else
782 //        std::cout << "At pos:" << i << ", not a string!" << std::endl;
783 //    }
784 //  Py_XDECREF(lst);
785 //}
786
787 /*!
788   \brief Returns trace string
789 */
790 QString PVGUI_Module::getTraceString()
791 {
792   QString traceString = "";
793
794   static const QString replaceStr( "paraview.simple" );
795   std::stringstream nl;
796   nl << std::endl; // surely there is some Qt trick to do that in a portable way??
797   QString end_line( nl.str().c_str() );
798
799   vtkSMTrace* tracer = vtkSMTrace::GetActiveTracer();
800   if ( tracer ) {
801     traceString = tracer->GetCurrentTrace().c_str();
802     // 'import pvsimple' is necessary to fix the first call to DisableFirstRenderCamera in the paraview trace
803     // 'ShowParaviewView()' ensure there is an opened viewing window (otherwise SEGFAULT!)
804     traceString = "import pvsimple" + end_line +
805       "pvsimple.ShowParaviewView()" + end_line + traceString;
806
807     // Replace import "paraview.simple" by "pvsimple"
808     if ( !traceString.isEmpty() ) {
809       int aPos = traceString.indexOf( replaceStr );
810       while ( aPos != -1 ) {
811         traceString = traceString.replace( aPos, replaceStr.length(), "pvsimple" );
812         aPos = traceString.indexOf( replaceStr, aPos );
813       }
814     }
815   }
816
817   // Save camera position to, which is no longer output by the tracer ...
818   {
819     vtkPythonScopeGilEnsurer psge;
820     PyObject * mods(PySys_GetObject(const_cast<char*>("modules")));
821     PyObject * trace_mod(PyDict_GetItemString(mods, "paraview.smtrace"));  // module was already (really) imported by vtkSMTrace
822     if (trace_mod && trace_mod != Py_None && PyModule_Check(trace_mod)) {
823         vtkSmartPyObject save_cam(PyObject_GetAttrString(trace_mod, const_cast<char*>("SaveCameras")));
824         vtkSmartPyObject camera_trace(PyObject_CallMethod(save_cam, const_cast<char*>("get_trace"), NULL));
825         // Convert to a single string
826         vtkSmartPyObject ret(PyUnicode_FromUnicode(Py_DecodeLocale(end_line.toStdString().c_str(), NULL), end_line.size()));
827         vtkSmartPyObject final_string(PyObject_CallMethod(ret, const_cast<char*>("join"),
828             const_cast<char*>("O"), (PyObject*)camera_trace));
829         if (PyUnicode_CheckExact(final_string))
830           {
831             QString camera_qs(Py_EncodeLocale(PyUnicode_AS_UNICODE(final_string.GetPointer()), NULL));  // deep copy
832             traceString = traceString + end_line  + end_line + QString("#### saving camera placements for all active views")
833                 + end_line + end_line + camera_qs + end_line;
834           }
835       }
836   } 
837
838   return traceString;
839 }
840
841 /*!
842   \brief Saves trace string to disk file
843 */
844 void PVGUI_Module::saveTrace( const char* theName )
845 {
846   QFile file( theName );
847   if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) {
848     MESSAGE( "Could not open file:" << theName );
849     return;
850   }
851   QTextStream out( &file );
852   out << getTraceString();
853   file.close();
854 }
855
856 /*!
857   \brief Saves ParaView state to a disk file
858 */
859 void PVGUI_Module::saveParaviewState( const QString& theFileName )
860 {
861   pqApplicationCore::instance()->saveState( theFileName.toStdString().c_str() );
862 }
863
864 /*!
865   \brief Delete all objects for Paraview Pipeline Browser
866 */
867 void PVGUI_Module::clearParaviewState()
868 {
869   QAction* deleteAllAction = action( DeleteAllId );
870   if ( deleteAllAction ) {
871     deleteAllAction->activate( QAction::Trigger );
872   }
873 }
874
875 /*!
876   \brief Restores ParaView state from a disk file
877 */
878 void PVGUI_Module::loadParaviewState( const QString& theFileName )
879 {
880   pqApplicationCore::instance()->loadState( theFileName.toStdString().c_str(), getActiveServer() );
881   pqLoadStateReaction::activateView();
882 }
883
884 /*!
885   \brief Returns current active ParaView server
886 */
887 pqServer* PVGUI_Module::getActiveServer()
888 {
889   return pqApplicationCore::instance()->getActiveServer();
890 }
891
892
893 /*!
894   \brief Creates PARAVIS preferences panel.
895 */
896 void PVGUI_Module::createPreferences()
897 {
898   QList<QVariant> aIndices;
899   QStringList aStrings;
900
901   // Paraview settings tab
902   int aParaViewSettingsTab = addPreference( tr( "TIT_PVIEWSETTINGS" ) );
903
904   setPreferenceProperty(aParaViewSettingsTab, "stretch", false );
905   int aPanel = addPreference( QString(), aParaViewSettingsTab,
906                               LightApp_Preferences::UserDefined, PARAVIS_MODULE_NAME, "" );
907
908   setPreferenceProperty( aPanel, "content", (qint64)( new PVGUI_ParaViewSettingsPane( 0, getApp() ) ) );
909
910   // Paravis settings tab
911   int aParaVisSettingsTab = addPreference( tr( "TIT_PVISSETTINGS" ) );
912
913   addPreference( tr( "PREF_NO_EXT_PVSERVER" ), aParaVisSettingsTab, 
914                  LightApp_Preferences::Bool, PARAVIS_MODULE_NAME, "no_ext_pv_server" );
915
916   int aSaveType = addPreference( tr( "PREF_SAVE_TYPE_LBL" ), aParaVisSettingsTab,
917                                  LightApp_Preferences::Selector,
918                                  PARAVIS_MODULE_NAME, "savestate_type" );
919
920   aStrings.clear();
921   aIndices.clear();
922   aIndices << 0 << 1 << 2;
923   aStrings << tr("PREF_SAVE_TYPE_0") << tr("PREF_SAVE_TYPE_1") << tr("PREF_SAVE_TYPE_2");
924   setPreferenceProperty( aSaveType, "strings", aStrings );
925   setPreferenceProperty( aSaveType, "indexes", aIndices );
926
927   // ... "Language" group <<start>>
928   int traceGroup = addPreference( tr( "PREF_GROUP_TRACE" ), aParaVisSettingsTab );
929
930   int stopTrace = addPreference( tr( "PREF_STOP_TRACE" ), traceGroup, 
931                                  LightApp_Preferences::Bool, PARAVIS_MODULE_NAME, "stop_trace" );
932   setPreferenceProperty( stopTrace, "restart",  true );
933
934   int aTraceType = addPreference( tr( "PREF_TRACE_TYPE_LBL" ), traceGroup,
935                                  LightApp_Preferences::Selector,
936                                  PARAVIS_MODULE_NAME, "tracestate_type" );
937   aStrings.clear();
938   aIndices.clear();
939   aIndices << 0 << 1 << 2;
940   aStrings << tr("PREF_TRACE_TYPE_0") << tr("PREF_TRACE_TYPE_1") << tr("PREF_TRACE_TYPE_2");
941   setPreferenceProperty( aTraceType, "strings", aStrings );
942   setPreferenceProperty( aTraceType, "indexes", aIndices );
943   setPreferenceProperty( aTraceType, "restart",  true );
944 }
945
946 /*!
947   \brief. Show ParaView python trace.
948 */
949 void PVGUI_Module::onShowTrace()
950 {
951   if (!myTraceWindow) {
952     myTraceWindow = new pqPythonScriptEditor(getApp()->desktop());
953   }
954   myTraceWindow->updateTrace(getTraceString());
955   myTraceWindow->show();
956   myTraceWindow->raise();
957   myTraceWindow->activateWindow();
958 }
959
960
961 /*!
962   \brief. Re-initialize ParaView python trace.
963 */
964 void PVGUI_Module::onRestartTrace()
965 {
966   stopTrace();
967   startTrace();
968 }
969
970 /*!
971   \brief. Close ParaView python trace.
972 */
973 void PVGUI_Module::onStopTrace()
974 {
975   stopTrace();
976 }
977 /*!
978   \brief Called when view manager is added
979 */
980 void PVGUI_Module::onViewManagerAdded( SUIT_ViewManager* vm )
981 {
982   if ( PVViewer_ViewManager* pvvm = dynamic_cast<PVViewer_ViewManager*>( vm ) ) {
983     connect( pvvm, SIGNAL( viewCreated( SUIT_ViewWindow* ) ), 
984              this, SLOT( onPVViewCreated( SUIT_ViewWindow* ) ) );
985     connect( pvvm, SIGNAL( deleteView( SUIT_ViewWindow* ) ),
986              this,  SLOT( onPVViewDelete( SUIT_ViewWindow* ) ) );
987   }
988 }
989
990 /*!
991   \brief Called when view manager is removed
992 */
993 void PVGUI_Module::onViewManagerRemoved( SUIT_ViewManager* vm )
994 {
995   if ( PVViewer_ViewManager* pvvm = dynamic_cast<PVViewer_ViewManager*>( vm ) )
996     disconnect( pvvm, SIGNAL( viewCreated( SUIT_ViewWindow* ) ),
997                 this, SLOT( onPVViewCreated( SUIT_ViewWindow* ) ) );
998 }
999
1000 /*!
1001   \brief Show toolbars at \a vw PV view window creating when PARAVIS is active.
1002 */
1003 void PVGUI_Module::onPVViewCreated( SUIT_ViewWindow* /*vw*/ )
1004 {
1005   myGuiElements->setToolBarVisible( true );
1006   restoreDockWidgetsState();
1007 }
1008
1009 /*!
1010   \brief Save toolbars state at \a view view closing.
1011 */
1012 void PVGUI_Module::onPVViewDelete( SUIT_ViewWindow* view )
1013 {
1014   if ( dynamic_cast<PVViewer_ViewWindow*>( view ) )
1015     saveDockWidgetsState( false );
1016 }
1017
1018 /*!
1019   \fn CAM_Module* createModule();
1020   \brief Export module instance (factory function).
1021   \return new created instance of the module
1022 */
1023
1024 #ifdef WNT
1025 #define PVGUI_EXPORT __declspec(dllexport)
1026 #else   // WNT
1027 #define PVGUI_EXPORT
1028 #endif  // WNT
1029
1030 extern "C" {
1031
1032   bool flag = false;
1033   PVGUI_EXPORT CAM_Module* createModule() {
1034     return new PVGUI_Module();
1035   }
1036   
1037   PVGUI_EXPORT char* getModuleVersion() {
1038     return (char*)PARAVIS_VERSION_STR;
1039   }
1040 }