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