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

KDEUI

kacceleratormanager.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 "kacceleratormanager.h"
00021 
00022 #include <QtGui/QApplication>
00023 #include <QtGui/QCheckBox>
00024 #include <QtGui/QComboBox>
00025 #include <QtGui/QGroupBox>
00026 #include <QtGui/QLabel>
00027 #include <QtGui/QLineEdit>
00028 #include <QtGui/QMenuBar>
00029 #include <QtGui/qmenudata.h>
00030 #include <QtCore/QMetaClassInfo>
00031 #include <QtCore/QObject>
00032 #include <QList>
00033 #include <QtGui/QPushButton>
00034 #include <QtGui/QRadioButton>
00035 #include <QtGui/QDoubleSpinBox>
00036 #include <QtGui/QTabBar>
00037 #include <QtGui/QTextEdit>
00038 #include <QtGui/QWidget>
00039 #include <QStackedWidget>
00040 #include <QDockWidget>
00041 #include <QTextDocument>
00042 
00043 #include <kstandardaction.h>
00044 #include <kdebug.h>
00045 #include <kdeversion.h>
00046 #include <kglobal.h>
00047 
00048 #include "kacceleratormanager_private.h"
00049 #include <kstandardaction_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>" + Qt::escape(t1) + "</td></tr>";
00088             } else if (as.originalAccel() == -1) {
00089                 added_string += "<tr><td>" + Qt::escape(t2) + "</td></tr>";
00090             } else {
00091                 changed_string += "<tr><td>" + Qt::escape(t1) + "</td>";
00092                 changed_string += "<td>" + Qt::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 QList<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   static void manageDockWidget(QDockWidget *dock, Item *item);
00115 
00116   static void calculateAccelerators(Item *item, QString &used);
00117 
00118   class Item
00119   {
00120   public:
00121 
00122     Item() : m_widget(0), m_children(0), m_index(-1) {}
00123     ~Item();
00124 
00125     void addChild(Item *item);
00126 
00127     QWidget       *m_widget;
00128     KAccelString  m_content;
00129     ItemList      *m_children;
00130     int           m_index;
00131 
00132   };
00133 };
00134 
00135 
00136 bool KAcceleratorManagerPrivate::programmers_mode = false;
00137 QString KAcceleratorManagerPrivate::changed_string;
00138 QString KAcceleratorManagerPrivate::added_string;
00139 QString KAcceleratorManagerPrivate::removed_string;
00140 K_GLOBAL_STATIC_WITH_ARGS(QStringList, kaccmp_sns, (KStandardAction::internal_stdNames()))
00141 QMap<QWidget*, int> KAcceleratorManagerPrivate::ignored_widgets;
00142 
00143 bool KAcceleratorManagerPrivate::standardName(const QString &str)
00144 {
00145     return kaccmp_sns->contains(str);
00146 }
00147 
00148 KAcceleratorManagerPrivate::Item::~Item()
00149 {
00150     if (m_children)
00151         while (!m_children->isEmpty())
00152             delete m_children->takeFirst();
00153 
00154     delete m_children;
00155 }
00156 
00157 
00158 void KAcceleratorManagerPrivate::Item::addChild(Item *item)
00159 {
00160     if (!m_children) {
00161         m_children = new ItemList;
00162     }
00163 
00164     m_children->append(item);
00165 }
00166 
00167 void KAcceleratorManagerPrivate::manage(QWidget *widget)
00168 {
00169     if (!widget)
00170     {
00171         kDebug(131) << "null pointer given to manage";
00172         return;
00173     }
00174 
00175     if (qobject_cast<QMenu*>(widget))
00176     {
00177         // create a popup accel manager that can deal with dynamic menus
00178         KPopupAccelManager::manage(static_cast<QMenu*>(widget));
00179         return;
00180     }
00181 
00182     Item *root = new Item;
00183 
00184     manageWidget(widget, root);
00185 
00186     QString used;
00187     calculateAccelerators(root, used);
00188     delete root;
00189 }
00190 
00191 
00192 void KAcceleratorManagerPrivate::calculateAccelerators(Item *item, QString &used)
00193 {
00194     if (!item->m_children)
00195         return;
00196 
00197     // collect the contents
00198     KAccelStringList contents;
00199     foreach(Item *it, *item->m_children)
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     foreach(Item *it, *item->m_children)
00210     {
00211         cnt++;
00212 
00213         QDockWidget *dock = qobject_cast<QDockWidget*>(it->m_widget);
00214         if (dock)
00215         {
00216             if (checkChange(contents[cnt]))
00217                 dock->setWindowTitle(contents[cnt].accelerated());
00218             continue;
00219         }
00220         QTabBar *tabBar = qobject_cast<QTabBar*>(it->m_widget);
00221         if (tabBar)
00222         {
00223             if (checkChange(contents[cnt]))
00224                 tabBar->setTabText(it->m_index, contents[cnt].accelerated());
00225             continue;
00226         }
00227         QMenuBar *menuBar = qobject_cast<QMenuBar*>(it->m_widget);
00228         if (menuBar)
00229         {
00230             if (it->m_index >= 0)
00231             {
00232                 QAction *maction = menuBar->actions()[it->m_index];
00233                 if (maction)
00234                 {
00235                     checkChange(contents[cnt]);
00236                     maction->setText(contents[cnt].accelerated());
00237                 }
00238                 continue;
00239             }
00240         }
00241         // we possibly reserved an accel, but we won't set it as it looks silly
00242         if ( qobject_cast<QGroupBox*>( it->m_widget ) )
00243              continue;
00244 
00245         int tprop = it->m_widget->metaObject()->indexOfProperty("text");
00246         if (tprop != -1)  {
00247             if (checkChange(contents[cnt]))
00248                 it->m_widget->setProperty("text", contents[cnt].accelerated());
00249         } else {
00250             tprop = it->m_widget->metaObject()->indexOfProperty("title");
00251             if (tprop != -1 && checkChange(contents[cnt]))
00252                 it->m_widget->setProperty("title", contents[cnt].accelerated());
00253         }
00254     }
00255 
00256     // calculate the accelerators for the children
00257     foreach(Item *it, *item->m_children)
00258     {
00259         if (it->m_widget && it->m_widget->isVisibleTo( item->m_widget ) )
00260             calculateAccelerators(it, used);
00261     }
00262 }
00263 
00264 
00265 void KAcceleratorManagerPrivate::traverseChildren(QWidget *widget, Item *item)
00266 {
00267   QList<QWidget*> childList = widget->findChildren<QWidget*>();
00268   foreach ( QWidget *w , childList ) {
00269     // Ignore unless we have the direct parent
00270     if(qobject_cast<QWidget *>(w->parent()) != widget) continue;
00271 
00272     if ( !w->isVisibleTo( widget ) || (w->isTopLevel() && qobject_cast<QMenu*>(w) == NULL) )
00273         continue;
00274 
00275     if ( KAcceleratorManagerPrivate::ignored_widgets.contains( w ) )
00276         continue;
00277 
00278     manageWidget(w, item);
00279   }
00280 }
00281 
00282 void KAcceleratorManagerPrivate::manageWidget(QWidget *w, Item *item)
00283 {
00284   // first treat the special cases
00285 
00286   QTabBar *tabBar = qobject_cast<QTabBar*>(w);
00287   if (tabBar)
00288   {
00289       manageTabBar(tabBar, item);
00290       return;
00291   }
00292 
00293   QStackedWidget *wds = qobject_cast<QStackedWidget*>( w );
00294   if ( wds )
00295   {
00296       QWidgetStackAccelManager::manage( wds );
00297       // return;
00298   }
00299 
00300   QDockWidget *dock = qobject_cast<QDockWidget*>( w );
00301   if ( dock )
00302   {
00303       //QWidgetStackAccelManager::manage( wds );
00304       manageDockWidget(dock, item);
00305   }
00306 
00307 
00308   QMenu *popupMenu = qobject_cast<QMenu*>(w);
00309   if (popupMenu)
00310   {
00311       // create a popup accel manager that can deal with dynamic menus
00312       KPopupAccelManager::manage(popupMenu);
00313       return;
00314   }
00315 
00316   QStackedWidget *wdst = qobject_cast<QStackedWidget*>( w );
00317   if ( wdst )
00318   {
00319       QWidgetStackAccelManager::manage( wdst );
00320       // return;
00321   }
00322 
00323   QMenuBar *menuBar = qobject_cast<QMenuBar*>(w);
00324   if (menuBar)
00325   {
00326       manageMenuBar(menuBar, item);
00327       return;
00328   }
00329 
00330   if (qobject_cast<QComboBox*>(w) || qobject_cast<QLineEdit*>(w) ||
00331       w->inherits("Q3TextEdit") ||
00332       qobject_cast<QTextEdit*>(w) ||
00333       qobject_cast<QAbstractSpinBox*>(w) || w->inherits( "KMultiTabBar" ) )
00334       return;
00335 
00336   // now treat 'ordinary' widgets
00337   QLabel *label =  qobject_cast<QLabel*>(w);
00338   if ( label  ) {
00339       if ( !label->buddy() )
00340           return;
00341       else {
00342           if ( label->textFormat() == Qt::RichText ||
00343                ( label->textFormat() == Qt::AutoText &&
00344                  Qt::mightBeRichText( label->text() ) ) )
00345               return;
00346       }
00347   }
00348 
00349   if (w->focusPolicy() != Qt::NoFocus || label || qobject_cast<QGroupBox*>(w) || qobject_cast<QRadioButton*>( w ))
00350   {
00351     QString content;
00352     QVariant variant;
00353     int tprop = w->metaObject()->indexOfProperty("text");
00354     if (tprop != -1)  {
00355         QMetaProperty p = w->metaObject()->property( tprop );
00356         if ( p.isValid() )
00357             variant = p.read (w);
00358         else
00359             tprop = -1;
00360     }
00361 
00362     if (tprop == -1)  {
00363         tprop = w->metaObject()->indexOfProperty("title");
00364         if (tprop != -1)  {
00365             QMetaProperty p = w->metaObject()->property( tprop );
00366             if ( p.isValid() )
00367                 variant = p.read (w);
00368         }
00369     }
00370 
00371     if (variant.isValid())
00372         content = variant.toString();
00373 
00374     if (!content.isEmpty())
00375     {
00376         Item *i = new Item;
00377         i->m_widget = w;
00378 
00379         // put some more weight on the usual action elements
00380         int weight = KAccelManagerAlgorithm::DEFAULT_WEIGHT;
00381         if (qobject_cast<QPushButton*>(w) || qobject_cast<QCheckBox*>(w) || qobject_cast<QRadioButton*>(w) || qobject_cast<QLabel*>(w))
00382             weight = KAccelManagerAlgorithm::ACTION_ELEMENT_WEIGHT;
00383 
00384         // don't put weight on group boxes, as usually the contents are more important
00385         if (qobject_cast<QGroupBox*>(w))
00386             weight = KAccelManagerAlgorithm::GROUP_BOX_WEIGHT;
00387         i->m_content = KAccelString(content, weight);
00388         item->addChild(i);
00389     }
00390   }
00391   traverseChildren(w, item);
00392 }
00393 
00394 void KAcceleratorManagerPrivate::manageTabBar(QTabBar *bar, Item *item)
00395 {
00396   for (int i=0; i<bar->count(); i++)
00397   {
00398     QString content = bar->tabText(i);
00399     if (content.isEmpty())
00400       continue;
00401 
00402     Item *it = new Item;
00403     item->addChild(it);
00404     it->m_widget = bar;
00405     it->m_index = i;
00406     it->m_content = KAccelString(content);
00407   }
00408 }
00409 
00410 void KAcceleratorManagerPrivate::manageDockWidget(QDockWidget *dock, Item *item)
00411 {
00412     QString content = dock->windowTitle();
00413     if (content.isEmpty())
00414         return;
00415 
00416     Item *it = new Item;
00417     item->addChild(it);
00418     it->m_widget = dock;
00419     it->m_content = KAccelString(content);
00420 }
00421 
00422 
00423 void KAcceleratorManagerPrivate::manageMenuBar(QMenuBar *mbar, Item *item)
00424 {
00425     QAction *maction;
00426     QString s;
00427 
00428     for (int i=0; i<mbar->actions().count(); ++i)
00429     {
00430         maction = mbar->actions()[i];
00431         if (!maction)
00432             continue;
00433 
00434         // nothing to do for separators
00435         if (maction->isSeparator())
00436             continue;
00437 
00438         s = maction->text();
00439         if (!s.isEmpty())
00440         {
00441             Item *it = new Item;
00442             item->addChild(it);
00443             it->m_content =
00444                 KAccelString(s,
00445                              // menu titles are important, so raise the weight
00446                              KAccelManagerAlgorithm::MENU_TITLE_WEIGHT);
00447 
00448             it->m_widget = mbar;
00449             it->m_index = i;
00450         }
00451 
00452         // have a look at the popup as well, if present
00453         if (maction->menu())
00454             KPopupAccelManager::manage(maction->menu());
00455     }
00456 }
00457 
00458 
00459 /*********************************************************************
00460 
00461  class KAcceleratorManager - main entry point
00462 
00463  This class is just here to provide a clean public API...
00464 
00465  *********************************************************************/
00466 
00467 void KAcceleratorManager::manage(QWidget *widget, bool programmers_mode)
00468 {
00469     KAcceleratorManagerPrivate::changed_string.clear();
00470     KAcceleratorManagerPrivate::added_string.clear();
00471     KAcceleratorManagerPrivate::removed_string.clear();
00472     KAcceleratorManagerPrivate::programmers_mode = programmers_mode;
00473     KAcceleratorManagerPrivate::manage(widget);
00474 }
00475 
00476 void KAcceleratorManager::last_manage(QString &added,  QString &changed, QString &removed)
00477 {
00478     added = KAcceleratorManagerPrivate::added_string;
00479     changed = KAcceleratorManagerPrivate::changed_string;
00480     removed = KAcceleratorManagerPrivate::removed_string;
00481 }
00482 
00483 
00484 /*********************************************************************
00485 
00486  class KAccelString - a string with weighted characters
00487 
00488  *********************************************************************/
00489 
00490 KAccelString::KAccelString(const QString &input, int initialWeight)
00491   : m_pureText(input), m_weight()
00492 {
00493     m_orig_accel = m_pureText.indexOf("(!)&");
00494     if (m_orig_accel != -1)
00495     m_pureText.remove(m_orig_accel, 4);
00496 
00497     m_orig_accel = m_pureText.indexOf("(&&)");
00498     if (m_orig_accel != -1)
00499         m_pureText.replace(m_orig_accel, 4, "&");
00500 
00501     m_origText = m_pureText;
00502 
00503     if (m_pureText.contains('\t'))
00504         m_pureText = m_pureText.left(m_pureText.indexOf('\t'));
00505 
00506     m_orig_accel = m_accel = stripAccelerator(m_pureText);
00507 
00508     if (initialWeight == -1)
00509         initialWeight = KAccelManagerAlgorithm::DEFAULT_WEIGHT;
00510 
00511     calculateWeights(initialWeight);
00512 
00513     // dump();
00514 }
00515 
00516 
00517 QString KAccelString::accelerated() const
00518 {
00519   QString result = m_origText;
00520   if (result.isEmpty())
00521       return result;
00522 
00523   if (KAcceleratorManagerPrivate::programmers_mode)
00524   {
00525     if (m_accel != m_orig_accel) {
00526       int oa = m_orig_accel;
00527 
00528       if (m_accel >= 0) {
00529               result.insert(m_accel, "(!)&");
00530               if (m_accel < m_orig_accel)
00531                   oa += 4;
00532       }
00533       if (m_orig_accel >= 0)
00534       result.replace(oa, 1, "(&&)");
00535     }
00536   } else {
00537       if (m_accel >= 0 && m_orig_accel != m_accel) {
00538           if (m_orig_accel != -1)
00539               result.remove(m_orig_accel, 1);
00540           result.insert(m_accel, "&");
00541       }
00542   }
00543   return result;
00544 }
00545 
00546 
00547 QChar KAccelString::accelerator() const
00548 {
00549   if ((m_accel < 0) || (m_accel > (int)m_pureText.length()))
00550     return QChar();
00551 
00552   return m_pureText[m_accel].toLower();
00553 }
00554 
00555 
00556 void KAccelString::calculateWeights(int initialWeight)
00557 {
00558   m_weight.resize(m_pureText.length());
00559 
00560   int pos = 0;
00561   bool start_character = true;
00562 
00563   while (pos<m_pureText.length())
00564   {
00565     QChar c = m_pureText[pos];
00566 
00567     int weight = initialWeight+1;
00568 
00569     // add special weight to first character
00570     if (pos == 0)
00571       weight += KAccelManagerAlgorithm::FIRST_CHARACTER_EXTRA_WEIGHT;
00572 
00573     // add weight to word beginnings
00574     if (start_character)
00575     {
00576       weight += KAccelManagerAlgorithm::WORD_BEGINNING_EXTRA_WEIGHT;
00577       start_character = false;
00578     }
00579 
00580     // add decreasing weight to left characters
00581     if (pos < 50)
00582       weight += (50-pos);
00583 
00584     // try to preserve the wanted accelarators
00585     if ((int)pos == accel()) {
00586         weight += KAccelManagerAlgorithm::WANTED_ACCEL_EXTRA_WEIGHT;
00587         // kDebug(131) << "wanted " << m_pureText << " " << KAcceleratorManagerPrivate::standardName(m_origText);
00588         if (KAcceleratorManagerPrivate::standardName(m_origText))  {
00589             weight += KAccelManagerAlgorithm::STANDARD_ACCEL;
00590         }
00591     }
00592 
00593     // skip non typeable characters
00594     if (!c.isLetterOrNumber())
00595     {
00596       weight = 0;
00597       start_character = true;
00598     }
00599 
00600     m_weight[pos] = weight;
00601 
00602     ++pos;
00603   }
00604 }
00605 
00606 
00607 int KAccelString::stripAccelerator(QString &text)
00608 {
00609   // Note: this code is derived from QAccel::shortcutKey
00610   int p = 0;
00611 
00612   while (p >= 0)
00613   {
00614     p = text.indexOf('&', p)+1;
00615 
00616     if (p <= 0 || p >= (int)text.length())
00617       return -1;
00618 
00619     if (text[p] != '&')
00620     {
00621       QChar c = text[p];
00622       if (c.isPrint())
00623       {
00624         text.remove(p-1,1);
00625     return p-1;
00626       }
00627     }
00628 
00629     p++;
00630   }
00631 
00632   return -1;
00633 }
00634 
00635 
00636 int KAccelString::maxWeight(int &index, const QString &used) const
00637 {
00638   int max = 0;
00639   index = -1;
00640 
00641   for (int pos=0; pos<m_pureText.length(); ++pos)
00642     if (used.indexOf(m_pureText[pos], 0, Qt::CaseInsensitive) == -1 && m_pureText[pos].toLatin1() != 0)
00643       if (m_weight[pos] > max)
00644       {
00645         max = m_weight[pos];
00646     index = pos;
00647       }
00648 
00649   return max;
00650 }
00651 
00652 
00653 void KAccelString::dump()
00654 {
00655   QString s;
00656   for (int i=0; i<m_weight.count(); ++i)
00657     s += QString("%1(%2) ").arg(pure()[i]).arg(m_weight[i]);
00658   kDebug() << "s " << s;
00659 }
00660 
00661 
00662 /*********************************************************************
00663 
00664  findAccelerators - the algorithm determining the new accelerators
00665 
00666  The algorithm is very crude:
00667 
00668    * each character in each widget text is assigned a weight
00669    * the character with the highest weight over all is picked
00670    * that widget is removed from the list
00671    * the weights are recalculated
00672    * the process is repeated until no more accelerators can be found
00673 
00674  The algorithm has some advantages:
00675 
00676    * it favors 'nice' accelerators (first characters in a word, etc.)
00677    * it is quite fast, O(N²)
00678    * it is easy to understand :-)
00679 
00680  The disadvantages:
00681 
00682    * it does not try to find as many accelerators as possible
00683 
00684  TODO:
00685 
00686  * The result is always correct, but not neccesarily optimal. Perhaps
00687    it would be a good idea to add another algorithm with higher complexity
00688    that gets used when this one fails, i.e. leaves widgets without
00689    accelerators.
00690 
00691  * The weights probably need some tweaking so they make more sense.
00692 
00693  *********************************************************************/
00694 
00695 void KAccelManagerAlgorithm::findAccelerators(KAccelStringList &result, QString &used)
00696 {
00697   KAccelStringList accel_strings = result;
00698 
00699   // initally remove all accelerators
00700   for (KAccelStringList::Iterator it = result.begin(); it != result.end(); ++it) {
00701     (*it).setAccel(-1);
00702   }
00703 
00704   // pick the highest bids
00705   for (int cnt=0; cnt<accel_strings.count(); ++cnt)
00706   {
00707     int max = 0, index = -1, accel = -1;
00708 
00709     // find maximum weight
00710     for (int i=0; i<accel_strings.count(); ++i)
00711     {
00712       int a;
00713       int m = accel_strings[i].maxWeight(a, used);
00714       if (m>max)
00715       {
00716         max = m;
00717         index = i;
00718         accel = a;
00719       }
00720     }
00721 
00722     // stop if no more accelerators can be found
00723     if (index < 0)
00724       return;
00725 
00726     // insert the accelerator
00727     if (accel >= 0)
00728     {
00729       result[index].setAccel(accel);
00730       used.append(result[index].accelerator());
00731     }
00732 
00733     // make sure we don't visit this one again
00734     accel_strings[index] = KAccelString();
00735   }
00736 }
00737 
00738 
00739 /*********************************************************************
00740 
00741  class KPopupAccelManager - managing QPopupMenu widgets dynamically
00742 
00743  *********************************************************************/
00744 
00745 KPopupAccelManager::KPopupAccelManager(QMenu *popup)
00746   : QObject(popup), m_popup(popup), m_count(-1)
00747 {
00748     aboutToShow(); // do one check and then connect to show
00749     connect(popup, SIGNAL(aboutToShow()), SLOT(aboutToShow()));
00750 }
00751 
00752 
00753 void KPopupAccelManager::aboutToShow()
00754 {
00755   // Note: we try to be smart and avoid recalculating the accelerators
00756   // whenever possible. Unfortunately, there is no way to know if an
00757  // item has been added or removed, so we can not do much more than
00758   // to compare the items each time the menu is shown :-(
00759 
00760   if (m_count != (int)m_popup->actions().count())
00761   {
00762     findMenuEntries(m_entries);
00763     calculateAccelerators();
00764     m_count = m_popup->actions().count();
00765   }
00766   else
00767   {
00768     KAccelStringList entries;
00769     findMenuEntries(entries);
00770     if (entries != m_entries)
00771     {
00772       m_entries = entries;
00773       calculateAccelerators();
00774     }
00775   }
00776 }
00777 
00778 
00779 void KPopupAccelManager::calculateAccelerators()
00780 {
00781   // find the new accelerators
00782   QString used;
00783   KAccelManagerAlgorithm::findAccelerators(m_entries, used);
00784 
00785   // change the menu entries
00786   setMenuEntries(m_entries);
00787 }
00788 
00789 
00790 void KPopupAccelManager::findMenuEntries(KAccelStringList &list)
00791 {
00792   QAction *maction;
00793   QString s;
00794 
00795   list.clear();
00796 
00797   // read out the menu entries
00798   for (int i=0; i<m_popup->actions().count(); i++)
00799   {
00800     maction = m_popup->actions()[i];
00801     if (maction->isSeparator())
00802       continue;
00803 
00804     s = maction->text();
00805 
00806     // in full menus, look at entries with global accelerators last
00807     int weight = 50;
00808     if (s.contains('\t'))
00809         weight = 0;
00810 
00811     list.append(KAccelString(s, weight));
00812 
00813     // have a look at the popup as well, if present
00814     if (maction->menu())
00815         KPopupAccelManager::manage(maction->menu());
00816   }
00817 }
00818 
00819 
00820 void KPopupAccelManager::setMenuEntries(const KAccelStringList &list)
00821 {
00822   QAction *maction;
00823 
00824   uint cnt = 0;
00825   for (int i=0; i<m_popup->actions().count(); i++)
00826   {
00827     maction = m_popup->actions()[i];
00828     if (maction->isSeparator())
00829       continue;
00830 
00831     if (KAcceleratorManagerPrivate::checkChange(list[cnt]))
00832         maction->setText(list[cnt].accelerated());
00833     cnt++;
00834   }
00835 }
00836 
00837 
00838 void KPopupAccelManager::manage(QMenu *popup)
00839 {
00840   // don't add more than one manager to a popup
00841   if (popup->findChild<KPopupAccelManager*>(QString()) == 0 )
00842     new KPopupAccelManager(popup);
00843 }
00844 
00845 void QWidgetStackAccelManager::manage( QStackedWidget *stack )
00846 {
00847     if ( stack->findChild<QWidgetStackAccelManager*>(QString()) == 0 )
00848         new QWidgetStackAccelManager( stack );
00849 }
00850 
00851 QWidgetStackAccelManager::QWidgetStackAccelManager(QStackedWidget *stack)
00852   : QObject(stack), m_stack(stack)
00853 {
00854     currentChanged(stack->currentIndex()); // do one check and then connect to show
00855     connect(stack, SIGNAL(currentChanged(int)), SLOT(currentChanged(int)));
00856 }
00857 
00858 bool QWidgetStackAccelManager::eventFilter ( QObject * watched, QEvent * e )
00859 {
00860     if ( e->type() == QEvent::Show && qApp->activeWindow() ) {
00861         KAcceleratorManager::manage( qApp->activeWindow() );
00862         watched->removeEventFilter( this );
00863     }
00864     return false;
00865 }
00866 
00867 void QWidgetStackAccelManager::currentChanged(int child)
00868 {
00869     if (child < 0 || child >= static_cast<QStackedWidget*>(parent())->count())
00870     {
00871         kDebug(131) << "invalid index provided";
00872         return;
00873     }
00874 
00875     static_cast<QStackedWidget*>(parent())->widget(child)->installEventFilter( this );
00876 }
00877 
00878 void KAcceleratorManager::setNoAccel( QWidget *widget )
00879 {
00880     KAcceleratorManagerPrivate::ignored_widgets[widget] = 1;
00881 }
00882 
00883 #include "kacceleratormanager_private.moc"

KDEUI

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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