1 // SALOME PatchQt : patch for Qt
3 // Copyright (C) 2003 CEA/DEN, EDF R&D
8 // Author : Vadim SANDLER
18 #include <qpopupmenu.h>
20 #include <qtoolbutton.h>
21 #include <qcombobox.h>
23 #include <qwhatsthis.h>
24 #include <qstatusbar.h>
25 #include <qobjectlist.h>
29 \class QActionP qaction.h
33 \brief The QActionP class provides an abstract user interface
34 action that can appear both in menus and tool bars.
36 In GUI applications many commands can be invoked via a menu option, a
37 toolbar button and a keyboard accelerator. Since the same action must
38 be performed regardless of how the action was invoked, and since the
39 menu and toolbar should be kept in sync, it is useful to represent a
40 command as an \e action. An action can be added to a menu and a
41 toolbar and will automatically keep them in sync. For example, if the
42 user presses a Bold toolbar button the Bold menu item will
43 automatically be checked.
45 A QActionP may contain an icon, a menu text, an accelerator, a status
46 text, a whats this text and a tool tip. Most of these can be set in
47 the constructor. They can also be set independently with setIconSet(),
48 setText(), setMenuText(), setToolTip(), setStatusTip(), setWhatsThis()
49 and setAccel(), respectively.
51 An action may be a toggle action e.g. a Bold toolbar button, or a
52 command action, e.g. 'Open File' to invoke an open file dialog.
53 Toggle actions emit the toggled() signal when their state changes.
54 Both command and toggle actions emit the activated() signal when they
55 are invoked. Use setToggleAction() to set an action's toggled status.
56 To see if an action is a toggle action use isToggleAction(). A toggle
57 action may be "on", isOn() returns TRUE, or "off", isOn() returns
60 Actions are added to widgets (menus or toolbars) using addTo(), and
61 removed using removeFrom().
63 Once a QActionP has been created it should be added to the relevant
64 menu and toolbar and then connected to the slot which will perform
65 the action. For example:
67 \quotefile action/application.cpp
71 We create a "File Save" action with a menu text of "&Save" and
72 \e{Ctrl+S} as the keyboard accelerator. We connect the
73 fileSaveAction's activated() signal to our own save() slot. Note that at
74 this point there is no menu or toolbar action, we'll add them next:
78 \skipto fileSaveAction->addTo
80 \skipto new QPopupMenu
81 \printuntil insertItem
82 \skipto fileSaveAction->addTo
85 We create a toolbar and add our fileSaveAction to it. Similarly we
86 create a menu, add a top-level menu item, and add our
89 (See the \link simple-application-action.html Simple Application
90 Walkthrough featuring QActionP \endlink for a detailed example.)
92 We recommend that actions are created as children of the window that
93 they are used in. In most cases actions will be children of the
94 application's main window.
96 To prevent recursion, don't create an action as a child of a widget
97 that the action is later added to.
101 class QActionPPrivate
118 uint toggleaction :1;
120 #ifndef QT_NO_TOOLTIP
121 QToolTipGroup* tipGroup;
125 MenuItem():popup(0),id(0){}
129 // ComboItem is only necessary for actions that are
130 // in dropdown/exclusive actiongroups. The actiongroup
131 // will clean this up
133 ComboItem():combo(0), id(0) {}
137 QPtrList<MenuItem> menuitems;
138 QPtrList<QToolButton> toolbuttons;
139 QPtrList<ComboItem> comboitems;
141 enum Update { Everything, Icons, State }; // Everything means everything but icons and state
142 void update( Update upd = Everything );
144 QString menuText() const;
145 QString toolTip() const;
146 QString statusTip() const;
149 QActionPPrivate::QActionPPrivate()
160 menuitems.setAutoDelete( TRUE );
161 comboitems.setAutoDelete( TRUE );
162 #ifndef QT_NO_TOOLTIP
163 tipGroup = new QToolTipGroup( 0 );
167 QActionPPrivate::~QActionPPrivate()
169 QPtrListIterator<QToolButton> ittb( toolbuttons );
172 while ( ( tb = ittb.current() ) ) {
177 QPtrListIterator<QActionPPrivate::MenuItem> itmi( menuitems);
178 QActionPPrivate::MenuItem* mi;
179 while ( ( mi = itmi.current() ) ) {
181 QPopupMenu* menu = mi->popup;
182 if ( menu->findItem( mi->id ) )
183 menu->removeItem( mi->id );
190 #ifndef QT_NO_TOOLTIP
195 void QActionPPrivate::update( Update upd )
197 for ( QPtrListIterator<MenuItem> it( menuitems); it.current(); ++it ) {
198 MenuItem* mi = it.current();
199 QString t = menuText();
202 t += '\t' + QAccel::keyToString( key );
206 mi->popup->setItemEnabled( mi->id, enabled );
208 mi->popup->setItemChecked( mi->id, on );
212 mi->popup->changeItem( mi->id, *iconset, t );
215 mi->popup->changeItem( mi->id, t );
216 if ( !whatsthis.isEmpty() )
217 mi->popup->setWhatsThis( mi->id, whatsthis );
218 if ( toggleaction ) {
219 mi->popup->setCheckable( TRUE );
220 mi->popup->setItemChecked( mi->id, on );
224 for ( QPtrListIterator<QToolButton> it2( toolbuttons); it2.current(); ++it2 ) {
225 QToolButton* btn = it2.current();
228 btn->setEnabled( enabled );
234 btn->setIconSet( *iconset );
237 btn->setToggleButton( toggleaction );
238 if ( !text.isEmpty() )
239 btn->setTextLabel( text, FALSE );
240 #ifndef QT_NO_TOOLTIP
241 QToolTip::remove( btn );
242 QToolTip::add( btn, toolTip(), tipGroup, statusTip() );
244 #ifndef QT_NO_WHATSTHIS
245 QWhatsThis::remove( btn );
246 if ( !whatsthis.isEmpty() )
247 QWhatsThis::add( btn, whatsthis );
251 // Only used by actiongroup
252 for ( QPtrListIterator<ComboItem> it3( comboitems ); it3.current(); ++it3 ) {
253 ComboItem *ci = it3.current();
257 ci->combo->changeItem( iconset->pixmap(), text, ci->id );
259 ci->combo->changeItem( text, ci->id );
261 // VSR : enable/disable accel according to action state
263 if ( upd == State && accel )
264 accel->setItemEnabled( key, enabled );
268 QString QActionPPrivate::menuText() const
270 if ( menutext.isNull() )
275 QString QActionPPrivate::toolTip() const
277 if ( tooltip.isNull() ) {
280 return text + " (" + QAccel::keyToString( accel->key( accelid )) + ")";
287 QString QActionPPrivate::statusTip() const
289 if ( statustip.isNull() )
297 Constructs an action with parent \a parent and name \a name.
299 If \a toggle is TRUE the action will be a toggle action, otherwise it
300 will be a command action.
302 If \a parent is a QActionPGroup, the new action inserts itself into \a parent.
304 For accelerators and status tips to work, \a parent must either be a
305 widget, or an action group whose parent is a widget.
307 QActionP::QActionP( QObject* parent, const char* name, bool toggle )
308 : QObject( parent, name )
310 d = new QActionPPrivate;
311 d->toggleaction = toggle;
317 This constructor creates an action with the following properties:
318 the description \a text, the icon or iconset \a icon, the menu text
319 \a menuText and keyboard accelerator \a accel. It is a child of \a parent
320 and named \a name. If \a toggle is TRUE the action will be a toggle
321 action, otherwise it will be a command action.
323 If \a parent is a QActionPGroup, the action automatically becomes a
326 For accelerators and status tips to work, \a parent must either be a
327 widget, or an action group whose parent is a widget.
329 The \a text and \a accel will be used for tool tips and status tips
330 unless you provide specific text for these using setToolTip() and
333 QActionP::QActionP( const QString& text, const QIconSet& icon, const QString& menuText, QKeySequence accel, QObject* parent, const char* name, bool toggle )
334 : QObject( parent, name )
336 d = new QActionPPrivate;
337 d->toggleaction = toggle;
338 if ( !icon.isNull() )
342 d->menutext = menuText;
347 /*! This constructor results in an iconless action with the description
348 \a text, the menu text \a menuText and the keyboard accelerator \a accel.
349 Its parent is \a parent and its name \a
350 name. If \a toggle is TRUE the action will be a toggle
351 action, otherwise it will be a command action.
353 The action automatically becomes a member of \a parent if \a parent
356 For accelerators and status tips to work, \a parent must either be a
357 widget, or an action group whose parent is a widget.
359 The \a text and \a accel will be used for tool tips and status tips
360 unless you provide specific text for these using setToolTip() and
363 QActionP::QActionP( const QString& text, const QString& menuText, QKeySequence accel, QObject* parent, const char* name, bool toggle )
364 : QObject( parent, name )
366 d = new QActionPPrivate;
367 d->toggleaction = toggle;
369 d->menutext = menuText;
377 void QActionP::init()
379 if ( parent() && parent()->inherits("QActionPGroup") ) {
380 ((QActionPGroup*) parent())->add( this ); // insert into action group
384 /*! Destroys the object and frees allocated resources. */
386 QActionP::~QActionP()
391 /*! \property QActionP::iconSet
392 \brief the action's icon
394 The icon is used as the tool button icon and in the menu to the left
395 of the menu text. There is no default icon.
397 (See the action/toggleaction/toggleaction.cpp example.)
400 void QActionP::setIconSet( const QIconSet& icon )
405 register QIconSet *i = d->iconset;
406 d->iconset = new QIconSet( icon );
408 d->update( QActionPPrivate::Icons );
411 QIconSet QActionP::iconSet() const
418 /*! \property QActionP::text
419 \brief the action's descriptive text
421 If \l QMainWindow::usesTextLabel is TRUE, the text appears as a
422 label in the relevant tool button. It also serves as the default text
423 in menus and tool tips if these have not been specifically defined. There
426 \sa setMenuText() setToolTip() setStatusTip()
428 void QActionP::setText( const QString& text )
434 QString QActionP::text() const
440 /*! \property QActionP::menuText
441 \brief the action's menu text
443 If the action is added to a menu the menu option will consist of
444 the icon (if there is one), the menu text and the accelerator (if
445 there is one). If the menu text is not explicitly set in the
446 constructor or by using setMenuText() the action's description
447 text will be used as the menu text. There is no default menu text.
451 void QActionP::setMenuText( const QString& text ) { d->menutext = text;
454 QString QActionP::menuText() const { return d->menuText(); }
457 \property QActionP::toolTip \brief the action's tool tip
459 This text is used for the tool tip. If no status tip has been set
460 the tool tip will be used for the status tip.
462 If no tool tip is specified the action's text is used, and if that
463 hasn't been specified the description text is used as the tool tip
466 There is no default tool tip text.
468 \sa setStatusTip() setAccel()
470 void QActionP::setToolTip( const QString& tip )
476 QString QActionP::toolTip() const
481 /*! \property QActionP::statusTip
482 \brief the action's status tip
484 The statusTip is displayed on all status bars that this action's
485 toplevel parent widget provides.
487 If no status tip is defined, the action uses the tool tip text.
489 There is no default tooltip text.
491 \sa setStatusTip() setToolTip()
493 //#### Please reimp for QActionPGroup!
494 //#### For consistency reasons even action groups should show
495 //#### status tips (as they already do with tool tips)
496 //#### Please change QActionPGroup class doc appropriately after
497 //#### reimplementation.
498 void QActionP::setStatusTip( const QString& tip )
504 QString QActionP::statusTip() const
506 return d->statusTip();
509 /*!\property QActionP::whatsThis
510 \brief the action's "What's This?" help text
512 The whats this text is used to provide a brief description of the
513 action. The text may contain rich text (i.e. HTML tags -- see
514 QStyleSheet for the list of supported tags). There is no default
519 void QActionP::setWhatsThis( const QString& whatsThis )
521 if ( d->whatsthis == whatsThis )
523 d->whatsthis = whatsThis;
525 if ( !d->whatsthis.isEmpty() && d->accel )
526 d->accel->setWhatsThis( d->accelid, d->whatsthis );
531 QString QActionP::whatsThis() const
537 /*! \property QActionP::accel
538 \brief the action's accelerator key
540 The keycodes can be found in \l Qt::Key and \l
541 Qt::Modifier. There is no default accelerator key.
545 //#### Please reimp for QActionPGroup!
546 //#### For consistency reasons even QActionPGroups should respond to
547 //#### their accelerators and e.g. open the relevant submenu.
548 //#### Please change appropriate QActionPGroup class doc after
549 //#### reimplementation.
550 void QActionP::setAccel( const QKeySequence& key )
564 QObject* p = parent();
565 while ( p && !p->isWidgetType() ) {
569 d->accel = new QAccel( (QWidget*)p, this, "qt_action_accel" );
570 d->accelid = d->accel->insertItem( d->key );
571 d->accel->connectItem( d->accelid, this, SLOT( internalActivation() ) );
572 if ( !d->whatsthis.isEmpty() )
573 d->accel->setWhatsThis( d->accelid, d->whatsthis );
575 #if defined(QT_CHECK_STATE)
577 qWarning( "QActionP::setAccel() (%s) requires widget in parent chain.", name( "unnamed" ) );
584 QKeySequence QActionP::accel() const
591 \property QActionP::toggleAction
592 \brief whether the action is a toggle action
594 A toggle action is one which has an on/off state. For example a Bold
595 toolbar button is either on or off. An action which is not a toggle
596 action is a command action; a command action is simply executed.
597 This property's default is FALSE.
599 In some situations, the state of one toggle action should depend on
600 the state of others. For example, "Left Align", "Center" and "Right
601 Align" toggle actions are mutually exclusive. To achieve exclusive
602 toggling, add the relevant toggle actions to a QActionPGroup with the
603 \l QActionPGroup::exclusive property set to TRUE.
606 void QActionP::setToggleAction( bool enable )
608 if ( enable == (bool)d->toggleaction )
614 d->toggleaction = enable;
618 bool QActionP::isToggleAction() const
620 return d->toggleaction;
624 Toggles the state of a toggle action.
626 \sa on, toggled(), isToggleAction()
628 void QActionP::toggle()
630 if ( !isToggleAction() ) {
631 #if defined(QT_CHECK_STATE)
632 qWarning( "QActionP::toggle() (%s) Only toggle actions "
633 "may be switched", name( "unnamed" ) );
641 \property QActionP::on
642 \brief whether a toggle action is on
644 This property is always on (TRUE) for command actions and
645 \l{QActionPGroup}s; setOn() has no effect on them. For action's where
646 isToggleAction() is TRUE, this property's default value is off
651 void QActionP::setOn( bool enable )
653 if ( !isToggleAction() ) {
654 #if defined(QT_CHECK_STATE)
655 qWarning( "QActionP::setOn() (%s) Only toggle actions "
656 "may be switched", name( "unnamed" ) );
660 if ( enable == (bool)d->on )
663 d->update( QActionPPrivate::State );
664 emit toggled( enable );
667 bool QActionP::isOn() const
672 /*! \property QActionP::enabled
673 \brief whether the action is enabled
675 Disabled actions can't be chosen by the user. They don't
676 disappear from the menu/tool bar but are displayed in a way which
677 indicates that they are unavailable, e.g. they might be displayed
680 What's this? help on disabled actions is still available
681 provided the \l QActionP::whatsThis property is set.
684 void QActionP::setEnabled( bool enable )
689 d->accel->setEnabled( enable );
691 d->update( QActionPPrivate::State );
694 bool QActionP::isEnabled() const
701 void QActionP::internalActivation()
703 if ( isToggleAction() )
710 void QActionP::toolButtonToggled( bool on )
712 if ( !isToggleAction() )
717 /*! Adds this action to widget \a w.
719 Currently actions may be added to QToolBar and QPopupMenu widgets.
721 An action added to a tool bar is automatically displayed
722 as a tool button; an action added to a pop up menu appears
725 addTo() returns TRUE if the action was added successfully and FALSE
726 otherwise. (If \a w is not a QToolBar or QPopupMenu the action will
727 not be added and FALSE will be returned.)
731 bool QActionP::addTo( QWidget* w )
733 #ifndef QT_NO_TOOLBAR
734 if ( w->inherits( "QToolBar" ) ) {
735 if ( !qstrcmp( name(), "qt_separator_action" ) ) {
736 ((QToolBar*)w)->addSeparator();
738 QCString bname = name() + QCString( "_action_button" );
739 QToolButton* btn = new QToolButton( (QToolBar*) w, bname );
741 btn->setToggleButton( d->toggleaction );
742 d->toolbuttons.append( btn );
744 btn->setIconSet( *d->iconset );
745 d->update( QActionPPrivate::State );
746 d->update( QActionPPrivate::Everything );
747 connect( btn, SIGNAL( clicked() ), this, SIGNAL( activated() ) );
748 connect( btn, SIGNAL( toggled(bool) ), this, SLOT( toolButtonToggled(bool) ) );
749 connect( btn, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
750 #ifndef QT_NO_TOOLTIP
751 connect( d->tipGroup, SIGNAL(showTip(const QString&)), this, SLOT(showStatusText(const QString&)) );
752 connect( d->tipGroup, SIGNAL(removeTip()), this, SLOT(clearStatusText()) );
757 if ( w->inherits( "QPopupMenu" ) ) {
758 if ( !qstrcmp( name(), "qt_separator_action" ) ) {
759 ((QPopupMenu*)w)->insertSeparator();
761 QActionPPrivate::MenuItem* mi = new QActionPPrivate::MenuItem;
762 mi->popup = (QPopupMenu*) w;
763 QIconSet* diconset = d->iconset;
765 mi->id = mi->popup->insertItem( *diconset, QString::fromLatin1("") );
767 mi->id = mi->popup->insertItem( QString::fromLatin1("") );
768 addedTo( mi->popup->indexOf( mi->id ), mi->popup );
769 mi->popup->connectItem( mi->id, this, SLOT(internalActivation()) );
770 d->menuitems.append( mi );
771 d->update( QActionPPrivate::State );
772 d->update( QActionPPrivate::Everything );
773 w->topLevelWidget()->className();
774 connect( mi->popup, SIGNAL(highlighted( int )), this, SLOT(menuStatusText( int )) );
775 connect( mi->popup, SIGNAL(aboutToHide()), this, SLOT(clearStatusText()) );
776 connect( mi->popup, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
778 // Makes only sense when called by QActionPGroup::addTo
779 } else if ( w->inherits( "QComboBox" ) ) {
780 if ( qstrcmp( name(), "qt_separator_action" ) ) {
781 QActionPPrivate::ComboItem *ci = new QActionPPrivate::ComboItem;
782 ci->combo = (QComboBox*)w;
783 connect( ci->combo, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
784 ci->id = ci->combo->count();
786 ci->combo->insertItem( d->iconset->pixmap(), text() );
788 ci->combo->insertItem( text() );
789 d->comboitems.append( ci );
792 qWarning( "QActionP::addTo(), unknown object" );
798 /*! This function is called from the addTo() function when it created
799 a widget (\a actionWidget) for the action in the \a container.
802 void QActionP::addedTo( QWidget *actionWidget, QWidget *container )
804 Q_UNUSED( actionWidget );
805 Q_UNUSED( container );
810 This function is called from the addTo() function when it created
811 a menu item at the index \a index in the popup menu \a menu.
814 void QActionP::addedTo( int index, QPopupMenu *menu )
820 /*! Sets the status message to \a text */
821 void QActionP::showStatusText( const QString& text )
823 #ifndef QT_NO_STATUSBAR
824 // find out whether we are clearing the status bar by the popup that actually set the text
825 static QPopupMenu *lastmenu = 0;
826 QObject *s = (QObject*)sender();
828 QPopupMenu *menu = (QPopupMenu*)s->qt_cast( "QPopupMenu" );
829 if ( menu && !!text )
831 else if ( menu && text.isEmpty() ) {
832 if ( lastmenu && menu != lastmenu )
838 QObject* par = parent();
841 while ( par && !bar ) {
843 bar = (QStatusBar*)par->child( 0, "QStatusBar", FALSE );
846 if ( !bar && lpar ) {
847 QObjectList *l = lpar->queryList( "QStatusBar" );
850 // #### hopefully the last one is the one of the mainwindow...
851 bar = (QStatusBar*)l->last();
855 if ( text.isEmpty() )
858 bar->message( text );
863 /*! Sets the status message to the menu item's status text, or
864 to the tooltip, if there is no status text.
866 void QActionP::menuStatusText( int id )
869 QPtrListIterator<QActionPPrivate::MenuItem> it( d->menuitems);
870 QActionPPrivate::MenuItem* mi;
871 while ( ( mi = it.current() ) ) {
873 if ( mi->id == id ) {
879 if ( !text.isEmpty() )
880 showStatusText( text );
883 /*! Clears the status text.
885 void QActionP::clearStatusText()
887 showStatusText( QString::null );
891 Removes the action from widget \a w.
893 Returns TRUE if the action was removed successfully; otherwise
898 bool QActionP::removeFrom( QWidget* w )
900 #ifndef QT_NO_TOOLBAR
901 if ( w->inherits( "QToolBar" ) ) {
902 QPtrListIterator<QToolButton> it( d->toolbuttons);
904 while ( ( btn = it.current() ) ) {
906 if ( btn->parentWidget() == w ) {
907 d->toolbuttons.removeRef( btn );
908 disconnect( btn, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
910 // no need to disconnect from statusbar
915 if ( w->inherits( "QPopupMenu" ) ) {
916 QPtrListIterator<QActionPPrivate::MenuItem> it( d->menuitems);
917 QActionPPrivate::MenuItem* mi;
918 while ( ( mi = it.current() ) ) {
920 if ( mi->popup == w ) {
921 disconnect( mi->popup, SIGNAL(highlighted( int )), this, SLOT(menuStatusText(int)) );
922 disconnect( mi->popup, SIGNAL(aboutToHide()), this, SLOT(clearStatusText()) );
923 disconnect( mi->popup, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
924 mi->popup->removeItem( mi->id );
925 d->menuitems.removeRef( mi );
928 } else if ( w->inherits( "QComboBox" ) ) {
929 QPtrListIterator<QActionPPrivate::ComboItem> it( d->comboitems );
930 QActionPPrivate::ComboItem *ci;
931 while ( ( ci = it.current() ) ) {
933 if ( ci->combo == w ) {
934 disconnect( ci->combo, SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
935 d->comboitems.removeRef( ci );
939 qWarning( "QActionP::removeFrom(), unknown object" );
948 void QActionP::objectDestroyed()
950 const QObject* obj = sender();
951 QPtrListIterator<QActionPPrivate::MenuItem> it( d->menuitems );
952 QActionPPrivate::MenuItem* mi;
953 while ( ( mi = it.current() ) ) {
955 if ( mi->popup == obj )
956 d->menuitems.removeRef( mi );
958 QActionPPrivate::ComboItem *ci;
959 QPtrListIterator<QActionPPrivate::ComboItem> it2( d->comboitems );
960 while ( ( ci = it2.current() ) ) {
962 if ( ci->combo == obj )
963 d->comboitems.removeRef( ci );
965 d->toolbuttons.removeRef( (QToolButton*) obj );
968 /*! \fn void QActionP::activated()
970 This signal is emitted when an action is activated by the user, i.e.
971 when the user clicks a menu option or a toolbar button or presses an
972 action's accelerator key combination.
974 Connect to this signal for command actions. Connect to the toggled()
975 signal for toggle actions.
978 /*! \fn void QActionP::toggled(bool)
980 This signal is emitted when a toggle action changes state;
981 command actions and QActionPGroups don't emit toggled().
983 The argument denotes the new state; i.e. TRUE
984 if the toggle action was switched on and FALSE if
987 To trigger a user command depending on whether a toggle action has
988 been switched on or off connect it to a slot that takes a bool to
989 indicate the state, e.g.
991 \quotefile action/toggleaction/toggleaction.cpp
992 \skipto QMainWindow * window
993 \printline QMainWindow * window
994 \skipto labelonoffaction
995 \printline labelonoffaction
997 \printuntil setUsesTextLabel
999 \sa activated() setToggleAction() setOn()
1004 class QActionPGroupPrivate
1009 QPtrList<QActionP> actions;
1011 QActionP* separatorAction;
1014 MenuItem():popup(0),id(0){}
1019 QPtrList<QComboBox> comboboxes;
1020 QPtrList<QToolButton> menubuttons;
1021 QPtrList<MenuItem> menuitems;
1022 QPtrList<QPopupMenu> popupmenus;
1024 void update( const QActionPGroup * );
1027 void QActionPGroupPrivate::update( const QActionPGroup* that )
1029 for ( QPtrListIterator<QActionP> it( actions ); it.current(); ++it ) {
1030 it.current()->setEnabled( that->isEnabled() );
1032 for ( QPtrListIterator<QComboBox> cb( comboboxes ); cb.current(); ++cb ) {
1033 cb.current()->setEnabled( that->isEnabled() );
1035 #ifndef QT_NO_TOOLTIP
1036 QToolTip::remove( cb.current() );
1037 if ( !!that->toolTip() )
1038 QToolTip::add( cb.current(), that->toolTip() );
1040 #ifndef QT_NO_WHATSTHIS
1041 QWhatsThis::remove( cb.current() );
1042 if ( !!that->whatsThis() )
1043 QWhatsThis::add( cb.current(), that->whatsThis() );
1046 for ( QPtrListIterator<QToolButton> mb( menubuttons ); mb.current(); ++mb ) {
1047 mb.current()->setEnabled( that->isEnabled() );
1049 if ( !that->text().isNull() )
1050 mb.current()->setTextLabel( that->text() );
1051 if ( !that->iconSet().isNull() )
1052 mb.current()->setIconSet( that->iconSet() );
1054 #ifndef QT_NO_TOOLTIP
1055 QToolTip::remove( mb.current() );
1056 if ( !!that->toolTip() )
1057 QToolTip::add( mb.current(), that->toolTip() );
1059 #ifndef QT_NO_WHATSTHIS
1060 QWhatsThis::remove( mb.current() );
1061 if ( !!that->whatsThis() )
1062 QWhatsThis::add( mb.current(), that->whatsThis() );
1065 for ( QPtrListIterator<QActionPGroupPrivate::MenuItem> pu( menuitems ); pu.current(); ++pu ) {
1066 QWidget* parent = pu.current()->popup->parentWidget();
1067 if ( parent->inherits( "QPopupMenu" ) ) {
1068 QPopupMenu* ppopup = (QPopupMenu*)parent;
1069 ppopup->setItemEnabled( pu.current()->id, that->isEnabled() );
1071 pu.current()->popup->setEnabled( that->isEnabled() );
1074 for ( QPtrListIterator<QPopupMenu> pm( popupmenus ); pm.current(); ++pm ) {
1075 QPopupMenu *popup = pm.current();
1076 QPopupMenu *parent = popup->parentWidget()->inherits( "QPopupMenu" ) ? (QPopupMenu*)popup->parentWidget() : 0;
1081 parent->findPopup( popup, &index );
1082 int id = parent->idAt( index );
1083 parent->changeItem( id, that->iconSet(), that->menuText() );
1084 parent->setItemEnabled( id, that->isEnabled() );
1085 parent->setAccel( that->accel(), id );
1090 \class QActionPGroup qaction.h
1092 \ingroup application
1094 \brief The QActionPGroup class groups actions together.
1096 In some situations it is useful to group actions together. For
1097 example, if you have a left justify action, a right justify action
1098 and a center action, only one of these actions should be active at
1099 any one time, and one simple way of achieving this is to group the
1100 actions together in an action group and call setExclusive(TRUE).
1102 An action group can also be added to a menu or a toolbar as a single
1103 unit, with all the actions within the action group appearing as
1104 separate menu options and toolbar buttons.
1106 Here's an example from examples/textedit:
1107 \quotefile textedit/textedit.cpp
1108 \skipto QActionPGroup
1111 We create a new action group and call setExclusive() to ensure that
1112 only one of the actions in the group is ever active at any one time.
1113 We then connect the group's selected() signal to our textAlign() slot.
1115 \printuntil actionAlignLeft->setToggleAction
1117 We create a left align action, add it to the toolbar and the menu
1118 and make it a toggle action. We create center and right align
1119 actions in exactly the same way.
1122 A QActionPGroup emits an activated() signal when one of its actions
1125 The actions in an action group emit their activated()
1126 (and for toggle actions, toggled()) signals as usual.
1128 The setExclusive() function is used to ensure that only one action
1129 is active at any one time: it should be used with actions which have
1130 their \c toggleAction set to TRUE.
1132 Action group actions appear as individual menu options and toolbar
1133 buttons. For exclusive action groups use setUsesDropDown() to
1134 display the actions in a subwidget of any widget the action group is
1135 added to. For example, the actions would appear in a combobox in a
1136 toolbar or as a submenu in a menu.
1138 Actions can be added to an action group using add(), but normally
1139 they are added by creating the action with the action group as
1140 parent. Actions can have separators dividing them using
1141 addSeparator(). Action groups are added to widgets with addTo().
1145 /*! Constructs an action group with parent \a parent and name \a name.
1147 If \a exclusive is TRUE only one toggle action in the group will
1151 QActionPGroup::QActionPGroup( QObject* parent, const char* name, bool exclusive )
1152 : QActionP( parent, name )
1154 d = new QActionPGroupPrivate;
1155 d->exclusive = exclusive;
1156 d->dropdown = FALSE;
1158 d->separatorAction = 0;
1160 connect( this, SIGNAL(selected(QActionP*)), SLOT(internalToggle(QActionP*)) );
1163 /*! Destroys the object and frees allocated resources. */
1165 QActionPGroup::~QActionPGroup()
1167 QPtrListIterator<QActionPGroupPrivate::MenuItem> mit( d->menuitems );
1168 while ( mit.current() ) {
1169 QActionPGroupPrivate::MenuItem *mi = mit.current();
1172 mi->popup->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
1175 QPtrListIterator<QComboBox> cbit( d->comboboxes );
1176 while ( cbit.current() ) {
1177 QComboBox *cb = cbit.current();
1179 cb->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
1181 QPtrListIterator<QToolButton> mbit( d->menubuttons );
1182 while ( mbit.current() ) {
1183 QToolButton *mb = mbit.current();
1185 mb->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
1187 QPtrListIterator<QPopupMenu> pmit( d->popupmenus );
1188 while ( pmit.current() ) {
1189 QPopupMenu *pm = pmit.current();
1191 pm->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
1194 delete d->separatorAction;
1195 d->menubuttons.setAutoDelete( TRUE );
1196 d->comboboxes.setAutoDelete( TRUE );
1197 d->menuitems.setAutoDelete( TRUE );
1198 d->popupmenus.setAutoDelete( TRUE );
1202 /*! \property QActionPGroup::exclusive
1203 \brief whether the action group does exclusive toggling
1205 If exclusive is TRUE only one toggle action in the action group can
1206 ever be active at any one time. If the user chooses another toggle
1207 action in the group the one they chose becomes active and the one
1208 that was active becomes inactive. By default this property is FALSE.
1210 \sa QActionP::toggleAction
1212 void QActionPGroup::setExclusive( bool enable )
1214 d->exclusive = enable;
1217 bool QActionPGroup::isExclusive() const
1219 return d->exclusive;
1222 /*! \property QActionPGroup::usesDropDown
1223 \brief whether the group's actions are displayed in a
1224 subwidget of the widgets the action group is added to
1226 Exclusive action groups added to a toolbar display their actions in
1227 a combobox with the action's \l QActionP::text and \l
1228 QActionP::iconSet properties shown. Non-exclusive groups are
1229 represented by a tool button showing their \l QActionP::iconSet and
1230 -- depending on \l QMainWindow::usesTextLabel() -- text() property.
1232 In a popup menu the member actions are displayed in a
1235 Changing usesDropDown only effects \e subsequent calls to addTo().
1237 This property's default is FALSE.
1240 void QActionPGroup::setUsesDropDown( bool enable )
1242 d->dropdown = enable;
1245 bool QActionPGroup::usesDropDown() const
1250 /*! Adds action \a action to this group.
1252 Normally an action is added to a group by creating it with the group
1253 as parent, so this function is not usually used.
1257 void QActionPGroup::add( QActionP* action )
1259 if ( d->actions.containsRef( action ) )
1262 d->actions.append( action );
1264 if ( action->whatsThis().isNull() )
1265 action->setWhatsThis( whatsThis() );
1266 if ( action->toolTip().isNull() )
1267 action->setToolTip( toolTip() );
1268 action->setEnabled( isEnabled() );
1270 connect( action, SIGNAL( destroyed() ), this, SLOT( childDestroyed() ) );
1271 connect( action, SIGNAL( activated() ), this, SIGNAL( activated() ) );
1272 connect( action, SIGNAL( toggled( bool ) ), this, SLOT( childToggled( bool ) ) );
1274 for ( QPtrListIterator<QComboBox> cb( d->comboboxes ); cb.current(); ++cb ) {
1275 cb.current()->insertItem( action->iconSet().pixmap(), action->text() );
1277 for ( QPtrListIterator<QToolButton> mb( d->menubuttons ); mb.current(); ++mb ) {
1278 QPopupMenu* popup = mb.current()->popup();
1281 action->addTo( popup );
1283 for ( QPtrListIterator<QActionPGroupPrivate::MenuItem> mi( d->menuitems ); mi.current(); ++mi ) {
1284 QPopupMenu* popup = mi.current()->popup;
1287 action->addTo( popup );
1291 /*! Adds a separator to the group. */
1292 void QActionPGroup::addSeparator()
1294 if ( !d->separatorAction )
1295 d->separatorAction = new QActionP( 0, "qt_separator_action" );
1296 d->actions.append( d->separatorAction );
1300 /*! \fn void QActionPGroup::insert( QActionP* a )
1304 Use add() instead, or better still create the action with the action
1305 group as its parent.
1309 Adds this action group to the widget \a w.
1311 If usesDropDown() is TRUE and exclusive is TRUE (see setExclusive())
1312 the actions are presented in a combobox if \a w is a toolbar and as
1313 a submenu if \a w is a menu. Otherwise (the default) the actions
1314 within the group are added to the widget individually. For example
1315 if the widget is a menu, the actions will appear as individual menu
1316 options, and if the widget is a toolbar, the actions will appear as
1319 It is recommended that actions in action groups, especially where
1320 usesDropDown() is TRUE, have their menuText() or text() property set.
1322 All actions should be added to the action group \e before the action
1323 group is added to the widget. If actions are added to the action
1324 group \e after the action group has been added to the widget these
1325 later actions will \e not appear.
1327 \sa setExclusive() setUsesDropDown() removeFrom()
1329 bool QActionPGroup::addTo( QWidget* w )
1331 #ifndef QT_NO_TOOLBAR
1332 if ( w->inherits( "QToolBar" ) ) {
1333 if ( d->dropdown ) {
1334 if ( !d->exclusive ) {
1335 QPtrListIterator<QActionP> it( d->actions);
1336 if ( !it.current() )
1339 QActionP *defAction = it.current();
1341 QToolButton* btn = new QToolButton( (QToolBar*) w, "qt_actiongroup_btn" );
1343 connect( btn, SIGNAL(destroyed()), SLOT(objectDestroyed()) );
1344 d->menubuttons.append( btn );
1346 if ( !iconSet().isNull() )
1347 btn->setIconSet( iconSet() );
1348 else if ( !defAction->iconSet().isNull() )
1349 btn->setIconSet( defAction->iconSet() );
1351 btn->setTextLabel( text() );
1352 else if ( !!defAction->text() )
1353 btn->setTextLabel( defAction->text() );
1354 #ifndef QT_NO_TOOLTIP
1356 QToolTip::add( btn, toolTip() );
1357 else if ( !!defAction->toolTip() )
1358 QToolTip::add( btn, defAction->toolTip() );
1360 #ifndef QT_NO_WHATSTHIS
1361 if ( !!whatsThis() )
1362 QWhatsThis::add( btn, whatsThis() );
1363 else if ( !!defAction->whatsThis() )
1364 QWhatsThis::add( btn, defAction->whatsThis() );
1367 connect( btn, SIGNAL( clicked() ), defAction, SIGNAL( activated() ) );
1368 connect( btn, SIGNAL( toggled(bool) ), defAction, SLOT( toolButtonToggled(bool) ) );
1369 connect( btn, SIGNAL( destroyed() ), defAction, SLOT( objectDestroyed() ) );
1371 QPopupMenu *menu = new QPopupMenu( btn, "qt_actiongroup_menu" );
1372 btn->setPopupDelay( 0 );
1373 btn->setPopup( menu );
1375 while( it.current() ) {
1376 it.current()->addTo( menu );
1381 QComboBox *box = new QComboBox( FALSE, w, "qt_actiongroup_combo" );
1383 connect( box, SIGNAL(destroyed()), SLOT(objectDestroyed()) );
1384 d->comboboxes.append( box );
1385 #ifndef QT_NO_TOOLTIP
1387 QToolTip::add( box, toolTip() );
1389 #ifndef QT_NO_WHATSTHIS
1390 if ( !!whatsThis() )
1391 QWhatsThis::add( box, whatsThis() );
1394 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1395 it.current()->addTo( box );
1397 connect( box, SIGNAL(activated(int)), this, SLOT( internalComboBoxActivated(int)) );
1403 if ( w->inherits( "QPopupMenu" ) ) {
1405 if ( d->dropdown ) {
1406 QPopupMenu *menu = (QPopupMenu*)w;
1407 popup = new QPopupMenu( w, "qt_actiongroup_menu" );
1408 d->popupmenus.append( popup );
1409 connect( popup, SIGNAL(destroyed()), SLOT(objectDestroyed()) );
1412 if ( !iconSet().isNull() ) {
1413 if ( menuText().isEmpty() )
1414 id = menu->insertItem( iconSet(), text(), popup );
1416 id = menu->insertItem( iconSet(), menuText(), popup );
1418 if ( menuText().isEmpty() )
1419 id = menu->insertItem( text(), popup );
1421 id = menu->insertItem( menuText(), popup );
1424 addedTo( menu->indexOf( id ), menu );
1426 QActionPGroupPrivate::MenuItem *item = new QActionPGroupPrivate::MenuItem;
1428 item->popup = popup;
1429 d->menuitems.append( item );
1431 popup = (QPopupMenu*)w;
1433 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1434 // #### do an addedTo( index, popup, action), need to find out index
1435 it.current()->addTo( popup );
1440 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1441 // #### do an addedTo( index, popup, action), need to find out index
1442 it.current()->addTo( w );
1450 bool QActionPGroup::removeFrom( QWidget* w )
1452 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1453 it.current()->removeFrom( w );
1456 #ifndef QT_NO_TOOLBAR
1457 if ( w->inherits( "QToolBar" ) ) {
1458 QPtrListIterator<QComboBox> cb( d->comboboxes );
1459 while( cb.current() ) {
1460 QComboBox *box = cb.current();
1462 if ( box->parentWidget() == w )
1465 QPtrListIterator<QToolButton> mb( d->menubuttons );
1466 while( mb.current() ) {
1467 QToolButton *btn = mb.current();
1469 if ( btn->parentWidget() == w )
1474 if ( w->inherits( "QPopupMenu" ) ) {
1475 QPtrListIterator<QActionPGroupPrivate::MenuItem> pu( d->menuitems );
1476 while ( pu.current() ) {
1477 QActionPGroupPrivate::MenuItem *mi = pu.current();
1479 if ( d->dropdown && mi->popup )
1480 ( (QPopupMenu*)w )->removeItem( mi->id );
1490 void QActionPGroup::childToggled( bool b )
1492 if ( !isExclusive() )
1494 QActionP* s = (QActionP*) sender();
1496 if ( s != d->selected ) {
1498 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1499 if ( it.current()->isToggleAction() && it.current() != s )
1500 it.current()->setOn( FALSE );
1506 if ( s == d->selected ) {
1507 // at least one has to be selected
1515 void QActionPGroup::childDestroyed()
1517 d->actions.removeRef( (QActionP*) sender() );
1518 if ( d->selected == sender() )
1524 void QActionPGroup::setEnabled( bool enable )
1526 if ( enable == isEnabled() )
1529 QActionP::setEnabled( enable );
1535 void QActionPGroup::setIconSet( const QIconSet& icon )
1537 QActionP::setIconSet( icon );
1543 void QActionPGroup::setText( const QString& txt )
1545 if ( txt == text() )
1548 QActionP::setText( txt );
1554 void QActionPGroup::setMenuText( const QString& text )
1556 if ( text == menuText() )
1559 QActionP::setMenuText( text );
1565 void QActionPGroup::setToolTip( const QString& text )
1567 if ( text == toolTip() )
1569 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1570 if ( it.current()->toolTip().isNull() )
1571 it.current()->setToolTip( text );
1573 QActionP::setToolTip( text );
1579 void QActionPGroup::setWhatsThis( const QString& text )
1581 if ( text == whatsThis() )
1583 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1584 if ( it.current()->whatsThis().isNull() )
1585 it.current()->setWhatsThis( text );
1587 QActionP::setWhatsThis( text );
1593 void QActionPGroup::childEvent( QChildEvent *e )
1595 if ( !e->child()->inherits( "QActionP" ) )
1598 QActionP *action = (QActionP*)e->child();
1600 if ( !e->removed() )
1603 for ( QPtrListIterator<QComboBox> cb( d->comboboxes ); cb.current(); ++cb ) {
1604 for ( int i = 0; i < cb.current()->count(); i++ ) {
1605 if ( cb.current()->text( i ) == action->text() ) {
1606 cb.current()->removeItem( i );
1611 for ( QPtrListIterator<QToolButton> mb( d->menubuttons ); mb.current(); ++mb ) {
1612 QPopupMenu* popup = mb.current()->popup();
1615 action->removeFrom( popup );
1617 for ( QPtrListIterator<QActionPGroupPrivate::MenuItem> mi( d->menuitems ); mi.current(); ++mi ) {
1618 QPopupMenu* popup = mi.current()->popup;
1621 action->removeFrom( popup );
1626 \fn void QActionPGroup::selected( QActionP* )
1628 This signal is emitted from exclusive groups when toggle actions
1631 The argument is the action whose state changed to "on".
1633 \quotefile action/actiongroup/editor.cpp
1634 \skipto QActionPGroup
1635 \printline QActionPGroup
1636 \skipto QObject::connect
1639 In this example we connect the selected() signal to our own
1640 setFontColor() slot, passing the QActionP so that we know which
1641 action was chosen by the user.
1643 (See the \link actiongroup.html QActionPGroup Walkthrough. \endlink)
1645 \sa setExclusive(), isOn()
1650 void QActionPGroup::internalComboBoxActivated( int index )
1652 QActionP *a = d->actions.at( index );
1654 if ( a != d->selected ) {
1656 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1657 if ( it.current()->isToggleAction() && it.current() != a )
1658 it.current()->setOn( FALSE );
1660 if ( a->isToggleAction() )
1664 emit selected( d->selected );
1665 emit ((QActionPGroup*)a)->activated();
1672 void QActionPGroup::internalToggle( QActionP *a )
1674 for ( QPtrListIterator<QComboBox> it( d->comboboxes); it.current(); ++it ) {
1675 int index = d->actions.find( a );
1677 it.current()->setCurrentItem( index );
1683 void QActionPGroup::objectDestroyed()
1685 const QObject* obj = sender();
1686 d->menubuttons.removeRef( (QToolButton*)obj );
1687 for ( QPtrListIterator<QActionPGroupPrivate::MenuItem> mi( d->menuitems ); mi.current(); ++mi ) {
1688 if ( mi.current()->popup == obj ) {
1689 d->menuitems.removeRef( mi.current() );
1693 d->popupmenus.removeRef( (QPopupMenu*)obj );
1694 d->comboboxes.removeRef( (QComboBox*)obj );
1697 /*! This function is called from the addTo() function when it created
1698 a widget (\a actionWidget) for the child action \a a in the \a
1702 void QActionPGroup::addedTo( QWidget *actionWidget, QWidget *container, QActionP *a )
1704 Q_UNUSED( actionWidget );
1705 Q_UNUSED( container );
1711 This function is called from the addTo() function when it created a
1712 menu item for the child action at the index \a index in the popup
1716 void QActionPGroup::addedTo( int index, QPopupMenu *menu, QActionP *a )
1725 This function is called from the addTo() function when it created
1726 a widget (\a actionWidget) in the \a container.
1729 void QActionPGroup::addedTo( QWidget *actionWidget, QWidget *container )
1731 Q_UNUSED( actionWidget );
1732 Q_UNUSED( container );
1737 This function is called from the addTo() function when it created a
1738 menu item at the index \a index in the popup menu \a menu.
1742 void QActionPGroup::addedTo( int index, QPopupMenu *menu )