Salome HOME
b439f0d0684307f6606154ed9f25a6403dc93b0a
[modules/gui.git] / src / LightApp / LightApp_ModuleAction.cxx
1 // Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File   : LightApp_ModuleAction.cxx
21 // Author : Sergey TELKOV, Vadim SANDLER
22 //
23 #include "LightApp_ModuleAction.h"
24
25 #include <QtxComboBox.h>
26 #include <QtxActionSet.h>
27 #include <QVBoxLayout>
28 #include <QApplication>
29 #include <QEvent>
30
31 /*!
32   \class LightApp_ModuleAction::ActionSet
33   \brief Internal class to represent list of modules buttons.
34   \internal
35 */
36
37 class LightApp_ModuleAction::ActionSet : public QtxActionSet
38 {
39 public:
40   ActionSet( QObject* );
41   QAction* moduleAction( const QString& ) const;
42   int      moduleId( const QString& ) const;
43   int      moduleId( QAction* ) const;
44   void     setVisible( bool );
45 };
46
47 /*!
48   \brief Constructor.
49   \internal
50   \param parent parent object
51 */
52 LightApp_ModuleAction::ActionSet::ActionSet( QObject* parent )
53 : QtxActionSet( parent ) 
54 {
55 }
56
57 /*!
58   \brief Get action corresponding to the specified module.
59   \internal
60   \param name module name
61   \return module action or 0 if \a name is invalid
62 */
63 QAction* LightApp_ModuleAction::ActionSet::moduleAction( const QString& name ) const
64 {
65   QAction* a = 0;
66
67   QList<QAction*> alist = actions();
68   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end() && !a; ++it )
69   {
70     if ( (*it)->text() == name )
71       a = *it;
72   }
73
74   return a;
75 }
76
77 /*!
78   \brief Get module action identifier.
79   \internal
80   \param name module name
81   \return module action ID or -1 if \a name is invalid
82 */
83 int LightApp_ModuleAction::ActionSet::moduleId( const QString& name ) const
84 {
85   int id = -1;
86
87   QList<QAction*> alist = actions();
88   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end() && id == -1; ++it )
89   {
90     if ( (*it)->text() == name )
91       id = actionId( *it );
92   }
93
94   return id;
95 }
96
97 /*!
98   \brief Get module action identifier.
99   \internal
100   \param a module action
101   \return module action ID or -1 if \a a is null or invalid
102 */
103 int LightApp_ModuleAction::ActionSet::moduleId( QAction* a ) const
104 {
105   return actionId( a );
106 }
107
108 /*!
109   \brief Show/hide modules actions.
110   \internal
111   \param on new visibility state
112 */
113 void LightApp_ModuleAction::ActionSet::setVisible( bool on )
114 {
115   QList<QAction*> alist = actions();
116   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end(); ++it )
117     (*it)->setVisible( on );
118
119   QtxActionSet::setVisible( on );
120 }
121
122 /*!
123   \class LightApp_ModuleAction::ComboAction
124   \brief Internal class to represent combo box with the list of modules in the toolbar.
125   \internal
126 */
127
128 /*!
129   \brief Constructor.
130   \internal
131   \param parent parent object
132 */
133 LightApp_ModuleAction::ComboAction::ComboAction( QObject* parent )
134 : QtxAction( parent )
135 {
136 }
137
138 /*!
139   \brief Get list of associated widgets.
140   \internal
141   \return list of created widgets (QtxComboBox)
142 */
143 QList<QtxComboBox*> LightApp_ModuleAction::ComboAction::widgets() const
144 {
145   QList<QtxComboBox*> lst;
146
147   QList<QWidget*> wlist = createdWidgets();
148   for ( QList<QWidget*>::const_iterator wit = wlist.begin(); wit != wlist.end(); ++wit )
149     lst += (*wit)->findChildren<QtxComboBox*>();
150
151   return lst;
152 }
153
154 /*!
155   \brief Create combo box widget by request from the toolbar.
156   \internal
157   \param parent parent widget (should be QToolBar or its successor)
158   \return new custom widget, containing combo box
159 */
160 QWidget* LightApp_ModuleAction::ComboAction::createWidget( QWidget* parent )
161 {
162   if ( !parent->inherits( "QToolBar" ) )
163     return 0;
164
165   QWidget* dumb = new QWidget( parent );
166   QVBoxLayout* l = new QVBoxLayout( dumb );
167   l->setSpacing( 0 ); l->setMargin( 0 );
168   QtxComboBox* cb = new QtxComboBox( dumb );
169   cb->setSizeAdjustPolicy( QComboBox::AdjustToContents );
170   cb->setFocusPolicy( Qt::NoFocus );
171   l->addWidget( cb );
172   l->addSpacing( 3 );
173
174   connect( cb, SIGNAL( activatedId( int ) ), this, SIGNAL( activatedId( int ) ) );
175
176   return dumb;
177 }
178
179 /*!
180   \fn void LightApp_ModuleAction::ComboAction::activatedId( int id );
181   \internal
182   \brief Emitted when the combo box item is activated
183   \param item identifier
184 */
185
186 /*!
187   \class LightApp_ModuleAction::ActivateEvent
188   \brief Internal class to represent custom event for transfer the activation item id.
189   \internal
190 */
191 class LightApp_ModuleAction::ActivateEvent : public QEvent
192 {
193 public:
194   ActivateEvent( QEvent::Type type, int id ) : QEvent( type ), myId( id ) {};
195   ~ActivateEvent() {};
196
197   int     id() const { return myId; }
198
199 private:
200   int     myId;
201 };
202
203 /*!
204   \class LightApp_ModuleAction
205   \brief An action, representing the list of modules to be inserted to the
206   toolbar.
207
208   This action is represented in the toolbar as combo box and a set of buttons 
209   for each module. In addition to the modules items, the combo box contains 
210   an item corresponding to the "neutral point" of the application 
211   (when there is no active module).
212   
213   The action can be constructed with up to two parameters, defining the text
214   and icon to be displayed for the "neutral point".
215
216   Only one module can be active at the moment. It can be set programmatically 
217   with setActiveModule() function. Use this method with empty string to turn
218   to the "neutral point". To get active module, use activeModule() function.
219
220   When user activates/deactivates any module, the signal moduleActivated() 
221   is emitted.
222
223   The action can be represented in the toolbar in different modes:
224   * as combo box only (Qtx::ComboItem)
225   * as set of modules buttons only (Qtx::Buttons)
226   * as combo box followed by the set of modules buttons (Qtx::All)
227   * as none (Qtx::None)
228   By default, both combo box and buttons set are shown. Use method 
229   setMode() to change this behavior.
230
231   An action can be also added to the popup menu, but combo box is never shown
232   in this case, only modules buttons.
233 */
234
235 /*!
236   \brief Constructor
237
238   Creates an module action with "neutral point" item described by \a text.
239
240   \param text "neutral point" item's text
241   \param parent parent object
242 */
243 LightApp_ModuleAction::LightApp_ModuleAction( const QString& text, QObject* parent )
244 : QtxAction( parent )
245 {
246   setText( text );
247   init();
248 }
249
250 /*!
251   \brief Constructor
252
253   Creates an module action with "neutral point" item described by \a text and \a ico.
254
255   \param text "neutral point" item's text
256   \param ico "neutral point" item's icon
257   \param parent parent object
258 */
259 LightApp_ModuleAction::LightApp_ModuleAction( const QString& text, const QIcon& ico, QObject* parent )
260 : QtxAction( parent )
261 {
262   setText( text );
263   setIcon( ico );
264   init();
265 }
266
267 /*!
268   \brief Destructor
269 */
270 LightApp_ModuleAction::~LightApp_ModuleAction()
271 {
272 }
273
274 /*!
275   \brief Get number of registered modules.
276   \return modules count
277 */
278 int LightApp_ModuleAction::count() const
279 {
280   return modules().count();
281 }
282
283 /*!
284   \brief Get list of modules.
285   \return modules names list
286 */
287 QStringList LightApp_ModuleAction::modules() const
288 {
289   QStringList lst;
290
291   QList<QAction*> alist = mySet->actions();
292   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end(); ++it )
293     lst.append( (*it)->text() );
294
295   return lst;
296 }
297
298 /*!
299   \brief Get module icon.
300   \param name module name
301   \return module icon
302   \sa setModuleIcon()
303 */
304 QIcon LightApp_ModuleAction::moduleIcon( const QString& name ) const
305 {
306   QAction* a = mySet->moduleAction( name );
307   return a ? a->icon() : QIcon();
308 }
309
310 /*!
311   \brief Set module icon.
312   \param name module name
313   \param ico new module icon
314   \sa moduleIcon()
315 */
316 void LightApp_ModuleAction::setModuleIcon( const QString& name, const QIcon& ico )
317 {
318   QAction* a = mySet->moduleAction( name );
319   if ( !a )
320     return;
321
322   a->setIcon( ico );
323   update();
324 }
325
326 /*!
327   \brief Get module action.
328   \param name module name
329 */
330 QAction* LightApp_ModuleAction::moduleAction( const QString& name ) const
331 {
332   return mySet->moduleAction( name );
333 }
334
335 /*!
336   \brief Add module into the list.
337   \param name module name
338   \param ico module icon
339   \param idx position in the module list (if -1, the module is added to the end of list)
340   \sa removeModule()
341 */
342 void LightApp_ModuleAction::insertModule( const QString& name, const QIcon& ico,
343                                           const int idx )
344 {
345   QtxAction* a = new QtxAction( name, ico, name, 0, this, true );
346   a->setStatusTip( tr( "ACTIVATE_MODULE_TOP" ).arg( name ) );
347
348   mySet->insertAction( a, -1, idx );
349   update();
350 }
351
352 /*!
353   \brief Remove module from the list.
354   \param name module name
355   \sa insertModule()
356 */
357 void LightApp_ModuleAction::removeModule( const QString& name )
358 {
359   int id = mySet->moduleId( name );
360   if ( id == -1 )
361     return;
362
363   mySet->removeAction( id );
364   update();
365 }
366
367 /*!
368   \brief Get active module.
369
370   If there is no active module ("neutral point"), then the null string 
371   is returned.
372
373   \return active module name
374   \sa setActiveModule()
375 */
376 QString LightApp_ModuleAction::activeModule() const
377 {
378   QAction* a = active();
379   return a ? a->text() : QString();
380 }
381
382 /*!
383   \brief Set active module.
384
385   To turn to the "neutral point" (no active module), pass empty string.
386
387   \param name new active module name
388   \sa activeModule()
389 */
390 void LightApp_ModuleAction::setActiveModule( const QString& name )
391 {
392   if ( name == activeModule() )
393     return;
394
395   int id = mySet->moduleId( name );
396   if ( name.isEmpty() || id != -1 )
397     activate( id, false );
398 }
399
400 /*!
401   \brief Set action display mode.
402
403   Action can be represented in the toolbar as
404   * combo box only (Qtx::ComboItem)
405   * set of modules buttons only (Qtx::Buttons)
406   * combo box followed by the set of modules buttons (Qtx::All)
407   * none (Qtx::None)
408
409   \param mode action display mode
410   \sa mode()
411 */
412 void LightApp_ModuleAction::setMode( const int mode )
413 {
414   myMode = mode;
415   update();
416 }
417
418 /*!
419   \brief Get action display mode.
420   \param mode action display mode
421   \sa setMode()
422 */
423 int LightApp_ModuleAction::mode() const
424 {
425   return myMode;
426 }
427
428 /*!
429   \brief Called when the action is added to the widget.
430   \param w widget (not used)
431 */
432 void LightApp_ModuleAction::addedTo( QWidget* w )
433 {
434   if ( w->inherits( "QToolBar" ) )
435     w->insertAction( this, myCombo );
436   w->insertAction( this, mySet );
437   update();
438 }
439
440 /*!
441   \brief Remove action from widget.
442   \param w widget (menu or toolbar)
443   \return \c true if the action is removed successfully and \c false otherwise.
444   \sa addTo()
445 */
446 void LightApp_ModuleAction::removedFrom( QWidget* w )
447 {
448   if ( w->inherits( "QToolBar" ) )
449     w->removeAction( myCombo );
450   w->removeAction( mySet );
451 }
452
453 /*!
454   \brief Perform delayed activation with specified id.
455   \param e custom event
456   \return \c true if the event was processed successfully and \c false otherwise.
457 */
458 bool LightApp_ModuleAction::event( QEvent* e )
459 {
460   if ( e->type() == QEvent::MaxUser ) {
461     activate( ((ActivateEvent*)e)->id(), false );
462     return true;
463   }
464   return QtxAction::event( e );
465 }
466
467 /*!
468   \fn void LightApp_ModuleAction::moduleActivated( const QString& name );
469   \brief Emitted when the module is activated
470   \param name module name (empty string for neutral point)
471 */
472
473 /*!
474   \brief Initialize an action,
475   \internal
476 */
477 void LightApp_ModuleAction::init()
478 {
479   setVisible( false );
480
481   myMode = All;
482   myCombo = new ComboAction( this );
483   mySet = new ActionSet( this );
484
485   connect( this,    SIGNAL( changed() ),          this, SLOT( onChanged() ) );
486   connect( mySet,   SIGNAL( triggered( int ) ),   this, SLOT( onTriggered( int ) ) );
487   connect( myCombo, SIGNAL( activatedId( int ) ), this, SLOT( onComboActivated( int ) ) );
488 }
489
490 /*!
491   \brief Update an action.
492   \internal
493 */
494 void LightApp_ModuleAction::update()
495 {
496   QList<QtxComboBox*> lst = myCombo->widgets();
497   for ( QList<QtxComboBox*>::const_iterator it = lst.begin(); it != lst.end(); ++it )
498     update( *it );
499
500   myCombo->setVisible( myMode & ComboItem );
501   mySet->setVisible( myMode & Buttons );
502 }
503
504 /*!
505   \brief Update combo box.
506   \internal
507   \param cb combo box
508 */
509 void LightApp_ModuleAction::update( QtxComboBox* cb )
510 {
511   if ( !cb )
512     return;
513
514   bool blocked = cb->blockSignals( true );
515   int curId = mySet->moduleId( active() );
516   QList<QAction*> alist = mySet->actions();
517   cb->clear();
518   
519   cb->addItem( icon(), text() );
520   cb->setId( 0, -1 );
521
522   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end(); ++it )
523   {
524     QAction* a = *it;
525     int id = mySet->moduleId( a );
526     cb->addItem( a->icon(), a->text() );
527     cb->setId( cb->count() - 1, id );
528   }
529
530   cb->setCurrentId( curId );
531   cb->blockSignals( blocked );
532 }
533
534 /*!
535   \brief Get an action corresponding to the active module.
536   \internal
537   \return active module action or 0 if there is no active module
538 */
539 QAction* LightApp_ModuleAction::active() const
540 {
541   QAction* a = 0;
542
543   QList<QAction*> alist = mySet->actions();
544   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end() && !a; ++it )
545   {
546     if ( (*it)->isChecked() )
547       a = *it;
548   }
549
550   return a;
551 }
552
553 /*!
554   \brief Activate a module item.
555   \internal
556   \param id module identifier
557   \param fromAction \c true if function is called from the module button
558 */
559 void LightApp_ModuleAction::activate( int id, bool fromAction )
560 {
561   bool checked = false;
562
563   QList<QAction*> alist = mySet->actions();
564   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end(); ++it )
565   {
566     if ( mySet->moduleId( *it ) != id ) {
567       (*it)->setChecked( false );
568     }
569     else {
570       if ( !fromAction )
571         (*it)->setChecked( true );
572       checked = (*it)->isChecked();
573     }
574   }
575
576   QList<QtxComboBox*> widgets = myCombo->widgets();
577   for ( QList<QtxComboBox*>::const_iterator wit = widgets.begin(); wit != widgets.end(); ++wit )
578   {
579     QtxComboBox* cb = *wit;
580     bool blocked = cb->signalsBlocked();
581     cb->blockSignals( true );
582     cb->setCurrentId( checked ? id : -1 );
583     cb->blockSignals( blocked );
584   }
585
586   emit moduleActivated( activeModule() );
587 }
588
589 /*!
590   \brief Called when module button is triggered.
591   \internal
592   \param id module identifier
593 */
594 void LightApp_ModuleAction::onTriggered( int id )
595 {
596   activate( id );
597 }
598
599 /*!
600   \brief Called when action state is changed.
601   \internal
602   
603   This slot is used to prevent making the parent action visible.
604 */
605 void LightApp_ModuleAction::onChanged()
606 {
607   if ( !isVisible() )
608     return;
609
610   bool block = signalsBlocked();
611   blockSignals( true );
612   setVisible( false );
613   blockSignals( block );
614 }
615
616 /*!
617   \brief Called when combo box item is activated.
618   \param id module identifier
619 */
620 void LightApp_ModuleAction::onComboActivated( int id )
621 {
622   QApplication::postEvent( this, new ActivateEvent( QEvent::MaxUser, id ) );
623