00001 /* This file is part of the KDE project
00002 Copyright (C) 2000 Keunwoo Lee <klee@cs.washington.edu>
00003
00004 This program 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 program 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
00012 GNU 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 #ifndef KACCELGEN_H
00021 #define KACCELGEN_H
00022
00023 #include <qmap.h>
00024 #include <qstring.h>
00025 #include <qstringlist.h>
00026
00027 #include <kdelibs_export.h>
00028
00080 namespace KAccelGen
00081 {
00082
00083 // HELPERS
00084
00088 template <class Iter>
00089 class Deref
00090 {
00091 public:
00092 static QString deref(Iter i) { return *i; }
00093 };
00094
00099 template <class Iter>
00100 class Deref_Key
00101 {
00102 public:
00103 static QString deref(Iter i) { return i.key(); }
00104 };
00105
00113 inline bool
00114 isLegalAccelerator(const QString& str, uint index)
00115 {
00116 return index < str.length()
00117 && str[index].isLetterOrNumber();
00118 }
00119
00128 template <class Iter, class Deref>
00129 inline void
00130 loadPredefined(Iter begin, Iter end, QMap<QChar,bool>& keys)
00131 {
00132 for (Iter i = begin; i != end; ++i) {
00133 QString item = Deref::deref(i);
00134 int user_ampersand = item.find(QChar('&'));
00135 if( user_ampersand >= 0 ) {
00136 // Sanity check. Note that we don't try to find an
00137 // accelerator if the user shoots him/herself in the foot
00138 // by adding a bad '&'.
00139 if( isLegalAccelerator(item, user_ampersand+1) ) {
00140 keys.insert(item[user_ampersand+1], true);
00141 }
00142 }
00143 }
00144 }
00145
00146
00147 // ///////////////////////////////////////////////////////////////////
00148 // MAIN USER FUNCTIONS
00149
00150
00165 template <class Iter, class Iter_Deref >
00166 void
00167 generate(Iter begin, Iter end, QStringList& target)
00168 {
00169 // Will keep track of used accelerator chars
00170 QMap<QChar,bool> used_accels;
00171
00172 // Prepass to detect manually user-coded accelerators
00173 loadPredefined<Iter,Iter_Deref>(begin, end, used_accels);
00174
00175 // Main pass
00176 for (Iter i = begin; i != end; ++i) {
00177 QString item = Iter_Deref::deref(i);
00178
00179 // Attempt to find a good accelerator, but only if the user
00180 // has not manually hardcoded one.
00181 int user_ampersand = item.find(QChar('&'));
00182 if( user_ampersand < 0 || item[user_ampersand+1] == '&') {
00183 bool found = false;
00184 uint found_idx;
00185 uint j;
00186
00187 // Check word-starting letters first.
00188 for( j=0; j < item.length(); ++j ) {
00189 if( isLegalAccelerator(item, j)
00190 && !used_accels.contains(item[j])
00191 && (0 == j || (j > 0 && item[j-1].isSpace())) ) {
00192 found = true;
00193 found_idx = j;
00194 break;
00195 }
00196 }
00197
00198 if( !found ) {
00199 // No word-starting letter; search for any letter.
00200 for( j=0; j < item.length(); ++j ) {
00201 if( isLegalAccelerator(item, j)
00202 && !used_accels.contains(item[j]) ) {
00203 found = true;
00204 found_idx = j;
00205 break;
00206 }
00207 }
00208 }
00209
00210 if( found ) {
00211 // Both upper and lower case marked as used
00212 used_accels.insert(item[j].upper(),true);
00213 used_accels.insert(item[j].lower(),true);
00214 item.insert(j,QChar('&'));
00215 }
00216 }
00217
00218 target.append( item );
00219 }
00220 }
00221
00230 template <class Iter>
00231 inline void
00232 generateFromKeys(Iter begin, Iter end, QStringList& target)
00233 {
00234 generate< Iter, Deref_Key<Iter> >(begin, end, target);
00235 }
00236
00237
00244 inline void
00245 generate(const QStringList& source, QStringList& target)
00246 {
00247 generate<QStringList::ConstIterator, Deref<QStringList::ConstIterator> >(source.begin(), source.end(), target);
00248 }
00249
00256 template <class Key>
00257 inline void
00258 generateFromValues(const QMap<Key,QString>& source, QStringList& target)
00259 {
00260 generate<QMapConstIterator<Key,QString>, Deref_Key<QMapConstIterator<Key,QString> > >(source.begin(), source.end(), target);
00261 }
00262
00269 template <class Data>
00270 inline void
00271 generateFromKeys(const QMap<QString,Data>& source, QStringList& target)
00272 {
00273 generateFromKeys(source.begin(), source.end(), target);
00274 }
00275
00276
00277 } // end namespace KAccelGen
00278
00279 #endif
00280