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