kdecore Library API Documentation

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., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #include "kaccelmanager.h" 00021 00022 #include <qapplication.h> 00023 #include <qcheckbox.h> 00024 #include <qcombobox.h> 00025 #include <qgroupbox.h> 00026 #include <qlabel.h> 00027 #include <qlineedit.h> 00028 #include <qmenubar.h> 00029 #include <qmemarray.h> 00030 #include <qmetaobject.h> 00031 #include <qmainwindow.h> 00032 #include <qobjectlist.h> 00033 #include <qpopupmenu.h> 00034 #include <qptrlist.h> 00035 #include <qpushbutton.h> 00036 #include <qradiobutton.h> 00037 #include <qspinbox.h> 00038 #include <qtabbar.h> 00039 #include <qtextview.h> 00040 #include <qwidget.h> 00041 #include <qwidgetstack.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(QWidget *widget); 00078 static bool programmers_mode; 00079 static bool standardName(const QString &str); 00080 00081 static bool checkChange(const KAccelString &as) { 00082 QString t2 = as.accelerated(); 00083 QString t1 = as.originalText(); 00084 if (t1 != t2) 00085 { 00086 if (as.accel() == -1) { 00087 removed_string += "<tr><td>" + QStyleSheet::escape(t1) + "</td></tr>"; 00088 } else if (as.originalAccel() == -1) { 00089 added_string += "<tr><td>" + QStyleSheet::escape(t2) + "</td></tr>"; 00090 } else { 00091 changed_string += "<tr><td>" + QStyleSheet::escape(t1) + "</td>"; 00092 changed_string += "<td>" + QStyleSheet::escape(t2) + "</td></tr>"; 00093 } 00094 return true; 00095 } 00096 return false; 00097 } 00098 static QString changed_string; 00099 static QString added_string; 00100 static QString removed_string; 00101 static QMap<QWidget *, int> ignored_widgets; 00102 00103 private: 00104 class Item; 00105 public: 00106 typedef QPtrList<Item> ItemList; 00107 00108 private: 00109 static void traverseChildren(QWidget *widget, Item *item); 00110 00111 static void manageWidget(QWidget *widget, Item *item); 00112 static void manageMenuBar(QMenuBar *mbar, Item *item); 00113 static void manageTabBar(QTabBar *bar, Item *item); 00114 00115 static void calculateAccelerators(Item *item, QString &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 QWidget *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 QString KAcceleratorManagerPrivate::changed_string; 00137 QString KAcceleratorManagerPrivate::added_string; 00138 QString KAcceleratorManagerPrivate::removed_string; 00139 static QStringList *kaccmp_sns = 0; 00140 static KStaticDeleter<QStringList> kaccmp_sns_d; 00141 QMap<QWidget*, int> KAcceleratorManagerPrivate::ignored_widgets; 00142 00143 bool KAcceleratorManagerPrivate::standardName(const QString &str) 00144 { 00145 if (!kaccmp_sns) 00146 kaccmp_sns_d.setObject(kaccmp_sns, new QStringList(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(QWidget *widget) 00167 { 00168 if (!widget) 00169 { 00170 kdDebug(125) << "null pointer given to manage" << endl; 00171 return; 00172 } 00173 00174 if (dynamic_cast<QPopupMenu*>(widget)) 00175 { 00176 // create a popup accel manager that can deal with dynamic menus 00177 KPopupAccelManager::manage(static_cast<QPopupMenu*>(widget)); 00178 return; 00179 } 00180 00181 Item *root = new Item; 00182 00183 manageWidget(widget, root); 00184 00185 QString used; 00186 calculateAccelerators(root, used); 00187 delete root; 00188 } 00189 00190 00191 void KAcceleratorManagerPrivate::calculateAccelerators(Item *item, QString &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 QTabBar *tabBar = dynamic_cast<QTabBar*>(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 QMenuBar *menuBar = dynamic_cast<QMenuBar*>(it->m_widget); 00222 if (menuBar) 00223 { 00224 if (it->m_index >= 0) 00225 { 00226 QMenuItem *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<QGroupBox*>( it->m_widget ) ) 00237 continue; 00238 00239 kdDebug(125) << "write " << cnt << " " << it->m_widget->className() << " " <<contents[cnt].accelerated() << endl; 00240 00241 int tprop = it->m_widget->metaObject()->findProperty("text", true); 00242 if (tprop != -1) { 00243 if (checkChange(contents[cnt])) 00244 it->m_widget->setProperty("text", contents[cnt].accelerated()); 00245 } else { 00246 tprop = it->m_widget->metaObject()->findProperty("title", true); 00247 if (tprop != -1 && checkChange(contents[cnt])) 00248 it->m_widget->setProperty("title", contents[cnt].accelerated()); 00249 } 00250 } 00251 00252 // calculate the accelerators for the children 00253 for (Item *it = item->m_children->first(); it != 0; 00254 it = item->m_children->next()) 00255 { 00256 kdDebug(125) << "children " << it->m_widget->className() << endl; 00257 if (it->m_widget && it->m_widget->isVisibleTo( item->m_widget ) ) 00258 calculateAccelerators(it, used); 00259 } 00260 } 00261 00262 00263 void KAcceleratorManagerPrivate::traverseChildren(QWidget *widget, Item *item) 00264 { 00265 QObjectList *childList = widget->queryList("QWidget", 0, false, false); 00266 for ( QObject *it = childList->first(); it; it = childList->next() ) 00267 { 00268 QWidget *w = static_cast<QWidget*>(it); 00269 00270 if ( !w->isVisibleTo( widget ) || w->isTopLevel() ) 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(QWidget *w, Item *item) 00282 { 00283 // first treat the special cases 00284 00285 QTabBar *tabBar = dynamic_cast<QTabBar*>(w); 00286 if (tabBar) 00287 { 00288 manageTabBar(tabBar, item); 00289 return; 00290 } 00291 00292 QWidgetStack *wds = dynamic_cast<QWidgetStack*>( w ); 00293 if ( wds ) 00294 { 00295 QWidgetStackAccelManager::manage( wds ); 00296 // return; 00297 } 00298 00299 QPopupMenu *popupMenu = dynamic_cast<QPopupMenu*>(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 QWidgetStack *wdst = dynamic_cast<QWidgetStack*>( w ); 00308 if ( wdst ) 00309 { 00310 QWidgetStackAccelManager::manage( wdst ); 00311 // return; 00312 } 00313 00314 QMenuBar *menuBar = dynamic_cast<QMenuBar*>(w); 00315 if (menuBar) 00316 { 00317 manageMenuBar(menuBar, item); 00318 return; 00319 } 00320 00321 if (dynamic_cast<QComboBox*>(w) || dynamic_cast<QLineEdit*>(w) || 00322 dynamic_cast<QTextEdit*>(w) || dynamic_cast<QTextView*>(w) || 00323 dynamic_cast<QSpinBox*>(w) || w->qt_cast( "KMultiTabBar" )) 00324 return; 00325 00326 // now treat 'ordinary' widgets 00327 QLabel *label = dynamic_cast<QLabel*>(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 QStyleSheet::mightBeRichText( label->text() ) ) ) 00335 label = 0; 00336 } 00337 } 00338 00339 if (w->isFocusEnabled() || label || dynamic_cast<QGroupBox*>(w) || dynamic_cast<QRadioButton*>( w )) 00340 { 00341 QString content; 00342 QVariant variant; 00343 int tprop = w->metaObject()->findProperty("text", true); 00344 if (tprop != -1) { 00345 const QMetaProperty* 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 QMetaProperty* 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<QPushButton*>(w) || dynamic_cast<QCheckBox*>(w) || dynamic_cast<QRadioButton*>(w) || dynamic_cast<QLabel*>(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<QGroupBox*>(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(QTabBar *bar, Item *item) 00390 { 00391 for (int i=0; i<bar->count(); i++) 00392 { 00393 QString 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(QMenuBar *mbar, Item *item) 00406 { 00407 QMenuItem *mitem; 00408 QString 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(QWidget *widget) 00450 { 00451 KAcceleratorManager::manage(widget, false); 00452 } 00453 00454 void KAcceleratorManager::manage(QWidget *widget, bool programmers_mode) 00455 { 00456 kdDebug(125) << "KAcceleratorManager::manage\n"; 00457 KAcceleratorManagerPrivate::changed_string = QString::null; 00458 KAcceleratorManagerPrivate::added_string = QString::null; 00459 KAcceleratorManagerPrivate::removed_string = QString::null; 00460 KAcceleratorManagerPrivate::programmers_mode = programmers_mode; 00461 KAcceleratorManagerPrivate::manage(widget); 00462 } 00463 00464 void KAcceleratorManager::last_manage(QString &added, QString &changed, QString &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 QString &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 kdDebug(125) << input << " " << m_orig_accel << " " << m_accel << " " << m_pureText << endl; 00497 if (initialWeight == -1) 00498 initialWeight = KAccelManagerAlgorithm::DEFAULT_WEIGHT; 00499 00500 calculateWeights(initialWeight); 00501 00502 // dump(); 00503 } 00504 00505 00506 QString KAccelString::accelerated() const 00507 { 00508 QString result = m_origText; 00509 if (result.isEmpty()) 00510 return result; 00511 00512 if (KAcceleratorManagerPrivate::programmers_mode) 00513 { 00514 if (m_accel != m_orig_accel) { 00515 int oa = m_orig_accel; 00516 00517 if (m_accel >= 0) { 00518 result.insert(m_accel, "(!)&"); 00519 if (m_accel < m_orig_accel) 00520 oa += 4; 00521 } 00522 if (m_orig_accel >= 0) 00523 result.replace(oa, 1, "(&&)"); 00524 } 00525 } else { 00526 if (m_accel >= 0 && m_orig_accel != m_accel) { 00527 result.remove(m_orig_accel, 1); 00528 result.insert(m_accel, "&"); 00529 } 00530 } 00531 return result; 00532 } 00533 00534 00535 QChar KAccelString::accelerator() const 00536 { 00537 if ((m_accel < 0) || (m_accel > (int)m_pureText.length())) 00538 return QChar(); 00539 00540 return m_pureText[m_accel].lower(); 00541 } 00542 00543 00544 void KAccelString::calculateWeights(int initialWeight) 00545 { 00546 m_weight.resize(m_pureText.length()); 00547 00548 uint pos = 0; 00549 bool start_character = true; 00550 00551 while (pos<m_pureText.length()) 00552 { 00553 QChar c = m_pureText[pos]; 00554 00555 int weight = initialWeight+1; 00556 00557 // add special weight to first character 00558 if (pos == 0) 00559 weight += KAccelManagerAlgorithm::FIRST_CHARACTER_EXTRA_WEIGHT; 00560 00561 // add weight to word beginnings 00562 if (start_character) 00563 { 00564 weight += KAccelManagerAlgorithm::WORD_BEGINNING_EXTRA_WEIGHT; 00565 start_character = false; 00566 } 00567 00568 // add decreasing weight to left characters 00569 if (pos < 50) 00570 weight += (50-pos); 00571 00572 // try to preserve the wanted accelarators 00573 if ((int)pos == accel()) { 00574 weight += KAccelManagerAlgorithm::WANTED_ACCEL_EXTRA_WEIGHT; 00575 // kdDebug(125) << "wanted " << m_pureText << " " << KAcceleratorManagerPrivate::standardName(m_origText) << endl; 00576 if (KAcceleratorManagerPrivate::standardName(m_origText)) { 00577 weight += KAccelManagerAlgorithm::STANDARD_ACCEL; 00578 } 00579 } 00580 00581 // skip non typeable characters 00582 if (!c.isLetterOrNumber()) 00583 { 00584 weight = 0; 00585 start_character = true; 00586 } 00587 00588 m_weight[pos] = weight; 00589 00590 ++pos; 00591 } 00592 } 00593 00594 00595 int KAccelString::stripAccelerator(QString &text) 00596 { 00597 // Note: this code is derived from QAccel::shortcutKey 00598 int p = 0; 00599 00600 while (p >= 0) 00601 { 00602 p = text.find('&', p)+1; 00603 00604 if (p <= 0 || p >= (int)text.length()) 00605 return -1; 00606 00607 if (text[p] != '&') 00608 { 00609 QChar c = text[p]; 00610 if (c.isPrint()) 00611 { 00612 text.remove(p-1,1); 00613 return p-1; 00614 } 00615 } 00616 00617 p++; 00618 } 00619 00620 return -1; 00621 } 00622 00623 00624 int KAccelString::maxWeight(int &index, const QString &used) 00625 { 00626 int max = 0; 00627 index = -1; 00628 00629 for (uint pos=0; pos<m_pureText.length(); ++pos) 00630 if (used.find(m_pureText[pos], 0, FALSE) == -1 && m_pureText[pos].latin1() != 0) 00631 if (m_weight[pos] > max) 00632 { 00633 max = m_weight[pos]; 00634 index = pos; 00635 } 00636 00637 return max; 00638 } 00639 00640 00641 void KAccelString::dump() 00642 { 00643 QString s; 00644 for (uint i=0; i<m_weight.count(); ++i) 00645 s += QString("%1(%2) ").arg(pure()[i]).arg(m_weight[i]); 00646 kdDebug() << "s " << s << endl; 00647 } 00648 00649 00650 /********************************************************************* 00651 00652 findAccelerators - the algorithm determining the new accelerators 00653 00654 The algorithm is very crude: 00655 00656 * each character in each widget text is assigned a weight 00657 * the character with the highest weight over all is picked 00658 * that widget is removed from the list 00659 * the weights are recalculated 00660 * the process is repeated until no more accelerators can be found 00661 00662 The algorithm has some advantages: 00663 00664 * it favors 'nice' accelerators (first characters in a word, etc.) 00665 * it is quite fast, O(N²) 00666 * it is easy to understand :-) 00667 00668 The disadvantages: 00669 00670 * it does not try to find as many accelerators as possible 00671 00672 TODO: 00673 00674 * The result is always correct, but not neccesarily optimal. Perhaps 00675 it would be a good idea to add another algorithm with higher complexity 00676 that gets used when this one fails, i.e. leaves widgets without 00677 accelerators. 00678 00679 * The weights probably need some tweaking so they make more sense. 00680 00681 *********************************************************************/ 00682 00683 void KAccelManagerAlgorithm::findAccelerators(KAccelStringList &result, QString &used) 00684 { 00685 kdDebug(125) << "findAccelerators\n"; 00686 KAccelStringList accel_strings = result; 00687 00688 // initally remove all accelerators 00689 for (KAccelStringList::Iterator it = result.begin(); it != result.end(); ++it) { 00690 kdDebug(125) << "reset " << ( *it ).pure() << endl; 00691 (*it).setAccel(-1); 00692 } 00693 00694 // pick the highest bids 00695 for (uint cnt=0; cnt<accel_strings.count(); ++cnt) 00696 { 00697 kdDebug(125) << "cnt " << accel_strings[cnt].pure() << endl; 00698 int max = 0, index = -1, accel = -1; 00699 00700 // find maximum weight 00701 for (uint i=0; i<accel_strings.count(); ++i) 00702 { 00703 int a; 00704 int m = accel_strings[i].maxWeight(a, used); 00705 if (m>max) 00706 { 00707 max = m; 00708 index = i; 00709 accel = a; 00710 } 00711 } 00712 00713 // stop if no more accelerators can be found 00714 if (index < 0) 00715 return; 00716 00717 // insert the accelerator 00718 if (accel >= 0) 00719 { 00720 result[index].setAccel(accel); 00721 used.append(result[index].accelerator()); 00722 } 00723 00724 // make sure we don't visit this one again 00725 accel_strings[index] = KAccelString(); 00726 } 00727 } 00728 00729 00730 /********************************************************************* 00731 00732 class KPopupAccelManager - managing QPopupMenu widgets dynamically 00733 00734 *********************************************************************/ 00735 00736 KPopupAccelManager::KPopupAccelManager(QPopupMenu *popup) 00737 : QObject(popup), m_popup(popup), m_count(-1) 00738 { 00739 aboutToShow(); // do one check and then connect to show 00740 connect(popup, SIGNAL(aboutToShow()), SLOT(aboutToShow())); 00741 } 00742 00743 00744 void KPopupAccelManager::aboutToShow() 00745 { 00746 // Note: we try to be smart and avoid recalculating the accelerators 00747 // whenever possible. Unfortunately, there is no way to know if an 00748 // item has been added or removed, so we can not do much more than 00749 // to compare the items each time the menu is shown :-( 00750 00751 if (m_count != (int)m_popup->count()) 00752 { 00753 findMenuEntries(m_entries); 00754 calculateAccelerators(); 00755 m_count = m_popup->count(); 00756 } 00757 else 00758 { 00759 KAccelStringList entries; 00760 findMenuEntries(entries); 00761 if (entries != m_entries) 00762 { 00763 m_entries = entries; 00764 calculateAccelerators(); 00765 } 00766 } 00767 } 00768 00769 00770 void KPopupAccelManager::calculateAccelerators() 00771 { 00772 // find the new accelerators 00773 QString used; 00774 KAccelManagerAlgorithm::findAccelerators(m_entries, used); 00775 00776 // change the menu entries 00777 setMenuEntries(m_entries); 00778 } 00779 00780 00781 void KPopupAccelManager::findMenuEntries(KAccelStringList &list) 00782 { 00783 QMenuItem *mitem; 00784 QString s; 00785 00786 list.clear(); 00787 00788 // read out the menu entries 00789 for (uint i=0; i<m_popup->count(); i++) 00790 { 00791 mitem = m_popup->findItem(m_popup->idAt(i)); 00792 if (mitem->isSeparator()) 00793 continue; 00794 00795 s = mitem->text(); 00796 00797 // in full menus, look at entries with global accelerators last 00798 int weight = 50; 00799 if (s.contains('\t')) 00800 weight = 0; 00801 00802 list.append(KAccelString(s, weight)); 00803 00804 // have a look at the popup as well, if present 00805 if (mitem->popup()) 00806 KPopupAccelManager::manage(mitem->popup()); 00807 } 00808 } 00809 00810 00811 void KPopupAccelManager::setMenuEntries(const KAccelStringList &list) 00812 { 00813 QMenuItem *mitem; 00814 00815 uint cnt = 0; 00816 for (uint i=0; i<m_popup->count(); i++) 00817 { 00818 mitem = m_popup->findItem(m_popup->idAt(i)); 00819 if (mitem->isSeparator()) 00820 continue; 00821 00822 if (KAcceleratorManagerPrivate::checkChange(list[cnt])) 00823 mitem->setText(list[cnt].accelerated()); 00824 cnt++; 00825 } 00826 } 00827 00828 00829 void KPopupAccelManager::manage(QPopupMenu *popup) 00830 { 00831 // don't add more than one manager to a popup 00832 if (popup->child(0, "KPopupAccelManager", false) == 0 ) 00833 new KPopupAccelManager(popup); 00834 } 00835 00836 void QWidgetStackAccelManager::manage( QWidgetStack *stack ) 00837 { 00838 if ( stack->child( 0, "QWidgetStackAccelManager", false ) == 0 ) 00839 new QWidgetStackAccelManager( stack ); 00840 } 00841 00842 QWidgetStackAccelManager::QWidgetStackAccelManager(QWidgetStack *stack) 00843 : QObject(stack), m_stack(stack) 00844 { 00845 aboutToShow(stack->visibleWidget()); // do one check and then connect to show 00846 connect(stack, SIGNAL(aboutToShow(QWidget *)), SLOT(aboutToShow(QWidget *))); 00847 } 00848 00849 bool QWidgetStackAccelManager::eventFilter ( QObject * watched, QEvent * e ) 00850 { 00851 if ( e->type() == QEvent::Show && qApp->activeWindow() ) { 00852 KAcceleratorManager::manage( qApp->activeWindow() ); 00853 watched->removeEventFilter( this ); 00854 } 00855 return false; 00856 } 00857 00858 void QWidgetStackAccelManager::aboutToShow(QWidget *child) 00859 { 00860 if (!child) 00861 { 00862 kdDebug(125) << "null pointer given to aboutToShow" << endl; 00863 return; 00864 } 00865 00866 child->installEventFilter( this ); 00867 } 00868 00869 void KAcceleratorManager::setNoAccel( QWidget *widget ) 00870 { 00871 KAcceleratorManagerPrivate::ignored_widgets[widget] = 1; 00872 } 00873 00874 #include "kaccelmanager_private.moc"
KDE Logo
This file is part of the documentation for kdecore Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 12 22:47:29 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003