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