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