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