Salome HOME
31f2f09f9e0f46fe27207f7307abc3788d5531e7
[modules/gui.git] / src / Qtx / QtxActionGroup.cxx
1 // Copyright (C) 2007-2022  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:      QtxActionGroup.cxx
21 // Author:    Sergey TELKOV
22 //
23 #include "QtxActionGroup.h"
24
25 #include "QtxComboBox.h"
26
27 #include <QMenu>
28 #include <QMenuBar>
29 #include <QActionGroup>
30
31 /*!
32   \class QtxActionGroup
33   \brief The QtxActionGroup class groups actions together.
34
35   QtxActionGroup class operates with a list of actions in the similar way as it does QActionGroup class.
36   But in contrast to the Qt 4's class, QtxActrionGroup behaves rather like it was in Qt series 3x.
37   For example, it automatically shows exclusive combo box widget when action group is added to the toolbar
38   and if \a usesDropDown and \a exclusive flags are both set to \c true.
39   
40   The setExclusive() function is used to ensure that only one action is active at any moment:
41   it should be used with actions which have their \a checkable state set to \c true.
42
43   Action group actions appear as individual menu options and toolbar buttons. For exclusive action
44   groups use setUsesDropDown() to display the actions in a subwidget of the toolbar or menu the action group
45   is added on.
46
47   Actions can be added to the action group using add() function. Add the action group to the menu or
48   toolbar in the same way as for single action - using addAction() method of QMenu or QToolbar class.
49 */
50
51 /*!
52   \brief Constructor
53
54   The created action group is exclusive by default.
55
56   \param parent owner object
57   \sa setExclusive()
58 */
59 QtxActionGroup::QtxActionGroup( QObject* parent )
60 : QtxActionSet( parent ),
61   myDropDown( false )
62 {
63   setMenu( new QMenu( 0 ) );
64   myActionGroup = new QActionGroup( this );
65
66   connect( myActionGroup, SIGNAL( triggered( QAction* ) ), this, SLOT( onTriggered( QAction* ) ) );
67 }
68
69 /*!
70   \brief Constructor
71   \param parent owner object
72   \param exclusive if \c true only one action in the group will ever be active
73   \sa setExclusive()
74 */
75 QtxActionGroup::QtxActionGroup( QObject* parent, const bool exclusive )
76 : QtxActionSet( parent ),
77   myDropDown( false )
78 {
79   setMenu( new QMenu( 0 ) );
80   myActionGroup = new QActionGroup( this );
81   myActionGroup->setExclusive( exclusive );
82
83   connect( myActionGroup, SIGNAL( triggered( QAction* ) ), this, SIGNAL( selected( QAction* ) ) );
84 }
85
86 /*!
87   \brief Destructor.
88 */
89 QtxActionGroup::~QtxActionGroup()
90 {
91 }
92
93 /*!
94   \brief Check if the action group is exclusive
95   \return \c true if the action group is exclusive and \c false otherwise
96   \sa setExclusive(), setUsesDropDown()
97 */
98 bool QtxActionGroup::isExclusive() const
99 {
100   return myActionGroup->isExclusive();
101 }
102
103 /*!
104   \brief Set/clear the action group exclusiveness
105   \param on if \c true the action group will be exclusive
106   \sa isExclusive(), setUsesDropDown()
107 */
108 void QtxActionGroup::setExclusive( const bool on )
109 {
110   if ( myActionGroup->isExclusive() == on )
111     return;
112
113   bool e = isEmptyAction();
114
115   myActionGroup->setExclusive( on );
116
117   if ( e != isEmptyAction() )
118     updateType();
119 }
120
121 /*!
122   \brief Check if action group should appear in a subwidget of parent widget
123
124   Note: for this option to take into effect, the \a exclusive flag should
125   be also set to \c true
126
127   \return \c true if the action group is shown in subwidget
128   \sa setUsesDropDown(), setExclusive()
129 */
130 bool QtxActionGroup::usesDropDown() const
131 {
132   return myDropDown;
133 }
134
135 /*!
136   \brief Defines a way how the group's actions should be displayed in parent widget 
137   action group is added to - as a group of actions or in a subwidget (e.g. in the
138   combo box).
139   \param on if \c true, action group will be shown in the subwidget
140   \sa usesDropDown(), setExclusive()
141 */
142 void QtxActionGroup::setUsesDropDown( const bool on )
143 {
144   if ( myDropDown == on )
145     return;
146
147   bool e = isEmptyAction();
148
149   myDropDown = on;
150
151   if ( e != isEmptyAction() )
152     updateType();
153 }
154
155 /*!
156   \brief Append the specified action into group.
157   \a action action to be added to the action group
158 */
159 void QtxActionGroup::add( QAction* a )
160 {
161   insertAction( a );
162 }
163
164 /*!
165   \brief Called when some subwidget item is activated by the user.
166   \param id item identifier
167 */
168 void QtxActionGroup::onActivated( int id )
169 {
170   const QObject* s = sender();
171
172   QAction* a = action( id );
173   if ( !a )
174     return;
175
176   if ( a->isChecked() )
177     return;
178
179   a->setChecked( true );
180   a->trigger();
181
182   QList<QWidget*> lst = createdWidgets();
183   for ( QList<QWidget*>::iterator it = lst.begin(); it != lst.end(); ++it )
184   {
185     QtxComboBox* cb = ::qobject_cast<QtxComboBox*>( *it );
186     if ( cb && cb != s )
187       cb->setCurrentId( id );
188   }
189 }
190
191 /*!
192   \brief Called when some action owned by this action group is activated by the user
193   \param a action being activated
194 */
195 void QtxActionGroup::onTriggered( QAction* a )
196 {
197   int id = actionId( a );
198   if ( id != -1 ) {
199     QList<QWidget*> lst = createdWidgets();
200     for ( QList<QWidget*>::iterator it = lst.begin(); it != lst.end(); ++it )
201     {
202       QtxComboBox* cb = ::qobject_cast<QtxComboBox*>( *it );
203       if ( cb )
204         cb->setCurrentId( id );
205     }
206   }
207   
208   emit selected( a );
209 }
210
211 /*!
212   \brief Enable/disable action group
213 */
214 void QtxActionGroup::setEnabled( bool on )
215 {
216   QtxActionSet::setEnabled( on );
217   myActionGroup->setEnabled( on );
218 }
219
220 /*!
221   \brief Update action group for the specified widget.
222   \param w a widget this action group is added to
223 */
224 void QtxActionGroup::updateAction( QWidget* w )
225 {
226   if ( !::qobject_cast<QMenu*>( w ) && !::qobject_cast<QMenuBar*>( w ) ) {
227     QtxComboBox* cb = createdWidget( w );
228     if ( !cb )
229       QtxActionSet::updateAction( w );
230     else
231     {
232       updateAction( cb );
233       
234       QList<QAction*> lst = actions();
235       for ( QList<QAction*>::iterator it = lst.begin(); it != lst.end(); ++it )
236         w->removeAction( *it );
237     }
238   }
239   else
240   {
241     if ( !usesDropDown() ) {
242       QtxActionSet::updateAction( w );
243     }
244     else {
245       QList<QAction*> lst = actions();
246       for ( QList<QAction*>::iterator it = lst.begin(); it != lst.end(); ++it )
247         w->removeAction( *it );
248     }
249   }
250 }
251
252 /*!
253   \brief Update action group for the specified combo box.
254   \param cb a combo box this action group is added to
255 */
256 void QtxActionGroup::updateAction( QtxComboBox* cb )
257 {
258   if ( !cb )
259     return;
260
261   cb->clear();
262   cb->setCleared( false );
263
264   QAction* cur = 0;
265   QList<QAction*> lst = actions();
266   for ( QList<QAction*>::iterator it = lst.begin(); it != lst.end(); ++it )
267   {
268     QAction* a = *it;
269     cb->addItem( a->icon(), a->text() );
270     cb->setId( cb->count() - 1, actionId( a ) );
271     if ( a->isChecked() )
272       cur = a;
273   }
274
275   if ( cur )
276     cb->setCurrentId( actionId( cur ) );
277   else
278     cb->setCleared( true );
279 }
280
281 /*!
282   \brief Create widget representing action group in the widget
283   this action group is added to.
284   \param p widget this action group is being added to
285   \return new widget representing this action group
286 */
287 QWidget* QtxActionGroup::createWidget( QWidget* p )
288 {
289   if ( ::qobject_cast<QMenu*>( p ) || ::qobject_cast<QMenuBar*>( p ) )
290     return 0;
291
292   QtxComboBox* cb = !isEmptyAction() ? new QtxComboBox( p ) : 0;
293   if ( cb )
294     connect( cb, SIGNAL( activatedId( int ) ), this, SLOT( onActivated( int ) ) );
295   return cb;
296 }
297
298 /*!
299   \brief Check if the action itself should be invisible
300   (only child action are shown)
301   \return \c true if the action itself should be visible
302 */
303 bool QtxActionGroup::isEmptyAction() const
304 {
305   return !isExclusive() || !usesDropDown();
306 }
307
308 /*!
309   \brief Called when action is added to the action group
310   \param a action being added to the action group
311 */
312 void QtxActionGroup::actionAdded( QAction* a )
313 {
314   myActionGroup->addAction( a );
315   if ( menu() )
316     menu()->addAction( a );
317 }
318
319 /*!
320   \brief Called when action is removed from the action group
321   \param a action being removed from the action group
322 */
323 void QtxActionGroup::actionRemoved( QAction* a )
324 {
325   myActionGroup->removeAction( a );
326   if ( menu() )
327     menu()->removeAction( a );
328 }
329
330 /*!
331   \brief Internal update
332 */
333 void QtxActionGroup::updateType()
334 {
335   QList<QWidget*> lst = associatedWidgets();
336   for ( QList<QWidget*>::iterator it = lst.begin(); it != lst.end(); ++it )
337   {
338     QWidget* w = *it;
339     QList<QAction*> lst = w->actions();
340
341     int i = lst.indexOf( this );
342     w->removeAction( this );
343
344     lst = w->actions();
345     w->insertAction( i < lst.count() ? lst.at( i ) : 0, this );
346   }
347   setVisible( !isEmptyAction() );
348 }
349
350 /*!
351   \brief Get combo box created by this action group for the specified widget.
352   \param p widget this action group is added to
353   \return combo box if it was created for the specified widget or 0 otherwise
354 */
355 QtxComboBox* QtxActionGroup::createdWidget( QWidget* p )
356 {
357   QtxComboBox* cb = 0;
358   QList<QWidget*> lst = createdWidgets();
359   for ( QList<QWidget*>::iterator it = lst.begin(); it != lst.end() && !cb; ++it )
360   {
361     if ( (*it)->parent() == p )
362       cb = ::qobject_cast<QtxComboBox*>( *it );
363   }
364   return cb;
365 }
366
367 /*!
368   \fn void QtxActionGroup::selected( QAction* a );
369   \brief Emitted when some child action is toggled by the user.
370   \param a action being toggled
371 */