aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/awt/DefaultKeyboardFocusManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/awt/DefaultKeyboardFocusManager.java')
-rw-r--r--libjava/java/awt/DefaultKeyboardFocusManager.java418
1 files changed, 391 insertions, 27 deletions
diff --git a/libjava/java/awt/DefaultKeyboardFocusManager.java b/libjava/java/awt/DefaultKeyboardFocusManager.java
index e2a2f68..79a9869 100644
--- a/libjava/java/awt/DefaultKeyboardFocusManager.java
+++ b/libjava/java/awt/DefaultKeyboardFocusManager.java
@@ -38,59 +38,423 @@ exception statement from your version. */
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 {@link java.util.List} of {@link java.awt.event.KeyEvent}s
+ that are being delayed, pending this request's {@link
+ 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 {@link #enqueuedKeyEvents} {@link
+ java.util.List}. */
+ public long timestamp;
+ /** When this {@link Component} becomes focused, all events
+ between this EventDelayRequest and the next one in will be
+ dispatched from {@link #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 ();
+ }
}
- public boolean dispatchEvent(AWTEvent e)
+ /** The {@link java.util.SortedSet} of current {@link
+ #EventDelayRequest}s. */
+ private SortedSet delayRequests = new TreeSet ();
+
+ public DefaultKeyboardFocusManager ()
{
- throw new Error("not implemented");
}
- public boolean dispatchKeyEvent(KeyEvent 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
+ && !(target instanceof Window))
+ {
+ if (((FocusEvent) e).isTemporary ())
+ setGlobalFocusOwner (target);
+ else
+ setGlobalPermanentFocusOwner (target);
+ }
+
+ if (!(target instanceof Window))
+ 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 postProcessKeyEvent(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 void processKeyEvent(Component comp, KeyEvent e)
+
+ public boolean dispatchKeyEvent (KeyEvent e)
{
- throw new Error("not implemented");
+ 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;
+
+ // Always return true.
+ return true;
}
- protected void enqueueKeyEvents(long after, Component comp)
+
+ public boolean postProcessKeyEvent (KeyEvent 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)
+ {
+ AWTKeyStroke eventKeystroke = AWTKeyStroke.getAWTKeyStrokeForEvent (e);
+ // For every focus traversal keystroke, we need to also consume
+ // the other two key event types for the same key (e.g. if
+ // KEY_PRESSED TAB is a focus traversal keystroke, we also need to
+ // consume KEY_RELEASED and KEY_TYPED TAB key events).
+ AWTKeyStroke oppositeKeystroke = AWTKeyStroke.getAWTKeyStroke (e.getKeyCode (),
+ e.getModifiers (),
+ !(e.id == KeyEvent.KEY_RELEASED));
+
+ 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 (eventKeystroke))
+ {
+ focusNextComponent (comp);
+ e.consume ();
+ }
+ else if (backwardKeystrokes.contains (eventKeystroke))
+ {
+ focusPreviousComponent (comp);
+ e.consume ();
+ }
+ else if (upKeystrokes.contains (eventKeystroke))
+ {
+ upFocusCycle (comp);
+ e.consume ();
+ }
+ else if (comp instanceof Container
+ && downKeystrokes.contains (eventKeystroke))
+ {
+ downFocusCycle ((Container) comp);
+ e.consume ();
+ }
+ else if (forwardKeystrokes.contains (oppositeKeystroke)
+ || backwardKeystrokes.contains (oppositeKeystroke)
+ || upKeystrokes.contains (oppositeKeystroke)
+ || (comp instanceof Container &&
+ downKeystrokes.contains (oppositeKeystroke)))
+ e.consume ();
+ }
+
+ protected void enqueueKeyEvents (long after, Component untilFocused)
{
- throw new Error("not implemented");
+ 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");
+ // 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");
+ // 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");
+ Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp;
+ Container focusCycleRoot = focusComp.getFocusCycleRootAncestor ();
+ FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy ();
+
+ Component previous = policy.getComponentBefore (focusCycleRoot, focusComp);
+ previous.requestFocusInWindow ();
}
- public void focusNextComponent(Component comp)
+
+ public void focusNextComponent (Component comp)
{
- throw new Error("not implemented");
+ Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp;
+ Container focusCycleRoot = focusComp.getFocusCycleRootAncestor ();
+ FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy ();
+
+ Component next = policy.getComponentAfter (focusCycleRoot, focusComp);
+ next.requestFocusInWindow ();
}
- public void upFocusCycle(Component comp)
+
+ public void upFocusCycle (Component comp)
{
- throw new Error("not implemented");
+ Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp;
+ Container focusCycleRoot = focusComp.getFocusCycleRootAncestor ();
+
+ if (focusCycleRoot instanceof Window)
+ {
+ FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy ();
+ Component defaultComponent = policy.getDefaultComponent (focusCycleRoot);
+ defaultComponent.requestFocusInWindow ();
+ }
+ else
+ {
+ Container parentFocusCycleRoot = focusCycleRoot.getFocusCycleRootAncestor ();
+
+ focusCycleRoot.requestFocusInWindow ();
+ setGlobalCurrentFocusCycleRoot (parentFocusCycleRoot);
+ }
}
- public void downFocusCycle(Container cont)
+
+ public void downFocusCycle (Container cont)
{
- throw new Error("not implemented");
+ if (cont == null)
+ return;
+
+ if (cont.isFocusCycleRoot (cont))
+ {
+ FocusTraversalPolicy policy = cont.getFocusTraversalPolicy ();
+ Component defaultComponent = policy.getDefaultComponent (cont);
+ defaultComponent.requestFocusInWindow ();
+ setGlobalCurrentFocusCycleRoot (cont);
+ }
}
} // class DefaultKeyboardFocusManager