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