1 19 20 package org.netbeans.editor; 21 22 import java.awt.event.KeyEvent ; 23 import java.awt.event.ActionEvent ; 24 import java.awt.event.InputEvent ; 25 import java.util.ArrayList ; 26 import java.util.Iterator ; 27 import java.util.List ; 28 import java.util.Map ; 29 import java.util.HashMap ; 30 import javax.swing.text.Keymap ; 31 import javax.swing.text.JTextComponent ; 32 import javax.swing.text.DefaultEditorKit ; 33 import javax.swing.KeyStroke ; 34 import javax.swing.Action ; 35 import javax.swing.AbstractAction ; 36 import org.openide.awt.StatusDisplayer; 37 import org.openide.util.Lookup; 38 39 45 46 public class MultiKeymap implements Keymap { 47 48 private static final boolean compatibleIgnoreNextTyped 49 = Boolean.getBoolean("netbeans.editor.keymap.compatible"); 50 51 52 public static final Action EMPTY_ACTION = new AbstractAction () { 53 public void actionPerformed(ActionEvent evt) { 54 } 55 }; 56 57 58 public static final Action BEEP_ACTION = new DefaultEditorKit.BeepAction (); 59 60 61 private Keymap delegate; 62 63 64 private Keymap context; 65 66 67 private boolean ignoreNextTyped = false; 68 69 73 private Action contextKeyNotFoundAction = BEEP_ACTION; 74 75 83 private List contextKeys; 84 85 88 public MultiKeymap(String name) { 89 delegate = JTextComponent.addKeymap(name, null); 90 contextKeys = new ArrayList (); 91 } 92 93 94 void setContext(Keymap contextKeymap) { 95 context = contextKeymap; 96 } 97 98 private static String getKeyText (KeyStroke keyStroke) { 99 if (keyStroke == null) return ""; String modifText = KeyEvent.getKeyModifiersText 101 (keyStroke.getModifiers ()); 102 if ("".equals (modifText)) return KeyEvent.getKeyText (keyStroke.getKeyCode ()); 104 return modifText + "+" + KeyEvent.getKeyText (keyStroke.getKeyCode ()); 106 } 107 108 109 public void resetContext() { 110 context = null; 111 contextKeys.clear(); 112 } 113 114 119 private void shiftGlobalContext(KeyStroke key) { 120 List globalContextList = getGlobalContextList(); 121 if (globalContextList != null) { 122 globalContextList.add(key); 123 124 StringBuffer text = new StringBuffer (); 125 for (Iterator it = globalContextList.iterator(); it.hasNext();) { 126 text.append(getKeyText((KeyStroke )it.next())).append(' '); 127 } 128 StatusDisplayer.getDefault().setStatusText(text.toString()); 129 } 130 contextKeys.add(key); 132 } 133 134 137 private void resetGlobalContext() { 138 List globalContextList = getGlobalContextList(); 139 if (globalContextList != null) { 140 globalContextList.clear(); 141 StatusDisplayer.getDefault().setStatusText(""); 142 } 143 } 144 145 private List getGlobalContextList() { 146 List globalContextList; 149 try { 150 ClassLoader sysCL = (ClassLoader )Lookup.getDefault().lookup(ClassLoader .class); 151 Class nbKeymapClass = Class.forName("org.netbeans.core.NbKeymap", true, sysCL); java.lang.reflect.Field contextField = nbKeymapClass.getDeclaredField("context"); contextField.setAccessible(true); 154 globalContextList = (List )contextField.get(null); 155 } catch (Exception e) { 156 globalContextList = null; 158 } 159 return globalContextList; 160 } 161 162 163 public void setContextKeyNotFoundAction(Action a) { 164 contextKeyNotFoundAction = a; 165 } 166 167 172 public void load(JTextComponent.KeyBinding [] bindings, Action [] actions) { 173 Map h = new HashMap (bindings.length); 174 for (int i = 0; i < actions.length; i++) { 176 Action a = actions[i]; 177 String value = (String )a.getValue(Action.NAME); 178 h.put((value != null ? value : ""), a); } 180 load(bindings, h); 181 } 182 183 187 public void load(JTextComponent.KeyBinding [] bindings, Map actions) { 188 for (int i = 0; i < bindings.length; i++) { 190 Action a = (Action )actions.get(bindings[i].actionName); 191 if (a != null) { 192 boolean added = false; 193 if (bindings[i] instanceof MultiKeyBinding) { 194 MultiKeyBinding mb = (MultiKeyBinding)bindings[i]; 195 if (mb.keys != null) { 196 Keymap cur = delegate; 197 for (int j = 0; j < mb.keys.length; j++) { 198 if (j == mb.keys.length - 1) { cur.addActionForKeyStroke(mb.keys[j], a); 200 } else { Action sca = cur.getAction(mb.keys[j]); 202 if (!(sca instanceof KeymapSetContextAction)) { 203 sca = new KeymapSetContextAction(JTextComponent.addKeymap(null, null)); 204 cur.addActionForKeyStroke(mb.keys[j], sca); 205 } 206 cur = ((KeymapSetContextAction)sca).contextKeymap; 207 } 208 } 209 added = true; 210 } 211 } 212 if (!added) { 213 if (bindings[i].key != null) { 214 delegate.addActionForKeyStroke(bindings[i].key, a); 215 } else { setDefaultAction(a); 217 } 218 } 219 } 220 } 221 } 222 223 public String getName() { 224 return (context != null) ? context.getName() 225 : delegate.getName(); 226 } 227 228 232 public Action getDefaultAction() { 233 return delegate.getDefaultAction(); 234 } 235 236 public void setDefaultAction(Action a) { 237 if (context != null) { 238 context.setDefaultAction(a); 239 } else { 240 delegate.setDefaultAction(a); 241 } 242 } 243 244 private Action getActionImpl(KeyStroke key) { 245 Action a = null; 246 if (context != null) { 247 a = context.getAction(key); 248 266 } else { 267 a = delegate.getAction(key); 268 } 269 270 return a; 271 } 272 273 private boolean contextKeysEqual(List keys) { 274 if (keys.size() != contextKeys.size()) { 275 return false; 276 } 277 for (int i = keys.size() - 1; i >= 0; i--) { 278 if (!contextKeys.get(i).equals(keys.get(i))) { 279 return false; 280 } 281 } 282 return true; 283 } 284 285 public Action getAction(KeyStroke key) { 286 Action ret = null; 287 288 List globalContextList = getGlobalContextList(); 292 if (globalContextList != null && globalContextList.size() > 0 && !contextKeysEqual(globalContextList)) { 293 resetContext(); 294 int i; 295 for (i = 0; i < globalContextList.size(); i++) { 296 Action a = getActionImpl((KeyStroke )globalContextList.get(i)); 297 if (a instanceof KeymapSetContextAction) { 298 a.actionPerformed(null); 299 } else { 300 resetContext(); 302 break; 303 } 304 } 305 if (i != globalContextList.size()) { return null; 307 } 308 } 309 310 if (ignoreNextTyped) { 312 if (key.isOnKeyRelease()) { ret = EMPTY_ACTION; 314 } else { ignoreNextTyped = false; 316 } 317 if (key.getKeyChar() != 0 && key.getKeyChar() != KeyEvent.CHAR_UNDEFINED) { 318 ret = EMPTY_ACTION; } 320 } 321 322 if (ret == null) { 323 ret = getActionImpl(key); 324 if (ret instanceof KeymapSetContextAction) { shiftGlobalContext(key); 327 328 } else { if (context != null) { ignoreNextTyped = true; 331 332 } else if (compatibleIgnoreNextTyped) { 333 if ( (key.getModifiers() & InputEvent.ALT_MASK) != 0 && (key.getModifiers() & InputEvent.CTRL_MASK) == 0 ) { 338 boolean patch = true; 339 if (key.getKeyChar() == 0 || key.getKeyChar() == KeyEvent.CHAR_UNDEFINED) { 340 switch (key.getKeyCode()) { 341 case KeyEvent.VK_ALT: case KeyEvent.VK_KANJI: 343 case KeyEvent.VK_KATAKANA: 344 case KeyEvent.VK_HIRAGANA: 345 case KeyEvent.VK_JAPANESE_KATAKANA: 346 case KeyEvent.VK_JAPANESE_HIRAGANA: 347 case 0x0107: case KeyEvent.VK_NUMPAD0: case KeyEvent.VK_NUMPAD1: 350 case KeyEvent.VK_NUMPAD2: 351 case KeyEvent.VK_NUMPAD3: 352 case KeyEvent.VK_NUMPAD4: 353 case KeyEvent.VK_NUMPAD5: 354 case KeyEvent.VK_NUMPAD6: 355 case KeyEvent.VK_NUMPAD7: 356 case KeyEvent.VK_NUMPAD8: 357 case KeyEvent.VK_NUMPAD9: 358 patch = false; 359 break; 360 } 361 } 362 363 if (patch) { 364 ignoreNextTyped = true; 365 } 366 } else if ((key.getModifiers() & InputEvent.META_MASK) != 0) { ignoreNextTyped = true; 368 } else if ((key.getModifiers() & InputEvent.CTRL_MASK) != 0 && 369 (key.getModifiers() & InputEvent.SHIFT_MASK) != 0 && 370 (key.getKeyCode() == KeyEvent.VK_ADD || key.getKeyCode() == KeyEvent.VK_SUBTRACT)) { 371 ignoreNextTyped = true; 373 } 374 } 375 376 resetContext(); } 381 382 if (context != null && ret == null) { } 386 } 387 388 if (ret != null && !(ret instanceof KeymapSetContextAction) && (ret != EMPTY_ACTION)) { 390 resetGlobalContext(); 391 } 392 393 if (compatibleIgnoreNextTyped) { 394 if (key == KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.CTRL_MASK)) { 397 ignoreNextTyped = true; 398 } 399 } 400 401 406 407 return ret; 408 } 409 410 public KeyStroke [] getBoundKeyStrokes() { 411 return (context != null) ? context.getBoundKeyStrokes() 412 : delegate.getBoundKeyStrokes(); 413 } 414 415 public Action [] getBoundActions() { 416 return (context != null) ? context.getBoundActions() 417 : delegate.getBoundActions(); 418 } 419 420 public KeyStroke [] getKeyStrokesForAction(Action a) { 421 return (context != null) ? context.getKeyStrokesForAction(a) 422 : delegate.getKeyStrokesForAction(a); 423 } 424 425 public boolean isLocallyDefined(KeyStroke key) { 426 return (context != null) ? context.isLocallyDefined(key) 427 : delegate.isLocallyDefined(key); 428 } 429 430 public void addActionForKeyStroke(KeyStroke key, Action a) { 431 if (context != null) { 432 context.addActionForKeyStroke(key, a); 433 } else { 434 delegate.addActionForKeyStroke(key, a); 435 } 436 } 437 438 public void removeKeyStrokeBinding(KeyStroke key) { 439 if (context != null) { 440 context.removeKeyStrokeBinding(key); 441 } else { 442 delegate.removeKeyStrokeBinding(key); 443 } 444 } 445 446 public void removeBindings() { 447 if (context != null) { 448 context.removeBindings(); 449 } else { 450 delegate.removeBindings(); 451 } 452 } 453 454 public Keymap getResolveParent() { 455 return (context != null) ? context.getResolveParent() 456 : delegate.getResolveParent(); 457 } 458 459 public void setResolveParent(Keymap parent) { 460 if (context != null) { 461 context.setResolveParent(parent); 462 } else { 463 delegate.setResolveParent(parent); 464 } 465 } 466 467 public String toString() { 468 return "MK: name=" + getName(); } 470 471 472 class KeymapSetContextAction extends AbstractAction { 473 474 Keymap contextKeymap; 475 476 static final long serialVersionUID =1034848289049566148L; 477 478 KeymapSetContextAction(Keymap contextKeymap) { 479 this.contextKeymap = contextKeymap; 480 } 481 482 public void actionPerformed(ActionEvent evt) { 483 setContext(contextKeymap); 484 } 485 486 } 487 488 } 489 | Popular Tags |