GNU Classpath (0.20) | |
Frames | No Frames |
1: /* ContainerOrderFocusTraversalPolicy.java -- 2: Copyright (C) 2002, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.awt; 40: 41: import java.io.Serializable; 42: 43: /** 44: * ContainerOrderFocusTraversalPolicy defines a focus traversal order 45: * based on the order in which Components were packed in a Container. 46: * This policy performs a pre-order traversal of the Component 47: * hierarchy starting from a given focus cycle root. Portions of the 48: * hierarchy that are not visible and displayable are skipped. 49: * 50: * By default, this policy transfers focus down-cycle implicitly. 51: * That is, if a forward traversal is requested on a focus cycle root 52: * and the focus cycle root has focusable children, the focus will 53: * automatically be transfered down to the lower focus cycle. 54: * 55: * The default implementation of accept accepts only Components that 56: * are visible, displayable, enabled and focusable. Derived classes 57: * can override these acceptance criteria by overriding accept. 58: * 59: * @author Michael Koch 60: * @author Thomas Fitzsimmons (fitzsim@redhat.com) 61: * @since 1.4 62: */ 63: public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy 64: implements Serializable 65: { 66: /** 67: * Compatible to JDK 1.4+ 68: */ 69: static final long serialVersionUID = 486933713763926351L; 70: 71: /** 72: * True if implicit down cycling is enabled. 73: */ 74: private boolean implicitDownCycleTraversal = true; 75: 76: /** 77: * Creates the <code>ContainerOrderFocusTraversalPolicy</code> object. 78: */ 79: public ContainerOrderFocusTraversalPolicy () 80: { 81: // Nothing to do here 82: } 83: 84: /** 85: * Returns the Component that should receive the focus after current. 86: * root must be a focus cycle root of current. 87: * 88: * @param root a focus cycle root of current 89: * @param current a (possibly indirect) child of root, or root itself 90: * 91: * @return the next Component in the focus traversal order for root, 92: * or null if no acceptable Component exists. 93: * 94: * @exception IllegalArgumentException If root is not a focus cycle 95: * root of current, or if either root or current is null. 96: */ 97: public Component getComponentAfter (Container root, Component current) 98: { 99: if (root == null) 100: throw new IllegalArgumentException ("focus cycle root is null"); 101: if (current == null) 102: throw new IllegalArgumentException ("current component is null"); 103: 104: if (!root.isFocusCycleRoot ()) 105: throw new IllegalArgumentException ("root is not a focus cycle root"); 106: 107: Container ancestor = current.getFocusCycleRootAncestor (); 108: Container prevAncestor = ancestor; 109: while (ancestor != root) 110: { 111: ancestor = current.getFocusCycleRootAncestor (); 112: if (ancestor == prevAncestor) 113: { 114: // We've reached the top focus cycle root ancestor. Check 115: // if it is root. 116: if (ancestor != root) 117: throw new IllegalArgumentException ("the given container is not" 118: + " a focus cycle root of the" 119: + " current component"); 120: else 121: break; 122: } 123: prevAncestor = ancestor; 124: } 125: 126: // FIXME: is this the right thing to do here? It moves the context 127: // for traversal up one focus traversal cycle. We'll need a test 128: // for this. 129: if ((Component) root == current) 130: root = current.getFocusCycleRootAncestor (); 131: 132: // Check if we've reached the top of the component hierarchy. If 133: // so then we want to loop around to the first component in the 134: // focus traversal cycle. 135: if (current instanceof Window) 136: return getFirstComponent ((Container) current); 137: 138: Container parent = current.getParent (); 139: 140: synchronized (parent.getTreeLock ()) 141: { 142: Component[] components = parent.getComponents (); 143: int componentIndex = 0; 144: int numComponents = parent.getComponentCount (); 145: 146: // Find component's index. 147: for (int i = 0; i < numComponents; i++) 148: { 149: if (components[i] == current) 150: componentIndex = i; 151: } 152: 153: // Search forward for the next acceptable component. 154: for (int i = componentIndex + 1; i < numComponents; i++) 155: { 156: if (accept (components[i])) 157: return components[i]; 158: 159: if (components[i] instanceof Container) 160: { 161: Component result = getFirstComponent ((Container) components[i]); 162: 163: if (result != null 164: && implicitDownCycleTraversal) 165: return result; 166: } 167: } 168: 169: // No focusable components after current in its Container. So go 170: // to the next Component after current's Container (parent). 171: Component result = getComponentAfter (root, parent); 172: 173: return result; 174: } 175: } 176: 177: /** 178: * Returns the Component that should receive the focus before 179: * <code>current</code>. <code>root</code> must be a focus cycle 180: * root of current. 181: * 182: * @param root a focus cycle root of current 183: * @param current a (possibly indirect) child of root, or root itself 184: * 185: * @return the previous Component in the focus traversal order for 186: * root, or null if no acceptable Component exists. 187: * 188: * @exception IllegalArgumentException If root is not a focus cycle 189: * root of current, or if either root or current is null. 190: */ 191: public Component getComponentBefore (Container root, Component current) 192: { 193: if (root == null) 194: throw new IllegalArgumentException ("focus cycle root is null"); 195: if (current == null) 196: throw new IllegalArgumentException ("current component is null"); 197: 198: if (!root.isFocusCycleRoot ()) 199: throw new IllegalArgumentException ("root is not a focus cycle root"); 200: 201: Container ancestor = current.getFocusCycleRootAncestor (); 202: Container prevAncestor = ancestor; 203: while (ancestor != root) 204: { 205: ancestor = current.getFocusCycleRootAncestor (); 206: if (ancestor == prevAncestor) 207: { 208: // We've reached the top focus cycle root ancestor. Check 209: // if it is root. 210: if (ancestor != root) 211: throw new IllegalArgumentException ("the given container is not" 212: + " a focus cycle root of the" 213: + " current component"); 214: else 215: break; 216: } 217: prevAncestor = ancestor; 218: } 219: 220: // FIXME: is this the right thing to do here? It moves the context 221: // for traversal up one focus traversal cycle. We'll need a test 222: // for this. 223: if ((Component) root == current) 224: root = current.getFocusCycleRootAncestor (); 225: 226: // Check if we've reached the top of the component hierarchy. If 227: // so then we want to loop around to the last component in the 228: // focus traversal cycle. 229: if (current instanceof Window) 230: return getLastComponent ((Container) current); 231: 232: Container parent = current.getParent (); 233: 234: synchronized (parent.getTreeLock ()) 235: { 236: Component[] components = parent.getComponents (); 237: int componentIndex = 0; 238: int numComponents = parent.getComponentCount (); 239: 240: // Find component's index. 241: for (int i = 0; i < numComponents; i++) 242: { 243: if (components[i] == current) 244: componentIndex = i; 245: } 246: 247: // Search backward for the next acceptable component. 248: for (int i = componentIndex - 1; i >= 0; i--) 249: { 250: if (accept (components[i])) 251: return components[i]; 252: 253: if (components[i] instanceof Container) 254: { 255: Component result = getLastComponent ((Container) components[i]); 256: 257: if (result != null) 258: return result; 259: } 260: } 261: 262: // No focusable components before current in its Container. So go 263: // to the previous Component before current's Container (parent). 264: Component result = getComponentBefore (root, parent); 265: 266: return result; 267: } 268: } 269: 270: /** 271: * Returns the first Component of root that should receive the focus. 272: * 273: * @param root a focus cycle root 274: * 275: * @return the first Component in the focus traversal order for 276: * root, or null if no acceptable Component exists. 277: * 278: * @exception IllegalArgumentException If root is null. 279: */ 280: public Component getFirstComponent(Container root) 281: { 282: if (root == null) 283: throw new IllegalArgumentException (); 284: 285: if (!root.isVisible () 286: || !root.isDisplayable ()) 287: return null; 288: 289: if (accept (root)) 290: return root; 291: 292: Component[] componentArray = root.getComponents (); 293: 294: for (int i = 0; i < componentArray.length; i++) 295: { 296: Component component = componentArray [i]; 297: 298: if (accept (component)) 299: return component; 300: 301: if (component instanceof Container) 302: { 303: Component result = getFirstComponent ((Container) component); 304: 305: if (result != null) 306: return result; 307: } 308: } 309: 310: return null; 311: } 312: 313: /** 314: * Returns the last Component of root that should receive the focus. 315: * 316: * @param root a focus cycle root 317: * 318: * @return the last Component in the focus traversal order for 319: * root, or null if no acceptable Component exists. 320: * 321: * @exception IllegalArgumentException If root is null. 322: */ 323: public Component getLastComponent (Container root) 324: { 325: if (root == null) 326: throw new IllegalArgumentException (); 327: 328: if (!root.isVisible () 329: || !root.isDisplayable ()) 330: return null; 331: 332: if (accept (root)) 333: return root; 334: 335: Component[] componentArray = root.getComponents (); 336: 337: for (int i = componentArray.length - 1; i >= 0; i--) 338: { 339: Component component = componentArray [i]; 340: 341: if (accept (component)) 342: return component; 343: 344: if (component instanceof Container) 345: { 346: Component result = getLastComponent ((Container) component); 347: 348: if (result != null) 349: return result; 350: } 351: } 352: 353: return null; 354: } 355: 356: /** 357: * Returns the default Component of root that should receive the focus. 358: * 359: * @param root a focus cycle root 360: * 361: * @return the default Component in the focus traversal order for 362: * root, or null if no acceptable Component exists. 363: * 364: * @exception IllegalArgumentException If root is null. 365: */ 366: public Component getDefaultComponent (Container root) 367: { 368: return getFirstComponent (root); 369: } 370: 371: /** 372: * Set whether or not implicit down cycling is enabled. If it is, 373: * then initiating a forward focus traversal operation onto a focus 374: * cycle root, the focus will be implicitly transferred into the 375: * root container's focus cycle. 376: * 377: * @param value the setting for implicit down cycling 378: */ 379: public void setImplicitDownCycleTraversal (boolean value) 380: { 381: implicitDownCycleTraversal = value; 382: } 383: 384: /** 385: * Check whether or not implicit down cycling is enabled. If it is, 386: * then initiating a forward focus traversal operation onto a focus 387: * cycle root, the focus will be implicitly transferred into the 388: * root container's focus cycle. 389: * 390: * @return true if the focus will be transferred down-cycle 391: * implicitly 392: */ 393: public boolean getImplicitDownCycleTraversal () 394: { 395: return implicitDownCycleTraversal; 396: } 397: 398: /** 399: * Check whether the given Component is an acceptable target for the 400: * keyboard input focus. 401: * 402: * @param current the Component to check 403: * 404: * @return true if current is acceptable, false otherwise 405: */ 406: protected boolean accept (Component current) 407: { 408: return (current.visible 409: && current.isDisplayable () 410: && current.enabled 411: && current.focusable); 412: } 413: }
GNU Classpath (0.20) |