kaccelmanager.cpp
00001 /* This file is part of the KDE project 00002 Copyright (C) 2002 Matthias H�lzer-Kl�pfel <mhk@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "kaccelmanager.h" 00021 00022 #include <tqapplication.h> 00023 #include <tqcheckbox.h> 00024 #include <tqcombobox.h> 00025 #include <tqgroupbox.h> 00026 #include <tqlabel.h> 00027 #include <tqlineedit.h> 00028 #include <tqmenubar.h> 00029 #include <tqmemarray.h> 00030 #include <tqmetaobject.h> 00031 #include <tqmainwindow.h> 00032 #include <tqobjectlist.h> 00033 #include <tqpopupmenu.h> 00034 #include <tqptrlist.h> 00035 #include <tqpushbutton.h> 00036 #include <tqradiobutton.h> 00037 #include <tqspinbox.h> 00038 #include <tqtabbar.h> 00039 #include <tqtextview.h> 00040 #include <tqwidget.h> 00041 #include <tqwidgetstack.h> 00042 00043 #include <kstdaction.h> 00044 #include <kstaticdeleter.h> 00045 #include <kdebug.h> 00046 00047 00048 #include "kaccelmanager_private.h" 00049 #include "../kdeui/kstdaction_p.h" 00050 00051 00052 /********************************************************************* 00053 00054 class Item - helper class containing widget information 00055 00056 This class stores information about the widgets the need accelerators, 00057 as well as about their relationship. 00058 00059 *********************************************************************/ 00060 00061 00062 00063 /********************************************************************* 00064 00065 class KAcceleratorManagerPrivate - internal helper class 00066 00067 This class does all the work to find accelerators for a hierarchy of 00068 widgets. 00069 00070 *********************************************************************/ 00071 00072 00073 class KAcceleratorManagerPrivate 00074 { 00075 public: 00076 00077 static void manage(TQWidget *widget); 00078 static bool programmers_mode; 00079 static bool standardName(const TQString &str); 00080 00081 static bool checkChange(const KAccelString &as) { 00082 TQString t2 = as.accelerated(); 00083 TQString t1 = as.originalText(); 00084 if (t1 != t2) 00085 { 00086 if (as.accel() == -1) { 00087 removed_string += "<tr><td>" + TQStyleSheet::escape(t1) + "</td></tr>"; 00088 } else if (as.originalAccel() == -1) { 00089 added_string += "<tr><td>" + TQStyleSheet::escape(t2) + "</td></tr>"; 00090 } else { 00091 changed_string += "<tr><td>" + TQStyleSheet::escape(t1) + "</td>"; 00092 changed_string += "<td>" + TQStyleSheet::escape(t2) + "</td></tr>"; 00093 } 00094 return true; 00095 } 00096 return false; 00097 } 00098 static TQString changed_string; 00099 static TQString added_string; 00100 static TQString removed_string; 00101 static TQMap<TQWidget *, int> ignored_widgets; 00102 00103 private: 00104 class Item; 00105 public: 00106 typedef TQPtrList<Item> ItemList; 00107 00108 private: 00109 static void traverseChildren(TQWidget *widget, Item *item); 00110 00111 static void manageWidget(TQWidget *widget, Item *item); 00112 static void manageMenuBar(TQMenuBar *mbar, Item *item); 00113 static void manageTabBar(TQTabBar *bar, Item *item); 00114 00115 static void calculateAccelerators(Item *item, TQString &used); 00116 00117 class Item 00118 { 00119 public: 00120 00121 Item() : m_widget(0), m_children(0), m_index(-1) {} 00122 ~Item(); 00123 00124 void addChild(Item *item); 00125 00126 TQWidget *m_widget; 00127 KAccelString m_content; 00128 ItemList *m_children; 00129 int m_index; 00130 00131 }; 00132 }; 00133 00134 00135 bool KAcceleratorManagerPrivate::programmers_mode = false; 00136 TQString KAcceleratorManagerPrivate::changed_string; 00137 TQString KAcceleratorManagerPrivate::added_string; 00138 TQString KAcceleratorManagerPrivate::removed_string; 00139 static TQStringList *kaccmp_sns = 0; 00140 static KStaticDeleter<TQStringList> kaccmp_sns_d; 00141 TQMap<TQWidget*, int> KAcceleratorManagerPrivate::ignored_widgets; 00142 00143 bool KAcceleratorManagerPrivate::standardName(const TQString &str) 00144 { 00145 if (!kaccmp_sns) 00146 kaccmp_sns_d.setObject(kaccmp_sns, new TQStringList(KStdAction::internal_stdNames())); 00147 return kaccmp_sns->contains(str); 00148 } 00149 00150 KAcceleratorManagerPrivate::Item::~Item() 00151 { 00152 delete m_children; 00153 } 00154 00155 00156 void KAcceleratorManagerPrivate::Item::addChild(Item *item) 00157 { 00158 if (!m_children) { 00159 m_children = new ItemList; 00160 m_children->setAutoDelete(true); 00161 } 00162 00163 m_children->append(item); 00164 } 00165 00166 void KAcceleratorManagerPrivate::manage(TQWidget *widget) 00167 { 00168 if (!widget) 00169 { 00170 kdDebug(131) << "null pointer given to manage" << endl; 00171 return; 00172 } 00173 00174 if (dynamic_cast<TQPopupMenu*>(widget)) 00175 { 00176 // create a popup accel manager that can deal with dynamic menus 00177 KPopupAccelManager::manage(static_cast<TQPopupMenu*>(widget)); 00178 return; 00179 } 00180 00181 Item *root = new Item; 00182 00183 manageWidget(widget, root); 00184 00185 TQString used; 00186 calculateAccelerators(root, used); 00187 delete root; 00188 } 00189 00190 00191 void KAcceleratorManagerPrivate::calculateAccelerators(Item *item, TQString &used) 00192 { 00193 if (!item->m_children) 00194 return; 00195 00196 // collect the contents 00197 KAccelStringList contents; 00198 for (Item *it = item->m_children->first(); it != 0; 00199 it = item->m_children->next()) 00200 { 00201 contents << it->m_content; 00202 } 00203 00204 // find the right accelerators 00205 KAccelManagerAlgorithm::findAccelerators(contents, used); 00206 00207 // write them back into the widgets 00208 int cnt = -1; 00209 for (Item *it = item->m_children->first(); it != 0; 00210 it = item->m_children->next()) 00211 { 00212 cnt++; 00213 00214 TQTabBar *tabBar = dynamic_cast<TQTabBar*>(it->m_widget); 00215 if (tabBar) 00216 { 00217 if (checkChange(contents[cnt])) 00218 tabBar->tabAt(it->m_index)->setText(contents[cnt].accelerated()); 00219 continue; 00220 } 00221 TQMenuBar *menuBar = dynamic_cast<TQMenuBar*>(it->m_widget); 00222 if (menuBar) 00223 { 00224 if (it->m_index >= 0) 00225 { 00226 TQMenuItem *mitem = menuBar->findItem(menuBar->idAt(it->m_index)); 00227 if (mitem) 00228 { 00229 checkChange(contents[cnt]); 00230 mitem->setText(contents[cnt].accelerated()); 00231 } 00232 continue; 00233 } 00234 } 00235 // we possibly reserved an accel, but we won't set it as it looks silly 00236 if ( dynamic_cast<TQGroupBox*>( it->m_widget ) ) 00237 continue; 00238 // links look weird with ampersands 00239 if ( dynamic_cast<TQLabel*>( it->m_widget ) && it->m_widget->inherits("KURLLabel") ) 00240 continue; 00241 00242 int tprop = it->m_widget->metaObject()->findProperty("text", true); 00243 if (tprop != -1) { 00244 if (checkChange(contents[cnt])) 00245 it->m_widget->setProperty("text", contents[cnt].accelerated()); 00246 } else { 00247 tprop = it->m_widget->metaObject()->findProperty("title", true); 00248 if (tprop != -1 && checkChange(contents[cnt])) 00249 it->m_widget->setProperty("title", contents[cnt].accelerated()); 00250 } 00251 } 00252 00253 // calculate the accelerators for the children 00254 for (Item *it = item->m_children->first(); it != 0; 00255 it = item->m_children->next()) 00256 { 00257 if (it->m_widget && it->m_widget->isVisibleTo( item->m_widget ) ) 00258 calculateAccelerators(it, used); 00259 } 00260 } 00261 00262 00263 void KAcceleratorManagerPrivate::traverseChildren(TQWidget *widget, Item *item) 00264 { 00265 TQObjectList *childList = widget->queryList(TQWIDGET_OBJECT_NAME_STRING, 0, false, false); 00266 for ( TQObject *it = childList->first(); it; it = childList->next() ) 00267 { 00268 TQWidget *w = TQT_TQWIDGET(it); 00269 00270 if ( !w->isVisibleTo( widget ) || ( w->isTopLevel() && dynamic_cast<TQPopupMenu*>(w) == NULL ) ) 00271 continue; 00272 00273 if ( KAcceleratorManagerPrivate::ignored_widgets.find( w ) != KAcceleratorManagerPrivate::ignored_widgets.end() ) 00274 continue; 00275 00276 manageWidget(w, item); 00277 } 00278 delete childList; 00279 } 00280 00281 void KAcceleratorManagerPrivate::manageWidget(TQWidget *w, Item *item) 00282 { 00283 // first treat the special cases 00284 00285 TQTabBar *tabBar = dynamic_cast<TQTabBar*>(w); 00286 if (tabBar) 00287 { 00288 manageTabBar(tabBar, item); 00289 return; 00290 } 00291 00292 TQWidgetStack *wds = dynamic_cast<TQWidgetStack*>( w ); 00293 if ( wds ) 00294 { 00295 QWidgetStackAccelManager::manage( wds ); 00296 // return; 00297 } 00298 00299 TQPopupMenu *popupMenu = dynamic_cast<TQPopupMenu*>(w); 00300 if (popupMenu) 00301 { 00302 // create a popup accel manager that can deal with dynamic menus 00303 KPopupAccelManager::manage(popupMenu); 00304 return; 00305 } 00306 00307 TQWidgetStack *wdst = dynamic_cast<TQWidgetStack*>( w ); 00308 if ( wdst ) 00309 { 00310 QWidgetStackAccelManager::manage( wdst ); 00311 // return; 00312 } 00313 00314 TQMenuBar *menuBar = dynamic_cast<TQMenuBar*>(w); 00315 if (menuBar) 00316 { 00317 manageMenuBar(menuBar, item); 00318 return; 00319 } 00320 00321 if (dynamic_cast<TQComboBox*>(w) || dynamic_cast<TQLineEdit*>(w) || 00322 dynamic_cast<TQTextEdit*>(w) || dynamic_cast<TQTextView*>(w) || 00323 dynamic_cast<TQSpinBox*>(w) || w->qt_cast("KMultiTabBar")) 00324 return; 00325 00326 // now treat 'ordinary' widgets 00327 TQLabel *label = dynamic_cast<TQLabel*>(w); 00328 if ( label ) { 00329 if ( !label->buddy() ) 00330 label = 0; 00331 else { 00332 if ( label->textFormat() == Qt::RichText || 00333 ( label->textFormat() == Qt::AutoText && 00334 TQStyleSheet::mightBeRichText( label->text() ) ) ) 00335 label = 0; 00336 } 00337 } 00338 00339 if (w->isFocusEnabled() || label || dynamic_cast<TQGroupBox*>(w) || dynamic_cast<TQRadioButton*>( w )) 00340 { 00341 TQString content; 00342 TQVariant variant; 00343 int tprop = w->metaObject()->findProperty("text", true); 00344 if (tprop != -1) { 00345 const TQMetaProperty* p = w->metaObject()->property( tprop, true ); 00346 if ( p && p->isValid() ) 00347 w->qt_property( tprop, 1, &variant ); 00348 else 00349 tprop = -1; 00350 } 00351 00352 if (tprop == -1) { 00353 tprop = w->metaObject()->findProperty("title", true); 00354 if (tprop != -1) { 00355 const TQMetaProperty* p = w->metaObject()->property( tprop, true ); 00356 if ( p && p->isValid() ) 00357 w->qt_property( tprop, 1, &variant ); 00358 } 00359 } 00360 00361 if (variant.isValid()) 00362 content = variant.toString(); 00363 00364 if (!content.isEmpty()) 00365 { 00366 Item *i = new Item; 00367 i->m_widget = w; 00368 00369 // put some more weight on the usual action elements 00370 int weight = KAccelManagerAlgorithm::DEFAULT_WEIGHT; 00371 if (dynamic_cast<TQPushButton*>(w) || dynamic_cast<TQCheckBox*>(w) || dynamic_cast<TQRadioButton*>(w) || dynamic_cast<TQLabel*>(w)) 00372 weight = KAccelManagerAlgorithm::ACTION_ELEMENT_WEIGHT; 00373 00374 // don't put weight on group boxes, as usually the contents are more important 00375 if (dynamic_cast<TQGroupBox*>(w)) 00376 weight = KAccelManagerAlgorithm::GROUP_BOX_WEIGHT; 00377 00378 // put a lot of extra weight on the KDialogBaseButton's 00379 if (w->inherits("KDialogBaseButton")) 00380 weight += KAccelManagerAlgorithm::DIALOG_BUTTON_EXTRA_WEIGHT; 00381 00382 i->m_content = KAccelString(content, weight); 00383 item->addChild(i); 00384 } 00385 } 00386 traverseChildren(w, item); 00387 } 00388 00389 void KAcceleratorManagerPrivate::manageTabBar(TQTabBar *bar, Item *item) 00390 { 00391 for (int i=0; i<bar->count(); i++) 00392 { 00393 TQString content = bar->tabAt(i)->text(); 00394 if (content.isEmpty()) 00395 continue; 00396 00397 Item *it = new Item; 00398 item->addChild(it); 00399 it->m_widget = bar; 00400 it->m_index = i; 00401 it->m_content = KAccelString(content); 00402 } 00403 } 00404 00405 void KAcceleratorManagerPrivate::manageMenuBar(TQMenuBar *mbar, Item *item) 00406 { 00407 TQMenuItem *mitem; 00408 TQString s; 00409 00410 for (uint i=0; i<mbar->count(); ++i) 00411 { 00412 mitem = mbar->findItem(mbar->idAt(i)); 00413 if (!mitem) 00414 continue; 00415 00416 // nothing to do for separators 00417 if (mitem->isSeparator()) 00418 continue; 00419 00420 s = mitem->text(); 00421 if (!s.isEmpty()) 00422 { 00423 Item *it = new Item; 00424 item->addChild(it); 00425 it->m_content = 00426 KAccelString(s, 00427 // menu titles are important, so raise the weight 00428 KAccelManagerAlgorithm::MENU_TITLE_WEIGHT); 00429 00430 it->m_widget = mbar; 00431 it->m_index = i; 00432 } 00433 00434 // have a look at the popup as well, if present 00435 if (mitem->popup()) 00436 KPopupAccelManager::manage(mitem->popup()); 00437 } 00438 } 00439 00440 00441 /********************************************************************* 00442 00443 class KAcceleratorManager - main entry point 00444 00445 This class is just here to provide a clean public API... 00446 00447 *********************************************************************/ 00448 00449 void KAcceleratorManager::manage(TQWidget *widget) 00450 { 00451 KAcceleratorManager::manage(widget, false); 00452 } 00453 00454 void KAcceleratorManager::manage(TQWidget *widget, bool programmers_mode) 00455 { 00456 kdDebug(131) << "KAcceleratorManager::manage\n"; 00457 KAcceleratorManagerPrivate::changed_string = TQString::null; 00458 KAcceleratorManagerPrivate::added_string = TQString::null; 00459 KAcceleratorManagerPrivate::removed_string = TQString::null; 00460 KAcceleratorManagerPrivate::programmers_mode = programmers_mode; 00461 KAcceleratorManagerPrivate::manage(widget); 00462 } 00463 00464 void KAcceleratorManager::last_manage(TQString &added, TQString &changed, TQString &removed) 00465 { 00466 added = KAcceleratorManagerPrivate::added_string; 00467 changed = KAcceleratorManagerPrivate::changed_string; 00468 removed = KAcceleratorManagerPrivate::removed_string; 00469 } 00470 00471 00472 /********************************************************************* 00473 00474 class KAccelString - a string with weighted characters 00475 00476 *********************************************************************/ 00477 00478 KAccelString::KAccelString(const TQString &input, int initialWeight) 00479 : m_pureText(input), m_weight() 00480 { 00481 m_orig_accel = m_pureText.find("(!)&"); 00482 if (m_orig_accel != -1) 00483 m_pureText.remove(m_orig_accel, 4); 00484 00485 m_orig_accel = m_pureText.find("(&&)"); 00486 if (m_orig_accel != -1) 00487 m_pureText.replace(m_orig_accel, 4, "&"); 00488 00489 m_origText = m_pureText; 00490 00491 if (m_pureText.contains('\t')) 00492 m_pureText = m_pureText.left(m_pureText.find('\t')); 00493 00494 m_orig_accel = m_accel = stripAccelerator(m_pureText); 00495 00496 if (initialWeight == -1) 00497 initialWeight = KAccelManagerAlgorithm::DEFAULT_WEIGHT; 00498 00499 calculateWeights(initialWeight); 00500 00501 // dump(); 00502 } 00503 00504 00505 TQString KAccelString::accelerated() const 00506 { 00507 TQString result = m_origText; 00508 if (result.isEmpty()) 00509 return result; 00510 00511 if (KAcceleratorManagerPrivate::programmers_mode) 00512 { 00513 if (m_accel != m_orig_accel) { 00514 int oa = m_orig_accel; 00515 00516 if (m_accel >= 0) { 00517 result.insert(m_accel, "(!)&"); 00518 if (m_accel < m_orig_accel) 00519 oa += 4; 00520 } 00521 if (m_orig_accel >= 0) 00522 result.replace(oa, 1, "(&&)"); 00523 } 00524 } else { 00525 if (m_accel >= 0 && m_orig_accel != m_accel) { 00526 result.remove(m_orig_accel, 1); 00527 result.insert(m_accel, "&"); 00528 } 00529 } 00530 return result; 00531 } 00532 00533 00534 TQChar KAccelString::accelerator() const 00535 { 00536 if ((m_accel < 0) || (m_accel > (int)m_pureText.length())) 00537 return TQChar(); 00538 00539 return m_pureText[m_accel].lower(); 00540 } 00541 00542 00543 void KAccelString::calculateWeights(int initialWeight) 00544 { 00545 m_weight.resize(m_pureText.length()); 00546 00547 uint pos = 0; 00548 bool start_character = true; 00549 00550 while (pos<m_pureText.length()) 00551 { 00552 TQChar c = m_pureText[pos]; 00553 00554 int weight = initialWeight+1; 00555 00556 // add special weight to first character 00557 if (pos == 0) 00558 weight += KAccelManagerAlgorithm::FIRST_CHARACTER_EXTRA_WEIGHT; 00559 00560 // add weight to word beginnings 00561 if (start_character) 00562 { 00563 weight += KAccelManagerAlgorithm::WORD_BEGINNING_EXTRA_WEIGHT; 00564 start_character = false; 00565 } 00566 00567 // add decreasing weight to left characters 00568 if (pos < 50) 00569 weight += (50-pos); 00570 00571 // try to preserve the wanted accelarators 00572 if ((int)pos == accel()) { 00573 weight += KAccelManagerAlgorithm::WANTED_ACCEL_EXTRA_WEIGHT; 00574 // kdDebug(131) << "wanted " << m_pureText << " " << KAcceleratorManagerPrivate::standardName(m_origText) << endl; 00575 if (KAcceleratorManagerPrivate::standardName(m_origText)) { 00576 weight += KAccelManagerAlgorithm::STANDARD_ACCEL; 00577 } 00578 } 00579 00580 // skip non typeable characters 00581 if (!c.isLetterOrNumber()) 00582 { 00583 weight = 0; 00584 start_character = true; 00585 } 00586 00587 m_weight[pos] = weight; 00588 00589 ++pos; 00590 } 00591 } 00592 00593 00594 int KAccelString::stripAccelerator(TQString &text) 00595 { 00596 // Note: this code is derived from TQAccel::shortcutKey 00597 int p = 0; 00598 00599 while (p >= 0) 00600 { 00601 p = text.find('&', p)+1; 00602 00603 if (p <= 0 || p >= (int)text.length()) 00604 return -1; 00605 00606 if (text[p] != '&') 00607 { 00608 TQChar c = text[p]; 00609 if (c.isPrint()) 00610 { 00611 text.remove(p-1,1); 00612 return p-1; 00613 } 00614 } 00615 00616 p++; 00617 } 00618 00619 return -1; 00620 } 00621 00622 00623 int KAccelString::maxWeight(int &index, const TQString &used) 00624 { 00625 int max = 0; 00626 index = -1; 00627 00628 for (uint pos=0; pos<m_pureText.length(); ++pos) 00629 if (used.find(m_pureText[pos], 0, FALSE) == -1 && m_pureText[pos].latin1() != 0) 00630 if (m_weight[pos] > max) 00631 { 00632 max = m_weight[pos]; 00633 index = pos; 00634 } 00635 00636 return max; 00637 } 00638 00639 00640 void KAccelString::dump() 00641 { 00642 TQString s; 00643 for (uint i=0; i<m_weight.count(); ++i) 00644 s += TQString("%1(%2) ").arg(pure()[i]).arg(m_weight[i]); 00645 kdDebug() << "s " << s << endl; 00646 } 00647 00648 00649 /********************************************************************* 00650 00651 findAccelerators - the algorithm determining the new accelerators 00652 00653 The algorithm is very crude: 00654 00655 * each character in each widget text is assigned a weight 00656 * the character with the highest weight over all is picked 00657 * that widget is removed from the list 00658 * the weights are recalculated 00659 * the process is repeated until no more accelerators can be found 00660 00661 The algorithm has some advantages: 00662 00663 * it favors 'nice' accelerators (first characters in a word, etc.) 00664 * it is quite fast, O(N�) 00665 * it is easy to understand :-) 00666 00667 The disadvantages: 00668 00669 * it does not try to find as many accelerators as possible 00670 00671 TODO: 00672 00673 * The result is always correct, but not neccesarily optimal. Perhaps 00674 it would be a good idea to add another algorithm with higher complexity 00675 that gets used when this one fails, i.e. leaves widgets without 00676 accelerators. 00677 00678 * The weights probably need some tweaking so they make more sense. 00679 00680 *********************************************************************/ 00681 00682 void KAccelManagerAlgorithm::findAccelerators(KAccelStringList &result, TQString &used) 00683 { 00684 kdDebug(131) << "findAccelerators\n"; 00685 KAccelStringList accel_strings = result; 00686 00687 // initally remove all accelerators 00688 for (KAccelStringList::Iterator it = result.begin(); it != result.end(); ++it) { 00689 (*it).setAccel(-1); 00690 } 00691 00692 // pick the highest bids 00693 for (uint cnt=0; cnt<accel_strings.count(); ++cnt) 00694 { 00695 int max = 0, index = -1, accel = -1; 00696 00697 // find maximum weight 00698 for (uint i=0; i<accel_strings.count(); ++i) 00699 { 00700 int a; 00701 int m = accel_strings[i].maxWeight(a, used); 00702 if (m>max) 00703 { 00704 max = m; 00705 index = i; 00706 accel = a; 00707 } 00708 } 00709 00710 // stop if no more accelerators can be found 00711 if (index < 0) 00712 return; 00713 00714 // insert the accelerator 00715 if (accel >= 0) 00716 { 00717 result[index].setAccel(accel); 00718 used.append(result[index].accelerator()); 00719 } 00720 00721 // make sure we don't visit this one again 00722 accel_strings[index] = KAccelString(); 00723 } 00724 } 00725 00726 00727 /********************************************************************* 00728 00729 class KPopupAccelManager - managing TQPopupMenu widgets dynamically 00730 00731 *********************************************************************/ 00732 00733 KPopupAccelManager::KPopupAccelManager(TQPopupMenu *popup) 00734 : TQObject(popup), m_popup(popup), m_count(-1) 00735 { 00736 aboutToShow(); // do one check and then connect to show 00737 connect(popup, TQT_SIGNAL(aboutToShow()), TQT_SLOT(aboutToShow())); 00738 } 00739 00740 00741 void KPopupAccelManager::aboutToShow() 00742 { 00743 // Note: we try to be smart and avoid recalculating the accelerators 00744 // whenever possible. Unfortunately, there is no way to know if an 00745 // item has been added or removed, so we can not do much more than 00746 // to compare the items each time the menu is shown :-( 00747 00748 if (m_count != (int)m_popup->count()) 00749 { 00750 findMenuEntries(m_entries); 00751 calculateAccelerators(); 00752 m_count = m_popup->count(); 00753 } 00754 else 00755 { 00756 KAccelStringList entries; 00757 findMenuEntries(entries); 00758 if (entries != m_entries) 00759 { 00760 m_entries = entries; 00761 calculateAccelerators(); 00762 } 00763 } 00764 } 00765 00766 00767 void KPopupAccelManager::calculateAccelerators() 00768 { 00769 // find the new accelerators 00770 TQString used; 00771 KAccelManagerAlgorithm::findAccelerators(m_entries, used); 00772 00773 // change the menu entries 00774 setMenuEntries(m_entries); 00775 } 00776 00777 00778 void KPopupAccelManager::findMenuEntries(KAccelStringList &list) 00779 { 00780 TQMenuItem *mitem; 00781 TQString s; 00782 00783 list.clear(); 00784 00785 // read out the menu entries 00786 for (uint i=0; i<m_popup->count(); i++) 00787 { 00788 mitem = m_popup->findItem(m_popup->idAt(i)); 00789 if (mitem->isSeparator()) 00790 continue; 00791 00792 s = mitem->text(); 00793 00794 // in full menus, look at entries with global accelerators last 00795 int weight = 50; 00796 if (s.contains('\t')) 00797 weight = 0; 00798 00799 list.append(KAccelString(s, weight)); 00800 00801 // have a look at the popup as well, if present 00802 if (mitem->popup()) 00803 KPopupAccelManager::manage(mitem->popup()); 00804 } 00805 } 00806 00807 00808 void KPopupAccelManager::setMenuEntries(const KAccelStringList &list) 00809 { 00810 TQMenuItem *mitem; 00811 00812 uint cnt = 0; 00813 for (uint i=0; i<m_popup->count(); i++) 00814 { 00815 mitem = m_popup->findItem(m_popup->idAt(i)); 00816 if (mitem->isSeparator()) 00817 continue; 00818 00819 if (KAcceleratorManagerPrivate::checkChange(list[cnt])) 00820 mitem->setText(list[cnt].accelerated()); 00821 cnt++; 00822 } 00823 } 00824 00825 00826 void KPopupAccelManager::manage(TQPopupMenu *popup) 00827 { 00828 // don't add more than one manager to a popup 00829 if (popup->child(0, "KPopupAccelManager", false) == 0 ) 00830 new KPopupAccelManager(popup); 00831 } 00832 00833 void QWidgetStackAccelManager::manage( TQWidgetStack *stack ) 00834 { 00835 if ( stack->child( 0, "QWidgetStackAccelManager", false ) == 0 ) 00836 new QWidgetStackAccelManager( stack ); 00837 } 00838 00839 QWidgetStackAccelManager::QWidgetStackAccelManager(TQWidgetStack *stack) 00840 : TQObject(stack), m_stack(stack) 00841 { 00842 aboutToShow(stack->visibleWidget()); // do one check and then connect to show 00843 connect(stack, TQT_SIGNAL(aboutToShow(TQWidget *)), TQT_SLOT(aboutToShow(TQWidget *))); 00844 } 00845 00846 bool QWidgetStackAccelManager::eventFilter ( TQObject * watched, TQEvent * e ) 00847 { 00848 if ( e->type() == TQEvent::Show && tqApp->activeWindow() ) { 00849 KAcceleratorManager::manage( TQT_TQWIDGET(tqApp->activeWindow()) ); 00850 watched->removeEventFilter( this ); 00851 } 00852 return false; 00853 } 00854 00855 void QWidgetStackAccelManager::aboutToShow(TQWidget *child) 00856 { 00857 if (!child) 00858 { 00859 kdDebug(131) << "null pointer given to aboutToShow" << endl; 00860 return; 00861 } 00862 00863 child->installEventFilter( this ); 00864 } 00865 00866 void KAcceleratorManager::setNoAccel( TQWidget *widget ) 00867 { 00868 KAcceleratorManagerPrivate::ignored_widgets[widget] = 1; 00869 } 00870 00871 #include "kaccelmanager_private.moc"