Salome HOME
Copyright update 2022
[modules/gui.git] / src / SUIT / SUIT_Application.cxx
1 // Copyright (C) 2007-2022  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   Clears given toolbar.
404   \param title - title of toolbar
405 */
406 void SUIT_Application::clearTool( const QString& title )
407 {
408   if ( desktop() && desktop()->toolMgr() )
409     desktop()->toolMgr()->clear( title );
410 }
411
412 /*!
413   Creates new menu item
414   \return identificator of new action in menu manager
415   \param subMenu - menu text of new item
416   \param menu - identificator of parent menu item
417   \param id - proposed identificator of action
418   \param group - group in menu manager
419   \param index - index in menu
420 */
421 int SUIT_Application::createMenu( const QString& subMenu, const int menu,
422                                   const int id, const int group, const int index )
423 {
424   if ( !desktop() || !desktop()->menuMgr() )
425     return -1;
426
427   return desktop()->menuMgr()->insert( subMenu, menu, group, id, index );
428 }
429
430 /*!
431   Creates new menu item
432   \return identificator of new action in menu manager
433   \param subMenu - menu text of new item
434   \param menu - menu text of parent menu item
435   \param id - proposed identificator of action
436   \param group - group in menu manager
437   \param index - index in menu
438 */
439 int SUIT_Application::createMenu( const QString& subMenu, const QString& menu,
440                                   const int id, const int group, const int index )
441 {
442   if ( !desktop() || !desktop()->menuMgr() )
443     return -1;
444
445   return desktop()->menuMgr()->insert( subMenu, menu, group, id, index );
446 }
447
448 /*!
449   Creates new menu item
450   \return SUIT identificator of new action
451   \param a - action
452   \param menu - identificator of parent menu item
453   \param id - proposed SUIT identificator of action
454   \param group - group in menu manager
455   \param index - index in menu
456 */
457 int SUIT_Application::createMenu( QAction* a, const int menu, const int id, const int group, const int index )
458 {
459   if ( !a || !desktop() || !desktop()->menuMgr() )
460     return -1;
461
462   int regId = registerAction( id, a );
463   int intId = desktop()->menuMgr()->insert( a, menu, group, index );
464   return intId != -1 ? regId : -1;
465 }
466
467 /*!
468   Creates new menu item
469   \return SUIT identificator of new action
470   \param a - action
471   \param menu - menu text of parent menu item
472   \param id - proposed SUIT identificator of action
473   \param group - group in menu manager
474   \param index - index in menu
475 */
476 int SUIT_Application::createMenu( QAction* a, const QString& menu, const int id, const int group, const int index )
477 {
478   if ( !a || !desktop() || !desktop()->menuMgr() )
479     return -1;
480
481   int regId = registerAction( id, a );
482   int intId = desktop()->menuMgr()->insert( a, menu, group, index );
483   return intId != -1 ? regId : -1;
484 }
485
486 /*!
487   Creates new menu item
488   \return identificator of new action in menu manager
489   \param id - SUIT identificator of action
490   \param menu - menu text of parent menu item
491   \param group - group in menu manager
492   \param index - index in menu
493 */
494 int SUIT_Application::createMenu( const int id, const int menu, const int group, const int index )
495 {
496   if ( !desktop() || !desktop()->menuMgr() )
497     return -1;
498
499   int intId = desktop()->menuMgr()->insert( action( id ), menu, group, index );
500   return intId != -1 ? id : -1;
501 }
502
503 /*!
504   Creates new menu item
505   \return identificator of new action in menu manager
506   \param id - SUIT identificator of action
507   \param menu - menu text of parent menu item
508   \param group - group in menu manager
509   \param index - index in menu
510 */
511 int SUIT_Application::createMenu( const int id, const QString& menu, const int group, const int index )
512 {
513   if ( !desktop() || !desktop()->menuMgr() )
514     return -1;
515
516   int intId = desktop()->menuMgr()->insert( action( id ), menu, group, index );
517   return intId != -1 ? id : -1;
518 }
519
520 /*!
521   Show/hide menu item corresponding to action
522   \param a - action
523   \param on - if it is \c true, the item will be shown, otherwise it will be hidden
524 */
525 void SUIT_Application::setMenuShown( QAction* a, const bool on )
526 {
527   if ( !a || !desktop() )
528     return;
529
530   QtxActionMenuMgr* mMgr = desktop()->menuMgr();
531   if ( mMgr )
532     mMgr->setShown( mMgr->actionId( a ), on );
533 }
534
535 /*!
536   Show/hide menu item corresponding to action
537   \param id - identificator of action in menu manager
538   \param on - if it is \c true, the item will be shown, otherwise it will be hidden
539 */
540 void SUIT_Application::setMenuShown( const int id, const bool on )
541 {
542   setMenuShown( action( id ), on );
543 }
544
545 /*!
546   Show/hide tool button corresponding to action
547   \param a - action
548   \param on - if it is \c true, the button will be shown, otherwise it will be hidden
549 */
550 void SUIT_Application::setToolShown( QAction* a, const bool on )
551 {
552   if ( !a || !desktop() )
553     return;
554
555   QtxActionToolMgr* tMgr = desktop()->toolMgr();
556   if ( tMgr )
557     tMgr->setShown( tMgr->actionId( a ), on );
558 }
559
560 /*!
561   Show/hide menu item corresponding to action
562   \param id - identificator of action in tool manager
563   \param on - if it is \c true, the button will be shown, otherwise it will be hidden
564 */
565 void SUIT_Application::setToolShown( const int id, const bool on )
566 {
567   setToolShown( action( id ), on );
568 }
569
570 /*!
571   Show/hide both menu item and tool button corresponding to action
572   \param a - action
573   \param on - if it is \c true, the item will be shown, otherwise it will be hidden
574 */
575 void SUIT_Application::setActionShown( QAction* a, const bool on )
576 {
577   setMenuShown( a, on );
578   setToolShown( a, on );
579 }
580
581 /*!
582   Show/hide both menu item and tool button corresponding to action
583   \param id - identificator in both menu manager and tool manager
584   \param on - if it is \c true, the item will be shown, otherwise it will be hidden
585 */
586 void SUIT_Application::setActionShown( const int id, const bool on )
587 {
588   setMenuShown( id, on );
589   setToolShown( id, on );
590 }
591
592 /*!
593   \return action by it's SUIT identificator
594   \param id - SUIT identificator
595 */
596 QAction* SUIT_Application::action( const int id ) const
597 {
598   QAction* a = 0;
599   if ( myActionMap.contains( id ) )
600     a = myActionMap[id];
601   return a;
602 }
603
604 /*!
605   \return SUIT identificator of action
606   \param a - action
607 */
608 int SUIT_Application::actionId( const QAction* a ) const
609 {
610   int id = -1;
611   for ( QMap<int, QAction*>::ConstIterator it = myActionMap.begin(); it != myActionMap.end() && id == -1; ++it )
612   {
613     if ( it.value() == a )
614       id = it.key();
615   }
616   return id;
617 }
618
619 QList<QAction*> SUIT_Application::actions() const
620 {
621   return myActionMap.values();
622 }
623
624 QList<int> SUIT_Application::actionIds() const
625 {
626   return myActionMap.keys();
627 }
628
629 /*!
630   Creates action and registers it both in menu manager and tool manager
631   \return new instance of action
632   \param id - proposed SUIT identificator
633   \param text - description
634   \param icon - icon for toolbar
635   \param menu - menu text
636   \param tip - tool tip
637   \param key - shortcut
638   \param parent - parent object
639   \param toggle - if it is \c true the action will be a toggle action, otherwise it will be a command action
640   \param reciever - object that contains slot
641   \param member - slot to be called when action is activated
642 */
643 QAction* SUIT_Application::createAction( const int id, const QString& text, const QIcon& icon,
644                                          const QString& menu, const QString& tip, const int key,
645                                          QObject* parent, const bool toggle, QObject* reciever, 
646                                          const char* member, const QString& shortcutAction )
647 {
648   return createAction( id, text, icon, menu, tip, QKeySequence(key), parent, toggle, reciever, member, shortcutAction );
649 }
650
651 /*!
652   Creates action and registers it both in menu manager and tool manager
653   \return new instance of action
654   \param id - proposed SUIT identificator
655   \param text - description
656   \param icon - icon for toolbar
657   \param menu - menu text
658   \param tip - tool tip
659   \param key - shortcut
660   \param parent - parent object
661   \param toggle - if it is TRUE the action will be a toggle action, otherwise it will be a command action
662   \param reciever - object that contains slot
663   \param member - slot to be called when action is activated
664 */
665 QAction* SUIT_Application::createAction( const int id, const QString& text, const QIcon& icon,
666                                          const QString& menu, const QString& tip, const QKeySequence& key,
667                                          QObject* parent, const bool toggle, QObject* reciever, 
668                                          const char* member, const QString& shortcutAction )
669 {
670   QtxAction* a = new QtxAction( text, icon, menu, key, parent, toggle, shortcutAction );
671   a->setStatusTip( tip );
672
673   if ( reciever && member )
674     connect( a, SIGNAL( triggered( bool ) ), reciever, member );
675
676   registerAction( id, a );
677
678   return a;
679 }
680
681 /*!
682   Registers action both in menu manager and tool manager
683   \param id - proposed SUIT identificator (if it is -1, auto generated one is used)
684   \param a - action
685 */
686 int SUIT_Application::registerAction( const int id, QAction* a )
687 {
688   int ident = actionId( a );
689   if ( ident != -1 )
690     return ident;
691
692   static int generatedId = -1;
693   ident = id == -1 ? --generatedId : id;
694
695   if ( action( ident ) )
696     qWarning( "Action registration id is already in use: %d", ident );
697
698   myActionMap.insert( ident, a );
699
700   if ( desktop() && desktop()->menuMgr() )
701     desktop()->menuMgr()->registerAction( a );
702
703   if ( desktop() && desktop()->toolMgr() )
704     desktop()->toolMgr()->registerAction( a );
705
706   if ( desktop() && a->shortcutContext() != Qt::WidgetShortcut &&
707        a->shortcutContext() != Qt::WidgetWithChildrenShortcut )
708     desktop()->addAction( a );
709
710   return ident;
711 }
712
713 /*!
714   \return global action used as separator
715 */
716 QAction* SUIT_Application::separator()
717 {
718   return QtxActionMgr::separator();
719 }
720
721 /*!
722   SLOT: it is called when desktop is activated
723 */
724
725 void SUIT_Application::onDesktopActivated()
726 {
727   emit activated( this );
728 }
729
730 /*!
731   SLOT: it is called when desktop is moved
732 */
733 /*void SUIT_Application::onDesktopMoved()
734 {
735   emit moving();
736 }*/
737 /*!
738   SLOT: is used for Help browsing
739 */
740 void SUIT_Application::onHelpContextModule( const QString& /*theComponentName*/,
741                                             const QString& /*theFileName*/,
742                                             const QString& /*theContext*/ )
743 {
744 }
745
746 void SUIT_Application::addPostRoutine( PostRoutine theRoutine )
747 {
748   if ( !myPostRoutines.contains( theRoutine ) )
749     myPostRoutines << theRoutine;
750 }