001: /*BEGIN_COPYRIGHT_BLOCK
002: *
003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are met:
008: * * Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.
010: * * Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014: * names of its contributors may be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: *
029: * This software is Open Source Initiative approved Open Source Software.
030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
031: *
032: * This file is part of DrJava. Download the current version of this project
033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034: *
035: * END_COPYRIGHT_BLOCK*/
036:
037: package edu.rice.cs.drjava.config;
038:
039: import edu.rice.cs.drjava.platform.PlatformFactory;
040: import edu.rice.cs.util.UnexpectedException;
041: import java.lang.reflect.Field;
042: import javax.swing.KeyStroke;
043: import java.awt.event.KeyEvent;
044: import java.awt.Event;
045: import java.util.Hashtable;
046:
047: /** Class representing all configuration options with values of type KeyStroke. Only runs in the event thread, so no
048: * synchronization is necessary (or advisable).*/
049: public class KeyStrokeOption extends Option<KeyStroke> {
050:
051: /** Storage for keystrokes.*/
052: static Hashtable<Integer, String> keys = new Hashtable<Integer, String>();
053: public static final KeyStroke NULL_KEYSTROKE = KeyStroke
054: .getKeyStroke(0, 0);
055:
056: /** Standard constructor
057: * @param key The name of this option.
058: */
059: public KeyStrokeOption(String key, KeyStroke def) {
060: super (key, def);
061: }
062:
063: // This sets up the hashtable that has key-value pairs consisting of
064: // ascii codes and Strings that describe the ascii character and are
065: // in the form that KeyStroke.getKeyStroke(String s) requires.
066: static {
067: try {
068: Field[] fields = KeyEvent.class.getFields();
069: for (int i = 0; i < fields.length; i++) {
070: Field currfield = fields[i];
071: String name = currfield.getName();
072: if (name.startsWith("VK_")) {
073: keys.put(new Integer(currfield.getInt(null)), name
074: .substring(3));
075: }
076: }
077: } catch (IllegalAccessException iae) {
078: throw new UnexpectedException(iae);
079: }
080: }
081:
082: /** @param s The String to be parsed, must be the string representation of
083: * the KeyStroke to be created. Uses the method KeyStroke.getKeyStroke(String s)
084: * which returns a KeyStroke if the string is correctly formatted or null
085: * otherwise.
086: * @return The KeyStroke object corresponding to the input string "s".
087: */
088: public KeyStroke parse(String s) {
089: if (s.equals("<none>")) {
090: return NULL_KEYSTROKE;
091: }
092:
093: // Replace "command" with "meta" (OS X)
094: int cIndex = s.indexOf("command");
095: if (cIndex > -1) {
096: final StringBuilder sb = new StringBuilder(s.substring(0,
097: cIndex));
098: sb.append("meta");
099: sb.append(s.substring(cIndex + "command".length(), s
100: .length()));
101: s = sb.toString();
102: }
103:
104: // Replace "option" with "alt" (OS X)
105: int oIndex = s.indexOf("option");
106: if (oIndex > -1) {
107: final StringBuilder sb = new StringBuilder(s.substring(0,
108: oIndex));
109: sb.append("alt");
110: sb.append(s.substring(oIndex + "option".length(), s
111: .length()));
112: s = sb.toString();
113: }
114:
115: KeyStroke ks = KeyStroke.getKeyStroke(s);
116: if (ks == null) {
117: throw new OptionParseException(name, s,
118: "Must be a valid string representation of a Keystroke.");
119: }
120: return ks;
121: }
122:
123: /** @param k The instance of class KeyStroke to be formatted.
124: * @return A String representing the KeyStroke "k".
125: */
126: public String format(KeyStroke k) {
127: if (k == NULL_KEYSTROKE) {
128: return "<none>";
129: }
130:
131: // This code prints out locale specific text, which is bad!
132: // (KeyStroke.getKeystroke(s) can't parse it.)
133: /*
134: StringBuffer buf = new StringBuffer();
135: String s = KeyEvent.getKeyModifiersText(k.getModifiers()).toLowerCase();
136: s = s.replace('+', ' ');
137: if (!s.equals(""))
138: s += " ";
139: buf.append(s);
140: */
141:
142: // Generate modifiers text on our own, since getKeyStroke can't parse locale-specific modifiers.
143: int modifiers = k.getModifiers();
144: boolean isMac = PlatformFactory.ONLY.isMacPlatform();
145: final StringBuilder buf = new StringBuilder();
146: if ((modifiers & Event.META_MASK) > 0) {
147: String meta = (!isMac) ? "meta " : "command ";
148: buf.append(meta);
149: }
150: if ((modifiers & Event.CTRL_MASK) > 0) {
151: buf.append("ctrl ");
152: }
153: if ((modifiers & Event.ALT_MASK) > 0) {
154: String alt = (!isMac) ? "alt " : "option ";
155: buf.append(alt);
156: }
157: if ((modifiers & Event.SHIFT_MASK) > 0) {
158: buf.append("shift ");
159: }
160:
161: // If the key code is undefined, this is a "typed" unicode character
162: if (k.getKeyCode() == KeyEvent.VK_UNDEFINED) {
163: buf.append("typed ");
164: buf.append(k.getKeyChar());
165: }
166: // else this corresponds to a static KeyEvent constant
167: else {
168: // defaults to pressed
169: if (k.isOnKeyRelease()) {
170: buf.append("released ");
171: }
172: String key = keys.get(new Integer(k.getKeyCode()));
173: if (key == null) {
174: throw new IllegalArgumentException("Invalid keystroke");
175: }
176: if (key.equals("CONTROL") || key.equals("ALT")
177: || key.equals("META") || key.equals("SHIFT")
178: || key.equals("ALT_GRAPH")) {
179: return buf.toString();
180: } else {
181: buf.append(key);
182: return buf.toString();
183: }
184: }
185: return buf.toString();
186: }
187: }
|