• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

kaccelmanager.cpp

Go to the documentation of this file.
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 <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(131) << "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         // links look weird with ampersands
00239         if ( dynamic_cast<QLabel*>( 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(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() && dynamic_cast<QPopupMenu*>(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(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(131) << "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     if (initialWeight == -1)
00497         initialWeight = KAccelManagerAlgorithm::DEFAULT_WEIGHT;
00498 
00499     calculateWeights(initialWeight);
00500 
00501     // dump();
00502 }
00503 
00504 
00505 QString KAccelString::accelerated() const
00506 {
00507   QString 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 QChar KAccelString::accelerator() const
00535 {
00536   if ((m_accel < 0) || (m_accel > (int)m_pureText.length()))
00537     return QChar();
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     QChar 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(QString &text)
00595 {
00596   // Note: this code is derived from QAccel::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       QChar 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 QString &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   QString s;
00643   for (uint i=0; i<m_weight.count(); ++i)
00644     s += QString("%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, QString &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 QPopupMenu widgets dynamically
00730 
00731  *********************************************************************/
00732 
00733 KPopupAccelManager::KPopupAccelManager(QPopupMenu *popup)
00734   : QObject(popup), m_popup(popup), m_count(-1)
00735 {
00736     aboutToShow(); // do one check and then connect to show
00737     connect(popup, SIGNAL(aboutToShow()), 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   QString 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   QMenuItem *mitem;
00781   QString 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   QMenuItem *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(QPopupMenu *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( QWidgetStack *stack )
00834 {
00835     if ( stack->child( 0, "QWidgetStackAccelManager", false ) == 0 )
00836         new QWidgetStackAccelManager( stack );
00837 }
00838 
00839 QWidgetStackAccelManager::QWidgetStackAccelManager(QWidgetStack *stack)
00840   : QObject(stack), m_stack(stack)
00841 {
00842     aboutToShow(stack->visibleWidget()); // do one check and then connect to show
00843     connect(stack, SIGNAL(aboutToShow(QWidget *)), SLOT(aboutToShow(QWidget *)));
00844 }
00845 
00846 bool QWidgetStackAccelManager::eventFilter ( QObject * watched, QEvent * e )
00847 {
00848     if ( e->type() == QEvent::Show && qApp->activeWindow() ) {
00849         KAcceleratorManager::manage( qApp->activeWindow() );
00850         watched->removeEventFilter( this );
00851     }
00852     return false;
00853 }
00854 
00855 void QWidgetStackAccelManager::aboutToShow(QWidget *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( QWidget *widget )
00867 {
00868     KAcceleratorManagerPrivate::ignored_widgets[widget] = 1;
00869 }
00870 
00871 #include "kaccelmanager_private.moc"

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal