Index: ide/golden/deps.txt
===================================================================
RCS file: /cvs/ide/golden/deps.txt,v
retrieving revision 1.211
retrieving revision 1.209.2.2
diff -u -r1.211 -r1.209.2.2
--- ide/golden/deps.txt 23 Sep 2005 15:25:54 -0000 1.211
+++ ide/golden/deps.txt 30 Sep 2005 08:41:35 -0000 1.209.2.2
@@ -572,6 +572,7 @@
MODULE org.netbeans.modules.editor.lib/1 (ide)
REQUIRES org.netbeans.modules.editor.fold/1 (ide)
REQUIRES org.netbeans.modules.editor.util/1 (ide)
+ REQUIRES org.openide.awt (platform)
REQUIRES org.openide.dialogs (platform)
REQUIRES org.openide.modules.ModuleFormat1
REQUIRES org.openide.util (platform)
Index: editor/lib/nbproject/project.xml
===================================================================
RCS file: /cvs/editor/lib/nbproject/project.xml,v
retrieving revision 1.5
retrieving revision 1.5.16.1
diff -u -r1.5 -r1.5.16.1
--- editor/lib/nbproject/project.xml 4 Jun 2005 05:16:07 -0000 1.5
+++ editor/lib/nbproject/project.xml 26 Sep 2005 14:20:29 -0000 1.5.16.1
@@ -41,12 +41,20 @@
6.2
-
+
org.openide.dialogs
6.2
+
+
+
+ org.openide.awt
+
+
+
+ 6.5
Index: editor/libsrc/org/netbeans/editor/BaseKit.java
===================================================================
RCS file: /cvs/editor/libsrc/org/netbeans/editor/BaseKit.java,v
retrieving revision 1.136
retrieving revision 1.135.4.2
diff -u -r1.136 -r1.135.4.2
--- editor/libsrc/org/netbeans/editor/BaseKit.java 27 Sep 2005 15:51:45 -0000 1.136
+++ editor/libsrc/org/netbeans/editor/BaseKit.java 29 Sep 2005 14:51:05 -0000 1.135.4.2
@@ -510,6 +510,9 @@
c.putClientProperty("hyperlink-operation", // NOI18N
org.netbeans.lib.editor.hyperlink.HyperlinkOperation.create(c, getContentType()));
+
+ // Mark that the editor's multi keymap adheres to context API in status displayer
+ c.putClientProperty("context-api-aware", Boolean.TRUE);
}
protected void executeInstallActions(JEditorPane c) {
Index: editor/libsrc/org/netbeans/editor/MultiKeymap.java
===================================================================
RCS file: /cvs/editor/libsrc/org/netbeans/editor/MultiKeymap.java,v
retrieving revision 1.27
retrieving revision 1.27.76.2
diff -u -r1.27 -r1.27.76.2
--- editor/libsrc/org/netbeans/editor/MultiKeymap.java 10 Aug 2004 15:53:53 -0000 1.27
+++ editor/libsrc/org/netbeans/editor/MultiKeymap.java 27 Sep 2005 08:44:07 -0000 1.27.76.2
@@ -16,6 +16,8 @@
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import java.util.HashMap;
import javax.swing.text.Keymap;
@@ -24,6 +26,7 @@
import javax.swing.KeyStroke;
import javax.swing.Action;
import javax.swing.AbstractAction;
+import org.openide.awt.StatusDisplayer;
/**
* Keymap that is capable to work with MultiKeyBindings
@@ -60,22 +63,52 @@
* is found in base context.
*/
private Action contextKeyNotFoundAction = BEEP_ACTION;
+
+ /**
+ * List of key strokes that form the present context.
+ * If this list differs from the global context maintained in the status displayer
+ * then the keymap must be reset and attempted to be put
+ * into the global context before attempting to process the given keystroke.
+ * If the keymap cannot be put into such a context then
+ * it returns null action for the given keystroke.
+ */
+ private List contextKeys;
/** Construct new keymap.
* @param name name of new keymap
*/
public MultiKeymap(String name) {
delegate = JTextComponent.addKeymap(name, null);
+ contextKeys = new ArrayList();
}
/** Set the context keymap */
void setContext(Keymap contextKeymap) {
context = contextKeymap;
}
-
+
/** Reset keymap to base context */
public void resetContext() {
context = null;
+ contextKeys.clear();
+ }
+
+ /**
+ * Add a context key to the global context maintained by the StatusDisplayer.
+ *
+ * @param key a key to be added to the global context.
+ */
+ private void shiftGlobalContext(KeyStroke key) {
+ StatusDisplayer.getDefault().shiftContext(key);
+ // Shift the locally maintained mirror context as well
+ contextKeys.add(key);
+ }
+
+ /**
+ * Reset the global context in case there is a reason for it.
+ */
+ private void resetGlobalContext() {
+ StatusDisplayer.getDefault().resetContext();
}
/** What to do when key is not resolved for context */
@@ -160,11 +193,14 @@
}
}
- Action getActionImpl(KeyStroke key) {
+ private Action getActionImpl(KeyStroke key) {
Action a = null;
if (context != null) {
a = context.getAction(key);
- if (a == null) { // possibly ignore modifier keystrokes
+ // Commented out the next part to allow the other
+ // keystroke processors to work when the editor does not have an action
+ // for the particular keystroke.
+/* if (a == null) { // possibly ignore modifier keystrokes
switch (key.getKeyCode()) {
case KeyEvent.VK_SHIFT:
case KeyEvent.VK_CONTROL:
@@ -178,16 +214,51 @@
return EMPTY_ACTION; // ignore releasing and typed events
}
}
+ */
} else {
a = delegate.getAction(key);
}
return a;
}
+
+ private boolean contextKeysEqual(KeyStroke[] keys) {
+ if (keys.length != contextKeys.size()) {
+ return false;
+ }
+ for (int i = keys.length - 1; i >= 0; i--) {
+ if (!contextKeys.get(i).equals(keys[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
public Action getAction(KeyStroke key) {
Action ret = null;
+ // Check whether the context in status displayer corresponds to the keymap's context
+ // If there would be a non-empty SD context that differs from the editor's one
+ // then do not return any action for this keystroke.
+ KeyStroke[] globalContext = StatusDisplayer.getDefault().getContext();
+ if (globalContext.length > 0 && !contextKeysEqual(globalContext)) {
+ resetContext();
+ int i;
+ for (i = 0; i < globalContext.length; i++) {
+ Action a = getActionImpl(globalContext[i]);
+ if (a instanceof KeymapSetContextAction) {
+ a.actionPerformed(null);
+ } else {
+ // no multi-keystrokes for such context in editor
+ resetContext();
+ break;
+ }
+ }
+ if (i != globalContext.length) { // unsuccessful context switch
+ return null;
+ }
+ }
+
// Explicit patches of the keyboard problems
if (ignoreNextTyped) {
if (key.isOnKeyRelease()) { // ignore releasing here
@@ -202,60 +273,73 @@
if (ret == null) {
ret = getActionImpl(key);
- if (ret != EMPTY_ACTION) { // key that should be ignored
- if (!(ret instanceof KeymapSetContextAction)) {
- if (context != null) {
- ignoreNextTyped = true;
- } else if (compatibleIgnoreNextTyped) {
- // #44307 = disabled extra ignoreNextTyped patches for past JDKs
- if ( // Explicit patch for the keyTyped sent after Alt+key
- (key.getModifiers() & InputEvent.ALT_MASK) != 0 // Alt pressed
- && (key.getModifiers() & InputEvent.CTRL_MASK) == 0 // Ctrl not pressed
- ) {
- boolean patch = true;
- if (key.getKeyChar() == 0 || key.getKeyChar() == KeyEvent.CHAR_UNDEFINED) {
- switch (key.getKeyCode()) {
- case KeyEvent.VK_ALT: // don't patch single Alt
- case KeyEvent.VK_KANJI:
- case KeyEvent.VK_KATAKANA:
- case KeyEvent.VK_HIRAGANA:
- case KeyEvent.VK_JAPANESE_KATAKANA:
- case KeyEvent.VK_JAPANESE_HIRAGANA:
- case 0x0107: // KeyEvent.VK_INPUT_METHOD_ON_OFF: - in 1.3 only
- case KeyEvent.VK_NUMPAD0: // Alt+NumPad keys
- case KeyEvent.VK_NUMPAD1:
- case KeyEvent.VK_NUMPAD2:
- case KeyEvent.VK_NUMPAD3:
- case KeyEvent.VK_NUMPAD4:
- case KeyEvent.VK_NUMPAD5:
- case KeyEvent.VK_NUMPAD6:
- case KeyEvent.VK_NUMPAD7:
- case KeyEvent.VK_NUMPAD8:
- case KeyEvent.VK_NUMPAD9:
- patch = false;
- break;
- }
+ if (ret instanceof KeymapSetContextAction) { //
+ // Mark the context shifting
+ shiftGlobalContext(key);
+
+ } else { // not a context shift action
+ if (context != null) { // Already in a non-empty context
+ ignoreNextTyped = true;
+
+ } else if (compatibleIgnoreNextTyped) {
+ // #44307 = disabled extra ignoreNextTyped patches for past JDKs
+ if ( // Explicit patch for the keyTyped sent after Alt+key
+ (key.getModifiers() & InputEvent.ALT_MASK) != 0 // Alt pressed
+ && (key.getModifiers() & InputEvent.CTRL_MASK) == 0 // Ctrl not pressed
+ ) {
+ boolean patch = true;
+ if (key.getKeyChar() == 0 || key.getKeyChar() == KeyEvent.CHAR_UNDEFINED) {
+ switch (key.getKeyCode()) {
+ case KeyEvent.VK_ALT: // don't patch single Alt
+ case KeyEvent.VK_KANJI:
+ case KeyEvent.VK_KATAKANA:
+ case KeyEvent.VK_HIRAGANA:
+ case KeyEvent.VK_JAPANESE_KATAKANA:
+ case KeyEvent.VK_JAPANESE_HIRAGANA:
+ case 0x0107: // KeyEvent.VK_INPUT_METHOD_ON_OFF: - in 1.3 only
+ case KeyEvent.VK_NUMPAD0: // Alt+NumPad keys
+ case KeyEvent.VK_NUMPAD1:
+ case KeyEvent.VK_NUMPAD2:
+ case KeyEvent.VK_NUMPAD3:
+ case KeyEvent.VK_NUMPAD4:
+ case KeyEvent.VK_NUMPAD5:
+ case KeyEvent.VK_NUMPAD6:
+ case KeyEvent.VK_NUMPAD7:
+ case KeyEvent.VK_NUMPAD8:
+ case KeyEvent.VK_NUMPAD9:
+ patch = false;
+ break;
}
+ }
- if (patch) {
- ignoreNextTyped = true;
- }
- } else if ((key.getModifiers() & InputEvent.META_MASK) != 0) { // Explicit patch for the keyTyped sent after Meta+key for Mac OS X
- ignoreNextTyped = true;
- } else if ((key.getModifiers() & InputEvent.CTRL_MASK) != 0 &&
- (key.getModifiers() & InputEvent.SHIFT_MASK) != 0 &&
- (key.getKeyCode() == KeyEvent.VK_ADD || key.getKeyCode() == KeyEvent.VK_SUBTRACT)) {
- // Explicit patch for keyTyped sent without the Ctrl+Shift modifiers on Mac OS X - see issue #39835
- ignoreNextTyped = true;
+ if (patch) {
+ ignoreNextTyped = true;
}
+ } else if ((key.getModifiers() & InputEvent.META_MASK) != 0) { // Explicit patch for the keyTyped sent after Meta+key for Mac OS X
+ ignoreNextTyped = true;
+ } else if ((key.getModifiers() & InputEvent.CTRL_MASK) != 0 &&
+ (key.getModifiers() & InputEvent.SHIFT_MASK) != 0 &&
+ (key.getKeyCode() == KeyEvent.VK_ADD || key.getKeyCode() == KeyEvent.VK_SUBTRACT)) {
+ // Explicit patch for keyTyped sent without the Ctrl+Shift modifiers on Mac OS X - see issue #39835
+ ignoreNextTyped = true;
}
- resetContext(); // reset context when resolved
}
- if (context != null && ret == null) { // no action found when in context
- ret = contextKeyNotFoundAction;
- }
+ resetContext(); // reset context when resolved
+ // The global context cannot be reset because
+ // this is just a situation when the editor keymap
+ // does not know but the system or other
}
+
+ if (context != null && ret == null) { // no action found when in context
+ // Letting to return null in order to give chance to other keymaps
+ // ret = contextKeyNotFoundAction;
+ }
+ }
+
+ // Reset global context if a valid action is found
+ if (ret != null && !(ret instanceof KeymapSetContextAction) && (ret != EMPTY_ACTION)) {
+ resetGlobalContext();
}
if (compatibleIgnoreNextTyped) {
Index: openide/awt/src/org/openide/awt/StatusDisplayer.java
===================================================================
RCS file: /cvs/openide/awt/src/org/openide/awt/StatusDisplayer.java,v
retrieving revision 1.1
retrieving revision 1.1.20.2
diff -u -r1.1 -r1.1.20.2
--- openide/awt/src/org/openide/awt/StatusDisplayer.java 21 Apr 2005 20:12:31 -0000 1.1
+++ openide/awt/src/org/openide/awt/StatusDisplayer.java 30 Sep 2005 16:11:45 -0000 1.1.20.2
@@ -14,14 +14,18 @@
import org.openide.util.Lookup;
+import java.awt.event.KeyEvent;
import java.util.*;
+import javax.swing.KeyStroke;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
-/** Permits control of a status line.
+/** Permits control of a status line and keeps track of current context in case
+ * of multikey action bindings.
* The default instance may correspond to the NetBeans status line in the main window.
+ *
* @author Jesse Glick
* @since 3.14
*/
@@ -75,6 +79,57 @@
*/
public abstract void removeChangeListener(ChangeListener l);
+ private List/**/ context = new ArrayList();
+ private String lastString = "";
+
+ /**
+ * Get current multikey context, that is, a sequence of keystrokes that
+ * were registered using {@link shiftContext(KeyStroke)}. The context should
+ * match a prefix of some registered multikey binding.
+ * @return current context
+ */
+ public KeyStroke[] getContext() {
+ return (KeyStroke[]) context.toArray(new KeyStroke[context.size()]);
+ }
+
+ /**
+ * Appends new keystroke to the current context. Should be called by the
+ * active multi keymap implementation when there exists an action binding
+ * that has a keystroke prefix consisting of current context followed by the
+ * keystroke stroke
.
+ * The method also displays the newly created context in the status line.
+ *
+ * @param stroke the new keystroke that shifts the context.
+ */
+ public void shiftContext(KeyStroke stroke) {
+ context.add(stroke);
+ lastString = lastString + getKeyText(stroke) + " ";
+ setStatusText(lastString);
+ }
+
+ private static String getKeyText (KeyStroke keyStroke) {
+ if (keyStroke == null) return ""; // NOI18N
+ String modifText = KeyEvent.getKeyModifiersText
+ (keyStroke.getModifiers ());
+ if ("".equals (modifText)) // NOI18N
+ return KeyEvent.getKeyText (keyStroke.getKeyCode ());
+ return modifText + "+" + // NOI18N
+ KeyEvent.getKeyText (keyStroke.getKeyCode ());
+ }
+
+ /**
+ * Resets the multikey context and clears the status line - displays the
+ * current (empty) context in the status line. Should be called by the
+ * active multi keymap in case it reached complete action binding or by the
+ * last keymap in the keymap stack in case there is no binding for current
+ * keystroke sequence anymore.
+ */
+ public void resetContext() {
+ context.clear();
+ lastString="";
+ setStatusText(lastString);
+ }
+
/**
* Trivial default impl for standalone usage.
* @see "#32154"
Index: core/src/org/netbeans/core/NbKeymap.java
===================================================================
RCS file: /cvs/core/src/org/netbeans/core/NbKeymap.java,v
retrieving revision 1.26
retrieving revision 1.26.8.2
diff -u -r1.26 -r1.26.8.2
--- core/src/org/netbeans/core/NbKeymap.java 28 Aug 2005 11:34:05 -0000 1.26
+++ core/src/org/netbeans/core/NbKeymap.java 21 Sep 2005 09:59:04 -0000 1.26.8.2
@@ -37,14 +37,11 @@
Action defaultAction;
/** hash table to map (Action -> ArrayList of KeyStrokes) */
Map actions;
+
+ private final Action NO_ACTION = new KeymapAction(null, null, null);
- /* The keymap that is currently active */
- private Keymap active;
-
- private final Action NO_ACTION = new KeymapAction(null, null);
-
- public Action createMapAction(Keymap k, String contextName) {
- return new KeymapAction(k, contextName);
+ public Action createMapAction(Keymap k, KeyStroke stroke, String contextName) {
+ return new KeymapAction(k, stroke, contextName);
}
/** Default constructor
@@ -78,46 +75,60 @@
public Action getAction(KeyStroke key) {
Action a;
-
- if (active != null) {
- a = active.getAction(key);
- if (a != null) {
- // always reset immediatelly, the action may set the new ctx then
- active = null;
- StatusDisplayer.getDefault ().setStatusText ("");
- return a;
+ KeyStroke[] ctx = StatusDisplayer.getDefault().getContext();
+ Keymap activ = this;
+ for (int i=0; i reset
+ StatusDisplayer.getDefault().resetContext();
+ } else {
+ StatusDisplayer.getDefault().shiftContext(stroke);
+ }
}
}
}
Index: core/src/org/netbeans/core/ShortcutsFolder.java
===================================================================
RCS file: /cvs/core/src/org/netbeans/core/ShortcutsFolder.java,v
retrieving revision 1.36
retrieving revision 1.36.2.1
diff -u -r1.36 -r1.36.2.1
--- core/src/org/netbeans/core/ShortcutsFolder.java 19 Sep 2005 10:04:39 -0000 1.36
+++ core/src/org/netbeans/core/ShortcutsFolder.java 19 Sep 2005 15:54:23 -0000 1.36.2.1
@@ -141,7 +141,7 @@
shoutcutText += " " + getKeyText (keyStrokes [i]); // NOI18N
if (a == null) {
a = keymap.createMapAction
- (new NbKeymap.SubKeymap (null), shoutcutText);
+ (new NbKeymap.SubKeymap (null), keyStrokes [i], shoutcutText);
currentKeymap.addActionForKeyStroke (keyStrokes [i], a);
}
if (!(a instanceof KeymapAction)) return;
Index: core/windows/src/org/netbeans/core/windows/ShortcutAndMenuKeyEventProcessor.java
===================================================================
RCS file: /cvs/core/windows/src/org/netbeans/core/windows/ShortcutAndMenuKeyEventProcessor.java,v
retrieving revision 1.14
retrieving revision 1.14.4.3
diff -u -r1.14 -r1.14.4.3
--- core/windows/src/org/netbeans/core/windows/ShortcutAndMenuKeyEventProcessor.java 9 Sep 2005 11:56:53 -0000 1.14
+++ core/windows/src/org/netbeans/core/windows/ShortcutAndMenuKeyEventProcessor.java 29 Sep 2005 15:38:26 -0000 1.14.4.3
@@ -17,6 +17,7 @@
import java.util.Set;
import org.netbeans.core.windows.view.ui.KeyboardPopupSwitcher;
import org.openide.actions.ActionManager;
+import org.openide.awt.StatusDisplayer;
import org.openide.util.Lookup;
import org.openide.util.Utilities;
@@ -114,6 +115,7 @@
private int lastModifiers;
private char lastKeyChar;
private boolean lastSampled = false;
+ private boolean skipNextTyped = false;
public boolean postProcessKeyEvent(KeyEvent ev) {
if (ev.isConsumed())
@@ -152,7 +154,20 @@
ev.setModifiers(mods);
}
}
-
+
+ // in some ctx, may need event filtering
+ if (StatusDisplayer.getDefault().getContext().length != 0) {
+ Component comp = ev.getComponent();
+ if (!(comp instanceof JComponent) ||
+ ((JComponent)comp).getClientProperty("context-api-aware") == null) {
+ // not context api aware, don't pass subsequent events
+ processShortcut(ev);
+ // ignore processShortcut result, consume everything while in ctx
+ skipNextTyped = true;
+ return true;
+ }
+ }
+
if (ev.getID() == KeyEvent.KEY_PRESSED
&& ev.getModifiers() == (InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK)
&& (ev.getKeyCode() == KeyEvent.VK_PAUSE
@@ -167,9 +182,23 @@
ev.consume();
return true;
}
+
+
+ // multi-shortcut in middle
+ if (ev.getID() == KeyEvent.KEY_TYPED && skipNextTyped) {
+ ev.consume();
+ skipNextTyped = false;
+ return true;
+ }
+
+ skipNextTyped = false;
+
+// if (ev.getID() == KeyEvent.KEY_PRESSED && StatusDisplayer.getDefault().getContext().length != 0) {
+// skipNextTyped = true;
+// }
if (ev.getID() == KeyEvent.KEY_PRESSED) {
- // decompose to primitive fields to avoid memory profiler confusion (keyEevnt keeps source reference)
+ // decompose to primitive fields to avoid memory profiler confusion (keyEvent keeps source reference)
lastKeyChar = ev.getKeyChar();
lastModifiers = ev.getModifiers();
lastSampled = true;
@@ -242,7 +271,7 @@
// don't let action keystrokes to propagate from both
// modal and nonmodal dialogs
- if (!isTransmodalAction(ks) && (w instanceof Dialog)) {
+ if ((w instanceof Dialog) && !isTransmodalAction(ks)) {
return false;
}