PatchSet 7333 Date: 2006/07/11 15:39:24 Author: riccardo Branch: HEAD Tag: (none) Log: further focus traversal improvments from CP
Members: ChangeLog:1.4836->1.4837 libraries/javalib/awt-implementations/kaffe/java/awt/Component.java:1.15->1.16 libraries/javalib/awt-implementations/kaffe/java/awt/Container.java:1.7->1.8 Index: kaffe/ChangeLog diff -u kaffe/ChangeLog:1.4836 kaffe/ChangeLog:1.4837 --- kaffe/ChangeLog:1.4836 Tue Jul 11 14:33:54 2006 +++ kaffe/ChangeLog Tue Jul 11 15:39:24 2006 @@ -1,3 +1,9 @@ +2006-07-11 Riccardo Mottola <[EMAIL PROTECTED]> + + * libraries/javalib/awt-implementations/kaffe/java/awt/Component.java, + libraries/javalib/awt-implementations/kaffe/java/awt/Container.java: + further focus traversal improvments from CP + 2006-07-11 Dalibor Topic <[EMAIL PROTECTED]> * configure.ac (REGEN_FORWARD): Removed. Index: kaffe/libraries/javalib/awt-implementations/kaffe/java/awt/Component.java diff -u kaffe/libraries/javalib/awt-implementations/kaffe/java/awt/Component.java:1.15 kaffe/libraries/javalib/awt-implementations/kaffe/java/awt/Component.java:1.16 --- kaffe/libraries/javalib/awt-implementations/kaffe/java/awt/Component.java:1.15 Mon Jul 10 22:51:20 2006 +++ kaffe/libraries/javalib/awt-implementations/kaffe/java/awt/Component.java Tue Jul 11 15:39:28 2006 @@ -3446,53 +3446,67 @@ return (getClass().getName() + '[' + paramString() + ']'); } -/** - * Transfer the focus to the next appropriate components in this - * components container. - */ -public void transferFocus() { - Component curr = this; - - while (curr.parent != null) { - - Container parent = curr.parent; - int end = parent.getComponentCount(); - - /* Find out where 'curr' is in its container so we can start - * looking for the next component after it - */ - int start; - for (start = 0; start < end; start++) { - Component c = parent.getComponent(start); - if (c == curr) { - break; - } - } - - /* This shouldn't happen but just in case ... */ - if (start == end) { - return; - } - - /* Look for next focusable component after me */ - for (start++; start < end; start++) { - Component c = parent.getComponent(start); - - if (c.isEnabled() && ((c.flags & IS_VISIBLE) !=0) && c.isFocusTraversable()) { - // Then if it is enabled, visible and focus traversable set the focus to it - c.requestFocus(); - return; - } else if (c instanceof Container) { - // If it is a container drop into it - parent = (Container)c; - end = parent.getComponentCount(); - start = -1; - } - } - - curr = parent; - } -} + /** + * 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 () + { + 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. + * + * @param c the container to test + * @return true if c is the focus cycle root + * @since 1.4 + */ + public boolean isFocusCycleRoot (Container c) + { + return c == getFocusCycleRootAncestor (); + } + + public void transferFocus () + { + // Find the nearest valid (== showing && focusable && enabled) focus + // cycle root ancestor and the focused component in it. + Container focusRoot = getFocusCycleRootAncestor(); + Component focusComp = this; + while (focusRoot != null + && ! (focusRoot.isShowing() && focusRoot.isFocusable() + && focusRoot.isEnabled())) + { + focusComp = focusRoot; + focusRoot = focusComp.getFocusCycleRootAncestor(); + } + + if (focusRoot != null) + { + // First try to get the componentBefore from the policy. + FocusTraversalPolicy policy = focusRoot.getFocusTraversalPolicy(); + Component nextFocus = policy.getComponentAfter(focusRoot, focusComp); + + // If this fails, then ask for the defaultComponent. + if (nextFocus == null) + nextFocus = policy.getDefaultComponent(focusRoot); + + // Request focus on this component, if not null. + if (nextFocus != null) + nextFocus.requestFocus(); + } + } PopupMenu triggerPopup ( int x, int y ) { if ( popup != null ) { Index: kaffe/libraries/javalib/awt-implementations/kaffe/java/awt/Container.java diff -u kaffe/libraries/javalib/awt-implementations/kaffe/java/awt/Container.java:1.7 kaffe/libraries/javalib/awt-implementations/kaffe/java/awt/Container.java:1.8 --- kaffe/libraries/javalib/awt-implementations/kaffe/java/awt/Container.java:1.7 Fri May 12 14:38:38 2006 +++ kaffe/libraries/javalib/awt-implementations/kaffe/java/awt/Container.java Tue Jul 11 15:39:28 2006 @@ -17,9 +17,14 @@ import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; +import java.awt.event.KeyEvent; import java.awt.event.PaintEvent; import java.io.PrintStream; import java.io.PrintWriter; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; abstract public class Container @@ -29,15 +34,37 @@ * Compatible with JDK 1.0+. */ private static final long serialVersionUID = 4613797578919906343L; + /* Serialized fields from the serialization spec. */ int ncomponents; Component[] component; LayoutManager layoutMgr; + /** + * @since 1.4 + */ + boolean focusCycleRoot; + + /* Anything else is non-serializable, and should be declared "transient". */ transient ContainerListener containerListener; + /** 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; + // ContainerListener cntrListener; Insets insets = Insets.noInsets; @@ -935,6 +962,321 @@ component[i].validate(); } + + /** + * Sets the focus traversal keys for a given traversal operation for this + * Container. + * + * @exception IllegalArgumentException If id is not one of + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, + * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, + * or if keystrokes contains null, or if any Object in keystrokes is not an + * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event, or if any + * keystroke already maps to another focus traversal operation for this + * Container. + * + * @since 1.4 + */ + public void setFocusTraversalKeys(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) + { + 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[4]; + + keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); + firePropertyChange (name, focusTraversalKeys[id], keystrokes); + + focusTraversalKeys[id] = keystrokes; + } + + /** + * Returns the Set of focus traversal keys for a given traversal operation for + * this Container. + * + * @exception IllegalArgumentException If id is not one of + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, + * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. + * + * @since 1.4 + */ + public Set getFocusTraversalKeys (int id) + { + 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 (); + + 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. + * If this method returns false, this Container is inheriting the Set from + * an ancestor, or from the current KeyboardFocusManager. + * + * @exception IllegalArgumentException If id is not one of + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, + * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. + * + * @since 1.4 + */ + public boolean areFocusTraversalKeysSet (int id) + { + 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 (); + + return focusTraversalKeys != null && focusTraversalKeys[id] != null; + } + + /** + * 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 <code>c</code> 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; + } + + /** + * 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 <code>policy</code> 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; + } + + /** + * 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 () + { + if (!isFocusCycleRoot ()) + return null; + + if (focusTraversalPolicy == null) + { + Container ancestor = getFocusCycleRootAncestor (); + + if (ancestor != this && ancestor != null) + return ancestor.getFocusTraversalPolicy (); + else + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + return manager.getDefaultFocusTraversalPolicy (); + } + } + else + return focusTraversalPolicy; + } + + /** + * 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 focusTraversalPolicy == null; + } + + /** + * 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. + * + * @param focusCycleRoot true if this is a focus cycle root, false otherwise + * + * @since 1.4 + */ + public void setFocusCycleRoot (boolean focusCycleRoot) + { + this.focusCycleRoot = focusCycleRoot; + } + + /** + * 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 focusCycleRoot; + } + + /** + * 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 () + { + if (isFocusCycleRoot()) + { + KeyboardFocusManager fm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + fm.setGlobalCurrentFocusCycleRoot(this); + FocusTraversalPolicy policy = getFocusTraversalPolicy(); + Component defaultComponent = policy.getDefaultComponent(this); + if (defaultComponent != null) + defaultComponent.requestFocus(); + } + } /** _______________________________________________ kaffe mailing list kaffe@kaffe.org http://kaffe.org/cgi-bin/mailman/listinfo/kaffe