KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > views > markers > internal > MnemonicAssigner


1 /*******************************************************************************
2  * Copyright (c) 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.views.markers.internal;
12
13 import java.util.HashSet JavaDoc;
14 import java.util.Set JavaDoc;
15
16 /**
17  * Can be used to automatically assign non-conflicting mnemonics to SWT widgets.
18  * Note: the current implementation is pretty bare-bones, and is intended to fix
19  * a couple dialogs where the widgets are generated programmatically. If this were
20  * to go into more general use, it would have to take into account preferred hotkeys
21  * for the locale and have preferences for words coming after whitespace, etc.
22  *
23  * @since 3.1
24  */

25 public class MnemonicAssigner {
26     // Stores keys that have already been assigned
27
private Set JavaDoc assigned = new HashSet JavaDoc();
28     
29     // List of all possible valid mnemonics
30
private String JavaDoc validHotkeys = new String JavaDoc();
31     
32     // Set of all possible valid mnemonics
33
private Set JavaDoc validKeys = new HashSet JavaDoc();
34     
35     public MnemonicAssigner() {
36         // Initialize the set of valid mnemonic keys
37
addKeys(Messages.getString("MnemonicAssigner.valid_mnemonics")); //$NON-NLS-1$
38
}
39     
40     /**
41      * Adds a set of keys to be considered as potentially valid mnemonics
42      *
43      * @param keys
44      * @return
45      * @since 3.1
46      */

47     private void addKeys(String JavaDoc keys) {
48         validHotkeys = validHotkeys + keys;
49         
50         for(int idx = 0; idx < validHotkeys.length(); idx++) {
51             validKeys.add(new Character JavaDoc(Character.toLowerCase(keys.charAt(idx))));
52         }
53     }
54     
55     public boolean isReserved(char toCheck) {
56         return assigned.contains(new Character JavaDoc(Character.toLowerCase(toCheck)));
57     }
58     
59     /**
60      * Returns the index of the mnemonic in the given string. Returns
61      * inputString.length() if the string does not contain a mnemonic.
62      *
63      * @param inputString
64      * @return
65      * @since 3.1
66      */

67     private static int getAmpersandIndex(String JavaDoc inputString) {
68         for(int idx = 0; idx < inputString.length() - 1; idx++) {
69             char next = inputString.charAt(idx);
70             
71             if (next == '&') {
72                 if (inputString.charAt(idx + 1) == '&') {
73                     // If dual-ampersand, skip it
74
idx++;
75                 } else {
76                     return idx;
77                 }
78             }
79         }
80         
81         return inputString.length();
82     }
83     
84     /**
85      * Returns the current mnemonic in the given input string. Returns
86      * 0 if none.
87      *
88      * @param inputString
89      * @return
90      * @since 3.1
91      */

92     public static char getMnemonic(String JavaDoc inputString) {
93         int idx = getAmpersandIndex(inputString);
94         
95         if (idx < inputString.length() - 1) {
96             return inputString.charAt(idx + 1);
97         }
98         
99         return 0;
100     }
101     
102     public void reserve(char toReserve) {
103         assigned.add(new Character JavaDoc(Character.toLowerCase(toReserve)));
104     }
105     
106     /**
107      * Returns the given string without its associated mnemonic
108      *
109      * @param toRemove
110      * @return
111      * @since 3.1
112      */

113     public static String JavaDoc withoutMnemonic(String JavaDoc toRemove) {
114         String JavaDoc working = toRemove;
115         
116         int idx = getAmpersandIndex(working);
117         while(idx < working.length()) {
118             working = working.substring(0, idx) + working.substring(idx + 1, working.length());
119             idx = getAmpersandIndex(working);
120         }
121         
122         return working;
123     }
124     
125     /**
126      * Suggests a unique mnemonic for the given input string and reserves it, preventing
127      * future conflicts
128      *
129      * @param inputString
130      * @return
131      * @since 3.1
132      */

133     public String JavaDoc assign(String JavaDoc inputString) {
134         String JavaDoc result = suggest(inputString);
135         reserve(result);
136         return result;
137     }
138     
139     /**
140      * Reserves the mnemonic that is currently being used by the given input string
141      *
142      * @param inputString
143      * @since 3.1
144      */

145     public void reserve(String JavaDoc inputString) {
146         reserve(getMnemonic(inputString));
147     }
148     
149     /**
150      * Returns true iff the given character could possibly be used as a mnemonic
151      *
152      * @param next
153      * @return
154      * @since 3.1
155      */

156     public boolean isValidMnemonic(char next) {
157         return validKeys.contains(new Character JavaDoc(Character.toLowerCase(next)));
158     }
159     
160     /**
161      * Suggests a unique mnemonic for the given input string that does not conflict with
162      * any existing mnemonics.
163      *
164      * @param inputString
165      * @return the string with a unique mnemonic
166      * @since 3.1
167      */

168     public String JavaDoc suggest(String JavaDoc inputString) {
169         char mnemonic = getMnemonic(inputString);
170         
171         if (mnemonic != 0 && !isReserved(mnemonic)) {
172             return inputString;
173         }
174         
175         // Try to find a suitable mnemonic from the input string.
176
String JavaDoc stripped = withoutMnemonic(inputString);
177         
178         // Index of the best mnemonic found so far
179
int bestMnemonic = -1;
180         
181         // Rank of the best mnemonic found so far (whenever a potential mnemonic is
182
// discovered in the string, we heuristically assign it a rank indicating how
183
// much we'd like this to be the mnemonic. Bigger ranks are preferred over smaller
184
// ones.
185
int mnemonicRank = -1;
186         
187         boolean lastWasWhitespace = true;
188         
189         for (int idx = 0; idx < stripped.length(); idx++) {
190             char next = stripped.charAt(idx);
191             
192             if (isValidMnemonic(next) && !isReserved(next)) {
193                 int thisRank = 0;
194                 
195                 // Prefer upper-case characters to lower-case ones
196
if (Character.isUpperCase(next)) {
197                     thisRank += 1;
198                 }
199                 
200                 // Give characters following whitespace the highest priority
201
if (lastWasWhitespace) {
202                     thisRank += 2;
203                 }
204                 
205                 if (thisRank > mnemonicRank) {
206                     bestMnemonic = idx;
207                     mnemonicRank = thisRank;
208                 }
209                 
210                 break;
211             }
212             
213             lastWasWhitespace = (Character.isWhitespace(next));
214         }
215         
216         // If there was a valid mnemonic within the string, return it
217
if (bestMnemonic >= 0) {
218             return stripped.substring(0, bestMnemonic) + '&'
219                 + stripped.substring(bestMnemonic, stripped.length());
220         }
221         
222         // No valid mnemonics within the string. Try to append one.
223
for (int idx = 0; idx < validHotkeys.length(); idx++) {
224             char next = validHotkeys.charAt(idx);
225             
226             if (!isReserved(next)) {
227                 return Messages.format(Messages.getString("MnemonicAssigner.missing_mnemonic_format"), new String JavaDoc[] {stripped, "&" + next}); //$NON-NLS-1$ //$NON-NLS-2$
228
}
229         }
230         
231         // No unique mnemonics remain. Leave the string unmodified
232
return inputString;
233     }
234 }
235
Popular Tags