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