1 19 20 package org.netbeans.core; 21 22 import java.awt.event.KeyEvent ; 23 import java.util.ArrayList ; 24 import java.util.Arrays ; 25 import java.util.Collections ; 26 import java.util.Comparator ; 27 import java.util.HashMap ; 28 import java.util.HashSet ; 29 import java.util.Iterator ; 30 import java.util.List ; 31 import java.util.Map ; 32 import java.util.Map.Entry; 33 import java.util.Observable ; 34 import java.util.Set ; 35 import javax.swing.Action ; 36 import javax.swing.KeyStroke ; 37 import javax.swing.text.Keymap ; 38 import org.openide.awt.StatusDisplayer; 39 import org.openide.util.Mutex; 40 41 45 public final class NbKeymap extends Observable implements Keymap , Comparator <KeyStroke > { 46 47 String name; 48 49 Keymap parent; 50 51 Map <KeyStroke ,Action > bindings; 52 53 Action defaultAction; 54 55 Map <Action ,List <KeyStroke >> actions; 56 57 private static List <KeyStroke > context = new ArrayList <KeyStroke >(); 58 59 public static void resetContext() { 60 context.clear(); 61 StatusDisplayer.getDefault().setStatusText(""); 62 } 63 64 public static KeyStroke [] getContext() { 65 return (KeyStroke []) context.toArray(new KeyStroke [context.size()]); 66 } 67 68 public static void shiftContext(KeyStroke stroke) { 69 context.add(stroke); 70 71 StringBuilder text = new StringBuilder (); 72 for (KeyStroke ks: context) { 73 text.append(getKeyText(ks)).append(' '); 74 } 75 StatusDisplayer.getDefault().setStatusText(text.toString()); 76 } 77 78 private static String getKeyText (KeyStroke keyStroke) { 79 if (keyStroke == null) return ""; 80 String modifText = KeyEvent.getKeyModifiersText 81 (keyStroke.getModifiers ()); 82 if ("".equals (modifText)) 83 return KeyEvent.getKeyText (keyStroke.getKeyCode ()); 84 return modifText + "+" + KeyEvent.getKeyText (keyStroke.getKeyCode ()); 86 } 87 88 private final Action NO_ACTION = new KeymapAction(null, null); 89 90 public Action createMapAction(Keymap k, KeyStroke stroke) { 91 return new KeymapAction(k, stroke); 92 } 93 94 96 public NbKeymap() { 97 this("Default", null); } 99 100 NbKeymap(final String name, final Keymap parent) { 101 this.name = name; 102 this.parent = parent; 103 bindings = new HashMap <KeyStroke ,Action >(); 104 } 105 106 public Action getDefaultAction() { 107 if (defaultAction != null) { 108 return defaultAction; 109 } 110 return (parent != null) ? parent.getDefaultAction() : null; 111 } 112 113 public void setDefaultAction(Action a) { 114 defaultAction = a; 115 setChanged(); 116 notifyObservers(); 117 } 118 119 public String getName() { 120 return name; 121 } 122 123 public Action getAction(KeyStroke key) { 124 Action a; 125 126 KeyStroke [] ctx = getContext(); 127 Keymap activ = this; 128 for (int i=0; i<ctx.length; i++) { 129 if (activ == this) { 130 a = bindings.get(ctx[i]); 131 if ((a == null) && (parent != null)) { 132 a = parent.getAction(ctx[i]); 133 } 134 } else { 135 a = activ.getAction(ctx[i]); 136 } 137 138 if (a instanceof KeymapAction) { 139 activ = ((KeymapAction)a).keymap; 140 } else { int code = key.getKeyCode(); 142 if (code != KeyEvent.VK_CONTROL && 143 code != KeyEvent.VK_ALT && 144 code != KeyEvent.VK_ALT_GRAPH && 145 code != KeyEvent.VK_SHIFT && 146 code != KeyEvent.VK_META) resetContext(); 147 return null; 148 } 149 } 150 151 if (activ == this) { 152 a = bindings.get(key); 153 if ((a == null) && (parent != null)) { 154 a = parent.getAction(key); 155 } 156 return a; 157 } else { 158 a = activ.getAction(key); 159 } 160 161 if (a != null) { 162 if (!(a instanceof KeymapAction)) { 163 resetContext(); 164 } 165 return a; 166 } 167 168 if (key.isOnKeyRelease() || 170 (key.getKeyChar() != 0 && key.getKeyChar() != KeyEvent.CHAR_UNDEFINED)) { 171 return null; 172 } 173 174 switch (key.getKeyCode()) { 175 case KeyEvent.VK_SHIFT: 176 case KeyEvent.VK_CONTROL: 177 case KeyEvent.VK_ALT: 178 case KeyEvent.VK_META: 179 return null; 180 default: 181 resetContext(); 182 return NO_ACTION; 183 } 184 } 185 186 public KeyStroke [] getBoundKeyStrokes() { 187 int i = 0; 188 KeyStroke [] keys = null; 189 synchronized (this) { 190 keys = new KeyStroke [bindings.size()]; 191 for (KeyStroke ks: bindings.keySet()) { 192 keys[i++] = ks; 193 } 194 } 195 return keys; 196 } 197 198 public Action [] getBoundActions() { 199 int i = 0; 200 Action [] actionsArray = null; 201 synchronized (this) { 202 actionsArray = new Action [bindings.size()]; 203 for (Iterator iter = bindings.values().iterator(); iter.hasNext(); ) { 204 actionsArray[i++] = (Action ) iter.next(); 205 } 206 } 207 return actionsArray; 208 } 209 210 public KeyStroke [] getKeyStrokesForAction(Action a) { 211 Map <Action ,List <KeyStroke >> localActions = actions; 212 if (localActions == null) { 213 localActions = buildReverseMapping (); 214 } 215 216 List <KeyStroke > strokes = localActions.get (a); 217 if (strokes != null) { 218 return strokes.toArray(new KeyStroke [strokes.size ()]); 219 } else { 220 return new KeyStroke [0]; 221 } 222 } 223 224 private Map <Action ,List <KeyStroke >> buildReverseMapping () { 225 Map <Action ,List <KeyStroke >> localActions = actions = new HashMap <Action ,List <KeyStroke >> (); 226 227 synchronized (this) { 228 for (Map.Entry <KeyStroke ,Action > curEntry: bindings.entrySet()) { 229 Action curAction = curEntry.getValue(); 230 KeyStroke curKey = curEntry.getKey(); 231 232 List <KeyStroke > keysForAction = localActions.get (curAction); 233 if (keysForAction == null) { 234 keysForAction = Collections.synchronizedList (new ArrayList <KeyStroke > (1)); 235 localActions.put (curAction, keysForAction); 236 } 237 keysForAction.add (curKey); 238 } 239 } 240 241 return localActions; 242 } 243 244 public synchronized boolean isLocallyDefined(KeyStroke key) { 245 return bindings.containsKey(key); 246 } 247 248 249 private void updateActionAccelerator(final Action a) { 250 if(a == null) { 251 return; 252 } 253 254 Mutex.EVENT.writeAccess(new Runnable () { 255 public void run() { 256 KeyStroke [] keystrokes = getKeyStrokesForAction(a); 257 Arrays.sort (keystrokes, NbKeymap.this); 258 a.putValue(Action.ACCELERATOR_KEY, keystrokes.length > 0 ? keystrokes[0] : null); 259 } 260 }); 261 } 262 263 public int compare(KeyStroke k1, KeyStroke k2) { 264 return KeyEvent.getKeyText(k1.getKeyCode()).length() - 267 KeyEvent.getKeyText(k2.getKeyCode()).length(); 268 } 269 270 271 public void addActionForKeyStroke(KeyStroke key, Action a) { 272 Action old; 274 synchronized (this) { 275 old = bindings.put(key, a); 276 actions = null; 277 } 278 279 updateActionAccelerator(a); 280 updateActionAccelerator(old); 281 setChanged(); 282 notifyObservers(); 283 } 284 285 void addActionForKeyStrokeMap(Map <KeyStroke ,Action > map) { 286 Set <Action > actionsSet = new HashSet <Action >(); 287 synchronized (this) { 288 for (Entry<KeyStroke ,Action > entry: map.entrySet ()) { 289 KeyStroke key = entry.getKey(); 290 Action value = entry.getValue(); 291 actionsSet.add(value); 293 actionsSet.add(bindings.put(key, value)); 294 } 295 actions = null; 296 } 297 298 for(Action a: actionsSet) { 299 updateActionAccelerator(a); 300 } 301 302 setChanged(); 303 notifyObservers(); 304 } 305 306 public void removeKeyStrokeBinding(KeyStroke key) { 307 Action a; 308 synchronized (this) { 309 a = bindings.remove(key); 310 actions = null; 311 } 312 updateActionAccelerator(a); 313 setChanged(); 314 notifyObservers(); 315 } 316 317 public void removeBindings() { 318 Set <Action > actionsSet; 319 synchronized (this) { 320 actionsSet = new HashSet <Action >(bindings.values()); 321 bindings.clear(); 322 actions = null; 323 } 324 325 for(Action a: actionsSet) { 326 updateActionAccelerator(a); 327 } 328 329 setChanged(); 330 notifyObservers(); 331 } 332 333 public Keymap getResolveParent() { 334 return parent; 335 } 336 337 public void setResolveParent(Keymap parent) { 338 this.parent = parent; 339 setChanged(); 340 notifyObservers(); 341 } 342 343 345 public String toString() { 346 return "Keymap[" + name + "]" + bindings; } 348 349 public static class SubKeymap implements Keymap { 350 Object hold; 351 Keymap parent; 352 Map <KeyStroke , Action > bindings; 353 Action defaultAction; 354 355 public SubKeymap(Object hold) { 356 this.hold = hold; 357 bindings = new HashMap <KeyStroke , Action >(); 358 } 359 360 public String getName() { 361 return "name"; 362 } 363 364 public void setResolveParent(Keymap parent) { 365 this.parent = parent; 366 } 367 368 public Keymap getResolveParent() { 369 return parent; 370 } 371 372 public void addActionForKeyStroke(KeyStroke key, Action a) { 373 bindings.put(key, a); 374 } 375 376 public KeyStroke [] getKeyStrokesForAction(Action a) { 377 return new KeyStroke [0]; 378 } 379 380 public void setDefaultAction(Action a) { 381 defaultAction = a; 382 } 383 384 public Action getAction(KeyStroke key) { 385 return bindings.get(key); 386 } 387 388 public boolean isLocallyDefined(KeyStroke key) { 389 return bindings.containsKey(key); 390 } 391 392 public void removeKeyStrokeBinding(KeyStroke keys) { 393 bindings.remove(keys); 394 } 395 396 public Action [] getBoundActions() { 397 synchronized (this) { 398 return bindings.values().toArray(new Action [0]); 399 } 400 } 401 402 public KeyStroke [] getBoundKeyStrokes() { 403 synchronized (this) { 404 return bindings.keySet().toArray(new KeyStroke [0]); 405 } 406 } 407 408 public Action getDefaultAction() { 409 return defaultAction; 410 } 411 412 public void removeBindings() { 413 bindings.clear(); 414 } 415 416 } 417 418 public static class KeymapAction extends javax.swing.AbstractAction { 419 private Keymap keymap; 420 private KeyStroke stroke; 421 422 public KeymapAction(Keymap keymap, KeyStroke stroke) { 423 this.keymap = keymap; 424 this.stroke = stroke; 425 } 426 427 public Keymap getSubMap() { 428 return keymap; 429 } 430 431 public void actionPerformed(java.awt.event.ActionEvent e) { 432 if (stroke == null) { resetContext(); 434 } else { 435 shiftContext(stroke); 436 } 437 } 438 } 439 } 440 | Popular Tags |