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