kdeui Library API Documentation

kaction.cpp

00001 /* This file is part of the KDE libraries
00002     Copyright (C) 1999 Reginald Stadlbauer <reggie@kde.org>
00003               (C) 1999 Simon Hausmann <hausmann@kde.org>
00004               (C) 2000 Nicolas Hadacek <haadcek@kde.org>
00005               (C) 2000 Kurt Granroth <granroth@kde.org>
00006               (C) 2000 Michael Koch <koch@kde.org>
00007               (C) 2001 Holger Freyther <freyther@kde.org>
00008               (C) 2002 Ellis Whitehead <ellis@kde.org>
00009               (C) 2002 Joseph Wenninger <jowenn@kde.org>
00010 
00011     This library is free software; you can redistribute it and/or
00012     modify it under the terms of the GNU Library General Public
00013     License version 2 as published by the Free Software Foundation.
00014 
00015     This library is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018     Library General Public License for more details.
00019 
00020     You should have received a copy of the GNU Library General Public License
00021     along with this library; see the file COPYING.LIB.  If not, write to
00022     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00023     Boston, MA 02111-1307, USA.
00024 */
00025 
00026 #include "kaction.h"
00027 
00028 #include <assert.h>
00029 
00030 #include <qtooltip.h>
00031 #include <qwhatsthis.h>
00032 
00033 #include <kaccel.h>
00034 #include <kaccelbase.h>
00035 #include <kaccelprivate.h>
00036 #include <kapplication.h>
00037 #include <kdebug.h>
00038 #include <kguiitem.h>
00039 #include <kmainwindow.h>
00040 #include <kmenubar.h>
00041 #include <kpopupmenu.h>
00042 #include <ktoolbar.h>
00043 #include <ktoolbarbutton.h>
00044 
00045 #include <ft2build.h>
00046 #include FT_FREETYPE_H
00047 #include <X11/Xdefs.h>
00048 #include <X11/Xlib.h>
00049 #include <X11/Xatom.h>
00050 #include <X11/Intrinsic.h>
00051 #include <X11/StringDefs.h>
00052 #include <X11/Shell.h>
00053 
00054 #include <X11/Xft/Xft.h>
00055 
00077 int KAction::getToolButtonID()
00078 {
00079     static int toolbutton_no = -2;
00080     return toolbutton_no--;
00081 }
00082 
00083 //---------------------------------------------------------------------
00084 // KAction::KActionPrivate
00085 //---------------------------------------------------------------------
00086 
00087 class KAction::KActionPrivate : public KGuiItem
00088 {
00089 public:
00090   KActionPrivate() : KGuiItem()
00091   {
00092     m_kaccel = 0;
00093     m_configurable = true;
00094   }
00095 
00096   KAccel *m_kaccel;
00097   QValueList<KAccel*> m_kaccelList;
00098 
00099   QString m_groupText;
00100   QString m_group;
00101 
00102   KShortcut m_cut;
00103   KShortcut m_cutDefault;
00104 
00105   bool m_configurable;
00106 
00107   struct Container
00108   {
00109     Container() { m_container = 0; m_representative = 0; m_id = 0; }
00110     Container( const Container& s ) { m_container = s.m_container;
00111                                       m_id = s.m_id; m_representative = s.m_representative; }
00112     QWidget* m_container;
00113     int m_id;
00114     QWidget* m_representative;
00115   };
00116 
00117   QValueList<Container> m_containers;
00118 };
00119 
00120 //---------------------------------------------------------------------
00121 // KAction
00122 //---------------------------------------------------------------------
00123 
00124 KAction::KAction( const QString& text, const KShortcut& cut,
00125              const QObject* receiver, const char* slot,
00126              KActionCollection* parent, const char* name )
00127 : QObject( parent, name ), d(new KActionPrivate)
00128 {
00129     initPrivate( text, cut, receiver, slot );
00130 }
00131 
00132 KAction::KAction( const QString& text, const QString& sIconName, const KShortcut& cut,
00133     const QObject* receiver, const char* slot,
00134     KActionCollection* parent, const char* name )
00135 : QObject( parent, name ), d(new KActionPrivate)
00136 {
00137     initPrivate( text, cut, receiver, slot );
00138     d->setIconName( sIconName );
00139 }
00140 
00141 KAction::KAction( const QString& text, const QIconSet& pix, const KShortcut& cut,
00142     const QObject* receiver, const char* slot,
00143     KActionCollection* parent, const char* name )
00144 : QObject( parent, name ), d(new KActionPrivate)
00145 {
00146     initPrivate( text, cut, receiver, slot );
00147     d->setIconSet( pix );
00148 }
00149 
00150 KAction::KAction( const KGuiItem& item, const KShortcut& cut,
00151     const QObject* receiver, const char* slot,
00152     KActionCollection* parent, const char* name )
00153 : QObject( parent, name ), d(new KActionPrivate)
00154 {
00155     initPrivate( item.text(), cut, receiver, slot );
00156     if( item.hasIcon() )
00157         setIcon( item.iconName() );
00158     setToolTip( item.toolTip() );
00159     setWhatsThis( item.whatsThis() );
00160 }
00161 
00162 #ifndef KDE_NO_COMPAT // KDE 4: remove
00163 KAction::KAction( const QString& text, const KShortcut& cut,
00164                   QObject* parent, const char* name )
00165  : QObject( parent, name ), d(new KActionPrivate)
00166 {
00167     initPrivate( text, cut, 0, 0 );
00168 }
00169 
00170 KAction::KAction( const QString& text, const KShortcut& cut,
00171                   const QObject* receiver,
00172                   const char* slot, QObject* parent, const char* name )
00173  : QObject( parent, name ), d(new KActionPrivate)
00174 {
00175     initPrivate( text, cut, receiver, slot );
00176 }
00177 
00178 KAction::KAction( const QString& text, const QIconSet& pix,
00179                   const KShortcut& cut,
00180                   QObject* parent, const char* name )
00181  : QObject( parent, name ), d(new KActionPrivate)
00182 {
00183     initPrivate( text, cut, 0, 0 );
00184     setIconSet( pix );
00185 }
00186 
00187 KAction::KAction( const QString& text, const QString& pix,
00188                   const KShortcut& cut,
00189                   QObject* parent, const char* name )
00190 : QObject( parent, name ), d(new KActionPrivate)
00191 {
00192     initPrivate( text, cut, 0, 0 );
00193     d->setIconName( pix );
00194 }
00195 
00196 KAction::KAction( const QString& text, const QIconSet& pix,
00197                   const KShortcut& cut,
00198                   const QObject* receiver, const char* slot, QObject* parent,
00199                   const char* name )
00200  : QObject( parent, name ), d(new KActionPrivate)
00201 {
00202     initPrivate( text, cut, receiver, slot );
00203     setIconSet( pix );
00204 }
00205 
00206 KAction::KAction( const QString& text, const QString& pix,
00207                   const KShortcut& cut,
00208                   const QObject* receiver, const char* slot, QObject* parent,
00209                   const char* name )
00210   : QObject( parent, name ), d(new KActionPrivate)
00211 {
00212     initPrivate( text, cut, receiver, slot );
00213     d->setIconName(pix);
00214 }
00215 
00216 KAction::KAction( QObject* parent, const char* name )
00217  : QObject( parent, name ), d(new KActionPrivate)
00218 {
00219     initPrivate( QString::null, KShortcut(), 0, 0 );
00220 }
00221 #endif // KDE 4: remove end
00222 
00223 KAction::~KAction()
00224 {
00225     kdDebug(129) << "KAction::~KAction( this = \"" << name() << "\" )" << endl; // -- ellis
00226 #ifndef KDE_NO_COMPAT
00227      if (d->m_kaccel)
00228        unplugAccel();
00229 #endif
00230 
00231     // If actionCollection hasn't already been destructed,
00232     if ( m_parentCollection ) {
00233         m_parentCollection->take( this );
00234 
00235         const QValueList<KAccel*> & accelList = d->m_kaccelList;
00236         QValueList<KAccel*>::const_iterator itr = accelList.constBegin();
00237         const QValueList<KAccel*>::const_iterator itrEnd = accelList.constEnd();
00238 
00239         const char * const namePtr = name();
00240         for (; itr != itrEnd; ++itr )
00241             (*itr)->remove(namePtr);
00242 
00243     }
00244 
00245     // Do not call unplugAll from here, as tempting as it sounds.
00246     // KAction is designed around the idea that you need to plug
00247     // _and_ to unplug it "manually". Unplugging leads to an important
00248     // slowdown when e.g. closing the window, in which case we simply
00249     // want to destroy everything asap, not to remove actions one by one
00250     // from the GUI.
00251 
00252     delete d;
00253 }
00254 
00255 void KAction::initPrivate( const QString& text, const KShortcut& cut,
00256                   const QObject* receiver, const char* slot )
00257 {
00258     d->m_cutDefault = cut;
00259 
00260     m_parentCollection = dynamic_cast<KActionCollection *>( parent() );
00261     kdDebug(129) << "KAction::initPrivate(): this = " << this << " name = \"" << name() << "\" cut = " << cut.toStringInternal() << " m_parentCollection = " << m_parentCollection << endl;
00262     if ( m_parentCollection )
00263         m_parentCollection->insert( this );
00264 
00265     if ( receiver && slot )
00266         connect( this, SIGNAL( activated() ), receiver, slot );
00267 
00268     if( !cut.isNull() && !qstrcmp( name(), "unnamed" ) )
00269         kdWarning(129) << "KAction::initPrivate(): trying to assign a shortcut (" << cut.toStringInternal() << ") to an unnamed action." << endl;
00270     d->setText( text );
00271     initShortcut( cut );
00272 }
00273 
00274 bool KAction::isPlugged() const
00275 {
00276   return (!d->m_containers.empty()) || d->m_kaccel;
00277 }
00278 
00279 bool KAction::isPlugged( const QWidget *container ) const
00280 {
00281   return findContainer( container ) > -1;
00282 }
00283 
00284 bool KAction::isPlugged( const QWidget *container, int id ) const
00285 {
00286   int i = findContainer( container );
00287   return ( i > -1 && itemId( i ) == id );
00288 }
00289 
00290 bool KAction::isPlugged( const QWidget *container, const QWidget *_representative ) const
00291 {
00292   int i = findContainer( container );
00293   return ( i > -1 && representative( i ) == _representative );
00294 }
00295 
00296 
00297 /*
00298 Three actionCollection conditions:
00299     1) Scope is known on creation and KAccel object is created (e.g. KMainWindow)
00300     2) Scope is unknown and no KAccel object is available (e.g. KXMLGUIClient)
00301         a) addClient() will be called on object
00302         b) we just want to add the actions to another KXMLGUIClient object
00303 
00304 The question is how to do we incorporate #2b into the XMLGUI framework?
00305 
00306 
00307 We have a KCommandHistory object with undo and redo actions in a passed actionCollection
00308 We have a KoDoc object which holds a KCommandHistory object and the actionCollection
00309 We have two KoView objects which both point to the same KoDoc object
00310 Undo and Redo should be available in both KoView objects, and
00311     calling the undo->setEnabled() should affect both KoViews
00312 
00313 When addClient is called, it needs to be able to find the undo and redo actions
00314 When it calls plug() on them, they need to be inserted into the KAccel object of the appropriate KoView
00315 
00316 In this case, the actionCollection belongs to KoDoc and we need to let it know that its shortcuts
00317 have the same scope as the KoView actionCollection
00318 
00319 KXMLGUIClient::addSubActionCollection
00320 
00321 Document:
00322     create document actions
00323 
00324 View
00325     create view actions
00326     add document actionCollection as sub-collection
00327 
00328 A parentCollection is created
00329 Scenario 1: parentCollection has a focus widget set (e.g. via KMainWindow)
00330     A KAccel object is created in the parentCollection
00331     A KAction is created with parent=parentCollection
00332     The shortcut is inserted into this actionCollection
00333     Scenario 1a: xml isn't used
00334         done
00335     Scenario 1b: KXMLGUIBuilder::addClient() called
00336         setWidget is called -- ignore
00337         shortcuts are set
00338 Scenario 2: parentCollection has no focus widget (e.g., KParts)
00339     A KAction is created with parent=parentCollection
00340     Scenario 2a: xml isn't used
00341         no shortcuts
00342     Scenario 2b: KXMLGUIBuilder::addClient() called
00343         setWidget is called
00344         shortcuts are inserted into current KAccel
00345         shortcuts are set in all other KAccels, if the action is present in the other KAccels
00346 */
00347 
00348 /*
00349 shortcut may be set:
00350     - on construction
00351     - on plug
00352     - on reading XML
00353     - on plugAccel (deprecated)
00354 
00355 On Construction: [via initShortcut()]
00356     insert into KAccel of m_parentCollection,
00357         if kaccel() && isAutoConnectShortcuts() exists
00358 
00359 On Plug: [via plug() -> plugShortcut()]
00360     insert into KAccel of m_parentCollection, if exists and not already inserted into
00361 
00362 On Read XML: [via setShortcut()]
00363     set in all current KAccels
00364     insert into KAccel of m_parentCollection, if exists and not already inserted into
00365 */
00366 
00367 KAccel* KAction::kaccelCurrent()
00368 {
00369   if( m_parentCollection && m_parentCollection->builderKAccel() )
00370     return m_parentCollection->builderKAccel();
00371   else if( m_parentCollection && m_parentCollection->kaccel() )
00372     return m_parentCollection->kaccel();
00373   else
00374     return 0L;
00375 }
00376 
00377 // Only to be called from initPrivate()
00378 bool KAction::initShortcut( const KShortcut& cut )
00379 {
00380     d->m_cut = cut;
00381 
00382     // Only insert action into KAccel if it has a valid name,
00383     if( qstrcmp( name(), "unnamed" ) &&
00384         m_parentCollection &&
00385         m_parentCollection->isAutoConnectShortcuts() &&
00386         m_parentCollection->kaccel() )
00387     {
00388         insertKAccel( m_parentCollection->kaccel() );
00389         return true;
00390     }
00391     return false;
00392  }
00393 
00394 // Only to be called from plug()
00395 void KAction::plugShortcut()
00396 {
00397   KAccel* const kaccel = kaccelCurrent();
00398 
00399   //kdDebug(129) << "KAction::plugShortcut(): this = " << this << " kaccel() = " << (m_parentCollection ? m_parentCollection->kaccel() : 0) << endl;
00400   if( kaccel && qstrcmp( name(), "unnamed" ) ) {
00401     // Check if already plugged into current KAccel object
00402     const QValueList<KAccel*> & accelList = d->m_kaccelList;
00403     QValueList<KAccel*>::const_iterator itr = accelList.constBegin();
00404     const QValueList<KAccel*>::const_iterator itrEnd = accelList.constEnd();
00405 
00406     for( ; itr != itrEnd; ++itr) {
00407       if( (*itr) == kaccel )
00408         return;
00409     }
00410 
00411     insertKAccel( kaccel );
00412   }
00413 }
00414 
00415 bool KAction::setShortcut( const KShortcut& cut )
00416 {
00417   bool bChanged = (d->m_cut != cut);
00418   d->m_cut = cut;
00419 
00420   KAccel* const kaccel = kaccelCurrent();
00421   bool bInsertRequired = true;
00422   // Apply new shortcut to all existing KAccel objects
00423 
00424   const QValueList<KAccel*> & accelList = d->m_kaccelList;
00425   QValueList<KAccel*>::const_iterator itr = accelList.constBegin();
00426   const QValueList<KAccel*>::const_iterator itrEnd = accelList.constEnd();
00427 
00428   for( ; itr != itrEnd; ++itr) {
00429     // Check whether shortcut has already been plugged into
00430     //  the current kaccel object.
00431     if( (*itr) == kaccel )
00432       bInsertRequired = false;
00433     if( bChanged )
00434       updateKAccelShortcut( *itr );
00435   }
00436 
00437   // Only insert action into KAccel if it has a valid name,
00438   if( kaccel && bInsertRequired && qstrcmp( name(), "unnamed" ) )
00439     insertKAccel( kaccel );
00440 
00441   if( bChanged ) {
00442 #ifndef KDE_NO_COMPAT    // KDE 4: remove
00443     if ( d->m_kaccel )
00444       d->m_kaccel->setShortcut( name(), cut );
00445 #endif    // KDE 4: remove end
00446       int len = containerCount();
00447       for( int i = 0; i < len; ++i )
00448           updateShortcut( i );
00449   }
00450   return true;
00451 }
00452 
00453 bool KAction::updateKAccelShortcut( KAccel* kaccel )
00454 {
00455   // Check if action is permitted
00456   if (kapp && !kapp->authorizeKAction(name()))
00457     return false;
00458 
00459   bool b = true;
00460 
00461   if ( !kaccel->actions().actionPtr( name() ) ) {
00462     if(!d->m_cut.isNull() ) {
00463       kdDebug(129) << "Inserting " << name() << ", " << d->text() << ", " << d->plainText() << endl;
00464       b = kaccel->insert( name(), d->plainText(), QString::null,
00465           d->m_cut,
00466           this, SLOT(slotActivated()),
00467           isShortcutConfigurable(), isEnabled() );
00468     }
00469   }
00470   else
00471     b = kaccel->setShortcut( name(), d->m_cut );
00472 
00473   return b;
00474 }
00475 
00476 void KAction::insertKAccel( KAccel* kaccel )
00477 {
00478   //kdDebug(129) << "KAction::insertKAccel( " << kaccel << " ): this = " << this << endl;
00479   if ( !kaccel->actions().actionPtr( name() ) ) {
00480     if( updateKAccelShortcut( kaccel ) ) {
00481       d->m_kaccelList.append( kaccel );
00482       connect( kaccel, SIGNAL(destroyed()), this, SLOT(slotDestroyed()) );
00483     }
00484   }
00485   else
00486     kdWarning(129) << "KAction::insertKAccel( kaccel = " << kaccel << " ): KAccel object already contains an action name \"" << name() << "\"" << endl; // -- ellis
00487 }
00488 
00489 void KAction::removeKAccel( KAccel* kaccel )
00490 {
00491   //kdDebug(129) << "KAction::removeKAccel( " << i << " ): this = " << this << endl;
00492   QValueList<KAccel*> & accelList = d->m_kaccelList;
00493   QValueList<KAccel*>::iterator itr = accelList.begin();
00494   const QValueList<KAccel*>::iterator itrEnd = accelList.end();
00495 
00496   for( ; itr != itrEnd; ++itr) {
00497     if( (*itr) == kaccel ) {
00498       kaccel->remove( name() );
00499       accelList.remove( itr );
00500       disconnect( kaccel, SIGNAL(destroyed()), this, SLOT(slotDestroyed()) );
00501       break;
00502     }
00503   }
00504 }
00505 
00506 #ifndef KDE_NO_COMPAT
00507 // KDE 4: remove
00508 void KAction::setAccel( int keyQt )
00509 {
00510   setShortcut( KShortcut(keyQt) );
00511 }
00512 #endif // KDE 4: remove end
00513 
00514 void KAction::updateShortcut( int i )
00515 {
00516   int id = itemId( i );
00517 
00518   QWidget* w = container( i );
00519   if ( ::qt_cast<QPopupMenu *>( w ) ) {
00520     QPopupMenu* menu = static_cast<QPopupMenu*>(w);
00521     updateShortcut( menu, id );
00522   }
00523   else if ( ::qt_cast<QMenuBar *>( w ) )
00524     static_cast<QMenuBar*>(w)->setAccel( d->m_cut.keyCodeQt(), id );
00525 }
00526 
00527 void KAction::updateShortcut( QPopupMenu* menu, int id )
00528 {
00529   //kdDebug(129) << "KAction::updateShortcut(): this = " << this << " d->m_kaccelList.count() = " << d->m_kaccelList.count() << endl;
00530   // If the action has a KAccel object,
00531   //  show the string representation of its shortcut.
00532   if ( d->m_kaccel || d->m_kaccelList.count() ) {
00533     QString s = menu->text( id );
00534     int i = s.find( '\t' );
00535     if ( i >= 0 )
00536       s.replace( i+1, s.length()-i, d->m_cut.seq(0).toString() );
00537     else
00538       s += "\t" + d->m_cut.seq(0).toString();
00539 
00540     menu->changeItem( id, s );
00541   }
00542   // Otherwise insert the shortcut itself into the popup menu.
00543   else {
00544     // This is a fall-hack in case the KAction is missing a proper parent collection.
00545     //  It should be removed eventually. --ellis
00546     menu->setAccel( d->m_cut.keyCodeQt(), id );
00547     kdDebug(129) << "KAction::updateShortcut(): name = \"" << name() << "\", cut = " << d->m_cut.toStringInternal() << "; No KAccel, probably missing a parent collection." << endl;
00548   }
00549 }
00550 
00551 const KShortcut& KAction::shortcut() const
00552 {
00553   return d->m_cut;
00554 }
00555 
00556 const KShortcut& KAction::shortcutDefault() const
00557 {
00558   return d->m_cutDefault;
00559 }
00560 
00561 QString KAction::shortcutText() const
00562 {
00563   return d->m_cut.toStringInternal();
00564 }
00565 
00566 void KAction::setShortcutText( const QString& s )
00567 {
00568   setShortcut( KShortcut(s) );
00569 }
00570 
00571 #ifndef KDE_NO_COMPAT // Remove in KDE 4
00572 int KAction::accel() const
00573 {
00574   return d->m_cut.keyCodeQt();
00575 }
00576 #endif
00577 
00578 void KAction::setGroup( const QString& grp )
00579 {
00580   d->m_group = grp;
00581 
00582   int len = containerCount();
00583   for( int i = 0; i < len; ++i )
00584     updateGroup( i );
00585 }
00586 
00587 void KAction::updateGroup( int )
00588 {
00589   // DO SOMETHING
00590 }
00591 
00592 QString KAction::group() const
00593 {
00594   return d->m_group;
00595 }
00596 
00597 bool KAction::isEnabled() const
00598 {
00599   return d->isEnabled();
00600 }
00601 
00602 bool KAction::isShortcutConfigurable() const
00603 {
00604   return d->m_configurable;
00605 }
00606 
00607 void KAction::setToolTip( const QString& tt )
00608 {
00609   d->setToolTip( tt );
00610 
00611   int len = containerCount();
00612   for( int i = 0; i < len; ++i )
00613     updateToolTip( i );
00614 }
00615 
00616 void KAction::updateToolTip( int i )
00617 {
00618   QWidget *w = container( i );
00619 
00620   if ( ::qt_cast<KToolBar *>( w ) )
00621     QToolTip::add( static_cast<KToolBar*>(w)->getWidget( itemId( i ) ), d->toolTip() );
00622 }
00623 
00624 QString KAction::toolTip() const
00625 {
00626   return d->toolTip();
00627 }
00628 
00629 int KAction::plug( QWidget *w, int index )
00630 {
00631   //kdDebug(129) << "KAction::plug( " << w << ", " << index << " )" << endl;
00632   if (!w ) {
00633     kdWarning(129) << "KAction::plug called with 0 argument\n";
00634     return -1;
00635   }
00636 
00637   // Ellis: print warning if there is a shortcut, but no KAccel available (often due to no widget available in the actioncollection)
00638   // David: Well, it doesn't matter much, things still work (e.g. Undo in koffice) via QAccel.
00639   // We should probably re-enable the warning for things that only KAccel can do, though - e.g. WIN key (mapped to Meta).
00640 #if 0 //ndef NDEBUG
00641   KAccel* kaccel = kaccelCurrent();
00642   if( !d->m_cut.isNull() && !kaccel ) {
00643     kdDebug(129) << "KAction::plug(): has no KAccel object; this = " << this << " name = " << name() << " parentCollection = " << m_parentCollection << endl; // ellis
00644   }
00645 #endif
00646 
00647   // Check if action is permitted
00648   if (kapp && !kapp->authorizeKAction(name()))
00649     return -1;
00650 
00651   plugShortcut();
00652 
00653   if ( ::qt_cast<QPopupMenu *>( w ) )
00654   {
00655     QPopupMenu* menu = static_cast<QPopupMenu*>( w );
00656     int id;
00657     // Don't insert shortcut into menu if it's already in a KAccel object.
00658     int keyQt = (d->m_kaccelList.count() || d->m_kaccel) ? 0 : d->m_cut.keyCodeQt();
00659 
00660     if ( d->hasIcon() )
00661     {
00662         KInstance *instance;
00663         if ( m_parentCollection )
00664           instance = m_parentCollection->instance();
00665         else
00666           instance = KGlobal::instance();
00667         id = menu->insertItem( d->iconSet( KIcon::Small, 0, instance ), d->text(), this,//dsweet
00668                                  SLOT( slotPopupActivated() ), keyQt,
00669                                  -1, index );
00670     }
00671     else
00672         id = menu->insertItem( d->text(), this,
00673                                SLOT( slotPopupActivated() ),
00674                                keyQt, -1, index );
00675 
00676     // If the shortcut is already in a KAccel object, then
00677     //  we need to set the menu item's shortcut text.
00678     if ( d->m_kaccelList.count() || d->m_kaccel )
00679         updateShortcut( menu, id );
00680 
00681     // call setItemEnabled only if the item really should be disabled,
00682     // because that method is slow and the item is per default enabled
00683     if ( !d->isEnabled() )
00684         menu->setItemEnabled( id, false );
00685 
00686     if ( !d->whatsThis().isEmpty() )
00687         menu->setWhatsThis( id, whatsThisWithIcon() );
00688 
00689     addContainer( menu, id );
00690     connect( menu, SIGNAL( destroyed() ), this, SLOT( slotDestroyed() ) );
00691 
00692     if ( m_parentCollection )
00693       m_parentCollection->connectHighlight( menu, this );
00694 
00695     return d->m_containers.count() - 1;
00696   }
00697   else if ( ::qt_cast<KToolBar *>( w ) )
00698   {
00699     KToolBar *bar = static_cast<KToolBar *>( w );
00700 
00701     int id_ = getToolButtonID();
00702     KInstance *instance;
00703     if ( m_parentCollection )
00704       instance = m_parentCollection->instance();
00705     else
00706       instance = KGlobal::instance();
00707 
00708     if ( icon().isEmpty() && !iconSet().pixmap().isNull() ) // old code using QIconSet directly
00709     {
00710         bar->insertButton( iconSet().pixmap(), id_, SIGNAL( buttonClicked(int, Qt::ButtonState) ), this,
00711                            SLOT( slotButtonClicked(int, Qt::ButtonState) ),
00712                            d->isEnabled(), d->plainText(), index );
00713     }
00714     else
00715     {
00716         QString icon = d->iconName();
00717         if ( icon.isEmpty() )
00718             icon = "unknown";
00719         bar->insertButton( icon, id_, SIGNAL( buttonClicked(int, Qt::ButtonState) ), this,
00720                            SLOT( slotButtonClicked(int, Qt::ButtonState) ),
00721                            d->isEnabled(), d->plainText(), index, instance );
00722     }
00723 
00724     KToolBarButton* ktb = bar->getButton(id_);
00725     ktb->setName( QCString("toolbutton_")+name() );
00726 
00727     if ( !d->whatsThis().isEmpty() )
00728         QWhatsThis::add( bar->getButton(id_), whatsThisWithIcon() );
00729 
00730     if ( !d->toolTip().isEmpty() )
00731       QToolTip::add( bar->getButton(id_), d->toolTip() );
00732 
00733     addContainer( bar, id_ );
00734 
00735     connect( bar, SIGNAL( destroyed() ), this, SLOT( slotDestroyed() ) );
00736 
00737     if ( m_parentCollection )
00738       m_parentCollection->connectHighlight( bar, this );
00739 
00740     return containerCount() - 1;
00741   }
00742 
00743   return -1;
00744 }
00745 
00746 void KAction::unplug( QWidget *w )
00747 {
00748   int i = findContainer( w );
00749   if ( i == -1 )
00750     return;
00751   int id = itemId( i );
00752 
00753   if ( ::qt_cast<QPopupMenu *>( w ) )
00754   {
00755     QPopupMenu *menu = static_cast<QPopupMenu *>( w );
00756     menu->removeItem( id );
00757   }
00758   else if ( ::qt_cast<KToolBar *>( w ) )
00759   {
00760     KToolBar *bar = static_cast<KToolBar *>( w );
00761     bar->removeItemDelayed( id );
00762   }
00763   else if ( ::qt_cast<QMenuBar *>( w ) )
00764   {
00765     QMenuBar *bar = static_cast<QMenuBar *>( w );
00766     bar->removeItem( id );
00767   }
00768 
00769   removeContainer( i );
00770   if ( m_parentCollection )
00771     m_parentCollection->disconnectHighlight( w, this );
00772 }
00773 
00774 void KAction::plugAccel(KAccel *kacc, bool configurable)
00775 {
00776   kdWarning(129) << "KAction::plugAccel(): call to deprecated action." << endl;
00777   kdDebug(129) << kdBacktrace() << endl;
00778   //kdDebug(129) << "KAction::plugAccel( kacc = " << kacc << " ): name \"" << name() << "\"" << endl;
00779   if ( d->m_kaccel )
00780     unplugAccel();
00781 
00782   // If the parent collection's accel ptr isn't set yet
00783   //if ( m_parentCollection && !m_parentCollection->accel() )
00784   //  m_parentCollection->setAccel( kacc );
00785 
00786   // We can only plug this action into the given KAccel object
00787   //  if it does not already contain an action with the same name.
00788   if ( !kacc->actions().actionPtr(name()) )
00789   {
00790     d->m_kaccel = kacc;
00791     d->m_kaccel->insert(name(), d->plainText(), QString::null,
00792         KShortcut(d->m_cut),
00793         this, SLOT(slotActivated()),
00794         configurable, isEnabled());
00795     connect(d->m_kaccel, SIGNAL(destroyed()), this, SLOT(slotDestroyed()));
00796     //connect(d->m_kaccel, SIGNAL(keycodeChanged()), this, SLOT(slotKeycodeChanged()));
00797   }
00798   else
00799     kdWarning(129) << "KAction::plugAccel( kacc = " << kacc << " ): KAccel object already contains an action name \"" << name() << "\"" << endl; // -- ellis
00800 }
00801 
00802 void KAction::unplugAccel()
00803 {
00804   //kdDebug(129) << "KAction::unplugAccel() " << this << " " << name() << endl;
00805   if ( d->m_kaccel )
00806   {
00807     d->m_kaccel->remove(name());
00808     d->m_kaccel = 0;
00809   }
00810 }
00811 
00812 void KAction::plugMainWindowAccel( QWidget *w )
00813 {
00814   // Note: topLevelWidget() stops too early, we can't use it.
00815   QWidget * tl = w;
00816   QWidget * n;
00817   while ( !tl->isDialog() && ( n = tl->parentWidget() ) ) // lookup parent and store
00818     tl = n;
00819 
00820   KMainWindow * mw = dynamic_cast<KMainWindow *>(tl); // try to see if it's a kmainwindow
00821   if (mw)
00822     plugAccel( mw->accel() );
00823   else
00824     kdDebug(129) << "KAction::plugMainWindowAccel: Toplevel widget isn't a KMainWindow, can't plug accel. " << tl << endl;
00825 }
00826 
00827 void KAction::setEnabled(bool enable)
00828 {
00829   //kdDebug(129) << "KAction::setEnabled( " << enable << " ): this = " << this << " d->m_kaccelList.count() = " << d->m_kaccelList.count() << endl;
00830   if ( enable == d->isEnabled() )
00831     return;
00832 
00833 #ifndef KDE_NO_COMPAT
00834   // KDE 4: remove
00835   if (d->m_kaccel)
00836     d->m_kaccel->setEnabled(name(), enable);
00837 #endif  // KDE 4: remove end
00838 
00839   const QValueList<KAccel*> & accelList = d->m_kaccelList;
00840   QValueList<KAccel*>::const_iterator itr = accelList.constBegin();
00841   const QValueList<KAccel*>::const_iterator itrEnd = accelList.constEnd();
00842 
00843   const char * const namePtr = name();
00844 
00845   for ( ; itr != itrEnd; ++itr )
00846     (*itr)->setEnabled( namePtr, enable );
00847 
00848   d->setEnabled( enable );
00849 
00850   int len = containerCount();
00851   for( int i = 0; i < len; ++i )
00852     updateEnabled( i );
00853 
00854   emit enabled( d->isEnabled() );
00855 }
00856 
00857 void KAction::updateEnabled( int i )
00858 {
00859     QWidget *w = container( i );
00860 
00861     if ( ::qt_cast<QPopupMenu *>( w ) )
00862       static_cast<QPopupMenu*>(w)->setItemEnabled( itemId( i ), d->isEnabled() );
00863     else if ( ::qt_cast<QMenuBar *>( w ) )
00864       static_cast<QMenuBar*>(w)->setItemEnabled( itemId( i ), d->isEnabled() );
00865     else if ( ::qt_cast<KToolBar *>( w ) )
00866       static_cast<KToolBar*>(w)->setItemEnabled( itemId( i ), d->isEnabled() );
00867 }
00868 
00869 void KAction::setShortcutConfigurable( bool b )
00870 {
00871     d->m_configurable = b;
00872 }
00873 
00874 void KAction::setText( const QString& text )
00875 {
00876 #ifndef KDE_NO_COMPAT
00877   // KDE 4: remove
00878   if (d->m_kaccel) {
00879     KAccelAction* pAction = d->m_kaccel->actions().actionPtr(name());
00880     if (pAction)
00881       pAction->setLabel( text );
00882   }
00883 #endif  // KDE 4: remove end
00884   const QValueList<KAccel*> & accelList = d->m_kaccelList;
00885   QValueList<KAccel*>::const_iterator itr = accelList.constBegin();
00886   const QValueList<KAccel*>::const_iterator itrEnd = accelList.constEnd();
00887 
00888   const char * const namePtr = name();
00889 
00890   for( ; itr != itrEnd; ++itr ) {
00891     KAccelAction* const pAction = (*itr)->actions().actionPtr(namePtr);
00892     if (pAction)
00893       pAction->setLabel( text );
00894   }
00895 
00896   d->setText( text );
00897 
00898   int len = containerCount();
00899   for( int i = 0; i < len; ++i )
00900     updateText( i );
00901 }
00902 
00903 void KAction::updateText( int i )
00904 {
00905   QWidget *w = container( i );
00906 
00907   if ( ::qt_cast<QPopupMenu *>( w ) ) {
00908     int id = itemId( i );
00909     static_cast<QPopupMenu*>(w)->changeItem( id, d->text() );
00910     if (!d->m_cut.isNull())
00911       updateShortcut( static_cast<QPopupMenu*>(w), id );
00912   }
00913   else if ( ::qt_cast<QMenuBar *>( w ) )
00914     static_cast<QMenuBar*>(w)->changeItem( itemId( i ), d->text() );
00915   else if ( ::qt_cast<KToolBar *>( w ) )
00916   {
00917     QWidget *button = static_cast<KToolBar *>(w)->getWidget( itemId( i ) );
00918     if ( ::qt_cast<KToolBarButton *>( button ) )
00919       static_cast<KToolBarButton *>(button)->setText( d->plainText() );
00920   }
00921 }
00922 
00923 QString KAction::text() const
00924 {
00925   return d->text();
00926 }
00927 
00928 QString KAction::plainText() const
00929 {
00930   return d->plainText( );
00931 }
00932 
00933 void KAction::setIcon( const QString &icon )
00934 {
00935   d->setIconName( icon );
00936 
00937   // now handle any toolbars
00938   int len = containerCount();
00939   for ( int i = 0; i < len; ++i )
00940     updateIcon( i );
00941 }
00942 
00943 void KAction::updateIcon( int id )
00944 {
00945   QWidget* w = container( id );
00946 
00947   if ( ::qt_cast<QPopupMenu *>( w ) ) {
00948     int itemId_ = itemId( id );
00949     static_cast<QPopupMenu*>(w)->changeItem( itemId_, d->iconSet( KIcon::Small ), d->text() );
00950     if (!d->m_cut.isNull())
00951       updateShortcut( static_cast<QPopupMenu*>(w), itemId_ );
00952   }
00953   else if ( ::qt_cast<QMenuBar *>( w ) )
00954     static_cast<QMenuBar*>(w)->changeItem( itemId( id ), d->iconSet( KIcon::Small ), d->text() );
00955   else if ( ::qt_cast<KToolBar *>( w ) )
00956     static_cast<KToolBar *>(w)->setButtonIcon( itemId( id ), d->iconName() );
00957 }
00958 
00959 QString KAction::icon() const
00960 {
00961   return d->iconName( );
00962 }
00963 
00964 void KAction::setIconSet( const QIconSet &iconset )
00965 {
00966   d->setIconSet( iconset );
00967 
00968   int len = containerCount();
00969   for( int i = 0; i < len; ++i )
00970     updateIconSet( i );
00971 }
00972 
00973 
00974 void KAction::updateIconSet( int id )
00975 {
00976   QWidget *w = container( id );
00977 
00978   if ( ::qt_cast<QPopupMenu *>( w ) )
00979   {
00980     int itemId_ = itemId( id );
00981     static_cast<QPopupMenu*>(w)->changeItem( itemId_, d->iconSet(), d->text() );
00982     if (!d->m_cut.isNull())
00983       updateShortcut( static_cast<QPopupMenu*>(w), itemId_ );
00984   }
00985   else if ( ::qt_cast<QMenuBar *>( w ) )
00986     static_cast<QMenuBar*>(w)->changeItem( itemId( id ), d->iconSet(), d->text() );
00987   else if ( ::qt_cast<KToolBar *>( w ) )
00988   {
00989     if ( icon().isEmpty() && d->hasIcon() ) // only if there is no named icon ( scales better )
00990       static_cast<KToolBar *>(w)->setButtonIconSet( itemId( id ), d->iconSet() );
00991     else
00992       static_cast<KToolBar *>(w)->setButtonIconSet( itemId( id ), d->iconSet( KIcon::Small ) );
00993   }
00994 }
00995 
00996 QIconSet KAction::iconSet( KIcon::Group group, int size ) const
00997 {
00998     return d->iconSet( group, size );
00999 }
01000 
01001 bool KAction::hasIcon() const
01002 {
01003   return d->hasIcon();
01004 }
01005 
01006 void KAction::setWhatsThis( const QString& text )
01007 {
01008   d->setWhatsThis(  text );
01009 
01010   int len = containerCount();
01011   for( int i = 0; i < len; ++i )
01012     updateWhatsThis( i );
01013 }
01014 
01015 void KAction::updateWhatsThis( int i )
01016 {
01017   QPopupMenu* pm = popupMenu( i );
01018   if ( pm )
01019   {
01020     pm->setWhatsThis( itemId( i ), d->whatsThis() );
01021     return;
01022   }
01023 
01024   KToolBar *tb = toolBar( i );
01025   if ( tb )
01026   {
01027     QWidget *w = tb->getButton( itemId( i ) );
01028     QWhatsThis::remove( w );
01029     QWhatsThis::add( w, d->whatsThis() );
01030     return;
01031   }
01032 }
01033 
01034 QString KAction::whatsThis() const
01035 {
01036   return d->whatsThis();
01037 }
01038 
01039 QString KAction::whatsThisWithIcon() const
01040 {
01041     QString text = whatsThis();
01042     if (!d->iconName().isEmpty())
01043       return QString::fromLatin1("<img source=\"small|%1\"> %2").arg(d->iconName() ).arg(text);
01044     return text;
01045 }
01046 
01047 QWidget* KAction::container( int index ) const
01048 {
01049   assert( index < containerCount() );
01050   return d->m_containers[ index ].m_container;
01051 }
01052 
01053 KToolBar* KAction::toolBar( int index ) const
01054 {
01055     return dynamic_cast<KToolBar *>( d->m_containers[ index ].m_container );
01056 }
01057 
01058 QPopupMenu* KAction::popupMenu( int index ) const
01059 {
01060     return dynamic_cast<QPopupMenu *>( d->m_containers[ index ].m_container );
01061 }
01062 
01063 QWidget* KAction::representative( int index ) const
01064 {
01065   return d->m_containers[ index ].m_representative;
01066 }
01067 
01068 int KAction::itemId( int index ) const
01069 {
01070   return d->m_containers[ index ].m_id;
01071 }
01072 
01073 int KAction::containerCount() const
01074 {
01075   return d->m_containers.count();
01076 }
01077 
01078 uint KAction::kaccelCount() const
01079 {
01080   return d->m_kaccelList.count();
01081 }
01082 
01083 void KAction::addContainer( QWidget* c, int id )
01084 {
01085   KActionPrivate::Container p;
01086   p.m_container = c;
01087   p.m_id = id;
01088   d->m_containers.append( p );
01089 }
01090 
01091 void KAction::addContainer( QWidget* c, QWidget* w )
01092 {
01093   KActionPrivate::Container p;
01094   p.m_container = c;
01095   p.m_representative = w;
01096   d->m_containers.append( p );
01097 }
01098 
01099 void KAction::activate()
01100 {
01101   emit activated( KAction::EmulatedActivation, Qt::NoButton );
01102   slotActivated();
01103 }
01104 
01105 void KAction::slotActivated()
01106 {
01107   const QObject *senderObj = sender();
01108   if ( senderObj )
01109   {
01110     if ( ::qt_cast<KAccelPrivate *>( senderObj ) )
01111         emit activated( KAction::AccelActivation, Qt::NoButton );
01112   }
01113   emit activated();
01114 }
01115 
01116 // This catches signals emitted by KActions inserted into QPopupMenu
01117 // We do crude things inside it, because we need to know which
01118 // QPopupMenu emitted the signal. We need to be sure that it is
01119 // only called by QPopupMenus, we plugged us in.
01120 void KAction::slotPopupActivated()
01121 {
01122   if( ::qt_cast<QSignal *>(sender()))
01123   {
01124     int id = dynamic_cast<const QSignal *>(sender())->value().toInt();
01125     int pos = findContainer(id);
01126     if(pos != -1)
01127     {
01128       QPopupMenu* qpm = dynamic_cast<QPopupMenu *>( container(pos) );
01129       if(qpm)
01130       {
01131         KPopupMenu* kpm = dynamic_cast<KPopupMenu *>( qpm );
01132         Qt::ButtonState state;
01133         if ( kpm ) // KPopupMenu? Nice, it stores the state.
01134             state = kpm->state();
01135         else { // just a QPopupMenu? We'll ask for the state now then (small race condition?)
01136             kdDebug(129) << "KAction::slotPopupActivated not a KPopupMenu -> using keyboardMouseState()" << endl;
01137             state = KApplication::keyboardMouseState();
01138         }
01139         emit activated( KAction::PopupMenuActivation, state );
01140         slotActivated();
01141         return;
01142       }
01143     }
01144   }
01145 
01146   kdWarning(129)<<"Don't connect KAction::slotPopupActivated() to anything, expect into QPopupMenus which are in containers. Use slotActivated instead."<<endl;
01147   emit activated( KAction::PopupMenuActivation, Qt::NoButton );
01148   slotActivated();
01149 }
01150 
01151 void KAction::slotButtonClicked( int, Qt::ButtonState state )
01152 {
01153   kdDebug(129) << "slotButtonClicked() state=" << state << endl;
01154   emit activated( KAction::ToolBarActivation, state );
01155 
01156   // RightButton isn't really an activation
01157   if ( ( state & LeftButton ) || ( state & MidButton ) )
01158     slotActivated();
01159 }
01160 
01161 
01162 void KAction::slotDestroyed()
01163 {
01164   kdDebug(129) << "KAction::slotDestroyed(): this = " << this << ", name = \"" << name() << "\", sender = " << sender() << endl;
01165   const QObject* const o = sender();
01166 
01167 #ifndef KDE_NO_COMPAT  // KDE 4: remove
01168   if ( o == d->m_kaccel )
01169   {
01170     d->m_kaccel = 0;
01171     return;
01172   }
01173 #endif  // KDE 4: remove end
01174   QValueList<KAccel*> & accelList = d->m_kaccelList;
01175   QValueList<KAccel*>::iterator itr = accelList.begin();
01176   const QValueList<KAccel*>::iterator itrEnd = accelList.end();
01177 
01178   for( ; itr != itrEnd; ++itr)
01179   {
01180     if ( o == *itr )
01181     {
01182       disconnect( *itr, SIGNAL(destroyed()), this, SLOT(slotDestroyed()) );
01183       accelList.remove(itr);
01184       return;
01185     }
01186   }
01187 
01188   int i;
01189   do
01190   {
01191     i = findContainer( static_cast<const QWidget*>( o ) );
01192     if ( i != -1 )
01193       removeContainer( i );
01194   } while ( i != -1 );
01195 }
01196 
01197 int KAction::findContainer( const QWidget* widget ) const
01198 {
01199   int pos = 0;
01200 
01201   const QValueList<KActionPrivate::Container> & containers = d->m_containers;
01202 
01203   QValueList<KActionPrivate::Container>::ConstIterator it = containers.constBegin();
01204   const QValueList<KActionPrivate::Container>::ConstIterator itEnd = containers.constEnd();
01205 
01206   while( it != itEnd )
01207   {
01208     if ( (*it).m_representative == widget || (*it).m_container == widget )
01209       return pos;
01210     ++it;
01211     ++pos;
01212   }
01213 
01214   return -1;
01215 }
01216 
01217 int KAction::findContainer( const int id ) const
01218 {
01219   int pos = 0;
01220 
01221   const QValueList<KActionPrivate::Container> & containers = d->m_containers;
01222 
01223   QValueList<KActionPrivate::Container>::ConstIterator it = containers.constBegin();
01224   const QValueList<KActionPrivate::Container>::ConstIterator itEnd = containers.constEnd();
01225 
01226   while( it != itEnd )
01227   {
01228     if ( (*it).m_id == id )
01229       return pos;
01230     ++it;
01231     ++pos;
01232   }
01233 
01234   return -1;
01235 }
01236 
01237 void KAction::removeContainer( int index )
01238 {
01239   int i = 0;
01240 
01241   QValueList<KActionPrivate::Container> & containers = d->m_containers;
01242 
01243   QValueList<KActionPrivate::Container>::Iterator it = containers.begin();
01244   const QValueList<KActionPrivate::Container>::Iterator itEnd = containers.end();
01245 
01246   while( it != itEnd )
01247   {
01248     if ( i == index )
01249     {
01250       containers.remove( it );
01251       return;
01252     }
01253     ++it;
01254     ++i;
01255   }
01256 }
01257 
01258 // FIXME: Remove this (ellis)
01259 void KAction::slotKeycodeChanged()
01260 {
01261   kdDebug(129) << "KAction::slotKeycodeChanged()" << endl; // -- ellis
01262   KAccelAction* pAction = d->m_kaccel->actions().actionPtr(name());
01263   if( pAction )
01264     setShortcut(pAction->shortcut());
01265 }
01266 
01267 KActionCollection *KAction::parentCollection() const
01268 {
01269     return m_parentCollection;
01270 }
01271 
01272 void KAction::unplugAll()
01273 {
01274   while ( containerCount() != 0 )
01275     unplug( container( 0 ) );
01276 }
01277 
01278 const KGuiItem& KAction::guiItem() const
01279 {
01280     return *d;
01281 }
01282 
01283 void KAction::virtual_hook( int, void* )
01284 { /*BASE::virtual_hook( id, data );*/ }
01285 
01286 /* vim: et sw=2 ts=2
01287  */
01288 
01289 #include "kaction.moc"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Mar 22 19:48:24 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003