]> SALOME platform Git repositories - modules/paravis.git/blob - src/PVGUI/PVGUI_Module.cxx
Salome HOME
Corrections for
[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.
377 */
378 void PVGUI_Module::pvShutdown()
379 {
380   if ( pqImplementation::myPVHelper )
381     pqImplementation::myPVHelper->finalize();
382 }  
383
384 /*!
385   \brief Shows (toShow = true) or hides ParaView view window
386 */
387 void PVGUI_Module::showView( bool toShow )
388 {
389   LightApp_Application* anApp = getApp();
390   PVGUI_ViewManager* viewMgr = dynamic_cast<PVGUI_ViewManager*>( anApp->getViewManager( PVGUI_Viewer::Type(), false ) );
391   if ( !viewMgr ) {
392     viewMgr = new PVGUI_ViewManager( anApp->activeStudy(), anApp->desktop() );
393     anApp->addViewManager( viewMgr );
394     connect( viewMgr, SIGNAL( lastViewClosed( SUIT_ViewManager* ) ),
395              anApp, SLOT( onCloseView( SUIT_ViewManager* ) ) );
396   }
397
398   PVGUI_ViewWindow* pvWnd = dynamic_cast<PVGUI_ViewWindow*>( viewMgr->getActiveView() );
399   if ( !pvWnd ) {
400     pvWnd = dynamic_cast<PVGUI_ViewWindow*>( viewMgr->createViewWindow() );
401     pvWnd->setMultiViewManager( &Implementation->Core.multiViewManager() );
402   }
403
404   pvWnd->setShown( toShow );
405 }
406
407 /*!
408   \brief Manage the label of Undo operation.
409 */
410 void PVGUI_Module::onUndoLabel( const QString& label )
411 {
412   action(UndoId)->setText(
413     label.isEmpty() ? tr("MEN_CANTUNDO") : QString(tr("MEN_UNDO_ACTION")).arg(label));
414   action(UndoId)->setStatusTip(
415     label.isEmpty() ? tr("MEN_CANTUNDO") : QString(tr("MEN_UNDO_ACTION_TIP")).arg(label));
416 }
417
418 /*!
419   \brief Manage the label of Redo operation.
420 */
421 void PVGUI_Module::onRedoLabel( const QString& label )
422 {
423   action(RedoId)->setText(
424     label.isEmpty() ? tr("MEN_CANTREDO") : QString(tr("MEN_REDO_ACTION")).arg(label));
425   action(RedoId)->setStatusTip(
426     label.isEmpty() ? tr("MEN_CANTREDO") : QString(tr("MEN_REDO_ACTION_TIP")).arg(label));
427 }
428
429 /*!
430   \brief Manage the label of Undo Camera operation.
431 */
432 void PVGUI_Module::onCameraUndoLabel( const QString& label )
433 {
434   action(CameraUndoId)->setText(
435     label.isEmpty() ? tr("MEN_CANT_CAMERA_UNDO") : QString(tr("MEN_CAMERA_UNDO_ACTION")).arg(label));
436   action(CameraUndoId)->setStatusTip(
437     label.isEmpty() ? tr("MEN_CANT_CAMERA_UNDO") : QString(tr("MEN_CAMERA_UNDO_ACTION_TIP")).arg(label));
438 }
439
440 /*!
441   \brief Manage the label of Redo Camera operation.
442 */
443 void PVGUI_Module::onCameraRedoLabel( const QString& label )
444 {
445   action(CameraRedoId)->setText(
446     label.isEmpty() ? tr("MEN_CANT_CAMERA_REDO") : QString(tr("MEN_CAMERA_REDO_ACTION")).arg(label));
447   action(CameraRedoId)->setStatusTip(
448     label.isEmpty() ? tr("MEN_CANT_CAMERA_REDO") : QString(tr("MEN_CAMERA_REDO_ACTION_TIP")).arg(label));
449 }
450
451 /*!
452   \brief Slot to delete all objects.
453 */
454 void PVGUI_Module::onDeleteAll()
455 {
456   pqObjectBuilder* builder = pqApplicationCore::instance()->getObjectBuilder();
457   Implementation->Core.getApplicationUndoStack()->beginUndoSet("Delete All");
458   builder->destroyPipelineProxies();
459   Implementation->Core.getApplicationUndoStack()->endUndoSet();
460 }
461
462 /*!
463   \brief Slot to check/uncheck the action for corresponding selection mode.
464 */
465 void PVGUI_Module::onSelectionModeChanged( int mode )
466 {
467   if( toolMgr()->toolBar( mySelectionControlsTb )->isEnabled() ) {
468     if(mode == pqRubberBandHelper::SELECT) //surface selection
469       action(SelectCellsOnId)->setChecked(true);
470     else if(mode == pqRubberBandHelper::SELECT_POINTS) //surface selection
471       action(SelectPointsOnId)->setChecked(true);
472     else if(mode == pqRubberBandHelper::FRUSTUM)
473       action(SelectCellsThroughId)->setChecked(true);
474     else if(mode == pqRubberBandHelper::FRUSTUM_POINTS)
475       action(SelectPointsThroughId)->setChecked(true);
476     else if (mode == pqRubberBandHelper::BLOCKS)
477       action(SelectBlockId)->setChecked(true);
478     else // INTERACT
479       action(InteractId)->setChecked(true);
480   }
481 }
482
483 /*!
484   \brief Slot to manage the change of axis center.
485 */
486 void PVGUI_Module::onShowCenterAxisChanged( bool enabled )
487 {
488   action(ShowCenterId)->setEnabled(enabled);
489   action(ShowCenterId)->blockSignals(true);
490   pqRenderView* renView = qobject_cast<pqRenderView*>(
491     pqActiveView::instance().current());
492   action(ShowCenterId)->setChecked( renView ? renView->getCenterAxesVisibility() : false);
493   action(ShowCenterId)->blockSignals(false);
494 }
495
496 /*!
497   \brief Slot to set tooltips for the first anf the last frames, i.e. a time range of animation.
498 */
499 void PVGUI_Module::setTimeRanges( double start, double end )
500 {
501   action(FirstFrameId)->setToolTip(QString("First Frame (%1)").arg(start, 0, 'g'));
502   action(LastFrameId)->setToolTip(QString("Last Frame (%1)").arg(end, 0, 'g'));
503 }
504
505 /*!
506   \brief Slot to manage the plaing process of animation.
507 */
508 void PVGUI_Module::onPlaying( bool playing )
509 {
510   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
511   if(playing) {
512     disconnect( action(PlayId),                        SIGNAL( triggered() ),
513                 &Implementation->Core.VCRController(), SLOT( onPlay() ) );
514     connect( action(PlayId),                        SIGNAL( triggered() ),
515              &Implementation->Core.VCRController(), SLOT( onPause() ) );
516     action(PlayId)->setIcon(QIcon(resMgr->loadPixmap("ParaView",tr("ICON_PAUSE"),false)));
517     action(PlayId)->setText("Pa&use");
518   }
519   else {
520     connect( action(PlayId),                        SIGNAL( triggered() ),
521              &Implementation->Core.VCRController(), SLOT( onPlay() ) );
522     disconnect( action(PlayId),                        SIGNAL( triggered() ),
523                 &Implementation->Core.VCRController(), SLOT( onPause() ) );
524     action(PlayId)->setIcon(QIcon(resMgr->loadPixmap("ParaView",tr("ICON_PLAY"),false)));
525     action(PlayId)->setText("&Play");
526   }
527
528   Implementation->Core.setSelectiveEnabledState(!playing);
529 }
530
531 /*!
532   \brief Slot to add camera link.
533 */
534 void PVGUI_Module::onAddCameraLink()
535 {
536   pqView* vm = pqActiveView::instance().current();
537   pqRenderView* rm = qobject_cast<pqRenderView*>(vm);
538   if(rm) rm->linkToOtherView();
539   else SUIT_MessageBox::warning(getApp()->desktop(),
540                                 tr("WARNING"), tr("WRN_ADD_CAMERA_LINK"));
541 }
542
543 /*!
544   \brief Slot to show information about ParaView.
545 */
546 void PVGUI_Module::onHelpAbout()
547 {
548   pqClientAboutDialog* const dialog = new pqClientAboutDialog(getApp()->desktop());
549   dialog->setAttribute(Qt::WA_DeleteOnClose);
550   dialog->show();
551 }
552
553 /*!
554   \brief Slot to show native ParaView user documentation.
555 */
556 void PVGUI_Module::onParaViewHelp()
557 {
558   showHelpForProxy("index");
559 }
560
561 /*!
562   \brief Slot to show help for proxy.
563 */
564 void PVGUI_Module::showHelpForProxy( const QString& proxy )
565 {
566   // make sure assistant is ready
567   this->makeAssistant();
568
569   if(this->Implementation->AssistantClient) {
570     this->Implementation->AssistantClient->openAssistant();
571     QString page("%1/Documentation/%2.html");
572     page = page.arg(this->Implementation->DocumentationDir);
573     page = page.arg(proxy);
574     this->Implementation->AssistantClient->showPage(page);
575   }
576 }
577
578 QString Locate( const QString& appName )
579 {
580   QString app_dir = QCoreApplication::applicationDirPath();
581   const char* inst_dirs[] = {
582     "/./",
583     "/../bin/",
584     "/../../bin/",
585     0
586   };
587   for (const char** dir = inst_dirs; *dir; ++dir) {
588     QString path = app_dir;
589     path += *dir;
590     path += appName;
591     //cout << "Checking : " << path.toAscii().data() << " ... ";
592     //cout.flush();
593     QFileInfo finfo (path);
594     if (finfo.exists()) {
595       //cout << " Success!" << endl;
596       return path;
597     }
598     //cout << " Failed" << endl;
599   }
600   return app_dir + QDir::separator() + appName;
601 }
602
603 /*!
604   \brief Initialized an assistant client.
605 */
606 void PVGUI_Module::makeAssistant()
607 {
608   if(this->Implementation->AssistantClient)
609     return;
610   
611   QString assistantExe;
612   QString profileFile;
613   
614   const char* assistantName = "assistant";
615 #ifdef WNT
616   const char* binDir = "\\";
617   const char* binDir1 = "\\..\\";
618 #else
619   const char* binDir = "/bin/";
620   const char* binDir1 = "/bin/bin/";
621 #endif
622
623   QString helper = QString(getenv("PVHOME")) + binDir + QString("pqClientDocFinder.txt");
624   if(!QFile::exists(helper))
625     helper = QString(getenv("PVHOME")) + binDir1 + QString("pqClientDocFinder.txt");
626   if(QFile::exists(helper)) {
627     QFile file(helper);
628     if(file.open(QIODevice::ReadOnly)) {
629       assistantExe = file.readLine().trimmed();
630       profileFile = file.readLine().trimmed();
631       // CMake escapes spaces, we need to unescape those.
632       assistantExe.replace("\\ ", " ");
633       profileFile.replace("\\ ", " ");
634     }
635   }
636
637   if(assistantExe.isEmpty()) {
638     assistantExe = ::Locate(assistantName);//assistantExe = ::Locate(assistantProgName);
639     /*
640     QString assistant = QCoreApplication::applicationDirPath();
641     assistant += QDir::separator();
642     assistant += assistantName;
643     assistantExe = assistant;
644     */
645   }
646
647   this->Implementation->AssistantClient = new QAssistantClient(assistantExe, this);
648   QObject::connect(this->Implementation->AssistantClient, SIGNAL(error(const QString&)),
649                    this,                                  SLOT(assistantError(const QString&)));
650
651   QStringList args;
652   args.append(QString("-profile"));
653
654   if(profileFile.isEmpty()) {
655     // see if help is bundled up with the application
656     QString profile = ::Locate("pqClient.adp");
657     /*QCoreApplication::applicationDirPath() + QDir::separator()
658       + QString("pqClient.adp");*/
659     
660     if(QFile::exists(profile))
661       profileFile = profile;
662   }
663
664   if(profileFile.isEmpty() && getenv("PARAVIEW_HELP")) {
665     // not bundled, ask for help
666     args.append(getenv("PARAVIEW_HELP"));
667   }
668   else if(profileFile.isEmpty()) {
669     // no help, error out
670     SUIT_MessageBox::critical(getApp()->desktop(),"Help error", "Couldn't find"
671                               " pqClient.adp.\nTry setting the PARAVIEW_HELP environment variable which"
672                               " points to that file");
673     delete this->Implementation->AssistantClient;
674     return;
675   }
676
677   QFileInfo fi(profileFile);
678   this->Implementation->DocumentationDir = fi.absolutePath();
679
680   args.append(profileFile);
681
682   this->Implementation->AssistantClient->setArguments(args);
683 }
684
685 /*!
686   \brief Slot to call the message handler with the critical message.
687 */
688 void PVGUI_Module::assistantError( const QString& error )
689 {
690   qCritical(error.toAscii().data());
691 }
692
693 /*!
694   \brief Slot to show the waiting state.
695 */
696 void PVGUI_Module::onPreAccept()
697 {
698   getApp()->desktop()->statusBar()->showMessage(tr("STB_PREACCEPT"));
699   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
700 }
701
702 /*!
703   \brief Slot to show the ready state.
704 */
705 void PVGUI_Module::onPostAccept()
706 {
707   getApp()->desktop()->statusBar()->showMessage(tr("STB_POSTACCEPT"), 2000);
708   QTimer::singleShot(0, this, SLOT(endWaitCursor()));
709 }
710
711 /*!
712   \brief Slot to switch off wait cursor.
713 */
714 void PVGUI_Module::endWaitCursor()
715 {
716   QApplication::restoreOverrideCursor();
717 }
718
719 /*!
720   \brief Returns the ParaView multi-view manager.
721 */
722 pqViewManager* PVGUI_Module::getMultiViewManager() const
723 {
724   pqViewManager* aMVM = 0; 
725   if ( Implementation )
726     aMVM = &Implementation->Core.multiViewManager();
727   return aMVM;
728 }
729
730 /*!
731   \brief Processes QEvent::ActionAdded and QEvent::ActionRemoved from Lookmarks toolbar
732   in order to register/unregister this action in/from QtxActionToolMgr.
733 */
734 bool PVGUI_Module::eventFilter( QObject* theObject, QEvent* theEvent )
735 {
736   QToolBar* aTB = toolMgr()->toolBar(tr("TOOL_LOOKMARKS"));
737   if ( theObject == aTB ) {
738     
739     if ( theEvent->type() == QEvent::ActionAdded ) {
740       QList<QAction*> anActns = aTB->actions();
741       for (int i = 0; i < anActns.size(); ++i)
742         if ( toolMgr()->actionId(anActns.at(i)) == -1 ) {
743           toolMgr()->setUpdatesEnabled(false);
744           createTool( anActns.at(i), tr("TOOL_LOOKMARKS") );
745           toolMgr()->setUpdatesEnabled(true);
746         }
747     }
748
749     if ( theEvent->type() == QEvent::ActionRemoved ) {
750       QList<QAction*> anActns = aTB->actions();
751       QIntList aIDL = toolMgr()->idList();
752       for (int i = 0; i < aIDL.size(); ++i) {
753         if ( toolMgr()->action(aIDL.at(i))->parent() == aTB
754              &&
755              !anActns.contains( toolMgr()->action(aIDL.at(i)) ) ) {
756           toolMgr()->setUpdatesEnabled(false);
757           toolMgr()->unRegisterAction( aIDL.at(i) );
758           toolMgr()->remove( aIDL.at(i), tr("TOOL_LOOKMARKS") );
759           toolMgr()->setUpdatesEnabled(true);
760         }
761       }
762     }
763     
764   }
765
766   return QObject::eventFilter( theObject, theEvent );
767 }
768
769 /*!
770   \brief Activate module.
771   \param study current study
772   \return \c true if activaion is done successfully or 0 to prevent
773   activation on error
774 */
775 bool PVGUI_Module::activateModule( SUIT_Study* study )
776 {
777   bool isDone = LightApp_Module::activateModule( study );
778   if ( !isDone ) return false;
779
780   showView( true );
781
782   if ( mySourcesMenuId != -1 ) menuMgr()->show(mySourcesMenuId);
783   if ( myFiltersMenuId != -1 ) menuMgr()->show(myFiltersMenuId);
784   setMenuShown( true );
785   setToolShown( true );
786
787   toolMgr()->toolBar(tr("TOOL_LOOKMARKS"))->installEventFilter(this);
788
789   // Make default server connection
790   if ( Implementation )
791     Implementation->Core.makeDefaultConnectionIfNoneExists();
792
793   restoreDockWidgetsState();
794
795   return isDone;
796 }
797
798
799 /*!
800   \brief Deactivate module.
801   \param study current study
802   \return \c true if deactivaion is done successfully or 0 to prevent
803   deactivation on error
804 */
805 bool PVGUI_Module::deactivateModule( SUIT_Study* study )
806 {
807   toolMgr()->toolBar(tr("TOOL_LOOKMARKS"))->removeEventFilter(this);
808
809   showView( false );
810
811   // hide menus
812   menuMgr()->hide(mySourcesMenuId);
813   menuMgr()->hide(myFiltersMenuId);
814   setMenuShown( false );
815   setToolShown( false );
816
817   saveDockWidgetsState();
818
819   return LightApp_Module::deactivateModule( study );
820 }
821
822 /*!
823   \brief Called when application is closed.
824
825   Process finalize application functionality from ParaView in order to save server settings
826   and nullify application pointer if the application is being closed.
827
828   \param theApp application
829 */
830 void PVGUI_Module::onApplicationClosed( SUIT_Application* theApp )
831 {
832   pvShutdown();
833   
834   CAM_Module::onApplicationClosed(theApp);
835 }
836
837 /*!
838   \brief Compares the contents of the window with the given reference image,
839   returns true if they "match" within some tolerance.
840 */
841 bool PVGUI_Module::compareView( const QString& ReferenceImage, double Threshold,
842                                 ostream& Output, const QString& TempDirectory )
843 {
844   if ( Implementation )
845     return Implementation->Core.compareView( ReferenceImage, Threshold, Output, TempDirectory );
846   return false;
847 }
848
849 /*!
850   \fn CAM_Module* createModule();
851   \brief Export module instance (factory function).
852   \return new created instance of the module
853 */
854
855 #ifdef WNT
856 #define PVGUI_EXPORT __declspec(dllexport)
857 #else   // WNT
858 #define PVGUI_EXPORT
859 #endif  // WNT
860
861 extern "C" {
862   PVGUI_EXPORT CAM_Module* createModule() {
863     return new PVGUI_Module();
864   }
865 }