001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.keys;
011:
012: import java.util.Arrays;
013: import java.util.Collections;
014: import java.util.Set;
015: import java.util.SortedSet;
016: import java.util.StringTokenizer;
017: import java.util.TreeSet;
018:
019: import org.eclipse.ui.internal.util.Util;
020:
021: /**
022: * <p>
023: * A <code>KeyStroke</code> is defined as an optional set of modifier keys
024: * followed optionally by a natural key. A <code>KeyStroke</code> is said to
025: * be complete if it contains a natural key. A natural key is any Unicode
026: * character (e.g., "backspace", etc.), any character belonging to a natural
027: * language (e.g., "A", "1", "[", etc.), or any special control character
028: * specific to computers (e.g., "F10", "PageUp", etc.).
029: * </p>
030: * <p>
031: * All <code>KeyStroke</code> objects have a formal string representation
032: * available via the <code>toString()</code> method. There are a number of
033: * methods to get instances of <code>KeyStroke</code> objects, including one
034: * which can parse this formal string representation.
035: * </p>
036: * <p>
037: * All <code>KeyStroke</code> objects, via the <code>format()</code> method,
038: * provide a version of their formal string representation translated by
039: * platform and locale, suitable for display to a user.
040: * </p>
041: * <p>
042: * <code>KeyStroke</code> objects are immutable. Clients are not permitted to
043: * extend this class.
044: * </p>
045: *
046: * @deprecated Please use org.eclipse.jface.bindings.keys.KeyStroke
047: * @since 3.0
048: * @see org.eclipse.ui.keys.ModifierKey
049: * @see org.eclipse.ui.keys.NaturalKey
050: */
051: public final class KeyStroke implements Comparable {
052:
053: /**
054: * The delimiter between multiple keys in a single key strokes -- expressed
055: * in the formal key stroke grammar. This is not to be displayed to the
056: * user. It is only intended as an internal representation.
057: */
058: public final static String KEY_DELIMITER = "\u002B"; //$NON-NLS-1$
059:
060: /**
061: * An internal constant used only in this object's hash code algorithm.
062: */
063: private final static int HASH_FACTOR = 89;
064:
065: /**
066: * An internal constant used only in this object's hash code algorithm.
067: */
068: private final static int HASH_INITIAL = KeyStroke.class.getName()
069: .hashCode();
070:
071: /**
072: * The set of delimiters for <code>Key</code> objects allowed during
073: * parsing of the formal string representation.
074: */
075: public final static String KEY_DELIMITERS = KEY_DELIMITER;
076:
077: /**
078: * Gets an instance of <code>KeyStroke</code> given a single modifier key
079: * and a natural key.
080: *
081: * @param modifierKey
082: * a modifier key. Must not be <code>null</code>.
083: * @param naturalKey
084: * the natural key. May be <code>null</code>.
085: * @return a key stroke. Guaranteed not to be <code>null</code>.
086: */
087: public static KeyStroke getInstance(ModifierKey modifierKey,
088: NaturalKey naturalKey) {
089: if (modifierKey == null) {
090: throw new NullPointerException();
091: }
092:
093: return new KeyStroke(new TreeSet(Collections
094: .singletonList(modifierKey)), naturalKey);
095: }
096:
097: /**
098: * Gets an instance of <code>KeyStroke</code> given an array of modifier
099: * keys and a natural key.
100: *
101: * @param modifierKeys
102: * the array of modifier keys. This array may be empty, but it
103: * must not be <code>null</code>. If this array is not empty,
104: * it must not contain <code>null</code> elements.
105: * @param naturalKey
106: * the natural key. May be <code>null</code>.
107: * @return a key stroke. Guaranteed not to be <code>null</code>.
108: */
109: public static KeyStroke getInstance(ModifierKey[] modifierKeys,
110: NaturalKey naturalKey) {
111: Util.assertInstance(modifierKeys, ModifierKey.class);
112: return new KeyStroke(new TreeSet(Arrays.asList(modifierKeys)),
113: naturalKey);
114: }
115:
116: /**
117: * Gets an instance of <code>KeyStroke</code> given a natural key.
118: *
119: * @param naturalKey
120: * the natural key. May be <code>null</code>.
121: * @return a key stroke. This key stroke will have no modifier keys.
122: * Guaranteed not to be <code>null</code>.
123: */
124: public static KeyStroke getInstance(NaturalKey naturalKey) {
125: return new KeyStroke(Util.EMPTY_SORTED_SET, naturalKey);
126: }
127:
128: /**
129: * Gets an instance of <code>KeyStroke</code> given a set of modifier
130: * keys and a natural key.
131: *
132: * @param modifierKeys
133: * the set of modifier keys. This set may be empty, but it must
134: * not be <code>null</code>. If this set is not empty, it
135: * must only contain instances of <code>ModifierKey</code>.
136: * @param naturalKey
137: * the natural key. May be <code>null</code>.
138: * @return a key stroke. Guaranteed not to be <code>null</code>.
139: */
140: public static KeyStroke getInstance(SortedSet modifierKeys,
141: NaturalKey naturalKey) {
142: return new KeyStroke(modifierKeys, naturalKey);
143: }
144:
145: /**
146: * Gets an instance of <code>KeyStroke</code> by parsing a given a formal
147: * string representation.
148: *
149: * @param string
150: * the formal string representation to parse.
151: * @return a key stroke. Guaranteed not to be <code>null</code>.
152: * @throws ParseException
153: * if the given formal string representation could not be
154: * parsed to a valid key stroke.
155: */
156: public static KeyStroke getInstance(String string)
157: throws ParseException {
158: if (string == null) {
159: throw new NullPointerException();
160: }
161:
162: SortedSet modifierKeys = new TreeSet();
163: NaturalKey naturalKey = null;
164: StringTokenizer stringTokenizer = new StringTokenizer(string,
165: KEY_DELIMITERS, true);
166: int i = 0;
167:
168: while (stringTokenizer.hasMoreTokens()) {
169: String token = stringTokenizer.nextToken();
170:
171: if (i % 2 == 0) {
172: if (stringTokenizer.hasMoreTokens()) {
173: token = token.toUpperCase();
174: ModifierKey modifierKey = (ModifierKey) ModifierKey.modifierKeysByName
175: .get(token);
176:
177: if (modifierKey == null
178: || !modifierKeys.add(modifierKey)) {
179: throw new ParseException(
180: "Cannot create key stroke with duplicate or non-existent modifier key: " //$NON-NLS-1$
181: + token);
182: }
183: } else if (token.length() == 1) {
184: naturalKey = CharacterKey.getInstance(token
185: .charAt(0));
186: break;
187: } else {
188: token = token.toUpperCase();
189: naturalKey = (NaturalKey) CharacterKey.characterKeysByName
190: .get(token);
191:
192: if (naturalKey == null) {
193: naturalKey = (NaturalKey) SpecialKey.specialKeysByName
194: .get(token);
195: }
196:
197: if (naturalKey == null) {
198: throw new ParseException(
199: "Cannot create key stroke with invalid natural key: " //$NON-NLS-1$
200: + token);
201: }
202: }
203: }
204:
205: i++;
206: }
207:
208: try {
209: return new KeyStroke(modifierKeys, naturalKey);
210: } catch (Throwable t) {
211: throw new ParseException("Cannot create key stroke with " //$NON-NLS-1$
212: + modifierKeys + " and " + naturalKey); //$NON-NLS-1$
213: }
214: }
215:
216: /**
217: * The cached hash code for this object. Because <code>KeyStroke</code>
218: * objects are immutable, their hash codes need only to be computed once.
219: * After the first call to <code>hashCode()</code>, the computed value
220: * is cached here for all subsequent calls.
221: */
222: private transient int hashCode;
223:
224: /**
225: * A flag to determine if the <code>hashCode</code> field has already
226: * been computed.
227: */
228: private transient boolean hashCodeComputed;
229:
230: /**
231: * The set of modifier keys for this key stroke.
232: */
233: private SortedSet modifierKeys;
234:
235: /**
236: * The set of modifier keys for this key stroke in the form of an array.
237: * Used internally by <code>int compareTo(Object)</code>.
238: */
239: private transient ModifierKey[] modifierKeysAsArray;
240:
241: /**
242: * The natural key for this key stroke.
243: */
244: private NaturalKey naturalKey;
245:
246: /**
247: * Constructs an instance of <code>KeyStroke</code> given a set of
248: * modifier keys and a natural key.
249: *
250: * @param modifierKeys
251: * the set of modifier keys. This set may be empty, but it must
252: * not be <code>null</code>. If this set is not empty, it
253: * must only contain instances of <code>ModifierKey</code>.
254: * @param naturalKey
255: * the natural key. May be <code>null</code>.
256: */
257: private KeyStroke(SortedSet modifierKeys, NaturalKey naturalKey) {
258: this .modifierKeys = Util.safeCopy(modifierKeys,
259: ModifierKey.class);
260: this .naturalKey = naturalKey;
261: this .modifierKeysAsArray = (ModifierKey[]) this .modifierKeys
262: .toArray(new ModifierKey[this .modifierKeys.size()]);
263: }
264:
265: /**
266: * @see java.lang.Comparable#compareTo(java.lang.Object)
267: */
268: public int compareTo(Object object) {
269: KeyStroke castedObject = (KeyStroke) object;
270: int compareTo = Util.compare(modifierKeysAsArray,
271: castedObject.modifierKeysAsArray);
272:
273: if (compareTo == 0) {
274: compareTo = Util.compare(naturalKey,
275: castedObject.naturalKey);
276: }
277:
278: return compareTo;
279: }
280:
281: /**
282: * @see java.lang.Object#equals(java.lang.Object)
283: */
284: public boolean equals(Object object) {
285: if (!(object instanceof KeyStroke)) {
286: return false;
287: }
288:
289: KeyStroke castedObject = (KeyStroke) object;
290:
291: if (!modifierKeys.equals(castedObject.modifierKeys)) {
292: return false;
293: }
294: return Util.equals(naturalKey, castedObject.naturalKey);
295: }
296:
297: /**
298: * Formats this key stroke into the current default look.
299: *
300: * @return A string representation for this key stroke using the default
301: * look; never <code>null</code>.
302: */
303: public String format() {
304: return KeyFormatterFactory.getDefault().format(this );
305: }
306:
307: /**
308: * Returns the set of modifier keys for this key stroke.
309: *
310: * @return the set of modifier keys. This set may be empty, but is
311: * guaranteed not to be <code>null</code>. If this set is not
312: * empty, it is guaranteed to only contain instances of <code>ModifierKey</code>.
313: */
314: public Set getModifierKeys() {
315: return Collections.unmodifiableSet(modifierKeys);
316: }
317:
318: /**
319: * Returns the natural key for this key stroke.
320: *
321: * @return the natural key. May be <code>null</code>.
322: */
323: public NaturalKey getNaturalKey() {
324: return naturalKey;
325: }
326:
327: /**
328: * @see java.lang.Object#hashCode()
329: */
330: public int hashCode() {
331: if (!hashCodeComputed) {
332: hashCode = HASH_INITIAL;
333: hashCode = hashCode * HASH_FACTOR + modifierKeys.hashCode();
334: hashCode = hashCode * HASH_FACTOR
335: + Util.hashCode(naturalKey);
336: hashCodeComputed = true;
337: }
338:
339: return hashCode;
340: }
341:
342: /**
343: * Returns whether or not this key stroke is complete. Key strokes are
344: * complete iff they have a natural key which is not <code>null</code>.
345: *
346: * @return <code>true</code>, iff the key stroke is complete.
347: */
348: public boolean isComplete() {
349: return naturalKey != null;
350: }
351:
352: /**
353: * Returns the formal string representation for this key stroke.
354: *
355: * @return The formal string representation for this key stroke. Guaranteed
356: * not to be <code>null</code>.
357: * @see java.lang.Object#toString()
358: */
359: public String toString() {
360: return KeyFormatterFactory.getFormalKeyFormatter().format(this);
361: }
362: }
|