Salome HOME
New generic 2D View based on Qt
[modules/gui.git] / src / SUIT / SUIT_Application.cxx
1 // Copyright (C) 2007-2024  CEA, EDF, 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::get();
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   \param actionID - application-unique action ID. Required by SUIT_ShortcutMgr for shortcut customization. May be left blank.
643 */
644 QAction* SUIT_Application::createAction( const int id, const QString& text, const QIcon& icon,
645                                          const QString& menu, const QString& tip, const int key,
646                                          QObject* parent, const bool toggle, QObject* reciever,
647                                          const char* member, const QString& actionID )
648 {
649   return createAction( id, text, icon, menu, tip, QKeySequence(key), parent, toggle, reciever, member, actionID );
650 }
651
652 /*!
653   Creates action and registers it both in menu manager and tool manager
654   \return new instance of action
655   \param id - proposed SUIT identificator
656   \param text - description
657   \param icon - icon for toolbar
658   \param menu - menu text
659   \param tip - tool tip
660   \param key - shortcut
661   \param parent - parent object
662   \param toggle - if it is TRUE the action will be a toggle action, otherwise it will be a command action
663   \param reciever - object that contains slot
664   \param member - slot to be called when action is activated
665   \param actionID - application-unique action ID. Required by SUIT_ShortcutMgr for shortcut customization. May be left blank.
666 */
667 QAction* SUIT_Application::createAction( const int id, const QString& text, const QIcon& icon,
668                                          const QString& menu, const QString& tip, const QKeySequence& key,
669                                          QObject* parent, const bool toggle, QObject* reciever,
670                                          const char* member, const QString& actionID )
671 {
672   QtxAction* a = new QtxAction( text, icon, menu, key, parent, toggle, actionID );
673   a->setStatusTip( tip );
674
675   if ( reciever && member )
676     connect( a, SIGNAL( triggered( bool ) ), reciever, member );
677
678   registerAction( id, a );
679
680   return a;
681 }
682
683 /*!
684   Creates action and registers it both in menu manager and tool manager
685   \return new instance of action
686   \param id proposed SUIT identificator
687   \param parent parent object
688   \param toggle if it is TRUE the action will be a toggle action, otherwise it will be a command action
689   \param actionID application-unique action ID. Required by SUIT_ShortcutMgr for shortcut customization. May be left blank.
690   \param toolTip
691   \param menuText can be later retrieved using QAction::text();
692   \param statusTip
693   \param icon icon for toolbar
694   \param reciever object that contains slot
695   \param member slot to be called when action is activated
696 */
697 QAction* SUIT_Application::createAction( const int id, QObject* parent, const bool toggle, const QString& actionID,
698                                          const QString& toolTip, const QString& menuText, const QString& statusTip, const QIcon& icon,
699                                          QObject* reciever, const char* member )
700 {
701   QtxAction* a = new QtxAction( parent, toggle, actionID, toolTip, menuText, icon);
702   a->setStatusTip( statusTip );
703
704   if ( reciever && member )
705     connect( a, SIGNAL( triggered( bool ) ), reciever, member );
706
707   registerAction( id, a );
708
709   return a;
710 }
711
712 /*!
713   Registers action both in menu manager and tool manager
714   \param id - proposed SUIT identificator (if it is -1, auto generated one is used)
715   \param a - action
716 */
717 int SUIT_Application::registerAction( const int id, QAction* a )
718 {
719   int ident = actionId( a );
720   if ( ident != -1 )
721     return ident;
722
723   static int generatedId = -1;
724   ident = id == -1 ? --generatedId : id;
725
726   if ( action( ident ) )
727     qWarning( "Action registration id is already in use: %d", ident );
728
729   myActionMap.insert( ident, a );
730
731   if ( desktop() && desktop()->menuMgr() )
732     desktop()->menuMgr()->registerAction( a );
733
734   if ( desktop() && desktop()->toolMgr() )
735     desktop()->toolMgr()->registerAction( a );
736
737   if ( desktop() && a->shortcutContext() != Qt::WidgetShortcut &&
738        a->shortcutContext() != Qt::WidgetWithChildrenShortcut )
739     desktop()->addAction( a );
740
741   return ident;
742 }
743
744 /*!
745   \return global action used as separator
746 */
747 QAction* SUIT_Application::separator()
748 {
749   return QtxActionMgr::separator();
750 }
751
752 /*!
753   SLOT: it is called when desktop is activated
754 */
755
756 void SUIT_Application::onDesktopActivated()
757 {
758   emit activated( this );
759 }
760
761 /*!
762   SLOT: it is called when desktop is moved
763 */
764 /*void SUIT_Application::onDesktopMoved()
765 {
766   emit moving();
767 }*/
768 /*!
769   SLOT: is used for Help browsing
770 */
771 void SUIT_Application::onHelpContextModule( const QString& /*theComponentName*/,
772                                             const QString& /*theFileName*/,
773                                             const QString& /*theContext*/ )
774 {
775 }
776
777 void SUIT_Application::addPostRoutine( PostRoutine theRoutine )
778 {
779   if ( !myPostRoutines.contains( theRoutine ) )
780     myPostRoutines << theRoutine;
781 }