001 /*
002 * Copyright 1999-2003 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025 package javax.swing;
026
027 import java.io.IOException;
028 import java.io.ObjectInputStream;
029 import java.io.ObjectOutputStream;
030 import java.io.Serializable;
031 import java.util.HashMap;
032 import java.util.Set;
033
034 /**
035 * <code>InputMap</code> provides a binding between an input event
036 * (currently only <code>KeyStroke</code>s are used)
037 * and an <code>Object</code>. <code>InputMap</code>s
038 * are usually used with an <code>ActionMap</code>,
039 * to determine an <code>Action</code> to perform
040 * when a key is pressed.
041 * An <code>InputMap</code> can have a parent
042 * that is searched for bindings not defined in the <code>InputMap</code>.
043 * <p>As with <code>ActionMap</code> if you create a cycle, eg:
044 * <pre>
045 * InputMap am = new InputMap();
046 * InputMap bm = new InputMap():
047 * am.setParent(bm);
048 * bm.setParent(am);
049 * </pre>
050 * some of the methods will cause a StackOverflowError to be thrown.
051 *
052 * @version 1.21 05/05/07
053 * @author Scott Violet
054 * @since 1.3
055 */
056 public class InputMap implements Serializable {
057 /** Handles the mapping between KeyStroke and Action name. */
058 private transient ArrayTable arrayTable;
059 /** Parent that handles any bindings we don't contain. */
060 private InputMap parent;
061
062 /**
063 * Creates an <code>InputMap</code> with no parent and no mappings.
064 */
065 public InputMap() {
066 }
067
068 /**
069 * Sets this <code>InputMap</code>'s parent.
070 *
071 * @param map the <code>InputMap</code> that is the parent of this one
072 */
073 public void setParent(InputMap map) {
074 this .parent = map;
075 }
076
077 /**
078 * Gets this <code>InputMap</code>'s parent.
079 *
080 * @return map the <code>InputMap</code> that is the parent of this one,
081 * or null if this <code>InputMap</code> has no parent
082 */
083 public InputMap getParent() {
084 return parent;
085 }
086
087 /**
088 * Adds a binding for <code>keyStroke</code> to <code>actionMapKey</code>.
089 * If <code>actionMapKey</code> is null, this removes the current binding
090 * for <code>keyStroke</code>.
091 */
092 public void put(KeyStroke keyStroke, Object actionMapKey) {
093 if (keyStroke == null) {
094 return;
095 }
096 if (actionMapKey == null) {
097 remove(keyStroke);
098 } else {
099 if (arrayTable == null) {
100 arrayTable = new ArrayTable();
101 }
102 arrayTable.put(keyStroke, actionMapKey);
103 }
104 }
105
106 /**
107 * Returns the binding for <code>keyStroke</code>, messaging the
108 * parent <code>InputMap</code> if the binding is not locally defined.
109 */
110 public Object get(KeyStroke keyStroke) {
111 if (arrayTable == null) {
112 InputMap parent = getParent();
113
114 if (parent != null) {
115 return parent.get(keyStroke);
116 }
117 return null;
118 }
119 Object value = arrayTable.get(keyStroke);
120
121 if (value == null) {
122 InputMap parent = getParent();
123
124 if (parent != null) {
125 return parent.get(keyStroke);
126 }
127 }
128 return value;
129 }
130
131 /**
132 * Removes the binding for <code>key</code> from this
133 * <code>InputMap</code>.
134 */
135 public void remove(KeyStroke key) {
136 if (arrayTable != null) {
137 arrayTable.remove(key);
138 }
139 }
140
141 /**
142 * Removes all the mappings from this <code>InputMap</code>.
143 */
144 public void clear() {
145 if (arrayTable != null) {
146 arrayTable.clear();
147 }
148 }
149
150 /**
151 * Returns the <code>KeyStroke</code>s that are bound in this <code>InputMap</code>.
152 */
153 public KeyStroke[] keys() {
154 if (arrayTable == null) {
155 return null;
156 }
157 KeyStroke[] keys = new KeyStroke[arrayTable.size()];
158 arrayTable.getKeys(keys);
159 return keys;
160 }
161
162 /**
163 * Returns the number of <code>KeyStroke</code> bindings.
164 */
165 public int size() {
166 if (arrayTable == null) {
167 return 0;
168 }
169 return arrayTable.size();
170 }
171
172 /**
173 * Returns an array of the <code>KeyStroke</code>s defined in this
174 * <code>InputMap</code> and its parent. This differs from <code>keys()</code> in that
175 * this method includes the keys defined in the parent.
176 */
177 public KeyStroke[] allKeys() {
178 int count = size();
179 InputMap parent = getParent();
180
181 if (count == 0) {
182 if (parent != null) {
183 return parent.allKeys();
184 }
185 return keys();
186 }
187 if (parent == null) {
188 return keys();
189 }
190 KeyStroke[] keys = keys();
191 KeyStroke[] pKeys = parent.allKeys();
192
193 if (pKeys == null) {
194 return keys;
195 }
196 if (keys == null) {
197 // Should only happen if size() != keys.length, which should only
198 // happen if mutated from multiple threads (or a bogus subclass).
199 return pKeys;
200 }
201
202 HashMap keyMap = new HashMap();
203 int counter;
204
205 for (counter = keys.length - 1; counter >= 0; counter--) {
206 keyMap.put(keys[counter], keys[counter]);
207 }
208 for (counter = pKeys.length - 1; counter >= 0; counter--) {
209 keyMap.put(pKeys[counter], pKeys[counter]);
210 }
211
212 KeyStroke[] allKeys = new KeyStroke[keyMap.size()];
213
214 return (KeyStroke[]) keyMap.keySet().toArray(allKeys);
215 }
216
217 private void writeObject(ObjectOutputStream s) throws IOException {
218 s.defaultWriteObject();
219
220 ArrayTable.writeArrayTable(s, arrayTable);
221 }
222
223 private void readObject(ObjectInputStream s)
224 throws ClassNotFoundException, IOException {
225 s.defaultReadObject();
226 for (int counter = s.readInt() - 1; counter >= 0; counter--) {
227 put((KeyStroke) s.readObject(), s.readObject());
228 }
229 }
230 }
|