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