1 /////////////////////////////////////////////////////////////////////////////
4 // Description : the patch for Qt's QAction class (qaction.cpp)
5 /////////////////////////////////////////////////////////////////////////////
7 /****************************************************************************
10 ** Implementation of QAction class
14 ** Copyright (C) 2000 Trolltech AS. All rights reserved.
16 ** This file is part of the widgets module of the Qt GUI Toolkit.
18 ** This file may be distributed under the terms of the Q Public License
19 ** as defined by Trolltech AS of Norway and appearing in the file
20 ** LICENSE.QPL included in the packaging of this file.
22 ** This file may be distributed and/or modified under the terms of the
23 ** GNU General Public License version 2 as published by the Free Software
24 ** Foundation and appearing in the file LICENSE.GPL included in the
25 ** packaging of this file.
27 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
28 ** licenses may use this file in accordance with the Qt Commercial License
29 ** Agreement provided with the Software.
31 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
32 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
34 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
35 ** information about Qt Commercial License Agreements.
36 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
37 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
39 ** Contact info@trolltech.com if any conditions of this licensing are
42 **********************************************************************/
50 #include <qpopupmenu.h>
52 #include <qtoolbutton.h>
53 #include <qcombobox.h>
55 #include <qwhatsthis.h>
56 #include <qstatusbar.h>
57 #include <qobjectlist.h>
61 \class QActionP qaction.h
65 \brief The QActionP class provides an abstract user interface
66 action that can appear both in menus and tool bars.
68 In GUI applications many commands can be invoked via a menu option, a
69 toolbar button and a keyboard accelerator. Since the same action must
70 be performed regardless of how the action was invoked, and since the
71 menu and toolbar should be kept in sync, it is useful to represent a
72 command as an \e action. An action can be added to a menu and a
73 toolbar and will automatically keep them in sync. For example, if the
74 user presses a Bold toolbar button the Bold menu item will
75 automatically be checked.
77 A QActionP may contain an icon, a menu text, an accelerator, a status
78 text, a whats this text and a tool tip. Most of these can be set in
79 the constructor. They can also be set independently with setIconSet(),
80 setText(), setMenuText(), setToolTip(), setStatusTip(), setWhatsThis()
81 and setAccel(), respectively.
83 An action may be a toggle action e.g. a Bold toolbar button, or a
84 command action, e.g. 'Open File' to invoke an open file dialog.
85 Toggle actions emit the toggled() signal when their state changes.
86 Both command and toggle actions emit the activated() signal when they
87 are invoked. Use setToggleAction() to set an action's toggled status.
88 To see if an action is a toggle action use isToggleAction(). A toggle
89 action may be "on", isOn() returns TRUE, or "off", isOn() returns
92 Actions are added to widgets (menus or toolbars) using addTo(), and
93 removed using removeFrom().
95 Once a QActionP has been created it should be added to the relevant
96 menu and toolbar and then connected to the slot which will perform
97 the action. For example:
99 \quotefile action/application.cpp
103 We create a "File Save" action with a menu text of "&Save" and
104 \e{Ctrl+S} as the keyboard accelerator. We connect the
105 fileSaveAction's activated() signal to our own save() slot. Note that at
106 this point there is no menu or toolbar action, we'll add them next:
110 \skipto fileSaveAction->addTo
112 \skipto new QPopupMenu
113 \printuntil insertItem
114 \skipto fileSaveAction->addTo
117 We create a toolbar and add our fileSaveAction to it. Similarly we
118 create a menu, add a top-level menu item, and add our
121 (See the \link simple-application-action.html Simple Application
122 Walkthrough featuring QActionP \endlink for a detailed example.)
124 We recommend that actions are created as children of the window that
125 they are used in. In most cases actions will be children of the
126 application's main window.
128 To prevent recursion, don't create an action as a child of a widget
129 that the action is later added to.
133 class QActionPPrivate
150 uint toggleaction :1;
152 #ifndef QT_NO_TOOLTIP
153 QToolTipGroup* tipGroup;
157 MenuItem():popup(0),id(0){}
161 // ComboItem is only necessary for actions that are
162 // in dropdown/exclusive actiongroups. The actiongroup
163 // will clean this up
165 ComboItem():combo(0), id(0) {}
169 QPtrList<MenuItem> menuitems;
170 QPtrList<QToolButton> toolbuttons;
171 QPtrList<ComboItem> comboitems;
173 enum Update { Everything, Icons, State }; // Everything means everything but icons and state
174 void update( Update upd = Everything );
176 QString menuText() const;
177 QString toolTip() const;
178 QString statusTip() const;
181 QActionPPrivate::QActionPPrivate()
192 menuitems.setAutoDelete( TRUE );
193 comboitems.setAutoDelete( TRUE );
194 #ifndef QT_NO_TOOLTIP
195 tipGroup = new QToolTipGroup( 0 );
199 QActionPPrivate::~QActionPPrivate()
201 QPtrListIterator<QToolButton> ittb( toolbuttons );
204 while ( ( tb = ittb.current() ) ) {
209 QPtrListIterator<QActionPPrivate::MenuItem> itmi( menuitems);
210 QActionPPrivate::MenuItem* mi;
211 while ( ( mi = itmi.current() ) ) {
213 QPopupMenu* menu = mi->popup;
214 if ( menu->findItem( mi->id ) )
215 menu->removeItem( mi->id );
222 #ifndef QT_NO_TOOLTIP
227 void QActionPPrivate::update( Update upd )
229 for ( QPtrListIterator<MenuItem> it( menuitems); it.current(); ++it ) {
230 MenuItem* mi = it.current();
231 QString t = menuText();
234 t += '\t' + QAccel::keyToString( key );
238 mi->popup->setItemEnabled( mi->id, enabled );
240 mi->popup->setItemChecked( mi->id, on );
244 mi->popup->changeItem( mi->id, *iconset, t );
247 mi->popup->changeItem( mi->id, t );
248 if ( !whatsthis.isEmpty() )
249 mi->popup->setWhatsThis( mi->id, whatsthis );
250 if ( toggleaction ) {
251 mi->popup->setCheckable( TRUE );
252 mi->popup->setItemChecked( mi->id, on );
256 for ( QPtrListIterator<QToolButton> it2( toolbuttons); it2.current(); ++it2 ) {
257 QToolButton* btn = it2.current();
260 btn->setEnabled( enabled );
266 btn->setIconSet( *iconset );
269 btn->setToggleButton( toggleaction );
270 if ( !text.isEmpty() )
271 btn->setTextLabel( text, FALSE );
272 #ifndef QT_NO_TOOLTIP
273 QToolTip::remove( btn );
274 QToolTip::add( btn, toolTip(), tipGroup, statusTip() );
276 #ifndef QT_NO_WHATSTHIS
277 QWhatsThis::remove( btn );
278 if ( !whatsthis.isEmpty() )
279 QWhatsThis::add( btn, whatsthis );
283 // Only used by actiongroup
284 for ( QPtrListIterator<ComboItem> it3( comboitems ); it3.current(); ++it3 ) {
285 ComboItem *ci = it3.current();
289 ci->combo->changeItem( iconset->pixmap(), text, ci->id );
291 ci->combo->changeItem( text, ci->id );
293 // VSR : enable/disable accel according to action state
295 if ( upd == State && accel )
296 accel->setItemEnabled( key, enabled );
300 QString QActionPPrivate::menuText() const
302 if ( menutext.isNull() )
307 QString QActionPPrivate::toolTip() const
309 if ( tooltip.isNull() ) {
312 return text + " (" + QAccel::keyToString( accel->key( accelid )) + ")";
319 QString QActionPPrivate::statusTip() const
321 if ( statustip.isNull() )
329 Constructs an action with parent \a parent and name \a name.
331 If \a toggle is TRUE the action will be a toggle action, otherwise it
332 will be a command action.
334 If \a parent is a QActionPGroup, the new action inserts itself into \a parent.
336 For accelerators and status tips to work, \a parent must either be a
337 widget, or an action group whose parent is a widget.
339 QActionP::QActionP( QObject* parent, const char* name, bool toggle )
340 : QObject( parent, name )
342 d = new QActionPPrivate;
343 d->toggleaction = toggle;
349 This constructor creates an action with the following properties:
350 the description \a text, the icon or iconset \a icon, the menu text
351 \a menuText and keyboard accelerator \a accel. It is a child of \a parent
352 and named \a name. If \a toggle is TRUE the action will be a toggle
353 action, otherwise it will be a command action.
355 If \a parent is a QActionPGroup, the action automatically becomes a
358 For accelerators and status tips to work, \a parent must either be a
359 widget, or an action group whose parent is a widget.
361 The \a text and \a accel will be used for tool tips and status tips
362 unless you provide specific text for these using setToolTip() and
365 QActionP::QActionP( const QString& text, const QIconSet& icon, const QString& menuText, QKeySequence accel, QObject* parent, const char* name, bool toggle )
366 : QObject( parent, name )
368 d = new QActionPPrivate;
369 d->toggleaction = toggle;
370 if ( !icon.isNull() )
374 d->menutext = menuText;
379 /*! This constructor results in an iconless action with the description
380 \a text, the menu text \a menuText and the keyboard accelerator \a accel.
381 Its parent is \a parent and its name \a
382 name. If \a toggle is TRUE the action will be a toggle
383 action, otherwise it will be a command action.
385 The action automatically becomes a member of \a parent if \a parent
388 For accelerators and status tips to work, \a parent must either be a
389 widget, or an action group whose parent is a widget.
391 The \a text and \a accel will be used for tool tips and status tips
392 unless you provide specific text for these using setToolTip() and
395 QActionP::QActionP( const QString& text, const QString& menuText, QKeySequence accel, QObject* parent, const char* name, bool toggle )
396 : QObject( parent, name )
398 d = new QActionPPrivate;
399 d->toggleaction = toggle;
401 d->menutext = menuText;
409 void QActionP::init()
411 if ( parent() && parent()->inherits("QActionPGroup") ) {
412 ((QActionPGroup*) parent())->add( this ); // insert into action group
416 /*! Destroys the object and frees allocated resources. */
418 QActionP::~QActionP()
423 /*! \property QActionP::iconSet
424 \brief the action's icon
426 The icon is used as the tool button icon and in the menu to the left
427 of the menu text. There is no default icon.
429 (See the action/toggleaction/toggleaction.cpp example.)
432 void QActionP::setIconSet( const QIconSet& icon )
437 register QIconSet *i = d->iconset;
438 d->iconset = new QIconSet( icon );
440 d->update( QActionPPrivate::Icons );
443 QIconSet QActionP::iconSet() const
450 /*! \property QActionP::text
451 \brief the action's descriptive text
453 If \l QMainWindow::usesTextLabel is TRUE, the text appears as a
454 label in the relevant tool button. It also serves as the default text
455 in menus and tool tips if these have not been specifically defined. There
458 \sa setMenuText() setToolTip() setStatusTip()
460 void QActionP::setText( const QString& text )
466 QString QActionP::text() const
472 /*! \property QActionP::menuText
473 \brief the action's menu text
475 If the action is added to a menu the menu option will consist of
476 the icon (if there is one), the menu text and the accelerator (if
477 there is one). If the menu text is not explicitly set in the
478 constructor or by using setMenuText() the action's description
479 text will be used as the menu text. There is no default menu text.
483 void QActionP::setMenuText( const QString& text ) { d->menutext = text;
486 QString QActionP::menuText() const { return d->menuText(); }
489 \property QActionP::toolTip \brief the action's tool tip
491 This text is used for the tool tip. If no status tip has been set
492 the tool tip will be used for the status tip.
494 If no tool tip is specified the action's text is used, and if that
495 hasn't been specified the description text is used as the tool tip
498 There is no default tool tip text.
500 \sa setStatusTip() setAccel()
502 void QActionP::setToolTip( const QString& tip )
508 QString QActionP::toolTip() const
513 /*! \property QActionP::statusTip
514 \brief the action's status tip
516 The statusTip is displayed on all status bars that this action's
517 toplevel parent widget provides.
519 If no status tip is defined, the action uses the tool tip text.
521 There is no default tooltip text.
523 \sa setStatusTip() setToolTip()
525 //#### Please reimp for QActionPGroup!
526 //#### For consistency reasons even action groups should show
527 //#### status tips (as they already do with tool tips)
528 //#### Please change QActionPGroup class doc appropriately after
529 //#### reimplementation.
530 void QActionP::setStatusTip( const QString& tip )
536 QString QActionP::statusTip() const
538 return d->statusTip();
541 /*!\property QActionP::whatsThis
542 \brief the action's "What's This?" help text
544 The whats this text is used to provide a brief description of the
545 action. The text may contain rich text (i.e. HTML tags -- see
546 QStyleSheet for the list of supported tags). There is no default
551 void QActionP::setWhatsThis( const QString& whatsThis )
553 if ( d->whatsthis == whatsThis )
555 d->whatsthis = whatsThis;
557 if ( !d->whatsthis.isEmpty() && d->accel )
558 d->accel->setWhatsThis( d->accelid, d->whatsthis );
563 QString QActionP::whatsThis() const
569 /*! \property QActionP::accel
570 \brief the action's accelerator key
572 The keycodes can be found in \l Qt::Key and \l
573 Qt::Modifier. There is no default accelerator key.
577 //#### Please reimp for QActionPGroup!
578 //#### For consistency reasons even QActionPGroups should respond to
579 //#### their accelerators and e.g. open the relevant submenu.
580 //#### Please change appropriate QActionPGroup class doc after
581 //#### reimplementation.
582 void QActionP::setAccel( const QKeySequence& key )
596 QObject* p = parent();
597 while ( p && !p->isWidgetType() ) {
601 d->accel = new QAccel( (QWidget*)p, this, "qt_action_accel" );
602 d->accelid = d->accel->insertItem( d->key );
603 d->accel->connectItem( d->accelid, this, SLOT( internalActivation() ) );
604 if ( !d->whatsthis.isEmpty() )
605 d->accel->setWhatsThis( d->accelid, d->whatsthis );
607 #if defined(QT_CHECK_STATE)
609 qWarning( "QActionP::setAccel() (%s) requires widget in parent chain.", name( "unnamed" ) );
616 QKeySequence QActionP::accel() const
623 \property QActionP::toggleAction
624 \brief whether the action is a toggle action
626 A toggle action is one which has an on/off state. For example a Bold
627 toolbar button is either on or off. An action which is not a toggle
628 action is a command action; a command action is simply executed.
629 This property's default is FALSE.
631 In some situations, the state of one toggle action should depend on
632 the state of others. For example, "Left Align", "Center" and "Right
633 Align" toggle actions are mutually exclusive. To achieve exclusive
634 toggling, add the relevant toggle actions to a QActionPGroup with the
635 \l QActionPGroup::exclusive property set to TRUE.
638 void QActionP::setToggleAction( bool enable )
640 if ( enable == (bool)d->toggleaction )
646 d->toggleaction = enable;
650 bool QActionP::isToggleAction() const
652 return d->toggleaction;
656 Toggles the state of a toggle action.
658 \sa on, toggled(), isToggleAction()
660 void QActionP::toggle()
662 if ( !isToggleAction() ) {
663 #if defined(QT_CHECK_STATE)
664 qWarning( "QActionP::toggle() (%s) Only toggle actions "
665 "may be switched", name( "unnamed" ) );
673 \property QActionP::on
674 \brief whether a toggle action is on
676 This property is always on (TRUE) for command actions and
677 \l{QActionPGroup}s; setOn() has no effect on them. For action's where
678 isToggleAction() is TRUE, this property's default value is off
683 void QActionP::setOn( bool enable )
685 if ( !isToggleAction() ) {
686 #if defined(QT_CHECK_STATE)
687 qWarning( "QActionP::setOn() (%s) Only toggle actions "
688 "may be switched", name( "unnamed" ) );
692 if ( enable == (bool)d->on )
695 d->update( QActionPPrivate::State );
696 emit toggled( enable );
699 bool QActionP::isOn() const
704 /*! \property QActionP::enabled
705 \brief whether the action is enabled
707 Disabled actions can't be chosen by the user. They don't
708 disappear from the menu/tool bar but are displayed in a way which
709 indicates that they are unavailable, e.g. they might be displayed
712 What's this? help on disabled actions is still available
713 provided the \l QActionP::whatsThis property is set.
716 void QActionP::setEnabled( bool enable )
721 d->accel->setEnabled( enable );
723 d->update( QActionPPrivate::State );
726 bool QActionP::isEnabled() const
733 void QActionP::internalActivation()
735 if ( isToggleAction() )
742 void QActionP::toolButtonToggled( bool on )
744 if ( !isToggleAction() )
749 /*! Adds this action to widget \a w.
751 Currently actions may be added to QToolBar and QPopupMenu widgets.
753 An action added to a tool bar is automatically displayed
754 as a tool button; an action added to a pop up menu appears
757 addTo() returns TRUE if the action was added successfully and FALSE
758 otherwise. (If \a w is not a QToolBar or QPopupMenu the action will
759 not be added and FALSE will be returned.)
763 bool QActionP::addTo( QWidget* w )
765 #ifndef QT_NO_TOOLBAR
766 if ( w->inherits( "QToolBar" ) ) {
767 if ( !qstrcmp( name(), "qt_separator_action" ) ) {
768 ((QToolBar*)w)->addSeparator();
770 QCString bname = name() + QCString( "_action_button" );
771 QToolButton* btn = new QToolButton( (QToolBar*) w, bname );
773 btn->setToggleButton( d->toggleaction );
774 d->toolbuttons.append( btn );
776 btn->setIconSet( *d->iconset );
777 d->update( QActionPPrivate::State );
778 d->update( QActionPPrivate::Everything );
779 connect( btn, SIGNAL( clicked() ), this, SIGNAL( activated() ) );
780 connect( btn, SIGNAL( toggled(bool) ), this, SLOT( toolButtonToggled(bool) ) );
781 connect( btn, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
782 #ifndef QT_NO_TOOLTIP
783 connect( d->tipGroup, SIGNAL(showTip(const QString&)), this, SLOT(showStatusText(const QString&)) );
784 connect( d->tipGroup, SIGNAL(removeTip()), this, SLOT(clearStatusText()) );
789 if ( w->inherits( "QPopupMenu" ) ) {
790 if ( !qstrcmp( name(), "qt_separator_action" ) ) {
791 ((QPopupMenu*)w)->insertSeparator();
793 QActionPPrivate::MenuItem* mi = new QActionPPrivate::MenuItem;
794 mi->popup = (QPopupMenu*) w;
795 QIconSet* diconset = d->iconset;
797 mi->id = mi->popup->insertItem( *diconset, QString::fromLatin1("") );
799 mi->id = mi->popup->insertItem( QString::fromLatin1("") );
800 addedTo( mi->popup->indexOf( mi->id ), mi->popup );
801 mi->popup->connectItem( mi->id, this, SLOT(internalActivation()) );
802 d->menuitems.append( mi );
803 d->update( QActionPPrivate::State );
804 d->update( QActionPPrivate::Everything );
805 w->topLevelWidget()->className();
806 connect( mi->popup, SIGNAL(highlighted( int )), this, SLOT(menuStatusText( int )) );
807 connect( mi->popup, SIGNAL(aboutToHide()), this, SLOT(clearStatusText()) );
808 connect( mi->popup, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
810 // Makes only sense when called by QActionPGroup::addTo
811 } else if ( w->inherits( "QComboBox" ) ) {
812 if ( qstrcmp( name(), "qt_separator_action" ) ) {
813 QActionPPrivate::ComboItem *ci = new QActionPPrivate::ComboItem;
814 ci->combo = (QComboBox*)w;
815 connect( ci->combo, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
816 ci->id = ci->combo->count();
818 ci->combo->insertItem( d->iconset->pixmap(), text() );
820 ci->combo->insertItem( text() );
821 d->comboitems.append( ci );
824 qWarning( "QActionP::addTo(), unknown object" );
830 /*! This function is called from the addTo() function when it created
831 a widget (\a actionWidget) for the action in the \a container.
834 void QActionP::addedTo( QWidget *actionWidget, QWidget *container )
836 Q_UNUSED( actionWidget );
837 Q_UNUSED( container );
842 This function is called from the addTo() function when it created
843 a menu item at the index \a index in the popup menu \a menu.
846 void QActionP::addedTo( int index, QPopupMenu *menu )
852 /*! Sets the status message to \a text */
853 void QActionP::showStatusText( const QString& text )
855 #ifndef QT_NO_STATUSBAR
856 // find out whether we are clearing the status bar by the popup that actually set the text
857 static QPopupMenu *lastmenu = 0;
858 QObject *s = (QObject*)sender();
860 QPopupMenu *menu = (QPopupMenu*)s->qt_cast( "QPopupMenu" );
861 if ( menu && !!text )
863 else if ( menu && text.isEmpty() ) {
864 if ( lastmenu && menu != lastmenu )
870 QObject* par = parent();
873 while ( par && !bar ) {
875 bar = (QStatusBar*)par->child( 0, "QStatusBar", FALSE );
878 if ( !bar && lpar ) {
879 QObjectList *l = lpar->queryList( "QStatusBar" );
882 // #### hopefully the last one is the one of the mainwindow...
883 bar = (QStatusBar*)l->last();
887 if ( text.isEmpty() )
890 bar->message( text );
895 /*! Sets the status message to the menu item's status text, or
896 to the tooltip, if there is no status text.
898 void QActionP::menuStatusText( int id )
901 QPtrListIterator<QActionPPrivate::MenuItem> it( d->menuitems);
902 QActionPPrivate::MenuItem* mi;
903 while ( ( mi = it.current() ) ) {
905 if ( mi->id == id ) {
911 if ( !text.isEmpty() )
912 showStatusText( text );
915 /*! Clears the status text.
917 void QActionP::clearStatusText()
919 showStatusText( QString::null );
923 Removes the action from widget \a w.
925 Returns TRUE if the action was removed successfully; otherwise
930 bool QActionP::removeFrom( QWidget* w )
932 #ifndef QT_NO_TOOLBAR
933 if ( w->inherits( "QToolBar" ) ) {
934 QPtrListIterator<QToolButton> it( d->toolbuttons);
936 while ( ( btn = it.current() ) ) {
938 if ( btn->parentWidget() == w ) {
939 d->toolbuttons.removeRef( btn );
940 disconnect( btn, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
942 // no need to disconnect from statusbar
947 if ( w->inherits( "QPopupMenu" ) ) {
948 QPtrListIterator<QActionPPrivate::MenuItem> it( d->menuitems);
949 QActionPPrivate::MenuItem* mi;
950 while ( ( mi = it.current() ) ) {
952 if ( mi->popup == w ) {
953 disconnect( mi->popup, SIGNAL(highlighted( int )), this, SLOT(menuStatusText(int)) );
954 disconnect( mi->popup, SIGNAL(aboutToHide()), this, SLOT(clearStatusText()) );
955 disconnect( mi->popup, SIGNAL( destroyed() ), this, SLOT( objectDestroyed() ) );
956 mi->popup->removeItem( mi->id );
957 d->menuitems.removeRef( mi );
960 } else if ( w->inherits( "QComboBox" ) ) {
961 QPtrListIterator<QActionPPrivate::ComboItem> it( d->comboitems );
962 QActionPPrivate::ComboItem *ci;
963 while ( ( ci = it.current() ) ) {
965 if ( ci->combo == w ) {
966 disconnect( ci->combo, SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
967 d->comboitems.removeRef( ci );
971 qWarning( "QActionP::removeFrom(), unknown object" );
980 void QActionP::objectDestroyed()
982 const QObject* obj = sender();
983 QPtrListIterator<QActionPPrivate::MenuItem> it( d->menuitems );
984 QActionPPrivate::MenuItem* mi;
985 while ( ( mi = it.current() ) ) {
987 if ( mi->popup == obj )
988 d->menuitems.removeRef( mi );
990 QActionPPrivate::ComboItem *ci;
991 QPtrListIterator<QActionPPrivate::ComboItem> it2( d->comboitems );
992 while ( ( ci = it2.current() ) ) {
994 if ( ci->combo == obj )
995 d->comboitems.removeRef( ci );
997 d->toolbuttons.removeRef( (QToolButton*) obj );
1000 /*! \fn void QActionP::activated()
1002 This signal is emitted when an action is activated by the user, i.e.
1003 when the user clicks a menu option or a toolbar button or presses an
1004 action's accelerator key combination.
1006 Connect to this signal for command actions. Connect to the toggled()
1007 signal for toggle actions.
1010 /*! \fn void QActionP::toggled(bool)
1012 This signal is emitted when a toggle action changes state;
1013 command actions and QActionPGroups don't emit toggled().
1015 The argument denotes the new state; i.e. TRUE
1016 if the toggle action was switched on and FALSE if
1017 it was switched off.
1019 To trigger a user command depending on whether a toggle action has
1020 been switched on or off connect it to a slot that takes a bool to
1021 indicate the state, e.g.
1023 \quotefile action/toggleaction/toggleaction.cpp
1024 \skipto QMainWindow * window
1025 \printline QMainWindow * window
1026 \skipto labelonoffaction
1027 \printline labelonoffaction
1029 \printuntil setUsesTextLabel
1031 \sa activated() setToggleAction() setOn()
1036 class QActionPGroupPrivate
1041 QPtrList<QActionP> actions;
1043 QActionP* separatorAction;
1046 MenuItem():popup(0),id(0){}
1051 QPtrList<QComboBox> comboboxes;
1052 QPtrList<QToolButton> menubuttons;
1053 QPtrList<MenuItem> menuitems;
1054 QPtrList<QPopupMenu> popupmenus;
1056 void update( const QActionPGroup * );
1059 void QActionPGroupPrivate::update( const QActionPGroup* that )
1061 for ( QPtrListIterator<QActionP> it( actions ); it.current(); ++it ) {
1062 it.current()->setEnabled( that->isEnabled() );
1064 for ( QPtrListIterator<QComboBox> cb( comboboxes ); cb.current(); ++cb ) {
1065 cb.current()->setEnabled( that->isEnabled() );
1067 #ifndef QT_NO_TOOLTIP
1068 QToolTip::remove( cb.current() );
1069 if ( !!that->toolTip() )
1070 QToolTip::add( cb.current(), that->toolTip() );
1072 #ifndef QT_NO_WHATSTHIS
1073 QWhatsThis::remove( cb.current() );
1074 if ( !!that->whatsThis() )
1075 QWhatsThis::add( cb.current(), that->whatsThis() );
1078 for ( QPtrListIterator<QToolButton> mb( menubuttons ); mb.current(); ++mb ) {
1079 mb.current()->setEnabled( that->isEnabled() );
1081 if ( !that->text().isNull() )
1082 mb.current()->setTextLabel( that->text() );
1083 if ( !that->iconSet().isNull() )
1084 mb.current()->setIconSet( that->iconSet() );
1086 #ifndef QT_NO_TOOLTIP
1087 QToolTip::remove( mb.current() );
1088 if ( !!that->toolTip() )
1089 QToolTip::add( mb.current(), that->toolTip() );
1091 #ifndef QT_NO_WHATSTHIS
1092 QWhatsThis::remove( mb.current() );
1093 if ( !!that->whatsThis() )
1094 QWhatsThis::add( mb.current(), that->whatsThis() );
1097 for ( QPtrListIterator<QActionPGroupPrivate::MenuItem> pu( menuitems ); pu.current(); ++pu ) {
1098 QWidget* parent = pu.current()->popup->parentWidget();
1099 if ( parent->inherits( "QPopupMenu" ) ) {
1100 QPopupMenu* ppopup = (QPopupMenu*)parent;
1101 ppopup->setItemEnabled( pu.current()->id, that->isEnabled() );
1103 pu.current()->popup->setEnabled( that->isEnabled() );
1106 for ( QPtrListIterator<QPopupMenu> pm( popupmenus ); pm.current(); ++pm ) {
1107 QPopupMenu *popup = pm.current();
1108 QPopupMenu *parent = popup->parentWidget()->inherits( "QPopupMenu" ) ? (QPopupMenu*)popup->parentWidget() : 0;
1113 parent->findPopup( popup, &index );
1114 int id = parent->idAt( index );
1115 parent->changeItem( id, that->iconSet(), that->menuText() );
1116 parent->setItemEnabled( id, that->isEnabled() );
1117 parent->setAccel( that->accel(), id );
1122 \class QActionPGroup qaction.h
1124 \ingroup application
1126 \brief The QActionPGroup class groups actions together.
1128 In some situations it is useful to group actions together. For
1129 example, if you have a left justify action, a right justify action
1130 and a center action, only one of these actions should be active at
1131 any one time, and one simple way of achieving this is to group the
1132 actions together in an action group and call setExclusive(TRUE).
1134 An action group can also be added to a menu or a toolbar as a single
1135 unit, with all the actions within the action group appearing as
1136 separate menu options and toolbar buttons.
1138 Here's an example from examples/textedit:
1139 \quotefile textedit/textedit.cpp
1140 \skipto QActionPGroup
1143 We create a new action group and call setExclusive() to ensure that
1144 only one of the actions in the group is ever active at any one time.
1145 We then connect the group's selected() signal to our textAlign() slot.
1147 \printuntil actionAlignLeft->setToggleAction
1149 We create a left align action, add it to the toolbar and the menu
1150 and make it a toggle action. We create center and right align
1151 actions in exactly the same way.
1154 A QActionPGroup emits an activated() signal when one of its actions
1157 The actions in an action group emit their activated()
1158 (and for toggle actions, toggled()) signals as usual.
1160 The setExclusive() function is used to ensure that only one action
1161 is active at any one time: it should be used with actions which have
1162 their \c toggleAction set to TRUE.
1164 Action group actions appear as individual menu options and toolbar
1165 buttons. For exclusive action groups use setUsesDropDown() to
1166 display the actions in a subwidget of any widget the action group is
1167 added to. For example, the actions would appear in a combobox in a
1168 toolbar or as a submenu in a menu.
1170 Actions can be added to an action group using add(), but normally
1171 they are added by creating the action with the action group as
1172 parent. Actions can have separators dividing them using
1173 addSeparator(). Action groups are added to widgets with addTo().
1177 /*! Constructs an action group with parent \a parent and name \a name.
1179 If \a exclusive is TRUE only one toggle action in the group will
1183 QActionPGroup::QActionPGroup( QObject* parent, const char* name, bool exclusive )
1184 : QActionP( parent, name )
1186 d = new QActionPGroupPrivate;
1187 d->exclusive = exclusive;
1188 d->dropdown = FALSE;
1190 d->separatorAction = 0;
1192 connect( this, SIGNAL(selected(QActionP*)), SLOT(internalToggle(QActionP*)) );
1195 /*! Destroys the object and frees allocated resources. */
1197 QActionPGroup::~QActionPGroup()
1199 QPtrListIterator<QActionPGroupPrivate::MenuItem> mit( d->menuitems );
1200 while ( mit.current() ) {
1201 QActionPGroupPrivate::MenuItem *mi = mit.current();
1204 mi->popup->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
1207 QPtrListIterator<QComboBox> cbit( d->comboboxes );
1208 while ( cbit.current() ) {
1209 QComboBox *cb = cbit.current();
1211 cb->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
1213 QPtrListIterator<QToolButton> mbit( d->menubuttons );
1214 while ( mbit.current() ) {
1215 QToolButton *mb = mbit.current();
1217 mb->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
1219 QPtrListIterator<QPopupMenu> pmit( d->popupmenus );
1220 while ( pmit.current() ) {
1221 QPopupMenu *pm = pmit.current();
1223 pm->disconnect( SIGNAL(destroyed()), this, SLOT(objectDestroyed()) );
1226 delete d->separatorAction;
1227 d->menubuttons.setAutoDelete( TRUE );
1228 d->comboboxes.setAutoDelete( TRUE );
1229 d->menuitems.setAutoDelete( TRUE );
1230 d->popupmenus.setAutoDelete( TRUE );
1234 /*! \property QActionPGroup::exclusive
1235 \brief whether the action group does exclusive toggling
1237 If exclusive is TRUE only one toggle action in the action group can
1238 ever be active at any one time. If the user chooses another toggle
1239 action in the group the one they chose becomes active and the one
1240 that was active becomes inactive. By default this property is FALSE.
1242 \sa QActionP::toggleAction
1244 void QActionPGroup::setExclusive( bool enable )
1246 d->exclusive = enable;
1249 bool QActionPGroup::isExclusive() const
1251 return d->exclusive;
1254 /*! \property QActionPGroup::usesDropDown
1255 \brief whether the group's actions are displayed in a
1256 subwidget of the widgets the action group is added to
1258 Exclusive action groups added to a toolbar display their actions in
1259 a combobox with the action's \l QActionP::text and \l
1260 QActionP::iconSet properties shown. Non-exclusive groups are
1261 represented by a tool button showing their \l QActionP::iconSet and
1262 -- depending on \l QMainWindow::usesTextLabel() -- text() property.
1264 In a popup menu the member actions are displayed in a
1267 Changing usesDropDown only effects \e subsequent calls to addTo().
1269 This property's default is FALSE.
1272 void QActionPGroup::setUsesDropDown( bool enable )
1274 d->dropdown = enable;
1277 bool QActionPGroup::usesDropDown() const
1282 /*! Adds action \a action to this group.
1284 Normally an action is added to a group by creating it with the group
1285 as parent, so this function is not usually used.
1289 void QActionPGroup::add( QActionP* action )
1291 if ( d->actions.containsRef( action ) )
1294 d->actions.append( action );
1296 if ( action->whatsThis().isNull() )
1297 action->setWhatsThis( whatsThis() );
1298 if ( action->toolTip().isNull() )
1299 action->setToolTip( toolTip() );
1300 action->setEnabled( isEnabled() );
1302 connect( action, SIGNAL( destroyed() ), this, SLOT( childDestroyed() ) );
1303 connect( action, SIGNAL( activated() ), this, SIGNAL( activated() ) );
1304 connect( action, SIGNAL( toggled( bool ) ), this, SLOT( childToggled( bool ) ) );
1306 for ( QPtrListIterator<QComboBox> cb( d->comboboxes ); cb.current(); ++cb ) {
1307 cb.current()->insertItem( action->iconSet().pixmap(), action->text() );
1309 for ( QPtrListIterator<QToolButton> mb( d->menubuttons ); mb.current(); ++mb ) {
1310 QPopupMenu* popup = mb.current()->popup();
1313 action->addTo( popup );
1315 for ( QPtrListIterator<QActionPGroupPrivate::MenuItem> mi( d->menuitems ); mi.current(); ++mi ) {
1316 QPopupMenu* popup = mi.current()->popup;
1319 action->addTo( popup );
1323 /*! Adds a separator to the group. */
1324 void QActionPGroup::addSeparator()
1326 if ( !d->separatorAction )
1327 d->separatorAction = new QActionP( 0, "qt_separator_action" );
1328 d->actions.append( d->separatorAction );
1332 /*! \fn void QActionPGroup::insert( QActionP* a )
1336 Use add() instead, or better still create the action with the action
1337 group as its parent.
1341 Adds this action group to the widget \a w.
1343 If usesDropDown() is TRUE and exclusive is TRUE (see setExclusive())
1344 the actions are presented in a combobox if \a w is a toolbar and as
1345 a submenu if \a w is a menu. Otherwise (the default) the actions
1346 within the group are added to the widget individually. For example
1347 if the widget is a menu, the actions will appear as individual menu
1348 options, and if the widget is a toolbar, the actions will appear as
1351 It is recommended that actions in action groups, especially where
1352 usesDropDown() is TRUE, have their menuText() or text() property set.
1354 All actions should be added to the action group \e before the action
1355 group is added to the widget. If actions are added to the action
1356 group \e after the action group has been added to the widget these
1357 later actions will \e not appear.
1359 \sa setExclusive() setUsesDropDown() removeFrom()
1361 bool QActionPGroup::addTo( QWidget* w )
1363 #ifndef QT_NO_TOOLBAR
1364 if ( w->inherits( "QToolBar" ) ) {
1365 if ( d->dropdown ) {
1366 if ( !d->exclusive ) {
1367 QPtrListIterator<QActionP> it( d->actions);
1368 if ( !it.current() )
1371 QActionP *defAction = it.current();
1373 QToolButton* btn = new QToolButton( (QToolBar*) w, "qt_actiongroup_btn" );
1375 connect( btn, SIGNAL(destroyed()), SLOT(objectDestroyed()) );
1376 d->menubuttons.append( btn );
1378 if ( !iconSet().isNull() )
1379 btn->setIconSet( iconSet() );
1380 else if ( !defAction->iconSet().isNull() )
1381 btn->setIconSet( defAction->iconSet() );
1383 btn->setTextLabel( text() );
1384 else if ( !!defAction->text() )
1385 btn->setTextLabel( defAction->text() );
1386 #ifndef QT_NO_TOOLTIP
1388 QToolTip::add( btn, toolTip() );
1389 else if ( !!defAction->toolTip() )
1390 QToolTip::add( btn, defAction->toolTip() );
1392 #ifndef QT_NO_WHATSTHIS
1393 if ( !!whatsThis() )
1394 QWhatsThis::add( btn, whatsThis() );
1395 else if ( !!defAction->whatsThis() )
1396 QWhatsThis::add( btn, defAction->whatsThis() );
1399 connect( btn, SIGNAL( clicked() ), defAction, SIGNAL( activated() ) );
1400 connect( btn, SIGNAL( toggled(bool) ), defAction, SLOT( toolButtonToggled(bool) ) );
1401 connect( btn, SIGNAL( destroyed() ), defAction, SLOT( objectDestroyed() ) );
1403 QPopupMenu *menu = new QPopupMenu( btn, "qt_actiongroup_menu" );
1404 btn->setPopupDelay( 0 );
1405 btn->setPopup( menu );
1407 while( it.current() ) {
1408 it.current()->addTo( menu );
1413 QComboBox *box = new QComboBox( FALSE, w, "qt_actiongroup_combo" );
1415 connect( box, SIGNAL(destroyed()), SLOT(objectDestroyed()) );
1416 d->comboboxes.append( box );
1417 #ifndef QT_NO_TOOLTIP
1419 QToolTip::add( box, toolTip() );
1421 #ifndef QT_NO_WHATSTHIS
1422 if ( !!whatsThis() )
1423 QWhatsThis::add( box, whatsThis() );
1426 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1427 it.current()->addTo( box );
1429 connect( box, SIGNAL(activated(int)), this, SLOT( internalComboBoxActivated(int)) );
1435 if ( w->inherits( "QPopupMenu" ) ) {
1437 if ( d->dropdown ) {
1438 QPopupMenu *menu = (QPopupMenu*)w;
1439 popup = new QPopupMenu( w, "qt_actiongroup_menu" );
1440 d->popupmenus.append( popup );
1441 connect( popup, SIGNAL(destroyed()), SLOT(objectDestroyed()) );
1444 if ( !iconSet().isNull() ) {
1445 if ( menuText().isEmpty() )
1446 id = menu->insertItem( iconSet(), text(), popup );
1448 id = menu->insertItem( iconSet(), menuText(), popup );
1450 if ( menuText().isEmpty() )
1451 id = menu->insertItem( text(), popup );
1453 id = menu->insertItem( menuText(), popup );
1456 addedTo( menu->indexOf( id ), menu );
1458 QActionPGroupPrivate::MenuItem *item = new QActionPGroupPrivate::MenuItem;
1460 item->popup = popup;
1461 d->menuitems.append( item );
1463 popup = (QPopupMenu*)w;
1465 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1466 // #### do an addedTo( index, popup, action), need to find out index
1467 it.current()->addTo( popup );
1472 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1473 // #### do an addedTo( index, popup, action), need to find out index
1474 it.current()->addTo( w );
1482 bool QActionPGroup::removeFrom( QWidget* w )
1484 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1485 it.current()->removeFrom( w );
1488 #ifndef QT_NO_TOOLBAR
1489 if ( w->inherits( "QToolBar" ) ) {
1490 QPtrListIterator<QComboBox> cb( d->comboboxes );
1491 while( cb.current() ) {
1492 QComboBox *box = cb.current();
1494 if ( box->parentWidget() == w )
1497 QPtrListIterator<QToolButton> mb( d->menubuttons );
1498 while( mb.current() ) {
1499 QToolButton *btn = mb.current();
1501 if ( btn->parentWidget() == w )
1506 if ( w->inherits( "QPopupMenu" ) ) {
1507 QPtrListIterator<QActionPGroupPrivate::MenuItem> pu( d->menuitems );
1508 while ( pu.current() ) {
1509 QActionPGroupPrivate::MenuItem *mi = pu.current();
1511 if ( d->dropdown && mi->popup )
1512 ( (QPopupMenu*)w )->removeItem( mi->id );
1522 void QActionPGroup::childToggled( bool b )
1524 if ( !isExclusive() )
1526 QActionP* s = (QActionP*) sender();
1528 if ( s != d->selected ) {
1530 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1531 if ( it.current()->isToggleAction() && it.current() != s )
1532 it.current()->setOn( FALSE );
1538 if ( s == d->selected ) {
1539 // at least one has to be selected
1547 void QActionPGroup::childDestroyed()
1549 d->actions.removeRef( (QActionP*) sender() );
1550 if ( d->selected == sender() )
1556 void QActionPGroup::setEnabled( bool enable )
1558 if ( enable == isEnabled() )
1561 QActionP::setEnabled( enable );
1567 void QActionPGroup::setIconSet( const QIconSet& icon )
1569 QActionP::setIconSet( icon );
1575 void QActionPGroup::setText( const QString& txt )
1577 if ( txt == text() )
1580 QActionP::setText( txt );
1586 void QActionPGroup::setMenuText( const QString& text )
1588 if ( text == menuText() )
1591 QActionP::setMenuText( text );
1597 void QActionPGroup::setToolTip( const QString& text )
1599 if ( text == toolTip() )
1601 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1602 if ( it.current()->toolTip().isNull() )
1603 it.current()->setToolTip( text );
1605 QActionP::setToolTip( text );
1611 void QActionPGroup::setWhatsThis( const QString& text )
1613 if ( text == whatsThis() )
1615 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1616 if ( it.current()->whatsThis().isNull() )
1617 it.current()->setWhatsThis( text );
1619 QActionP::setWhatsThis( text );
1625 void QActionPGroup::childEvent( QChildEvent *e )
1627 if ( !e->child()->inherits( "QActionP" ) )
1630 QActionP *action = (QActionP*)e->child();
1632 if ( !e->removed() )
1635 for ( QPtrListIterator<QComboBox> cb( d->comboboxes ); cb.current(); ++cb ) {
1636 for ( int i = 0; i < cb.current()->count(); i++ ) {
1637 if ( cb.current()->text( i ) == action->text() ) {
1638 cb.current()->removeItem( i );
1643 for ( QPtrListIterator<QToolButton> mb( d->menubuttons ); mb.current(); ++mb ) {
1644 QPopupMenu* popup = mb.current()->popup();
1647 action->removeFrom( popup );
1649 for ( QPtrListIterator<QActionPGroupPrivate::MenuItem> mi( d->menuitems ); mi.current(); ++mi ) {
1650 QPopupMenu* popup = mi.current()->popup;
1653 action->removeFrom( popup );
1658 \fn void QActionPGroup::selected( QActionP* )
1660 This signal is emitted from exclusive groups when toggle actions
1663 The argument is the action whose state changed to "on".
1665 \quotefile action/actiongroup/editor.cpp
1666 \skipto QActionPGroup
1667 \printline QActionPGroup
1668 \skipto QObject::connect
1671 In this example we connect the selected() signal to our own
1672 setFontColor() slot, passing the QActionP so that we know which
1673 action was chosen by the user.
1675 (See the \link actiongroup.html QActionPGroup Walkthrough. \endlink)
1677 \sa setExclusive(), isOn()
1682 void QActionPGroup::internalComboBoxActivated( int index )
1684 QActionP *a = d->actions.at( index );
1686 if ( a != d->selected ) {
1688 for ( QPtrListIterator<QActionP> it( d->actions); it.current(); ++it ) {
1689 if ( it.current()->isToggleAction() && it.current() != a )
1690 it.current()->setOn( FALSE );
1692 if ( a->isToggleAction() )
1696 emit selected( d->selected );
1697 emit ((QActionPGroup*)a)->activated();
1704 void QActionPGroup::internalToggle( QActionP *a )
1706 for ( QPtrListIterator<QComboBox> it( d->comboboxes); it.current(); ++it ) {
1707 int index = d->actions.find( a );
1709 it.current()->setCurrentItem( index );
1715 void QActionPGroup::objectDestroyed()
1717 const QObject* obj = sender();
1718 d->menubuttons.removeRef( (QToolButton*)obj );
1719 for ( QPtrListIterator<QActionPGroupPrivate::MenuItem> mi( d->menuitems ); mi.current(); ++mi ) {
1720 if ( mi.current()->popup == obj ) {
1721 d->menuitems.removeRef( mi.current() );
1725 d->popupmenus.removeRef( (QPopupMenu*)obj );
1726 d->comboboxes.removeRef( (QComboBox*)obj );
1729 /*! This function is called from the addTo() function when it created
1730 a widget (\a actionWidget) for the child action \a a in the \a
1734 void QActionPGroup::addedTo( QWidget *actionWidget, QWidget *container, QActionP *a )
1736 Q_UNUSED( actionWidget );
1737 Q_UNUSED( container );
1743 This function is called from the addTo() function when it created a
1744 menu item for the child action at the index \a index in the popup
1748 void QActionPGroup::addedTo( int index, QPopupMenu *menu, QActionP *a )
1757 This function is called from the addTo() function when it created
1758 a widget (\a actionWidget) in the \a container.
1761 void QActionPGroup::addedTo( QWidget *actionWidget, QWidget *container )
1763 Q_UNUSED( actionWidget );
1764 Q_UNUSED( container );
1769 This function is called from the addTo() function when it created a
1770 menu item at the index \a index in the popup menu \a menu.
1774 void QActionPGroup::addedTo( int index, QPopupMenu *menu )