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

KDEUI

  • 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
74class KAcceleratorManagerPrivate
75{
76public:
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
104private:
105 class Item;
106public:
107 typedef QList<Item *> ItemList;
108
109private:
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
137bool KAcceleratorManagerPrivate::programmers_mode = false;
138QString KAcceleratorManagerPrivate::changed_string;
139QString KAcceleratorManagerPrivate::added_string;
140QString KAcceleratorManagerPrivate::removed_string;
141K_GLOBAL_STATIC_WITH_ARGS(QStringList, kaccmp_sns, (KStandardAction::internal_stdNames()))
142QMap<QWidget*, int> KAcceleratorManagerPrivate::ignored_widgets;
143
144bool KAcceleratorManagerPrivate::standardName(const QString &str)
145{
146 return kaccmp_sns->contains(str);
147}
148
149KAcceleratorManagerPrivate::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
159void KAcceleratorManagerPrivate::Item::addChild(Item *item)
160{
161 if (!m_children) {
162 m_children = new ItemList;
163 }
164
165 m_children->append(item);
166}
167
168void 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
197void 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
272void 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
289void 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
414void 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
442void 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
465void 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
509void 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
518void 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
532KAccelString::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
559QString 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
589QChar 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
598void 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
649int 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
678int 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
695void 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
737void 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
787KPopupAccelManager::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
795void 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
821void 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
832void 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
860void 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
875void 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
882void QWidgetStackAccelManager::manage( QStackedWidget *stack )
883{
884 if ( stack->findChild<QWidgetStackAccelManager*>(QString()) == 0 )
885 new QWidgetStackAccelManager( stack );
886}
887
888QWidgetStackAccelManager::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
895bool 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
904void 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
915void KAcceleratorManager::setNoAccel( QWidget *widget )
916{
917 KAcceleratorManagerPrivate::ignored_widgets[widget] = 1;
918}
919
920#include "kacceleratormanager_private.moc"
KAccelManagerAlgorithm::findAccelerators
static void findAccelerators(KAccelStringList &result, QString &used)
Definition: kacceleratormanager.cpp:737
KAccelManagerAlgorithm::DEFAULT_WEIGHT
@ DEFAULT_WEIGHT
Definition: kacceleratormanager_private.h:95
KAccelManagerAlgorithm::WANTED_ACCEL_EXTRA_WEIGHT
@ WANTED_ACCEL_EXTRA_WEIGHT
Definition: kacceleratormanager_private.h:103
KAccelManagerAlgorithm::CHECKABLE_GROUP_BOX_WEIGHT
@ CHECKABLE_GROUP_BOX_WEIGHT
Definition: kacceleratormanager_private.h:109
KAccelManagerAlgorithm::ACTION_ELEMENT_WEIGHT
@ ACTION_ELEMENT_WEIGHT
Definition: kacceleratormanager_private.h:105
KAccelManagerAlgorithm::MENU_TITLE_WEIGHT
@ MENU_TITLE_WEIGHT
Definition: kacceleratormanager_private.h:111
KAccelManagerAlgorithm::FIRST_CHARACTER_EXTRA_WEIGHT
@ FIRST_CHARACTER_EXTRA_WEIGHT
Definition: kacceleratormanager_private.h:97
KAccelManagerAlgorithm::STANDARD_ACCEL
@ STANDARD_ACCEL
Definition: kacceleratormanager_private.h:113
KAccelManagerAlgorithm::WORD_BEGINNING_EXTRA_WEIGHT
@ WORD_BEGINNING_EXTRA_WEIGHT
Definition: kacceleratormanager_private.h:99
KAccelManagerAlgorithm::GROUP_BOX_WEIGHT
@ GROUP_BOX_WEIGHT
Definition: kacceleratormanager_private.h:107
KAccelString
A string class handling accelerators.
Definition: kacceleratormanager_private.h:42
KAccelString::KAccelString
KAccelString()
Definition: kacceleratormanager_private.h:45
KAccelString::calculateWeights
void calculateWeights(int initialWeight)
Definition: kacceleratormanager.cpp:598
KAccelString::pure
const QString & pure() const
Definition: kacceleratormanager_private.h:50
KAccelString::originalText
QString originalText() const
Definition: kacceleratormanager_private.h:57
KAccelString::maxWeight
int maxWeight(int &index, const QString &used) const
Definition: kacceleratormanager.cpp:678
KAccelString::accel
int accel() const
Definition: kacceleratormanager_private.h:53
KAccelString::accelerator
QChar accelerator() const
Definition: kacceleratormanager.cpp:589
KAccelString::accelerated
QString accelerated() const
Definition: kacceleratormanager.cpp:559
KAccelString::originalAccel
int originalAccel() const
Definition: kacceleratormanager_private.h:56
KAcceleratorManager::last_manage
static void last_manage(QString &added, QString &changed, QString &removed)
Definition: kacceleratormanager.cpp:518
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
KAcceleratorManager::manage
static void manage(QWidget *widget, bool programmers_mode=false)
Manages the accelerators of a widget.
Definition: kacceleratormanager.cpp:509
KPopupAccelManager
This class manages a popup menu.
Definition: kacceleratormanager_private.h:131
KPopupAccelManager::KPopupAccelManager
KPopupAccelManager(QMenu *popup)
Definition: kacceleratormanager.cpp:787
KPopupAccelManager::manage
static void manage(QMenu *popup)
Definition: kacceleratormanager.cpp:875
QAction
QGroupBox
QLabel
QList
QMainWindow
QMap
QMenuBar
QMenu
QObject
QTabBar
QWidgetStackAccelManager
Definition: kacceleratormanager_private.h:164
QWidgetStackAccelManager::manage
static void manage(QStackedWidget *popup)
Definition: kacceleratormanager.cpp:882
QWidgetStackAccelManager::QWidgetStackAccelManager
QWidgetStackAccelManager(QStackedWidget *popup)
Definition: kacceleratormanager.cpp:888
QWidget
kDebug
#define kDebug
kacceleratormanager.h
kacceleratormanager_private.h
kdebug.h
K_GLOBAL_STATIC_WITH_ARGS
K_GLOBAL_STATIC_WITH_ARGS(KComponentData, fakeComponent,(KGlobalPrivate::initFakeComponent())) KStandardDirs *KGlobal
kglobal.h
kstandardaction.h
KStandardShortcut::label
QString label(StandardShortcut id)
Returns a localized label for user-visible display.
Definition: kstandardshortcut.cpp:267
Item
Item
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 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
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
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