Salome HOME
Merge from V6_main 01/04/2013
[modules/gui.git] / src / Qtx / QtxActionGroup.cxx
1 // Copyright (C) 2007-2013  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.
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 Update action group for the specified widget.
213   \param w a widget this action group is added to
214 */
215 void QtxActionGroup::updateAction( QWidget* w )
216 {
217   if ( !::qobject_cast<QMenu*>( w ) && !::qobject_cast<QMenuBar*>( w ) ) {
218     QtxComboBox* cb = createdWidget( w );
219     if ( !cb )
220       QtxActionSet::updateAction( w );
221     else
222     {
223       updateAction( cb );
224       
225       QList<QAction*> lst = actions();
226       for ( QList<QAction*>::iterator it = lst.begin(); it != lst.end(); ++it )
227         w->removeAction( *it );
228     }
229   }
230   else
231   {
232     if ( !usesDropDown() ) {
233       QtxActionSet::updateAction( w );
234     }
235     else {
236       QList<QAction*> lst = actions();
237       for ( QList<QAction*>::iterator it = lst.begin(); it != lst.end(); ++it )
238         w->removeAction( *it );
239     }
240   }
241 }
242
243 /*!
244   \brief Update action group for the specified combo box.
245   \param cb a combo box this action group is added to
246 */
247 void QtxActionGroup::updateAction( QtxComboBox* cb )
248 {
249   if ( !cb )
250     return;
251
252   cb->clear();
253   cb->setCleared( false );
254
255   QAction* cur = 0;
256   QList<QAction*> lst = actions();
257   for ( QList<QAction*>::iterator it = lst.begin(); it != lst.end(); ++it )
258   {
259     QAction* a = *it;
260     cb->addItem( a->icon(), a->text() );
261     cb->setId( cb->count() - 1, actionId( a ) );
262     if ( a->isChecked() )
263       cur = a;
264   }
265
266   if ( cur )
267     cb->setCurrentId( actionId( cur ) );
268   else
269     cb->setCleared( true );
270 }
271
272 /*!
273   \brief Create widget representing action group in the widget
274   this action group is added to.
275   \param p widget this action group is being added to
276   \return new widget representing this action group
277 */
278 QWidget* QtxActionGroup::createWidget( QWidget* p )
279 {
280   if ( ::qobject_cast<QMenu*>( p ) || ::qobject_cast<QMenuBar*>( p ) )
281     return 0;
282
283   QtxComboBox* cb = !isEmptyAction() ? new QtxComboBox( p ) : 0;
284   if ( cb )
285     connect( cb, SIGNAL( activatedId( int ) ), this, SLOT( onActivated( int ) ) );
286   return cb;
287 }
288
289 /*!
290   \brief Check if the action itself should be invisible
291   (only child action are shown)
292   \return \c true if the action itself should be visible
293 */
294 bool QtxActionGroup::isEmptyAction() const
295 {
296   return !isExclusive() || !usesDropDown();
297 }
298
299 /*!
300   \brief Called when action is added to the action group
301   \param a action being added to the action group
302 */
303 void QtxActionGroup::actionAdded( QAction* a )
304 {
305   myActionGroup->addAction( a );
306   if ( menu() )
307     menu()->addAction( a );
308 }
309
310 /*!
311   \brief Called when action is removed from the action group
312   \param a action being removed from the action group
313 */
314 void QtxActionGroup::actionRemoved( QAction* a )
315 {
316   myActionGroup->removeAction( a );
317   if ( menu() )
318     menu()->removeAction( a );
319 }
320
321 /*!
322   \brief Internal update
323 */
324 void QtxActionGroup::updateType()
325 {
326   QList<QWidget*> lst = associatedWidgets();
327   for ( QList<QWidget*>::iterator it = lst.begin(); it != lst.end(); ++it )
328   {
329     QWidget* w = *it;
330     QList<QAction*> lst = w->actions();
331
332     int i = lst.indexOf( this );
333     w->removeAction( this );
334
335     lst = w->actions();
336     w->insertAction( i < lst.count() ? lst.at( i ) : 0, this );
337   }
338   setVisible( !isEmptyAction() );
339 }
340
341 /*!
342   \brief Get combo box created by this action group for the specified widget.
343   \param p widget this action group is added to
344   \return combo box if it was created for the specified widget or 0 otherwise
345 */
346 QtxComboBox* QtxActionGroup::createdWidget( QWidget* p )
347 {
348   QtxComboBox* cb = 0;
349   QList<QWidget*> lst = createdWidgets();
350   for ( QList<QWidget*>::iterator it = lst.begin(); it != lst.end() && !cb; ++it )
351   {
352     if ( (*it)->parent() == p )
353       cb = ::qobject_cast<QtxComboBox*>( *it );
354   }
355   return cb;
356 }
357
358 /*!
359   \fn void QtxActionGroup::selected( QAction* a );
360   \brief Emitted when some child action is toggled by the user.
361   \param a action being toggled
362 */