KDELibs4Support

kaccelgen.h
1 /* This file is part of the KDE project
2  Copyright (C) 2000 Keunwoo Lee <[email protected]>
3 
4  This program 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 program 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
12  GNU 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 #ifndef KACCELGEN_H
21 #define KACCELGEN_H
22 
23 #include <QMap>
24 #include <QString>
25 #include <QStringList>
26 
27 /**
28  * Provides functions that, given a collection of QStrings, will
29  * automatically and intelligently assign menu accelerators to the
30  * QStrings in the collection.
31  *
32  * NOTE: When this file speaks of "accelerators", we really mean
33  * accelerators as defined by the KDE User Interface Guidelines. We
34  * do NOT mean "shortcuts", which are what's handled by most other KDE
35  * libraries with "accel" in the name.
36  *
37  * In the Qt library, the mechanism for adding a keyboard accelerator
38  * to a menu item is to insert an '&' before the letter. Since we
39  * usually don't want to disturb the original collection, the idiom in
40  * these functions is to populate a "target" QStringList parameter
41  * with the input collectin's QStrings, plus possibly some added '&'
42  * characters.
43  *
44  * That is the mechanism. Here is the policy, in order of decreasing
45  * importance (it may seem like these are implementation details, but
46  * IMHO the policy is an important part of the interface):
47  *
48  * 1. If the string already contains an '&' character, skip this
49  * string, because we consider such strings to be "user-specified"
50  * accelerators.
51  *
52  * 2. No accelerator may clash with a previously defined accelerator,
53  * including any legal (alphanumeric) user-specified accelerator
54  * anywhere in the collection
55  *
56  * 3. Prefer alphanumerics at the start of the string.
57  *
58  * 4. Otherwise, prefer alphanumerics at the start of a word.
59  *
60  * 5. Otherwise, choose any alphanumeric character not already
61  * taken. If no such character is available, give up & skip this
62  * string.
63  *
64  * A typical use of these functions would be to automatically assign
65  * accelerators to a dynamically populated popup menu. For example,
66  * the core code was written to automatically set accelerators for the
67  * "Load View Profile" popup menu for Konqueror. We quickly realized
68  * that it would be useful to make this facility more generally
69  * available, so I abstracted it out into a set of templates.
70  *
71  * TODO:
72  *
73  * + Add sugar functions for more collections.
74  *
75  * + Add more Deref classes so that we can access a wider variety of
76  * collections.
77  *
78  * @deprecated
79  * */
80 namespace KAccelGen
81 {
82 
83 // HELPERS
84 
85 /**
86  * Static dereference class, for use as a template parameter.
87  */
88 template <class Iter>
89 class Deref
90 {
91 public:
92  static QString deref(Iter i)
93  {
94  return *i;
95  }
96 };
97 
98 /**
99  * Static dereference class that calls the key() method on its
100  * target; for use as a template parameter.
101  */
102 template <class Iter>
104 {
105 public:
106  static QString deref(Iter i)
107  {
108  return i.key();
109  }
110 };
111 
112 /**
113  * Helper to determine if the given offset in the string could be a
114  * legal alphanumeric accelerator.
115  *
116  * @param str base string
117  * @param index offset to check
118  */
119 inline bool
120 isLegalAccelerator(const QString &str, int index)
121 {
122  return index >= 0 && index < str.length()
123  && str[index].isLetterOrNumber();
124 }
125 
126 /**
127  * Loads all legal predefined accelerators in the (implicitly
128  * specified) collection into the given QMap.
129  *
130  * @param begin start iterator
131  * @param end (last+1) iterator
132  * @param keys map to store output
133  */
134 template <class Iter, class Deref>
135 inline void
136 loadPredefined(Iter begin, Iter end, QMap<QChar, bool> &keys)
137 {
138  for (Iter i = begin; i != end; ++i) {
139  QString item = Deref::deref(i);
140  int user_ampersand = item.indexOf(QLatin1Char('&'));
141  if (user_ampersand >= 0) {
142  // Sanity check. Note that we don't try to find an
143  // accelerator if the user shoots him/herself in the foot
144  // by adding a bad '&'.
145  if (isLegalAccelerator(item, user_ampersand + 1)) {
146  keys.insert(item[user_ampersand + 1], true);
147  }
148  }
149  }
150 }
151 
152 // ///////////////////////////////////////////////////////////////////
153 // MAIN USER FUNCTIONS
154 
155 /**
156  * Main, maximally flexible template function that assigns
157  * accelerators to the elements of a collection of QStrings. Clients
158  * will seldom use this directly, as it's usually easier to use one of
159  * the wrapper functions that simply takes a collection (see below).
160  *
161  * The Deref template parameter is a class containing a static
162  * dereferencing function, modeled after the comparison class C in
163  * Stroustrup 13.4.
164  *
165  * @param begin (you know)
166  * @param end (you know)
167  * @param target collection to store generated strings
168  */
169 template <class Iter, class Iter_Deref >
170 void
171 generate(Iter begin, Iter end, QStringList &target)
172 {
173  // Will keep track of used accelerator chars
174  QMap<QChar, bool> used_accels;
175 
176  // Prepass to detect manually user-coded accelerators
177  loadPredefined<Iter, Iter_Deref>(begin, end, used_accels);
178 
179  // Main pass
180  for (Iter i = begin; i != end; ++i) {
181  QString item = Iter_Deref::deref(i);
182 
183  // Attempt to find a good accelerator, but only if the user
184  // has not manually hardcoded one.
185  int user_ampersand = item.indexOf(QLatin1Char('&'));
186  if (user_ampersand < 0 || item[user_ampersand + 1] == QLatin1Char('&')) {
187  bool found = false;
188  int j;
189 
190  // Check word-starting letters first.
191  for (j = 0; j < item.length(); ++j) {
192  if (isLegalAccelerator(item, j)
193  && !used_accels.contains(item[j])
194  && (0 == j || (j > 0 && item[j - 1].isSpace()))) {
195  found = true;
196  break;
197  }
198  }
199 
200  if (!found) {
201  // No word-starting letter; search for any letter.
202  for (j = 0; j < item.length(); ++j) {
203  if (isLegalAccelerator(item, j)
204  && !used_accels.contains(item[j])) {
205  found = true;
206  break;
207  }
208  }
209  }
210 
211  if (found) {
212  // Both upper and lower case marked as used
213  used_accels.insert(item[j].toUpper(), true);
214  used_accels.insert(item[j].toLower(), true);
215  item.insert(j, QLatin1Char('&'));
216  }
217  }
218 
219  target.append(item);
220  }
221 }
222 
223 /**
224  * Another convenience function; looks up the key instead of
225  * dereferencing directly for the given iterator.
226  *
227  * @param begin
228  * @param end
229  * @param target
230  */
231 template <class Iter>
232 inline void
233 generateFromKeys(Iter begin, Iter end, QStringList &target)
234 {
235  generate< Iter, Deref_Key<Iter> >(begin, end, target);
236 }
237 
238 /**
239  * Convenience function; generates accelerators for all the items in
240  * a QStringList.
241  *
242  * @param source Strings for which to generate accelerators
243  * @param target Output for accelerator-added strings */
244 inline void
245 generate(const QStringList &source, QStringList &target)
246 {
247  generate<QStringList::ConstIterator, Deref<QStringList::ConstIterator> >(source.begin(), source.end(), target);
248 }
249 
250 /**
251  * Convenience function; generates accelerators for all the values in
252  * a QMap<T,QString>.
253  *
254  * @param source Map with input strings as VALUES.
255  * @param target Output for accelerator-added strings */
256 template <class Key>
257 inline void
259 {
260  generate<typename QMap<Key, QString>::ConstIterator, Deref_Key<typename QMap<Key, QString>::ConstIterator> >(source.begin(), source.end(), target);
261 }
262 
263 /**
264  * Convenience function; generates an accelerator mapping from all the
265  * keys in a QMap<QString,T>
266  *
267  * @param source Map with input strings as KEYS.
268  * @param target Output for accelerator-added strings */
269 template <class Data>
270 inline void
272 {
273  generateFromKeys(source.begin(), source.end(), target);
274 }
275 
276 } // end namespace KAccelGen
277 
278 #endif
279 
void generateFromKeys(Iter begin, Iter end, QStringList &target)
Another convenience function; looks up the key instead of dereferencing directly for the given iterat...
Definition: kaccelgen.h:233
void append(const T &value)
bool contains(const Key &key) const const
void generate(Iter begin, Iter end, QStringList &target)
Main, maximally flexible template function that assigns accelerators to the elements of a collection ...
Definition: kaccelgen.h:171
QMap::iterator begin()
void deref()
Tells KGlobal that one operation such as those described in ref() just finished.
Definition: kglobal.cpp:213
void generateFromValues(const QMap< Key, QString > &source, QStringList &target)
Convenience function; generates accelerators for all the values in a QMap<T,QString>.
Definition: kaccelgen.h:258
QMap::iterator insert(const Key &key, const T &value)
QMap::iterator end()
Provides functions that, given a collection of QStrings, will automatically and intelligently assign ...
Definition: kaccelgen.h:80
Static dereference class that calls the key() method on its target; for use as a template parameter.
Definition: kaccelgen.h:103
int length() const const
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
Definition: netaccess.h:36
Static dereference class, for use as a template parameter.
Definition: kaccelgen.h:89
QString & insert(int position, QChar ch)
bool isLegalAccelerator(const QString &str, int index)
Helper to determine if the given offset in the string could be a legal alphanumeric accelerator.
Definition: kaccelgen.h:120
QList::iterator begin()
QList::iterator end()
void loadPredefined(Iter begin, Iter end, QMap< QChar, bool > &keys)
Loads all legal predefined accelerators in the (implicitly specified) collection into the given QMap.
Definition: kaccelgen.h:136
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Sep 26 2023 03:54:12 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.