Salome HOME
Merge remote branch 'origin/V7_dev' into V8_0_0_BR
[modules/gui.git] / src / LightApp / LightApp_ModuleAction.cxx
1 // Copyright (C) 2007-2015  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 list of modules.
276   \return modules names list
277 */
278 QStringList LightApp_ModuleAction::modules() const
279 {
280   QStringList lst;
281
282   QList<QAction*> alist = mySet->actions();
283   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end(); ++it )
284     lst.append( (*it)->text() );
285
286   return lst;
287 }
288
289 /*!
290   \brief Get module icon.
291   \param name module name
292   \return module icon
293   \sa setModuleIcon()
294 */
295 QIcon LightApp_ModuleAction::moduleIcon( const QString& name ) const
296 {
297   QAction* a = mySet->moduleAction( name );
298   return a ? a->icon() : QIcon();
299 }
300
301 /*!
302   \brief Set module icon.
303   \param name module name
304   \param ico new module icon
305   \sa moduleIcon()
306 */
307 void LightApp_ModuleAction::setModuleIcon( const QString& name, const QIcon& ico )
308 {
309   QAction* a = mySet->moduleAction( name );
310   if ( !a )
311     return;
312
313   a->setIcon( ico );
314   update();
315 }
316
317 /*!
318   \brief Add module into the list.
319   \param name module name
320   \param ico module icon
321   \param idx position in the module list (if -1, the module is added to the end of list)
322   \sa removeModule()
323 */
324 void LightApp_ModuleAction::insertModule( const QString& name, const QIcon& ico,
325                                           const int idx )
326 {
327   QtxAction* a = new QtxAction( name, ico, name, 0, this, true );
328   a->setStatusTip( tr( "ACTIVATE_MODULE_TOP" ).arg( name ) );
329
330   mySet->insertAction( a, -1, idx );
331   update();
332 }
333
334 /*!
335   \brief Remove module from the list.
336   \param name module name
337   \sa insertModule()
338 */
339 void LightApp_ModuleAction::removeModule( const QString& name )
340 {
341   int id = mySet->moduleId( name );
342   if ( id == -1 )
343     return;
344
345   mySet->removeAction( id );
346   update();
347 }
348
349 /*!
350   \brief Get active module.
351
352   If there is no active module ("neutral point"), then the null string 
353   is returned.
354
355   \return active module name
356   \sa setActiveModule()
357 */
358 QString LightApp_ModuleAction::activeModule() const
359 {
360   QAction* a = active();
361   return a ? a->text() : QString();
362 }
363
364 /*!
365   \brief Set active module.
366
367   To turn to the "neutral point" (no active module), pass empty string.
368
369   \param name new active module name
370   \sa activeModule()
371 */
372 void LightApp_ModuleAction::setActiveModule( const QString& name )
373 {
374   if ( name == activeModule() )
375     return;
376
377   int id = mySet->moduleId( name );
378   if ( name.isEmpty() || id != -1 )
379     activate( id, false );
380 }
381
382 /*!
383   \brief Set action display mode.
384
385   Action can be represented in the toolbar as
386   * combo box only (Qtx::ComboItem)
387   * set of modules buttons only (Qtx::Buttons)
388   * combo box followed by the set of modules buttons (Qtx::All)
389   * none (Qtx::None)
390
391   \param mode action display mode
392   \sa mode()
393 */
394 void LightApp_ModuleAction::setMode( const int mode )
395 {
396   myMode = mode;
397   update();
398 }
399
400 /*!
401   \brief Get action display mode.
402   \param mode action display mode
403   \sa setMode()
404 */
405 int LightApp_ModuleAction::mode() const
406 {
407   return myMode;
408 }
409
410 /*!
411   \brief Called when the action is added to the widget.
412   \param w widget (not used)
413 */
414 void LightApp_ModuleAction::addedTo( QWidget* w )
415 {
416   if ( w->inherits( "QToolBar" ) )
417     w->insertAction( this, myCombo );
418   w->insertAction( this, mySet );
419   update();
420 }
421
422 /*!
423   \brief Remove action from widget.
424   \param w widget (menu or toolbar)
425   \return \c true if the action is removed successfully and \c false otherwise.
426   \sa addTo()
427 */
428 void LightApp_ModuleAction::removedFrom( QWidget* w )
429 {
430   if ( w->inherits( "QToolBar" ) )
431     w->removeAction( myCombo );
432   w->removeAction( mySet );
433 }
434
435 /*!
436   \brief Perform delayed activation with specified id.
437   \param e custom event
438   \return \c true if the event was processed successfully and \c false otherwise.
439 */
440 bool LightApp_ModuleAction::event( QEvent* e )
441 {
442   if ( e->type() == QEvent::MaxUser ) {
443     activate( ((ActivateEvent*)e)->id(), false );
444     return true;
445   }
446   return QtxAction::event( e );
447 }
448
449 /*!
450   \fn void LightApp_ModuleAction::moduleActivated( const QString& name );
451   \brief Emitted when the module is activated
452   \param name module name (empty string for neutral point)
453 */
454
455 /*!
456   \brief Initialize an action,
457   \internal
458 */
459 void LightApp_ModuleAction::init()
460 {
461   setVisible( false );
462
463   myMode = All;
464   myCombo = new ComboAction( this );
465   mySet = new ActionSet( this );
466
467   connect( this,    SIGNAL( changed() ),          this, SLOT( onChanged() ) );
468   connect( mySet,   SIGNAL( triggered( int ) ),   this, SLOT( onTriggered( int ) ) );
469   connect( myCombo, SIGNAL( activatedId( int ) ), this, SLOT( onComboActivated( int ) ) );
470 }
471
472 /*!
473   \brief Update an action.
474   \internal
475 */
476 void LightApp_ModuleAction::update()
477 {
478   QList<QtxComboBox*> lst = myCombo->widgets();
479   for ( QList<QtxComboBox*>::const_iterator it = lst.begin(); it != lst.end(); ++it )
480     update( *it );
481
482   myCombo->setVisible( myMode & ComboItem );
483   mySet->setVisible( myMode & Buttons );
484 }
485
486 /*!
487   \brief Update combo box.
488   \internal
489   \param cb combo box
490 */
491 void LightApp_ModuleAction::update( QtxComboBox* cb )
492 {
493   if ( !cb )
494     return;
495
496   bool blocked = cb->blockSignals( true );
497   int curId = mySet->moduleId( active() );
498   QList<QAction*> alist = mySet->actions();
499   cb->clear();
500   
501   cb->addItem( icon(), text() );
502   cb->setId( 0, -1 );
503
504   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end(); ++it )
505   {
506     QAction* a = *it;
507     int id = mySet->moduleId( a );
508     cb->addItem( a->icon(), a->text() );
509     cb->setId( cb->count() - 1, id );
510   }
511
512   cb->setCurrentId( curId );
513   cb->blockSignals( blocked );
514 }
515
516 /*!
517   \brief Get an action corresponding to the active module.
518   \internal
519   \return active module action or 0 if there is no active module
520 */
521 QAction* LightApp_ModuleAction::active() const
522 {
523   QAction* a = 0;
524
525   QList<QAction*> alist = mySet->actions();
526   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end() && !a; ++it )
527   {
528     if ( (*it)->isChecked() )
529       a = *it;
530   }
531
532   return a;
533 }
534
535 /*!
536   \brief Activate a module item.
537   \internal
538   \param id module identifier
539   \param fromAction \c true if function is called from the module button
540 */
541 void LightApp_ModuleAction::activate( int id, bool fromAction )
542 {
543   bool checked = false;
544
545   QList<QAction*> alist = mySet->actions();
546   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end(); ++it )
547   {
548     if ( mySet->moduleId( *it ) != id ) {
549       (*it)->setChecked( false );
550     }
551     else {
552       if ( !fromAction )
553         (*it)->setChecked( true );
554       checked = (*it)->isChecked();
555     }
556   }
557
558   QList<QtxComboBox*> widgets = myCombo->widgets();
559   for ( QList<QtxComboBox*>::const_iterator wit = widgets.begin(); wit != widgets.end(); ++wit )
560   {
561     QtxComboBox* cb = *wit;
562     bool blocked = cb->signalsBlocked();
563     cb->blockSignals( true );
564     cb->setCurrentId( checked ? id : -1 );
565     cb->blockSignals( blocked );
566   }
567
568   emit moduleActivated( activeModule() );
569 }
570
571 /*!
572   \brief Called when module button is triggered.
573   \internal
574   \param id module identifier
575 */
576 void LightApp_ModuleAction::onTriggered( int id )
577 {
578   activate( id );
579 }
580
581 /*!
582   \brief Called when action state is changed.
583   \internal
584   
585   This slot is used to prevent making the parent action visible.
586 */
587 void LightApp_ModuleAction::onChanged()
588 {
589   if ( !isVisible() )
590     return;
591
592   bool block = signalsBlocked();
593   blockSignals( true );
594   setVisible( false );
595   blockSignals( block );
596 }
597
598 /*!
599   \brief Called when combo box item is activated.
600   \param id module identifier
601 */
602 void LightApp_ModuleAction::onComboActivated( int id )
603 {
604   QApplication::postEvent( this, new ActivateEvent( QEvent::MaxUser, id ) );
605