1 /*
2     This file is part of the KDE project
3     SPDX-FileCopyrightText: 2002 Matthias Hölzer-Klüpfel <mhk@kde.org>
4 
5     SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #ifndef KACCELERATORMANAGER_PRIVATE_H
9 #define KACCELERATORMANAGER_PRIVATE_H
10 
11 #include <QObject>
12 #include <QString>
13 #include <QVector>
14 
15 class QStackedWidget;
16 class QMenu;
17 class QMenuBar;
18 class QTabBar;
19 class QDockWidget;
20 
21 /**
22  * A string class handling accelerators.
23  *
24  * This class contains a string and knowledge about accelerators.
25  * It keeps a list weights, telling how valuable each character
26  * would be as an accelerator.
27  *
28  * @author Matthias Hölzer-Klüpfel <mhk@kde.org>
29  */
30 
31 class KAccelString
32 {
33 public:
KAccelString()34     KAccelString()
35         : m_pureText()
36         , m_accel(-1)
37         , m_orig_accel(-1)
38     {
39     }
40     explicit KAccelString(const QString &input, int initalWeight = -1);
41 
42     void calculateWeights(int initialWeight);
43 
pure()44     const QString &pure() const
45     {
46         return m_pureText;
47     }
48     QString accelerated() const;
49 
accel()50     int accel() const
51     {
52         return m_accel;
53     }
setAccel(int accel)54     void setAccel(int accel)
55     {
56         m_accel = accel;
57     }
58 
originalAccel()59     int originalAccel() const
60     {
61         return m_orig_accel;
62     }
originalText()63     QString originalText() const
64     {
65         return m_origText;
66     }
67 
68     QChar accelerator() const;
69 
70     int maxWeight(int &index, const QString &used) const;
71 
72     bool operator==(const KAccelString &c) const
73     {
74         return m_pureText == c.m_pureText && m_accel == c.m_accel && m_orig_accel == c.m_orig_accel;
75     }
76 
77 private:
78     int stripAccelerator(QString &input);
79 
80     void dump();
81 
82     QString m_pureText;
83     QString m_origText;
84     int m_accel;
85     int m_orig_accel;
86     QVector<int> m_weight;
87 };
88 
89 typedef QList<KAccelString> KAccelStringList;
90 
91 /**
92  * This class encapsulates the algorithm finding the 'best'
93  * distribution of accelerators in a hierarchy of widgets.
94  *
95  * @author Matthias Hölzer-Klüpfel <mhk@kde.org>
96  */
97 
98 class KAccelManagerAlgorithm
99 {
100 public:
101     enum {
102         // Default control weight
103         DEFAULT_WEIGHT = 50,
104         // Additional weight for first character in string
105         FIRST_CHARACTER_EXTRA_WEIGHT = 50,
106         // Additional weight for the beginning of a word
107         WORD_BEGINNING_EXTRA_WEIGHT = 50,
108         // Additional weight for the dialog buttons (large, we basically never want these reassigned)
109         DIALOG_BUTTON_EXTRA_WEIGHT = 300,
110         // Additional weight for a 'wanted' accelerator
111         WANTED_ACCEL_EXTRA_WEIGHT = 150,
112         // Default weight for an 'action' widget (ie, pushbuttons)
113         ACTION_ELEMENT_WEIGHT = 50,
114         // Default weight for group boxes (lowest priority)
115         GROUP_BOX_WEIGHT = -2000,
116         // Default weight for checkable group boxes (low priority)
117         CHECKABLE_GROUP_BOX_WEIGHT = 20,
118         // Default weight for menu titles
119         MENU_TITLE_WEIGHT = 250,
120         // Additional weight for KDE standard accelerators
121         STANDARD_ACCEL = 300,
122     };
123 
124     static void findAccelerators(KAccelStringList &result, QString &used);
125 };
126 
127 /**
128  * This class manages a popup menu. It will notice if entries have been
129  * added or changed, and will recalculate the accelerators accordingly.
130  *
131  * This is necessary for dynamic menus like for example in kicker.
132  *
133  * @author Matthias Hölzer-Klüpfel <mhk@kde.org>
134  */
135 
136 class KPopupAccelManager : public QObject
137 {
138     Q_OBJECT
139 
140 public:
141     static void manage(QMenu *popup);
142 
143 protected:
144     KPopupAccelManager(QMenu *popup);
145 
146 private Q_SLOTS:
147 
148     void aboutToShow();
149 
150 private:
151     void calculateAccelerators();
152 
153     void findMenuEntries(KAccelStringList &list);
154     void setMenuEntries(const KAccelStringList &list);
155 
156     QMenu *m_popup;
157     KAccelStringList m_entries;
158     int m_count;
159 };
160 
161 class QWidgetStackAccelManager : public QObject
162 {
163     Q_OBJECT
164 
165 public:
166     static void manage(QStackedWidget *popup);
167 
168 protected:
169     QWidgetStackAccelManager(QStackedWidget *popup);
170 
171 private Q_SLOTS:
172 
173     void currentChanged(int child);
174     bool eventFilter(QObject *watched, QEvent *e) override;
175 
176 private:
177     void calculateAccelerators();
178 
179     QStackedWidget *m_stack;
180     KAccelStringList m_entries;
181 };
182 
183 /*********************************************************************
184 
185  class KAcceleratorManagerPrivate - internal helper class
186 
187  This class does all the work to find accelerators for a hierarchy of
188  widgets.
189 
190  *********************************************************************/
191 
192 class KAcceleratorManagerPrivate
193 {
194 public:
195     static void manage(QWidget *widget);
196     static bool programmers_mode;
197     static void addStandardActionNames(const QStringList &strList);
198     static bool standardName(const QString &str);
199 
checkChange(const KAccelString & as)200     static bool checkChange(const KAccelString &as)
201     {
202         QString t2 = as.accelerated();
203         QString t1 = as.originalText();
204         if (t1 != t2) {
205             if (as.accel() == -1) {
206                 removed_string += QLatin1String("<tr><td>") + t1.toHtmlEscaped() + QLatin1String("</td></tr>");
207             } else if (as.originalAccel() == -1) {
208                 added_string += QLatin1String("<tr><td>") + t2.toHtmlEscaped() + QLatin1String("</td></tr>");
209             } else {
210                 changed_string += QLatin1String("<tr><td>") + t1.toHtmlEscaped() + QLatin1String("</td>");
211                 changed_string += QLatin1String("<td>") + t2.toHtmlEscaped() + QLatin1String("</td></tr>");
212             }
213             return true;
214         }
215         return false;
216     }
217     static QString changed_string;
218     static QString added_string;
219     static QString removed_string;
220     static QMap<QWidget *, int> ignored_widgets;
221     static QStringList standardNames;
222 
223 private:
224     class Item;
225 
226 public:
227     typedef QList<Item *> ItemList;
228 
229 private:
230     static void traverseChildren(QWidget *widget, Item *item, QString &used);
231 
232     static void manageWidget(QWidget *widget, Item *item, QString &used);
233     static void manageMenuBar(QMenuBar *mbar, Item *item);
234     static void manageTabBar(QTabBar *bar, Item *item);
235     static void manageDockWidget(QDockWidget *dock, Item *item);
236 
237     static void calculateAccelerators(Item *item, QString &used);
238 
239     class Item
240     {
241     public:
Item()242         Item()
243             : m_widget(nullptr)
244             , m_children(nullptr)
245             , m_index(-1)
246         {
247         }
248         ~Item();
249 
250         Item(const Item &) = delete;
251         Item &operator=(const Item &) = delete;
252 
253         void addChild(Item *item);
254 
255         QWidget *m_widget;
256         KAccelString m_content;
257         ItemList *m_children;
258         int m_index;
259     };
260 };
261 
262 #endif // KACCELERATORMANAGER_PRIVATE_H
263