Salome HOME
247f4b69637da5492a189856c5b6cd04cc9f7bfc
[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 }
365
366 /*!
367  * \brief Slot called when the progress bar starts.
368  */
369 void PVGUI_Module::onStartProgress()
370 {
371   // VSR 19/03/2015, issue 0023025
372   // next line is commented: it is bad idea to show wait cursor on ANY vtk event
373   // moreover, it does not work when running pvserver with --multi-client mode
374   //QApplication::setOverrideCursor(Qt::WaitCursor);
375 }
376
377 /*!
378  * \brief Slot called when the progress bar is done.
379  */
380 void PVGUI_Module::onEndProgress()
381 {
382   // VSR 19/03/2015, issue 0023025
383   // next line is commented: it is bad idea to show wait cursor on ANY vtk event
384   // moreover, it does not work when running pvserver with --multi-client mode
385   //QApplication::restoreOverrideCursor();
386 }
387
388 void PVGUI_Module::onDataRepresentationUpdated() {
389   LightApp_Study* activeStudy = dynamic_cast<LightApp_Study*>(application()->activeStudy());
390   if(!activeStudy) return;
391   
392   activeStudy->Modified();
393 }
394
395 /*!
396   \brief Initialisation timer event - Starts up the Python trace
397 */
398 void PVGUI_Module::onInitTimer()
399 {
400   startTrace();
401 }
402   
403 /*!
404   \brief Get list of embedded macros files
405 */
406 QStringList PVGUI_Module::getEmbeddedMacrosList()
407 {
408   QString aRootDir = getenv("PARAVIS_ROOT_DIR");
409
410   QString aSourcePath = aRootDir + "/bin/salome/Macro";
411
412   QStringList aFilter;
413   aFilter << "*.py";
414
415   QDir aSourceDir(aSourcePath);
416   QStringList aSourceFiles = aSourceDir.entryList(aFilter, QDir::Files);
417   QStringList aFullPathSourceFiles;
418   foreach (QString aMacrosName, aSourceFiles) {
419     aFullPathSourceFiles << aSourceDir.absoluteFilePath(aMacrosName);
420   }
421   return aFullPathSourceFiles;
422 }
423
424 /*!
425   \brief Update the list of embedded macros
426 */
427 void PVGUI_Module::updateMacros()
428 {
429   pqPythonManager* aPythonManager = pqPVApplicationCore::instance()->pythonManager();
430   if(!aPythonManager)  {
431     return;
432   }
433   
434   foreach (QString aStr, getEmbeddedMacrosList()) {
435     aPythonManager->addMacro(aStr);
436   }
437 }
438
439
440 /*!
441   \brief Get list of compliant dockable GUI elements
442   \param m map to be filled in ("type":"default_position")
443 */
444 void PVGUI_Module::windows( QMap<int, int>& m ) const
445 {
446   m.insert( LightApp_Application::WT_ObjectBrowser, Qt::LeftDockWidgetArea );
447 #ifndef DISABLE_PYCONSOLE
448   m.insert( LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea );
449 #endif
450   // ParaView diagnostic output redirected here
451   m.insert( LightApp_Application::WT_LogWindow, Qt::BottomDockWidgetArea );
452 }
453
454 /*!
455   \brief Shows (toShow = true) or hides ParaView view window
456 */
457 void PVGUI_Module::showView( bool toShow )
458 {
459   // VSR: TODO: all below is not needed, if we use standard approach
460   // that consists in implementing viewManagers() function properly
461   // This should be done after we decide what to do with Log window.
462   LightApp_Application* anApp = getApp();
463   PVViewer_ViewManager* viewMgr =
464     dynamic_cast<PVViewer_ViewManager*>( anApp->getViewManager( PVViewer_Viewer::Type(), false ) );
465   if ( !viewMgr ) {
466     viewMgr = new PVViewer_ViewManager( anApp->activeStudy(), anApp->desktop(), anApp->logWindow() );
467     anApp->addViewManager( viewMgr );
468     connect( viewMgr, SIGNAL( lastViewClosed( SUIT_ViewManager* ) ),
469              anApp, SLOT( onCloseView( SUIT_ViewManager* ) ) );
470   }
471
472   PVViewer_ViewWindow* pvWnd = dynamic_cast<PVViewer_ViewWindow*>( viewMgr->getActiveView() );
473   if ( !pvWnd ) {
474     pvWnd = dynamic_cast<PVViewer_ViewWindow*>( viewMgr->createViewWindow() );
475     // this also connects to the pvserver and instantiates relevant PV behaviors
476   }
477
478   pvWnd->setShown( toShow );
479   if ( toShow ) pvWnd->setFocus();
480 }
481
482 /*!
483   \brief Slot to show help for proxy.
484 */
485 void PVGUI_Module::showHelpForProxy( const QString& groupname, const QString& proxyname )
486 {
487   pqHelpReaction::showProxyHelp(groupname, proxyname);
488 }
489
490 /*!
491   \brief Slot to show the waiting state.
492 */
493 void PVGUI_Module::onPreAccept()
494 {
495   getApp()->desktop()->statusBar()->showMessage(tr("STB_PREACCEPT"));
496   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
497 }
498
499 /*!
500   \brief Slot to show the ready state.
501 */
502 void PVGUI_Module::onPostAccept()
503 {
504   getApp()->desktop()->statusBar()->showMessage(tr("STB_POSTACCEPT"), 2000);
505   QTimer::singleShot(0, this, SLOT(endWaitCursor()));
506 }
507
508 /*!
509   \brief Slot to switch off wait cursor.
510 */
511 void PVGUI_Module::endWaitCursor()
512 {
513   QApplication::restoreOverrideCursor();
514 }
515
516 /*!
517   \brief Handler method for the output of messages.
518 */
519 static void ParavisMessageOutput(QtMsgType type, const char *msg)
520 {
521   switch(type)
522     {
523   case QtDebugMsg:
524     vtkOutputWindow::GetInstance()->DisplayText(msg);
525     break;
526   case QtWarningMsg:
527     vtkOutputWindow::GetInstance()->DisplayErrorText(msg);
528     break;
529   case QtCriticalMsg:
530     vtkOutputWindow::GetInstance()->DisplayErrorText(msg);
531     break;
532   case QtFatalMsg:
533     vtkOutputWindow::GetInstance()->DisplayErrorText(msg);
534     break;
535     }
536 }
537
538 /*!
539   \brief Activate module.
540   \param study current study
541   \return \c true if activaion is done successfully or 0 to prevent
542   activation on error
543 */
544 bool PVGUI_Module::activateModule( SUIT_Study* study )
545 {
546   myOldMsgHandler = qInstallMsgHandler(ParavisMessageOutput);
547   
548   SUIT_ExceptionHandler::addCleanUpRoutine( paravisCleanUp );
549
550   storeCommonWindowsState();
551
552   bool isDone = LightApp_Module::activateModule( study );
553   if ( !isDone ) return false;
554
555   showView( true );
556   if ( mySourcesMenuId != -1 ) menuMgr()->show(mySourcesMenuId);
557   if ( myFiltersMenuId != -1 ) menuMgr()->show(myFiltersMenuId);
558   if ( myMacrosMenuId != -1 ) menuMgr()->show(myMacrosMenuId);
559
560   // Update the various menus with the content pre-loaded in myGuiElements
561 //  QMenu* srcMenu = menuMgr()->findMenu( mySourcesMenuId );
562 //  myGuiElements->updateSourcesMenu(srcMenu);
563 //  QMenu* filtMenu = menuMgr()->findMenu( myFiltersMenuId );
564 //  myGuiElements->updateFiltersMenu(filtMenu);
565 //  QMenu* macMenu = menuMgr()->findMenu( myMacrosMenuId );
566 //  myGuiElements->updateMacrosMenu(macMenu);
567
568   setMenuShown( true );
569   setToolShown( true );
570
571   restoreDockWidgetsState();
572
573   QMenu* aMenu = menuMgr()->findMenu( myRecentMenuId );
574   if(aMenu) {
575     QList<QAction*> anActns = aMenu->actions();
576     for (int i = 0; i < anActns.size(); ++i) {
577       QAction* a = anActns.at(i);
578       if(a)
579         a->setVisible(true);
580     }
581   }
582
583   QList<QMenu*>::iterator it;
584   for (it = myMenus.begin(); it != myMenus.end(); ++it) {
585     QAction* a = (*it)->menuAction();
586     if(a)
587       a->setVisible(true);
588   }
589
590   if ( myRecentMenuId != -1 ) menuMgr()->show(myRecentMenuId);
591   
592   return isDone;
593 }
594
595
596 /*!
597   \brief Deactivate module.
598   \param study current study
599   \return \c true if deactivaion is done successfully or 0 to prevent
600   deactivation on error
601 */
602 bool PVGUI_Module::deactivateModule( SUIT_Study* study )
603 {
604   MESSAGE("PARAVIS deactivation ...")
605
606   QMenu* aMenu = menuMgr()->findMenu( myRecentMenuId );
607   if(aMenu) {
608     QList<QAction*> anActns = aMenu->actions();
609     for (int i = 0; i < anActns.size(); ++i) {
610       QAction* a = anActns.at(i);
611       if(a)
612         a->setVisible(false);
613     }
614   }
615
616   QList<QMenu*>::iterator it;
617   for (it = myMenus.begin(); it != myMenus.end(); ++it) {
618     QAction* a = (*it)->menuAction();
619     if(a)
620       a->setVisible(false);
621   }
622
623   QList<QDockWidget*> aStreamingViews = application()->desktop()->findChildren<QDockWidget*>("pqStreamingControls");
624   foreach(QDockWidget* aView, aStreamingViews) {
625     if (!myDockWidgets.contains(aView))
626       myDockWidgets[aView] = aView->isVisible();
627   }
628
629   /*if (pqImplementation::helpWindow) {
630     pqImplementation::helpWindow->hide();
631     }*/
632   // hide menus
633   menuMgr()->hide(myRecentMenuId);
634   menuMgr()->hide(mySourcesMenuId);
635   menuMgr()->hide(myFiltersMenuId);
636   menuMgr()->hide(myMacrosMenuId);
637   setMenuShown( false );
638   setToolShown( false );
639
640   saveDockWidgetsState();
641
642   SUIT_ExceptionHandler::removeCleanUpRoutine( paravisCleanUp );
643
644   if (myOldMsgHandler)
645     qInstallMsgHandler(myOldMsgHandler);
646
647   restoreCommonWindowsState();
648   
649   return LightApp_Module::deactivateModule( study );
650 }
651
652
653 /*!
654   \brief Called when application is closed.
655
656   Process finalize application functionality from ParaView in order to save server settings
657   and nullify application pointer if the application is being closed.
658
659   \param theApp application
660 */
661 void PVGUI_Module::onApplicationClosed( SUIT_Application* theApp )
662 {
663   PVViewer_Core::ParaviewCleanup();
664   CAM_Module::onApplicationClosed(theApp);
665 }
666
667 /*!
668   \brief Called when study is closed.
669
670   Removes data model from the \a study.
671
672   \param study study being closed
673 */
674 void PVGUI_Module::studyClosed(SUIT_Study* study)
675 {
676   showView(false); // VSR: this seems to be not needed (all views are automatically closed)
677   clearParaviewState();
678   //Re-start trace 
679   onRestartTrace();
680
681   LightApp_Module::studyClosed(study);
682 }
683
684 /*!
685   \brief Open file of format supported by ParaView
686 */
687 void PVGUI_Module::openFile( const char* theName )
688 {
689   QStringList aFiles;
690   aFiles << theName;
691   pqLoadDataReaction::loadData( aFiles );
692 }
693
694 /*!
695   \brief Starts Python trace.
696  
697   Start trace invoking the newly introduced C++ API (PV 4.2)
698   (inspired from pqTraceReaction::start())
699 */
700 void PVGUI_Module::startTrace()
701 {
702   vtkSMSessionProxyManager* pxm = pqActiveObjects::instance().activeServer()->proxyManager();
703
704   vtkSmartPointer<vtkSMProxy> proxy;
705   proxy.TakeReference( pxm->NewProxy( "pythontracing", "PythonTraceOptions" ) );
706   if ( proxy ) {
707     vtkNew<vtkSMParaViewPipelineController> controller;
708     controller->InitializeProxy( proxy );
709   }
710   vtkSMTrace* trace = vtkSMTrace::StartTrace();
711   if ( proxy ) {
712     // Set manually the properties entered via the dialog box poping-up when requiring
713     // a trace start in PV4.2 (trace options)
714     SUIT_ResourceMgr* aResourceMgr = SUIT_Session::session()->resourceMgr();
715     int type = aResourceMgr->integerValue( PARAVIS_MODULE_NAME, "tracestate_type", 2 );
716     trace->SetPropertiesToTraceOnCreate( type );
717     trace->SetFullyTraceSupplementalProxies( false );
718   }
719 }
720
721 /*!
722   \brief Stops Python trace.
723 */
724 void PVGUI_Module::stopTrace()
725 {
726   vtkSMTrace::StopTrace();
727 }
728
729 /*!
730   \brief Execute a Python script.
731 */
732 void PVGUI_Module::executeScript( const char* script )
733 {
734 #ifndef WNT
735   pqPythonManager* manager = qobject_cast<pqPythonManager*>(
736                              pqApplicationCore::instance()->manager( "PYTHON_MANAGER" ) );
737   if ( manager )  {
738     pqPythonDialog* pyDiag = manager->pythonShellDialog();
739     if ( pyDiag ) {
740       pyDiag->runString(script);  
741     }
742   }
743 #endif
744 }
745
746 ///**
747 // *  Debug function printing out the given interpreter's execution context
748 // */
749 //void printInterpContext(PyInterp_Interp * interp )
750 //{
751 //  // Extract __smtraceString from interpreter's context
752 //  const PyObject* ctxt = interp->getExecutionContext();
753 //
754 //  PyObject* lst = PyDict_Keys((PyObject *)ctxt);
755 //  Py_ssize_t siz = PyList_GET_SIZE(lst);
756 //  for (Py_ssize_t i = 0; i < siz; i++)
757 //    {
758 //      PyObject * elem = PyList_GetItem(lst, i);
759 //      if (PyString_Check(elem))
760 //        {
761 //          std::cout << "At pos:" << i << ", " << PyString_AsString(elem) << std::endl;
762 //        }
763 //      else
764 //        std::cout << "At pos:" << i << ", not a string!" << std::endl;
765 //    }
766 //  Py_XDECREF(lst);
767 //}
768
769 /*!
770   \brief Returns trace string
771 */
772 QString PVGUI_Module::getTraceString()
773 {
774   QString traceString = "";
775
776   static const QString replaceStr( "paraview.simple" );
777   std::stringstream nl;
778   nl << std::endl; // surely there is some Qt trick to do that in a portable way??
779   QString end_line( nl.str().c_str() );
780
781   vtkSMTrace* tracer = vtkSMTrace::GetActiveTracer();
782   if ( tracer ) {
783     traceString = tracer->GetCurrentTrace();
784     // 'import pvsimple' is necessary to fix the first call to DisableFirstRenderCamera in the paraview trace
785     // 'ShowParaviewView()' ensure there is an opened viewing window (otherwise SEGFAULT!)
786     traceString = "import pvsimple" + end_line +
787       "pvsimple.ShowParaviewView()" + end_line + traceString;
788
789     // Replace import "paraview.simple" by "pvsimple"
790     if ( !traceString.isEmpty() ) {
791       int aPos = traceString.indexOf( replaceStr );
792       while ( aPos != -1 ) {
793         traceString = traceString.replace( aPos, replaceStr.length(), "pvsimple" );
794         aPos = traceString.indexOf( replaceStr, aPos );
795       }
796     }
797   }
798
799   // Save camera position to, which is no longer output by the tracer ...
800   VTK_PY_GIL_ENSURE
801   PyObject * mods(PySys_GetObject(const_cast<char*>("modules")));
802   PyObject * trace_mod(PyDict_GetItemString(mods, "paraview.smtrace"));  // module was already (really) imported by vtkSMTrace
803   if (PyModule_Check(trace_mod)) {
804       vtkSmartPyObject save_cam(PyObject_GetAttrString(trace_mod, const_cast<char*>("SaveCameras")));
805       vtkSmartPyObject camera_trace(PyObject_CallMethod(save_cam, const_cast<char*>("get_trace"), NULL));
806       // Convert to a single string
807       vtkSmartPyObject ret(PyString_FromString(end_line.toStdString().c_str()));
808       vtkSmartPyObject final_string(PyObject_CallMethod(ret, const_cast<char*>("join"),
809           const_cast<char*>("O"), (PyObject*)camera_trace));
810       if (PyString_CheckExact(final_string))
811         {
812           QString camera_qs(PyString_AsString(final_string));  // deep copy
813           traceString = traceString + end_line  + end_line + QString("#### saving camera placements for all active views")
814               + end_line + end_line + camera_qs + end_line;
815         }
816     }
817   VTK_PY_GIL_RELEASE
818
819   return traceString;
820 }
821
822 /*!
823   \brief Saves trace string to disk file
824 */
825 void PVGUI_Module::saveTrace( const char* theName )
826 {
827   QFile file( theName );
828   if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) {
829     MESSAGE( "Could not open file:" << theName );
830     return;
831   }
832   QTextStream out( &file );
833   out << getTraceString();
834   file.close();
835 }
836
837 /*!
838   \brief Saves ParaView state to a disk file
839 */
840 void PVGUI_Module::saveParaviewState( const char* theFileName )
841 {
842   pqApplicationCore::instance()->saveState( theFileName );
843 }
844
845 /*!
846   \brief Delete all objects for Paraview Pipeline Browser
847 */
848 void PVGUI_Module::clearParaviewState()
849 {
850   QAction* deleteAllAction = action( DeleteAllId );
851   if ( deleteAllAction ) {
852     deleteAllAction->activate( QAction::Trigger );
853   }
854 }
855
856 /*!
857   \brief Restores ParaView state from a disk file
858 */
859 void PVGUI_Module::loadParaviewState( const char* theFileName )
860 {
861   pqApplicationCore::instance()->loadState( theFileName, getActiveServer() );
862 }
863
864 /*!
865   \brief Returns current active ParaView server
866 */
867 pqServer* PVGUI_Module::getActiveServer()
868 {
869   return pqApplicationCore::instance()->getActiveServer();
870 }
871
872
873 /*!
874   \brief Creates PARAVIS preferences panel.
875 */
876 void PVGUI_Module::createPreferences()
877 {
878   QList<QVariant> aIndices;
879   QStringList aStrings;
880
881   // Paraview settings tab
882   int aParaViewSettingsTab = addPreference( tr( "TIT_PVIEWSETTINGS" ) );
883
884   setPreferenceProperty(aParaViewSettingsTab, "stretch", false );
885   int aPanel = addPreference( QString(), aParaViewSettingsTab,
886                               LightApp_Preferences::UserDefined, PARAVIS_MODULE_NAME, "" );
887
888   setPreferenceProperty( aPanel, "content", (qint64)( new PVGUI_ParaViewSettingsPane( 0, getApp() ) ) );
889
890   // Paravis settings tab
891   int aParaVisSettingsTab = addPreference( tr( "TIT_PVISSETTINGS" ) );
892
893   addPreference( tr( "PREF_NO_EXT_PVSERVER" ), aParaVisSettingsTab, 
894                  LightApp_Preferences::Bool, PARAVIS_MODULE_NAME, "no_ext_pv_server" );
895
896   /* VSR: not used
897   int aSaveType = addPreference( tr( "PREF_SAVE_TYPE_LBL" ), aParaVisSettingsTab,
898                                  LightApp_Preferences::Selector,
899                                  PARAVIS_MODULE_NAME, "savestate_type" );
900
901   aStrings.clear();
902   aIndices.clear();
903   aIndices << 0 << 1 << 2;
904   aStrings << tr("PREF_SAVE_TYPE_0") << tr("PREF_SAVE_TYPE_1") << tr("PREF_SAVE_TYPE_2");
905   setPreferenceProperty( aSaveType, "strings", aStrings );
906   setPreferenceProperty( aSaveType, "indexes", aIndices );
907   */
908
909   // ... "Language" group <<start>>
910   int traceGroup = addPreference( tr( "PREF_GROUP_TRACE" ), aParaVisSettingsTab );
911
912   int stopTrace = addPreference( tr( "PREF_STOP_TRACE" ), traceGroup, 
913                                  LightApp_Preferences::Bool, PARAVIS_MODULE_NAME, "stop_trace" );
914   setPreferenceProperty( stopTrace, "restart",  true );
915
916   int aTraceType = addPreference( tr( "PREF_TRACE_TYPE_LBL" ), traceGroup,
917                                  LightApp_Preferences::Selector,
918                                  PARAVIS_MODULE_NAME, "tracestate_type" );
919   aStrings.clear();
920   aIndices.clear();
921   aIndices << 0 << 1 << 2;
922   aStrings << tr("PREF_TRACE_TYPE_0") << tr("PREF_TRACE_TYPE_1") << tr("PREF_TRACE_TYPE_2");
923   setPreferenceProperty( aTraceType, "strings", aStrings );
924   setPreferenceProperty( aTraceType, "indexes", aIndices );
925   setPreferenceProperty( aTraceType, "restart",  true );
926 }
927
928 /*!
929   \brief. Show ParaView python trace.
930 */
931 void PVGUI_Module::onShowTrace()
932 {
933   if (!myTraceWindow) {
934     myTraceWindow = new pqPythonScriptEditor(getApp()->desktop());
935   }
936   myTraceWindow->setText(getTraceString());
937   myTraceWindow->show();
938   myTraceWindow->raise();
939   myTraceWindow->activateWindow();
940 }
941
942
943 /*!
944   \brief. Re-initialize ParaView python trace.
945 */
946 void PVGUI_Module::onRestartTrace()
947 {
948   stopTrace();
949   startTrace();
950 }
951
952 /*!
953   \brief Called when view manager is added
954 */
955 void PVGUI_Module::onViewManagerAdded( SUIT_ViewManager* vm )
956 {
957   if ( PVViewer_ViewManager* pvvm = dynamic_cast<PVViewer_ViewManager*>( vm ) ) {
958     connect( pvvm, SIGNAL( viewCreated( SUIT_ViewWindow* ) ), 
959              this, SLOT( onPVViewCreated( SUIT_ViewWindow* ) ) );
960     connect( pvvm, SIGNAL( deleteView( SUIT_ViewWindow* ) ),
961              this,  SLOT( onPVViewDelete( SUIT_ViewWindow* ) ) );
962   }
963 }
964
965 /*!
966   \brief Called when view manager is removed
967 */
968 void PVGUI_Module::onViewManagerRemoved( SUIT_ViewManager* vm )
969 {
970   if ( PVViewer_ViewManager* pvvm = dynamic_cast<PVViewer_ViewManager*>( vm ) )
971     disconnect( pvvm, SIGNAL( viewCreated( SUIT_ViewWindow* ) ),
972                 this, SLOT( onPVViewCreated( SUIT_ViewWindow* ) ) );
973 }
974
975 /*!
976   \brief Show toolbars at \a vw PV view window creating when PARAVIS is active.
977 */
978 void PVGUI_Module::onPVViewCreated( SUIT_ViewWindow* vw )
979 {
980   myGuiElements->setToolBarVisible( true );
981   restoreDockWidgetsState();
982 }
983
984 /*!
985   \brief Save toolbars state at \a view view closing.
986 */
987 void PVGUI_Module::onPVViewDelete( SUIT_ViewWindow* view )
988 {
989   if ( dynamic_cast<PVViewer_ViewWindow*>( view ) )
990     saveDockWidgetsState( false );
991 }
992
993 /*!
994   \fn CAM_Module* createModule();
995   \brief Export module instance (factory function).
996   \return new created instance of the module
997 */
998
999 #ifdef WNT
1000 #define PVGUI_EXPORT __declspec(dllexport)
1001 #else   // WNT
1002 #define PVGUI_EXPORT
1003 #endif  // WNT
1004
1005 extern "C" {
1006
1007   bool flag = false;
1008   PVGUI_EXPORT CAM_Module* createModule() {
1009     return new PVGUI_Module();
1010   }
1011   
1012   PVGUI_EXPORT char* getModuleVersion() {
1013     return (char*)PARAVIS_VERSION_STR;
1014   }
1015 }