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