kdecore Library: kaccelmanager.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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"

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:00 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003