]> SALOME platform Git repositories - modules/paravis.git/blob - src/PVGUI/PVGUI_Module.cxx
Salome HOME
Minor changes
[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   ParaView GUI resources (icons) are reused directly from the ParaView resource directory, they are loaded into SALOME GUI 
219   resource manager, the path to these icons is specified in PARAVIS configuration XML files (LightApp.xml and SlomeApp.xml).
220
221   As both SALOME destop and ParaView main window classes inherit QMainWindow and %pqMainWindowCore deals with QMainWindow API to control
222   menus, tollbars and dock widgets, its integration into SALOME GUI is straightforward and smooth.
223
224   <h3>Multi-view manager</h3>
225
226   SALOME GUI requires that each kind of view be implemnted with help of (at least) three classes. For ParaView multi-view manager 
227   these are:
228
229   \li PVGUI_ViewManager - view manager class
230   \li PVGUI_Viewer      - view model class
231   \li PVGUI_ViewWindow  - view window class that acts as a parent for %pqViewManager
232
233   Single instances of PVGUI_ViewManager and PVGUI_ViewWindow classes are created by \link PVGUI_Module::showView() 
234   PVGUI_Module::showView()\endlink method upon the first PARAVIS module activation. The same method hides the multi-view manager 
235   when the module is deactivated (the user switches to another module or a study is closed). 
236   A special trick is used to make PVGUI_ViewWindow the parent of %pqViewManager widget. It is created initally by %pqMainWindowCore
237   with the desktop as a parent, so when it is shown PVGUI_ViewWindow instance is passed to its setParent() method. In  
238   \link PVGUI_ViewWindow::~PVGUI_ViewWindow() PVGUI_ViewWindow::~PVGUI_ViewWindow()\endlink the parent is nullified to avoid deletion
239   of %pqViewManager widget that would break %pqMainWindowCore class.
240
241   <h3>ParaView plugins</h3>
242   ParaView server and client plugins are managed by %pqMainWindowCore slots that has full access to PARAVIS menus and toolbars. 
243   As a result they appears automatically in PARAVIS menus and toolbars if loaded successfully.
244
245   <h2>Limitations of 2008 year prototype</h2>
246   \li SALOME persistence (possibility to save the module data into a tsudy file) is not implemented for PARAVIS module.
247   \li As a light module, PARAVIS does not have a CORBA engine that follows SALOME rules, however PARAVIS can use load a CORBA engine 
248   on its own if needed.
249 */
250
251 /*!
252   \class PVGUI_Module
253   \brief Implementation of light (no-CORBA-engine) 
254          SALOME module wrapping ParaView GUI.
255 */
256
257 /*!
258   \brief Constructor. Sets the default name for the module.
259 */
260 PVGUI_Module::PVGUI_Module()
261   : LightApp_Module( "PARAVIS" ),
262     Implementation( 0 ),
263     mySelectionControlsTb( -1 ),
264     mySourcesMenuId( -1 ),
265     myFiltersMenuId( -1 )
266 {
267 }
268
269 /*!
270   \brief Destructor.
271 */
272 PVGUI_Module::~PVGUI_Module()
273 {
274 }
275
276 /*!
277   \brief Initialize module. Creates menus, prepares context menu, etc.
278   \param app SALOME GUI application instance
279 */
280 void PVGUI_Module::initialize( CAM_Application* app )
281 {
282   LightApp_Module::initialize( app );
283
284   // Uncomment to debug ParaView initialization
285   // "aa" used instead of "i" as GDB doesn't like "i" variables :)
286   /*
287   int aa = 1;
288   while( aa ){
289     aa = aa;
290   }
291   */
292   
293   // Initialize ParaView client
294   pvInit();
295
296   // Create GUI elements (menus, toolbars, dock widgets)
297   if ( !Implementation ){
298     LightApp_Application* anApp = getApp();
299
300     // Simulate ParaView client main window
301     Implementation = new pqImplementation( anApp->desktop() );
302
303     setupDockWidgets();
304     
305     pvCreateActions();
306     pvCreateMenus();
307     pvCreateToolBars();
308     
309     setupDockWidgetsContextMenu();
310
311     // Now that we're ready, initialize everything ...
312     Implementation->Core.initializeStates();
313   }
314 }
315
316 /*!
317   \brief Get list of compliant dockable GUI elements
318   \param m map to be filled in ("type":"default_position")
319 */
320 void PVGUI_Module::windows( QMap<int, int>& m ) const
321 {
322   m.insert( LightApp_Application::WT_ObjectBrowser, Qt::LeftDockWidgetArea );
323   m.insert( LightApp_Application::WT_PyConsole, Qt::BottomDockWidgetArea );
324   // ParaView diagnostic output redirected here
325   m.insert( LightApp_Application::WT_LogWindow, Qt::BottomDockWidgetArea );
326 }
327
328 /*!
329   \brief Static method, performs initialization of ParaView session.
330   \return \c true if ParaView has been initialized successfully, otherwise false
331 */
332 bool PVGUI_Module::pvInit()
333 {
334   if ( !pqImplementation::myPVMain ){
335     // Obtain command-line arguments
336     int argc = 0;
337     QStringList args = QApplication::arguments();
338     char** argv = new char*[args.size()];
339     for ( QStringList::const_iterator it = args.begin(); argc < 1 && it != args.end(); it++, argc++ )
340       argv[argc] = strdup( (*it).toLatin1().constData() );
341
342     vtkPVMain::SetInitializeMPI(0);  // pvClient never runs with MPI.
343     vtkPVMain::Initialize(&argc, &argv); // Perform any initializations.
344
345     // TODO: Set plugin dir from preferences
346     //QApplication::setLibraryPaths(QStringList(dir.absolutePath()));
347
348     pqImplementation::myPVMain = vtkPVMain::New();
349     if ( !pqImplementation::myPVOptions )
350       pqImplementation::myPVOptions = pqOptions::New();
351     if ( !pqImplementation::myPVHelper )
352       pqImplementation::myPVHelper = PVGUI_ProcessModuleHelper::New();
353
354     pqImplementation::myPVOptions->SetProcessType(vtkPVOptions::PVCLIENT);
355
356     // This creates the Process Module and initializes it.
357     int ret = pqImplementation::myPVMain->Initialize(pqImplementation::myPVOptions, 
358                                                      pqImplementation::myPVHelper, 
359                                                      ParaViewInitializeInterpreter,
360                                                      argc, argv);
361     if (!ret){
362       // Tell process module that we support Multiple connections.
363       // This must be set before starting the event loop.
364       vtkProcessModule::GetProcessModule()->SupportMultipleConnectionsOn();
365       ret = pqImplementation::myPVHelper->Run(pqImplementation::myPVOptions);
366     }
367
368     delete[] argv;
369     return !ret;
370   }
371   
372   return true;
373 }
374  
375 /*!
376   \brief Static method, cleans up ParaView session at application exit. Not yet implemented.
377 */
378 void PVGUI_Module::pvShutdown()
379 {
380   // TODO...
381 }  
382
383 /*!
384   \brief Shows (toShow = true) or hides ParaView view window
385 */
386 void PVGUI_Module::showView( bool toShow )
387 {
388   LightApp_Application* anApp = getApp();
389   PVGUI_ViewManager* viewMgr = dynamic_cast<PVGUI_ViewManager*>( anApp->getViewManager( PVGUI_Viewer::Type(), false ) );
390   if ( !viewMgr ) {
391     viewMgr = new PVGUI_ViewManager( anApp->activeStudy(), anApp->desktop() );
392     anApp->addViewManager( viewMgr );
393     connect( viewMgr, SIGNAL( lastViewClosed( SUIT_ViewManager* ) ),
394              anApp, SLOT( onCloseView( SUIT_ViewManager* ) ) );
395   }
396
397   PVGUI_ViewWindow* pvWnd = dynamic_cast<PVGUI_ViewWindow*>( viewMgr->getActiveView() );
398   if ( !pvWnd ) {
399     pvWnd = dynamic_cast<PVGUI_ViewWindow*>( viewMgr->createViewWindow() );
400     pvWnd->setMultiViewManager( &Implementation->Core.multiViewManager() );
401   }
402
403   pvWnd->setShown( toShow );
404 }
405
406 /*!
407   \brief Manage the label of Undo operation.
408 */
409 void PVGUI_Module::onUndoLabel( const QString& label )
410 {
411   action(UndoId)->setText(
412     label.isEmpty() ? tr("MEN_CANTUNDO") : QString(tr("MEN_UNDO_ACTION")).arg(label));
413   action(UndoId)->setStatusTip(
414     label.isEmpty() ? tr("MEN_CANTUNDO") : QString(tr("MEN_UNDO_ACTION_TIP")).arg(label));
415 }
416
417 /*!
418   \brief Manage the label of Redo operation.
419 */
420 void PVGUI_Module::onRedoLabel( const QString& label )
421 {
422   action(RedoId)->setText(
423     label.isEmpty() ? tr("MEN_CANTREDO") : QString(tr("MEN_REDO_ACTION")).arg(label));
424   action(RedoId)->setStatusTip(
425     label.isEmpty() ? tr("MEN_CANTREDO") : QString(tr("MEN_REDO_ACTION_TIP")).arg(label));
426 }
427
428 /*!
429   \brief Manage the label of Undo Camera operation.
430 */
431 void PVGUI_Module::onCameraUndoLabel( const QString& label )
432 {
433   action(CameraUndoId)->setText(
434     label.isEmpty() ? tr("MEN_CANT_CAMERA_UNDO") : QString(tr("MEN_CAMERA_UNDO_ACTION")).arg(label));
435   action(CameraUndoId)->setStatusTip(
436     label.isEmpty() ? tr("MEN_CANT_CAMERA_UNDO") : QString(tr("MEN_CAMERA_UNDO_ACTION_TIP")).arg(label));
437 }
438
439 /*!
440   \brief Manage the label of Redo Camera operation.
441 */
442 void PVGUI_Module::onCameraRedoLabel( const QString& label )
443 {
444   action(CameraRedoId)->setText(
445     label.isEmpty() ? tr("MEN_CANT_CAMERA_REDO") : QString(tr("MEN_CAMERA_REDO_ACTION")).arg(label));
446   action(CameraRedoId)->setStatusTip(
447     label.isEmpty() ? tr("MEN_CANT_CAMERA_REDO") : QString(tr("MEN_CAMERA_REDO_ACTION_TIP")).arg(label));
448 }
449
450 /*!
451   \brief Slot to delete all objects.
452 */
453 void PVGUI_Module::onDeleteAll()
454 {
455   pqObjectBuilder* builder = pqApplicationCore::instance()->getObjectBuilder();
456   Implementation->Core.getApplicationUndoStack()->beginUndoSet("Delete All");
457   builder->destroyPipelineProxies();
458   Implementation->Core.getApplicationUndoStack()->endUndoSet();
459 }
460
461 /*!
462   \brief Slot to check/uncheck the action for corresponding selection mode.
463 */
464 void PVGUI_Module::onSelectionModeChanged( int mode )
465 {
466   if( toolMgr()->toolBar( mySelectionControlsTb )->isEnabled() ) {
467     if(mode == pqRubberBandHelper::SELECT) //surface selection
468       action(SelectCellsOnId)->setChecked(true);
469     else if(mode == pqRubberBandHelper::SELECT_POINTS) //surface selection
470       action(SelectPointsOnId)->setChecked(true);
471     else if(mode == pqRubberBandHelper::FRUSTUM)
472       action(SelectCellsThroughId)->setChecked(true);
473     else if(mode == pqRubberBandHelper::FRUSTUM_POINTS)
474       action(SelectPointsThroughId)->setChecked(true);
475     else if (mode == pqRubberBandHelper::BLOCKS)
476       action(SelectBlockId)->setChecked(true);
477     else // INTERACT
478       action(InteractId)->setChecked(true);
479   }
480 }
481
482 /*!
483   \brief Slot to manage the change of axis center.
484 */
485 void PVGUI_Module::onShowCenterAxisChanged( bool enabled )
486 {
487   action(ShowCenterId)->setEnabled(enabled);
488   action(ShowCenterId)->blockSignals(true);
489   pqRenderView* renView = qobject_cast<pqRenderView*>(
490     pqActiveView::instance().current());
491   action(ShowCenterId)->setChecked( renView ? renView->getCenterAxesVisibility() : false);
492   action(ShowCenterId)->blockSignals(false);
493 }
494
495 /*!
496   \brief Slot to set tooltips for the first anf the last frames, i.e. a time range of animation.
497 */
498 void PVGUI_Module::setTimeRanges( double start, double end )
499 {
500   action(FirstFrameId)->setToolTip(QString("First Frame (%1)").arg(start, 0, 'g'));
501   action(LastFrameId)->setToolTip(QString("Last Frame (%1)").arg(end, 0, 'g'));
502 }
503
504 /*!
505   \brief Slot to manage the plaing process of animation.
506 */
507 void PVGUI_Module::onPlaying( bool playing )
508 {
509   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
510   if(playing) {
511     disconnect( action(PlayId),                        SIGNAL( triggered() ),
512                 &Implementation->Core.VCRController(), SLOT( onPlay() ) );
513     connect( action(PlayId),                        SIGNAL( triggered() ),
514              &Implementation->Core.VCRController(), SLOT( onPause() ) );
515     action(PlayId)->setIcon(QIcon(resMgr->loadPixmap("ParaView",tr("ICON_PAUSE"),false)));
516     action(PlayId)->setText("Pa&use");
517   }
518   else {
519     connect( action(PlayId),                        SIGNAL( triggered() ),
520              &Implementation->Core.VCRController(), SLOT( onPlay() ) );
521     disconnect( action(PlayId),                        SIGNAL( triggered() ),
522                 &Implementation->Core.VCRController(), SLOT( onPause() ) );
523     action(PlayId)->setIcon(QIcon(resMgr->loadPixmap("ParaView",tr("ICON_PLAY"),false)));
524     action(PlayId)->setText("&Play");
525   }
526
527   Implementation->Core.setSelectiveEnabledState(!playing);
528 }
529
530 /*!
531   \brief Slot to add camera link.
532 */
533 void PVGUI_Module::onAddCameraLink()
534 {
535   pqView* vm = pqActiveView::instance().current();
536   pqRenderView* rm = qobject_cast<pqRenderView*>(vm);
537   if(rm) rm->linkToOtherView();
538   else SUIT_MessageBox::warning(getApp()->desktop(),
539                                 tr("WARNING"), tr("WRN_ADD_CAMERA_LINK"));
540 }
541
542 /*!
543   \brief Slot to show information about ParaView.
544 */
545 void PVGUI_Module::onHelpAbout()
546 {
547   pqClientAboutDialog* const dialog = new pqClientAboutDialog(getApp()->desktop());
548   dialog->setAttribute(Qt::WA_DeleteOnClose);
549   dialog->show();
550 }
551
552 /*!
553   \brief Slot to show help for proxy.
554 */
555 void PVGUI_Module::showHelpForProxy( const QString& proxy )
556 {
557   // make sure assistant is ready
558   this->makeAssistant();
559
560   if(this->Implementation->AssistantClient) {
561     this->Implementation->AssistantClient->openAssistant();
562     QString page("%1/Documentation/%2.html");
563     page = page.arg(this->Implementation->DocumentationDir);
564     page = page.arg(proxy);
565     this->Implementation->AssistantClient->showPage(page);
566   }
567 }
568
569 QString Locate( const QString& appName )
570 {
571   QString app_dir = QCoreApplication::applicationDirPath();
572   const char* inst_dirs[] = {
573     "/./",
574     "/../bin/",
575     "/../../bin/",
576     0
577   };
578   for (const char** dir = inst_dirs; *dir; ++dir) {
579     QString path = app_dir;
580     path += *dir;
581     path += appName;
582     //cout << "Checking : " << path.toAscii().data() << " ... ";
583     //cout.flush();
584     QFileInfo finfo (path);
585     if (finfo.exists()) {
586       //cout << " Success!" << endl;
587       return path;
588     }
589     //cout << " Failed" << endl;
590   }
591   return app_dir + QDir::separator() + appName;
592 }
593
594 /*!
595   \brief Initialized an assistant client.
596 */
597 void PVGUI_Module::makeAssistant()
598 {
599   if(this->Implementation->AssistantClient)
600     return;
601   
602   QString assistantExe;
603   QString profileFile;
604   
605   const char* assistantName = "assistant";
606 #ifdef WNT
607   const char* binDir = "\\";
608   const char* binDir1 = "\\..\\";
609 #else
610   const char* binDir = "/bin/";
611   const char* binDir1 = "/bin/bin/";
612 #endif
613
614   QString helper = QString(getenv("PVHOME")) + binDir + QString("pqClientDocFinder.txt");
615   if(!QFile::exists(helper))
616     helper = QString(getenv("PVHOME")) + binDir1 + QString("pqClientDocFinder.txt");
617   if(QFile::exists(helper)) {
618     QFile file(helper);
619     if(file.open(QIODevice::ReadOnly)) {
620       assistantExe = file.readLine().trimmed();
621       profileFile = file.readLine().trimmed();
622       // CMake escapes spaces, we need to unescape those.
623       assistantExe.replace("\\ ", " ");
624       profileFile.replace("\\ ", " ");
625     }
626   }
627
628   if(assistantExe.isEmpty()) {
629     assistantExe = ::Locate(assistantName);//assistantExe = ::Locate(assistantProgName);
630     /*
631     QString assistant = QCoreApplication::applicationDirPath();
632     assistant += QDir::separator();
633     assistant += assistantName;
634     assistantExe = assistant;
635     */
636   }
637
638   this->Implementation->AssistantClient = new QAssistantClient(assistantExe, this);
639   QObject::connect(this->Implementation->AssistantClient, SIGNAL(error(const QString&)),
640                    this,                                  SLOT(assistantError(const QString&)));
641
642   QStringList args;
643   args.append(QString("-profile"));
644
645   if(profileFile.isEmpty()) {
646     // see if help is bundled up with the application
647     QString profile = ::Locate("pqClient.adp");
648     /*QCoreApplication::applicationDirPath() + QDir::separator()
649       + QString("pqClient.adp");*/
650     
651     if(QFile::exists(profile))
652       profileFile = profile;
653   }
654
655   if(profileFile.isEmpty() && getenv("PARAVIEW_HELP")) {
656     // not bundled, ask for help
657     args.append(getenv("PARAVIEW_HELP"));
658   }
659   else if(profileFile.isEmpty()) {
660     // no help, error out
661     SUIT_MessageBox::critical(getApp()->desktop(),"Help error", "Couldn't find"
662                               " pqClient.adp.\nTry setting the PARAVIEW_HELP environment variable which"
663                               " points to that file");
664     delete this->Implementation->AssistantClient;
665     return;
666   }
667
668   QFileInfo fi(profileFile);
669   this->Implementation->DocumentationDir = fi.absolutePath();
670
671   args.append(profileFile);
672
673   this->Implementation->AssistantClient->setArguments(args);
674 }
675
676 /*!
677   \brief Slot to call the message handler with the critical message.
678 */
679 void PVGUI_Module::assistantError( const QString& error )
680 {
681   qCritical(error.toAscii().data());
682 }
683
684 /*!
685   \brief Slot to show the waiting state.
686 */
687 void PVGUI_Module::onPreAccept()
688 {
689   getApp()->desktop()->statusBar()->showMessage(tr("STB_PREACCEPT"));
690   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
691 }
692
693 /*!
694   \brief Slot to show the ready state.
695 */
696 void PVGUI_Module::onPostAccept()
697 {
698   getApp()->desktop()->statusBar()->showMessage(tr("STB_POSTACCEPT"), 2000);
699   QTimer::singleShot(0, this, SLOT(endWaitCursor()));
700 }
701
702 /*!
703   \brief Slot to switch off wait cursor.
704 */
705 void PVGUI_Module::endWaitCursor()
706 {
707   QApplication::restoreOverrideCursor();
708 }
709
710 /*!
711   \brief Returns the ParaView multi-view manager.
712 */
713 pqViewManager* PVGUI_Module::getMultiViewManager() const
714 {
715   pqViewManager* aMVM = 0; 
716   if ( Implementation )
717     aMVM = &Implementation->Core.multiViewManager();
718   return aMVM;
719 }
720
721 /*!
722   \brief Processes QEvent::ActionAdded and QEvent::ActionRemoved from Lookmarks toolbar
723   in order to register/unregister this action in/from QtxActionToolMgr.
724 */
725 bool PVGUI_Module::eventFilter( QObject* theObject, QEvent* theEvent )
726 {
727   QToolBar* aTB = toolMgr()->toolBar(tr("TOOL_LOOKMARKS"));
728   if ( theObject == aTB ) {
729     
730     if ( theEvent->type() == QEvent::ActionAdded ) {
731       QList<QAction*> anActns = aTB->actions();
732       for (int i = 0; i < anActns.size(); ++i)
733         if ( toolMgr()->actionId(anActns.at(i)) == -1 ) {
734           toolMgr()->setUpdatesEnabled(false);
735           createTool( anActns.at(i), tr("TOOL_LOOKMARKS") );
736           toolMgr()->setUpdatesEnabled(true);
737         }
738     }
739
740     if ( theEvent->type() == QEvent::ActionRemoved ) {
741       QList<QAction*> anActns = aTB->actions();
742       QIntList aIDL = toolMgr()->idList();
743       for (int i = 0; i < aIDL.size(); ++i) {
744         if ( toolMgr()->action(aIDL.at(i))->parent() == aTB
745              &&
746              !anActns.contains( toolMgr()->action(aIDL.at(i)) ) ) {
747           toolMgr()->setUpdatesEnabled(false);
748           toolMgr()->unRegisterAction( aIDL.at(i) );
749           toolMgr()->remove( aIDL.at(i), tr("TOOL_LOOKMARKS") );
750           toolMgr()->setUpdatesEnabled(true);
751         }
752       }
753     }
754     
755   }
756
757   return QObject::eventFilter( theObject, theEvent );
758 }
759
760 /*!
761   \brief Activate module.
762   \param study current study
763   \return \c true if activaion is done successfully or 0 to prevent
764   activation on error
765 */
766 bool PVGUI_Module::activateModule( SUIT_Study* study )
767 {
768   bool isDone = LightApp_Module::activateModule( study );
769   if ( !isDone ) return false;
770
771   showView( true );
772
773   if ( mySourcesMenuId != -1 ) menuMgr()->show(mySourcesMenuId);
774   if ( myFiltersMenuId != -1 ) menuMgr()->show(myFiltersMenuId);
775   setMenuShown( true );
776   setToolShown( true );
777
778   toolMgr()->toolBar(tr("TOOL_LOOKMARKS"))->installEventFilter(this);
779
780   // Make default server connection
781   if ( Implementation )
782     Implementation->Core.makeDefaultConnectionIfNoneExists();
783
784   restoreDockWidgetsState();
785
786   return isDone;
787 }
788
789
790 /*!
791   \brief Deactivate module.
792   \param study current study
793   \return \c true if deactivaion is done successfully or 0 to prevent
794   deactivation on error
795 */
796 bool PVGUI_Module::deactivateModule( SUIT_Study* study )
797 {
798   toolMgr()->toolBar(tr("TOOL_LOOKMARKS"))->removeEventFilter(this);
799
800   showView( false );
801
802   // hide menus
803   menuMgr()->hide(mySourcesMenuId);
804   menuMgr()->hide(myFiltersMenuId);
805   setMenuShown( false );
806   setToolShown( false );
807
808   saveDockWidgetsState();
809
810   return LightApp_Module::deactivateModule( study );
811 }
812
813 /*!
814   \brief Compares the contents of the window with the given reference image,
815   returns true if they "match" within some tolerance.
816 */
817 bool PVGUI_Module::compareView( const QString& ReferenceImage, double Threshold,
818                                 ostream& Output, const QString& TempDirectory )
819 {
820   if ( Implementation )
821     return Implementation->Core.compareView( ReferenceImage, Threshold, Output, TempDirectory );
822   return false;
823 }
824
825 /*!
826   \fn CAM_Module* createModule();
827   \brief Export module instance (factory function).
828   \return new created instance of the module
829 */
830
831 #ifdef WNT
832 #define PVGUI_EXPORT __declspec(dllexport)
833 #else   // WNT
834 #define PVGUI_EXPORT
835 #endif  // WNT
836
837 extern "C" {
838   PVGUI_EXPORT CAM_Module* createModule() {
839     return new PVGUI_Module();
840   }
841 }