Salome HOME
Adding option to skip the connection to an external server.
[modules/paravis.git] / src / PVGUI / PVGUI_Module.cxx
1 // PARAVIS : ParaView wrapper SALOME module
2 //
3 // Copyright (C) 2010-2014  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 #include <Standard_math.hxx>  // E.A. must be included before Python.h to fix compilation on windows
24 #ifdef HAVE_FINITE
25 #undef HAVE_FINITE            // VSR: avoid compilation warning on Linux : "HAVE_FINITE" redefined
26 #endif
27 #include <vtkPython.h> // Python first
28 #include "PVGUI_Module.h"
29
30 #ifdef PARAVIS_WITH_FULL_CORBA
31 # include "PARAVIS_Gen_i.hh"
32 #endif
33
34 #include CORBA_SERVER_HEADER(SALOME_ModuleCatalog)
35 #include CORBA_SERVER_HEADER(SALOMEDS)
36
37 #include "PVViewer_ViewManager.h"
38 #include "PVViewer_ViewWindow.h"
39 #include "PVViewer_ViewModel.h"
40 #include "PVGUI_Tools.h"
41 #include "PVGUI_ParaViewSettingsPane.h"
42
43 // SALOME Includes
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 <SALOME_LifeCycleCORBA.hxx>
53 #include <SALOMEDS_SObject.hxx>
54
55 #include <LightApp_SelectionMgr.h>
56 #include <LightApp_NameDlg.h>
57 #include <SalomeApp_Application.h>
58 #include <SalomeApp_Study.h>
59 #include <SALOME_ListIO.hxx>
60 #include <SALOMEDS_Tool.hxx>
61 #include <Utils_ORB_INIT.hxx>
62 #include <Utils_SINGLETON.hxx>
63
64 #include <QtxActionMenuMgr.h>
65 #include <QtxActionToolMgr.h>
66
67 #include <PARAVIS_version.h>
68
69 // External includes
70 #include <sstream>
71
72 #include <QAction>
73 #include <QApplication>
74 #include <QCursor>
75 #include <QDir>
76 #include <QFile>
77 #include <QFileInfo>
78 #include <QIcon>
79 #include <QInputDialog>
80 #include <QMenu>
81 #include <QStatusBar>
82 #include <QString>
83 #include <QStringList>
84 #include <QTimer>
85 #include <QToolBar>
86 #include <QTextStream>
87 #include <QShortcut>
88 #include <QDockWidget>
89 #include <QHelpEngine>
90
91 // Paraview includes
92 #include <vtkPVConfig.h>  // for symbol PARAVIEW_VERSION
93 #include <vtkProcessModule.h>
94 #include <vtkPVSession.h>
95 #include <vtkPVProgressHandler.h>
96 #include <vtkOutputWindow.h>
97 #include <vtkEventQtSlotConnect.h>
98 #include <vtkNew.h>
99 #include <vtkSMProxy.h>
100 #include <vtkSmartPointer.h>
101 #include <vtkSMSession.h>
102 #include <vtkSMTrace.h>
103 #include <vtkSMSessionProxyManager.h>
104 #include <vtkSMParaViewPipelineController.h>
105
106 #include <pqApplicationCore.h>
107 #include <pqPVApplicationCore.h>
108 #include <pqActiveView.h>
109 #include <pqObjectBuilder.h>
110 #include <pqOptions.h>
111 #include <pqSettings.h>
112 #include <pqServer.h>
113 #include <pqUndoStack.h>
114 #include <pqTabbedMultiViewWidget.h>
115 #include <pqActiveObjects.h>
116 #include <pqHelpReaction.h>
117 #include <pqPluginManager.h>
118 #include <pqPythonDialog.h>
119 #include <pqPythonManager.h>
120 #include <pqLoadDataReaction.h>
121 #include <pqPythonScriptEditor.h>
122 #include <pqDataRepresentation.h>
123 #include <pqDisplayColorWidget.h>
124 #include <pqColorToolbar.h>
125 #include <pqScalarBarVisibilityReaction.h>
126 #include <pqServerResource.h>
127 #include <pqServerConnectReaction.h>
128
129 // TO REMOVE:
130 #include <PyInterp_Interp.h>
131
132
133 //----------------------------------------------------------------------------
134 PVGUI_Module* ParavisModule = 0;
135
136 /*!
137   \mainpage
138
139   <h2>Building and installing PARAVIS</h2>
140   As any other SALOME module, PARAVIS requires PARAVIS_ROOT_DIR environment variable to be set to PARAVIS
141   installation directory.
142   Other variables needed for correct detection of ParaView location:
143   \li PVHOME - points at the ParaView installation directory tree
144   \li PVVERSION - number of ParaView version
145
146   It also requires common SALOME environment including GUI_ROOT_DIR and other prerequsites.
147
148
149   PARAVIS module can be launched using the following commands:
150   \li Full SALOME configuration
151   \code
152   runSalome --modules="PARAVIS"
153   \endcode
154
155   <h2>ParaView GUI integration</h2>
156   <h3>ParaView GUI integration overview</h3>
157
158   The main idea is to reuse ParaView GUI internal logic as much as possible, providing a layer 
159   between it and SALOME GUI that hides the following SALOME GUI implementation details from ParaView:
160
161   \li SALOME GUI executable and Qt event loop
162   \li SALOME GUI desktop
163   \li Dock windows areas
164   \li SALOME menu and toolbar managers
165
166   Major part of the integration is implemented in PVGUI_Module class.
167
168   <h3>ParaView client initalization</h3>
169
170   ParaView client initalization is performed when an instance of PVGUI_Module class has been created 
171   and \link PVGUI_Module::initialize() PVGUI_Module::initialize()\endlink method is called by SALOME GUI.
172   The actual client start-up is done in \link PVGUI_Module::pvInit() PVGUI_Module::pvInit()\endlink method. 
173   
174
175   <h3>Multi-view manager</h3>
176
177   SALOME GUI requires that each kind of view be implemnted with help of (at least) three classes. For ParaView multi-view manager 
178   these are:
179
180   \li PVGUI_ViewManager - view manager class
181   \li PVGUI_Viewer      - view model class
182   \li PVGUI_ViewWindow  - view window class that acts as a parent for %pqViewManager
183
184   Single instances of PVGUI_ViewManager and PVGUI_ViewWindow classes are created by \link PVGUI_Module::showView() 
185   PVGUI_Module::showView()\endlink method upon the first PARAVIS module activation. The same method hides the multi-view manager 
186   when the module is deactivated (the user switches to another module or a study is closed). 
187   A special trick is used to make PVGUI_ViewWindow the parent of %pqViewManager widget. It is created initally by %pqMainWindowCore
188   with the desktop as a parent, so when it is shown PVGUI_ViewWindow instance is passed to its setParent() method. In  
189   \link PVGUI_ViewWindow::~PVGUI_ViewWindow() PVGUI_ViewWindow::~PVGUI_ViewWindow()\endlink the parent is nullified to avoid deletion
190   of %pqViewManager widget that would break %pqMainWindowCore class.
191
192   <h3>ParaView plugins</h3>
193   ParaView server and client plugins are managed by %pqMainWindowCore slots that has full access to PARAVIS menus and toolbars. 
194   As a result they appears automatically in PARAVIS menus and toolbars if loaded successfully.
195 */
196
197 /*!
198   \class PVGUI_Module
199   \brief Implementation 
200          SALOME module wrapping ParaView GUI.
201 */
202
203 _PTR(SComponent)
204 ClientFindOrCreateParavisComponent(_PTR(Study) theStudyDocument)
205 {
206   _PTR(SComponent) aSComponent = theStudyDocument->FindComponent("PARAVIS");
207   if (!aSComponent) {
208     _PTR(StudyBuilder) aStudyBuilder = theStudyDocument->NewBuilder();
209     aStudyBuilder->NewCommand();
210     int aLocked = theStudyDocument->GetProperties()->IsLocked();
211     if (aLocked) theStudyDocument->GetProperties()->SetLocked(false);
212     aSComponent = aStudyBuilder->NewComponent("PARAVIS");
213     _PTR(GenericAttribute) anAttr =
214       aStudyBuilder->FindOrCreateAttribute(aSComponent, "AttributeName");
215     _PTR(AttributeName) aName (anAttr);
216
217     ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
218     CORBA::ORB_var anORB = init( qApp->argc(), qApp->argv() );
219
220     SALOME_NamingService *NamingService = new SALOME_NamingService( anORB );
221     CORBA::Object_var objVarN = NamingService->Resolve("/Kernel/ModulCatalog");
222     SALOME_ModuleCatalog::ModuleCatalog_var Catalogue =
223       SALOME_ModuleCatalog::ModuleCatalog::_narrow(objVarN);
224     SALOME_ModuleCatalog::Acomponent_var Comp = Catalogue->GetComponent( "PARAVIS" );
225     if (!Comp->_is_nil()) {
226       aName->SetValue(Comp->componentusername());
227     }
228
229     anAttr = aStudyBuilder->FindOrCreateAttribute(aSComponent, "AttributePixMap");
230     _PTR(AttributePixMap) aPixmap (anAttr);
231     aPixmap->SetPixMap( "pqAppIcon16.png" );
232
233     // Create Attribute parameters for future using
234     anAttr = aStudyBuilder->FindOrCreateAttribute(aSComponent, "AttributeParameter");
235
236     aStudyBuilder->DefineComponentInstance(aSComponent, PVGUI_Module::GetEngine()->GetIOR());
237     if (aLocked) theStudyDocument->GetProperties()->SetLocked(true);
238     aStudyBuilder->CommitCommand();
239   }
240   return aSComponent;
241 }
242
243 /*!
244   Clean up function; used to stop ParaView progress events when
245   exception is caught by global exception handler.
246 */
247 void paravisCleanUp()
248 {
249   if ( pqApplicationCore::instance() ) {
250     pqServer* s = pqApplicationCore::instance()->getActiveServer();
251     if ( s ) s->session()->GetProgressHandler()->CleanupPendingProgress();
252   }
253 }
254
255 /*!
256   \brief Constructor. Sets the default name for the module.
257 */
258 PVGUI_Module::PVGUI_Module()
259   : SalomeApp_Module( "PARAVIS" ),
260     mySelectionControlsTb( -1 ),
261     mySourcesMenuId( -1 ),
262     myFiltersMenuId( -1 ),
263     myMacrosMenuId(-1),
264     myToolbarsMenuId(-1),
265     myRecentMenuId(-1),
266     myOldMsgHandler(0),
267     myTraceWindow(0),
268     myStateCounter(0),
269     myInitTimer(0),
270     myPushTraceTimer(0)
271 {
272 #ifdef HAS_PV_DOC
273   Q_INIT_RESOURCE( PVGUI );
274 #endif
275   ParavisModule = this;
276
277   // Clear old copies of embedded macros files
278   QString aDestPath = QString( "%1/.config/%2/Macros" ).arg( QDir::homePath() ).arg( QApplication::applicationName() );
279   QStringList aFilter;
280   aFilter << "*.py";
281
282   QDir aDestDir(aDestPath);
283   QStringList aDestFiles = aDestDir.entryList(aFilter, QDir::Files);
284   foreach (QString aMacrosPath, getEmbeddedMacrosList()) {
285     QString aMacrosName = QFileInfo(aMacrosPath).fileName();
286     if (aDestFiles.contains(aMacrosName)) {
287       aDestDir.remove(aMacrosName);
288     }
289   }
290 }
291
292 /*!
293   \brief Destructor.
294 */
295 PVGUI_Module::~PVGUI_Module()
296 {
297   if (myPushTraceTimer)
298     delete myPushTraceTimer;
299   if (myInitTimer)
300     delete myInitTimer;
301 }
302
303 PARAVIS_ORB::PARAVIS_Gen_var PVGUI_Module::GetEngine()
304 {
305   return PVViewer_ViewManager::GetEngine();
306 }
307
308 pqPVApplicationCore * PVGUI_Module::GetPVApplication()
309 {
310   return PVViewer_ViewManager::GetPVApplication();
311 }
312
313 /*!
314   \brief Initialize module. Creates menus, prepares context menu, etc.
315   \param app SALOME GUI application instance
316 */
317 void PVGUI_Module::initialize( CAM_Application* app )
318 {
319   SalomeApp_Module::initialize( app );
320
321   // Create ParaViS actions
322   createActions();
323   // Create ParaViS menus
324   createMenus();
325
326   // Uncomment to debug ParaView initialization
327   // "aa" used instead of "i" as GDB doesn't like "i" variables :)
328   /*
329   int aa = 1;
330   while( aa ){
331     aa = aa;
332   }
333   */
334
335   SalomeApp_Application* anApp = getApp();
336   SUIT_Desktop* aDesktop = anApp->desktop();
337
338   // Initialize ParaView client and associated behaviors
339   // and connect to externally launched pvserver
340   PVViewer_ViewManager::ParaviewInitApp(aDesktop);
341
342   // Remember current state of desktop toolbars
343   QList<QToolBar*> foreignToolbars = aDesktop->findChildren<QToolBar*>();
344
345   setupDockWidgets();
346
347   // Behaviors and connection must be instanciated *after* widgets are in place
348   // In PARAVIS module we do not wait for PVViewer_ViewWindow to be instanciated to have this:
349   PVViewer_ViewManager::ParaviewInitBehaviors(true, aDesktop);
350   PVViewer_ViewManager::ConnectToExternalPVServer(aDesktop);
351
352   pvCreateActions();
353   pvCreateToolBars();
354   pvCreateMenus();
355
356   QList<QDockWidget*> activeDocks = aDesktop->findChildren<QDockWidget*>();
357   QList<QMenu*> activeMenus = aDesktop->findChildren<QMenu*>();
358
359   // Setup quick-launch shortcuts.
360   QShortcut *ctrlSpace = new QShortcut(Qt::CTRL + Qt::Key_Space, aDesktop);
361   QObject::connect(ctrlSpace, SIGNAL(activated()),
362     pqApplicationCore::instance(), SLOT(quickLaunch()));
363
364   // Find Plugin Dock Widgets
365   QList<QDockWidget*> currentDocks = aDesktop->findChildren<QDockWidget*>();
366   QList<QDockWidget*>::iterator i;
367   for (i = currentDocks.begin(); i != currentDocks.end(); ++i) {
368     if(!activeDocks.contains(*i)) {
369       myDockWidgets[*i] = false; // hidden by default
370       (*i)->hide();
371     }
372   }
373
374     // Find Plugin Menus
375     // [ABN] TODO: fix this - triggers a SEGFAULT at deactivation() time.
376 //    QList<QMenu*> currentMenus = aDesktop->findChildren<QMenu*>();
377 //    QList<QMenu*>::iterator im;
378 //    for (im = currentMenus.begin(); im != currentMenus.end(); ++im) {
379 //      if(!activeMenus.contains(*im)) {
380 //          QString s = (*im)->title();
381 //          std::cout << " MENU "<<  s.toStdString() << std::endl;
382 //          myMenus.append(*im);
383 //      }
384 //    }
385
386   PVViewer_ViewManager::ParaviewLoadConfigurations();
387   updateObjBrowser();
388
389   // Find created toolbars
390   QCoreApplication::processEvents();
391
392   QList<QToolBar*> allToolbars = aDesktop->findChildren<QToolBar*>();
393   foreach(QToolBar* aBar, allToolbars) {
394     if (!foreignToolbars.contains(aBar)) {
395       myToolbars[aBar] = true;
396       myToolbarBreaks[aBar] = false;
397       aBar->setVisible(false);
398       aBar->toggleViewAction()->setVisible(false);
399     }
400   }
401
402   updateMacros();
403  
404   SUIT_ResourceMgr* aResourceMgr = SUIT_Session::session()->resourceMgr();
405   bool isStop = aResourceMgr->booleanValue( "PARAVIS", "stop_trace", false );
406   if(!isStop)
407     {
408       // Start a timer to schedule asap:
409       //  - the trace start
410       myInitTimer = new QTimer(aDesktop);
411       QObject::connect(myInitTimer, SIGNAL(timeout()), this, SLOT(onInitTimer()) );
412       myInitTimer->setSingleShot(true);
413       myInitTimer->start(0);
414
415       // Another timer to regularly push the trace onto the engine:
416       myPushTraceTimer = new QTimer(aDesktop);
417       QObject::connect(myPushTraceTimer, SIGNAL(timeout()), this, SLOT(onPushTraceTimer()) );
418       myPushTraceTimer->setSingleShot(false);
419       myPushTraceTimer->start(500);
420     }
421
422   this->VTKConnect = vtkEventQtSlotConnect::New();
423   
424   vtkProcessModule* pm = vtkProcessModule::GetProcessModule();
425   if(pm) {
426     vtkPVSession* pvs = dynamic_cast<vtkPVSession*>(pm->GetSession());
427     if(pvs) {
428       vtkPVProgressHandler* ph = pvs->GetProgressHandler();
429       if(ph) {
430           this->VTKConnect->Connect(ph, vtkCommand::StartEvent,
431                                     this, SLOT(onStartProgress()));
432           this->VTKConnect->Connect(ph, vtkCommand::EndEvent,
433                                     this, SLOT(onEndProgress()));
434       }
435     }
436   }
437 }
438
439 void PVGUI_Module::onStartProgress()
440 {
441   QApplication::setOverrideCursor(Qt::WaitCursor);
442 }
443
444 void PVGUI_Module::onEndProgress()
445 {
446   QApplication::restoreOverrideCursor();
447 }
448
449 void PVGUI_Module::onDataRepresentationUpdated() {
450   SalomeApp_Study* activeStudy = dynamic_cast<SalomeApp_Study*>(application()->activeStudy());
451   if(!activeStudy) return;
452   
453   activeStudy->Modified();
454 }
455
456 /*!
457   \brief Initialisation timer event - trace start up
458 */
459 void PVGUI_Module::onInitTimer()
460 {
461   startTrace();
462 }
463   
464 /*!
465   \brief Get list of embedded macros files
466 */
467 QStringList PVGUI_Module::getEmbeddedMacrosList()
468 {
469   QString aRootDir = getenv("PARAVIS_ROOT_DIR");
470
471   QString aSourcePath = aRootDir + "/bin/salome/Macro";
472
473   QStringList aFilter;
474   aFilter << "*.py";
475
476   QDir aSourceDir(aSourcePath);
477   QStringList aSourceFiles = aSourceDir.entryList(aFilter, QDir::Files);
478   QStringList aFullPathSourceFiles;
479   foreach (QString aMacrosName, aSourceFiles) {
480     aFullPathSourceFiles << aSourceDir.absoluteFilePath(aMacrosName);
481   }
482   return aFullPathSourceFiles;
483 }
484
485 void PVGUI_Module::updateMacros()
486 {
487   pqPythonManager* aPythonManager = pqPVApplicationCore::instance()->pythonManager();
488   if(!aPythonManager)  {
489     return;
490   }
491   
492   foreach (QString aStr, getEmbeddedMacrosList()) {
493     aPythonManager->addMacro(aStr);
494   }
495 }
496
497
498 /*!
499   \brief Get list of compliant dockable GUI elements
500   \param m map to be filled in ("type":"default_position")
501 */
502 void PVGUI_Module::windows( QMap<int, int>& m ) const
503 {
504   m.insert( LightApp_Application::WT_ObjectBrowser, Qt::LeftDockWidgetArea );
505   m.insert( LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea );
506   // ParaView diagnostic output redirected here
507   m.insert( LightApp_Application::WT_LogWindow, Qt::BottomDockWidgetArea );
508 }
509
510 /*!
511   \brief Shows (toShow = true) or hides ParaView view window
512 */
513 void PVGUI_Module::showView( bool toShow )
514 {
515   SalomeApp_Application* anApp = getApp();
516   PVViewer_ViewManager* viewMgr =
517     dynamic_cast<PVViewer_ViewManager*>( anApp->getViewManager( PVViewer_Viewer::Type(), false ) );
518   if ( !viewMgr ) {
519     viewMgr = new PVViewer_ViewManager( anApp->activeStudy(), anApp->desktop() );
520     anApp->addViewManager( viewMgr );
521     connect( viewMgr, SIGNAL( lastViewClosed( SUIT_ViewManager* ) ),
522              anApp, SLOT( onCloseView( SUIT_ViewManager* ) ) );
523   }
524
525   PVViewer_ViewWindow* pvWnd = dynamic_cast<PVViewer_ViewWindow*>( viewMgr->getActiveView() );
526   if ( !pvWnd ) {
527     pvWnd = dynamic_cast<PVViewer_ViewWindow*>( viewMgr->createViewWindow() );
528     // this also connects to the pvserver and instantiates relevant PV behaviors
529   }
530
531   pvWnd->setShown( toShow );
532   if ( toShow ) pvWnd->setFocus();
533 }
534
535 /*!
536   \brief Slot to show help for proxy.
537 */
538 void PVGUI_Module::showHelpForProxy( const QString& groupname, const QString& proxyname )
539 {
540   pqHelpReaction::showProxyHelp(groupname, proxyname);
541 }
542
543
544 /*!
545   \brief Slot to show the waiting state.
546 */
547 void PVGUI_Module::onPreAccept()
548 {
549   getApp()->desktop()->statusBar()->showMessage(tr("STB_PREACCEPT"));
550   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
551 }
552
553 /*!
554   \brief Slot to show the ready state.
555 */
556 void PVGUI_Module::onPostAccept()
557 {
558   getApp()->desktop()->statusBar()->showMessage(tr("STB_POSTACCEPT"), 2000);
559   QTimer::singleShot(0, this, SLOT(endWaitCursor()));
560 }
561
562 /*!
563   \brief Slot to switch off wait cursor.
564 */
565 void PVGUI_Module::endWaitCursor()
566 {
567   QApplication::restoreOverrideCursor();
568 }
569
570 static void ParavisMessageOutput(QtMsgType type, const char *msg)
571 {
572   switch(type)
573     {
574   case QtDebugMsg:
575     vtkOutputWindow::GetInstance()->DisplayText(msg);
576     break;
577   case QtWarningMsg:
578     vtkOutputWindow::GetInstance()->DisplayErrorText(msg);
579     break;
580   case QtCriticalMsg:
581     vtkOutputWindow::GetInstance()->DisplayErrorText(msg);
582     break;
583   case QtFatalMsg:
584     vtkOutputWindow::GetInstance()->DisplayErrorText(msg);
585     break;
586     }
587 }
588
589 /*!
590   \brief Activate module.
591   \param study current study
592   \return \c true if activaion is done successfully or 0 to prevent
593   activation on error
594 */
595 bool PVGUI_Module::activateModule( SUIT_Study* study )
596 {
597   myOldMsgHandler = qInstallMsgHandler(ParavisMessageOutput);
598   
599   SUIT_ExceptionHandler::addCleanUpRoutine( paravisCleanUp );
600
601   storeCommonWindowsState();
602
603   bool isDone = SalomeApp_Module::activateModule( study );
604   if ( !isDone ) return false;
605
606   showView( true );  // this will also trigger the connection to the server
607                      // and the instanciation of the relevant PV behaviors
608   if ( mySourcesMenuId != -1 ) menuMgr()->show(mySourcesMenuId);
609   if ( myFiltersMenuId != -1 ) menuMgr()->show(myFiltersMenuId);
610   if ( myFiltersMenuId != -1 ) menuMgr()->show(myMacrosMenuId);
611   if ( myFiltersMenuId != -1 ) menuMgr()->show(myToolbarsMenuId);
612   setMenuShown( true );
613   setToolShown( true );
614
615   restoreDockWidgetsState();
616
617   QMenu* aMenu = menuMgr()->findMenu( myRecentMenuId );
618   if(aMenu) {
619     QList<QAction*> anActns = aMenu->actions();
620     for (int i = 0; i < anActns.size(); ++i) {
621       QAction* a = anActns.at(i);
622       if(a)
623         a->setVisible(true);
624     }
625   }
626
627   QList<QMenu*>::iterator it;
628   for (it = myMenus.begin(); it != myMenus.end(); ++it) {
629     QAction* a = (*it)->menuAction();
630     if(a)
631       a->setVisible(true);
632   }
633
634   if ( myRecentMenuId != -1 ) menuMgr()->show(myRecentMenuId);
635
636   ClientFindOrCreateParavisComponent(PARAVIS::GetCStudy(this));
637
638   return isDone;
639 }
640
641
642 /*!
643   \brief Deactivate module.
644   \param study current study
645   \return \c true if deactivaion is done successfully or 0 to prevent
646   deactivation on error
647 */
648 bool PVGUI_Module::deactivateModule( SUIT_Study* study )
649 {
650   MESSAGE("PARAVIS deactivation ...")
651
652   QMenu* aMenu = menuMgr()->findMenu( myRecentMenuId );
653   if(aMenu) {
654     QList<QAction*> anActns = aMenu->actions();
655     for (int i = 0; i < anActns.size(); ++i) {
656       QAction* a = anActns.at(i);
657       if(a)
658         a->setVisible(false);
659     }
660   }
661
662   QList<QMenu*>::iterator it;
663   for (it = myMenus.begin(); it != myMenus.end(); ++it) {
664     QAction* a = (*it)->menuAction();
665     if(a)
666       a->setVisible(false);
667   }
668
669   QList<QDockWidget*> aStreamingViews = application()->desktop()->findChildren<QDockWidget*>("pqStreamingControls");
670   foreach(QDockWidget* aView, aStreamingViews) {
671     if (!myDockWidgets.contains(aView))
672       myDockWidgets[aView] = aView->isVisible();
673   }
674
675   /*if (pqImplementation::helpWindow) {
676     pqImplementation::helpWindow->hide();
677     }*/
678   showView( false );
679   // hide menus
680   menuMgr()->hide(myRecentMenuId);
681   menuMgr()->hide(mySourcesMenuId);
682   menuMgr()->hide(myFiltersMenuId);
683   menuMgr()->hide(myMacrosMenuId);
684   menuMgr()->hide(myToolbarsMenuId);
685   setMenuShown( false );
686   setToolShown( false );
687
688   saveDockWidgetsState();
689
690   SUIT_ExceptionHandler::removeCleanUpRoutine( paravisCleanUp );
691
692   if (myOldMsgHandler)
693     qInstallMsgHandler(myOldMsgHandler);
694
695   restoreCommonWindowsState();
696   
697   return SalomeApp_Module::deactivateModule( study );
698 }
699
700
701 /*!
702   \brief Called when application is closed.
703
704   Process finalize application functionality from ParaView in order to save server settings
705   and nullify application pointer if the application is being closed.
706
707   \param theApp application
708 */
709 void PVGUI_Module::onApplicationClosed( SUIT_Application* theApp )
710 {
711   PVViewer_ViewManager::ParaviewCleanup();
712
713   int aAppsNb = SUIT_Session::session()->applications().size();
714   if (aAppsNb == 1) {
715     deleteTemporaryFiles();
716   }
717   CAM_Module::onApplicationClosed(theApp);
718 }
719
720
721 /*!
722   \brief Deletes temporary files created during import operation from VISU
723 */
724 void PVGUI_Module::deleteTemporaryFiles()
725 {
726   foreach(QString aFile, myTemporaryFiles) {
727     if (QFile::exists(aFile)) {
728       QFile::remove(aFile);
729     }
730   }
731 }
732
733
734 /*!
735   \brief Called when study is closed.
736
737   Removes data model from the \a study.
738
739   \param study study being closed
740 */
741 void PVGUI_Module::studyClosed(SUIT_Study* study)
742 {
743   clearParaviewState();
744
745   SalomeApp_Module::studyClosed(study);
746 }
747
748 /*!
749   \brief Called when study is opened.
750 */
751 void PVGUI_Module::onModelOpened()
752 {
753   _PTR(Study) studyDS = PARAVIS::GetCStudy(this);
754   if(!studyDS) {
755     return;
756   }
757   
758   _PTR(SComponent) paravisComp = 
759     studyDS->FindComponent(GetEngine()->ComponentDataType());
760   if(!paravisComp) {
761     return;
762   }
763
764   _PTR(ChildIterator) anIter(studyDS->NewChildIterator(paravisComp));
765   for (; anIter->More(); anIter->Next()) {
766     _PTR(SObject) aSObj = anIter->Value();
767     _PTR(GenericAttribute) anAttr;
768     if (!aSObj->FindAttribute(anAttr, "AttributeLocalID")) {
769       continue;
770     }
771     _PTR(AttributeLocalID) anID(anAttr);
772     if (anID->Value() == PVSTATEID) {
773       myStateCounter++;
774     }
775   }
776 }
777
778 /*!
779   \brief Returns IOR of current engine
780 */
781 QString PVGUI_Module::engineIOR() const
782 {
783   CORBA::String_var anIOR = GetEngine()->GetIOR();
784   return QString(anIOR.in());
785 }
786
787 /*!
788   \brief Open file of format supported by ParaView
789 */
790 void PVGUI_Module::openFile(const char* theName)
791 {
792   QStringList aFiles;
793   aFiles<<theName;
794   pqLoadDataReaction::loadData(aFiles);
795 }
796
797 /**!
798  * Start trace invoking the newly introduced C++ API (PV 4.2)
799  * (inspired from pqTraceReaction::start())
800  */
801 void PVGUI_Module::startTrace()
802 {
803   vtkSMSessionProxyManager* pxm = pqActiveObjects::instance().activeServer()->proxyManager();
804
805   vtkSmartPointer<vtkSMProxy> proxy;
806   proxy.TakeReference(pxm->NewProxy("pythontracing", "PythonTraceOptions"));
807   if (proxy)
808     {
809       vtkNew<vtkSMParaViewPipelineController> controller;
810       controller->InitializeProxy(proxy);
811     }
812   vtkSMTrace* trace = vtkSMTrace::StartTrace();
813   if (proxy)
814     {
815       // Set manually the properties entered via the dialog box poping-up when requiring
816       // a trace start in PV4.2 (trace options)
817       trace->SetPropertiesToTraceOnCreate(vtkSMTrace::RECORD_USER_MODIFIED_PROPERTIES);
818       trace->SetFullyTraceSupplementalProxies(false);
819     }
820 }
821
822 void PVGUI_Module::stopTrace()
823 {
824   vtkSMTrace::StopTrace();
825 }
826
827 void PVGUI_Module::executeScript(const char *script)
828 {
829 #ifndef WNT
830   pqPythonManager* manager = qobject_cast<pqPythonManager*>(
831                              pqApplicationCore::instance()->manager("PYTHON_MANAGER"));
832   if (manager)  {
833     pqPythonDialog* pyDiag = manager->pythonShellDialog();
834     if (pyDiag) {
835       pyDiag->runString(script);  
836       }
837     }
838 #endif
839 }
840
841 ///**
842 // *  Debug function printing out the given interpreter's execution context
843 // */
844 //void printInterpContext(PyInterp_Interp * interp )
845 //{
846 //  // Extract __smtraceString from interpreter's context
847 //  const PyObject* ctxt = interp->getExecutionContext();
848 //
849 //  PyObject* lst = PyDict_Keys((PyObject *)ctxt);
850 //  Py_ssize_t siz = PyList_GET_SIZE(lst);
851 //  for (Py_ssize_t i = 0; i < siz; i++)
852 //    {
853 //      PyObject * elem = PyList_GetItem(lst, i);
854 //      if (PyString_Check(elem))
855 //        {
856 //          std::cout << "At pos:" << i << ", " << PyString_AsString(elem) << std::endl;
857 //        }
858 //      else
859 //        std::cout << "At pos:" << i << ", not a string!" << std::endl;
860 //    }
861 //  Py_XDECREF(lst);
862 //}
863
864 /*!
865   \brief Returns trace string
866 */
867 static const QString MYReplaceStr("paraview.simple");
868 static const QString MYReplaceImportStr("except: from pvsimple import *");
869 QString PVGUI_Module::getTraceString()
870 {
871   vtkSMTrace *tracer = vtkSMTrace::GetActiveTracer();
872   if (!tracer) // trace is not started
873     return QString("");
874
875   QString traceString(tracer->GetCurrentTrace());
876
877   // Replace import "paraview.simple" by "pvsimple"
878   if ((!traceString.isNull()) && traceString.length() != 0) {
879     int aPos = traceString.indexOf(MYReplaceStr);
880     while (aPos != -1) {
881       traceString = traceString.replace(aPos, MYReplaceStr.length(), "pvsimple");
882       aPos = traceString.indexOf(MYReplaceStr, aPos);
883     }
884     int aImportPos = traceString.indexOf(MYReplaceImportStr);
885     if(aImportPos != -1)
886       {
887       traceString = traceString.replace(aImportPos, MYReplaceImportStr.length(), "except:\n  import pvsimple\n  from pvsimple import *");
888       }
889   }
890
891   return traceString;
892 }
893
894 /*!
895   \brief Saves trace string to disk file
896 */
897 void PVGUI_Module::saveTrace(const char* theName)
898 {
899   QFile file(theName);
900   if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
901     MESSAGE( "Could not open file:" << theName );
902     return;
903   }
904   QTextStream out(&file);
905   out << getTraceString();
906   file.close();
907 }
908
909 /*!
910   \brief Saves ParaView state to a disk file
911 */
912 void PVGUI_Module::saveParaviewState(const char* theFileName)
913 {
914   pqApplicationCore::instance()->saveState(theFileName);
915 }
916
917 /*!
918   \brief Delete all objects for Paraview Pipeline Browser
919 */
920 void PVGUI_Module::clearParaviewState()
921 {
922   QAction* deleteAllAction = action(DeleteAllId);
923   if (deleteAllAction) {
924     deleteAllAction->activate(QAction::Trigger);
925   }
926 }
927
928 /*!
929   \brief Restores ParaView state from a disk file
930
931   If toClear == true, the current ojects will be deleted
932 */
933 void PVGUI_Module::loadParaviewState(const char* theFileName)
934 {
935   pqApplicationCore::instance()->loadState(theFileName, getActiveServer());
936 }
937
938 /*!
939   \brief Returns current active ParaView server
940 */
941 pqServer* PVGUI_Module::getActiveServer()
942 {
943   return pqApplicationCore::instance()->getActiveServer();
944 }
945
946
947 /*!
948   \brief Creates PARAVIS preference pane 
949 */
950 void PVGUI_Module::createPreferences()
951 {
952   // Paraview settings tab
953   int aParaViewSettingsTab = addPreference( tr( "TIT_PVIEWSETTINGS" ) );
954   int aPanel = addPreference(QString(), aParaViewSettingsTab, LightApp_Preferences::UserDefined, "PARAVIS", "");
955   setPreferenceProperty(aPanel, "content", (qint64)(new PVGUI_ParaViewSettingsPane()));
956
957   // Paravis settings tab
958   int aParaVisSettingsTab = addPreference( tr( "TIT_PVISSETTINGS" ) );
959   addPreference( tr( "PREF_STOP_TRACE" ), aParaVisSettingsTab, LightApp_Preferences::Bool, "PARAVIS", "stop_trace");
960
961   addPreference( tr( "PREF_NO_EXT_PVSERVER" ), aParaVisSettingsTab, LightApp_Preferences::Bool, "PARAVIS", "no_ext_pv_server");
962
963   int aSaveType = addPreference(tr( "PREF_SAVE_TYPE_LBL" ), aParaVisSettingsTab,
964                                 LightApp_Preferences::Selector,
965                                 "PARAVIS", "savestate_type");
966   QList<QVariant> aIndices;
967   QStringList aStrings;
968   aIndices<<0<<1<<2;
969   aStrings<<tr("PREF_SAVE_TYPE_0");
970   aStrings<<tr("PREF_SAVE_TYPE_1");
971   aStrings<<tr("PREF_SAVE_TYPE_2");
972   setPreferenceProperty(aSaveType, "strings", aStrings);
973   setPreferenceProperty(aSaveType, "indexes", aIndices);
974 }
975
976 /*!
977   \brief Creates ParaViS context menu popup
978 */
979 void PVGUI_Module::contextMenuPopup(const QString& theClient, QMenu* theMenu, QString& theTitle)
980 {
981   SalomeApp_Module::contextMenuPopup(theClient, theMenu, theTitle);
982   
983   // Check if we are in Object Browser
984   SUIT_DataBrowser* ob = getApp()->objectBrowser();
985   bool isOBClient = (ob && theClient == ob->popupClientType());
986   if (!isOBClient) {
987     return;
988   }
989
990   // Get list of selected objects
991   LightApp_SelectionMgr* aSelectionMgr = getApp()->selectionMgr();
992   SALOME_ListIO aListIO;
993   aSelectionMgr->selectedObjects(aListIO);
994   if (aListIO.Extent() == 1 && aListIO.First()->hasEntry()) {
995     QString entry = QString(aListIO.First()->getEntry());
996     
997     // Get active study
998     SalomeApp_Study* activeStudy = 
999       dynamic_cast<SalomeApp_Study*>(getApp()->activeStudy());
1000     if(!activeStudy) {
1001       return;
1002     }
1003
1004     // Get SALOMEDS client study 
1005     _PTR(Study) studyDS = activeStudy->studyDS();
1006     if(!studyDS) {
1007       return;
1008     }
1009
1010     QString paravisDataType(GetEngine()->ComponentDataType());
1011     if(activeStudy && activeStudy->isComponent(entry) && 
1012        activeStudy->componentDataType(entry) == paravisDataType) {
1013       // ParaViS module object
1014       theMenu->addSeparator();
1015       theMenu->addAction(action(SaveStatePopupId));
1016     }
1017     else {
1018       // Try to get state object
1019       _PTR(SObject) stateSObj = 
1020           studyDS->FindObjectID(entry.toLatin1().constData());
1021       if (!stateSObj) {
1022           return;
1023       }
1024       
1025       // Check local id
1026       _PTR(GenericAttribute) anAttr;
1027       if (!stateSObj->FindAttribute(anAttr, "AttributeLocalID")) {
1028           return;
1029       }
1030
1031       _PTR(AttributeLocalID) anID(anAttr);
1032       
1033       if (anID->Value() == PVSTATEID) {
1034         // Paraview state object
1035         theMenu->addSeparator();
1036         theMenu->addAction(action(AddStatePopupId));
1037         theMenu->addAction(action(CleanAndAddStatePopupId));
1038         theMenu->addSeparator();
1039         theMenu->addAction(action(ParaVisRenameId));
1040         theMenu->addAction(action(ParaVisDeleteId));
1041       }
1042     }
1043   }
1044 }
1045
1046 /*!
1047   \brief. Show ParaView python trace.
1048 */
1049 void PVGUI_Module::onShowTrace()
1050 {
1051   if (!myTraceWindow) {
1052     myTraceWindow = new pqPythonScriptEditor(getApp()->desktop());
1053   }
1054   myTraceWindow->setText(getTraceString());
1055   myTraceWindow->show();
1056   myTraceWindow->raise();
1057   myTraceWindow->activateWindow();
1058 }
1059
1060
1061 /*!
1062   \brief. Re-initialize ParaView python trace.
1063 */
1064 void PVGUI_Module::onRestartTrace()
1065 {
1066   stopTrace();
1067   startTrace();
1068 }
1069
1070 /*!
1071   \brief Show ParaView view.
1072 */
1073 void PVGUI_Module::onNewParaViewWindow()
1074 {
1075   showView(true);
1076 }
1077
1078 /*!
1079   \brief Save state under the module root object.
1080 */
1081 void PVGUI_Module::onSaveMultiState()
1082 {
1083   // Create state study object
1084   
1085   // Get SALOMEDS client study
1086   _PTR(Study) studyDS = PARAVIS::GetCStudy(this);
1087   if(!studyDS) {
1088     return;
1089   }
1090   
1091   _PTR(SComponent) paravisComp = 
1092     studyDS->FindComponent(GetEngine()->ComponentDataType());
1093   if(!paravisComp) {
1094     return;
1095   }
1096
1097   // Unlock the study if it is locked
1098   bool isLocked = studyDS->GetProperties()->IsLocked();
1099   if (isLocked) {
1100     studyDS->GetProperties()->SetLocked(false);
1101   }
1102   
1103   QString stateName = tr("SAVED_PARAVIEW_STATE_NAME") + 
1104     QString::number(myStateCounter + 1);
1105
1106   _PTR(StudyBuilder) studyBuilder = studyDS->NewBuilder();
1107   _PTR(SObject) newSObj = studyBuilder->NewObject(paravisComp);
1108
1109   // Set name
1110   _PTR(GenericAttribute) anAttr;
1111   anAttr = studyBuilder->FindOrCreateAttribute(newSObj, "AttributeName");
1112   _PTR(AttributeName) nameAttr(anAttr);
1113   
1114   nameAttr->SetValue(stateName.toLatin1().constData());
1115
1116   // Set local id
1117   anAttr = studyBuilder->FindOrCreateAttribute(newSObj, "AttributeLocalID");
1118   _PTR(AttributeLocalID) localIdAttr(anAttr);
1119   
1120   localIdAttr->SetValue(PVSTATEID);
1121
1122   // Set file name
1123   QString stateEntry = QString::fromStdString(newSObj->GetID());
1124  
1125   // File name for state saving
1126   QString tmpDir = QString::fromStdString(SALOMEDS_Tool::GetTmpDir());
1127   QString fileName = QString("%1_paravisstate:%2").arg(tmpDir, stateEntry);
1128
1129   anAttr = studyBuilder->FindOrCreateAttribute(newSObj, "AttributeString");
1130   _PTR(AttributeString) stringAttr(anAttr);
1131   
1132   stringAttr->SetValue(fileName.toLatin1().constData());
1133
1134   // Lock the study back if necessary
1135   if (isLocked) {
1136     studyDS->GetProperties()->SetLocked(true);
1137   }
1138   
1139   // Save state
1140   saveParaviewState(fileName.toLatin1().constData());
1141   myTemporaryFiles.append(fileName);
1142   
1143   // Increment the counter
1144   myStateCounter++;
1145
1146   updateObjBrowser();
1147 }
1148
1149 /*!
1150   \brief Restore the selected state by merging with the current one.
1151 */
1152 void PVGUI_Module::onAddState()
1153 {
1154   loadSelectedState(false);
1155 }
1156
1157 /*!
1158   \brief Clean the current state and restore the selected one.
1159 */
1160 void PVGUI_Module::onCleanAddState()
1161 {
1162   loadSelectedState(true);
1163 }
1164
1165 /*!
1166   \brief Rename the selected object.
1167 */
1168 void PVGUI_Module::onRename()
1169 {
1170   LightApp_SelectionMgr* aSelectionMgr = getApp()->selectionMgr();
1171   SALOME_ListIO aListIO;
1172   aSelectionMgr->selectedObjects(aListIO);
1173   
1174   if (aListIO.Extent() == 1 && aListIO.First()->hasEntry()) {
1175     std::string entry = aListIO.First()->getEntry();
1176     
1177     // Get SALOMEDS client study 
1178     _PTR(Study) studyDS = PARAVIS::GetCStudy(this);
1179     if(!studyDS) {
1180       return;
1181     }
1182     
1183     // Unlock the study if it is locked
1184     bool isLocked = studyDS->GetProperties()->IsLocked();
1185     if (isLocked) {
1186       studyDS->GetProperties()->SetLocked(false);
1187     }
1188     
1189     // Rename the selected state object
1190     _PTR(SObject) stateSObj = studyDS->FindObjectID(entry);
1191     if (!stateSObj) {
1192       return;
1193     }
1194     
1195     _PTR(GenericAttribute) anAttr;
1196     if (stateSObj->FindAttribute(anAttr, "AttributeName")) {
1197       _PTR(AttributeName) nameAttr (anAttr);
1198       QString newName = 
1199           LightApp_NameDlg::getName(getApp()->desktop(), nameAttr->Value().c_str());
1200       if (!newName.isEmpty()) {
1201         nameAttr->SetValue(newName.toLatin1().constData());
1202         aListIO.First()->setName(newName.toLatin1().constData());
1203       }
1204     }
1205     
1206     // Lock the study back if necessary
1207     if (isLocked) {
1208       studyDS->GetProperties()->SetLocked(true);
1209     }
1210     
1211     // Update object browser
1212     updateObjBrowser();
1213     
1214   }
1215 }
1216
1217 /*!
1218   \brief Delete the selected objects.
1219 */
1220 void PVGUI_Module::onDelete()
1221 {
1222   LightApp_SelectionMgr* aSelectionMgr = getApp()->selectionMgr();
1223   SALOME_ListIO aListIO;
1224   aSelectionMgr->selectedObjects(aListIO);
1225   
1226   if (aListIO.Extent() == 1 && aListIO.First()->hasEntry()) {
1227     std::string entry = aListIO.First()->getEntry();
1228     
1229     // Get SALOMEDS client study 
1230     _PTR(Study) studyDS = PARAVIS::GetCStudy(this);
1231     if(!studyDS) {
1232       return;
1233     }
1234     
1235     // Unlock the study if it is locked
1236     bool isLocked = studyDS->GetProperties()->IsLocked();
1237     if (isLocked) {
1238       studyDS->GetProperties()->SetLocked(false);
1239     }
1240     
1241     // Remove the selected state from the study
1242     _PTR(StudyBuilder) studyBuilder = studyDS->NewBuilder();
1243     _PTR(SObject) stateSObj = studyDS->FindObjectID(entry);
1244     studyBuilder->RemoveObject(stateSObj);
1245     
1246     // Lock the study back if necessary
1247     if (isLocked) {
1248       studyDS->GetProperties()->SetLocked(true);
1249     }
1250     
1251     // Update object browser
1252     updateObjBrowser();
1253   }
1254 }
1255
1256 void PVGUI_Module::onPushTraceTimer()
1257 {
1258 //  MESSAGE("onPushTraceTimer(): Pushing trace to engine...");
1259   GetEngine()->PutPythonTraceStringToEngine(getTraceString().toStdString().c_str());
1260 }
1261
1262 /*!
1263   \brief Discover help project files from the resources.
1264   \return name of the help file. 
1265 */
1266 QString PVGUI_Module::getHelpFileName() {
1267   QString aPVHome(getenv("PVHOME"));
1268   if (aPVHome.isNull()) {
1269     qWarning("Wariable PVHOME is not defined");
1270     return QString();
1271   }
1272   QChar aSep = QDir::separator();
1273   //PARAVIEW_VERSION from the vtkPVConfig.h file
1274   QString aFileName =  aPVHome + aSep + "share" + aSep + "doc" + aSep + "paraview-"+ PARAVIEW_VERSION + aSep + "paraview.qch";
1275   return aFileName;
1276 }
1277
1278
1279 /*!
1280   \brief Load selected paraview state
1281
1282   If toClear == true, the current state will be cleared
1283 */
1284 void PVGUI_Module::loadSelectedState(bool toClear)
1285 {
1286   QString fileName;
1287
1288   LightApp_SelectionMgr* aSelectionMgr = getApp()->selectionMgr();
1289   SALOME_ListIO aListIO;
1290   aSelectionMgr->selectedObjects(aListIO);
1291   
1292   if (aListIO.Extent() == 1 && aListIO.First()->hasEntry()) {
1293     std::string entry = aListIO.First()->getEntry();
1294     
1295     // Get SALOMEDS client study 
1296     _PTR(Study) studyDS = PARAVIS::GetCStudy(this);
1297     if(!studyDS) {
1298       return;
1299     }
1300
1301     // Check local id
1302     _PTR(SObject) stateSObj = studyDS->FindObjectID(entry);
1303     _PTR(GenericAttribute) anAttr;
1304     if (!stateSObj->FindAttribute(anAttr, "AttributeLocalID")) {
1305       return;
1306     }
1307     _PTR(AttributeLocalID) anID(anAttr);
1308     if (!anID->Value() == PVSTATEID) {
1309       return;
1310     }
1311
1312     // Get state file name
1313     if (stateSObj->FindAttribute(anAttr, "AttributeString")) {
1314       _PTR(AttributeString) aStringAttr(anAttr);
1315       QString stringValue(aStringAttr->Value().c_str());
1316
1317       if (QFile::exists(stringValue)) {
1318           fileName = stringValue;
1319       }
1320     }
1321   }
1322   
1323   if (!fileName.isEmpty()) {
1324     if (toClear) {
1325       clearParaviewState();
1326     }
1327
1328     loadParaviewState(fileName.toLatin1().constData());
1329   } 
1330   else {
1331     SUIT_MessageBox::critical(getApp()->desktop(),
1332                               tr("ERR_ERROR"),
1333                               tr("ERR_STATE_CANNOT_BE_RESTORED"));
1334   }
1335 }
1336
1337 /*!
1338   \fn CAM_Module* createModule();
1339   \brief Export module instance (factory function).
1340   \return new created instance of the module
1341 */
1342
1343 #ifdef WNT
1344 #define PVGUI_EXPORT __declspec(dllexport)
1345 #else   // WNT
1346 #define PVGUI_EXPORT
1347 #endif  // WNT
1348
1349 extern "C" {
1350
1351   bool flag = false;
1352   PVGUI_EXPORT CAM_Module* createModule() {
1353     return new PVGUI_Module();
1354   }
1355   
1356   PVGUI_EXPORT char* getModuleVersion() {
1357     return (char*)PARAVIS_VERSION_STR;
1358   }
1359 }