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

KDEUI

  • sources
  • kde-4.12
  • kdelibs
  • kdeui
  • shortcuts
kacceleratormanager.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE project
2  Copyright (C) 2002 Matthias Hölzer-Klüpfel <mhk@kde.org>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 #include "kacceleratormanager.h"
21 
22 #include <QtGui/QApplication>
23 #include <QtGui/QMainWindow>
24 #include <QtGui/QCheckBox>
25 #include <QtGui/QComboBox>
26 #include <QtGui/QGroupBox>
27 #include <QtGui/QLabel>
28 #include <QtGui/QLineEdit>
29 #include <QtGui/QMenuBar>
30 #include <QtGui/qmenudata.h>
31 #include <QtCore/QMetaClassInfo>
32 #include <QtCore/QObject>
33 #include <QList>
34 #include <QtGui/QPushButton>
35 #include <QtGui/QRadioButton>
36 #include <QtGui/QDoubleSpinBox>
37 #include <QtGui/QTabBar>
38 #include <QtGui/QTextEdit>
39 #include <QtGui/QWidget>
40 #include <QStackedWidget>
41 #include <QDockWidget>
42 #include <QTextDocument>
43 
44 #include <kstandardaction.h>
45 #include <kdebug.h>
46 #include <kdeversion.h>
47 #include <kglobal.h>
48 
49 #include "kacceleratormanager_private.h"
50 #include <kstandardaction_p.h>
51 
52 
53 /*********************************************************************
54 
55  class Item - helper class containing widget information
56 
57  This class stores information about the widgets the need accelerators,
58  as well as about their relationship.
59 
60  *********************************************************************/
61 
62 
63 
64 /*********************************************************************
65 
66  class KAcceleratorManagerPrivate - internal helper class
67 
68  This class does all the work to find accelerators for a hierarchy of
69  widgets.
70 
71  *********************************************************************/
72 
73 
74 class KAcceleratorManagerPrivate
75 {
76 public:
77 
78  static void manage(QWidget *widget);
79  static bool programmers_mode;
80  static bool standardName(const QString &str);
81 
82  static bool checkChange(const KAccelString &as) {
83  QString t2 = as.accelerated();
84  QString t1 = as.originalText();
85  if (t1 != t2)
86  {
87  if (as.accel() == -1) {
88  removed_string += "<tr><td>" + Qt::escape(t1) + "</td></tr>";
89  } else if (as.originalAccel() == -1) {
90  added_string += "<tr><td>" + Qt::escape(t2) + "</td></tr>";
91  } else {
92  changed_string += "<tr><td>" + Qt::escape(t1) + "</td>";
93  changed_string += "<td>" + Qt::escape(t2) + "</td></tr>";
94  }
95  return true;
96  }
97  return false;
98  }
99  static QString changed_string;
100  static QString added_string;
101  static QString removed_string;
102  static QMap<QWidget *, int> ignored_widgets;
103 
104 private:
105  class Item;
106 public:
107  typedef QList<Item *> ItemList;
108 
109 private:
110  static void traverseChildren(QWidget *widget, Item *item);
111 
112  static void manageWidget(QWidget *widget, Item *item);
113  static void manageMenuBar(QMenuBar *mbar, Item *item);
114  static void manageTabBar(QTabBar *bar, Item *item);
115  static void manageDockWidget(QDockWidget *dock, Item *item);
116 
117  static void calculateAccelerators(Item *item, QString &used);
118 
119  class Item
120  {
121  public:
122 
123  Item() : m_widget(0), m_children(0), m_index(-1) {}
124  ~Item();
125 
126  void addChild(Item *item);
127 
128  QWidget *m_widget;
129  KAccelString m_content;
130  ItemList *m_children;
131  int m_index;
132 
133  };
134 };
135 
136 
137 bool KAcceleratorManagerPrivate::programmers_mode = false;
138 QString KAcceleratorManagerPrivate::changed_string;
139 QString KAcceleratorManagerPrivate::added_string;
140 QString KAcceleratorManagerPrivate::removed_string;
141 K_GLOBAL_STATIC_WITH_ARGS(QStringList, kaccmp_sns, (KStandardAction::internal_stdNames()))
142 QMap<QWidget*, int> KAcceleratorManagerPrivate::ignored_widgets;
143 
144 bool KAcceleratorManagerPrivate::standardName(const QString &str)
145 {
146  return kaccmp_sns->contains(str);
147 }
148 
149 KAcceleratorManagerPrivate::Item::~Item()
150 {
151  if (m_children)
152  while (!m_children->isEmpty())
153  delete m_children->takeFirst();
154 
155  delete m_children;
156 }
157 
158 
159 void KAcceleratorManagerPrivate::Item::addChild(Item *item)
160 {
161  if (!m_children) {
162  m_children = new ItemList;
163  }
164 
165  m_children->append(item);
166 }
167 
168 void KAcceleratorManagerPrivate::manage(QWidget *widget)
169 {
170  if (!widget)
171  {
172  kDebug(240) << "null pointer given to manage";
173  return;
174  }
175 
176  if (KAcceleratorManagerPrivate::ignored_widgets.contains(widget)) {
177  return;
178  }
179 
180  if (qobject_cast<QMenu*>(widget))
181  {
182  // create a popup accel manager that can deal with dynamic menus
183  KPopupAccelManager::manage(static_cast<QMenu*>(widget));
184  return;
185  }
186 
187  Item *root = new Item;
188 
189  manageWidget(widget, root);
190 
191  QString used;
192  calculateAccelerators(root, used);
193  delete root;
194 }
195 
196 
197 void KAcceleratorManagerPrivate::calculateAccelerators(Item *item, QString &used)
198 {
199  if (!item->m_children)
200  return;
201 
202  // collect the contents
203  KAccelStringList contents;
204  foreach(Item *it, *item->m_children)
205  {
206  contents << it->m_content;
207  }
208 
209  // find the right accelerators
210  KAccelManagerAlgorithm::findAccelerators(contents, used);
211 
212  // write them back into the widgets
213  int cnt = -1;
214  foreach(Item *it, *item->m_children)
215  {
216  cnt++;
217 
218  QDockWidget *dock = qobject_cast<QDockWidget*>(it->m_widget);
219  if (dock)
220  {
221  if (checkChange(contents[cnt]))
222  dock->setWindowTitle(contents[cnt].accelerated());
223  continue;
224  }
225  QTabBar *tabBar = qobject_cast<QTabBar*>(it->m_widget);
226  if (tabBar)
227  {
228  if (checkChange(contents[cnt]))
229  tabBar->setTabText(it->m_index, contents[cnt].accelerated());
230  continue;
231  }
232  QMenuBar *menuBar = qobject_cast<QMenuBar*>(it->m_widget);
233  if (menuBar)
234  {
235  if (it->m_index >= 0)
236  {
237  QAction *maction = menuBar->actions()[it->m_index];
238  if (maction)
239  {
240  checkChange(contents[cnt]);
241  maction->setText(contents[cnt].accelerated());
242  }
243  continue;
244  }
245  }
246 
247  // we possibly reserved an accel, but we won't set it as it looks silly
248  QGroupBox *groupBox = qobject_cast<QGroupBox*>(it->m_widget);
249  if (groupBox && !groupBox->isCheckable())
250  continue;
251 
252  int tprop = it->m_widget->metaObject()->indexOfProperty("text");
253  if (tprop != -1) {
254  if (checkChange(contents[cnt]))
255  it->m_widget->setProperty("text", contents[cnt].accelerated());
256  } else {
257  tprop = it->m_widget->metaObject()->indexOfProperty("title");
258  if (tprop != -1 && checkChange(contents[cnt]))
259  it->m_widget->setProperty("title", contents[cnt].accelerated());
260  }
261  }
262 
263  // calculate the accelerators for the children
264  foreach(Item *it, *item->m_children)
265  {
266  if (it->m_widget && it->m_widget->isVisibleTo( item->m_widget ) )
267  calculateAccelerators(it, used);
268  }
269 }
270 
271 
272 void KAcceleratorManagerPrivate::traverseChildren(QWidget *widget, Item *item)
273 {
274  QList<QWidget*> childList = widget->findChildren<QWidget*>();
275  foreach ( QWidget *w , childList ) {
276  // Ignore unless we have the direct parent
277  if(qobject_cast<QWidget *>(w->parent()) != widget) continue;
278 
279  if ( !w->isVisibleTo( widget ) || (w->isTopLevel() && qobject_cast<QMenu*>(w) == NULL) )
280  continue;
281 
282  if ( KAcceleratorManagerPrivate::ignored_widgets.contains( w ) )
283  continue;
284 
285  manageWidget(w, item);
286  }
287 }
288 
289 void KAcceleratorManagerPrivate::manageWidget(QWidget *w, Item *item)
290 {
291  // first treat the special cases
292 
293  QTabBar *tabBar = qobject_cast<QTabBar*>(w);
294  if (tabBar)
295  {
296  manageTabBar(tabBar, item);
297  return;
298  }
299 
300  QStackedWidget *wds = qobject_cast<QStackedWidget*>( w );
301  if ( wds )
302  {
303  QWidgetStackAccelManager::manage( wds );
304  // return;
305  }
306 
307  QDockWidget *dock = qobject_cast<QDockWidget*>( w );
308  if ( dock )
309  {
310  //QWidgetStackAccelManager::manage( wds );
311  manageDockWidget(dock, item);
312  }
313 
314 
315  QMenu *popupMenu = qobject_cast<QMenu*>(w);
316  if (popupMenu)
317  {
318  // create a popup accel manager that can deal with dynamic menus
319  KPopupAccelManager::manage(popupMenu);
320  return;
321  }
322 
323  QStackedWidget *wdst = qobject_cast<QStackedWidget*>( w );
324  if ( wdst )
325  {
326  QWidgetStackAccelManager::manage( wdst );
327  // return;
328  }
329 
330  QMenuBar *menuBar = qobject_cast<QMenuBar*>(w);
331  if (menuBar)
332  {
333  manageMenuBar(menuBar, item);
334  return;
335  }
336 
337  if (qobject_cast<QComboBox*>(w) || qobject_cast<QLineEdit*>(w) ||
338  w->inherits("Q3TextEdit") ||
339  qobject_cast<QTextEdit*>(w) ||
340  qobject_cast<QAbstractSpinBox*>(w) || w->inherits( "KMultiTabBar" ) )
341  return;
342 
343  if ( w->inherits("KUrlRequester") ) {
344  traverseChildren(w, item);
345  return;
346  }
347 
348  // now treat 'ordinary' widgets
349  QLabel *label = qobject_cast<QLabel*>(w);
350  if ( label ) {
351  if ( !label->buddy() )
352  return;
353  else {
354  if ( label->textFormat() == Qt::RichText ||
355  ( label->textFormat() == Qt::AutoText &&
356  Qt::mightBeRichText( label->text() ) ) )
357  return;
358  }
359  }
360 
361  if (w->focusPolicy() != Qt::NoFocus || label || qobject_cast<QGroupBox*>(w) || qobject_cast<QRadioButton*>( w ))
362  {
363  QString content;
364  QVariant variant;
365  int tprop = w->metaObject()->indexOfProperty("text");
366  if (tprop != -1) {
367  QMetaProperty p = w->metaObject()->property( tprop );
368  if ( p.isValid() && p.isWritable() )
369  variant = p.read (w);
370  else
371  tprop = -1;
372  }
373 
374  if (tprop == -1) {
375  tprop = w->metaObject()->indexOfProperty("title");
376  if (tprop != -1) {
377  QMetaProperty p = w->metaObject()->property( tprop );
378  if ( p.isValid() && p.isWritable() )
379  variant = p.read (w);
380  }
381  }
382 
383  if (variant.isValid())
384  content = variant.toString();
385 
386  if (!content.isEmpty())
387  {
388  Item *i = new Item;
389  i->m_widget = w;
390 
391  // put some more weight on the usual action elements
392  int weight = KAccelManagerAlgorithm::DEFAULT_WEIGHT;
393  if (qobject_cast<QPushButton*>(w) || qobject_cast<QCheckBox*>(w) || qobject_cast<QRadioButton*>(w) || qobject_cast<QLabel*>(w))
394  weight = KAccelManagerAlgorithm::ACTION_ELEMENT_WEIGHT;
395 
396  // don't put weight on non-checkable group boxes,
397  // as usually the contents are more important
398  QGroupBox *groupBox = qobject_cast<QGroupBox*>(w);
399  if (groupBox)
400  {
401  if (groupBox->isCheckable())
402  weight = KAccelManagerAlgorithm::CHECKABLE_GROUP_BOX_WEIGHT;
403  else
404  weight = KAccelManagerAlgorithm::GROUP_BOX_WEIGHT;
405  }
406 
407  i->m_content = KAccelString(content, weight);
408  item->addChild(i);
409  }
410  }
411  traverseChildren(w, item);
412 }
413 
414 void KAcceleratorManagerPrivate::manageTabBar(QTabBar *bar, Item *item)
415 {
416  // ignore QTabBar for QDockWidgets, because QDockWidget on its title change
417  // also updates its tabbar entry, so on the next run of KCheckAccelerators
418  // this looks like a conflict and triggers a new reset of the shortcuts -> endless loop
419  QWidget* parentWidget = bar->parentWidget();
420  if( parentWidget )
421  {
422  QMainWindow* mainWindow = qobject_cast<QMainWindow*>(parentWidget);
423  // TODO: find better hints that this is a QTabBar for QDockWidgets
424  if( mainWindow ) // && (mainWindow->layout()->indexOf(bar) != -1)) QMainWindowLayout lacks proper support
425  return;
426  }
427 
428  for (int i=0; i<bar->count(); i++)
429  {
430  QString content = bar->tabText(i);
431  if (content.isEmpty())
432  continue;
433 
434  Item *it = new Item;
435  item->addChild(it);
436  it->m_widget = bar;
437  it->m_index = i;
438  it->m_content = KAccelString(content);
439  }
440 }
441 
442 void KAcceleratorManagerPrivate::manageDockWidget(QDockWidget *dock, Item *item)
443 {
444  // As of Qt 4.4.3 setting a shortcut to a QDockWidget has no effect,
445  // because a QDockWidget does not grab it, even while displaying an underscore
446  // in the title for the given shortcut letter.
447  // Still it is useful to set the shortcut, because if QDockWidgets are tabbed,
448  // the tab automatically gets the same text as the QDockWidget title, including the shortcut.
449  // And for the QTabBar the shortcut does work, it gets grabbed as usual.
450  // Having the QDockWidget without a shortcut and resetting the tab text with a title including
451  // the shortcut does not work, the tab text is instantly reverted to the QDockWidget title
452  // (see also manageTabBar()).
453  // All in all QDockWidgets and shortcuts are a little broken for now.
454  QString content = dock->windowTitle();
455  if (content.isEmpty())
456  return;
457 
458  Item *it = new Item;
459  item->addChild(it);
460  it->m_widget = dock;
461  it->m_content = KAccelString(content, KAccelManagerAlgorithm::STANDARD_ACCEL);
462 }
463 
464 
465 void KAcceleratorManagerPrivate::manageMenuBar(QMenuBar *mbar, Item *item)
466 {
467  QAction *maction;
468  QString s;
469 
470  for (int i=0; i<mbar->actions().count(); ++i)
471  {
472  maction = mbar->actions()[i];
473  if (!maction)
474  continue;
475 
476  // nothing to do for separators
477  if (maction->isSeparator())
478  continue;
479 
480  s = maction->text();
481  if (!s.isEmpty())
482  {
483  Item *it = new Item;
484  item->addChild(it);
485  it->m_content =
486  KAccelString(s,
487  // menu titles are important, so raise the weight
488  KAccelManagerAlgorithm::MENU_TITLE_WEIGHT);
489 
490  it->m_widget = mbar;
491  it->m_index = i;
492  }
493 
494  // have a look at the popup as well, if present
495  if (maction->menu())
496  KPopupAccelManager::manage(maction->menu());
497  }
498 }
499 
500 
501 /*********************************************************************
502 
503  class KAcceleratorManager - main entry point
504 
505  This class is just here to provide a clean public API...
506 
507  *********************************************************************/
508 
509 void KAcceleratorManager::manage(QWidget *widget, bool programmers_mode)
510 {
511  KAcceleratorManagerPrivate::changed_string.clear();
512  KAcceleratorManagerPrivate::added_string.clear();
513  KAcceleratorManagerPrivate::removed_string.clear();
514  KAcceleratorManagerPrivate::programmers_mode = programmers_mode;
515  KAcceleratorManagerPrivate::manage(widget);
516 }
517 
518 void KAcceleratorManager::last_manage(QString &added, QString &changed, QString &removed)
519 {
520  added = KAcceleratorManagerPrivate::added_string;
521  changed = KAcceleratorManagerPrivate::changed_string;
522  removed = KAcceleratorManagerPrivate::removed_string;
523 }
524 
525 
526 /*********************************************************************
527 
528  class KAccelString - a string with weighted characters
529 
530  *********************************************************************/
531 
532 KAccelString::KAccelString(const QString &input, int initialWeight)
533  : m_pureText(input), m_weight()
534 {
535  m_orig_accel = m_pureText.indexOf("(!)&");
536  if (m_orig_accel != -1)
537  m_pureText.remove(m_orig_accel, 4);
538 
539  m_orig_accel = m_pureText.indexOf("(&&)");
540  if (m_orig_accel != -1)
541  m_pureText.replace(m_orig_accel, 4, "&");
542 
543  m_origText = m_pureText;
544 
545  if (m_pureText.contains('\t'))
546  m_pureText = m_pureText.left(m_pureText.indexOf('\t'));
547 
548  m_orig_accel = m_accel = stripAccelerator(m_pureText);
549 
550  if (initialWeight == -1)
551  initialWeight = KAccelManagerAlgorithm::DEFAULT_WEIGHT;
552 
553  calculateWeights(initialWeight);
554 
555  // dump();
556 }
557 
558 
559 QString KAccelString::accelerated() const
560 {
561  QString result = m_origText;
562  if (result.isEmpty())
563  return result;
564 
565  if (KAcceleratorManagerPrivate::programmers_mode)
566  {
567  if (m_accel != m_orig_accel) {
568  int oa = m_orig_accel;
569 
570  if (m_accel >= 0) {
571  result.insert(m_accel, "(!)&");
572  if (m_accel < m_orig_accel)
573  oa += 4;
574  }
575  if (m_orig_accel >= 0)
576  result.replace(oa, 1, "(&&)");
577  }
578  } else {
579  if (m_accel >= 0 && m_orig_accel != m_accel) {
580  if (m_orig_accel != -1)
581  result.remove(m_orig_accel, 1);
582  result.insert(m_accel, "&");
583  }
584  }
585  return result;
586 }
587 
588 
589 QChar KAccelString::accelerator() const
590 {
591  if ((m_accel < 0) || (m_accel > (int)m_pureText.length()))
592  return QChar();
593 
594  return m_pureText[m_accel].toLower();
595 }
596 
597 
598 void KAccelString::calculateWeights(int initialWeight)
599 {
600  m_weight.resize(m_pureText.length());
601 
602  int pos = 0;
603  bool start_character = true;
604 
605  while (pos<m_pureText.length())
606  {
607  QChar c = m_pureText[pos];
608 
609  int weight = initialWeight+1;
610 
611  // add special weight to first character
612  if (pos == 0)
613  weight += KAccelManagerAlgorithm::FIRST_CHARACTER_EXTRA_WEIGHT;
614 
615  // add weight to word beginnings
616  if (start_character)
617  {
618  weight += KAccelManagerAlgorithm::WORD_BEGINNING_EXTRA_WEIGHT;
619  start_character = false;
620  }
621 
622  // add decreasing weight to left characters
623  if (pos < 50)
624  weight += (50-pos);
625 
626  // try to preserve the wanted accelarators
627  if ((int)pos == accel()) {
628  weight += KAccelManagerAlgorithm::WANTED_ACCEL_EXTRA_WEIGHT;
629  // kDebug(240) << "wanted " << m_pureText << " " << KAcceleratorManagerPrivate::standardName(m_origText);
630  if (KAcceleratorManagerPrivate::standardName(m_origText)) {
631  weight += KAccelManagerAlgorithm::STANDARD_ACCEL;
632  }
633  }
634 
635  // skip non typeable characters
636  if (!c.isLetterOrNumber())
637  {
638  weight = 0;
639  start_character = true;
640  }
641 
642  m_weight[pos] = weight;
643 
644  ++pos;
645  }
646 }
647 
648 
649 int KAccelString::stripAccelerator(QString &text)
650 {
651  // Note: this code is derived from QAccel::shortcutKey
652  int p = 0;
653 
654  while (p >= 0)
655  {
656  p = text.indexOf('&', p)+1;
657 
658  if (p <= 0 || p >= (int)text.length())
659  break;
660 
661  if (text[p] != '&')
662  {
663  QChar c = text[p];
664  if (c.isPrint())
665  {
666  text.remove(p-1,1);
667  return p-1;
668  }
669  }
670 
671  p++;
672  }
673 
674  return -1;
675 }
676 
677 
678 int KAccelString::maxWeight(int &index, const QString &used) const
679 {
680  int max = 0;
681  index = -1;
682 
683  for (int pos=0; pos<m_pureText.length(); ++pos)
684  if (used.indexOf(m_pureText[pos], 0, Qt::CaseInsensitive) == -1 && m_pureText[pos].toLatin1() != 0)
685  if (m_weight[pos] > max)
686  {
687  max = m_weight[pos];
688  index = pos;
689  }
690 
691  return max;
692 }
693 
694 
695 void KAccelString::dump()
696 {
697  QString s;
698  for (int i=0; i<m_weight.count(); ++i)
699  s += QString("%1(%2) ").arg(pure()[i]).arg(m_weight[i]);
700  kDebug() << "s " << s;
701 }
702 
703 
704 /*********************************************************************
705 
706  findAccelerators - the algorithm determining the new accelerators
707 
708  The algorithm is very crude:
709 
710  * each character in each widget text is assigned a weight
711  * the character with the highest weight over all is picked
712  * that widget is removed from the list
713  * the weights are recalculated
714  * the process is repeated until no more accelerators can be found
715 
716  The algorithm has some advantages:
717 
718  * it favors 'nice' accelerators (first characters in a word, etc.)
719  * it is quite fast, O(N²)
720  * it is easy to understand :-)
721 
722  The disadvantages:
723 
724  * it does not try to find as many accelerators as possible
725 
726  TODO:
727 
728  * The result is always correct, but not necessarily optimal. Perhaps
729  it would be a good idea to add another algorithm with higher complexity
730  that gets used when this one fails, i.e. leaves widgets without
731  accelerators.
732 
733  * The weights probably need some tweaking so they make more sense.
734 
735  *********************************************************************/
736 
737 void KAccelManagerAlgorithm::findAccelerators(KAccelStringList &result, QString &used)
738 {
739  KAccelStringList accel_strings = result;
740 
741  // initially remove all accelerators
742  for (KAccelStringList::Iterator it = result.begin(); it != result.end(); ++it) {
743  (*it).setAccel(-1);
744  }
745 
746  // pick the highest bids
747  for (int cnt=0; cnt<accel_strings.count(); ++cnt)
748  {
749  int max = 0, index = -1, accel = -1;
750 
751  // find maximum weight
752  for (int i=0; i<accel_strings.count(); ++i)
753  {
754  int a;
755  int m = accel_strings[i].maxWeight(a, used);
756  if (m>max)
757  {
758  max = m;
759  index = i;
760  accel = a;
761  }
762  }
763 
764  // stop if no more accelerators can be found
765  if (index < 0)
766  return;
767 
768  // insert the accelerator
769  if (accel >= 0)
770  {
771  result[index].setAccel(accel);
772  used.append(result[index].accelerator());
773  }
774 
775  // make sure we don't visit this one again
776  accel_strings[index] = KAccelString();
777  }
778 }
779 
780 
781 /*********************************************************************
782 
783  class KPopupAccelManager - managing QPopupMenu widgets dynamically
784 
785  *********************************************************************/
786 
787 KPopupAccelManager::KPopupAccelManager(QMenu *popup)
788  : QObject(popup), m_popup(popup), m_count(-1)
789 {
790  aboutToShow(); // do one check and then connect to show
791  connect(popup, SIGNAL(aboutToShow()), SLOT(aboutToShow()));
792 }
793 
794 
795 void KPopupAccelManager::aboutToShow()
796 {
797  // Note: we try to be smart and avoid recalculating the accelerators
798  // whenever possible. Unfortunately, there is no way to know if an
799  // item has been added or removed, so we can not do much more than
800  // to compare the items each time the menu is shown :-(
801 
802  if (m_count != (int)m_popup->actions().count())
803  {
804  findMenuEntries(m_entries);
805  calculateAccelerators();
806  m_count = m_popup->actions().count();
807  }
808  else
809  {
810  KAccelStringList entries;
811  findMenuEntries(entries);
812  if (entries != m_entries)
813  {
814  m_entries = entries;
815  calculateAccelerators();
816  }
817  }
818 }
819 
820 
821 void KPopupAccelManager::calculateAccelerators()
822 {
823  // find the new accelerators
824  QString used;
825  KAccelManagerAlgorithm::findAccelerators(m_entries, used);
826 
827  // change the menu entries
828  setMenuEntries(m_entries);
829 }
830 
831 
832 void KPopupAccelManager::findMenuEntries(KAccelStringList &list)
833 {
834  QString s;
835 
836  list.clear();
837 
838  // read out the menu entries
839  foreach (QAction *maction, m_popup->actions())
840  {
841  if (maction->isSeparator())
842  continue;
843 
844  s = maction->text();
845 
846  // in full menus, look at entries with global accelerators last
847  int weight = 50;
848  if (s.contains('\t'))
849  weight = 0;
850 
851  list.append(KAccelString(s, weight));
852 
853  // have a look at the popup as well, if present
854  if (maction->menu())
855  KPopupAccelManager::manage(maction->menu());
856  }
857 }
858 
859 
860 void KPopupAccelManager::setMenuEntries(const KAccelStringList &list)
861 {
862  uint cnt = 0;
863  foreach (QAction *maction, m_popup->actions())
864  {
865  if (maction->isSeparator())
866  continue;
867 
868  if (KAcceleratorManagerPrivate::checkChange(list[cnt]))
869  maction->setText(list[cnt].accelerated());
870  cnt++;
871  }
872 }
873 
874 
875 void KPopupAccelManager::manage(QMenu *popup)
876 {
877  // don't add more than one manager to a popup
878  if (popup->findChild<KPopupAccelManager*>(QString()) == 0 )
879  new KPopupAccelManager(popup);
880 }
881 
882 void QWidgetStackAccelManager::manage( QStackedWidget *stack )
883 {
884  if ( stack->findChild<QWidgetStackAccelManager*>(QString()) == 0 )
885  new QWidgetStackAccelManager( stack );
886 }
887 
888 QWidgetStackAccelManager::QWidgetStackAccelManager(QStackedWidget *stack)
889  : QObject(stack), m_stack(stack)
890 {
891  currentChanged(stack->currentIndex()); // do one check and then connect to show
892  connect(stack, SIGNAL(currentChanged(int)), SLOT(currentChanged(int)));
893 }
894 
895 bool QWidgetStackAccelManager::eventFilter ( QObject * watched, QEvent * e )
896 {
897  if ( e->type() == QEvent::Show && qApp->activeWindow() ) {
898  KAcceleratorManager::manage( qApp->activeWindow() );
899  watched->removeEventFilter( this );
900  }
901  return false;
902 }
903 
904 void QWidgetStackAccelManager::currentChanged(int child)
905 {
906  if (child < 0 || child >= static_cast<QStackedWidget*>(parent())->count())
907  {
908  // NOTE: QStackedWidget emits currentChanged(-1) when it is emptied
909  return;
910  }
911 
912  static_cast<QStackedWidget*>(parent())->widget(child)->installEventFilter( this );
913 }
914 
915 void KAcceleratorManager::setNoAccel( QWidget *widget )
916 {
917  KAcceleratorManagerPrivate::ignored_widgets[widget] = 1;
918 }
919 
920 #include "kacceleratormanager_private.moc"
QVariant
KAccelString::pure
const QString & pure() const
Definition: kacceleratormanager_private.h:50
KAccelManagerAlgorithm::DEFAULT_WEIGHT
Definition: kacceleratormanager_private.h:95
kdebug.h
QWidgetStackAccelManager::QWidgetStackAccelManager
QWidgetStackAccelManager(QStackedWidget *popup)
Definition: kacceleratormanager.cpp:888
KAccelString
A string class handling accelerators.
Definition: kacceleratormanager_private.h:41
KStandardShortcut::label
QString label(StandardShortcut id)
Returns a localized label for user-visible display.
Definition: kstandardshortcut.cpp:267
QWidget
KAccelManagerAlgorithm::WANTED_ACCEL_EXTRA_WEIGHT
Definition: kacceleratormanager_private.h:103
KAccelString::accelerated
QString accelerated() const
Definition: kacceleratormanager.cpp:559
QTabBar
kacceleratormanager.h
QString
QObject
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KAccelString::KAccelString
KAccelString()
Definition: kacceleratormanager_private.h:45
KAccelManagerAlgorithm::FIRST_CHARACTER_EXTRA_WEIGHT
Definition: kacceleratormanager_private.h:97
QWidgetStackAccelManager::manage
static void manage(QStackedWidget *popup)
Definition: kacceleratormanager.cpp:882
KAcceleratorManager::last_manage
static void last_manage(QString &added, QString &changed, QString &removed)
Definition: kacceleratormanager.cpp:518
KPopupAccelManager
This class manages a popup menu.
Definition: kacceleratormanager_private.h:130
kglobal.h
KAccelManagerAlgorithm::WORD_BEGINNING_EXTRA_WEIGHT
Definition: kacceleratormanager_private.h:99
KPopupAccelManager::KPopupAccelManager
KPopupAccelManager(QMenu *popup)
Definition: kacceleratormanager.cpp:787
KAcceleratorManager::setNoAccel
static void setNoAccel(QWidget *widget)
Use this method for a widget (and its children) you want no accels to be set on.
Definition: kacceleratormanager.cpp:915
KAccelManagerAlgorithm::ACTION_ELEMENT_WEIGHT
Definition: kacceleratormanager_private.h:105
QStringList
KAccelString::originalText
QString originalText() const
Definition: kacceleratormanager_private.h:57
K_GLOBAL_STATIC_WITH_ARGS
K_GLOBAL_STATIC_WITH_ARGS(QStringList, kaccmp_sns,(KStandardAction::internal_stdNames())) QMap< QWidget *
QGroupBox
kstandardaction.h
KAccelManagerAlgorithm::findAccelerators
static void findAccelerators(KAccelStringList &result, QString &used)
Definition: kacceleratormanager.cpp:737
KAccelString::maxWeight
int maxWeight(int &index, const QString &used) const
Definition: kacceleratormanager.cpp:678
QMenuBar
KAccelManagerAlgorithm::GROUP_BOX_WEIGHT
Definition: kacceleratormanager_private.h:107
QMenu
QWidgetStackAccelManager
Definition: kacceleratormanager_private.h:163
KPopupAccelManager::manage
static void manage(QMenu *popup)
Definition: kacceleratormanager.cpp:875
QMainWindow
QLabel
Item
KAccelString::calculateWeights
void calculateWeights(int initialWeight)
Definition: kacceleratormanager.cpp:598
KAccelManagerAlgorithm::STANDARD_ACCEL
Definition: kacceleratormanager_private.h:113
KAccelString::accelerator
QChar accelerator() const
Definition: kacceleratormanager.cpp:589
KAcceleratorManager::manage
static void manage(QWidget *widget, bool programmers_mode=false)
Manages the accelerators of a widget.
Definition: kacceleratormanager.cpp:509
QAction
QMap< QWidget *, int >
QTextEdit
kacceleratormanager_private.h
QList
KAccelManagerAlgorithm::MENU_TITLE_WEIGHT
Definition: kacceleratormanager_private.h:111
KAccelString::originalAccel
int originalAccel() const
Definition: kacceleratormanager_private.h:56
KAccelString::accel
int accel() const
Definition: kacceleratormanager_private.h:53
KAccelManagerAlgorithm::CHECKABLE_GROUP_BOX_WEIGHT
Definition: kacceleratormanager_private.h:109
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:49:13 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

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

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal