Salome HOME
Merge branch 'pre/V8_3_BR'
[modules/gui.git] / src / SUIT / SUIT_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 "SUIT_Application.h"
24
25 #include "SUIT_Study.h"
26 #include "SUIT_Session.h"
27 #include "SUIT_Desktop.h"
28 #include "SUIT_ResourceMgr.h"
29 #include "SUIT_ShortcutMgr.h"
30
31 #include <QTimer>
32 #include <QLabel>
33 #include <QStatusBar>
34 #include <QApplication>
35 #include <QSize>
36
37 #include <QtxAction.h>
38 #include <QtxActionMenuMgr.h>
39 #include <QtxActionToolMgr.h>
40
41
42 /*!
43   \class StatusLabel
44   \brief Status bar customization label. Used to workaroubd desktop resizing bug.
45   \internal
46 */
47 class StatusLabel : public QLabel
48 {
49 public:
50   StatusLabel( QWidget* parent ) : QLabel( parent ) {}
51   QSize minimumSizeHint () const { return QSize( 0, QLabel::minimumSizeHint().height() ); }
52 };
53
54 /*!
55   Default constructor
56 */
57 SUIT_Application::SUIT_Application()
58 : QObject( 0 ),
59   myStudy( 0 ),
60   myDesktop( 0 ),
61   myStatusLabel( 0 ),
62   myPostRoutines( QList<PostRoutine>() )
63 {
64   if ( SUIT_Session::session() )
65     SUIT_Session::session()->insertApplication( this );
66 }
67
68 /*!
69   Destructor
70 */
71 SUIT_Application::~SUIT_Application()
72 {
73   SUIT_Study* s = myStudy;
74   setActiveStudy( 0 );
75   delete s;
76
77   setDesktop( 0 );
78
79   foreach ( PostRoutine routine, myPostRoutines )
80     routine();
81 }
82
83 /*!
84   \return main window of application (desktop)
85 */
86 SUIT_Desktop* SUIT_Application::desktop()
87 {
88   return myDesktop;
89 }
90
91 /*!
92    \return \c false if application can not be closed (because of non saved data for example).
93    This method called by SUIT_Session when closing of application was requested.
94 */
95 bool SUIT_Application::isPossibleToClose( bool& )
96 {
97   return true;
98 }
99
100 /*!
101   Performs some finalization of life cycle of this application.
102   For instance, the application can force its documents(s) to close.
103 */
104 void SUIT_Application::closeApplication()
105 {
106   emit applicationClosed( this );
107 }
108
109 /*!
110   \return active Study. If Application supports wirking with several studies this method should be redefined
111 */
112 SUIT_Study* SUIT_Application::activeStudy() const
113 {
114   return myStudy;
115 }
116
117 /*!
118   \return version of application
119 */
120 QString SUIT_Application::applicationVersion() const
121 {
122   return QString();
123 }
124
125 /*!
126   Shows the application's main widget. For non GUI application must be redefined.
127 */
128 void SUIT_Application::start()
129 {
130   if ( desktop() )
131     desktop()->show();
132
133   // Initialize shortcut manager
134   SUIT_ShortcutMgr::Init();
135 }
136
137 /*!
138   Opens document into active Study. If Study is empty - creates it.
139   \param theFileName - name of document file
140 */
141 bool SUIT_Application::useFile( const QString& theFileName )
142 {
143   createEmptyStudy();
144   SUIT_Study* study = activeStudy();
145
146   bool status = study ? study->openDocument( theFileName ) : false;
147
148   if ( !status )
149   {
150     setActiveStudy( 0 );
151     delete study;
152   }
153
154   return status;
155 }
156
157 /*!
158   Creates new empty Study if active Study = 0
159 */
160 void SUIT_Application::createEmptyStudy()
161 {
162   if ( !activeStudy() )
163     setActiveStudy( createNewStudy() );
164 }
165
166 /*!
167   \return number of Studies.
168   Must be redefined in Applications which support several studies for one Application instance.
169 */
170 int SUIT_Application::getNbStudies() const
171 {
172   return activeStudy() ? 1 : 0;
173 }
174
175 /*!
176   \return global resource manager
177 */
178 SUIT_ResourceMgr* SUIT_Application::resourceMgr() const
179 {
180   if ( !SUIT_Session::session() )
181     return 0;
182
183   return SUIT_Session::session()->resourceMgr();
184 }
185
186 /*!
187   \brief Get access to shortcut manager.
188   \return global shortcut manager
189 */
190 SUIT_ShortcutMgr* SUIT_Application::shortcutMgr() const
191 {
192   return SUIT_ShortcutMgr::getShortcutMgr();
193 }
194
195 #define DEFAULT_MESSAGE_DELAY 3000
196
197 /*!
198   Puts the message to the status bar
199   \param msg - text of message
200   \param msec - time in milliseconds, after that the status label will be cleared
201 */
202 void SUIT_Application::putInfo( const QString& msg, const int msec )
203 {
204   if ( !desktop() )
205     return;
206
207   if ( !myStatusLabel )
208   {
209     myStatusLabel = new StatusLabel( desktop()->statusBar() );
210     desktop()->statusBar()->addWidget( myStatusLabel, 1 );
211     myStatusLabel->show();
212   }
213
214   QString prev = myStatusLabel->text();
215
216   myStatusLabel->setText( msg );
217   if ( msec != -1 )
218     QTimer::singleShot( msec <= 0 ? DEFAULT_MESSAGE_DELAY : msec, this, SLOT( onInfoClear() ) );
219
220   if ( prev != msg )
221     emit infoChanged( msg );
222 }
223
224 /*!
225   Clear the information label in status bar after delay.
226 */
227 void SUIT_Application::onInfoClear()
228 {
229   if ( !myStatusLabel )
230     return;
231
232   bool changed = !myStatusLabel->text().isEmpty();
233   myStatusLabel->clear();
234   if ( changed )
235     emit infoChanged( QString() );
236 }
237
238 /*!
239   Update status of the registerd actions
240 */
241 void SUIT_Application::updateCommandsStatus()
242 {
243 }
244
245 /*!
246   Initialize with application arguments
247   \param argc - number of application arguments
248   \param argv - array of application arguments
249 */
250 SUIT_Application* SUIT_Application::startApplication( int argc, char** argv ) const
251 {
252   return startApplication( objectName(), argc, argv );
253 }
254
255 /*!
256   Initialize with application name and arguments
257   \param name - name of application
258   \param argc - number of application arguments
259   \param argv - array of application arguments
260 */
261 SUIT_Application* SUIT_Application::startApplication( const QString& name, int argc, char** argv ) const
262 {
263   SUIT_Session* session = SUIT_Session::session();
264   if ( !session )
265     return 0;
266
267   return session->startApplication( name, argc, argv );
268 }
269
270 /*!
271   Sets the main window of application
272   \param desk - new main window (desktop)
273 */
274 void SUIT_Application::setDesktop( SUIT_Desktop* desk )
275 {
276   if ( myDesktop == desk )
277     return;
278
279   // >> VSR 09/06/2009: workaround about the Qt 4.5.0 bug: SIGSEGV on desktop delete
280   myDesktop->deleteLater(); // delete myDesktop;
281   // << VSR 09/06/2009
282   myDesktop = desk;
283   if ( myDesktop ) {
284     connect( myDesktop, SIGNAL( activated() ), this, SLOT( onDesktopActivated() ) );
285 //    connect( myDesktop, SIGNAL( moved() ), this, SLOT( onDesktopMoved() ) );
286     // Force desktop activation (NPAL16628)
287     QApplication::postEvent(myDesktop, new QEvent(QEvent::WindowActivate));
288   }
289 }
290
291 /*!
292   Creates new instance of study.
293   By default, it is called from createEmptyStudy()
294   \sa createEmptyStudy()
295 */
296 SUIT_Study* SUIT_Application::createNewStudy()
297 {
298   return new SUIT_Study( this );
299 }
300
301 /*!
302   Sets study as active
303   \param study - instance of study to be set as active
304 */
305 void SUIT_Application::setActiveStudy( SUIT_Study* study )
306 {
307   if ( myStudy == study )
308     return;
309
310   if ( myStudy )
311     disconnect( myStudy, SIGNAL( studyModified( SUIT_Study* ) ),
312                 this, SLOT( updateCommandsStatus() ) );
313   if ( study )
314     connect( study, SIGNAL( studyModified( SUIT_Study* ) ),
315              this, SLOT( updateCommandsStatus() ) );
316
317   myStudy = study;
318 }
319
320 /*!
321   Creates new toolbar
322   \return identificator of new toolbar in tool manager
323   \param title - title of new toolbar
324   \param name - name (identifier) of new toolbar
325 */
326 int SUIT_Application::createTool( const QString& title, const QString& name )
327 {
328   if ( !desktop() || !desktop()->toolMgr() )
329     return -1;
330
331   return desktop()->toolMgr()->createToolBar( title, name );
332 }
333
334 /*!
335   Creates new toolbutton
336   \return SUIT identificator of new action
337   \param a - action
338   \param tBar - identificator of toolbar
339   \param id - proposed SUIT identificator of action (if it is -1, then must be use any free)
340   \param idx - index in toolbar
341 */
342 int SUIT_Application::createTool( QAction* a, const int tBar, const int id, const int idx )
343 {
344   if ( !desktop() || !desktop()->toolMgr() )
345     return -1;
346
347   int regId = registerAction( id, a );
348   int intId = desktop()->toolMgr()->insert( a, tBar, idx );
349   return intId != -1 ? regId : -1;
350 }
351
352 /*!
353   Creates new toolbutton
354   \return SUIT identificator of new action
355   \param a - action
356   \param tBar - name of toolbar
357   \param id - proposed SUIT identificator of action (if it is -1, then must be use any free)
358   \param idx - index in toolbar
359 */
360 int SUIT_Application::createTool( QAction* a, const QString& tBar, const int id, const int idx )
361 {
362   if ( !desktop() || !desktop()->toolMgr() )
363     return -1;
364
365   int regId = registerAction( id, a );
366   int intId = desktop()->toolMgr()->insert( a, tBar, idx );
367   return intId != -1 ? regId : -1;
368 }
369
370 /*!
371   Creates new toolbutton
372   \return "id" if all right or -1 otherwise
373   \param id - SUIT identificator of action
374   \param tBar - identificator of toolbar
375   \param idx - index in toolbar
376 */
377 int SUIT_Application::createTool( const int id, const int tBar, const int idx )
378 {
379   if ( !desktop() || !desktop()->toolMgr() )
380     return -1;
381
382   int intId = desktop()->toolMgr()->insert( action( id ), tBar, idx );
383   return intId != -1 ? id : -1;
384 }
385
386 /*!
387   Creates new toolbutton
388   \return "id" if all right or -1 otherwise
389   \param id - SUIT identificator of action
390   \param tBar - name of toolbar
391   \param idx - index in toolbar
392 */
393 int SUIT_Application::createTool( const int id, const QString& tBar, const int idx )
394 {
395   if ( !desktop() || !desktop()->toolMgr() )
396     return -1;
397
398   int intId = desktop()->toolMgr()->insert( action( id ), tBar, idx );
399   return intId != -1 ? id : -1;
400 }
401
402 /*!
403   Creates new menu item
404   \return identificator of new action in menu manager
405   \param subMenu - menu text of new item
406   \param menu - identificator of parent menu item
407   \param id - proposed identificator of action
408   \param group - group in menu manager
409   \param index - index in menu
410 */
411 int SUIT_Application::createMenu( const QString& subMenu, const int menu,
412                                   const int id, const int group, const int index )
413 {
414   if ( !desktop() || !desktop()->menuMgr() )
415     return -1;
416
417   return desktop()->menuMgr()->insert( subMenu, menu, group, id, index );
418 }
419
420 /*!
421   Creates new menu item
422   \return identificator of new action in menu manager
423   \param subMenu - menu text of new item
424   \param menu - menu text of parent menu item
425   \param id - proposed identificator of action
426   \param group - group in menu manager
427   \param index - index in menu
428 */
429 int SUIT_Application::createMenu( const QString& subMenu, const QString& menu,
430                                   const int id, const int group, const int index )
431 {
432   if ( !desktop() || !desktop()->menuMgr() )
433     return -1;
434
435   return desktop()->menuMgr()->insert( subMenu, menu, group, id, index );
436 }
437
438 /*!
439   Creates new menu item
440   \return SUIT identificator of new action
441   \param a - action
442   \param menu - identificator of parent menu item
443   \param id - proposed SUIT identificator of action
444   \param group - group in menu manager
445   \param index - index in menu
446 */
447 int SUIT_Application::createMenu( QAction* a, const int menu, const int id, const int group, const int index )
448 {
449   if ( !a || !desktop() || !desktop()->menuMgr() )
450     return -1;
451
452   int regId = registerAction( id, a );
453   int intId = desktop()->menuMgr()->insert( a, menu, group, index );
454   return intId != -1 ? regId : -1;
455 }
456
457 /*!
458   Creates new menu item
459   \return SUIT identificator of new action
460   \param a - action
461   \param menu - menu text of parent menu item
462   \param id - proposed SUIT identificator of action
463   \param group - group in menu manager
464   \param index - index in menu
465 */
466 int SUIT_Application::createMenu( QAction* a, const QString& menu, const int id, const int group, const int index )
467 {
468   if ( !a || !desktop() || !desktop()->menuMgr() )
469     return -1;
470
471   int regId = registerAction( id, a );
472   int intId = desktop()->menuMgr()->insert( a, menu, group, index );
473   return intId != -1 ? regId : -1;
474 }
475
476 /*!
477   Creates new menu item
478   \return identificator of new action in menu manager
479   \param id - SUIT identificator of action
480   \param menu - menu text of parent menu item
481   \param group - group in menu manager
482   \param index - index in menu
483 */
484 int SUIT_Application::createMenu( const int id, const int menu, const int group, const int index )
485 {
486   if ( !desktop() || !desktop()->menuMgr() )
487     return -1;
488
489   int intId = desktop()->menuMgr()->insert( action( id ), menu, group, index );
490   return intId != -1 ? id : -1;
491 }
492
493 /*!
494   Creates new menu item
495   \return identificator of new action in menu manager
496   \param id - SUIT identificator of action
497   \param menu - menu text of parent menu item
498   \param group - group in menu manager
499   \param index - index in menu
500 */
501 int SUIT_Application::createMenu( const int id, const QString& menu, const int group, const int index )
502 {
503   if ( !desktop() || !desktop()->menuMgr() )
504     return -1;
505
506   int intId = desktop()->menuMgr()->insert( action( id ), menu, group, index );
507   return intId != -1 ? id : -1;
508 }
509
510 /*!
511   Show/hide menu item corresponding to action
512   \param a - action
513   \param on - if it is \c true, the item will be shown, otherwise it will be hidden
514 */
515 void SUIT_Application::setMenuShown( QAction* a, const bool on )
516 {
517   if ( !a || !desktop() )
518     return;
519
520   QtxActionMenuMgr* mMgr = desktop()->menuMgr();
521   if ( mMgr )
522     mMgr->setShown( mMgr->actionId( a ), on );
523 }
524
525 /*!
526   Show/hide menu item corresponding to action
527   \param id - identificator of action in menu manager
528   \param on - if it is \c true, the item will be shown, otherwise it will be hidden
529 */
530 void SUIT_Application::setMenuShown( const int id, const bool on )
531 {
532   setMenuShown( action( id ), on );
533 }
534
535 /*!
536   Show/hide tool button corresponding to action
537   \param a - action
538   \param on - if it is \c true, the button will be shown, otherwise it will be hidden
539 */
540 void SUIT_Application::setToolShown( QAction* a, const bool on )
541 {
542   if ( !a || !desktop() )
543     return;
544
545   QtxActionToolMgr* tMgr = desktop()->toolMgr();
546   if ( tMgr )
547     tMgr->setShown( tMgr->actionId( a ), on );
548 }
549
550 /*!
551   Show/hide menu item corresponding to action
552   \param id - identificator of action in tool manager
553   \param on - if it is \c true, the button will be shown, otherwise it will be hidden
554 */
555 void SUIT_Application::setToolShown( const int id, const bool on )
556 {
557   setToolShown( action( id ), on );
558 }
559
560 /*!
561   Show/hide both menu item and tool button corresponding to action
562   \param a - action
563   \param on - if it is \c true, the item will be shown, otherwise it will be hidden
564 */
565 void SUIT_Application::setActionShown( QAction* a, const bool on )
566 {
567   setMenuShown( a, on );
568   setToolShown( a, on );
569 }
570
571 /*!
572   Show/hide both menu item and tool button corresponding to action
573   \param id - identificator in both menu manager and tool manager
574   \param on - if it is \c true, the item will be shown, otherwise it will be hidden
575 */
576 void SUIT_Application::setActionShown( const int id, const bool on )
577 {
578   setMenuShown( id, on );
579   setToolShown( id, on );
580 }
581
582 /*!
583   \return action by it's SUIT identificator
584   \param id - SUIT identificator
585 */
586 QAction* SUIT_Application::action( const int id ) const
587 {
588   QAction* a = 0;
589   if ( myActionMap.contains( id ) )
590     a = myActionMap[id];
591   return a;
592 }
593
594 /*!
595   \return SUIT identificator of action
596   \param a - action
597 */
598 int SUIT_Application::actionId( const QAction* a ) const
599 {
600   int id = -1;
601   for ( QMap<int, QAction*>::ConstIterator it = myActionMap.begin(); it != myActionMap.end() && id == -1; ++it )
602   {
603     if ( it.value() == a )
604       id = it.key();
605   }
606   return id;
607 }
608
609 QList<QAction*> SUIT_Application::actions() const
610 {
611   return myActionMap.values();
612 }
613
614 QList<int> SUIT_Application::actionIds() const
615 {
616   return myActionMap.keys();
617 }
618
619 /*!
620   Creates action and registers it both in menu manager and tool manager
621   \return new instance of action
622   \param id - proposed SUIT identificator
623   \param text - description
624   \param icon - icon for toolbar
625   \param menu - menu text
626   \param tip - tool tip
627   \param key - shortcut
628   \param parent - parent object
629   \param toggle - if it is \c true the action will be a toggle action, otherwise it will be a command action
630   \param reciever - object that contains slot
631   \param member - slot to be called when action is activated
632 */
633 QAction* SUIT_Application::createAction( const int id, const QString& text, const QIcon& icon,
634                                          const QString& menu, const QString& tip, const int key,
635                                          QObject* parent, const bool toggle, QObject* reciever, 
636                                          const char* member, const QString& shortcutAction )
637 {
638   return createAction( id, text, icon, menu, tip, QKeySequence(key), parent, toggle, reciever, member, shortcutAction );
639 }
640
641 /*!
642   Creates action and registers it both in menu manager and tool manager
643   \return new instance of action
644   \param id - proposed SUIT identificator
645   \param text - description
646   \param icon - icon for toolbar
647   \param menu - menu text
648   \param tip - tool tip
649   \param key - shortcut
650   \param parent - parent object
651   \param toggle - if it is TRUE the action will be a toggle action, otherwise it will be a command action
652   \param reciever - object that contains slot
653   \param member - slot to be called when action is activated
654 */
655 QAction* SUIT_Application::createAction( const int id, const QString& text, const QIcon& icon,
656                                          const QString& menu, const QString& tip, const QKeySequence& key,
657                                          QObject* parent, const bool toggle, QObject* reciever, 
658                                          const char* member, const QString& shortcutAction )
659 {
660   QtxAction* a = new QtxAction( text, icon, menu, key, parent, toggle, shortcutAction );
661   a->setStatusTip( tip );
662
663   if ( reciever && member )
664     connect( a, SIGNAL( triggered( bool ) ), reciever, member );
665
666   registerAction( id, a );
667
668   return a;
669 }
670
671 /*!
672   Registers action both in menu manager and tool manager
673   \param id - proposed SUIT identificator (if it is -1, auto generated one is used)
674   \param a - action
675 */
676 int SUIT_Application::registerAction( const int id, QAction* a )
677 {
678   int ident = actionId( a );
679   if ( ident != -1 )
680     return ident;
681
682   static int generatedId = -1;
683   ident = id == -1 ? --generatedId : id;
684
685   if ( action( ident ) )
686     qWarning( "Action registration id is already in use: %d", ident );
687
688   myActionMap.insert( ident, a );
689
690   if ( desktop() && desktop()->menuMgr() )
691     desktop()->menuMgr()->registerAction( a );
692
693   if ( desktop() && desktop()->toolMgr() )
694     desktop()->toolMgr()->registerAction( a );
695
696   if ( desktop() && a->shortcutContext() != Qt::WidgetShortcut &&
697        a->shortcutContext() != Qt::WidgetWithChildrenShortcut )
698     desktop()->addAction( a );
699
700   return ident;
701 }
702
703 /*!
704   \return global action used as separator
705 */
706 QAction* SUIT_Application::separator()
707 {
708   return QtxActionMgr::separator();
709 }
710
711 /*!
712   SLOT: it is called when desktop is activated
713 */
714
715 void SUIT_Application::onDesktopActivated()
716 {
717   emit activated( this );
718 }
719
720 /*!
721   SLOT: it is called when desktop is moved
722 */
723 /*void SUIT_Application::onDesktopMoved()
724 {
725   emit moving();
726 }*/
727 /*!
728   SLOT: is used for Help browsing
729 */
730 void SUIT_Application::onHelpContextModule( const QString& /*theComponentName*/,
731                                             const QString& /*theFileName*/,
732                                             const QString& /*theContext*/ )
733 {
734 }
735
736 void SUIT_Application::addPostRoutine( PostRoutine theRoutine )
737 {
738   if ( !myPostRoutines.contains( theRoutine ) )
739     myPostRoutines << theRoutine;
740 }