Salome HOME
Control for the status of the document opening. Function useFile return boolean value.
[modules/gui.git] / src / STD / STD_Application.cxx
1 #include "STD_Application.h"
2
3 #include "STD_MDIDesktop.h"
4
5 #include <SUIT_Tools.h>
6 #include <SUIT_Desktop.h>
7 #include <SUIT_Session.h>
8 #include <SUIT_ViewModel.h>
9 #include <SUIT_Operation.h>
10 #include <SUIT_MessageBox.h>
11 #include <SUIT_ResourceMgr.h>
12
13 #include <QtxDockAction.h>
14 #include <QtxActionMenuMgr.h>
15 #include <QtxActionToolMgr.h>
16 #include <QtxPopupMenu.h>
17
18 #include <qmenubar.h>
19 #include <qtoolbar.h>
20 #include <qpopupmenu.h>
21 #include <qstatusbar.h>
22 #include <qfiledialog.h>
23 #include <qapplication.h>
24
25 extern "C" STD_EXPORT SUIT_Application* createApplication()
26 {
27   return new STD_Application();
28 }
29
30 STD_Application::STD_Application()
31 : SUIT_Application(),
32 myEditEnabled( true ),
33 myActiveViewMgr( 0 )
34 {
35   STD_MDIDesktop* desk = new STD_MDIDesktop();
36
37   connect( desk, SIGNAL( closing( SUIT_Desktop*, QCloseEvent* ) ),
38            this, SLOT( onDesktopClosing( SUIT_Desktop*, QCloseEvent* ) ) );
39
40   setDesktop( desk );
41 }
42
43 STD_Application::~STD_Application()
44 {
45 }
46
47 QString STD_Application::applicationName() const
48 {
49   return QString( "StdApplication" );
50 }
51
52 void STD_Application::start()
53 {
54   createActions();
55
56   updateDesktopTitle();
57   updateCommandsStatus();
58   setEditEnabled( myEditEnabled );
59
60   SUIT_Application::start();
61 }
62
63 void STD_Application::onDesktopClosing( SUIT_Desktop*, QCloseEvent* e )
64 {
65   if ( !isPossibleToClose() )
66   {
67     e->ignore();
68     return;
69   }
70
71   SUIT_Study* study = activeStudy();
72
73   if ( study )
74     study->closeDocument();
75
76   setActiveStudy( 0 );
77   delete study;
78
79   setDesktop( 0 );
80
81   closeApplication();
82 }
83
84 void STD_Application::createActions()
85 {
86   SUIT_Desktop* desk = desktop();
87   SUIT_ResourceMgr* resMgr = resourceMgr();
88   if ( !desk || !resMgr )
89     return;
90
91   // Create actions
92
93   createAction( FileNewId, tr( "TOT_DESK_FILE_NEW" ),
94                 resMgr->loadPixmap( "STD", tr( "ICON_FILE_NEW" ) ),
95                 tr( "MEN_DESK_FILE_NEW" ), tr( "PRP_DESK_FILE_NEW" ),
96                 CTRL+Key_N, desk, false, this, SLOT( onNewDoc() ) );
97
98   createAction( FileOpenId, tr( "TOT_DESK_FILE_OPEN" ),
99                 resMgr->loadPixmap( "STD", tr( "ICON_FILE_OPEN" ) ),
100                 tr( "MEN_DESK_FILE_OPEN" ), tr( "PRP_DESK_FILE_OPEN" ),
101                 CTRL+Key_O, desk, false, this, SLOT( onOpenDoc() ) );
102
103   createAction( FileCloseId, tr( "TOT_DESK_FILE_CLOSE" ),
104                 resMgr->loadPixmap( "STD", tr( "ICON_FILE_CLOSE" ) ),
105                 tr( "MEN_DESK_FILE_CLOSE" ), tr( "PRP_DESK_FILE_CLOSE" ),
106                 CTRL+Key_W, desk, false, this, SLOT( onCloseDoc() ) );
107
108   createAction( FileExitId, tr( "TOT_DESK_FILE_EXIT" ), QIconSet(),
109                 tr( "MEN_DESK_FILE_EXIT" ), tr( "PRP_DESK_FILE_EXIT" ),
110                 CTRL+Key_Q, desk, false, this, SLOT( onExit() ) );
111
112   createAction( FileSaveId, tr( "TOT_DESK_FILE_SAVE" ),
113                 resMgr->loadPixmap( "STD", tr( "ICON_FILE_SAVE" ) ),
114                 tr( "MEN_DESK_FILE_SAVE" ), tr( "PRP_DESK_FILE_SAVE" ),
115                 CTRL+Key_S, desk, false, this, SLOT( onSaveDoc() ) );
116
117   createAction( FileSaveAsId, tr( "TOT_DESK_FILE_SAVEAS" ), QIconSet(),
118                 tr( "MEN_DESK_FILE_SAVEAS" ), tr( "PRP_DESK_FILE_SAVEAS" ),
119                 0, desk, false, this, SLOT( onSaveAsDoc() ) );
120
121   createAction( EditCutId, tr( "TOT_DESK_EDIT_CUT" ),
122                 resMgr->loadPixmap( "STD", tr( "ICON_EDIT_CUT" ) ),
123                 tr( "MEN_DESK_EDIT_CUT" ), tr( "PRP_DESK_EDIT_CUT" ),
124                 CTRL+Key_X, desk, false, this, SLOT( onCut() ) );
125
126   createAction( EditCopyId, tr( "TOT_DESK_EDIT_COPY" ),
127                 resMgr->loadPixmap( "STD", tr( "ICON_EDIT_COPY" ) ),
128                 tr( "MEN_DESK_EDIT_COPY" ), tr( "PRP_DESK_EDIT_COPY" ),
129                 CTRL+Key_C, desk, false, this, SLOT( onCopy() ) );
130
131   createAction( EditPasteId, tr( "TOT_DESK_EDIT_PASTE" ),
132                 resMgr->loadPixmap( "STD", tr( "ICON_EDIT_PASTE" ) ),
133                 tr( "MEN_DESK_EDIT_PASTE" ), tr( "PRP_DESK_EDIT_PASTE" ),
134                 CTRL+Key_V, desk, false, this, SLOT( onPaste() ) );
135
136   QAction* a = createAction( ViewStatusBarId, tr( "TOT_DESK_VIEW_STATUSBAR" ),
137                              QIconSet(), tr( "MEN_DESK_VIEW_STATUSBAR" ),
138                              tr( "PRP_DESK_VIEW_STATUSBAR" ), 0, desk, true );
139   a->setOn( desk->statusBar()->isVisibleTo( desk ) );
140   connect( a, SIGNAL( toggled( bool ) ), this, SLOT( onViewStatusBar( bool ) ) );
141
142   createAction( NewWindowId, tr( "TOT_DESK_NEWWINDOW" ), QIconSet(),
143                 tr( "MEN_DESK_NEWWINDOW" ), tr( "PRP_DESK_NEWWINDOW" ), 0, desk  );
144
145   createAction( HelpAboutId, tr( "TOT_DESK_HELP_ABOUT" ), QIconSet(),
146                 tr( "MEN_DESK_HELP_ABOUT" ), tr( "PRP_DESK_HELP_ABOUT" ),
147                 0, desk, false, this, SLOT( onHelpAbout() ) );
148
149   QtxDockAction* da = new QtxDockAction( tr( "TOT_DOCK_WINDOWS" ), tr( "MEN_DOCK_WINDOWS" ), desk );
150   registerAction( ViewWindowsId, da );
151   da->setAutoPlace( false );
152
153   // Create menus
154
155   int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1, -1, 0 );
156   int editMenu = createMenu( tr( "MEN_DESK_EDIT" ), -1, -1, 10 );
157   int viewMenu = createMenu( tr( "MEN_DESK_VIEW" ), -1, -1, 10 );
158   int helpMenu = createMenu( tr( "MEN_DESK_HELP" ), -1, -1, 1000 );
159
160   // Create menu items
161
162   createMenu( FileNewId, fileMenu, 0 );
163   createMenu( FileOpenId, fileMenu, 0 );
164   createMenu( FileCloseId, fileMenu, 0 );
165   createMenu( separator(), fileMenu, -1, 0 );
166   createMenu( FileSaveId, fileMenu, 0 );
167   createMenu( FileSaveAsId, fileMenu, 0 );
168   createMenu( separator(), fileMenu, -1, 0 );
169
170   createMenu( separator(), fileMenu );
171   createMenu( FileExitId, fileMenu );
172
173   createMenu( EditCutId, editMenu );
174   createMenu( EditCopyId, editMenu );
175   createMenu( EditPasteId, editMenu );
176   createMenu( separator(), editMenu );
177
178   createMenu( ViewWindowsId, viewMenu );
179   createMenu( ViewStatusBarId, viewMenu );
180   createMenu( separator(), viewMenu );
181
182   createMenu( HelpAboutId, helpMenu );
183   createMenu( separator(), helpMenu );
184
185   // Create tool bars
186
187   int stdTBar = createTool( tr( "INF_DESK_TOOLBAR_STANDARD" ) );
188
189   // Create tool items
190
191   createTool( FileNewId, stdTBar );
192   createTool( FileOpenId, stdTBar );
193   createTool( FileSaveId, stdTBar );
194   createTool( FileCloseId, stdTBar );
195   createTool( separator(), stdTBar );
196   createTool( EditCutId, stdTBar );
197   createTool( EditCopyId, stdTBar );
198   createTool( EditPasteId, stdTBar );
199 }
200
201 /*!
202   Opens new application
203 */
204 void STD_Application::onNewDoc() 
205 {
206   if ( !activeStudy() )
207   {
208     createEmptyStudy();
209     activeStudy()->createDocument();
210     updateDesktopTitle();
211     updateCommandsStatus();
212   }
213   else
214   {
215     SUIT_Application* aApp = startApplication( 0, 0 );
216     if ( aApp->inherits( "STD_Application" ) )
217       ((STD_Application*)aApp)->onNewDoc();
218     else {
219       aApp->createEmptyStudy();
220       aApp->activeStudy()->createDocument();
221     }
222   }
223 }
224
225 void STD_Application::onOpenDoc()
226 {
227   // It is preferrable to use OS-specific file dialog box here !!!
228   QString aName = getFileName( true, QString::null, getFileFilter(), QString::null, 0 );
229   if ( aName.isNull() )
230     return;
231
232   onOpenDoc( aName );
233 }
234
235 bool STD_Application::onOpenDoc( const QString& aName )
236 {
237   bool res = true;
238   if ( !activeStudy() )
239   {
240     // if no study - open in current desktop
241     createEmptyStudy();
242     res = activeStudy()->openDocument( aName );
243     updateDesktopTitle();
244     updateCommandsStatus();
245   }
246   else
247   {
248     // if study exists - open in new desktop. Check: is the same file is opened?
249     SUIT_Session* aSession = SUIT_Session::session();
250     QPtrList<SUIT_Application> aAppList = aSession->applications();
251     bool isAlreadyOpen = false;
252     SUIT_Application* aApp = 0;
253     for ( QPtrListIterator<SUIT_Application> it( aAppList ); it.current() && !isAlreadyOpen; ++it )
254     {
255       aApp = it.current();
256       if ( aApp->activeStudy()->studyName() == aName )
257         isAlreadyOpen = true;
258     }
259     if ( !isAlreadyOpen )
260     {
261       aApp = startApplication( 0, 0 );
262       if ( aApp )
263         res = aApp->useFile( aName );
264     }
265     else
266       aApp->desktop()->setActiveWindow();
267   }
268   return res;
269 }
270
271 void STD_Application::beforeCloseDoc( SUIT_Study* )
272 {
273 }
274
275 void STD_Application::afterCloseDoc()
276 {
277 }
278
279 void STD_Application::onCloseDoc()
280 {
281   if ( !isPossibleToClose() )
282     return;
283
284   SUIT_Study* study = activeStudy();
285
286   beforeCloseDoc( study );
287
288   if ( study )
289     study->closeDocument();
290
291   clearViewManagers();
292
293   setActiveStudy( 0 );
294   delete study;
295
296   int aNbStudies = 0;
297   QPtrList<SUIT_Application> apps = SUIT_Session::session()->applications();
298   for ( unsigned i = 0; i < apps.count(); i++ )
299     aNbStudies += apps.at( i )->getNbStudies();
300
301   // STV: aNbStudies - number of currently existing studies (exclude currently closed)
302   // STV: aNbStudies should be compared with 0.
303   if ( aNbStudies )
304     setDesktop( 0 );
305   else
306   {
307     updateDesktopTitle();
308     updateCommandsStatus();
309   }
310
311   afterCloseDoc();
312
313   if ( !desktop() )
314     closeApplication();
315 }
316
317 bool STD_Application::isPossibleToClose()
318 {
319   if ( activeStudy() )
320   {
321     activeStudy()->abortAllOperations();
322     if ( activeStudy()->isModified() )
323     {
324       QString sName = activeStudy()->studyName().stripWhiteSpace();
325       QString msg = sName.isEmpty() ? tr( "INF_DOC_MODIFIED" ) : tr ( "INF_DOCUMENT_MODIFIED" ).arg( sName );
326       int aAnswer = SUIT_MessageBox::warn3( desktop(), tr( "TOT_DESK_FILE_CLOSE" ), msg,
327                                             tr( "BUT_YES" ), tr( "BUT_NO" ), tr( "BUT_CANCEL" ), 1, 2, 3, 1 );
328       switch ( aAnswer )
329       {
330       case 1:
331         if ( !activeStudy()->isSaved() )
332           if ( !onSaveAsDoc() )
333             return false;
334         else
335           onSaveDoc();
336         break;
337       case 2:
338         break;
339       case 3:
340       default:
341         return false;
342       }
343     }
344   }
345   return true;
346 }
347
348 void STD_Application::onSaveDoc()
349 {
350   if ( !activeStudy() )
351     return;
352
353   bool isOk = false;
354   if ( activeStudy()->isSaved() )
355   {
356     isOk = activeStudy()->saveDocument();
357     if ( !isOk )
358       SUIT_MessageBox::error1( desktop(), tr( "TIT_FILE_SAVEAS" ),
359                                tr( "MSG_CANT_SAVE" ).arg( activeStudy()->studyName() ), tr( "BUT_OK" ) );
360   }
361
362   if ( isOk )
363     updateCommandsStatus();
364   else
365     onSaveAsDoc();
366 }
367
368 bool STD_Application::onSaveAsDoc()
369 {
370   SUIT_Study* study = activeStudy();
371   if ( !study )
372     return false;
373
374   QString aName = getFileName( false, study->studyName(), getFileFilter(), QString::null, 0 );
375
376   if ( aName.isNull() ) 
377     return false;
378   bool isOk = study->saveDocumentAs( aName );
379
380   updateDesktopTitle();
381   updateCommandsStatus();
382
383   return isOk;
384 }
385
386 void STD_Application::onExit()
387 {
388   SUIT_Session::session()->closeSession();
389 }
390
391 void STD_Application::onCut()
392 {
393 }
394
395 void STD_Application::onCopy()
396 {
397 }
398
399 void STD_Application::onPaste()
400 {
401 }
402
403 void STD_Application::setEditEnabled( bool theEnable )
404 {
405   myEditEnabled = theEnable;
406
407   QtxActionMenuMgr* mMgr = desktop()->menuMgr();
408   QtxActionToolMgr* tMgr = desktop()->toolMgr();
409
410   for ( int i = EditCutId; i <= EditPasteId; i++ )
411   {
412     mMgr->setShown( i, myEditEnabled );
413     tMgr->setShown( i, myEditEnabled );
414   }
415 }
416
417 bool STD_Application::useFile(const QString& theFileName)
418 {
419   bool res = SUIT_Application::useFile(theFileName);
420   updateDesktopTitle();
421   updateCommandsStatus();
422   return res;
423 }
424
425 void STD_Application::updateDesktopTitle()
426 {
427   QString aTitle = applicationName();
428   QString aVer = applicationVersion();
429   if ( !aVer.isEmpty() )
430     aTitle += QString( " " ) + aVer;
431
432   if ( activeStudy() )
433   {
434     QString sName = SUIT_Tools::file( activeStudy()->studyName().stripWhiteSpace(), false );
435     if ( !sName.isEmpty() )
436       aTitle += QString( " - [%1]" ).arg( sName );
437   }
438
439   desktop()->setCaption( aTitle );
440 }
441
442 void STD_Application::updateCommandsStatus()
443 {
444   bool aHasStudy = activeStudy() != 0;
445   bool aIsNeedToSave = false;
446   if ( aHasStudy ) 
447     aIsNeedToSave = !activeStudy()->isSaved() || activeStudy()->isModified();
448
449   if ( action( FileSaveId ) )
450     action( FileSaveId )->setEnabled( aIsNeedToSave );
451   if ( action( FileSaveAsId ) )
452     action( FileSaveAsId )->setEnabled( aHasStudy );
453   if ( action( FileCloseId ) )
454     action( FileCloseId )->setEnabled( aHasStudy );
455   if ( action( NewWindowId ) )
456     action( NewWindowId )->setEnabled( aHasStudy );
457 }
458
459 SUIT_ViewManager* STD_Application::viewManager( const QString& vmType ) const
460 {
461   SUIT_ViewManager* vm = 0;
462   for ( QPtrListIterator<SUIT_ViewManager> it( myViewMgrs ); it.current() && !vm; ++it )
463   {
464     if ( it.current()->getType() == vmType )
465       vm = it.current();
466   }
467   return vm;
468 }
469
470 void STD_Application::viewManagers( const QString& vmType, ViewManagerList& lst ) const
471 {
472   for ( QPtrListIterator<SUIT_ViewManager> it( myViewMgrs ); it.current(); ++it )
473     if ( it.current()->getType() == vmType )
474       lst.append( it.current() );
475 }
476
477 void STD_Application::viewManagers( ViewManagerList& lst ) const
478 {
479   for ( QPtrListIterator<SUIT_ViewManager> it( myViewMgrs ); it.current(); ++it )
480     lst.append( it.current() );
481 }
482
483 ViewManagerList STD_Application::viewManagers() const
484 {
485   ViewManagerList lst;
486   viewManagers( lst );
487   return lst;
488 }
489
490 SUIT_ViewManager* STD_Application::activeViewManager() const
491 {
492   return myActiveViewMgr;
493 }
494
495 void STD_Application::addViewManager( SUIT_ViewManager* vm )
496 {
497   if ( !vm )
498     return;
499
500   if ( !containsViewManager( vm ) )
501   {
502     myViewMgrs.append( vm );
503     connect( vm, SIGNAL( activated( SUIT_ViewManager* ) ),
504              this, SLOT( onViewManagerActivated( SUIT_ViewManager* ) ) );
505     vm->connectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
506
507     emit viewManagerAdded( vm );
508   }
509 /*
510   if ( !activeViewManager() && myViewMgrs.count() == 1 )
511     setActiveViewManager( vm );
512 */
513 }
514
515 void STD_Application::removeViewManager( SUIT_ViewManager* vm )
516 {
517   if ( !vm )
518     return;
519
520   vm->closeAllViews();
521
522   emit viewManagerRemoved( vm );
523
524   vm->disconnectPopupRequest( this, SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
525   vm->disconnect();
526   myViewMgrs.removeRef( vm );
527
528   if ( myActiveViewMgr == vm )
529     myActiveViewMgr = 0;
530 }
531
532 void STD_Application::clearViewManagers()
533 {
534   ViewManagerList lst;
535   viewManagers( lst );
536
537   for ( QPtrListIterator<SUIT_ViewManager> it( lst ); it.current(); ++it )
538     removeViewManager( it.current() );
539 }
540
541 bool STD_Application::containsViewManager( SUIT_ViewManager* vm ) const
542 {
543   return myViewMgrs.contains( vm ) > 0;
544 }
545
546 void STD_Application::onViewManagerActivated( SUIT_ViewManager* vm )
547 {
548   setActiveViewManager( vm );
549 }
550
551 void STD_Application::onViewStatusBar( bool on )
552 {
553   if ( on )
554     desktop()->statusBar()->show();
555   else
556     desktop()->statusBar()->hide();
557 }
558
559 void STD_Application::onHelpAbout()
560 {
561   SUIT_MessageBox::info1( desktop(), tr( "About" ), tr( "ABOUT_INFO" ), "&OK" );
562 }
563
564 void STD_Application::createEmptyStudy()
565 {
566   SUIT_Application::createEmptyStudy();
567
568   SUIT_ViewManager* vm = new SUIT_ViewManager( activeStudy(), desktop(), new SUIT_ViewModel() );
569
570   addViewManager( vm );
571 }
572
573 void STD_Application::setActiveViewManager( SUIT_ViewManager* vm )
574 {
575   if ( !containsViewManager( vm ) )
576     return;
577
578   myActiveViewMgr = vm;
579   emit viewManagerActivated( vm );
580 }
581
582 void STD_Application::onConnectPopupRequest( SUIT_PopupClient* client, QContextMenuEvent* e )
583 {
584   QtxPopupMenu* popup = new QtxPopupMenu();
585   // fill popup by own items
586   QString title;
587   contextMenuPopup( client->popupClientType(), popup, title );
588   popup->setTitleText( title );
589
590   popup->insertSeparator();
591   // add items from popup client
592   client->contextMenuPopup( popup );
593   
594   SUIT_Tools::simplifySeparators( popup );
595
596   if ( popup->count() )
597     popup->exec( e->globalPos() );
598   delete popup;
599 }
600
601 QString STD_Application::getFileName( bool open, const QString& initial, const QString& filters, 
602                                       const QString& caption, QWidget* parent )
603 {
604   if ( !parent )
605     parent = desktop();
606   QStringList fls = QStringList::split( ";", filters, false );
607   if ( open ) 
608   {
609     return QFileDialog::getOpenFileName( initial, fls.join( ";;" ), parent, 0, caption );
610   }
611   else
612   {
613     QString aName;
614     QString aUsedFilter;
615     QString anOldPath = initial;
616
617     bool isOk = false;
618     while ( !isOk )
619     {
620       // It is preferrable to use OS-specific file dialog box here !!!
621       aName = QFileDialog::getSaveFileName( anOldPath, fls.join( ";;" ), parent,
622                                             0, caption, &aUsedFilter);
623
624       if ( aName.isNull() )
625         isOk = true;
626       else
627       {
628         if ( !getFileFilter().isNull() ) // check extension and add if it is necessary
629         {
630           int aStart = aUsedFilter.find( '*' );
631           int aEnd = aUsedFilter.find( ')', aStart + 1 );
632           QString aExt = aUsedFilter.mid( aStart + 1, aEnd - aStart - 1 );
633           if ( aExt.contains( '*' ) == 0 ) // if it is not *.*
634           {
635             // Check that there is an extension at the end of the name
636             QString aNameTail = aName.right( aExt.length() );
637             if ( aNameTail != aExt )
638               aName += aExt;
639           }
640         }
641         if ( QFileInfo( aName ).exists() )
642         {
643           int aAnswer = SUIT_MessageBox::warn3( desktop(), tr( "TIT_FILE_SAVEAS" ),
644                                                 tr( "MSG_FILE_EXISTS" ).arg( aName ),
645                                                 tr( "BUT_YES" ), tr( "BUT_NO" ), tr( "BUT_CANCEL" ), 1, 2, 3, 1 );
646           if ( aAnswer == 3 ) {     // cancelled
647             aName = QString::null;
648             isOk = true;
649           }
650           else if ( aAnswer == 2 ) // not save to this file
651             anOldPath = aName;             // not to return to the same initial dir at each "while" step
652           else                     // overwrite the existing file
653             isOk = true;
654         }
655         else
656           isOk = true;
657       }
658     }
659     return aName;
660   }
661 }