Salome HOME
updated copyright message
[modules/gui.git] / src / LightApp / LightApp_ModuleAction.cxx
1 // Copyright (C) 2007-2023  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 <QtxActionSet.h>
26 #include <QtxComboBox.h>
27 #include <QtxResourceMgr.h>
28 #include <QVBoxLayout>
29 #include <QApplication>
30 #include <QEvent>
31 #include <QMenu>
32 #include <QSignalMapper>
33
34 #include <utilities.h>
35
36 // Prevent slot compilation error
37 #pragma push_macro("slots")
38 #undef slots
39 #include "PyInterp_Utils.h"
40 #pragma pop_macro("slots")
41
42 /*!
43   \class LightApp_ModuleAction::ActionSet
44   \brief Internal class to represent list of modules buttons.
45   \internal
46 */
47
48 class LightApp_ModuleAction::ActionSet : public QtxActionSet
49 {
50 public:
51   ActionSet( QObject* );
52   QAction* moduleAction( const QString& ) const;
53   int      moduleId( const QString& ) const;
54   int      moduleId( QAction* ) const;
55   void     setVisible( bool );
56 };
57
58 /*!
59   \brief Constructor.
60   \internal
61   \param parent parent object
62 */
63 LightApp_ModuleAction::ActionSet::ActionSet( QObject* parent )
64 : QtxActionSet( parent )
65 {
66 }
67
68 /*!
69   \brief Get action corresponding to the specified module.
70   \internal
71   \param name module name
72   \return module action or 0 if \a name is invalid
73 */
74 QAction* LightApp_ModuleAction::ActionSet::moduleAction( const QString& name ) const
75 {
76   QAction* a = 0;
77
78   QList<QAction*> alist = actions();
79   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end() && !a; ++it )
80   {
81     if ( (*it)->text() == name )
82       a = *it;
83   }
84
85   return a;
86 }
87
88 /*!
89   \brief Get module action identifier.
90   \internal
91   \param name module name
92   \return module action ID or -1 if \a name is invalid
93 */
94 int LightApp_ModuleAction::ActionSet::moduleId( const QString& name ) const
95 {
96   int id = -1;
97
98   QList<QAction*> alist = actions();
99   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end() && id == -1; ++it )
100   {
101     if ( (*it)->text() == name )
102       id = actionId( *it );
103   }
104
105   return id;
106 }
107
108 /*!
109   \brief Get module action identifier.
110   \internal
111   \param a module action
112   \return module action ID or -1 if \a a is null or invalid
113 */
114 int LightApp_ModuleAction::ActionSet::moduleId( QAction* a ) const
115 {
116   return actionId( a );
117 }
118
119 /*!
120   \brief Show/hide modules actions.
121   \internal
122   \param on new visibility state
123 */
124 void LightApp_ModuleAction::ActionSet::setVisible( bool on )
125 {
126   QList<QAction*> alist = actions();
127   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end(); ++it )
128     (*it)->setVisible( on );
129
130   QtxActionSet::setVisible( on );
131 }
132
133 /*!
134   \class LightApp_ModuleAction::ComboAction
135   \brief Internal class to represent combo box with the list of modules in the toolbar.
136   \internal
137 */
138
139 /*!
140   \brief Constructor.
141   \internal
142   \param parent parent object
143 */
144 LightApp_ModuleAction::ComboAction::ComboAction( QObject* parent )
145 : QtxAction( parent )
146 {
147 }
148
149 /*!
150   \brief Get list of associated widgets.
151   \internal
152   \return list of created widgets (QtxComboBox)
153 */
154 QList<QtxComboBox*> LightApp_ModuleAction::ComboAction::widgets() const
155 {
156   QList<QtxComboBox*> lst;
157
158   QList<QWidget*> wlist = createdWidgets();
159   for ( QList<QWidget*>::const_iterator wit = wlist.begin(); wit != wlist.end(); ++wit )
160     lst += qobject_cast<QtxComboBox*>(*wit);
161
162   return lst;
163 }
164
165 /*!
166   \brief Create combo box widget by request from the toolbar.
167   \internal
168   \param parent parent widget (should be QToolBar or its successor)
169   \return new custom widget, containing combo box
170 */
171 QWidget* LightApp_ModuleAction::ComboAction::createWidget( QWidget* parent )
172 {
173   if ( !parent->inherits( "QToolBar" ) )
174     return 0;
175
176   QtxComboBox* cb = new QtxComboBox( parent );
177   cb->setSizeAdjustPolicy( QComboBox::AdjustToContents );
178   cb->setFocusPolicy( Qt::NoFocus );
179   connect( cb, SIGNAL( activatedId( int ) ), this, SIGNAL( activatedId( int ) ) );
180   return cb;
181 }
182
183 /*!
184   \fn void LightApp_ModuleAction::ComboAction::activatedId( int id );
185   \internal
186   \brief Emitted when the combo box item is activated
187   \param item identifier
188 */
189
190 /*!
191   \class LightApp_ModuleAction::ActivateEvent
192   \brief Internal class to represent custom event for transfer the activation item id.
193   \internal
194 */
195 class LightApp_ModuleAction::ActivateEvent : public QEvent
196 {
197 public:
198   ActivateEvent( QEvent::Type type, int id ) : QEvent( type ), myId( id ) {};
199   ~ActivateEvent() {};
200
201   int     id() const { return myId; }
202
203 private:
204   int     myId;
205 };
206
207 /*!
208   \class LightApp_ModuleAction
209   \brief An action, representing the list of modules to be inserted to the
210   toolbar.
211
212   In the toolbar this action is represented as the combo box with the list of
213   available modules, and a set of buttons for each module. Additionally, combo box
214   contains an item representing "neutral point" of the application (i.e. no active module).
215
216   In menu, the action is represented as a plain list of items, one per module.
217
218   Only one module can be active at the moment. It can be set programmatically
219   with setActiveModule() function. Use this method with empty string to turn
220   to the "neutral point". To get active module, use activeModule() function.
221
222   When user activates/deactivates a module, the moduleActivated() signal
223   is emitted.
224
225   The action also provides an additional separate item "Add modules"; when
226   this button is pressed, a adding() signal is emitted. This signal
227   can be connected to a dedicated slot aimed to dynamically add a new module
228   into the application. In addition, a button "Remove module" shows a dropdown menu
229   with the list of user modules; when any item is selected, the removing() signal
230   is emitted. This signal may be connected to a slot aimed to dynamically remove
231   selected user module from application.
232
233   It is possible to customize which elements to show via the setMode() of setModeEnabled()
234   functions. By default, all elements are shown. The following choices are possible:
235
236   - LightApp_ModuleAction::Buttons: show separate items for all modules
237   - LightApp_ModuleAction::List: show combo box with list of modules (in toolbar only)
238   - LightApp_ModuleAction::AddRemove: show "Add modules" and "Remove modules" items
239   - LightApp_ModuleAction::All: show all items
240 */
241
242 /*!
243   \brief Constructor
244   \param resMgr resource manager
245   \param parent parent object
246 */
247 LightApp_ModuleAction::LightApp_ModuleAction( QtxResourceMgr* resMgr, QObject* parent )
248 : QtxAction( parent )
249 {
250   setText( tr( "APP_NAME" ) );
251   setIcon( resMgr->loadPixmap( "LightApp", tr( "APP_DEFAULT_ICO" ), false ) );
252   setVisible( false );
253
254   myMode = All;
255   myCombo = new ComboAction( this );
256   myAdd = new QtxAction( tr( "ADD_MODULE"),
257                          resMgr->loadPixmap( "LightApp", tr( "ICON_ADD_MODULE" ), false ),
258                          tr( "ADD_MODULE"),
259                          0, this );
260   myRemove = new QtxAction( tr( "REMOVE_MODULE"),
261                             resMgr->loadPixmap( "LightApp", tr( "ICON_REMOVE_MODULE" ), false ),
262                             tr( "REMOVE_MODULE"),
263                             0, this );
264   myRemove->setEnabled( false );
265   myRemove->setMenu( new QMenu() );
266   myInfo = new QtxAction( tr( "INFO_MODULE"),
267                             resMgr->loadPixmap( "LightApp", tr( "ICON_INFO_MODULE" ), false ),
268                             tr( "INFO_MODULE"),
269                             0, this );
270   mySeparator = new QAction( this );
271   mySeparator->setSeparator( true );
272   mySet = new ActionSet( this );
273
274   myMapper = new QSignalMapper( this );
275
276   connect( this,     SIGNAL( changed() ),          this, SLOT( onChanged() ) );
277   connect( myAdd,    SIGNAL( triggered( bool ) ),  this, SIGNAL( adding() ) );
278   connect( myInfo,   SIGNAL( triggered( bool ) ),  this, SIGNAL( showExtInfo() ) );
279   connect( mySet,    SIGNAL( triggered( int ) ),   this, SLOT( onTriggered( int ) ) );
280   connect( myCombo,  SIGNAL( activatedId( int ) ), this, SLOT( onComboActivated( int ) ) );
281   connect( myMapper, SIGNAL( mapped( QString ) ),  this, SIGNAL( removing( QString ) ) );
282 }
283
284 /*!
285   \brief Destructor
286 */
287 LightApp_ModuleAction::~LightApp_ModuleAction()
288 {
289 }
290
291 /*!
292   \brief Get number of registered modules.
293   \return modules count
294 */
295 int LightApp_ModuleAction::count() const
296 {
297   return modules().count();
298 }
299
300 /*!
301   \brief Get list of modules.
302   \return modules names list
303 */
304 QStringList LightApp_ModuleAction::modules() const
305 {
306   QStringList lst;
307
308   QList<QAction*> alist = mySet->actions();
309   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end(); ++it )
310     lst.append( (*it)->text() );
311
312   return lst;
313 }
314
315 /*!
316   \brief Get module icon.
317   \param name module name
318   \return module icon
319   \sa setModuleIcon()
320 */
321 QIcon LightApp_ModuleAction::moduleIcon( const QString& name ) const
322 {
323   QAction* a = mySet->moduleAction( name );
324   return a ? a->icon() : QIcon();
325 }
326
327 /*!
328   \brief Set module icon.
329   \param name module name
330   \param ico new module icon
331   \sa moduleIcon()
332 */
333 void LightApp_ModuleAction::setModuleIcon( const QString& name, const QIcon& ico )
334 {
335   QAction* a = mySet->moduleAction( name );
336   if ( !a )
337     return;
338
339   a->setIcon( ico );
340   update();
341 }
342
343 /*!
344   \brief Get module action.
345   \param name module name
346 */
347 QAction* LightApp_ModuleAction::moduleAction( const QString& name ) const
348 {
349   return mySet->moduleAction( name );
350 }
351
352 /*!
353   \brief Add module into the list.
354   \param name module name
355   \param ico module icon
356   \param idx position in the module list (if -1, the module is added to the end of list)
357   \sa removeModule()
358 */
359 void LightApp_ModuleAction::insertModule( const QString& name, const QIcon& ico,
360                                           const int idx )
361 {
362   insertModule( name, ico, false, idx );
363 }
364
365 /*!
366   \brief Add module into the list.
367   \param name module name
368   \param ico module icon
369   \param isCustom \c false to insert regular module, \c true to insert user module
370   \param idx position in the module list (if -1, the module is added to the end of list)
371   \sa removeModule()
372 */
373 void LightApp_ModuleAction::insertModule( const QString& name, const QIcon& ico,
374                                           bool isCustom, const int idx)
375
376 {
377   QtxAction* a = new QtxAction( name, ico, name, 0, this, true );
378   a->setStatusTip( tr( "ACTIVATE_MODULE_TOP" ).arg( name ) );
379  
380   // Commented because the next call mySet->insertAction() overrides it with
381   // action id int != 0 value, so test a->data().toBool() is always true after that.
382   // Leave it here to mention that we need other approach to mark module as custom.
383   // a->setData( isCustom );
384
385   mySet->insertAction( a, -1, idx );
386   update();
387 }
388
389 /*!
390   \brief Remove module from the list.
391   \param name module name
392   \sa insertModule()
393 */
394 void LightApp_ModuleAction::removeModule( const QString& name )
395 {
396   MESSAGE("Start to remove module...");
397
398   int id = mySet->moduleId( name );
399   SCRUTE(id);
400   if ( id == -1 )
401   {
402     MESSAGE("Can't get a module's id! Return");
403     return;
404   }
405
406   MESSAGE("Remove action by id...");
407   mySet->removeAction(id);
408
409   update();
410
411   MESSAGE("Module was removed");
412 }
413
414 /*!
415   \brief Add an installed extension. Now only to the Remove button's menu.
416   \param name an extension's name
417   \sa removeExtension()
418 */
419 void LightApp_ModuleAction::insertExtension(const QString& name)
420 {
421   MESSAGE("Insert an extension's action...");
422   SCRUTE(name.toStdString());
423
424   myRemove->setEnabled(true);
425
426   // Find a place to insert in the alphabetical order
427   QAction* insertBefore = nullptr;
428   foreach(QAction* curAction, myRemove->menu()->actions())
429   {
430     int compareRes = QString::compare(curAction->text(), name, Qt::CaseInsensitive);
431     if (!compareRes)
432     {
433       return; // already added
434     }
435     else if (compareRes > 0)
436     {
437       insertBefore = curAction;
438
439       SCRUTE(insertBefore->text().toStdString());
440       break;
441     }
442   }
443
444   QAction* inserted = new QAction(name);
445
446   myRemove->menu()->insertAction(insertBefore, inserted);
447   connect(inserted, SIGNAL(triggered()), myMapper, SLOT(map()));
448   myMapper->setMapping(inserted, name);
449
450   MESSAGE("An extension's action was inserted");
451 }
452
453 /*!
454   \brief Remove an installed extension.
455   \param name an extension's name
456   \sa insertExtension()
457 */
458 void LightApp_ModuleAction::removeExtension(const QString& name)
459 {
460   MESSAGE("Remove an extension's action...");
461   SCRUTE(name.toStdString());
462
463   foreach(QAction* ma, myRemove->menu()->actions())
464   {
465     if (ma->text() == name)
466     {
467       myRemove->menu()->removeAction(ma);
468
469       MESSAGE("Extension's action was removed");
470       break;
471     }
472   }
473
474   myRemove->setEnabled(!myRemove->menu()->actions().isEmpty());
475
476   updateExtActions();
477   update();
478 }
479
480 /*!
481   \brief Get active module.
482
483   If there is no active module ("neutral point"), then the null string
484   is returned.
485
486   \return active module name
487   \sa setActiveModule()
488 */
489 QString LightApp_ModuleAction::activeModule() const
490 {
491   QAction* a = active();
492   return a ? a->text() : QString();
493 }
494
495 /*!
496   \brief Set active module.
497
498   To turn to the "neutral point" (no active module), pass empty string.
499
500   \param name new active module name
501   \sa activeModule()
502 */
503 void LightApp_ModuleAction::setActiveModule( const QString& name )
504 {
505   if ( name == activeModule() )
506     return;
507
508   int id = mySet->moduleId( name );
509   if ( name.isEmpty() || id != -1 )
510     activate( id, false );
511 }
512
513 /*!
514   \brief Set action display mode.
515   \param mode action display options (combination of flags)
516   \sa mode()
517 */
518 void LightApp_ModuleAction::setMode( const LightApp_ModuleAction::Mode& mode )
519 {
520   myMode = mode;
521   update();
522 }
523
524 /*!
525   \brief Enable / disable action display mode.
526   \param mode action display options (combination of flags)
527   \param enabled \c true to enable mode, \c false to disable mode
528   \sa mode()
529 */
530 void LightApp_ModuleAction::setModeEnabled( const LightApp_ModuleAction::Mode& mode, bool enabled )
531 {
532   if ( enabled )
533     myMode |= mode;
534   else
535     myMode &= ~mode;
536   update();
537 }
538
539 /*!
540   \brief Get action display mode.
541   \param mode action display mode
542   \sa setMode()
543 */
544 bool LightApp_ModuleAction::isModeEnabled( const LightApp_ModuleAction::Mode& mode ) const
545 {
546   return (bool)( myMode & mode );
547 }
548
549 /*!
550   \brief Called when the action is added to the widget.
551   \param w widget (not used)
552 */
553 void LightApp_ModuleAction::addedTo( QWidget* w )
554 {
555   if ( w->inherits( "QToolBar" ) )
556     w->insertAction( this, myCombo );
557   w->insertAction( this, myAdd );
558   w->insertAction( this, myRemove );
559   w->insertAction( this, myInfo );
560   w->insertAction( this, mySeparator );
561   w->insertAction( this, mySet );
562   update();
563 }
564
565 /*!
566   \brief Remove action from widget.
567   \param w widget (menu or toolbar)
568   \return \c true if the action is removed successfully and \c false otherwise.
569   \sa addTo()
570 */
571 void LightApp_ModuleAction::removedFrom( QWidget* w )
572 {
573   if ( w->inherits( "QToolBar" ) )
574     w->removeAction( myCombo );
575   w->removeAction( myAdd );
576   w->removeAction( myRemove );
577   w->removeAction( myInfo );
578   w->removeAction( mySeparator );
579   w->removeAction( mySet );
580 }
581
582 /*!
583   \brief Perform delayed activation with specified id.
584   \param e custom event
585   \return \c true if the event was processed successfully and \c false otherwise.
586 */
587 bool LightApp_ModuleAction::event( QEvent* e )
588 {
589   if ( e->type() == QEvent::MaxUser ) {
590     activate( ((ActivateEvent*)e)->id(), false );
591     return true;
592   }
593   return QtxAction::event( e );
594 }
595
596 /*!
597   \fn void LightApp_ModuleAction::moduleActivated( const QString& name );
598   \brief Emitted when the module is activated
599   \param name module name (empty string for neutral point)
600 */
601
602 /*!
603   \brief Update an action.
604   \internal
605 */
606 void LightApp_ModuleAction::update()
607 {
608   QList<QtxComboBox*> lst = myCombo->widgets();
609   for ( QList<QtxComboBox*>::const_iterator it = lst.begin(); it != lst.end(); ++it )
610     update( *it );
611
612
613   myCombo->setVisible( myMode & List );
614   if ( QString::compare(getenv("SALOME_ON_DEMAND"),"HIDE", Qt::CaseInsensitive) != 0)
615   {
616     myAdd->setVisible( myMode & AddRemove );
617     myRemove->setVisible( myMode & AddRemove );
618     myInfo->setVisible( myMode & All );
619   }
620   else
621   {
622     myAdd->setVisible(false);
623     myRemove->setVisible( false );
624     myInfo->setVisible( false );
625   }
626   mySet->setVisible( myMode & Buttons );
627 }
628
629 /*!
630   \brief Update combo box.
631   \internal
632   \param cb combo box
633 */
634 void LightApp_ModuleAction::update( QtxComboBox* cb )
635 {
636   if ( !cb )
637     return;
638
639   bool blocked = cb->blockSignals( true );
640   int curId = mySet->moduleId( active() );
641   QList<QAction*> alist = mySet->actions();
642   cb->clear();
643
644   cb->addItem( icon(), text() );
645   cb->setId( 0, -1 );
646
647   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end(); ++it )
648   {
649     QAction* a = *it;
650     int id = mySet->moduleId( a );
651     cb->addItem( a->icon(), a->text() );
652     cb->setId( cb->count() - 1, id );
653   }
654
655   cb->setCurrentId( curId );
656   cb->blockSignals( blocked );
657 }
658
659 /*!
660   \brief Update extension actions based on dependencies.
661   \internal
662   \param
663 */
664 void LightApp_ModuleAction::updateExtActions()
665 {
666   MESSAGE("Check dependencies to update extensions actions...");
667
668   // It should be set on the app start
669   auto extRootDir = getenv("SALOME_APPLICATION_DIR");
670   if (!extRootDir)
671   {
672     MESSAGE("Cannot get SALOME_APPLICATION_DIR env variable! Cancel adding selected extensions.");
673     return;
674   }
675   SCRUTE(extRootDir);
676
677   // Import Python module that manages SALOME extensions.
678   PyLockWrapper lck; // acquire GIL
679   PyObjWrapper extensionQuery = PyImport_ImportModule((char*)"SalomeOnDemandTK.extension_query");
680   PyObjWrapper extCanRemoveDict = PyObject_CallMethod(extensionQuery, (char*)"ext_canremove_flags", (char*)"s", extRootDir);
681   if (!extCanRemoveDict || extCanRemoveDict == Py_None)
682   {
683     MESSAGE("Couldn't get <ext>:<can_remove> dictionary from SalomeOnDemandTK.extension_query! Return.");
684     return;
685   }
686
687   // Iterate extensions' actions to disable ones we can't remove because of dependencies.
688   foreach(QAction* curAction, myRemove->menu()->actions())
689   {
690     const std::string action_name = curAction->text().toStdString();
691     SCRUTE(action_name);
692
693     PyObject* canRemoveObject = PyDict_GetItemString(extCanRemoveDict, action_name.c_str());
694     if (!canRemoveObject)
695     {
696       MESSAGE("Couldn't get can remove flag from dictionary! Skip.");
697       continue;
698     }
699
700     const int isTrueRes = PyObject_IsTrue(canRemoveObject);
701     if (isTrueRes == -1)
702     {
703       MESSAGE("PyObject_IsTrue() failed. Using false value instead.");
704     }
705     const bool canRemove = isTrueRes == 1;
706     SCRUTE(canRemove);
707
708     curAction->setEnabled(canRemove);
709   }
710 }
711
712 /*!
713   \brief Get an action corresponding to the active module.
714   \internal
715   \return active module action or 0 if there is no active module
716 */
717 QAction* LightApp_ModuleAction::active() const
718 {
719   QAction* a = 0;
720
721   QList<QAction*> alist = mySet->actions();
722   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end() && !a; ++it )
723   {
724     if ( (*it)->isChecked() )
725       a = *it;
726   }
727
728   return a;
729 }
730
731 /*!
732   \brief Activate a module item.
733   \internal
734   \param id module identifier
735   \param fromAction \c true if function is called from the module button
736 */
737 void LightApp_ModuleAction::activate( int id, bool fromAction )
738 {
739   bool checked = false;
740
741   QList<QAction*> alist = mySet->actions();
742   for ( QList<QAction*>::const_iterator it = alist.begin(); it != alist.end(); ++it )
743   {
744     if ( mySet->moduleId( *it ) != id ) {
745       (*it)->setChecked( false );
746     }
747     else {
748       if ( !fromAction )
749         (*it)->setChecked( true );
750       checked = (*it)->isChecked();
751     }
752   }
753
754   QList<QtxComboBox*> widgets = myCombo->widgets();
755   for ( QList<QtxComboBox*>::const_iterator wit = widgets.begin(); wit != widgets.end(); ++wit )
756   {
757     QtxComboBox* cb = *wit;
758     bool blocked = cb->signalsBlocked();
759     cb->blockSignals( true );
760     cb->setCurrentId( checked ? id : -1 );
761     cb->blockSignals( blocked );
762   }
763
764   emit moduleActivated( activeModule() );
765 }
766
767 /*!
768   \brief Called when module button is triggered.
769   \internal
770   \param id module identifier
771 */
772 void LightApp_ModuleAction::onTriggered( int id )
773 {
774   activate( id );
775 }
776
777 /*!
778   \brief Called when action state is changed.
779   \internal
780
781   This slot is used to prevent making the parent action visible.
782 */
783 void LightApp_ModuleAction::onChanged()
784 {
785   if ( !isVisible() )
786     return;
787
788   bool block = signalsBlocked();
789   blockSignals( true );
790   setVisible( false );
791   blockSignals( block );
792 }
793
794 /*!
795   \brief Called when combo box item is activated.
796   \param id module identifier
797 */
798 void LightApp_ModuleAction::onComboActivated( int id )
799 {
800   QApplication::postEvent( this, new ActivateEvent( QEvent::MaxUser, id ) );
801 }