Salome HOME
Redesign SALOME documentation
[modules/gui.git] / src / STD / STD_Application.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  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, or (at your option) any later version.
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
23 #include "STD_Application.h"
24
25 #include "STD_MDIDesktop.h"
26
27 #include <SUIT_Tools.h>
28 #include <SUIT_Study.h>
29 #include <SUIT_Desktop.h>
30 #include <SUIT_Session.h>
31 #include <SUIT_MessageBox.h>
32 #include <SUIT_ViewManager.h>
33 #include <SUIT_ResourceMgr.h>
34
35 #include <QtxDockAction.h>
36 #include <QtxMenu.h>
37 #include <QtxActionMenuMgr.h>
38 #include <QtxActionToolMgr.h>
39
40 #include <QMenu>
41 #include <QStatusBar>
42 #include <QCloseEvent>
43 #include <QFileDialog>
44 #include <QApplication>
45
46 /*!Create and return new instance of STD_Application*/
47 extern "C" STD_EXPORT SUIT_Application* createApplication()
48 {
49   return new STD_Application();
50 }
51
52 /*!Constructor.*/
53 STD_Application::STD_Application()
54 : SUIT_Application(),
55   myActiveViewMgr( 0 ),
56   myExitConfirm( true ),
57   myEditEnabled( true )
58 {
59   setDesktop( new STD_MDIDesktop() );
60 }
61
62 /*!Destructor.*/
63 STD_Application::~STD_Application()
64 {
65   clearViewManagers();
66 }
67
68 /*! \retval requirement of exit confirmation*/
69 bool STD_Application::exitConfirmation() const
70 {
71   return myExitConfirm;
72 }
73
74 /*! Set the requirement of exit confirmation*/
75 void STD_Application::setExitConfirmation( const bool on )
76 {
77   myExitConfirm = on;
78 }
79
80 /*! \retval QString "StdApplication"*/
81 QString STD_Application::applicationName() const
82 {
83   return QString( "StdApplication" );
84 }
85
86 /*!Start STD_Application*/
87 void STD_Application::start()
88 {
89   createActions();
90
91   updateDesktopTitle();
92   updateCommandsStatus();
93   setEditEnabled( myEditEnabled );
94
95   loadPreferences();
96
97   SUIT_Application::start();
98 }
99
100 /*!
101   Close the Application
102 */
103 void STD_Application::closeApplication()
104 {
105   if ( desktop() )
106     savePreferences();
107   SUIT_Study* study = activeStudy();
108
109   if ( study )
110   {
111     beforeCloseDoc( study );
112
113     study->closeDocument();
114     emit appClosed();
115     setActiveStudy( 0 );
116     delete study;
117
118     afterCloseDoc();
119   }
120
121   setDesktop( 0 );
122
123   SUIT_Application::closeApplication();
124 }
125
126 /*!Event on closing desktop*/
127 void STD_Application::onDesktopClosing( SUIT_Desktop*, QCloseEvent* e )
128 {
129   if ( SUIT_Session::session()->applications().count() < 2 )
130   {
131     onExit();
132     return;
133   }
134
135   bool closePermanently;
136   if ( !isPossibleToClose( closePermanently ) )
137   {
138     e->ignore();
139     return;
140   }
141
142   closeApplication();
143 }
144
145 /*!Create actions, menus and tools*/
146 void STD_Application::createActions()
147 {
148   SUIT_Desktop* desk = desktop();
149   SUIT_ResourceMgr* resMgr = resourceMgr();
150   if ( !desk || !resMgr )
151     return;
152
153   // Create actions
154
155   createAction( FileNewId, tr( "TOT_DESK_FILE_NEW" ),
156                 resMgr->loadPixmap( "STD", tr( "ICON_FILE_NEW" ) ),
157                 tr( "MEN_DESK_FILE_NEW" ), tr( "PRP_DESK_FILE_NEW" ),
158                 Qt::CTRL+Qt::Key_N, desk, false, this, SLOT( onNewDoc() ) );
159
160   createAction( FileOpenId, tr( "TOT_DESK_FILE_OPEN" ),
161                 resMgr->loadPixmap( "STD", tr( "ICON_FILE_OPEN" ) ),
162                 tr( "MEN_DESK_FILE_OPEN" ), tr( "PRP_DESK_FILE_OPEN" ),
163                 Qt::CTRL+Qt::Key_O, desk, false, this, SLOT( onOpenDoc() ) );
164
165   createAction( FileReopenId, tr( "TOT_DESK_FILE_REOPEN" ), QIcon(),
166                 tr( "MEN_DESK_FILE_REOPEN" ), tr( "PRP_DESK_FILE_REOPEN" ),
167                 0, desk, false, this, SLOT( onReopenDoc() ) );
168
169   createAction( FileCloseId, tr( "TOT_DESK_FILE_CLOSE" ),
170                 resMgr->loadPixmap( "STD", tr( "ICON_FILE_CLOSE" ) ),
171                 tr( "MEN_DESK_FILE_CLOSE" ), tr( "PRP_DESK_FILE_CLOSE" ),
172                 Qt::CTRL+Qt::Key_W, desk, false, this, SLOT( onCloseDoc() ) );
173
174   createAction( FileExitId, tr( "TOT_DESK_FILE_EXIT" ), QIcon(),
175                 tr( "MEN_DESK_FILE_EXIT" ), tr( "PRP_DESK_FILE_EXIT" ),
176                 Qt::CTRL+Qt::Key_Q, desk, false, this, SLOT( onExit() ) );
177
178   createAction( FileSaveId, tr( "TOT_DESK_FILE_SAVE" ),
179                 resMgr->loadPixmap( "STD", tr( "ICON_FILE_SAVE" ) ),
180                 tr( "MEN_DESK_FILE_SAVE" ), tr( "PRP_DESK_FILE_SAVE" ),
181                 Qt::CTRL+Qt::Key_S, desk, false, this, SLOT( onSaveDoc() ) );
182
183   createAction( FileSaveAsId, tr( "TOT_DESK_FILE_SAVEAS" ), QIcon(),
184                 tr( "MEN_DESK_FILE_SAVEAS" ), tr( "PRP_DESK_FILE_SAVEAS" ),
185                 Qt::CTRL+Qt::SHIFT+Qt::Key_S, desk, false, this, SLOT( onSaveAsDoc() ) );
186
187   createAction( EditCopyId, tr( "TOT_DESK_EDIT_COPY" ),
188                 resMgr->loadPixmap( "STD", tr( "ICON_EDIT_COPY" ) ),
189                 tr( "MEN_DESK_EDIT_COPY" ), tr( "PRP_DESK_EDIT_COPY" ),
190                 Qt::CTRL+Qt::Key_C, desk, false, this, SLOT( onCopy() ) );
191
192   createAction( EditPasteId, tr( "TOT_DESK_EDIT_PASTE" ),
193                 resMgr->loadPixmap( "STD", tr( "ICON_EDIT_PASTE" ) ),
194                 tr( "MEN_DESK_EDIT_PASTE" ), tr( "PRP_DESK_EDIT_PASTE" ),
195                 Qt::CTRL+Qt::Key_V, desk, false, this, SLOT( onPaste() ) );
196
197   QAction* a = createAction( ViewStatusBarId, tr( "TOT_DESK_VIEW_STATUSBAR" ),
198                              QIcon(), tr( "MEN_DESK_VIEW_STATUSBAR" ),
199                              tr( "PRP_DESK_VIEW_STATUSBAR" ), Qt::ALT+Qt::SHIFT+Qt::Key_S, desk, true );
200   a->setChecked( desk->statusBar()->isVisibleTo( desk ) );
201   connect( a, SIGNAL( toggled( bool ) ), this, SLOT( onViewStatusBar( bool ) ) );
202
203   createAction( NewWindowId, tr( "TOT_DESK_NEWWINDOW" ), QIcon(),
204                 tr( "MEN_DESK_NEWWINDOW" ), tr( "PRP_DESK_NEWWINDOW" ), 0, desk  );
205
206   createAction( HelpAboutId, tr( "TOT_DESK_HELP_ABOUT" ),
207                 resMgr->loadPixmap( "STD", tr( "ICON_DESK_ABOUT" ) ),
208                 tr( "MEN_DESK_HELP_ABOUT" ), tr( "PRP_DESK_HELP_ABOUT" ),
209                 Qt::ALT+Qt::SHIFT+Qt::Key_A, desk, false, this, SLOT( onHelpAbout() ) );
210
211
212   QtxDockAction* dwa = new QtxDockAction( tr( "TOT_DOCKWINDOWS" ), tr( "MEN_DESK_VIEW_DOCKWINDOWS" ), desk );
213   dwa->setDockType( QtxDockAction::DockWidget );
214   registerAction( ViewWindowsId, dwa );
215
216   QtxDockAction* tba = new QtxDockAction( tr( "TOT_TOOLBARS" ), tr( "MEN_DESK_VIEW_TOOLBARS" ), desk );
217   tba->setDockType( QtxDockAction::ToolBar );
218   registerAction( ViewToolBarsId, tba );
219
220   // Create menus
221
222   int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1, MenuFileId, 0 );
223   // Let the application developers insert some menus between Edit and View
224   int editMenu = createMenu( tr( "MEN_DESK_EDIT" ), -1, MenuEditId, 5 );
225   int viewMenu = createMenu( tr( "MEN_DESK_VIEW" ), -1, MenuViewId, 10 );
226   int helpMenu = createMenu( tr( "MEN_DESK_HELP" ), -1, MenuHelpId, 1000 );
227
228   // Create menu items
229
230   createMenu( FileNewId,    fileMenu, 0 );
231   createMenu( FileOpenId,   fileMenu, 0 );
232   createMenu( FileReopenId, fileMenu, 0 ); 
233   createMenu( FileSaveId,   fileMenu, 5 );
234   createMenu( FileSaveAsId, fileMenu, 5 );
235   createMenu( FileCloseId,  fileMenu, 5 );
236   createMenu( separator(),  fileMenu, -1, 5 );
237
238   createMenu( separator(),  fileMenu );
239   createMenu( FileExitId,   fileMenu );
240
241   createMenu( EditCopyId,  editMenu );
242   createMenu( EditPasteId, editMenu );
243   createMenu( separator(), editMenu );
244
245   createMenu( ViewToolBarsId,  viewMenu, 0 );
246   createMenu( ViewWindowsId,   viewMenu, 0 );
247   createMenu( separator(),     viewMenu, -1, 10 );
248   createMenu( ViewStatusBarId, viewMenu, 10 );
249   createMenu( separator(),     viewMenu );
250
251   createMenu( HelpAboutId, helpMenu );
252   createMenu( separator(), helpMenu );
253
254   // Create tool bars
255
256   int stdTBar = createTool( tr( "INF_DESK_TOOLBAR_STANDARD" ),  // title (language-dependant)
257                             QString( "SalomeStandard" ) );      // name (language-independant)
258
259   // Create tool items
260
261   createTool( FileNewId, stdTBar );
262   createTool( FileOpenId, stdTBar );
263   createTool( FileSaveId, stdTBar );
264   createTool( FileCloseId, stdTBar );
265   createTool( separator(), stdTBar );
266   createTool( EditCopyId, stdTBar );
267   createTool( EditPasteId, stdTBar );
268 }
269
270 /*!Opens new application*/
271 void STD_Application::onNewDoc()
272 {
273   onNewDoc( QString() );
274 }
275
276 /*!Opens new application*/
277 bool STD_Application::onNewDoc( const QString& name )
278 {
279   QApplication::setOverrideCursor( Qt::WaitCursor );
280
281   bool res = true;
282   if ( !activeStudy() )
283   {
284     createEmptyStudy();
285     res = activeStudy()->createDocument( name );
286     if ( res )
287       studyCreated( activeStudy() );
288     else
289     {
290       SUIT_Study* st = activeStudy();
291       setActiveStudy( 0 );
292       delete st;
293     }
294   }
295   else
296   {
297     SUIT_Application* aApp = startApplication( 0, 0 );
298     if ( aApp->inherits( "STD_Application" ) )
299       res = ((STD_Application*)aApp)->onNewDoc( name );
300     else
301     {
302       aApp->createEmptyStudy();
303       res = aApp->activeStudy()->createDocument( name );
304     }
305     if ( !res )
306       aApp->closeApplication();
307   }
308
309   QApplication::restoreOverrideCursor();
310
311   return res;
312 }
313
314 /*!Put file name from file dialog to onOpenDoc(const QString&) function*/
315 void STD_Application::onOpenDoc()
316 {
317   // It is preferrable to use OS-specific file dialog box here !!!
318   QString aName = getFileName( true, QString(), getFileFilter( true ), QString(), 0 );
319   if ( aName.isNull() )
320     return;
321
322   onOpenDoc( aName );
323 }
324
325 /*! \retval \c true, if document was opened successful, else \c false.*/
326 bool STD_Application::onOpenDoc( const QString& aName )
327 {
328   if ( !abortAllOperations() )
329     return false;
330
331   QApplication::setOverrideCursor( Qt::WaitCursor );
332
333   bool res = openAction( openChoice( aName ), aName );
334   
335   QApplication::restoreOverrideCursor();
336
337   return res;
338 }
339
340 /*! Reload document from the file.*/
341 bool STD_Application::onReopenDoc()
342 {
343   bool res = false;
344
345   SUIT_Study* study = activeStudy();
346   if ( study && study->isSaved() ) {
347     // ask user for the confirmation
348     if ( SUIT_MessageBox::question( desktop(), tr( "REOPEN_STUDY" ), tr( "REOPEN_QUESTION" ),
349                                     SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No
350                                     ) == SUIT_MessageBox::No )
351       return false;
352
353     // remember study name
354     QString studyName = study->studyName();
355
356     // close study
357     beforeCloseDoc( study );
358     study->closeDocument( true );
359
360     // update views / windows / status bar / title
361     clearViewManagers();
362     setActiveStudy( 0 );
363
364     // delete study
365     delete study;
366     study = 0;
367     
368     // post closing actions
369     afterCloseDoc();
370
371     int aNbStudies = 0;
372     QList<SUIT_Application*> apps = SUIT_Session::session()->applications();
373     for ( int i = 0; i < apps.count(); i++ )
374       aNbStudies += apps.at( i )->getNbStudies();
375
376     // reload study from the file
377     res = useFile( studyName ) && activeStudy();
378
379     // if reloading is failed, close the desktop
380     if ( aNbStudies && !res )
381       closeApplication();
382     else
383     {
384       updateDesktopTitle();
385       updateCommandsStatus();
386     }
387   }
388   return res;
389 }
390
391 /*!Virtual function. Not implemented here.*/
392 void STD_Application::beforeCloseDoc( SUIT_Study* )
393 {
394 }
395
396 /*!Virtual function. Not implemented here.*/
397 void STD_Application::afterCloseDoc()
398 {
399 }
400
401 /*!Close document, if it's possible.*/
402 void STD_Application::onCloseDoc( bool ask )
403 {
404   closeDoc( ask );
405 }
406
407 /*!Close document, if it's possible.*/
408 bool STD_Application::closeDoc( bool ask )
409 {
410   bool closePermanently = true;
411
412   if ( ask && !isPossibleToClose( closePermanently ) )
413     return false;
414
415   return closeActiveDoc( closePermanently );
416 }
417
418 /*!Close document.*/
419 bool STD_Application::closeActiveDoc( bool permanently )
420 {
421   SUIT_Study* study = activeStudy();
422   if ( !study ) // no active study
423     return true;
424
425   beforeCloseDoc( study );
426
427   if ( study )
428     study->closeDocument( permanently );
429
430   clearViewManagers();
431
432   setActiveStudy( 0 );
433
434   int aNbStudies = 0;
435   QList<SUIT_Application*> apps = SUIT_Session::session()->applications();
436   for ( int i = 0; i < apps.count(); i++ )
437     aNbStudies += apps.at( i )->getNbStudies();
438
439   if ( aNbStudies )
440   {
441     savePreferences();
442     setDesktop( 0 );
443   }
444   else
445   {
446     updateDesktopTitle();
447     updateCommandsStatus();
448   }
449
450   // IPAL19532: deleting study should be performed after calling setDesktop(0)
451   delete study;
452
453   afterCloseDoc();
454
455   if ( !desktop() )
456     closeApplication();
457   return true;
458 }
459
460 /*!Check the application on closing.
461  * \retval \c true if possible, else \c false
462  */
463 bool STD_Application::isPossibleToClose( bool& closePermanently )
464 {
465   if ( activeStudy() )
466   {
467     activeStudy()->abortAllOperations();
468     if ( activeStudy()->isModified() )
469     {
470       QString sName = activeStudy()->studyName().trimmed();
471       return closeAction( closeChoice( sName ), closePermanently );
472     }
473   }
474   return true;
475 }
476
477 int STD_Application::closeChoice( const QString& docName )
478 {
479   int answer = SUIT_MessageBox::question( desktop(), tr( "CLOSE_STUDY" ), tr( "CLOSE_QUESTION" ),
480                                           SUIT_MessageBox::Save | SUIT_MessageBox::Discard | SUIT_MessageBox::Cancel,
481                                           SUIT_MessageBox::Save );
482
483   int res = CloseCancel;
484   if ( answer == SUIT_MessageBox::Save )
485     res = CloseSave;
486   else if ( answer == SUIT_MessageBox::Discard )
487     res = CloseDiscard;
488
489   return res;
490 }
491
492 bool STD_Application::closeAction( const int choice, bool& closePermanently )
493 {
494   bool res = true;
495   switch( choice )
496   {
497   case CloseSave:
498     if ( activeStudy()->isSaved() )
499       onSaveDoc();
500     else if ( !onSaveAsDoc() )
501       res = false;
502     break;
503   case CloseDiscard:
504     break;
505   case CloseCancel:
506   default:
507     res = false;
508   }
509
510   return res;
511 }
512
513 int STD_Application::openChoice( const QString& aName )
514 {
515   SUIT_Session* aSession = SUIT_Session::session();
516
517   bool isAlreadyOpen = false;
518   QList<SUIT_Application*> aAppList = aSession->applications();
519   for ( QList<SUIT_Application*>::iterator it = aAppList.begin(); it != aAppList.end() && !isAlreadyOpen; ++it )
520     isAlreadyOpen = (*it)->activeStudy() && (*it)->activeStudy()->studyName() == aName;
521   return isAlreadyOpen ? OpenExist : OpenNew;
522 }
523
524 bool STD_Application::openAction( const int choice, const QString& aName )
525 {
526   bool res = true;
527   switch ( choice )
528   {
529   case OpenExist:
530     {
531       SUIT_Application* aApp = 0;
532       SUIT_Session* aSession = SUIT_Session::session();
533       QList<SUIT_Application*> aAppList = aSession->applications();
534       for ( QList<SUIT_Application*>::iterator it = aAppList.begin(); it != aAppList.end() && !aApp; ++it )
535       {
536         if ( (*it)->activeStudy() && (*it)->activeStudy()->studyName() == aName )
537           aApp = *it;
538       }
539       if ( aApp )
540         aApp->desktop()->activateWindow();
541       else
542         res = false;
543     }
544     break;
545   case OpenNew:
546     if ( !activeStudy() )
547       res = useFile( aName );
548     else
549     {
550       SUIT_Application* aApp = startApplication( 0, 0 );
551       if ( aApp )
552         res = aApp->useFile( aName );
553       if ( !res )
554         aApp->closeApplication();
555     }
556     break;
557   case OpenCancel:
558   default:
559     res = false;
560   }
561
562   return res;
563 }
564
565 /*!Save document if all ok, else error message.*/
566 void STD_Application::onSaveDoc()
567 {
568   if ( !activeStudy() )
569     return;
570
571   if ( !abortAllOperations() )
572     return;
573
574   bool isOk = false;
575   if ( activeStudy()->isSaved() )
576   {
577     putInfo( tr( "INF_DOC_SAVING" ) + activeStudy()->studyName() );
578
579     QApplication::setOverrideCursor( Qt::WaitCursor );
580
581     isOk = activeStudy()->saveDocument();
582
583     QApplication::restoreOverrideCursor();
584
585     if ( !isOk )
586     {
587       putInfo( "" );
588       // displaying a message box as SUIT_Validator in case file can't be written (the most frequent case)
589       SUIT_MessageBox::critical( desktop(), tr( "ERR_ERROR" ),
590                                  tr( "INF_DOC_SAVING_FAILS" ).arg( activeStudy()->studyName() ) );
591     }
592     else
593       putInfo( tr( "INF_DOC_SAVED" ).arg( "" ) );
594   }
595
596   if ( isOk )
597     studySaved( activeStudy() );
598   else
599     onSaveAsDoc();
600 }
601
602 /*! \retval \c true, if document saved successfully, else \c false.*/
603 bool STD_Application::onSaveAsDoc()
604 {
605   SUIT_Study* study = activeStudy();
606   if ( !study )
607     return false;
608
609   if ( !abortAllOperations() )
610     return false;
611
612   bool isOk = false;
613   while ( !isOk )
614   {
615     QString aName = getFileName( false, study->studyName(), getFileFilter( false ), QString(), 0 );
616     if ( aName.isNull() )
617       return false;
618
619     QApplication::setOverrideCursor( Qt::WaitCursor );
620
621     putInfo( tr( "INF_DOC_SAVING" ) + aName );
622     isOk = study->saveDocumentAs( aName );
623
624     putInfo( isOk ? tr( "INF_DOC_SAVED" ).arg( aName ) : "" );
625
626     QApplication::restoreOverrideCursor();
627
628     if ( !isOk )
629       SUIT_MessageBox::critical( desktop(), tr( "ERROR" ), tr( "INF_DOC_SAVING_FAILS" ).arg( aName ) );
630   }
631
632   studySaved( activeStudy() );
633
634   return isOk;
635 }
636
637 /*!Closing session.*/
638 void STD_Application::onExit()
639 {
640   int aAnswer = SUIT_MessageBox::Ok;
641   if ( exitConfirmation() )
642     aAnswer = SUIT_MessageBox::question( desktop(), tr( "INF_DESK_EXIT" ), tr( "QUE_DESK_EXIT" ),
643                                          SUIT_MessageBox::Ok | SUIT_MessageBox::Cancel, SUIT_MessageBox::Cancel );
644   if ( aAnswer == SUIT_MessageBox::Ok )
645     SUIT_Session::session()->closeSession();
646 }
647
648 /*!Virtual slot. Not implemented here.*/
649 void STD_Application::onCopy()
650 {
651 }
652
653 /*!Virtual slot. Not implemented here.*/
654 void STD_Application::onPaste()
655 {
656 }
657
658 /*!Sets \a theEnable for menu manager and for tool manager.*/
659 void STD_Application::setEditEnabled( bool theEnable )
660 {
661   myEditEnabled = theEnable;
662
663   QtxActionMenuMgr* mMgr = desktop()->menuMgr();
664   QtxActionToolMgr* tMgr = desktop()->toolMgr();
665
666   for ( int i = EditCopyId; i <= EditPasteId; i++ )
667   {
668     mMgr->setShown( mMgr->actionId(action(i)), myEditEnabled );
669     tMgr->setShown( tMgr->actionId(action(i)), myEditEnabled );
670   }
671 }
672
673 /*!\retval \c true, if document opened successfully, else \c false.*/
674 bool STD_Application::useFile(const QString& theFileName)
675 {
676   bool res = SUIT_Application::useFile( theFileName );
677
678   if ( res )
679     studyOpened( activeStudy() );
680
681   return res;
682 }
683
684 /*!Update desktop title.*/
685 void STD_Application::updateDesktopTitle()
686 {
687   QString aTitle = applicationName();
688   QString aVer = applicationVersion();
689   if ( !aVer.isEmpty() )
690     aTitle += QString( " " ) + aVer;
691
692   if ( activeStudy() )
693   {
694     QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
695     if ( !sName.isEmpty() )
696       aTitle += QString( " - [%1]" ).arg( sName );
697   }
698
699   desktop()->setWindowTitle( aTitle );
700 }
701
702 /*!Update commands status.*/
703 void STD_Application::updateCommandsStatus()
704 {
705   SUIT_Application::updateCommandsStatus();
706
707   bool aHasStudy     = activeStudy() != 0;
708   bool aSaved        = aHasStudy && activeStudy()->isSaved();
709   bool aModified     = aHasStudy && activeStudy()->isModified();
710   bool aIsNeedToSave = aHasStudy && ( !aSaved || aModified );
711
712  if ( action( FileReopenId ) )
713     action( FileReopenId )->setEnabled( aSaved );
714  if ( action( FileSaveId ) )
715     action( FileSaveId )->setEnabled( aIsNeedToSave );
716   if ( action( FileSaveAsId ) )
717     action( FileSaveAsId )->setEnabled( aHasStudy );
718   if ( action( FileCloseId ) )
719     action( FileCloseId )->setEnabled( aHasStudy );
720   if ( action( NewWindowId ) )
721     action( NewWindowId )->setEnabled( aHasStudy );
722 }
723
724 /*!\retval SUIT_ViewManager by viewer manager type name.*/
725 SUIT_ViewManager* STD_Application::viewManager( const QString& vmType ) const
726 {
727   SUIT_ViewManager* vm = 0;
728   for ( QList<SUIT_ViewManager*>::const_iterator it = myViewMgrs.begin(); it != myViewMgrs.end() && !vm; ++it )
729   {
730     if ( (*it)->getType() == vmType && !(*it)->getDetached())
731       vm = *it;
732   }
733   return vm;
734 }
735
736 /*! \param vmType - input view manager type name
737  * \param lst - output list of view managers with types \a vmType.
738  */
739 void STD_Application::viewManagers( const QString& vmType, ViewManagerList& lst ) const
740 {
741   for ( QList<SUIT_ViewManager*>::const_iterator it = myViewMgrs.begin(); it != myViewMgrs.end(); ++it )
742   {
743     if ( (*it)->getType() == vmType )
744       lst.append( *it );
745   }
746 }
747
748 /*!\param lst - output list of all view managers.*/
749 void STD_Application::viewManagers( ViewManagerList& lst ) const
750 {
751   for ( QList<SUIT_ViewManager*>::const_iterator it = myViewMgrs.begin(); it != myViewMgrs.end(); ++it )
752     lst.append( *it );
753 }
754
755 /*!\retval ViewManagerList - const list of all view managers.*/
756 ViewManagerList STD_Application::viewManagers() const
757 {
758   ViewManagerList lst;
759   viewManagers( lst );
760   return lst;
761 }
762
763 /*!\retval SUIT_ViewManager - return pointer to active view manager.*/
764 SUIT_ViewManager* STD_Application::activeViewManager() const
765 {
766   return myActiveViewMgr;
767 }
768
769 /*!Add view manager to view managers list, if it not already there.*/
770 void STD_Application::addViewManager( SUIT_ViewManager* vm )
771 {
772   if ( !vm )
773     return;
774
775   if ( !containsViewManager( vm ) )
776   {
777     myViewMgrs.append( vm );
778     connect( vm, SIGNAL( activated( SUIT_ViewManager* ) ),
779              this, SLOT( onViewManagerActivated( SUIT_ViewManager* ) ) );
780     vm->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
781
782     emit viewManagerAdded( vm );
783   }
784 /*
785   if ( !activeViewManager() && myViewMgrs.count() == 1 )
786     setActiveViewManager( vm );
787 */
788 }
789
790 /*!Remove view manager from view managers list.*/
791 void STD_Application::removeViewManager( SUIT_ViewManager* vm )
792 {
793   if ( !vm )
794     return;
795
796   vm->closeAllViews();
797
798   emit viewManagerRemoved( vm );
799
800   vm->disconnectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
801   disconnect( vm, SIGNAL( activated( SUIT_ViewManager* ) ),
802              this, SLOT( onViewManagerActivated( SUIT_ViewManager* ) ) );
803   myViewMgrs.removeAll( vm );
804
805   if ( myActiveViewMgr == vm )
806     myActiveViewMgr = 0;
807 }
808
809 /*!Remove all view managers from view managers list.*/
810 void STD_Application::clearViewManagers()
811 {
812   ViewManagerList lst;
813   viewManagers( lst );
814
815   for ( QList<SUIT_ViewManager*>::iterator it = lst.begin(); it != lst.end(); ++it )
816   {
817     QPointer<SUIT_ViewManager> vm = *it;
818     removeViewManager( vm );
819     delete vm;
820   }
821 }
822
823 /*!\retval \c true, if view manager \a vm, already in view manager list (\a myViewMgrs).*/
824 bool STD_Application::containsViewManager( SUIT_ViewManager* vm ) const
825 {
826   return myViewMgrs.contains( vm );
827 }
828
829 /*!Private slot, sets active manager to \vm, if \vm in view managers list.*/
830 void STD_Application::onViewManagerActivated( SUIT_ViewManager* vm )
831 {
832   setActiveViewManager( vm );
833 }
834
835 /*!Shows status bar, if on is \c true, else hides status bar.*/
836 void STD_Application::onViewStatusBar( bool on )
837 {
838   if ( on )
839     desktop()->statusBar()->show();
840   else
841     desktop()->statusBar()->hide();
842 }
843
844 /*!Call SUIT_MessageBox::info1(...) with about information.*/
845 void STD_Application::onHelpAbout()
846 {
847   SUIT_MessageBox::information( desktop(), tr( "About" ), tr( "ABOUT_INFO" ) );
848 }
849
850 /*!Create empty study. \n
851  * Create new view manager and adding it to view managers list.
852  */
853 void STD_Application::createEmptyStudy()
854 {
855   SUIT_Application::createEmptyStudy();
856 }
857
858 /*!Sets active manager to \vm, if \vm in view managers list.*/
859 void STD_Application::setActiveViewManager( SUIT_ViewManager* vm )
860 {
861   if ( !containsViewManager( vm ) )
862     return;
863
864   myActiveViewMgr = vm;
865   emit viewManagerActivated( vm );
866 }
867
868 /*!Public slot. */
869 void STD_Application::onConnectPopupRequest( SUIT_PopupClient* client, QContextMenuEvent* e )
870 {
871   QtxMenu* popup = new QtxMenu();
872   // fill popup by own items
873   QString title;
874   contextMenuPopup( client->popupClientType(), popup, title );
875   popup->setTitleText( title );
876
877   popup->addSeparator();
878   // add items from popup client
879   client->contextMenuPopup( popup );
880
881   SUIT_Tools::simplifySeparators( popup );
882
883   if ( !popup->actions().isEmpty() )
884     popup->exec( e->globalPos() );
885   delete popup;
886 }
887
888 /*!\retval QString - return file extension(s).*/
889 QString STD_Application::getFileFilter( bool /*open*/ ) const
890 {
891   return QString();
892 }
893
894 /*!\retval QString - return file name from dialog.*/
895 QString STD_Application::getFileName( bool open, const QString& initial, const QString& filters,
896                                       const QString& caption, QWidget* parent )
897 {
898   if ( !parent )
899     parent = desktop();
900   if ( open )
901     return QFileDialog::getOpenFileName( parent, caption, initial, filters );
902   else
903   {
904     QString aName;
905     QString aUsedFilter;
906     QString anOldPath = initial;
907
908     bool isOk = false;
909     while ( !isOk )
910     {
911       // It is preferrable to use OS-specific file dialog box here !!!
912       aName = QFileDialog::getSaveFileName( parent, caption, anOldPath, filters, &aUsedFilter );
913
914       if ( aName.isNull() )
915         isOk = true;
916       else
917       {
918         int aEnd = aUsedFilter.lastIndexOf( ')' );
919         int aStart = aUsedFilter.lastIndexOf( '(', aEnd );
920         QString wcStr = aUsedFilter.mid( aStart + 1, aEnd - aStart - 1 );
921
922         int idx = 0;
923         QStringList extList;
924         QRegExp rx( "[\b\\*]*\\.([\\w]+)" );
925         while ( ( idx = rx.indexIn( wcStr, idx ) ) != -1 )
926         {
927           extList.append( rx.cap( 1 ) );
928           idx += rx.matchedLength();
929         }
930
931         if ( !extList.isEmpty() && !extList.contains( SUIT_Tools::extension( aName ) ) )
932           aName += QString( ".%1" ).arg( extList.first() );
933
934         if ( QFileInfo( aName ).exists() )
935         {
936           int aAnswer = SUIT_MessageBox::question( desktop(), tr( "TIT_FILE_SAVEAS" ),
937                                                    tr( "MSG_FILE_EXISTS" ).arg( aName ),
938                                                    SUIT_MessageBox::Yes | SUIT_MessageBox::No | SUIT_MessageBox::Cancel, SUIT_MessageBox::Yes );
939           if ( aAnswer == SUIT_MessageBox::Cancel )
940           {     // cancelled
941             aName = QString();
942             isOk = true;
943           }
944           else if ( aAnswer == SUIT_MessageBox::No ) // not save to this file
945             anOldPath = aName;             // not to return to the same initial dir at each "while" step
946           else                     // overwrite the existing file
947             isOk = true;
948         }
949         else
950           isOk = true;
951       }
952     }
953     return aName;
954   }
955 }
956
957 /*!\retval QString - return directory name from dialog.*/
958 QString STD_Application::getDirectory( const QString& initial, const QString& caption, QWidget* parent )
959 {
960   if ( !parent )
961     parent = desktop();
962
963   return QFileDialog::getExistingDirectory( parent, caption, initial );
964 }
965
966 /*!
967   Changes desktop
968   \param desk - new desktop
969 */
970 void STD_Application::setDesktop( SUIT_Desktop* desk )
971 {
972   SUIT_Application::setDesktop( desk );
973
974   if ( desk ) {
975     connect( desk, SIGNAL( closing( SUIT_Desktop*, QCloseEvent* ) ),
976              this, SLOT( onDesktopClosing( SUIT_Desktop*, QCloseEvent* ) ), Qt::UniqueConnection );
977   }
978 }
979
980 /*!
981   Allow to load preferences before the desktop will be shown.
982 */
983 void STD_Application::loadPreferences()
984 {
985 }
986
987 /*!
988   Allow to save preferences before the application will be closed.
989 */
990 void STD_Application::savePreferences()
991 {
992 }
993
994 /*!
995   Custom activity after study is created
996   Updates desktop and actions
997 */
998 void STD_Application::studyCreated( SUIT_Study* )
999 {
1000   updateDesktopTitle();
1001   updateCommandsStatus();
1002 }
1003
1004 /*!
1005   Custom activity after study is opened
1006   Updates desktop and actions
1007 */
1008 void STD_Application::studyOpened( SUIT_Study* )
1009 {
1010   updateDesktopTitle();
1011   updateCommandsStatus();
1012 }
1013
1014 /*!
1015   Custom activity after study is opened
1016   Updates desktop and actions
1017 */
1018 void STD_Application::studySaved( SUIT_Study* )
1019 {
1020   updateDesktopTitle();
1021   updateCommandsStatus();
1022 }
1023
1024 /*!
1025   Return index of the view ma
1026 */
1027 int STD_Application::viewManagerId( const SUIT_ViewManager* theManager) const
1028 {
1029   return myViewMgrs.indexOf(const_cast<SUIT_ViewManager*>(theManager));
1030 }
1031
1032 /*!
1033   \brief Abort active operations if there are any
1034   \return \c false if some operation cannot be aborted
1035 */
1036 bool STD_Application::abortAllOperations()
1037 {
1038   return true;
1039 }