Salome HOME
Update copyrights
[modules/gui.git] / src / STD / STD_Application.cxx
1 // Copyright (C) 2007-2019  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     if ( (*it)->getType() == vmType && !(*it)->getDetached())
781       vm = *it;
782   }
783   return vm;
784 }
785
786 /*! \param vmType - input view manager type name
787  * \param lst - output list of view managers with types \a vmType.
788  */
789 void STD_Application::viewManagers( const QString& vmType, ViewManagerList& lst ) const
790 {
791   for ( QList<SUIT_ViewManager*>::const_iterator it = myViewMgrs.begin(); it != myViewMgrs.end(); ++it )
792   {
793     if ( (*it)->getType() == vmType )
794       lst.append( *it );
795   }
796 }
797
798 /*!\param lst - output list of all view managers.*/
799 void STD_Application::viewManagers( ViewManagerList& lst ) const
800 {
801   for ( QList<SUIT_ViewManager*>::const_iterator it = myViewMgrs.begin(); it != myViewMgrs.end(); ++it )
802     lst.append( *it );
803 }
804
805 /*!\retval ViewManagerList - const list of all view managers.*/
806 ViewManagerList STD_Application::viewManagers() const
807 {
808   ViewManagerList lst;
809   viewManagers( lst );
810   return lst;
811 }
812
813 /*!\retval SUIT_ViewManager - return pointer to active view manager.*/
814 SUIT_ViewManager* STD_Application::activeViewManager() const
815 {
816   return myActiveViewMgr;
817 }
818
819 /*!Add view manager to view managers list, if it not already there.*/
820 void STD_Application::addViewManager( SUIT_ViewManager* vm )
821 {
822   if ( !vm )
823     return;
824
825   if ( !containsViewManager( vm ) )
826   {
827     myViewMgrs.append( vm );
828     connect( vm, SIGNAL( activated( SUIT_ViewManager* ) ),
829              this, SLOT( onViewManagerActivated( SUIT_ViewManager* ) ) );
830     vm->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
831
832     emit viewManagerAdded( vm );
833   }
834 /*
835   if ( !activeViewManager() && myViewMgrs.count() == 1 )
836     setActiveViewManager( vm );
837 */
838 }
839
840 /*!Remove view manager from view managers list.*/
841 void STD_Application::removeViewManager( SUIT_ViewManager* vm )
842 {
843   if ( !vm )
844     return;
845
846   vm->closeAllViews();
847
848   emit viewManagerRemoved( vm );
849
850   vm->disconnectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
851   disconnect( vm, SIGNAL( activated( SUIT_ViewManager* ) ),
852              this, SLOT( onViewManagerActivated( SUIT_ViewManager* ) ) );
853   myViewMgrs.removeAll( vm );
854
855   if ( myActiveViewMgr == vm )
856     myActiveViewMgr = 0;
857 }
858
859 /*!Remove all view managers from view managers list.*/
860 void STD_Application::clearViewManagers()
861 {
862   ViewManagerList lst;
863   viewManagers( lst );
864
865   for ( QList<SUIT_ViewManager*>::iterator it = lst.begin(); it != lst.end(); ++it )
866   {
867     QPointer<SUIT_ViewManager> vm = *it;
868     removeViewManager( vm );
869     delete vm;
870   }
871 }
872
873 /*!\retval \c true, if view manager \a vm, already in view manager list (\a myViewMgrs).*/
874 bool STD_Application::containsViewManager( SUIT_ViewManager* vm ) const
875 {
876   return myViewMgrs.contains( vm );
877 }
878
879 /*!Private slot, sets active manager to \vm, if \vm in view managers list.*/
880 void STD_Application::onViewManagerActivated( SUIT_ViewManager* vm )
881 {
882   setActiveViewManager( vm );
883 }
884
885 /*!Shows status bar, if on is \c true, else hides status bar.*/
886 void STD_Application::onViewStatusBar( bool on )
887 {
888   if ( on )
889     desktop()->statusBar()->show();
890   else
891     desktop()->statusBar()->hide();
892 }
893
894 /*!Call SUIT_MessageBox::info1(...) with about information.*/
895 void STD_Application::onHelpAbout()
896 {
897   SUIT_MessageBox::information( desktop(), tr( "About" ), tr( "ABOUT_INFO" ) );
898 }
899
900 /*!Create empty study. \n
901  * Create new view manager and adding it to view managers list.
902  */
903 void STD_Application::createEmptyStudy()
904 {
905   SUIT_Application::createEmptyStudy();
906 }
907
908 /*!Sets active manager to \vm, if \vm in view managers list.*/
909 void STD_Application::setActiveViewManager( SUIT_ViewManager* vm )
910 {
911   if ( !containsViewManager( vm ) )
912     return;
913
914   myActiveViewMgr = vm;
915   emit viewManagerActivated( vm );
916 }
917
918 /*!Public slot. */
919 void STD_Application::onConnectPopupRequest( SUIT_PopupClient* client, QContextMenuEvent* e )
920 {
921   QtxMenu* popup = new QtxMenu();
922   // fill popup by own items
923   QString title;
924   contextMenuPopup( client->popupClientType(), popup, title );
925   popup->setTitleText( title );
926
927   popup->addSeparator();
928   // add items from popup client
929   client->contextMenuPopup( popup );
930
931   SUIT_Tools::simplifySeparators( popup );
932
933   if ( !popup->actions().isEmpty() )
934     popup->exec( e->globalPos() );
935   delete popup;
936 }
937
938 /*!\retval QString - return file extension(s).*/
939 QString STD_Application::getFileFilter( bool /*open*/ ) const
940 {
941   return QString();
942 }
943
944 /*!\retval QString - return file name from dialog.*/
945 QString STD_Application::getFileName( bool open, const QString& initial, const QString& filters,
946                                       const QString& caption, QWidget* parent )
947 {
948   if ( !parent )
949     parent = desktop();
950   if ( open )
951     return QFileDialog::getOpenFileName( parent, caption, initial, filters );
952   else
953   {
954     QString aName;
955     QString aUsedFilter;
956     QString anOldPath = initial;
957
958     bool isOk = false;
959     while ( !isOk )
960     {
961       // It is preferrable to use OS-specific file dialog box here !!!
962       aName = QFileDialog::getSaveFileName( parent, caption, anOldPath, filters, &aUsedFilter );
963
964       if ( aName.isNull() )
965         isOk = true;
966       else
967       {
968         int aEnd = aUsedFilter.lastIndexOf( ')' );
969         int aStart = aUsedFilter.lastIndexOf( '(', aEnd );
970         QString wcStr = aUsedFilter.mid( aStart + 1, aEnd - aStart - 1 );
971
972         int idx = 0;
973         QStringList extList;
974         QRegExp rx( "[\b\\*]*\\.([\\w]+)" );
975         while ( ( idx = rx.indexIn( wcStr, idx ) ) != -1 )
976         {
977           extList.append( rx.cap( 1 ) );
978           idx += rx.matchedLength();
979         }
980
981         if ( !extList.isEmpty() && !extList.contains( SUIT_Tools::extension( aName ) ) )
982           aName += QString( ".%1" ).arg( extList.first() );
983
984         if ( QFileInfo( aName ).exists() )
985         {
986           int aAnswer = SUIT_MessageBox::question( desktop(), tr( "TIT_FILE_SAVEAS" ),
987                                                    tr( "MSG_FILE_EXISTS" ).arg( aName ),
988                                                    SUIT_MessageBox::Yes | SUIT_MessageBox::No | SUIT_MessageBox::Cancel, SUIT_MessageBox::Yes );
989           if ( aAnswer == SUIT_MessageBox::Cancel )
990           {     // cancelled
991             aName = QString();
992             isOk = true;
993           }
994           else if ( aAnswer == SUIT_MessageBox::No ) // not save to this file
995             anOldPath = aName;             // not to return to the same initial dir at each "while" step
996           else                     // overwrite the existing file
997             isOk = true;
998         }
999         else
1000           isOk = true;
1001       }
1002     }
1003     return aName;
1004   }
1005 }
1006
1007 /*!\retval QString - return directory name from dialog.*/
1008 QString STD_Application::getDirectory( const QString& initial, const QString& caption, QWidget* parent )
1009 {
1010   if ( !parent )
1011     parent = desktop();
1012
1013   return QFileDialog::getExistingDirectory( parent, caption, initial );
1014 }
1015
1016 /*!
1017   Changes desktop
1018   \param desk - new desktop
1019 */
1020 void STD_Application::setDesktop( SUIT_Desktop* desk )
1021 {
1022   SUIT_Application::setDesktop( desk );
1023
1024   if ( desk ) {
1025     connect( desk, SIGNAL( closing( SUIT_Desktop*, QCloseEvent* ) ),
1026              this, SLOT( onDesktopClosing( SUIT_Desktop*, QCloseEvent* ) ), Qt::UniqueConnection );
1027   }
1028 }
1029
1030 /*!
1031   Allow to load preferences before the desktop will be shown.
1032 */
1033 void STD_Application::loadPreferences()
1034 {
1035 }
1036
1037 /*!
1038   Allow to save preferences before the application will be closed.
1039 */
1040 void STD_Application::savePreferences()
1041 {
1042 }
1043
1044 /*!
1045   Custom activity after study is created
1046   Updates desktop and actions
1047 */
1048 void STD_Application::studyCreated( SUIT_Study* )
1049 {
1050   updateDesktopTitle();
1051   updateCommandsStatus();
1052 }
1053
1054 /*!
1055   Custom activity after study is opened
1056   Updates desktop and actions
1057 */
1058 void STD_Application::studyOpened( SUIT_Study* )
1059 {
1060   updateDesktopTitle();
1061   updateCommandsStatus();
1062 }
1063
1064 /*!
1065   Custom activity after study is opened
1066   Updates desktop and actions
1067 */
1068 void STD_Application::studySaved( SUIT_Study* )
1069 {
1070   updateDesktopTitle();
1071   updateCommandsStatus();
1072 }
1073
1074 /*!
1075   Return index of the view ma
1076 */
1077 int STD_Application::viewManagerId( const SUIT_ViewManager* theManager) const
1078 {
1079   return myViewMgrs.indexOf(const_cast<SUIT_ViewManager*>(theManager));
1080 }
1081
1082 /*!
1083   \brief Abort active operations if there are any
1084   \return \c false if some operation cannot be aborted
1085 */
1086 bool STD_Application::abortAllOperations()
1087 {
1088   return true;
1089 }
1090
1091 /*!
1092   \brief Gets the notification manager. Creates it if not exists.
1093   \return \c notification manager instance
1094 */
1095 QtxNotify* STD_Application::notifyMgr()
1096 {
1097   if ( !myNotify )
1098   {
1099     myNotify = new QtxNotify(desktop());
1100     myNotify->setWindow(desktop());
1101
1102     SUIT_ResourceMgr* aResMgr = resourceMgr();
1103     if (aResMgr)
1104     {
1105       int anim = aResMgr->integerValue("notification", "animation", 0);
1106       myNotify->setAnimationTime(anim);
1107
1108       double size = aResMgr->integerValue("notification", "size", 250);
1109       myNotify->setNotificationSize(size);
1110     }
1111   }
1112   return myNotify;
1113 }