1. /*
  2. * @(#)InputMap.java 1.9 00/02/02
  3. *
  4. * Copyright 1999, 2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing;
  11. import java.io.IOException;
  12. import java.io.ObjectInputStream;
  13. import java.io.ObjectOutputStream;
  14. import java.io.Serializable;
  15. import java.util.HashMap;
  16. import java.util.Set;
  17. /**
  18. * <code>InputMap</code> provides a binding between an input event
  19. * (currently only <code>KeyStroke</code>s are used)
  20. * and an <code>Object</code>. <code>InputMap</code>s
  21. * are usually used with an <code>ActionMap</code>,
  22. * to determine an <code>Action</code> to perform
  23. * when a key is pressed.
  24. * An <code>InputMap</code> can have a parent
  25. * that is searched for bindings not defined in the <code>InputMap</code>.
  26. * <p>As with <code>ActionMap</code> if you create a cycle, eg:
  27. * <pre>
  28. * InputMap am = new InputMap();
  29. * InputMap bm = new InputMap():
  30. * am.setParent(bm);
  31. * bm.setParent(am);
  32. * </pre>
  33. * some of the methods will cause a StackOverflowError to be thrown.
  34. *
  35. * @version 1.9 02/02/00
  36. * @author Scott Violet
  37. * @since 1.3
  38. */
  39. public class InputMap implements Serializable {
  40. /** Handles the mapping between KeyStroke and Action name. */
  41. private transient AbstractAction.ArrayTable arrayTable;
  42. /** Parent that handles any bindings we don't contain. */
  43. private InputMap parent;
  44. /**
  45. * Creates an <code>InputMap</code> with no parent and no mappings.
  46. */
  47. public InputMap() {
  48. }
  49. /**
  50. * Sets this <code>InputMap</code>'s parent.
  51. *
  52. * @param map the <code>InputMap</code> that is the parent of this one
  53. */
  54. public void setParent(InputMap map) {
  55. this.parent = map;
  56. }
  57. /**
  58. * Gets this <code>InputMap</code>'s parent.
  59. *
  60. * @return map the <code>InputMap</code> that is the parent of this one,
  61. * or null if this <code>InputMap</code> has no parent
  62. */
  63. public InputMap getParent() {
  64. return parent;
  65. }
  66. /**
  67. * Adds a binding for <code>keyStroke</code> to <code>actionMapKey</code>.
  68. * If <code>actionMapKey</code> is null, this removes the current binding
  69. * for <code>keyStroke</code>.
  70. */
  71. public void put(KeyStroke keyStroke, Object actionMapKey) {
  72. if (keyStroke == null) {
  73. return;
  74. }
  75. if (actionMapKey == null) {
  76. remove(keyStroke);
  77. }
  78. else {
  79. if (arrayTable == null) {
  80. arrayTable = new AbstractAction.ArrayTable();
  81. }
  82. arrayTable.put(keyStroke, actionMapKey);
  83. }
  84. }
  85. /**
  86. * Returns the binding for <code>keyStroke</code>, messaging the
  87. * parent <code>InputMap</code> if the binding is not locally defined.
  88. */
  89. public Object get(KeyStroke keyStroke) {
  90. if (arrayTable == null) {
  91. InputMap parent = getParent();
  92. if (parent != null) {
  93. return parent.get(keyStroke);
  94. }
  95. return null;
  96. }
  97. Object value = arrayTable.get(keyStroke);
  98. if (value == null) {
  99. InputMap parent = getParent();
  100. if (parent != null) {
  101. return parent.get(keyStroke);
  102. }
  103. }
  104. return value;
  105. }
  106. /**
  107. * Removes the binding for <code>key</code> from this
  108. * <code>InputMap</code>.
  109. */
  110. public void remove(KeyStroke key) {
  111. if (arrayTable != null) {
  112. arrayTable.remove(key);
  113. }
  114. }
  115. /**
  116. * Removes all the mappings from this <code>InputMap</code>.
  117. */
  118. public void clear() {
  119. if (arrayTable != null) {
  120. arrayTable.clear();
  121. }
  122. }
  123. /**
  124. * Returns the <code>KeyStroke</code>s that are bound in this <code>InputMap</code>.
  125. */
  126. public KeyStroke[] keys() {
  127. if (arrayTable == null) {
  128. return null;
  129. }
  130. KeyStroke[] keys = new KeyStroke[arrayTable.size()];
  131. arrayTable.getKeys(keys);
  132. return keys;
  133. }
  134. /**
  135. * Returns the number of <code>KeyStroke</code> bindings.
  136. */
  137. public int size() {
  138. if (arrayTable == null) {
  139. return 0;
  140. }
  141. return arrayTable.size();
  142. }
  143. /**
  144. * Returns an array of the <code>KeyStroke</code>s defined in this
  145. * <code>InputMap</code> and its parent. This differs from <code>keys()</code> in that
  146. * this method includes the keys defined in the parent.
  147. */
  148. public KeyStroke[] allKeys() {
  149. int count = size();
  150. InputMap parent = getParent();
  151. if (count == 0) {
  152. if (parent != null) {
  153. return parent.allKeys();
  154. }
  155. return keys();
  156. }
  157. if (parent == null) {
  158. return keys();
  159. }
  160. KeyStroke[] keys = keys();
  161. KeyStroke[] pKeys = parent.allKeys();
  162. if (pKeys == null) {
  163. return keys;
  164. }
  165. if (keys == null) {
  166. // Should only happen if size() != keys.length, which should only
  167. // happen if mutated from multiple threads (or a bogus subclass).
  168. return pKeys;
  169. }
  170. HashMap keyMap = new HashMap();
  171. int counter;
  172. for (counter = keys.length - 1; counter >= 0; counter--) {
  173. keyMap.put(keys[counter], keys[counter]);
  174. }
  175. for (counter = pKeys.length - 1; counter >= 0; counter--) {
  176. keyMap.put(pKeys[counter], pKeys[counter]);
  177. }
  178. KeyStroke[] allKeys = new KeyStroke[keyMap.size()];
  179. return (KeyStroke[])keyMap.keySet().toArray(allKeys);
  180. }
  181. private void writeObject(ObjectOutputStream s) throws IOException {
  182. s.defaultWriteObject();
  183. KeyStroke[] keys = keys();
  184. // Determine valid count
  185. int validCount = 0;
  186. if (keys != null) {
  187. for(int counter = 0; counter < keys.length; counter++) {
  188. Object value = get(keys[counter]);
  189. if (value instanceof Serializable) {
  190. validCount++;
  191. }
  192. else {
  193. keys[counter] = null;
  194. }
  195. }
  196. }
  197. s.writeInt(validCount);
  198. int counter = 0;
  199. while (validCount > 0) {
  200. if (keys[counter] != null) {
  201. s.writeObject(keys[counter]);
  202. s.writeObject(get(keys[counter]));
  203. validCount--;
  204. }
  205. counter++;
  206. }
  207. }
  208. private void readObject(ObjectInputStream s) throws ClassNotFoundException,
  209. IOException {
  210. s.defaultReadObject();
  211. for (int counter = s.readInt() - 1; counter >= 0; counter--) {
  212. put((KeyStroke)s.readObject(), s.readObject());
  213. }
  214. }
  215. }