Index: gnu/java/awt/peer/gtk/GtkComponentPeer.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GtkComponentPeer.java,v
retrieving revision 1.16.2.3
diff -u -r1.16.2.3 GtkComponentPeer.java
--- gnu/java/awt/peer/gtk/GtkComponentPeer.java 10 Mar 2004 15:48:01 -0000 1.16.2.3
+++ gnu/java/awt/peer/gtk/GtkComponentPeer.java 22 Apr 2004 16:01:10 -0000
@@ -54,12 +54,14 @@
import java.awt.Image;
import java.awt.Insets;
import java.awt.ItemSelectable;
+import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
+import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.PaintEvent;
@@ -91,6 +93,9 @@
native void gtkWidgetSetCursor (int type);
native void gtkWidgetSetBackground (int red, int green, int blue);
native void gtkWidgetSetForeground (int red, int green, int blue);
+ native void gtkWidgetRequestFocus ();
+ native void gtkWidgetDispatchKeyEvent (int id, long when, int mods,
+ int keyCode, char keyChar, int keyLocation);
native void gtkSetFont (String name, int style, int size);
native void gtkWidgetQueueDrawArea(int x, int y, int width, int height);
native void addExposeFilter();
@@ -222,6 +227,7 @@
public void handleEvent (AWTEvent event)
{
int id = event.getID();
+ KeyEvent ke = null;
switch (id)
{
@@ -251,6 +257,16 @@
}
}
break;
+ case KeyEvent.KEY_PRESSED:
+ ke = (KeyEvent) event;
+ gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiers (),
+ ke.getKeyCode (), ke.getKeyChar (), ke.getKeyLocation ());
+ break;
+ case KeyEvent.KEY_RELEASED:
+ ke = (KeyEvent) event;
+ gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiers (),
+ ke.getKeyCode (), ke.getKeyChar (), ke.getKeyLocation ());
+ break;
}
}
@@ -335,7 +351,12 @@
new Rectangle (x, y, width, height)));
}
- native public void requestFocus ();
+ public void requestFocus ()
+ {
+ System.out.println ("In GtkComponentPeer.requestFocus");
+ gtkWidgetRequestFocus ();
+ postFocusEvent (FocusEvent.FOCUS_GAINED, false);
+ }
public void reshape (int x, int y, int width, int height)
{
@@ -456,11 +477,12 @@
int keyCode, char keyChar, int keyLocation)
{
q.postEvent (new KeyEvent (awtComponent, id, when, mods,
- keyCode, keyChar, keyLocation));
+ keyCode, keyChar, keyLocation));
}
protected void postFocusEvent (int id, boolean temporary)
{
+ System.out.println ("GtkComponentPeer.postFocusEvent: " + awtComponent);
q.postEvent (new FocusEvent (awtComponent, id, temporary));
}
Index: java/awt/Component.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/Component.java,v
retrieving revision 1.37.2.7
diff -u -r1.37.2.7 Component.java
--- java/awt/Component.java 2 Apr 2004 15:52:54 -0000 1.37.2.7
+++ java/awt/Component.java 22 Apr 2004 16:01:10 -0000
@@ -382,18 +382,18 @@
boolean focusable = true;
/**
- * Tracks whether this component uses default focus traversal, or has a
- * different policy.
+ * Tracks whether this component's address@hidden #isFocusTraversable}
+ * method has been overridden.
*
- * @see #isFocusTraversableOverridden()
* @since 1.4
*/
int isFocusTraversableOverridden;
/**
- * The focus traversal keys, if not inherited from the parent or default
- * keyboard manager. These sets will contain only AWTKeyStrokes that
- * represent press and release events to use as focus control.
+ * The focus traversal keys, if not inherited from the parent or
+ * default keyboard focus manager. These sets will contain only
+ * AWTKeyStrokes that represent press and release events to use as
+ * focus control.
*
* @see #getFocusTraversalKeys(int)
* @see #setFocusTraversalKeys(int, Set)
@@ -556,6 +556,12 @@
transient BufferStrategy bufferStrategy;
/**
+ * true if requestFocus was called on this component when its
+ * top-level ancestor was not focusable.
+ */
+ private transient FocusEvent pendingFocusRequest = null;
+
+ /**
* The system properties that affect image updating.
*/
private static transient boolean incrementalDraw;
@@ -2962,6 +2968,7 @@
{
if (focusListener == null)
return;
+
switch (e.id)
{
case FocusEvent.FOCUS_GAINED:
@@ -3410,13 +3417,18 @@
}
/**
- * Sets the focus traversal keys for a given type of focus events. Normally,
- * the default values should match the operating system's native choices. To
- * disable a given traversal, use Collections.EMPTY_SET
. The
- * event dispatcher will consume PRESSED, RELEASED, and TYPED events for the
- * specified key, although focus can only transfer on PRESSED or RELEASED.
+ * Sets the focus traversal keys for one of the three focus
+ * traversal directions supported by Components: address@hidden
+ * #KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS}, address@hidden
+ * #KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS}, or address@hidden
+ * #KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS}. Normally, the
+ * default values should match the operating system's native
+ * choices. To disable a given traversal, use
+ * Collections.EMPTY_SET
. The event dispatcher will
+ * consume PRESSED, RELEASED, and TYPED events for the specified
+ * key, although focus can only transfer on PRESSED or RELEASED.
*
- *
The defauts are: + *
The defaults are: *
Identifier | Meaning | Default | *
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS | @@ -3429,10 +3441,13 @@ *Go up a traversal cycle | None |
Specifying null allows inheritance from the parent, or from the current
- * KeyboardFocusManager default set. If not null, the set must contain only
- * AWTKeyStrokes that are not already focus keys and are not KEY_TYPED
- * events.
+ * If keystrokes is null, this component's focus traversal key set
+ * is inherited from one of its ancestors. If none of its ancestors
+ * has its own set of focus traversal keys, the focus traversal keys
+ * are set to the defaults retrieved from the current
+ * KeyboardFocusManager. If not null, the set must contain only
+ * AWTKeyStrokes that are not already focus keys and are not
+ * KEY_TYPED events.
*
* @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or
* UP_CYCLE_TRAVERSAL_KEYS
@@ -3447,7 +3462,24 @@
public void setFocusTraversalKeys(int id, Set keystrokes)
{
if (keystrokes == null)
- throw new IllegalArgumentException();
+ {
+ Container parent = getParent ();
+
+ while (parent != null)
+ {
+ if (parent.areFocusTraversalKeysSet (id))
+ {
+ keystrokes = parent.getFocusTraversalKeys (id);
+ break;
+ }
+ parent = parent.getParent ();
+ }
+
+ if (keystrokes == null)
+ keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager ().
+ getDefaultFocusTraversalKeys (id);
+ }
+
Set sa;
Set sb;
String name;
@@ -3475,50 +3507,60 @@
name = "upCycleFocusTraversalKeys";
break;
default:
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException ();
}
- int i = keystrokes.size();
- Iterator iter = keystrokes.iterator();
+
+ int i = keystrokes.size ();
+ Iterator iter = keystrokes.iterator ();
+
while (--i >= 0)
{
- Object o = iter.next();
- if (! (o instanceof AWTKeyStroke)
- || sa.contains(o) || sb.contains(o)
+ Object o = iter.next ();
+ if (!(o instanceof AWTKeyStroke)
+ || sa.contains (o) || sb.contains (o)
|| ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED)
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException ();
}
+
if (focusTraversalKeys == null)
focusTraversalKeys = new Set[3];
- keystrokes = Collections.unmodifiableSet(new HashSet(keystrokes));
- firePropertyChange(name, focusTraversalKeys[id], keystrokes);
+
+ keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes));
+ firePropertyChange (name, focusTraversalKeys[id], keystrokes);
+
focusTraversalKeys[id] = keystrokes;
}
/**
- * Returns the set of keys for a given focus traversal action, as defined
- * in setFocusTraversalKeys
. If not set, this is inherited from
- * the parent component, which may have gotten it from the
- * KeyboardFocusManager.
+ * Returns the set of keys for a given focus traversal action, as
+ * defined in setFocusTraversalKeys
. If not set, this
+ * is inherited from the parent component, which may have gotten it
+ * from the KeyboardFocusManager.
*
- * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or
- * UP_CYCLE_TRAVERSAL_KEYS
+ * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS,
+ * or UP_CYCLE_TRAVERSAL_KEYS
* @throws IllegalArgumentException if id is invalid
- * @see #setFocusTraversalKeys(int, Set)
+ * @see #setFocusTraversalKeys (int, Set)
* @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
* @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
* @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
* @since 1.4
*/
- public Set getFocusTraversalKeys(int id)
+ public Set getFocusTraversalKeys (int id)
{
- if (id < KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS
- || id > KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS)
+ if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
+ id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
+ id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS)
throw new IllegalArgumentException();
+
Set s = null;
+
if (focusTraversalKeys != null)
s = focusTraversalKeys[id];
+
if (s == null && parent != null)
- s = parent.getFocusTraversalKeys(id);
+ s = parent.getFocusTraversalKeys (id);
+
return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager()
.getDefaultFocusTraversalKeys(id)) : s;
}
@@ -3527,269 +3569,405 @@
* Tests whether the focus traversal keys for a given action are explicitly
* set or inherited.
*
- * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or
- * UP_CYCLE_TRAVERSAL_KEYS
+ * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS,
+ * or UP_CYCLE_TRAVERSAL_KEYS
* @return true if that set is explicitly specified
* @throws IllegalArgumentException if id is invalid
- * @see #getFocusTraversalKeys(int)
+ * @see #getFocusTraversalKeys (int)
* @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
* @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
* @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
* @since 1.4
*/
- public boolean areFocusTraversalKeysSet(int id)
+ public boolean areFocusTraversalKeysSet (int id)
{
- if (id < KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS
- || id > KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS)
- throw new IllegalArgumentException();
+ if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
+ id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
+ id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS)
+ throw new IllegalArgumentException ();
+
return focusTraversalKeys != null && focusTraversalKeys[id] != null;
}
/**
- * Sets whether focus traversal keys are enabled, which consumes traversal
- * keys and performs the focus event automatically.
+ * Enable or disable focus traversal keys on this Component. If
+ * they are, then the keyboard focus manager consumes and acts on
+ * key press and release events that trigger focus traversal, and
+ * discards the corresponding key typed events. If focus traversal
+ * keys are disabled, then all key events that would otherwise
+ * trigger focus traversal are sent to this Component.
*
* @param focusTraversalKeysEnabled the new value of the flag
- * @see #getFocusTraversalKeysEnabled()
- * @see #setFocusTraversalKeys(int, Set)
- * @see #getFocusTraversalKeys(int)
+ * @see #getFocusTraversalKeysEnabled ()
+ * @see #setFocusTraversalKeys (int, Set)
+ * @see #getFocusTraversalKeys (int)
* @since 1.4
*/
- public void setFocusTraversalKeysEnabled(boolean focusTraversalKeysEnabled)
+ public void setFocusTraversalKeysEnabled (boolean focusTraversalKeysEnabled)
{
- firePropertyChange("focusTraversalKeysEnabled",
- this.focusTraversalKeysEnabled,
- focusTraversalKeysEnabled);
+ firePropertyChange ("focusTraversalKeysEnabled",
+ this.focusTraversalKeysEnabled,
+ focusTraversalKeysEnabled);
this.focusTraversalKeysEnabled = focusTraversalKeysEnabled;
}
/**
- * Tests whether focus traversal keys are enabled. If they are, then focus
- * traversal keys are consumed and focus events performed automatically,
- * without the component seeing the keystrokes.
- *
- * @return true if focus traversal is enabled
- * @see #setFocusTraversalKeysEnabled(boolean)
- * @see #setFocusTraversalKeys(int, Set)
- * @see #getFocusTraversalKeys(int)
+ * Check whether or not focus traversal keys are enabled on this
+ * Component. If they are, then the keyboard focus manager consumes
+ * and acts on key press and release events that trigger focus
+ * traversal, and discards the corresponding key typed events. If
+ * focus traversal keys are disabled, then all key events that would
+ * otherwise trigger focus traversal are sent to this Component.
+ *
+ * @return true if focus traversal keys are enabled
+ * @see #setFocusTraversalKeysEnabled (boolean)
+ * @see #setFocusTraversalKeys (int, Set)
+ * @see #getFocusTraversalKeys (int)
* @since 1.4
*/
- public boolean getFocusTraversalKeysEnabled()
+ public boolean getFocusTraversalKeysEnabled ()
{
return focusTraversalKeysEnabled;
}
/**
- * Requests that this component be given focus. A FOCUS_GAINED
- * event will be fired if and only if this request is successful. To be
- * successful, the component must be displayable, visible, and focusable,
- * and the top-level Window must be able to receive focus. Thus, this
- * request may fail, or be delayed until the window receives focus. It is
- * recommended that requestFocusInWindow
be used where
- * possible to be more platform-independent.
+ * Request that this Component be given the keyboard input focus and
+ * that its top-level ancestor become the focused Window.
+ *
+ * For the request to be granted, the Component must be focusable,
+ * displayable and visible and the top-level Window to which it
+ * belongs must be focusable. If the request is initially denied on
+ * the basis that the top-level Window is not focusable, the request
+ * will be remembered and granted when the Window does become
+ * focused.
+ *
+ * Never assume that this Component is the focus owner until it
+ * receives a FOCUS_GAINED event.
*
- * @see #requestFocusInWindow()
+ * The behaviour of this method is platform-dependent.
+ * address@hidden #requestFocusInWindow} should be used instead.
+ *
+ * @see #requestFocusInWindow ()
* @see FocusEvent
- * @see #addFocusListener(FocusListener)
- * @see #isFocusable()
- * @see #isDisplayable()
- * @see KeyboardFocusManager#clearGlobalFocusOwner()
- */
- public void requestFocus()
- {
- // If there's no peer then this component can't get the focus. We
- // treat it as a silent rejection of the request.
- if (peer != null)
- peer.requestFocus();
+ * @see #addFocusListener (FocusListener)
+ * @see #isFocusable ()
+ * @see #isDisplayable ()
+ * @see KeyboardFocusManager#clearGlobalFocusOwner ()
+ */
+ public void requestFocus ()
+ {
+ if (isDisplayable ()
+ && isVisible ()
+ && isFocusable ())
+ {
+ // FIXME: need to get the tree lock here.
+ // Find this Component's top-level ancestor.
+ Container parent = getParent ();
+
+ while (parent != null
+ && !(parent instanceof Window))
+ parent = parent.getParent ();
+
+ Window toplevel = (Window) parent;
+ if (toplevel.isFocusableWindow ())
+ {
+ if (peer != null)
+ // This call will cause a FOCUS_GAINED event to be
+ // posted to the system event queue if the native
+ // windowing system grants the focus request.
+ peer.requestFocus ();
+ else
+ {
+ // Either our peer hasn't been created yet or we're a
+ // lightweight component. In either case we want to
+ // post a FOCUS_GAINED event.
+ EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
+ eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED));
+ }
+ }
+ else
+ pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED);
+ }
}
/**
- * Requests that this component be given focus. A FOCUS_GAINED
- * event will be fired if and only if this request is successful. To be
- * successful, the component must be displayable, visible, and focusable,
- * and the top-level Window must be able to receive focus. Thus, this
- * request may fail, or be delayed until the window receives focus. It is
- * recommended that requestFocusInWindow
be used where
- * possible to be more platform-independent.
- *
- *
If the return value is false, the request is guaranteed to fail. If
- * it is true, it will likely succeed unless the action is vetoed or
- * something in the native windowing system intervenes. The temporary flag,
- * and thus this method in general, is not designed for public use; rather
- * it is a hook for lightweight components to notify their container in
- * an attempt to reduce the amount of repainting necessary.
+ * Request that this Component be given the keyboard input focus and
+ * that its top-level ancestor become the focused Window.
+ *
+ * For the request to be granted, the Component must be focusable,
+ * displayable and visible and the top-level Window to which it
+ * belongs must be focusable. If the request is initially denied on
+ * the basis that the top-level Window is not focusable, the request
+ * will be remembered and granted when the Window does become
+ * focused.
+ *
+ * Never assume that this Component is the focus owner until it
+ * receives a FOCUS_GAINED event.
+ *
+ * The behaviour of this method is platform-dependent.
+ * address@hidden #requestFocusInWindow} should be used instead.
+ *
+ * If the return value is false, the request is guaranteed to fail.
+ * If the return value is true, the request will succeed unless it
+ * is vetoed or something in the native windowing system intervenes,
+ * preventing this Component's top-level ancestor from becoming
+ * focused. This method is meant to be called by derived
+ * lightweight Components that want to avoid unnecessary repainting
+ * when they know a given focus transfer need only be temporary.
*
* @param temporary true if the focus request is temporary
* @return true if the request has a chance of success
- * @see #requestFocusInWindow()
+ * @see #requestFocusInWindow ()
* @see FocusEvent
- * @see #addFocusListener(FocusListener)
- * @see #isFocusable()
- * @see #isDisplayable()
- * @see KeyboardFocusManager#clearGlobalFocusOwner()
+ * @see #addFocusListener (FocusListener)
+ * @see #isFocusable ()
+ * @see #isDisplayable ()
+ * @see KeyboardFocusManager#clearGlobalFocusOwner ()
* @since 1.4
*/
- protected boolean requestFocus(boolean temporary)
+ protected boolean requestFocus (boolean temporary)
{
- // XXX Implement correctly.
- requestFocus();
+ if (isDisplayable ()
+ && isVisible ()
+ && isFocusable ())
+ {
+ // FIXME: need to get the tree lock here.
+ // Find this Component's top-level ancestor.
+ Container parent = getParent ();
+
+ while (parent != null
+ && !(parent instanceof Window))
+ parent = parent.getParent ();
+
+ Window toplevel = (Window) parent;
+ if (toplevel.isFocusableWindow ())
+ {
+ if (peer != null)
+ // This call will cause a FOCUS_GAINED event to be
+ // posted to the system event queue if the native
+ // windowing system grants the focus request.
+ peer.requestFocus ();
+ else
+ {
+ // Either our peer hasn't been created yet or we're a
+ // lightweight component. In either case we want to
+ // post a FOCUS_GAINED event.
+ EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
+ eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary));
+ }
+ }
+ else
+ // FIXME: need to add a focus listener to our top-level
+ // ancestor, so that we can post this event when it becomes
+ // the focused window.
+ pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary);
+ }
+ // Always return true.
return true;
}
/**
- * Requests that this component be given focus, if it resides in the
- * top-level window which already has focus. A FOCUS_GAINED
- * event will be fired if and only if this request is successful. To be
- * successful, the component must be displayable, visible, and focusable,
- * and the top-level Window must be focused.
- *
- *
If the return value is false, the request is guaranteed to fail. If
- * it is true, it will likely succeed unless the action is vetoed or
- * something in the native windowing system intervenes. The temporary flag,
- * and thus this method in general, is not designed for public use; rather
- * it is a hook for lightweight components to notify their container in
- * an attempt to reduce the amount of repainting necessary.
+ * Request that this component be given the keyboard input focus, if
+ * its top-level ancestor is the currently focused Window. A
+ * FOCUS_GAINED
event will be fired if and only if this
+ * request is successful. To be successful, the component must be
+ * displayable, visible, and focusable, and its ancestor top-level
+ * Window must be focused.
+ *
+ * If the return value is false, the request is guaranteed to fail.
+ * If the return value is true, the request will succeed unless it
+ * is vetoed or something in the native windowing system intervenes,
+ * preventing this Component's top-level ancestor from becoming
+ * focused.
*
* @return true if the request has a chance of success
- * @see #requestFocus()
+ * @see #requestFocus ()
* @see FocusEvent
- * @see #addFocusListener(FocusListener)
- * @see #isFocusable()
- * @see #isDisplayable()
- * @see KeyboardFocusManager#clearGlobalFocusOwner()
+ * @see #addFocusListener (FocusListener)
+ * @see #isFocusable ()
+ * @see #isDisplayable ()
+ * @see KeyboardFocusManager#clearGlobalFocusOwner ()
* @since 1.4
*/
- public boolean requestFocusInWindow()
+ public boolean requestFocusInWindow ()
{
- // XXX Implement correctly.
- requestFocus();
- return true;
+ return requestFocusInWindow (false);
}
/**
- * Requests that this component be given focus, if it resides in the
- * top-level window which already has focus. A FOCUS_GAINED
- * event will be fired if and only if this request is successful. To be
- * successful, the component must be displayable, visible, and focusable,
- * and the top-level Window must be focused.
- *
- *
If the return value is false, the request is guaranteed to fail. If
- * it is true, it will likely succeed unless the action is vetoed or
- * something in the native windowing system intervenes. The temporary flag,
- * and thus this method in general, is not designed for public use; rather
- * it is a hook for lightweight components to notify their container in
- * an attempt to reduce the amount of repainting necessary.
+ * Request that this component be given the keyboard input focus, if
+ * its top-level ancestor is the currently focused Window. A
+ * FOCUS_GAINED
event will be fired if and only if this
+ * request is successful. To be successful, the component must be
+ * displayable, visible, and focusable, and its ancestor top-level
+ * Window must be focused.
+ *
+ * If the return value is false, the request is guaranteed to fail.
+ * If the return value is true, the request will succeed unless it
+ * is vetoed or something in the native windowing system intervenes,
+ * preventing this Component's top-level ancestor from becoming
+ * focused. This method is meant to be called by derived
+ * lightweight Components that want to avoid unnecessary repainting
+ * when they know a given focus transfer need only be temporary.
*
* @param temporary true if the focus request is temporary
* @return true if the request has a chance of success
- * @see #requestFocus()
+ * @see #requestFocus ()
* @see FocusEvent
- * @see #addFocusListener(FocusListener)
- * @see #isFocusable()
- * @see #isDisplayable()
- * @see KeyboardFocusManager#clearGlobalFocusOwner()
+ * @see #addFocusListener (FocusListener)
+ * @see #isFocusable ()
+ * @see #isDisplayable ()
+ * @see KeyboardFocusManager#clearGlobalFocusOwner ()
* @since 1.4
*/
- protected boolean requestFocusInWindow(boolean temporary)
+ protected boolean requestFocusInWindow (boolean temporary)
{
- // XXX Implement correctly.
- requestFocus();
+ KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+ Window focusedWindow = manager.getFocusedWindow ();
+
+ if (focusedWindow != null)
+ {
+ // FIXME: get tree lock here.
+ Container parent = getParent ();
+
+ while (parent != null
+ && !(parent instanceof Window))
+ parent = parent.getParent ();
+
+ Window toplevel = (Window) parent;
+
+ // Check if top-level ancestor is currently focused window.
+ if (focusedWindow == toplevel)
+ {
+ if (peer != null)
+ // This call will cause a FOCUS_GAINED event to be
+ // posted to the system event queue if the native
+ // windowing system grants the focus request.
+ peer.requestFocus ();
+ else
+ {
+ // Either our peer hasn't been created yet or we're a
+ // lightweight component. In either case we want to
+ // post a FOCUS_GAINED event.
+ EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
+ eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary));
+ }
+ }
+ else
+ return false;
+ }
+
return true;
}
/**
- * Transfers focus to the next component in the focus traversal order, as
- * though this were the current focus owner.
+ * Transfers focus to the next component in the focus traversal
+ * order, as though this were the current focus owner.
*
* @see #requestFocus()
* @since 1.1
*/
- public void transferFocus()
+ public void transferFocus ()
{
- Component next;
- if (parent == null)
- next = findNextFocusComponent(null);
- else
- next = parent.findNextFocusComponent(this);
- if (next != null && next != this)
- next.requestFocus();
+ nextFocus ();
}
/**
- * Returns the root container that owns the focus cycle where this component
- * resides. A focus cycle root is in two cycles, one as the ancestor, and
- * one as the focusable element; this call always returns the ancestor.
+ * Returns the root container that owns the focus cycle where this
+ * component resides. A focus cycle root is in two cycles, one as
+ * the ancestor, and one as the focusable element; this call always
+ * returns the ancestor.
*
* @return the ancestor container that owns the focus cycle
* @since 1.4
*/
- public Container getFocusCycleRootAncestor()
+ public Container getFocusCycleRootAncestor ()
{
- // XXX Implement.
- throw new Error("not implemented");
+ if (this instanceof Window
+ && ((Container) this).isFocusCycleRoot ())
+ return (Container) this;
+
+ Container parent = getParent ();
+
+ while (parent != null
+ && !parent.isFocusCycleRoot ())
+ parent = parent.getParent ();
+
+ return parent;
}
/**
- * Tests if the container is the ancestor of the focus cycle that this
- * component belongs to.
+ * Tests if the container is the ancestor of the focus cycle that
+ * this component belongs to.
*
* @param c the container to test
* @return true if c is the focus cycle root
* @since 1.4
*/
- public boolean isFocusCycleRoot(Container c)
+ public boolean isFocusCycleRoot (Container c)
{
- return c == getFocusCycleRootAncestor();
+ return c == getFocusCycleRootAncestor ();
}
/**
- * AWT 1.0 focus event processor.
+ * AWT 1.0 focus event processor. Transfers focus to the next
+ * component in the focus traversal order, as though this were the
+ * current focus owner.
*
- * @deprecated use address@hidden #transferFocus()} instead
+ * @deprecated use address@hidden #transferFocus ()} instead
*/
- public void nextFocus()
+ public void nextFocus ()
{
- transferFocus();
+ KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+ manager.focusNextComponent (this);
}
/**
- * Transfers focus to the previous component in the focus traversal order, as
- * though this were the current focus owner.
+ * Transfers focus to the previous component in the focus traversal
+ * order, as though this were the current focus owner.
*
- * @see #requestFocus()
+ * @see #requestFocus ()
* @since 1.4
*/
- public void transferFocusBackward()
+ public void transferFocusBackward ()
{
- // XXX Implement.
- throw new Error("not implemented");
+ KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+ manager.focusPreviousComponent (this);
}
/**
- * Transfers focus to the focus cycle root of this component. However, if
- * this is a Window, the default focus owner in the window in the current
- * focus cycle is focused instead.
+ * Transfers focus to the focus cycle root of this component.
+ * However, if this is a Window, the default focus owner in the
+ * window in the current focus cycle is focused instead.
*
- * @see #requestFocus()
- * @see #isFocusCycleRoot()
+ * @see #requestFocus ()
+ * @see #isFocusCycleRoot ()
* @since 1.4
*/
- public void transferFocusUpCycle()
+ public void transferFocusUpCycle ()
{
- // XXX Implement.
- throw new Error("not implemented");
+ KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+ manager.upFocusCycle (this);
}
/**
- * Tests if this component is the focus owner. Use address@hidden #isFocusOwner()}
- * instead.
+ * Tests if this component is the focus owner. Use address@hidden
+ * #isFocusOwner ()} instead.
*
* @return true if this component owns focus
* @since 1.2
*/
- public boolean hasFocus()
+ public boolean hasFocus ()
{
- return isFocusOwner();
+ KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+ Component focusOwner = manager.getFocusOwner ();
+
+ return this == focusOwner;
}
/**
@@ -3800,8 +3978,7 @@
*/
public boolean isFocusOwner()
{
- // XXX Implement.
- throw new Error("not implemented");
+ return hasFocus ();
}
/**
@@ -4336,6 +4513,8 @@
* making the request. This is overridden by Container; when called for an
* ordinary component there is no child and so we always return null.
*
+ * FIXME: is this still needed, in light of focus traversal policies?
+ *
* @param child the component making the request
* @return the next component to focus on
*/
@@ -4896,23 +5075,23 @@
* Tests whether this component can accept focus.
*
* @return true if this is focus traversable
- * @see #getAccessibleStateSet()
+ * @see #getAccessibleStateSet ()
* @see AccessibleState#FOCUSABLE
* @see AccessibleState#FOCUSED
*/
- public boolean isFocusTraversable()
+ public boolean isFocusTraversable ()
{
- return Component.this.isFocusTraversable();
+ return Component.this.isFocusTraversable ();
}
/**
* Requests focus for this component.
*
- * @see #isFocusTraversable()
+ * @see #isFocusTraversable ()
*/
- public void requestFocus()
+ public void requestFocus ()
{
- Component.this.requestFocus();
+ Component.this.requestFocus ();
}
/**
Index: java/awt/Container.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/Container.java,v
retrieving revision 1.34.2.6
diff -u -r1.34.2.6 Container.java
--- java/awt/Container.java 10 Mar 2004 21:43:01 -0000 1.34.2.6
+++ java/awt/Container.java 22 Apr 2004 16:01:10 -0000
@@ -46,10 +46,16 @@
import java.awt.peer.LightweightPeer;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Serializable;
+import java.util.Collections;
import java.util.EventListener;
+import java.util.Iterator;
+import java.util.HashSet;
import java.util.Set;
import javax.accessibility.Accessible;
import javax.swing.SwingUtilities;
@@ -93,6 +99,21 @@
transient ContainerListener containerListener;
transient PropertyChangeSupport changeSupport;
+ /** The focus traversal policy that determines how focus is
+ transferred between this Container and its children. */
+ private FocusTraversalPolicy focusTraversalPolicy;
+
+ /**
+ * The focus traversal keys, if not inherited from the parent or default
+ * keyboard manager. These sets will contain only AWTKeyStrokes that
+ * represent press and release events to use as focus control.
+ *
+ * @see #getFocusTraversalKeys(int)
+ * @see #setFocusTraversalKeys(int, Set)
+ * @since 1.4
+ */
+ transient Set[] focusTraversalKeys;
+
/**
* Default constructor for subclasses.
*/
@@ -1068,9 +1089,89 @@
throw new IllegalArgumentException ();
if (keystrokes == null)
- throw new IllegalArgumentException ();
+ {
+ Container parent = getParent ();
+
+ while (parent != null)
+ {
+ if (parent.areFocusTraversalKeysSet (id))
+ {
+ keystrokes = parent.getFocusTraversalKeys (id);
+ break;
+ }
+ parent = parent.getParent ();
+ }
+
+ if (keystrokes == null)
+ keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager ().
+ getDefaultFocusTraversalKeys (id);
+ }
+
+ Set sa;
+ Set sb;
+ Set sc;
+ String name;
+ switch (id)
+ {
+ case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS:
+ sa = getFocusTraversalKeys
+ (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+ sb = getFocusTraversalKeys
+ (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
+ sc = getFocusTraversalKeys
+ (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
+ name = "forwardFocusTraversalKeys";
+ break;
+ case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS:
+ sa = getFocusTraversalKeys
+ (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+ sb = getFocusTraversalKeys
+ (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
+ sc = getFocusTraversalKeys
+ (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
+ name = "backwardFocusTraversalKeys";
+ break;
+ case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS:
+ sa = getFocusTraversalKeys
+ (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+ sb = getFocusTraversalKeys
+ (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+ sc = getFocusTraversalKeys
+ (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
+ name = "upCycleFocusTraversalKeys";
+ break;
+ case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS:
+ sa = getFocusTraversalKeys
+ (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+ sb = getFocusTraversalKeys
+ (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+ sc = getFocusTraversalKeys
+ (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
+ name = "downCycleFocusTraversalKeys";
+ break;
+ default:
+ throw new IllegalArgumentException ();
+ }
+
+ int i = keystrokes.size ();
+ Iterator iter = keystrokes.iterator ();
+
+ while (--i >= 0)
+ {
+ Object o = iter.next ();
+ if (!(o instanceof AWTKeyStroke)
+ || sa.contains (o) || sb.contains (o) || sc.contains (o)
+ || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED)
+ throw new IllegalArgumentException ();
+ }
+
+ if (focusTraversalKeys == null)
+ focusTraversalKeys = new Set[3];
+
+ keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes));
+ firePropertyChange (name, focusTraversalKeys[id], keystrokes);
- throw new Error ("not implemented");
+ focusTraversalKeys[id] = keystrokes;
}
/**
@@ -1085,7 +1186,7 @@
*
* @since 1.4
*/
- public Set getFocusTraversalKeys(int id)
+ public Set getFocusTraversalKeys (int id)
{
if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
@@ -1093,9 +1194,18 @@
id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
throw new IllegalArgumentException ();
- return null;
+ Set s = null;
+
+ if (focusTraversalKeys != null)
+ s = focusTraversalKeys[id];
+
+ if (s == null && parent != null)
+ s = parent.getFocusTraversalKeys (id);
+
+ return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager()
+ .getDefaultFocusTraversalKeys(id)) : s;
}
-
+
/**
* Returns whether the Set of focus traversal keys for the given focus
* traversal operation has been explicitly defined for this Container.
@@ -1110,7 +1220,7 @@
*
* @since 1.4
*/
- public boolean areFocusTraversalKeysSet(int id)
+ public boolean areFocusTraversalKeysSet (int id)
{
if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
@@ -1118,43 +1228,148 @@
id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
throw new IllegalArgumentException ();
- return false;
+ return focusTraversalKeys != null && focusTraversalKeys[id] != null;
}
-
- public boolean isFocusCycleRoot(Container c)
+
+ /**
+ * Check whether the given Container is the focus cycle root of this
+ * Container's focus traversal cycle. If this Container is a focus
+ * cycle root itself, then it will be in two different focus cycles
+ * -- it's own, and that of its ancestor focus cycle root's. In
+ * that case, if c
is either of those containers, this
+ * method will return true.
+ *
+ * @param c the candidate Container
+ *
+ * @return true if c is the focus cycle root of the focus traversal
+ * cycle to which this Container belongs, false otherwise
+ *
+ * @since 1.4
+ */
+ public boolean isFocusCycleRoot (Container c)
{
+ if (this == c
+ && isFocusCycleRoot ())
+ return true;
+
+ Container ancestor = getFocusCycleRootAncestor ();
+
+ if (c == ancestor)
+ return true;
+
return false;
}
-
- public void transferFocusBackward()
- {
- }
-
- public void setFocusTraversalPolicy(FocusTraversalPolicy policy)
+
+ /**
+ * If this Container is a focus cycle root, set the focus traversal
+ * policy that determines the focus traversal order for its
+ * children. If non-null, this policy will be inherited by all
+ * inferior focus cycle roots. If policy
is null, this
+ * Container will inherit its policy from the closest ancestor focus
+ * cycle root that's had its policy set.
+ *
+ * @param policy the new focus traversal policy for this Container or null
+ *
+ * @since 1.4
+ */
+ public void setFocusTraversalPolicy (FocusTraversalPolicy policy)
{
+ focusTraversalPolicy = policy;
}
-
- public FocusTraversalPolicy getFocusTraversalPolicy()
+
+ /**
+ * Return the focus traversal policy that determines the focus
+ * traversal order for this Container's children. This method
+ * returns null if this Container is not a focus cycle root. If the
+ * focus traversal policy has not been set explicitly, then this
+ * method will return an ancestor focus cycle root's policy instead.
+ *
+ * @return this Container's focus traversal policy or null
+ *
+ * @since 1.4
+ */
+ public FocusTraversalPolicy getFocusTraversalPolicy ()
{
- return null;
+ if (!isFocusCycleRoot ())
+ return null;
+
+ if (focusTraversalPolicy == null)
+ {
+ Container ancestor = getFocusCycleRootAncestor ();
+
+ if (ancestor != this)
+ return ancestor.getFocusTraversalPolicy ();
+ else
+ {
+ KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+ return manager.getDefaultFocusTraversalPolicy ();
+ }
+ }
+ else
+ return focusTraversalPolicy;
}
-
- public boolean isFocusTraversalPolicySet()
+
+ /**
+ * Check whether this Container's focus traversal policy has been
+ * explicitly set. If it has not, then this Container will inherit
+ * its focus traversal policy from one of its ancestor focus cycle
+ * roots.
+ *
+ * @return true if focus traversal policy is set, false otherwise
+ */
+ public boolean isFocusTraversalPolicySet ()
{
- return false;
+ return focusTraversalPolicy == null;
}
-
- public void setFocusCycleRoot(boolean focusCycleRoot)
+
+ /**
+ * Set whether or not this Container is the root of a focus
+ * traversal cycle. This Container's focus traversal policy
+ * determines the order of focus traversal. Some policies prevent
+ * the focus from being transferred between two traversal cycles
+ * until an up or down traversal operation is performed. In that
+ * case, normal traversal (not up or down) is limited to this
+ * Container and all of this Container's descendents that are not
+ * descendents of inferior focus cycle roots. In the default case
+ * however, ContainerOrderFocusTraversalPolicy is in effect, and it
+ * supports implicit down-cycle traversal operations.
+ *
+ * @return true if this is a focus cycle root, false otherwise
+ *
+ * @since 1.4
+ */
+ public void setFocusCycleRoot (boolean focusCycleRoot)
{
+ this.focusCycleRoot = focusCycleRoot;
}
-
- public boolean isFocusCycleRoot()
+
+ /**
+ * Check whether this Container is a focus cycle root.
+ *
+ * @return true if this is a focus cycle root, false otherwise
+ *
+ * @since 1.4
+ */
+ public boolean isFocusCycleRoot ()
{
- return false;
+ return focusCycleRoot;
}
-
- public void transferFocusDownCycle()
+
+ /**
+ * Transfer focus down one focus traversal cycle. If this Container
+ * is a focus cycle root, then its default component becomes the
+ * focus owner, and this Container becomes the current focus cycle
+ * root. No traversal will occur if this Container is not a focus
+ * cycle root.
+ *
+ * @since 1.4
+ */
+ public void transferFocusDownCycle ()
{
+ KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+ manager.downFocusCycle (this);
}
/**
@@ -1369,6 +1584,61 @@
}
}
}
+ }
+
+ /**
+ * Deserialize this Container:
+ *
ContainerOrderFocusTraversalPolicy
object.
*/
- public ContainerOrderFocusTraversalPolicy()
+ public ContainerOrderFocusTraversalPolicy ()
{
// Nothing to do here
}
@@ -66,37 +85,193 @@
* Returns the Component that should receive the focus after current.
* root must be a focus cycle root of current.
*
+ * @param root a focus cycle root of current
+ * @param current a (possibly indirect) child of root, or root itself
+ *
+ * @return the next Component in the focus traversal order for root,
+ * or null if no acceptable Component exists.
+ *
* @exception IllegalArgumentException If root is not a focus cycle
* root of current, or if either root or current is null.
*/
- public Component getComponentAfter(Container root, Component current)
+ public Component getComponentAfter (Container root, Component current)
{
- if (root == null
- || current == null)
- throw new IllegalArgumentException ();
-
+ if (root == null)
+ throw new IllegalArgumentException ("focus cycle root is null");
+ if (current == null)
+ throw new IllegalArgumentException ("current component is null");
+
+ // FIXME: is this the right thing to do here? it move the context
+ // for traversal up one focus traversal cycle.
+ if ((Component) root == current)
+ root = current.getFocusCycleRootAncestor ();
+
+ Container ancestor = current.getFocusCycleRootAncestor ();
+ Container prevAncestor = ancestor;
+ while (ancestor != root)
+ {
+ ancestor = current.getFocusCycleRootAncestor ();
+ if (ancestor == prevAncestor)
+ {
+ // We've reached the top focus cycle root ancestor. Check
+ // if it is root.
+ if (ancestor != root)
+ throw new IllegalArgumentException ("the given container is not"
+ + " a focus cycle root of the"
+ + " current component");
+ else
+ break;
+ }
+ prevAncestor = ancestor;
+ }
+
+ // FIXME: need locking on root.
+ Component[] components = root.getComponents ();
+ int componentIndex = 0;
+ int numComponents = root.getComponentCount ();
+
+ // Find component's index.
+ for (int i = 0; i < numComponents; i++)
+ {
+ if (components[i] == current)
+ componentIndex = i;
+ }
+
+ // Search forward for the next acceptable component.
+ for (int i = componentIndex + 1; i < numComponents; i++)
+ {
+ if (components[i] instanceof Container)
+ {
+ Component result = getFirstComponent ((Container) components[i]);
+
+ if (result != null
+ && implicitDownCycleTraversal)
+ return result;
+ }
+
+ if (accept (components[i]))
+ return components[i];
+ }
+
+ for (int i = 0; i < componentIndex; i++)
+ {
+ if (components[i] instanceof Container)
+ {
+ Component result = getFirstComponent ((Container) components[i]);
+
+ if (result != null
+ && implicitDownCycleTraversal)
+ return result;
+ }
+
+ // FIXME: see below.
+ if (accept (components[i]))
+ return components[i];
+ }
+
+ // No acceptable component found.
return null;
}
/**
- * Returns the Component that should receive the focus before current.
- * root must be a focus cycle root of current.
+ * Returns the Component that should receive the focus before
+ * current
. root
must be a focus cycle
+ * root of current.
+ *
+ * @param root a focus cycle root of current
+ * @param current a (possibly indirect) child of root, or root itself
+ *
+ * @return the previous Component in the focus traversal order for
+ * root, or null if no acceptable Component exists.
*
* @exception IllegalArgumentException If root is not a focus cycle
* root of current, or if either root or current is null.
*/
- public Component getComponentBefore(Container root, Component current)
+ public Component getComponentBefore (Container root, Component current)
{
- if (root == null
- || current == null)
- throw new IllegalArgumentException ();
+ if (root == null)
+ throw new IllegalArgumentException ("focus cycle root is null");
+ if (current == null)
+ throw new IllegalArgumentException ("current component is null");
+
+ // FIXME: is this the right thing to do here? it move the context
+ // for traversal up one focus traversal cycle.
+ if ((Component) root == current)
+ root = current.getFocusCycleRootAncestor ();
+
+ Container ancestor = current.getFocusCycleRootAncestor ();
+ Container prevAncestor = ancestor;
+ while (ancestor != root)
+ {
+ ancestor = current.getFocusCycleRootAncestor ();
+ if (ancestor == prevAncestor)
+ {
+ // We've reached the top focus cycle root ancestor. Check
+ // if it is root.
+ if (ancestor != root)
+ throw new IllegalArgumentException ("the given container is not"
+ + " a focus cycle root of the"
+ + " current component");
+ else
+ break;
+ }
+ prevAncestor = ancestor;
+ }
+
+ // FIXME: need locking on root.
+ Component[] components = root.getComponents ();
+ int componentIndex = 0;
+ int numComponents = root.getComponentCount ();
+
+ // Find component's index.
+ for (int i = 0; i < numComponents; i++)
+ {
+ if (components[i] == current)
+ componentIndex = i;
+ }
+ // Search backward for the next acceptable component.
+ for (int i = componentIndex - 1; i >= 0; i--)
+ {
+ if (components[i] instanceof Container)
+ {
+ Component result = getLastComponent ((Container) components[i]);
+
+ if (result != null)
+ return result;
+ }
+
+ if (accept (components[i]))
+ return components[i];
+ }
+
+ for (int i = numComponents - 1; i > componentIndex; i--)
+ {
+ if (components[i] instanceof Container)
+ {
+ Component result = getLastComponent ((Container) components[i]);
+
+ if (result != null)
+ return result;
+ }
+
+ // FIXME: see below.
+ if (accept (components[i]))
+ return components[i];
+ }
+
+ // No acceptable component found.
return null;
}
/**
* Returns the first Component of root that should receive the focus.
*
+ * @param root a focus cycle root
+ *
+ * @return the first Component in the focus traversal order for
+ * root, or null if no acceptable Component exists.
+ *
* @exception IllegalArgumentException If root is null.
*/
public Component getFirstComponent(Container root)
@@ -119,16 +294,17 @@
if (component instanceof Container)
{
- Component result = getLastComponent ((Container) component);
+ Component result = getFirstComponent ((Container) component);
if (result != null)
return result;
}
- else
- {
- if (accept (component))
- return component;
- }
+
+ // FIXME: can the container itself be focused? if not, then
+ // this part needs to be in the else clause of the if
+ // statement above.
+ if (accept (component))
+ return component;
}
return null;
@@ -137,9 +313,14 @@
/**
* Returns the last Component of root that should receive the focus.
*
+ * @param root a focus cycle root
+ *
+ * @return the last Component in the focus traversal order for
+ * root, or null if no acceptable Component exists.
+ *
* @exception IllegalArgumentException If root is null.
*/
- public Component getLastComponent(Container root)
+ public Component getLastComponent (Container root)
{
if (root == null)
throw new IllegalArgumentException ();
@@ -164,11 +345,10 @@
if (result != null)
return result;
}
- else
- {
- if (accept (component))
- return component;
- }
+
+ // FIXME: see above.
+ if (accept (component))
+ return component;
}
return null;
@@ -177,28 +357,58 @@
/**
* Returns the default Component of root that should receive the focus.
*
+ * @param root a focus cycle root
+ *
+ * @return the default Component in the focus traversal order for
+ * root, or null if no acceptable Component exists.
+ *
* @exception IllegalArgumentException If root is null.
*/
- public Component getDefaultComponent(Container root)
+ public Component getDefaultComponent (Container root)
{
return getFirstComponent (root);
}
- public void setImplicitDownCycleTraversal(boolean value)
+ /**
+ * Set whether or not implicit down cycling is enabled. If it is,
+ * then initiating a forward focus traversal operation onto a focus
+ * cycle root, the focus will be implicitly transferred into the
+ * root container's focus cycle.
+ *
+ * @param value the setting for implicit down cycling
+ */
+ public void setImplicitDownCycleTraversal (boolean value)
{
implicitDownCycleTraversal = value;
}
- public boolean getImplicitDownCycleTraversal()
+ /**
+ * Check whether or not implicit down cycling is enabled. If it is,
+ * then initiating a forward focus traversal operation onto a focus
+ * cycle root, the focus will be implicitly transferred into the
+ * root container's focus cycle.
+ *
+ * @return true if the focus will be transferred down-cycle
+ * implicitly
+ */
+ public boolean getImplicitDownCycleTraversal ()
{
return implicitDownCycleTraversal;
}
- protected boolean accept(Component current)
+ /**
+ * Check whether the given Component is an acceptable target for the
+ * keyboard input focus.
+ *
+ * @param current the Component to check
+ *
+ * @return true if current is acceptable, false otherwise
+ */
+ protected boolean accept (Component current)
{
return (current.visible
- && current.isDisplayable()
+ && current.isDisplayable ()
&& current.enabled
&& current.focusable);
}
-} // class ContainerOrderFocusTraversalPolicy
+}
Index: java/awt/DefaultFocusTraversalPolicy.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/DefaultFocusTraversalPolicy.java,v
retrieving revision 1.1
diff -u -r1.1 DefaultFocusTraversalPolicy.java
--- java/awt/DefaultFocusTraversalPolicy.java 9 Aug 2002 04:26:14 -0000 1.1
+++ java/awt/DefaultFocusTraversalPolicy.java 22 Apr 2004 16:01:10 -0000
@@ -39,17 +39,73 @@
package java.awt;
/**
- * STUB CLASS ONLY
+ * DefaultFocusTraversalPolicy is the default focus traversal policy
+ * used by Containers.
+ *
+ * This policy sharpens ContainerOrderFocusTraversalPolicy's
+ * acceptance criteria, to reject those Components that have
+ * unfocusable peers. Despite this extra strictness, this policy will
+ * always accept a Component that has explicitly been set focusable by
+ * any means.
+ *
+ * This AWT implementation assumes that the peers of the following
+ * Components are not focusable: Canvas, Panel, Label, ScrollPane,
+ * Scrollbar, Window, and any lightweight Component.
+ *
+ * A Component's focusability is independent of the focusability of
+ * its peer.
+ *
+ * @author Thomas Fitzsimmons
+ * @since 1.4
*/
public class DefaultFocusTraversalPolicy
extends ContainerOrderFocusTraversalPolicy
{
- public DefaultFocusTraversalPolicy()
+ /**
+ * Construct a default focus traversal policy.
+ */
+ public DefaultFocusTraversalPolicy ()
{
}
- protected boolean accept(Component comp)
+ /**
+ * Check whether a given Component would be acceptable as a focus
+ * owner. The Component must be displayable, visible and enabled to
+ * be acceptable. If the Component's focus traversability has been
+ * overridden, by overriding Component.isFocusTraversable or
+ * Component.isFocusable, or by calling Component.setFocusable, then
+ * the Component will be accepted if it is focusable. If the
+ * Component uses the default focus traversable behaviour, then
+ * comp
will always be rejected if it is a Canvas,
+ * Panel, Label, ScrollPane, Scrollbar, Window or lightweight
+ * Component.
+ *
+ * @param comp the Component to check
+ *
+ * @return true if the Component is an acceptable target for
+ * keyboard input focus, false otherwise
+ */
+ protected boolean accept (Component comp)
{
- throw new Error("not implemented");
+ if (comp.visible
+ && comp.isDisplayable ()
+ && comp.enabled)
+ {
+ if (comp.isFocusTraversableOverridden != 0
+ && comp.isFocusTraversable ())
+ return true;
+ else
+ {
+ if (!(comp instanceof Canvas
+ || comp instanceof Panel
+ || comp instanceof Label
+ || comp instanceof ScrollPane
+ || comp instanceof Scrollbar
+ || comp instanceof Window
+ || comp.isLightweight ()))
+ return true;
+ }
+ }
+ return false;
}
-} // class DefaultFocusTraversalPolicy
+}
Index: java/awt/DefaultKeyboardFocusManager.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/DefaultKeyboardFocusManager.java,v
retrieving revision 1.1
diff -u -r1.1 DefaultKeyboardFocusManager.java
--- java/awt/DefaultKeyboardFocusManager.java 9 Aug 2002 04:26:14 -0000 1.1
+++ java/awt/DefaultKeyboardFocusManager.java 22 Apr 2004 16:01:10 -0000
@@ -38,59 +38,434 @@
package java.awt;
-import java.awt.event.KeyEvent;
+import java.util.*;
+import java.awt.event.*;
-/**
- * STUB CLASS ONLY
- */
+// FIXME: finish documentation
public class DefaultKeyboardFocusManager extends KeyboardFocusManager
{
- public DefaultKeyboardFocusManager()
+ /**
+ * This class models a request to delay the dispatch of events that
+ * arrive after a certain time, until a certain component becomes
+ * the focus owner.
+ */
+ private class EventDelayRequest implements Comparable
+ {
+ /** A address@hidden java.util.List} of address@hidden java.awt.event.KeyEvent}s
+ that are being delayed, pending this request's address@hidden
+ Component} receiving the keyboard focus. */
+ private LinkedList enqueuedKeyEvents = new LinkedList ();
+
+ /** An event timestamp. All events that arrive after this time
+ should be queued in the address@hidden #enqueuedKeyEvents} address@hidden
+ java.util.List}. */
+ public long timestamp;
+ /** When this address@hidden Component} becomes focused, all events
+ between this EventDelayRequest and the next one in will be
+ dispatched from address@hidden #enqueuedKeyEvents}. */
+ public Component focusedComp;
+
+ /**
+ * Construct a new EventDelayRequest.
+ *
+ * @param timestamp events that arrive after this time will be
+ * delayed
+ * @param focusedComp the Component that needs to receive focus
+ * before events are dispatched
+ */
+ public EventDelayRequest (long timestamp, Component focusedComp)
+ {
+ this.timestamp = timestamp;
+ this.focusedComp = focusedComp;
+ }
+
+ public int compareTo (Object o)
+ {
+ if (!(o instanceof EventDelayRequest))
+ throw new ClassCastException ();
+
+ EventDelayRequest request = (EventDelayRequest) o;
+
+ if (request.timestamp < timestamp)
+ return -1;
+ else if (request.timestamp == timestamp)
+ return 0;
+ else
+ return 1;
+ }
+
+ public boolean equals (Object o)
+ {
+ if (!(o instanceof EventDelayRequest) || o == null)
+ return false;
+
+ EventDelayRequest request = (EventDelayRequest) o;
+
+ return (request.timestamp == timestamp
+ && request.focusedComp == focusedComp);
+ }
+
+ public void enqueueEvent (KeyEvent e)
+ {
+ KeyEvent last = (KeyEvent) enqueuedKeyEvents.getLast ();
+ if (last != null && e.getWhen () < last.getWhen ())
+ throw new RuntimeException ("KeyEvents enqueued out-of-order");
+
+ if (e.getWhen () <= timestamp)
+ throw new RuntimeException ("KeyEvents enqueued before starting timestamp");
+
+ enqueuedKeyEvents.add (e);
+ }
+
+ public void dispatchEvents ()
+ {
+ int size = enqueuedKeyEvents.size ();
+ for (int i = 0; i < size; i++)
+ {
+ KeyEvent e = (KeyEvent) enqueuedKeyEvents.remove (0);
+ dispatchKeyEvent (e);
+ }
+ }
+
+ public void discardEvents ()
+ {
+ enqueuedKeyEvents.clear ();
+ }
+ }
+
+ /** The address@hidden java.util.SortedSet} of current address@hidden
+ #EventDelayRequest}s. */
+ private SortedSet delayRequests = new TreeSet ();
+
+ public DefaultKeyboardFocusManager ()
{
}
- public boolean dispatchEvent(AWTEvent e)
+ public boolean dispatchEvent (AWTEvent e)
{
- throw new Error("not implemented");
+ if (e instanceof WindowEvent)
+ {
+ Window target = (Window) e.getSource ();
+
+ if (e.id == WindowEvent.WINDOW_ACTIVATED)
+ setGlobalActiveWindow (target);
+ else if (e.id == WindowEvent.WINDOW_GAINED_FOCUS)
+ setGlobalFocusedWindow (target);
+ else if (e.id != WindowEvent.WINDOW_LOST_FOCUS
+ && e.id != WindowEvent.WINDOW_DEACTIVATED)
+ return false;
+
+ target.dispatchEvent (e);
+ return true;
+ }
+ else if (e instanceof FocusEvent)
+ {
+ Component target = (Component) e.getSource ();
+
+ if (e.id == FocusEvent.FOCUS_GAINED)
+ {
+ if (((FocusEvent) e).isTemporary ())
+ setGlobalFocusOwner (target);
+ else
+ {
+ System.out.println ("SETTING FOCUS TO: " + target);
+ setGlobalPermanentFocusOwner (target);
+ }
+ }
+
+ target.dispatchEvent (e);
+ return true;
+ }
+ else if (e instanceof KeyEvent)
+ {
+ // Loop through all registered KeyEventDispatchers, giving
+ // each a chance to handle this event.
+ Iterator i = keyEventDispatchers.iterator ();
+
+ while (i.hasNext ())
+ {
+ KeyEventDispatcher dispatcher = (KeyEventDispatcher) i.next ();
+ if (dispatcher.dispatchKeyEvent ((KeyEvent) e))
+ return true;
+ }
+
+ // processKeyEvent checks if this event represents a focus
+ // traversal key stroke.
+ Component focusOwner = getGlobalPermanentFocusOwner ();
+ processKeyEvent (focusOwner, (KeyEvent) e);
+
+ if (e.isConsumed ())
+ return true;
+
+ if (enqueueKeyEvent ((KeyEvent) e))
+ // This event was enqueued for dispatch at a later time.
+ return true;
+ else
+ // This event wasn't handled by any of the registered
+ // KeyEventDispatchers, and wasn't enqueued for dispatch
+ // later, so send it to the default dispatcher.
+ return dispatchKeyEvent ((KeyEvent) e);
+ }
+
+ return false;
}
- public boolean dispatchKeyEvent(KeyEvent e)
+
+ private boolean enqueueKeyEvent (KeyEvent e)
{
- throw new Error("not implemented");
+ Iterator i = delayRequests.iterator ();
+ boolean oneEnqueued = false;
+ while (i.hasNext ())
+ {
+ EventDelayRequest request = (EventDelayRequest) i.next ();
+ if (e.getWhen () > request.timestamp)
+ {
+ request.enqueueEvent (e);
+ oneEnqueued = true;
+ }
+ }
+ return oneEnqueued;
+ }
+
+ public boolean dispatchKeyEvent (KeyEvent e)
+ {
+ // System.out.println ("DefaultKeyboardFocusManager.dispatchKeyEvent: " + e);
+
+ Component focusOwner = getGlobalPermanentFocusOwner ();
+
+ focusOwner.dispatchEvent (e);
+
+ // Loop through all registered KeyEventPostProcessors, giving
+ // each a chance to process this event.
+ Iterator i = keyEventPostProcessors.iterator ();
+
+ while (i.hasNext ())
+ {
+ KeyEventPostProcessor processor = (KeyEventPostProcessor) i.next ();
+ if (processor.postProcessKeyEvent ((KeyEvent) e))
+ return true;
+ }
+
+ // The event hasn't been consumed yet. Check if it is an
+ // MenuShortcut.
+ if (postProcessKeyEvent (e))
+ return true;
+
+ // FIXME: how do we "pass the event to the peers for processing"?
+
+ // Always return true.
+ return true;
}
- public boolean postProcessKeyEvent(KeyEvent e)
+
+ public boolean postProcessKeyEvent (KeyEvent e)
{
- throw new Error("not implemented");
+ // System.out.println ("DefaultKeyboardFocusManager.postProcessKeyEvent: " + e);
+
+ // Check if this event represents a menu shortcut.
+
+ // MenuShortcuts are activated by Ctrl- KeyEvents.
+ int modifiers = e.getModifiers ();
+ if ((modifiers & KeyEvent.CTRL_MASK) != 0
+ || (modifiers & KeyEvent.CTRL_DOWN_MASK) != 0)
+ {
+ Window focusedWindow = getGlobalFocusedWindow ();
+ if (focusedWindow instanceof Frame)
+ {
+ MenuBar menubar = ((Frame) focusedWindow).getMenuBar ();
+
+ if (menubar != null)
+ {
+ // If there's a menubar, loop through all menu items,
+ // checking whether each one has a shortcut, and if
+ // so, whether this key event should activate it.
+ int numMenus = menubar.getMenuCount ();
+
+ for (int i = 0; i < numMenus; i++)
+ {
+ Menu menu = menubar.getMenu (i);
+ int numItems = menu.getItemCount ();
+
+ for (int j = 0; j < numItems; j++)
+ {
+ MenuItem item = menu.getItem (j);
+ MenuShortcut shortcut = item.getShortcut ();
+
+ if (shortcut != null)
+ {
+ // Dispatch a new ActionEvent if this is a
+ // Shift- KeyEvent and the shortcut requires
+ // the Shift modifier, or if the shortcut
+ // doesn't require the Shift modifier.
+ if ((shortcut.usesShiftModifier ()
+ && ((modifiers & KeyEvent.SHIFT_MASK) != 0
+ || (modifiers & KeyEvent.SHIFT_DOWN_MASK) != 0)
+ || !shortcut.usesShiftModifier ())
+ && shortcut.getKey () == e.getKeyCode ())
+ {
+ item.dispatchEvent (new ActionEvent (item,
+ ActionEvent.ACTION_PERFORMED,
+ item.getActionCommand (),
+ modifiers));
+ // The event was dispatched.
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
}
- public void processKeyEvent(Component comp, KeyEvent e)
+
+ public void processKeyEvent (Component comp, KeyEvent e)
{
- throw new Error("not implemented");
+ // System.out.println ("DefaultKeyboardFocusManager.processKeyEvent: " + e);
+
+ AWTKeyStroke keystroke = AWTKeyStroke.getAWTKeyStrokeForEvent (e);
+
+ Set forwardKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+ Set backwardKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+ Set upKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
+ Set downKeystrokes = null;
+ if (comp instanceof Container)
+ downKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
+
+ if (forwardKeystrokes.contains (keystroke))
+ {
+ focusNextComponent (comp);
+ e.consume ();
+ }
+ else if (backwardKeystrokes.contains (keystroke))
+ {
+ focusPreviousComponent (comp);
+ e.consume ();
+ }
+ else if (upKeystrokes.contains (keystroke))
+ {
+ upFocusCycle (comp);
+ e.consume ();
+ }
+ else if (comp instanceof Container
+ && downKeystrokes.contains (keystroke))
+ {
+ downFocusCycle ((Container) comp);
+ e.consume ();
+ }
}
- protected void enqueueKeyEvents(long after, Component comp)
+
+ protected void enqueueKeyEvents (long after, Component untilFocused)
{
- throw new Error("not implemented");
+ System.out.println ("DefaultKeyboardFocusManager.enqueueKeyEvents: " + untilFocused);
+
+ delayRequests.add (new EventDelayRequest (after, untilFocused));
}
- protected void dequeueKeyEvents(long after, Component comp)
+
+ protected void dequeueKeyEvents (long after, Component untilFocused)
{
- throw new Error("not implemented");
+ System.out.println ("DefaultKeyboardFocusManager.dequeueKeyEvents: " + untilFocused);
+
+ // FIXME: need synchronization on delayRequests and enqueuedKeyEvents.
+
+ // Remove the KeyEvent with the oldest timestamp, which should be
+ // the first element in the SortedSet.
+ if (after < 0)
+ {
+ int size = delayRequests.size ();
+ if (size > 0)
+ delayRequests.remove (delayRequests.first ());
+ }
+ else
+ {
+ EventDelayRequest template = new EventDelayRequest (after, untilFocused);
+ if (delayRequests.contains (template))
+ {
+ EventDelayRequest actual = (EventDelayRequest) delayRequests.tailSet (template).first ();
+ delayRequests.remove (actual);
+ actual.dispatchEvents ();
+ }
+ }
}
- protected void discardKeyEvents(Component comp)
+
+ protected void discardKeyEvents (Component comp)
{
- throw new Error("not implemented");
+ System.out.println ("DefaultKeyboardFocusManager.discardKeyEvents: " + comp);
+
+ // FIXME: need synchronization on delayRequests and enqueuedKeyEvents.
+
+ Iterator i = delayRequests.iterator ();
+
+ while (i.hasNext ())
+ {
+ EventDelayRequest request = (EventDelayRequest) i.next ();
+
+ if (request.focusedComp == comp
+ || (comp instanceof Container
+ && ((Container) comp).isAncestorOf (request.focusedComp)))
+ request.discardEvents ();
+ }
}
- public void focusPreviousComponent(Component comp)
+
+ public void focusPreviousComponent (Component comp)
{
- throw new Error("not implemented");
+ System.out.println ("DefaultKeyboardFocusManager.focusPreviousComponent: " + comp);
+
+ Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp;
+ Container focusCycleRoot = focusComp.getFocusCycleRootAncestor ();
+ FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy ();
+
+ Component previous = policy.getComponentBefore (focusCycleRoot, focusComp);
+ previous.requestFocus ();
}
- public void focusNextComponent(Component comp)
+
+ public void focusNextComponent (Component comp)
{
- throw new Error("not implemented");
+ System.out.println ("DefaultKeyboardFocusManager.focusNextComponent: " + comp);
+
+ Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp;
+ Container focusCycleRoot = focusComp.getFocusCycleRootAncestor ();
+ FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy ();
+
+ Component next = policy.getComponentAfter (focusCycleRoot, focusComp);
+ System.out.println ("Got next component: " + next);
+ System.out.println ("Got focus comp: " + focusComp);
+ next.requestFocus ();
}
- public void upFocusCycle(Component comp)
+
+ public void upFocusCycle (Component comp)
{
- throw new Error("not implemented");
+ System.out.println ("DefaultKeyboardFocusManager.upFocusCycle: " + comp);
+
+ Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp;
+ Container focusCycleRoot = focusComp.getFocusCycleRootAncestor ();
+
+ if (focusCycleRoot instanceof Window)
+ {
+ FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy ();
+ Component defaultComponent = policy.getDefaultComponent (focusCycleRoot);
+ defaultComponent.requestFocus ();
+ }
+ else
+ {
+ Container parentFocusCycleRoot = focusCycleRoot.getFocusCycleRootAncestor ();
+
+ focusCycleRoot.requestFocus ();
+ setGlobalCurrentFocusCycleRoot (parentFocusCycleRoot);
+ }
}
- public void downFocusCycle(Container cont)
+
+ public void downFocusCycle (Container cont)
{
- throw new Error("not implemented");
+ System.out.println ("DefaultKeyboardFocusManager.downFocusCycle: " + cont);
+
+ if (cont == null)
+ return;
+
+ if (cont.isFocusCycleRoot (cont))
+ {
+ FocusTraversalPolicy policy = cont.getFocusTraversalPolicy ();
+ Component defaultComponent = policy.getDefaultComponent (cont);
+ defaultComponent.requestFocus ();
+ setGlobalCurrentFocusCycleRoot (cont);
+ }
}
} // class DefaultKeyboardFocusManager
Index: java/awt/EventDispatchThread.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/EventDispatchThread.java,v
retrieving revision 1.5
diff -u -r1.5 EventDispatchThread.java
--- java/awt/EventDispatchThread.java 16 Jan 2004 16:15:49 -0000 1.5
+++ java/awt/EventDispatchThread.java 22 Apr 2004 16:01:10 -0000
@@ -57,6 +57,9 @@
public void run()
{
+ // Set the default KeyboardFocusManager.
+ KeyboardFocusManager.setCurrentKeyboardFocusManager (null);
+
while (true)
{
try
@@ -67,7 +70,23 @@
// We are interrupted when we should finish executing
return;
}
- queue.dispatchEvent(evt);
+
+ KeyboardFocusManager manager;
+ manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+ // Try to dispatch this event to the current keyboard focus
+ // manager. It will dispatch all FocusEvents, all
+ // WindowEvents related to focus, and all KeyEvents,
+ // returning true. Otherwise, it returns false and we
+ // dispatch the event normally.
+ if (!manager.dispatchEvent (evt))
+ {
+ queue.dispatchEvent(evt);
+ }
+ else
+ {
+ // System.out.println ("Dispatched " + evt + " to DefaultKeyboardFocusManager");
+ }
}
catch (InterruptedException ie)
{
Index: java/awt/KeyboardFocusManager.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/KeyboardFocusManager.java,v
retrieving revision 1.2
diff -u -r1.2 KeyboardFocusManager.java
--- java/awt/KeyboardFocusManager.java 13 Feb 2003 07:02:12 -0000 1.2
+++ java/awt/KeyboardFocusManager.java 22 Apr 2004 16:01:10 -0000
@@ -39,34 +39,66 @@
package java.awt;
import java.awt.event.KeyEvent;
+import java.awt.event.FocusEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+// FIXME: finish documentation
+
/**
*
+ * FIXME: discuss applet contexts and thread groups and codebases
+ * being insulated.
+ *
+ * FIXME: discuss where default focus traversal key sets apply
+ * (inherited by child Components etc.)
+ *
* @author Eric Blake
+ * @author Thomas Fitzsimmons
* @since 1.4
* @status partially updated to 1.4, needs documentation.
*/
public abstract class KeyboardFocusManager
implements KeyEventDispatcher, KeyEventPostProcessor
{
+ /** Identifies address@hidden AWTKeyStroke}s that move the focus forward in
+ the focus cycle. */
public static final int FORWARD_TRAVERSAL_KEYS = 0;
+
+ /** Identifies address@hidden AWTKeyStroke}s that move the focus backward in
+ the focus cycle. */
public static final int BACKWARD_TRAVERSAL_KEYS = 1;
+
+ /** Identifies address@hidden AWTKeyStroke}s that move the focus up to the
+ parent focus cycle root. */
public static final int UP_CYCLE_TRAVERSAL_KEYS = 2;
+
+ /** Identifies address@hidden AWTKeyStroke}s that move the focus down to the
+ child focus cycle root. */
public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3;
+ /** The set of address@hidden AWTKeyStroke}s that cause focus to be moved to
+ the next focusable Component in the focus cycle. */
private static final Set DEFAULT_FORWARD_KEYS;
+
+ /** The set of address@hidden AWTKeyStroke}s that cause focus to be moved to
+ the previous focusable Component in the focus cycle. */
private static final Set DEFAULT_BACKWARD_KEYS;
+
+ /** Populate the DEFAULT_FORWARD_KEYS and DEFAULT_BACKWARD_KEYS
+ address@hidden java.util.Set}s. */
static
{
Set s = new HashSet();
@@ -83,232 +115,403 @@
DEFAULT_BACKWARD_KEYS = Collections.unmodifiableSet(s);
}
- private static KeyboardFocusManager current
- = new DefaultKeyboardFocusManager();
-
- // XXX Not implemented correctly. I think a good implementation here may
- // be to have permanentFocusOwner be null, and fall back to focusOwner,
- // unless a temporary focus change is in effect.
- private static Component focusOwner;
- private static Component permanentFocusOwner;
-
- private static Window focusedWindow;
- private static Window activeWindow;
- private static Container focusCycleRoot;
+ /** The global object address@hidden java.util.Map}s. */
+ /** For security reasons, address@hidden java.applet.Applet}s in different
+ codebases must be insulated from one another. Since address@hidden
+ KeyboardFocusManager}s have the ability to return address@hidden
+ Component}s from a given address@hidden java.applet.Applet}, each
+ codebase must have an independent address@hidden KeyboardFocusManager}.
+ Since each codebase has its own address@hidden ThreadGroup} in which its
+ address@hidden Applet}s run, it makes sense to partition address@hidden
+ KeyboardFocusManager}s according to address@hidden
+ java.lang.ThreadGroup}. Thus, currentKeyboardFocusManagers is a
+ address@hidden java.util.Map} keyed on address@hidden java.lang.ThreadGroup}. */
+ private static Map currentKeyboardFocusManagers = new HashMap ();
+
+ /** address@hidden java.applet.Applet}s in one codebase must not be allowed
+ to access address@hidden Component}s in address@hidden java.applet.Applet}s in
+ other codebases. To enforce this restriction, we key the
+ following address@hidden java.util.Map}s on address@hidden java.lang.ThreadGroup}s (which
+ are per-codebase). For example, if address@hidden
+ java.lang.ThreadGroup} A calls address@hidden #setGlobalFocusOwner},
+ passing address@hidden Component} C, currentFocusOwners[A] is assigned
+ C, and all other currentFocusOwners values are nullified. Then
+ if address@hidden java.lang.ThreadGroup} A subsequently calls address@hidden
+ #getGlobalFocusOwner}, it will return currentFocusOwners[A],
+ that is, address@hidden Component} C. If another address@hidden
+ java.lang.ThreadGroup} K calls address@hidden #getGlobalFocusOwner}, it
+ will return currentFocusOwners[K], that is, null.
+
+ Since this is a static field, we ensure that there is only one
+ focused address@hidden Component} per class loader. */
+ private static Map currentFocusOwners = new HashMap ();
+
+ /** A address@hidden java.util.Map} keyed on address@hidden java.lang.ThreadGroup}s
+ that stores the address@hidden Component} that owns the permanent
+ keyboard focus. @see currentFocusOwners */
+ private static Map currentPermanentFocusOwners = new HashMap ();
+
+ /** A address@hidden java.util.Map} keyed on address@hidden java.lang.ThreadGroup}s
+ that stores the focused address@hidden Window}. @see
+ currentFocusOwners */
+ private static Map currentFocusedWindows = new HashMap ();
+
+ /** A address@hidden java.util.Map} keyed on address@hidden java.lang.ThreadGroup}s
+ that stores the active address@hidden Window}. @see
+ currentFocusOwners */
+ private static Map currentActiveWindows = new HashMap ();
+
+ /** A address@hidden java.util.Map} keyed on address@hidden java.lang.ThreadGroup}s
+ that stores the focus cycle root address@hidden Container}. @see
+ currentFocusOwners */
+ private static Map currentFocusCycleRoots = new HashMap ();
+
+ /** The default address@hidden FocusTraveralPolicy} that focus-managing
+ address@hidden Container}s will use to define their initial focus
+ traversal policy. */
private FocusTraversalPolicy defaultPolicy;
- private Set[] defaultFocusKeys = new Set[] {
+
+ /** An array that stores the address@hidden #FORWARD_TRAVERSAL_KEYS}, address@hidden
+ #BACKWARD_TRAVERSAL_KEYS}, address@hidden #UP_CYCLE_TRAVERSAL_KEYS} and
+ address@hidden #DOWN_CYCLE_TRAVERSAL_KEYS} address@hidden AWTKeyStroke}s address@hidden
+ java.util.Set}s. */
+ private Set[] defaultFocusKeys = new Set[]
+ {
DEFAULT_FORWARD_KEYS, DEFAULT_BACKWARD_KEYS,
Collections.EMPTY_SET, Collections.EMPTY_SET
};
- private final PropertyChangeSupport propertyChangeSupport
- = new PropertyChangeSupport(this);
- private final VetoableChangeSupport vetoableChangeSupport
- = new VetoableChangeSupport(this);
+ private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport (this);
+ private final VetoableChangeSupport vetoableChangeSupport = new VetoableChangeSupport (this);
+
+ /** A list of address@hidden KeyEventDispatcher}s that process address@hidden
+ KeyEvent}s before they are processed the default keyboard focus
+ manager. */
private final ArrayList keyEventDispatchers = new ArrayList();
- private final ArrayList keyEventPostProcessors = new ArrayList();
-
- public KeyboardFocusManager()
- {
- }
+ /** A list of address@hidden KeyEventPostProcessor}s that process unconsumed
+ address@hidden KeyEvent}s. */
+ private final ArrayList keyEventPostProcessors = new ArrayList();
- public static KeyboardFocusManager getCurrentKeyboardFocusManager()
+ /**
+ * Construct a KeyboardFocusManager.
+ */
+ public KeyboardFocusManager ()
{
- // XXX Need a way to divide this into contexts.
- return current;
}
- public static void setCurrentKeyboardFocusManager(KeyboardFocusManager m)
+ /**
+ * Retrieve the keyboard focus manager associated with the address@hidden
+ * java.lang.ThreadGroup} to which the calling thread belongs.
+ *
+ * @return the keyboard focus manager associated with the current
+ * thread group
+ */
+ public static KeyboardFocusManager getCurrentKeyboardFocusManager ()
+ {
+ ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup ();
+ return (KeyboardFocusManager) currentKeyboardFocusManagers.get (currentGroup);
+ }
+
+ /**
+ * Set the keyboard focus manager associated with the address@hidden
+ * java.lang.ThreadGroup} to which the calling thread belongs.
+ *
+ * @param m the keyboard focus manager for the current thread group
+ */
+ public static void setCurrentKeyboardFocusManager (KeyboardFocusManager m)
{
- SecurityManager sm = System.getSecurityManager();
+ SecurityManager sm = System.getSecurityManager ();
if (sm != null)
- sm.checkPermission(new AWTPermission("replaceKeyboardFocusManager"));
- // XXX Need a way to divide this into contexts.
- current = m == null ? new DefaultKeyboardFocusManager() : m;
- }
+ sm.checkPermission (new AWTPermission ("replaceKeyboardFocusManager"));
- public Component getFocusOwner()
- {
- // XXX Need an easy way to test if this thread is in the context of the
- // global focus owner, to avoid creating the exception in the first place.
- try
- {
- return getGlobalFocusOwner();
- }
- catch (SecurityException e)
- {
- return null;
- }
- }
-
- protected Component getGlobalFocusOwner()
- {
- // XXX Need a way to test if this thread is in the context of the focus
- // owner, and throw a SecurityException if that is the case.
- // XXX Implement.
- return focusOwner;
- }
+ ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup ();
+ KeyboardFocusManager manager;
- protected void setGlobalFocusOwner(Component owner)
+ if (m == null)
+ manager = new DefaultKeyboardFocusManager ();
+ else
+ manager = m;
+
+ currentKeyboardFocusManagers.put (currentGroup, manager);
+ }
+
+ /**
+ * Retrieve the address@hidden Component} that has the keyboard focus, or
+ * null if the focus owner was not set by a thread in the current
+ * address@hidden java.lang.ThreadGroup}.
+ *
+ * @return the keyboard focus owner or null
+ */
+ public Component getFocusOwner ()
+ {
+ return (Component) getObject (currentFocusOwners);
+ }
+
+ /**
+ * Retrieve the address@hidden Component} that has the keyboard focus,
+ * regardless of whether or not it was set by a thread in the
+ * current address@hidden java.lang.ThreadGroup}. If there is no temporary
+ * focus owner in effect then this method will return the same value
+ * as address@hidden #getGlobalPermanentFocusOwner}.
+ *
+ * @return the keyboard focus owner
+ * @throws SecurityException if this is not the keyboard focus
+ * manager associated with the current address@hidden java.lang.ThreadGroup}
+ */
+ protected Component getGlobalFocusOwner ()
+ {
+ // Check if there is a temporary focus owner.
+ Component focusOwner = (Component) getGlobalObject (currentFocusOwners);
+
+ return (focusOwner == null) ? getGlobalPermanentFocusOwner () : focusOwner;
+ }
+
+ /**
+ * Set the address@hidden Component} that will be returned by address@hidden
+ * #getFocusOwner} (when it is called from the current address@hidden
+ * java.lang.ThreadGroup}) and address@hidden #getGlobalFocusOwner}. This
+ * method does not actually transfer the keyboard focus.
+ *
+ * @param owner the Component to return from getFocusOwner and
+ * getGlobalFocusOwner
+ *
+ * @see Component.requestFocus ()
+ * @see Component.requestFocusInWindow ()
+ */
+ protected void setGlobalFocusOwner (Component owner)
{
- // XXX Should this send focus events to the components involved?
if (owner == null || owner.focusable)
- {
- firePropertyChange("focusOwner", focusOwner, owner);
- try
- {
- fireVetoableChange("focusOwner", focusOwner, owner);
- focusOwner = owner;
- }
- catch (PropertyVetoException e)
- {
- }
- }
+ setGlobalObject (currentFocusOwners, owner, "focusOwner");
}
- public void clearGlobalFocusOwner()
+ /**
+ * Clear the global focus owner and deliver a FOCUS_LOST event to
+ * the previously-focused address@hidden Component}. Until another address@hidden
+ * Component} becomes the keyboard focus owner, key events will be
+ * discarded by top-level windows.
+ */
+ public void clearGlobalFocusOwner ()
{
- // XXX Is this enough?
- setGlobalFocusOwner(null);
- }
-
- public Component getPermanentFocusOwner()
- {
- // XXX Need an easy way to test if this thread is in the context of the
- // global focus owner, to avoid creating the exception in the first place.
- try
+ synchronized (currentFocusOwners)
{
- return getGlobalPermanentFocusOwner();
- }
- catch (SecurityException e)
- {
- return null;
- }
- }
+ Component focusOwner = getGlobalFocusOwner ();
+ Component permanentFocusOwner = getGlobalPermanentFocusOwner ();
- protected Component getGlobalPermanentFocusOwner()
- {
- // XXX Need a way to test if this thread is in the context of the focus
- // owner, and throw a SecurityException if that is the case.
- // XXX Implement.
- return permanentFocusOwner == null ? focusOwner : permanentFocusOwner;
- }
+ setGlobalFocusOwner (null);
+ setGlobalPermanentFocusOwner (null);
- protected void setGlobalPermanentFocusOwner(Component focusOwner)
- {
- // XXX Should this send focus events to the components involved?
- if (focusOwner == null || focusOwner.focusable)
- {
- firePropertyChange("permanentFocusOwner", permanentFocusOwner,
- focusOwner);
- try
+ // Inform the old focus owner that it has lost permanent
+ // focus.
+ if (focusOwner != null)
{
- fireVetoableChange("permanentFocusOwner", permanentFocusOwner,
- focusOwner);
- permanentFocusOwner = focusOwner;
+ // We can't cache the event queue, because of
+ // bootstrapping issues. We need to set the default
+ // KeyboardFocusManager in EventQueue before the event
+ // queue is started.
+ EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
+ if (focusOwner != permanentFocusOwner)
+ q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, true));
+ else
+ q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, false));
}
- catch (PropertyVetoException e)
+
+ if (focusOwner != permanentFocusOwner)
{
+ EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
+ q.postEvent (new FocusEvent (permanentFocusOwner, FocusEvent.FOCUS_LOST, false));
}
}
}
- public Window getFocusedWindow()
+ /**
+ * Retrieve the address@hidden Component} that has the permanent keyboard
+ * focus, or null if the focus owner was not set by a thread in the
+ * current address@hidden java.lang.ThreadGroup}.
+ *
+ * @return the keyboard focus owner or null
+ */
+ public Component getPermanentFocusOwner ()
+ {
+ return (Component) getObject (currentPermanentFocusOwners);
+ }
+
+ /**
+ * Retrieve the address@hidden Component} that has the permanent keyboard
+ * focus, regardless of whether or not it was set by a thread in the
+ * current address@hidden java.lang.ThreadGroup}.
+ *
+ * @return the keyboard focus owner
+ * @throws SecurityException if this is not the keyboard focus
+ * manager associated with the current address@hidden java.lang.ThreadGroup}
+ */
+ protected Component getGlobalPermanentFocusOwner ()
+ {
+ return (Component) getGlobalObject (currentPermanentFocusOwners);
+ }
+
+ /**
+ * Set the address@hidden Component} that will be returned by address@hidden
+ * #getPermanentFocusOwner} (when it is called from the current
+ * address@hidden java.lang.ThreadGroup}) and address@hidden
+ * #getGlobalPermanentFocusOwner}. This method does not actually
+ * transfer the keyboard focus.
+ *
+ * @param focusOwner the Component to return from
+ * getPermanentFocusOwner and getGlobalPermanentFocusOwner
+ *
+ * @see Component.requestFocus ()
+ * @see Component.requestFocusInWindow ()
+ */
+ protected void setGlobalPermanentFocusOwner (Component focusOwner)
{
- // XXX Need an easy way to test if this thread is in the context of the
- // global focus owner, to avoid creating the exception in the first place.
- try
- {
- return getGlobalFocusedWindow();
- }
- catch (SecurityException e)
- {
- return null;
- }
- }
-
- protected Window getGlobalFocusedWindow()
- {
- // XXX Need a way to test if this thread is in the context of the focus
- // owner, and throw a SecurityException if that is the case.
- // XXX Implement.
- return focusedWindow;
+ System.out.println ("in setGlobalFocusOwner: " + focusOwner);
+ if (focusOwner == null || focusOwner.focusable)
+ setGlobalObject (currentPermanentFocusOwners, focusOwner,
+ "permanentFocusOwner");
}
- protected void setGlobalFocusedWindow(Window window)
+ /**
+ * Retrieve the address@hidden Window} that is or contains the keyboard
+ * focus owner, or null if the focused window was not set by a
+ * thread in the current address@hidden java.lang.ThreadGroup}.
+ *
+ * @return the focused window or null
+ */
+ public Window getFocusedWindow ()
+ {
+ return (Window) getObject (currentFocusedWindows);
+ }
+
+ /**
+ * Retrieve the address@hidden Window} that is or contains the focus owner,
+ * regardless of whether or not the address@hidden Window} was set focused
+ * by a thread in the current address@hidden java.lang.ThreadGroup}.
+ *
+ * @return the focused window
+ * @throws SecurityException if this is not the keyboard focus
+ * manager associated with the current address@hidden java.lang.ThreadGroup}
+ */
+ protected Window getGlobalFocusedWindow ()
+ {
+ return (Window) getGlobalObject (currentFocusedWindows);
+ }
+
+ /**
+ * Set the address@hidden Window} that will be returned by address@hidden
+ * #getFocusedWindow} (when it is called from the current address@hidden
+ * java.lang.ThreadGroup}) and address@hidden #getGlobalFocusedWindow}.
+ * This method does not actually cause window
to become
+ * the focused address@hidden Window}.
+ *
+ * @param window the Window to return from getFocusedWindow and
+ * getGlobalFocusedWindow
+ */
+ protected void setGlobalFocusedWindow (Window window)
{
- // XXX Should this send focus events to the windows involved?
if (window == null || window.focusable)
- {
- firePropertyChange("focusedWindow", focusedWindow, window);
- try
- {
- fireVetoableChange("focusedWindow", focusedWindow, window);
- focusedWindow = window;
- }
- catch (PropertyVetoException e)
- {
- }
- }
+ setGlobalObject (currentFocusedWindows, window, "focusedWindow");
}
+ /**
+ * Retrieve the active address@hidden Window}, or null if the active window
+ * was not set by a thread in the current address@hidden
+ * java.lang.ThreadGroup}.
+ *
+ * @return the active window or null
+ */
public Window getActiveWindow()
{
- // XXX Need an easy way to test if this thread is in the context of the
- // global focus owner, to avoid creating the exception in the first place.
- try
- {
- return getGlobalActiveWindow();
- }
- catch (SecurityException e)
- {
- return null;
- }
+ return (Window) getObject (currentActiveWindows);
}
+ /**
+ * Retrieve the active address@hidden Window}, regardless of whether or not
+ * the address@hidden Window} was made active by a thread in the current
+ * address@hidden java.lang.ThreadGroup}.
+ *
+ * @return the active window
+ * @throws SecurityException if this is not the keyboard focus
+ * manager associated with the current address@hidden java.lang.ThreadGroup}
+ */
protected Window getGlobalActiveWindow()
{
- // XXX Need a way to test if this thread is in the context of the focus
- // owner, and throw a SecurityException if that is the case.
- // XXX Implement.
- return activeWindow;
+ return (Window) getGlobalObject (currentActiveWindows);
}
+ /**
+ * Set the address@hidden Window} that will be returned by address@hidden
+ * #getActiveWindow} (when it is called from the current address@hidden
+ * java.lang.ThreadGroup}) and address@hidden #getGlobalActiveWindow}. This
+ * method does not actually cause window
to be made
+ * active.
+ *
+ * @param window the Window to return from getActiveWindow and
+ * getGlobalActiveWindow
+ */
protected void setGlobalActiveWindow(Window window)
{
- // XXX Should this send focus events to the windows involved?
- firePropertyChange("activeWindow", activeWindow, window);
- try
- {
- fireVetoableChange("activeWindow", activeWindow, window);
- activeWindow = window;
- }
- catch (PropertyVetoException e)
- {
- }
+ setGlobalObject (currentActiveWindows, window, "activeWindow");
}
- public FocusTraversalPolicy getDefaultFocusTraversalPolicy()
+ /**
+ * Retrieve the default address@hidden FocusTraversalPolicy}.
+ * Focus-managing address@hidden Container}s use the returned object to
+ * define their initial focus traversal policy.
+ *
+ * @return a non-null default FocusTraversalPolicy object
+ */
+ public FocusTraversalPolicy getDefaultFocusTraversalPolicy ()
{
if (defaultPolicy == null)
- defaultPolicy = new DefaultFocusTraversalPolicy();
+ defaultPolicy = new DefaultFocusTraversalPolicy ();
return defaultPolicy;
}
- public void setDefaultFocusTraversalPolicy(FocusTraversalPolicy policy)
+ /**
+ * Set the address@hidden FocusTraversalPolicy} returned by address@hidden
+ * #getDefaultFocusTraversalPolicy}. Focus-managing address@hidden
+ * Container}s created after this call will use policy as their
+ * initial focus traversal policy. Existing address@hidden Container}s'
+ * focus traversal policies will not be affected by calls to this
+ * method.
+ *
+ * @param policy the FocusTraversalPolicy that will be returned by
+ * subsequent calls to getDefaultFocusTraversalPolicy
+ * @throws IllegalArgumentException if policy is null
+ */
+ public void setDefaultFocusTraversalPolicy (FocusTraversalPolicy policy)
{
if (policy == null)
- throw new IllegalArgumentException();
- firePropertyChange("defaultFocusTraversalPolicy", defaultPolicy, policy);
+ throw new IllegalArgumentException ();
+ firePropertyChange ("defaultFocusTraversalPolicy", defaultPolicy, policy);
defaultPolicy = policy;
}
- public void setDefaultFocusTraversalKeys(int id, Set keystrokes)
- {
+ /**
+ * Set the default address@hidden java.util.Set} of focus traversal keys for
+ * one of the focus traversal directions.
+ *
+ * @param id focus traversal direction identifier
+ * @param keystrokes set of AWTKeyStrokes
+ *
+ * @see #FORWARD_TRAVERSAL_KEYS
+ * @see #BACKWARD_TRAVERSAL_KEYS
+ * @see #UP_CYCLE_TRAVERSAL_KEYS
+ * @see #DOWN_CYCLE_TRAVERSAL_KEYS
+ */
+ public void setDefaultFocusTraversalKeys (int id, Set keystrokes)
+ {
+ if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
+ id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
+ id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS &&
+ id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
+ throw new IllegalArgumentException ();
+
if (keystrokes == null)
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException ();
+
Set sa;
Set sb;
Set sc;
@@ -340,56 +543,82 @@
type = "downCycleDefaultFocusTraversalKeys";
break;
default:
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException ();
}
- int i = keystrokes.size();
- Iterator iter = keystrokes.iterator();
+ int i = keystrokes.size ();
+ Iterator iter = keystrokes.iterator ();
while (--i >= 0)
{
- Object o = iter.next();
- if (! (o instanceof AWTKeyStroke)
- || sa.contains(o) || sb.contains(o) || sc.contains(o)
+ Object o = iter.next ();
+ if (!(o instanceof AWTKeyStroke)
+ || sa.contains (o) || sb.contains (o) || sc.contains (o)
|| ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED)
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException ();
}
- keystrokes = Collections.unmodifiableSet(new HashSet(keystrokes));
- firePropertyChange(type, defaultFocusKeys[id], keystrokes);
+ keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes));
+ firePropertyChange (type, defaultFocusKeys[id], keystrokes);
defaultFocusKeys[id] = keystrokes;
}
- public Set getDefaultFocusTraversalKeys(int id)
+ /**
+ * Retrieve the default address@hidden java.util.Set} of focus traversal
+ * keys for one of the focus traversal directions.
+ *
+ * @param id focus traversal direction identifier
+ *
+ * @return the default set of AWTKeyStrokes
+ *
+ * @see #FORWARD_TRAVERSAL_KEYS
+ * @see #BACKWARD_TRAVERSAL_KEYS
+ * @see #UP_CYCLE_TRAVERSAL_KEYS
+ * @see #DOWN_CYCLE_TRAVERSAL_KEYS
+ */
+ public Set getDefaultFocusTraversalKeys (int id)
{
if (id < FORWARD_TRAVERSAL_KEYS || id > DOWN_CYCLE_TRAVERSAL_KEYS)
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException ();
return defaultFocusKeys[id];
}
- public Container getCurrentFocusCycleRoot()
- {
- // XXX Need an easy way to test if this thread is in the context of the
- // global focus owner, to avoid creating the exception in the first place.
- try
- {
- return getGlobalCurrentFocusCycleRoot();
- }
- catch (SecurityException e)
- {
- return null;
- }
- }
-
- protected Container getGlobalCurrentFocusCycleRoot()
- {
- // XXX Need a way to test if this thread is in the context of the focus
- // owner, and throw a SecurityException if that is the case.
- // XXX Implement.
- return focusCycleRoot;
- }
-
- public void setGlobalCurrentFocusCycleRoot(Container cycleRoot)
+ /**
+ * Retrieve the current focus cycle root, or null if the focus owner
+ * was not set by a thread in the current address@hidden
+ * java.lang.ThreadGroup}.
+ *
+ * @return the current focus cycle root or null
+ */
+ public Container getCurrentFocusCycleRoot ()
+ {
+ return (Container) getObject (currentFocusCycleRoots);
+ }
+
+ /**
+ * Retrieve the current focus cycle root, regardless of whether or
+ * not it was made set by a thread in the current address@hidden
+ * java.lang.ThreadGroup}.
+ *
+ * @return the current focus cycle root
+ * @throws SecurityException if this is not the keyboard focus
+ * manager associated with the current address@hidden java.lang.ThreadGroup}
+ */
+ protected Container getGlobalCurrentFocusCycleRoot ()
+ {
+ return (Container) getGlobalObject (currentFocusCycleRoots);
+ }
+
+ /**
+ * Set the address@hidden Container} that will be returned by address@hidden
+ * #getCurrentFocusCycleRoot} (when it is called from the current
+ * address@hidden java.lang.ThreadGroup}) and address@hidden
+ * #getGlobalCurrentFocusCycleRoot}. This method does not actually
+ * make cycleRoot
the current focus cycle root.
+ *
+ * @param cycleRoot the focus cycle root to return from
+ * getCurrentFocusCycleRoot and getGlobalCurrentFocusCycleRoot
+ */
+ public void setGlobalCurrentFocusCycleRoot (Container cycleRoot)
{
- firePropertyChange("currentFocusCycleRoot", focusCycleRoot, cycleRoot);
- focusCycleRoot = cycleRoot;
+ setGlobalObject (currentFocusCycleRoots, cycleRoot, "currentFocusCycleRoot");
}
public void addPropertyChangeListener(PropertyChangeListener l)
@@ -484,73 +713,196 @@
keyEventDispatchers.remove(dispatcher);
}
- protected List getKeyEventDispatchers()
+ protected List getKeyEventDispatchers ()
{
- return (List) keyEventDispatchers.clone();
+ return (List) keyEventDispatchers.clone ();
}
- public void addKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
+ public void addKeyEventPostProcessor (KeyEventPostProcessor postProcessor)
{
if (postProcessor != null)
- keyEventPostProcessors.add(postProcessor);
+ keyEventPostProcessors.add (postProcessor);
}
- public void removeKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
+ public void removeKeyEventPostProcessor (KeyEventPostProcessor postProcessor)
{
- keyEventPostProcessors.remove(postProcessor);
+ keyEventPostProcessors.remove (postProcessor);
}
- protected List getKeyEventPostProcessors()
+ protected List getKeyEventPostProcessors ()
{
- return (List) keyEventPostProcessors.clone();
+ return (List) keyEventPostProcessors.clone ();
}
- public abstract boolean dispatchEvent(AWTEvent e);
+ public abstract boolean dispatchEvent (AWTEvent e);
- public final void redispatchEvent(Component target, AWTEvent e)
+ public final void redispatchEvent (Component target, AWTEvent e)
{
- throw new Error("not implemented");
+ e.setSource (target);
+ dispatchEvent (e);
}
- public abstract boolean dispatchKeyEvent(KeyEvent e);
+ public abstract boolean dispatchKeyEvent (KeyEvent e);
- public abstract boolean postProcessKeyEvent(KeyEvent e);
+ public abstract boolean postProcessKeyEvent (KeyEvent e);
- public abstract void processKeyEvent(Component focused, KeyEvent e);
+ public abstract void processKeyEvent (Component focused, KeyEvent e);
- protected abstract void enqueueKeyEvents(long after, Component untilFocused);
+ protected abstract void enqueueKeyEvents (long after, Component untilFocused);
- protected abstract void dequeueKeyEvents(long after, Component untilFocused);
+ protected abstract void dequeueKeyEvents (long after, Component untilFocused);
- protected abstract void discardKeyEvents(Component comp);
+ protected abstract void discardKeyEvents (Component comp);
- public abstract void focusNextComponent(Component comp);
+ public abstract void focusNextComponent (Component comp);
- public abstract void focusPreviousComponent(Component comp);
+ public abstract void focusPreviousComponent (Component comp);
- public abstract void upFocusCycle(Component comp);
+ public abstract void upFocusCycle (Component comp);
- public abstract void downFocusCycle(Container cont);
+ public abstract void downFocusCycle (Container cont);
- public final void focusNextComponent()
+ public final void focusNextComponent ()
{
- focusNextComponent(focusOwner);
+ focusNextComponent (null);
}
- public final void focusPreviousComponent()
+ public final void focusPreviousComponent ()
{
- focusPreviousComponent(focusOwner);
+ focusPreviousComponent (null);
}
- public final void upFocusCycle()
+ public final void upFocusCycle ()
{
- upFocusCycle(focusOwner);
+ upFocusCycle (null);
}
- public final void downFocusCycle()
+ public final void downFocusCycle ()
{
+ Component focusOwner = getGlobalFocusOwner ();
if (focusOwner instanceof Container
- && ((Container) focusOwner).isFocusCycleRoot())
- downFocusCycle((Container) focusOwner);
+ && ((Container) focusOwner).isFocusCycleRoot ())
+ downFocusCycle ((Container) focusOwner);
+ }
+
+ /**
+ * Retrieve an object from one of the global object address@hidden
+ * java.util.Map}s, if the object was set by the a thread in the
+ * current address@hidden java.lang.ThreadGroup}. Otherwise, return null.
+ *
+ * @param globalMap one of the global object Maps
+ *
+ * @return a global object set by the current ThreadGroup, or null
+ *
+ * @see getFocusOwner
+ * @see getPermanentFocusOwner
+ * @see getFocusedWindow
+ * @see getActiveWindow
+ * @see getCurrentFocusCycleRoot
+ */
+ private Object getObject (Map globalMap)
+ {
+ ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup ();
+ return globalMap.get (currentGroup);
+ }
+
+ /**
+ * Retrieve an object from one of the global object address@hidden
+ * java.util.Map}s, regardless of whether or not the object was set
+ * by a thread in the current address@hidden java.lang.ThreadGroup}.
+ *
+ * @param globalMap one of the global object Maps
+ *
+ * @return a global object set by the current ThreadGroup, or null
+ *
+ * @throws SecurityException if this is not the keyboard focus
+ * manager associated with the current address@hidden java.lang.ThreadGroup}
+ *
+ * @see getGlobalFocusOwner
+ * @see getGlobalPermanentFocusOwner
+ * @see getGlobalFocusedWindow
+ * @see getGlobalActiveWindow
+ * @see getGlobalCurrentFocusCycleRoot
+ */
+ private Object getGlobalObject (Map globalMap)
+ {
+ ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup ();
+ KeyboardFocusManager managerForCallingThread
+ = (KeyboardFocusManager) currentKeyboardFocusManagers.get (currentGroup);
+
+ if (this != managerForCallingThread)
+ throw new SecurityException ("Attempted to retrieve an object from a "
+ + "keyboard focus manager that isn't "
+ + "associated with the current thread group.");
+
+ synchronized (globalMap)
+ {
+ Collection globalObjects = globalMap.values ();
+ Iterator i = globalObjects.iterator ();
+ Component globalObject;
+
+ while (i.hasNext ())
+ {
+ globalObject = (Component) i.next ();
+ if (globalObject != null)
+ return globalObject;
+ }
+ }
+
+ // No Object was found.
+ return null;
+ }
+
+ /**
+ * Set an object in one of the global object address@hidden java.util.Map}s,
+ * that will be returned by subsequent calls to getGlobalObject on
+ * the same address@hidden java.util.Map}.
+ *
+ * @param globalMap one of the global object Maps
+ * @param newObject the object to set
+ * @param property the property that will change
+ *
+ * @see setGlobalFocusOwner
+ * @see setGlobalPermanentFocusOwner
+ * @see setGlobalFocusedWindow
+ * @see setGlobalActiveWindow
+ * @see setGlobalCurrentFocusCycleRoot
+ */
+ private void setGlobalObject (Map globalMap,
+ Object newObject,
+ String property)
+ {
+ synchronized (globalMap)
+ {
+ // Save old object.
+ Object oldObject = getGlobalObject (globalMap);
+
+ // Nullify old object.
+ Collection threadGroups = globalMap.keySet ();
+ Iterator i = threadGroups.iterator ();
+ while (i.hasNext ())
+ {
+ ThreadGroup oldThreadGroup = (ThreadGroup) i.next ();
+ if (globalMap.get (oldThreadGroup) != null)
+ {
+ globalMap.put (oldThreadGroup, null);
+ // There should only be one object set at a time, so
+ // we can short circuit.
+ break;
+ }
+ }
+
+ ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup ();
+ firePropertyChange (property, oldObject, newObject);
+ try
+ {
+ fireVetoableChange (property, oldObject, newObject);
+ // Set new object.
+ globalMap.put (currentGroup, newObject);
+ }
+ catch (PropertyVetoException e)
+ {
+ }
+ }
}
-} // class KeyboardFocusManager
+}
Index: java/awt/Window.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/Window.java,v
retrieving revision 1.32.12.2
diff -u -r1.32.12.2 Window.java
--- java/awt/Window.java 17 Feb 2004 21:26:32 -0000 1.32.12.2
+++ java/awt/Window.java 22 Apr 2004 16:01:10 -0000
@@ -83,6 +83,8 @@
private transient GraphicsConfiguration graphicsConfiguration;
private transient AccessibleContext accessibleContext;
+ private transient boolean shown;
+
/**
* This (package access) constructor is used by subclasses that want
* to build windows that do not have parents. Eg. toplevel
@@ -92,6 +94,9 @@
Window()
{
visible = false;
+ // Windows are the only Containers that default to being focus
+ // cycle roots.
+ focusCycleRoot = true;
setLayout(new BorderLayout());
}
@@ -242,6 +247,24 @@
validate();
super.show();
toFront();
+
+ KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+ manager.setGlobalFocusedWindow (this);
+
+ if (!shown)
+ {
+ FocusTraversalPolicy policy = getFocusTraversalPolicy ();
+ Component initialFocusOwner = null;
+
+ if (policy != null)
+ initialFocusOwner = policy.getInitialComponent (this);
+
+ if (initialFocusOwner != null)
+ initialFocusOwner.requestFocusInWindow (false);
+
+ System.out.println ("GOT INITIAL FOCUS OWNER: " + initialFocusOwner);
+ shown = true;
+ }
}
public void hide()
@@ -627,9 +650,16 @@
* @return The component that has focus, or null
if no
* component has focus.
*/
- public Component getFocusOwner()
+ public Component getFocusOwner ()
{
- // FIXME
+ KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+ Window activeWindow = manager.getActiveWindow ();
+
+ // The currently-focused Component belongs to the active Window.
+ if (activeWindow == this)
+ return manager.getFocusOwner ();
+
return null;
}
Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c,v
retrieving revision 1.15.2.3
diff -u -r1.15.2.3 gnu_java_awt_peer_gtk_GtkComponentPeer.c
--- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c 26 Mar 2004 20:30:37 -0000 1.15.2.3
+++ jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c 22 Apr 2004 16:01:10 -0000
@@ -42,6 +42,12 @@
static GtkWidget *find_fg_color_widget (GtkWidget *widget);
static GtkWidget *find_bg_color_widget (GtkWidget *widget);
+static gboolean focus_in_cb (GtkWidget *widget,
+ GdkEventFocus *event,
+ jobject peer);
+static gboolean focus_out_cb (GtkWidget *widget,
+ GdkEventFocus *event,
+ jobject peer);
JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkGenericPeer_dispose
(JNIEnv *env, jobject obj)
@@ -128,7 +134,7 @@
gdk_threads_leave ();
}
-JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_requestFocus
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetRequestFocus
(JNIEnv *env, jobject obj)
{
void *ptr;
@@ -136,7 +142,59 @@
ptr = NSA_GET_PTR (env, obj);
gdk_threads_enter ();
- // gtk_widget_grab_focus (GTK_WIDGET (ptr));
+ gtk_widget_grab_focus (GTK_WIDGET (ptr));
+ gdk_threads_leave ();
+}
+
+/*
+ * Translate a Java KeyEvent object into a GdkEventKey event, then
+ * pass it to the GTK main loop for processing.
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetDispatchKeyEvent
+ (JNIEnv *env, jobject obj, jint id, jlong when, jint mods,
+ jint keyCode, jchar keyChar, jint keyLocation)
+{
+ void *ptr;
+ GdkEvent *event = gdk_event_new (GDK_MOTION_NOTIFY);
+
+ ptr = NSA_GET_PTR (env, obj);
+
+ // FIXME: need to flesh this out.
+ // Translate
+ if (id == AWT_KEY_PRESSED)
+ event->type = GDK_KEY_PRESS;
+ else if (id == AWT_KEY_RELEASED)
+ event->type = GDK_KEY_RELEASE;
+ else
+ // Don't send AWT KEY_TYPED events to GTK.
+ return;
+
+ // FIXME: this won't work for TextAreas or Lists, which are packed
+ // in GtkScrolledWindows.
+ if (GTK_IS_BUTTON (ptr))
+ event->key.window = GTK_BUTTON (ptr)->event_window;
+ else
+ event->key.window = GTK_WIDGET (ptr)->window;
+
+ event->key.send_event = TRUE;
+
+ event->key.time = (guint32) when;
+ // Translate state
+ event->key.state = 0;
+ // Translate keyval
+ event->key.keyval = keyCode;
+ event->key.length = 1;
+ // Translate keyChar
+ event->key.string = g_strdup ("a");
+ event->key.hardware_keycode = 0;
+ event->key.group = 0;
+
+ gdk_threads_enter ();
+
+ g_printerr ("sending event\n");
+ gtk_main_do_event (event);
+
gdk_threads_leave ();
}
@@ -775,6 +833,12 @@
g_signal_connect (GTK_OBJECT (ptr), "event",
G_CALLBACK (pre_event_handler), *gref);
+ g_signal_connect (G_OBJECT (ptr), "focus-in-event",
+ G_CALLBACK (focus_in_cb), *gref);
+
+ g_signal_connect (G_OBJECT (ptr), "focus-out-event",
+ G_CALLBACK (focus_out_cb), *gref);
+
gdk_threads_leave ();
}
@@ -813,3 +877,26 @@
return bg_color_widget;
}
+static gboolean focus_in_cb (GtkWidget *widget,
+ GdkEventFocus *event,
+ jobject peer)
+{
+ g_printerr (" focus in: %p\n", peer);
+ (*gdk_env)->CallVoidMethod (gdk_env, peer,
+ postFocusEventID,
+ AWT_FOCUS_GAINED,
+ JNI_FALSE);
+ return FALSE;
+}
+
+static gboolean focus_out_cb (GtkWidget *widget,
+ GdkEventFocus *event,
+ jobject peer)
+{
+ g_printerr (" focus out: %p\n", peer);
+ (*gdk_env)->CallVoidMethod (gdk_env, peer,
+ postFocusEventID,
+ AWT_FOCUS_LOST,
+ JNI_FALSE);
+ return FALSE;
+}
Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c,v
retrieving revision 1.19.2.1
diff -u -r1.19.2.1 gnu_java_awt_peer_gtk_GtkEvents.c
--- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c 5 Mar 2004 22:24:50 -0000 1.19.2.1
+++ jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c 22 Apr 2004 16:01:10 -0000
@@ -1055,104 +1055,54 @@
}
}
break;
+
case GDK_FOCUS_CHANGE:
(*gdk_env)->CallVoidMethod (gdk_env, peer,
postFocusEventID,
- (jint) (event->focus_change.in) ?
+ (jint) (event->focus_change.in) ?
AWT_FOCUS_GAINED : AWT_FOCUS_LOST,
JNI_FALSE);
break;
case GDK_KEY_PRESS:
- case GDK_KEY_RELEASE:
- {
- GdkWindow *obj_window;
- jobject *focus_obj_ptr = NULL;
- int generates_key_typed = 0;
-
- /* A widget with a grab will get key events */
- if (!GTK_IS_WINDOW (widget))
- focus_obj_ptr = &peer;
- else
- {
- GtkWindow *window;
-
- /* Check if we have an enabled focused widget in this window.
- If not don't handle the event. */
- window = GTK_WINDOW (widget);
- if (!window->focus_widget
- || !GTK_WIDGET_IS_SENSITIVE (window->focus_widget)
- || !window->focus_widget->window)
- return FALSE;
-
- /* TextArea peers are attached to the scrolled window
- that contains the GtkTextView, not to the text view
- itself. Same for List. */
- if (GTK_IS_TEXT_VIEW (window->focus_widget)
- || GTK_IS_CLIST (window->focus_widget))
- {
- obj_window = gtk_widget_get_parent (window->focus_widget)->window;
- }
- else if (GTK_IS_BUTTON (window->focus_widget))
- /* GtkButton events go to the "event_window" and this is what
- we registered when the button was created. */
- obj_window = GTK_BUTTON (window->focus_widget)->event_window;
- else
- obj_window = window->focus_widget->window;
-
- gdk_property_get (obj_window,
- gdk_atom_intern ("_GNU_GTKAWT_ADDR", FALSE),
- gdk_atom_intern ("CARDINAL", FALSE),
- 0,
- sizeof (jobject),
- FALSE,
- NULL,
- NULL,
- NULL,
- (guchar **)&focus_obj_ptr);
-
- /* If the window has no jobject attached we can't send anything */
- if (!focus_obj_ptr)
- return FALSE;
-
- /* Should we generate an AWT_KEY_TYPED event? */
- generates_key_typed = generates_key_typed_event (event, window->focus_widget);
- }
+ if (GTK_IS_WINDOW (widget))
+ {
+ g_print("got key event on widget %s\n", gtk_widget_get_name (widget));
- if (event->type == GDK_KEY_PRESS)
- {
- (*gdk_env)->CallVoidMethod (gdk_env, *focus_obj_ptr,
- postKeyEventID,
- (jint) AWT_KEY_PRESSED,
- (jlong) event->key.time,
+ (*gdk_env)->CallVoidMethod (gdk_env, peer,
+ postKeyEventID,
+ (jint) AWT_KEY_PRESSED,
+ (jlong) event->key.time,
keyevent_state_to_awt_mods (event),
keysym_to_awt_keycode (event),
keyevent_to_awt_keychar (event),
keysym_to_awt_keylocation (event));
-
- if (generates_key_typed)
- {
- (*gdk_env)->CallVoidMethod (gdk_env, *focus_obj_ptr,
- postKeyEventID,
- (jint) AWT_KEY_TYPED,
- (jlong) event->key.time,
- state_to_awt_mods (event->key.state),
- VK_UNDEFINED,
- keyevent_to_awt_keychar (event),
- AWT_KEY_LOCATION_UNKNOWN);
- }
+ return TRUE;
}
- else /* GDK_KEY_RELEASE */
- {
- (*gdk_env)->CallVoidMethod (gdk_env, *focus_obj_ptr,
- postKeyEventID,
- (jint) AWT_KEY_RELEASED,
- (jlong) event->key.time,
- keyevent_state_to_awt_mods (event),
- keysym_to_awt_keycode (event),
+ else
+ return FALSE;
+ break;
+ case GDK_KEY_RELEASE:
+ if (GTK_IS_WINDOW (widget))
+ {
+ g_print("got key event on widget %s\n", gtk_widget_get_name (widget));
+
+ (*gdk_env)->CallVoidMethod (gdk_env, peer,
+ postKeyEventID,
+ (jint) AWT_KEY_RELEASED,
+ (jlong) event->key.time,
+ keyevent_state_to_awt_mods (event),
+ keysym_to_awt_keycode (event),
keyevent_to_awt_keychar (event),
keysym_to_awt_keylocation (event));
- }
- }
+ return TRUE;
+ }
+ else
+ {
+ // We generated this event after Java processed the
+ // corresponding event on the window.
+ if (event->key.send_event)
+ return FALSE;
+ }
break;
default:
break;
Index: jni/gtk-peer/gtkpeer.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gtkpeer.h,v
retrieving revision 1.12
diff -u -r1.12 gtkpeer.h
--- jni/gtk-peer/gtkpeer.h 23 Dec 2003 19:24:00 -0000 1.12
+++ jni/gtk-peer/gtkpeer.h 22 Apr 2004 16:01:10 -0000
@@ -361,8 +361,8 @@
#define VK_ALT_GRAPH 65406
#define VK_UNDEFINED 0
-#define AWT_FOCUS_LOST 1004
-#define AWT_FOCUS_GAINED 1005
+#define AWT_FOCUS_GAINED 1004
+#define AWT_FOCUS_LOST 1005
#define AWT_WINDOW_OPENED 200
#define AWT_WINDOW_CLOSING 201