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