]> SALOME platform Git repositories - modules/paravis.git/blob - src/PVGUI/PVGUI_Module.cxx
Salome HOME
PARAVIS HTML docs
[modules/paravis.git] / src / PVGUI / PVGUI_Module.cxx
1 // PARAVIS : ParaView wrapper SALOME module
2 //
3 // Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File   : PVGUI_Module.cxx
23 // Author : Julia DOROVSKIKH
24 //
25
26 #include "PVGUI_Module.h"
27 #include "PVGUI_Module_impl.h"
28 #include "PVGUI_ProcessModuleHelper.h"
29 #include "PVGUI_ViewModel.h"
30 #include "PVGUI_ViewManager.h"
31 #include "PVGUI_ViewWindow.h"
32
33 #include <SUIT_Desktop.h>
34 #include <SUIT_MessageBox.h>
35 #include <SUIT_ResourceMgr.h>
36 #include <SUIT_Session.h>
37 #include <LightApp_Application.h>
38 #include <LightApp_SelectionMgr.h>
39 #include <QtxActionMenuMgr.h>
40 #include <QtxActionToolMgr.h>
41
42 #include <QAction>
43 #include <QApplication>
44 #include <QCursor>
45 #include <QDir>
46 #include <QFile>
47 #include <QFileInfo>
48 #include <QIcon>
49 #include <QInputDialog>
50 #include <QStatusBar>
51 #include <QString>
52 #include <QStringList>
53 #include <QTimer>
54 #include <QToolBar>
55
56 #include <pqApplicationCore.h>
57 #include <pqActiveServer.h>
58 #include <pqActiveView.h>
59 #include <pqClientAboutDialog.h>
60 #include <pqObjectBuilder.h>
61 #include <pqOptions.h>
62 #include <pqRenderView.h>
63 #include <pqRubberBandHelper.h>
64 #include <pqServer.h>
65 #include <pqServerManagerModel.h>
66 #include <pqServerResource.h>
67 #include <pqUndoStack.h>
68 #include <pqVCRController.h>
69 #include <pqViewManager.h>
70 #include <vtkPVMain.h>
71 #include <vtkProcessModule.h>
72
73 /*
74  * Make sure all the kits register their classes with vtkInstantiator.
75  * Since ParaView uses Tcl wrapping, all of VTK is already compiled in
76  * anyway.  The instantiators will add no more code for the linker to
77  * collect.
78  */
79
80 #include <vtkCommonInstantiator.h>
81 #include <vtkFilteringInstantiator.h>
82 #include <vtkGenericFilteringInstantiator.h>
83 #include <vtkIOInstantiator.h>
84 #include <vtkImagingInstantiator.h>
85 #include <vtkInfovisInstantiator.h>
86 #include <vtkGraphicsInstantiator.h>
87
88 #include <vtkRenderingInstantiator.h>
89 #include <vtkVolumeRenderingInstantiator.h>
90 #include <vtkHybridInstantiator.h>
91 #include <vtkParallelInstantiator.h>
92
93 #include <vtkPVServerCommonInstantiator.h>
94 #include <vtkPVFiltersInstantiator.h>
95 #include <vtkPVServerManagerInstantiator.h>
96 #include <vtkClientServerInterpreter.h>
97
98
99 //----------------------------------------------------------------------------
100 // ClientServer wrapper initialization functions.
101 // Taken from ParaView sources (file pqMain.cxx)
102 extern "C" void vtkCommonCS_Initialize(vtkClientServerInterpreter*);
103 extern "C" void vtkFilteringCS_Initialize(vtkClientServerInterpreter*);
104 extern "C" void vtkGenericFilteringCS_Initialize(vtkClientServerInterpreter*);
105 extern "C" void vtkImagingCS_Initialize(vtkClientServerInterpreter*);
106 extern "C" void vtkInfovisCS_Initialize(vtkClientServerInterpreter*);
107 extern "C" void vtkGraphicsCS_Initialize(vtkClientServerInterpreter*);
108 extern "C" void vtkIOCS_Initialize(vtkClientServerInterpreter*);
109 extern "C" void vtkRenderingCS_Initialize(vtkClientServerInterpreter*);
110 extern "C" void vtkVolumeRenderingCS_Initialize(vtkClientServerInterpreter*);
111 extern "C" void vtkHybridCS_Initialize(vtkClientServerInterpreter*);
112 extern "C" void vtkWidgetsCS_Initialize(vtkClientServerInterpreter*);
113 extern "C" void vtkParallelCS_Initialize(vtkClientServerInterpreter*);
114 extern "C" void vtkPVServerCommonCS_Initialize(vtkClientServerInterpreter*);
115 extern "C" void vtkPVFiltersCS_Initialize(vtkClientServerInterpreter*);
116 extern "C" void vtkXdmfCS_Initialize(vtkClientServerInterpreter *);
117
118 //----------------------------------------------------------------------------
119 void ParaViewInitializeInterpreter(vtkProcessModule* pm)
120 {
121   // Initialize built-in wrapper modules.
122   vtkCommonCS_Initialize(pm->GetInterpreter());
123   vtkFilteringCS_Initialize(pm->GetInterpreter());
124   vtkGenericFilteringCS_Initialize(pm->GetInterpreter());
125   vtkImagingCS_Initialize(pm->GetInterpreter());
126   vtkInfovisCS_Initialize(pm->GetInterpreter());
127   vtkGraphicsCS_Initialize(pm->GetInterpreter());
128   vtkIOCS_Initialize(pm->GetInterpreter());
129   vtkRenderingCS_Initialize(pm->GetInterpreter());
130   vtkVolumeRenderingCS_Initialize(pm->GetInterpreter());
131   vtkHybridCS_Initialize(pm->GetInterpreter());
132   vtkWidgetsCS_Initialize(pm->GetInterpreter());
133   vtkParallelCS_Initialize(pm->GetInterpreter());
134   vtkPVServerCommonCS_Initialize(pm->GetInterpreter());
135   vtkPVFiltersCS_Initialize(pm->GetInterpreter());
136   vtkXdmfCS_Initialize(pm->GetInterpreter());
137 }
138
139 vtkPVMain*                 PVGUI_Module::pqImplementation::myPVMain = 0;
140 pqOptions*                 PVGUI_Module::pqImplementation::myPVOptions = 0;
141 PVGUI_ProcessModuleHelper* PVGUI_Module::pqImplementation::myPVHelper = 0;
142
143 /*!
144   \mainpage
145
146   <h2>Building and installing PARAVIS</h2>
147   As any other SALOME module, PARAVIS requires PARAVIS_ROOT_DIR environment variable to be set to PARAVIS
148   installation directory.
149   Other variables needed for correct detection of ParaView location:
150   \li PVSRCHOME - points at the root of ParaView source directory tree
151   \li PVINSTALLHOME - points at the top of ParaView build tree (currently, due to some drawbacks in its buld procedure
152   ParaView should not be installed, its build directory is used instead).
153
154   It also requires common SALOME environment including GUI_ROOT_DIR and other prerequsites.
155
156   As soon as the environment is set, excute the following commands in a shell:
157   \code
158   mkdir PARAVIS_BUILD
159   cd PARAVIS_BUILD
160   ../PARAVIS_SRC/build_configure
161   ../PARAVIS_SRC/configure --prefix=${PARAVIS_ROOT_DIR}
162   make 
163   make docs
164   make install
165   \endcode
166
167   PARAVIS module can be launched using the following commands:
168   \li Light SALOME configuration
169   \code
170   runLightSalome.sh --modules="PARAVIS"
171   \endcode
172   or
173   \li Full SALOME configuration
174   \code
175   runSalome --modules="PARAVIS"
176   \endcode
177
178   <h2>ParaView GUI integration</h2>
179   <h3>ParaView GUI integration overview</h3>
180
181   The main idea is to reuse ParaView GUI internal logic as much as possible, providing a layer 
182   between it and SALOME GUI that hides the following SALOME GUI implementation details from ParaView:
183
184   \li SALOME GUI executable and Qt event loop
185   \li SALOME GUI desktop
186   \li Dock windows areas
187   \li SALOME menu and toolbar managers
188
189   Major part of the integration is implemented in PVGUI_Module class.
190
191   <h3>ParaView client initalization</h3>
192
193   ParaView client initalization is performed when an instance of PVGUI_Module class has been created 
194   and \link PVGUI_Module::initialize() PVGUI_Module::initialize()\endlink method is called by SALOME GUI.
195   The actual client start-up is done in \link PVGUI_Module::pvInit() PVGUI_Module::pvInit()\endlink method. 
196   It simulates actions perfomed by pqMain::Run( QApplication&, pqProcessModuleGUIHelper* ) method.
197   
198   Custom PVGUI_ProcessModuleHelper class derived from %pqProcessModuleGUIHelper base is the main actor in ParaView 
199   client initialization. It initializes the client that uses the main window (SALOME desktop) supplied from the outside, 
200   it does not start Qt event loop as this is done in SALOME GUI executable (SUITApp or SALOME_Session_Server), and after all 
201   it redirects ParaView diagnostic output to SALOME LogWindow with help of PVGUI_OutputWindowAdapter class.
202   This is achieved by reimplementing \link PVGUI_ProcessModuleHelper::InitializeApplication() InitializeApplication()\endlink,
203   \link PVGUI_ProcessModuleHelper::appExec() appExec()\endlink, \link PVGUI_ProcessModuleHelper::postAppExec() postAppExec()\endlink
204   virtual methods as well as those responsible for main window management.
205
206   <h3>ParaView GUI connection to SALOME desktop</h3>
207
208   ParaView Qt components include pqMainWindowCore class that handles most ParaView GUI client actions,
209   updates menu states and connects many GUI components.
210   After the client initalization \link PVGUI_Module::initialize() PVGUI_Module::initialize()\endlink method creates
211   an instance of internal PVGUI_Module::pqImplementation class (declared PVGUI_Module_impl.h) that wraps some ParaView GUI components: 
212   pqMainWindowCore, pqServer, etc. Instance of SALOME desktop widget is passed to pqMainWindowCore instead of ParaView main window.
213
214   Basically it simulates constructor of ParaView client's %MainWindow class (src/Applications/Client/MainWindow.cxx). It creates the same
215   menu and toolbar commands using SALOME menu and toolbar managers, connecting the actions to %pqMainWindowCore slots or to the module's 
216   slots in some cases. It also sets up dock widgets for ParaView widgets, such as object inspector, pipeline browser, etc.
217
218   As both SALOME destop and ParaView main winodw classes inherit QMainWindow and %pqMainWindowCore deals with QMainWindow API to control
219   menus, tollbars and dock widgets, its integration into SALOME GUI is straightforward and smooth.
220
221   <h3>Multi-view manager</h3>
222
223   SALOME GUI requires that each kind of view be implemnted with help of (at least) three classes. For ParaView multi-view manager 
224   these are:
225
226   \li PVGUI_ViewManager - view manager class
227   \li PVGUI_Viewer      - view model class
228   \li PVGUI_ViewWindow  - view window class that acts as a parent for %pqViewManager
229
230   Single instances of PVGUI_ViewManager and PVGUI_ViewWindow classes are created by \link PVGUI_Module::showView() 
231   PVGUI_Module::showView()\endlink method upon the first PARAVIS module activation. The same method hides the multi-view manager 
232   when the module is deactivated (the user switches to another module or a study is closed). 
233   A special trick is used to make PVGUI_ViewWindow the parent of %pqViewManager widget. It is created initally by %pqMainWindowCore
234   with the desktop as a parent, so when it is shown PVGUI_ViewWindow instance is passed to its setParent() method. In  
235   \link PVGUI_ViewWindow::~PVGUI_ViewWindow() PVGUI_ViewWindow::~PVGUI_ViewWindow()\endlink the parent is nullified to avoid deletion
236   of %pqViewManager widget that would break %pqMainWindowCore class.
237
238   <h3>ParaView plugins</h3>
239   ParaView server and client plugins are managed by %pqMainWindowCore slots that has full access to PARAVIS menus and toolbars. 
240   As a result they appears automatically in PARAVIS menus and toolbars if loaded successfully.
241
242   <h2>Limitations of 2008 year prototype</h2>
243   \li SALOME persistence (possibility to save the module data into a tsudy file) is not implemented for PARAVIS module.
244   \li As a light module, PARAVIS does not have a CORBA engine that follows SALOME rules, however PARAVIS can use load a CORBA engine 
245   on its own if needed.
246 */
247
248 /*
249   A link to the file documentation PVGUI_Module_actions.cxx
250
251   A link to the file documentation PVGUI_Module_impl.h
252
253   A link to the class documentation PVGUI_Module
254
255   The class name as a text (not a link to its documentation) %PVGUI_Module
256
257   A link to the constructor of the class PVGUI_ViewWindow#PVGUI_ViewWindow or PVGUI_Module::PVGUI_Module()
258
259   A link to the destructor of the class PVGUI_ViewWindow#~PVGUI_ViewWindow
260
261   A link to the member function PVGUI_ViewWindow::getVisualParameters or PVGUI_ViewWindow#getVisualParameters
262
263   Arguments of a function should be specified only for the overloaded functions PVGUI_Module::initialize(CAM_Application*)
264
265   A link to some enumeration values PVGUI_Module::OpenFileId and PVGUI_Module::CreateLookmarkId
266
267   A link to a protected member variable of the class PVGUI_ViewWindow#myModel
268
269   A link to a variable \link PVGUI_ViewWindow#myModel using another text\endlink as a link
270
271 */
272
273 /*!
274   \class PVGUI_Module
275   \brief Implementation of light (no-CORBA-engine) 
276          SALOME module wrapping ParaView GUI.
277 */
278
279 /*!
280   \brief Constructor. Sets the default name for the module.
281 */
282 PVGUI_Module::PVGUI_Module()
283   : LightApp_Module( "PARAVIS" ),
284     Implementation( 0 ),
285     mySelectionControlsTb( -1 ),
286     mySourcesMenuId( -1 ),
287     myFiltersMenuId( -1 )
288 {
289 }
290
291 /*!
292   \brief Destructor.
293 */
294 PVGUI_Module::~PVGUI_Module()
295 {
296 }
297
298 /*!
299   \brief Initialize module. Creates menus, prepares context menu, etc.
300   \param app SALOME GUI application instance
301 */
302 void PVGUI_Module::initialize( CAM_Application* app )
303 {
304   LightApp_Module::initialize( app );
305
306   // Uncomment to debug ParaView initialization
307   // "aa" used instead of "i" as GDB doesn't like "i" variables :)
308   /*
309   int aa = 1;
310   while( aa ){
311     aa = aa;
312   }
313   */
314   
315   // Initialize ParaView client
316   pvInit();
317
318   // Create GUI elements (menus, toolbars, dock widgets)
319   if ( !Implementation ){
320     LightApp_Application* anApp = getApp();
321
322     // Simulate ParaView client main window
323     Implementation = new pqImplementation( anApp->desktop() );
324
325     setupDockWidgets();
326     
327     pvCreateActions();
328     pvCreateMenus();
329     pvCreateToolBars();
330     
331     setupDockWidgetsContextMenu();
332
333     // Now that we're ready, initialize everything ...
334     Implementation->Core.initializeStates();
335   }
336 }
337
338 /*!
339   \brief Get list of compliant dockable GUI elements
340   \param m map to be filled in ("type":"default_position")
341 */
342 void PVGUI_Module::windows( QMap<int, int>& m ) const
343 {
344   m.insert( LightApp_Application::WT_ObjectBrowser, Qt::LeftDockWidgetArea );
345   m.insert( LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea );
346   // ParaView diagnostic output redirected here
347   m.insert( LightApp_Application::WT_LogWindow, Qt::BottomDockWidgetArea );
348 }
349
350 /*!
351   \brief Static method, performs initialization of ParaView session.
352   \return \c true if ParaView has been initialized successfully, otherwise false
353 */
354 bool PVGUI_Module::pvInit()
355 {
356   if ( !pqImplementation::myPVMain ){
357     // Obtain command-line arguments
358     int argc = 0;
359     QStringList args = QApplication::arguments();
360     char** argv = new char*[args.size()];
361     for ( QStringList::const_iterator it = args.begin(); argc < 1 && it != args.end(); it++, argc++ )
362       argv[argc] = strdup( (*it).toLatin1().constData() );
363
364     vtkPVMain::SetInitializeMPI(0);  // pvClient never runs with MPI.
365     vtkPVMain::Initialize(&argc, &argv); // Perform any initializations.
366
367     // TODO: Set plugin dir from preferences
368     //QApplication::setLibraryPaths(QStringList(dir.absolutePath()));
369
370     pqImplementation::myPVMain = vtkPVMain::New();
371     if ( !pqImplementation::myPVOptions )
372       pqImplementation::myPVOptions = pqOptions::New();
373     if ( !pqImplementation::myPVHelper )
374       pqImplementation::myPVHelper = PVGUI_ProcessModuleHelper::New();
375
376     pqImplementation::myPVOptions->SetProcessType(vtkPVOptions::PVCLIENT);
377
378     // This creates the Process Module and initializes it.
379     int ret = pqImplementation::myPVMain->Initialize(pqImplementation::myPVOptions, 
380                                                      pqImplementation::myPVHelper, 
381                                                      ParaViewInitializeInterpreter,
382                                                      argc, argv);
383     if (!ret){
384       // Tell process module that we support Multiple connections.
385       // This must be set before starting the event loop.
386       vtkProcessModule::GetProcessModule()->SupportMultipleConnectionsOn();
387       ret = pqImplementation::myPVHelper->Run(pqImplementation::myPVOptions);
388     }
389
390     delete[] argv;
391     return !ret;
392   }
393   
394   return true;
395 }
396  
397 /*!
398   \brief Static method, cleans up ParaView session at application exit. Not yet implemented.
399 */
400 void PVGUI_Module::pvShutdown()
401 {
402   // TODO...
403 }  
404
405 /*!
406   \brief Shows (toShow = true) or hides ParaView view window
407 */
408 void PVGUI_Module::showView( bool toShow )
409 {
410   LightApp_Application* anApp = getApp();
411   PVGUI_ViewManager* viewMgr = dynamic_cast<PVGUI_ViewManager*>( anApp->getViewManager( PVGUI_Viewer::Type(), false ) );
412   if ( !viewMgr ) {
413     viewMgr = new PVGUI_ViewManager( anApp->activeStudy(), anApp->desktop() );
414     anApp->addViewManager( viewMgr );
415     connect( viewMgr, SIGNAL( lastViewClosed( SUIT_ViewManager* ) ),
416              anApp, SLOT( onCloseView( SUIT_ViewManager* ) ) );
417   }
418
419   PVGUI_ViewWindow* pvWnd = dynamic_cast<PVGUI_ViewWindow*>( viewMgr->getActiveView() );
420   if ( !pvWnd ) {
421     pvWnd = dynamic_cast<PVGUI_ViewWindow*>( viewMgr->createViewWindow() );
422     pvWnd->setMultiViewManager( &Implementation->Core.multiViewManager() );
423   }
424
425   pvWnd->setShown( toShow );
426 }
427
428 /*!
429   \brief Manage the label of Undo operation.
430 */
431 void PVGUI_Module::onUndoLabel( const QString& label )
432 {
433   action(UndoId)->setText(
434     label.isEmpty() ? tr("MEN_CANTUNDO") : QString(tr("MEN_UNDO_ACTION")).arg(label));
435   action(UndoId)->setStatusTip(
436     label.isEmpty() ? tr("MEN_CANTUNDO") : QString(tr("MEN_UNDO_ACTION_TIP")).arg(label));
437 }
438
439 /*!
440   \brief Manage the label of Redo operation.
441 */
442 void PVGUI_Module::onRedoLabel( const QString& label )
443 {
444   action(RedoId)->setText(
445     label.isEmpty() ? tr("MEN_CANTREDO") : QString(tr("MEN_REDO_ACTION")).arg(label));
446   action(RedoId)->setStatusTip(
447     label.isEmpty() ? tr("MEN_CANTREDO") : QString(tr("MEN_REDO_ACTION_TIP")).arg(label));
448 }
449
450 /*!
451   \brief Manage the label of Undo Camera operation.
452 */
453 void PVGUI_Module::onCameraUndoLabel( const QString& label )
454 {
455   action(CameraUndoId)->setText(
456     label.isEmpty() ? tr("MEN_CANT_CAMERA_UNDO") : QString(tr("MEN_CAMERA_UNDO_ACTION")).arg(label));
457   action(CameraUndoId)->setStatusTip(
458     label.isEmpty() ? tr("MEN_CANT_CAMERA_UNDO") : QString(tr("MEN_CAMERA_UNDO_ACTION_TIP")).arg(label));
459 }
460
461 /*!
462   \brief Manage the label of Redo Camera operation.
463 */
464 void PVGUI_Module::onCameraRedoLabel( const QString& label )
465 {
466   action(CameraRedoId)->setText(
467     label.isEmpty() ? tr("MEN_CANT_CAMERA_REDO") : QString(tr("MEN_CAMERA_REDO_ACTION")).arg(label));
468   action(CameraRedoId)->setStatusTip(
469     label.isEmpty() ? tr("MEN_CANT_CAMERA_REDO") : QString(tr("MEN_CAMERA_REDO_ACTION_TIP")).arg(label));
470 }
471
472 /*!
473   \brief Slot to delete all objects.
474 */
475 void PVGUI_Module::onDeleteAll()
476 {
477   pqObjectBuilder* builder = pqApplicationCore::instance()->getObjectBuilder();
478   Implementation->Core.getApplicationUndoStack()->beginUndoSet("Delete All");
479   builder->destroyPipelineProxies();
480   Implementation->Core.getApplicationUndoStack()->endUndoSet();
481 }
482
483 /*!
484   \brief Slot to check/uncheck the action for corresponding selection mode.
485 */
486 void PVGUI_Module::onSelectionModeChanged( int mode )
487 {
488   if( toolMgr()->toolBar( mySelectionControlsTb )->isEnabled() ) {
489     if(mode == pqRubberBandHelper::SELECT) //surface selection
490       action(SelectCellsOnId)->setChecked(true);
491     else if(mode == pqRubberBandHelper::SELECT_POINTS) //surface selection
492       action(SelectPointsOnId)->setChecked(true);
493     else if(mode == pqRubberBandHelper::FRUSTUM)
494       action(SelectCellsThroughId)->setChecked(true);
495     else if(mode == pqRubberBandHelper::FRUSTUM_POINTS)
496       action(SelectPointsThroughId)->setChecked(true);
497     else if (mode == pqRubberBandHelper::BLOCKS)
498       action(SelectBlockId)->setChecked(true);
499     else // INTERACT
500       action(InteractId)->setChecked(true);
501   }
502 }
503
504 /*!
505   \brief Slot to manage the change of axis center.
506 */
507 void PVGUI_Module::onShowCenterAxisChanged( bool enabled )
508 {
509   action(ShowCenterId)->setEnabled(enabled);
510   action(ShowCenterId)->blockSignals(true);
511   pqRenderView* renView = qobject_cast<pqRenderView*>(
512     pqActiveView::instance().current());
513   action(ShowCenterId)->setChecked( renView ? renView->getCenterAxesVisibility() : false);
514   action(ShowCenterId)->blockSignals(false);
515 }
516
517 /*!
518   \brief Slot to set tooltips for the first anf the last frames, i.e. a time range of animation.
519 */
520 void PVGUI_Module::setTimeRanges( double start, double end )
521 {
522   action(FirstFrameId)->setToolTip(QString("First Frame (%1)").arg(start, 0, 'g'));
523   action(LastFrameId)->setToolTip(QString("Last Frame (%1)").arg(end, 0, 'g'));
524 }
525
526 /*!
527   \brief Slot to manage the plaing process of animation.
528 */
529 void PVGUI_Module::onPlaying( bool playing )
530 {
531   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
532   if(playing) {
533     disconnect( action(PlayId),                        SIGNAL( triggered() ),
534                 &Implementation->Core.VCRController(), SLOT( onPlay() ) );
535     connect( action(PlayId),                        SIGNAL( triggered() ),
536              &Implementation->Core.VCRController(), SLOT( onPause() ) );
537     action(PlayId)->setIcon(QIcon(resMgr->loadPixmap("ParaView",tr("ICON_PAUSE"),false)));
538     action(PlayId)->setText("Pa&use");
539   }
540   else {
541     connect( action(PlayId),                        SIGNAL( triggered() ),
542              &Implementation->Core.VCRController(), SLOT( onPlay() ) );
543     disconnect( action(PlayId),                        SIGNAL( triggered() ),
544                 &Implementation->Core.VCRController(), SLOT( onPause() ) );
545     action(PlayId)->setIcon(QIcon(resMgr->loadPixmap("ParaView",tr("ICON_PLAY"),false)));
546     action(PlayId)->setText("&Play");
547   }
548
549   Implementation->Core.setSelectiveEnabledState(!playing);
550 }
551
552 /*!
553   \brief Slot to add camera link.
554 */
555 void PVGUI_Module::onAddCameraLink()
556 {
557   pqView* vm = pqActiveView::instance().current();
558   pqRenderView* rm = qobject_cast<pqRenderView*>(vm);
559   if(rm) rm->linkToOtherView();
560   else SUIT_MessageBox::warning(getApp()->desktop(),
561                                 tr("WARNING"), tr("WRN_ADD_CAMERA_LINK"));
562 }
563
564 /*!
565   \brief Slot to show information about ParaView.
566 */
567 void PVGUI_Module::onHelpAbout()
568 {
569   pqClientAboutDialog* const dialog = new pqClientAboutDialog(getApp()->desktop());
570   dialog->setAttribute(Qt::WA_DeleteOnClose);
571   dialog->show();
572 }
573
574 /*!
575   \brief Slot to show help for proxy.
576 */
577 void PVGUI_Module::showHelpForProxy( const QString& proxy )
578 {
579   // make sure assistant is ready
580   this->makeAssistant();
581
582   if(this->Implementation->AssistantClient) {
583     this->Implementation->AssistantClient->openAssistant();
584     QString page("%1/Documentation/%2.html");
585     page = page.arg(this->Implementation->DocumentationDir);
586     page = page.arg(proxy);
587     this->Implementation->AssistantClient->showPage(page);
588   }
589 }
590
591 QString Locate( const QString& appName )
592 {
593   QString app_dir = QCoreApplication::applicationDirPath();
594   const char* inst_dirs[] = {
595     "/./",
596     "/../bin/",
597     "/../../bin/",
598     0
599   };
600   for (const char** dir = inst_dirs; *dir; ++dir) {
601     QString path = app_dir;
602     path += *dir;
603     path += appName;
604     //cout << "Checking : " << path.toAscii().data() << " ... ";
605     //cout.flush();
606     QFileInfo finfo (path);
607     if (finfo.exists()) {
608       //cout << " Success!" << endl;
609       return path;
610     }
611     //cout << " Failed" << endl;
612   }
613   return app_dir + QDir::separator() + appName;
614 }
615
616 /*!
617   \brief Initialized an assistant client.
618 */
619 void PVGUI_Module::makeAssistant()
620 {
621   if(this->Implementation->AssistantClient)
622     return;
623   
624   QString assistantExe;
625   QString profileFile;
626   
627   const char* assistantName = "assistant";
628 #ifdef WNT
629   const char* binDir = "\\";
630   const char* binDir1 = "\\..\\";
631 #else
632   const char* binDir = "/bin/";
633   const char* binDir1 = "/bin/bin/";
634 #endif
635
636   QString helper = QString(getenv("PVHOME")) + binDir + QString("pqClientDocFinder.txt");
637   if(!QFile::exists(helper))
638     helper = QString(getenv("PVHOME")) + binDir1 + QString("pqClientDocFinder.txt");
639   if(QFile::exists(helper)) {
640     QFile file(helper);
641     if(file.open(QIODevice::ReadOnly)) {
642       assistantExe = file.readLine().trimmed();
643       profileFile = file.readLine().trimmed();
644       // CMake escapes spaces, we need to unescape those.
645       assistantExe.replace("\\ ", " ");
646       profileFile.replace("\\ ", " ");
647     }
648   }
649
650   if(assistantExe.isEmpty()) {
651     assistantExe = ::Locate(assistantName);//assistantExe = ::Locate(assistantProgName);
652     /*
653     QString assistant = QCoreApplication::applicationDirPath();
654     assistant += QDir::separator();
655     assistant += assistantName;
656     assistantExe = assistant;
657     */
658   }
659
660   this->Implementation->AssistantClient = new QAssistantClient(assistantExe, this);
661   QObject::connect(this->Implementation->AssistantClient, SIGNAL(error(const QString&)),
662                    this,                                  SLOT(assistantError(const QString&)));
663
664   QStringList args;
665   args.append(QString("-profile"));
666
667   if(profileFile.isEmpty()) {
668     // see if help is bundled up with the application
669     QString profile = ::Locate("pqClient.adp");
670     /*QCoreApplication::applicationDirPath() + QDir::separator()
671       + QString("pqClient.adp");*/
672     
673     if(QFile::exists(profile))
674       profileFile = profile;
675   }
676
677   if(profileFile.isEmpty() && getenv("PARAVIEW_HELP")) {
678     // not bundled, ask for help
679     args.append(getenv("PARAVIEW_HELP"));
680   }
681   else if(profileFile.isEmpty()) {
682     // no help, error out
683     SUIT_MessageBox::critical(getApp()->desktop(),"Help error", "Couldn't find"
684                               " pqClient.adp.\nTry setting the PARAVIEW_HELP environment variable which"
685                               " points to that file");
686     delete this->Implementation->AssistantClient;
687     return;
688   }
689
690   QFileInfo fi(profileFile);
691   this->Implementation->DocumentationDir = fi.absolutePath();
692
693   args.append(profileFile);
694
695   this->Implementation->AssistantClient->setArguments(args);
696 }
697
698 /*!
699   \brief Slot to call the message handler with the critical message.
700 */
701 void PVGUI_Module::assistantError( const QString& error )
702 {
703   qCritical(error.toAscii().data());
704 }
705
706 /*!
707   \brief Slot to show the waiting state.
708 */
709 void PVGUI_Module::onPreAccept()
710 {
711   getApp()->desktop()->statusBar()->showMessage(tr("STB_PREACCEPT"));
712   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
713 }
714
715 /*!
716   \brief Slot to show the ready state.
717 */
718 void PVGUI_Module::onPostAccept()
719 {
720   getApp()->desktop()->statusBar()->showMessage(tr("STB_POSTACCEPT"), 2000);
721   QTimer::singleShot(0, this, SLOT(endWaitCursor()));
722 }
723
724 /*!
725   \brief Slot to switch off wait cursor.
726 */
727 void PVGUI_Module::endWaitCursor()
728 {
729   QApplication::restoreOverrideCursor();
730 }
731
732 /*!
733   \brief Returns the ParaView multi-view manager.
734 */
735 pqViewManager* PVGUI_Module::getMultiViewManager() const
736 {
737   pqViewManager* aMVM = 0; 
738   if ( Implementation )
739     aMVM = &Implementation->Core.multiViewManager();
740   return aMVM;
741 }
742
743 /*!
744   \brief Processes QEvent::ActionAdded and QEvent::ActionRemoved from Lookmarks toolbar
745   in order to register/unregister this action in/from QtxActionToolMgr.
746 */
747 bool PVGUI_Module::eventFilter( QObject* theObject, QEvent* theEvent )
748 {
749   QToolBar* aTB = toolMgr()->toolBar(tr("TOOL_LOOKMARKS"));
750   if ( theObject == aTB ) {
751     
752     if ( theEvent->type() == QEvent::ActionAdded ) {
753       QList<QAction*> anActns = aTB->actions();
754       for (int i = 0; i < anActns.size(); ++i)
755         if ( toolMgr()->actionId(anActns.at(i)) == -1 ) {
756           toolMgr()->setUpdatesEnabled(false);
757           createTool( anActns.at(i), tr("TOOL_LOOKMARKS") );
758           toolMgr()->setUpdatesEnabled(true);
759         }
760     }
761
762     if ( theEvent->type() == QEvent::ActionRemoved ) {
763       QList<QAction*> anActns = aTB->actions();
764       QIntList aIDL = toolMgr()->idList();
765       for (int i = 0; i < aIDL.size(); ++i) {
766         if ( toolMgr()->action(aIDL.at(i))->parent() == aTB
767              &&
768              !anActns.contains( toolMgr()->action(aIDL.at(i)) ) ) {
769           toolMgr()->setUpdatesEnabled(false);
770           toolMgr()->unRegisterAction( aIDL.at(i) );
771           toolMgr()->remove( aIDL.at(i), tr("TOOL_LOOKMARKS") );
772           toolMgr()->setUpdatesEnabled(true);
773         }
774       }
775     }
776     
777   }
778
779   return QObject::eventFilter( theObject, theEvent );
780 }
781
782 /*!
783   \brief Activate module.
784   \param study current study
785   \return \c true if activaion is done successfully or 0 to prevent
786   activation on error
787 */
788 bool PVGUI_Module::activateModule( SUIT_Study* study )
789 {
790   bool isDone = LightApp_Module::activateModule( study );
791   if ( !isDone ) return false;
792
793   showView( true );
794
795   if ( mySourcesMenuId != -1 ) menuMgr()->show(mySourcesMenuId);
796   if ( myFiltersMenuId != -1 ) menuMgr()->show(myFiltersMenuId);
797   setMenuShown( true );
798   setToolShown( true );
799
800   toolMgr()->toolBar(tr("TOOL_LOOKMARKS"))->installEventFilter(this);
801
802   // Make default server connection
803   if ( Implementation )
804     Implementation->Core.makeDefaultConnectionIfNoneExists();
805
806   restoreDockWidgetsState();
807
808   return isDone;
809 }
810
811
812 /*!
813   \brief Deactivate module.
814   \param study current study
815   \return \c true if deactivaion is done successfully or 0 to prevent
816   deactivation on error
817 */
818 bool PVGUI_Module::deactivateModule( SUIT_Study* study )
819 {
820   toolMgr()->toolBar(tr("TOOL_LOOKMARKS"))->removeEventFilter(this);
821
822   showView( false );
823
824   // hide menus
825   menuMgr()->hide(mySourcesMenuId);
826   menuMgr()->hide(myFiltersMenuId);
827   setMenuShown( false );
828   setToolShown( false );
829
830   saveDockWidgetsState();
831
832   return LightApp_Module::deactivateModule( study );
833 }
834
835 /*!
836   \brief Compares the contents of the window with the given reference image,
837   returns true if they "match" within some tolerance.
838 */
839 bool PVGUI_Module::compareView( const QString& ReferenceImage, double Threshold,
840                                 ostream& Output, const QString& TempDirectory )
841 {
842   if ( Implementation )
843     return Implementation->Core.compareView( ReferenceImage, Threshold, Output, TempDirectory );
844   return false;
845 }
846
847 /*!
848   \fn CAM_Module* createModule();
849   \brief Export module instance (factory function).
850   \return new created instance of the module
851 */
852
853 #ifdef WNT
854 #define PVGUI_EXPORT __declspec(dllexport)
855 #else   // WNT
856 #define PVGUI_EXPORT
857 #endif  // WNT
858
859 extern "C" {
860   PVGUI_EXPORT CAM_Module* createModule() {
861     return new PVGUI_Module();
862   }
863 }