1. /*
  2. * @(#)LayoutFocusTraversalPolicy.java 1.8 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.Component;
  9. import java.awt.Container;
  10. import java.awt.ComponentOrientation;
  11. import java.util.Comparator;
  12. import java.io.*;
  13. /**
  14. * A SortingFocusTraversalPolicy which sorts Components based on their size,
  15. * position, and orientation. Based on their size and position, Components are
  16. * roughly categorized into rows and columns. For a Container with horizontal
  17. * orientation, columns run left-to-right or right-to-left, and rows run top-
  18. * to-bottom. For a Container with vertical orientation, columns run top-to-
  19. * bottom and rows run left-to-right or right-to-left. See
  20. * <code>ComponentOrientation</code> for more information. All columns in a
  21. * row are fully traversed before proceeding to the next row.
  22. *
  23. * @version 1.8, 01/23/03
  24. * @author David Mendenhall
  25. *
  26. * @see java.awt.ComponentOrientation
  27. * @since 1.4
  28. */
  29. public class LayoutFocusTraversalPolicy extends SortingFocusTraversalPolicy
  30. implements Serializable
  31. {
  32. // Delegate most of our fitness test to Default so that we only have to
  33. // code the algorithm once.
  34. private static final SwingDefaultFocusTraversalPolicy fitnessTestPolicy =
  35. new SwingDefaultFocusTraversalPolicy();
  36. /**
  37. * Constructs a LayoutFocusTraversalPolicy.
  38. */
  39. public LayoutFocusTraversalPolicy() {
  40. super(new LayoutComparator());
  41. }
  42. /**
  43. * Constructs a LayoutFocusTraversalPolicy with the passed in
  44. * <code>Comparator</code>.
  45. */
  46. LayoutFocusTraversalPolicy(Comparator c) {
  47. super(c);
  48. }
  49. /**
  50. * Returns the Component that should receive the focus after aComponent.
  51. * focusCycleRoot must be a focus cycle root of aComponent.
  52. * <p>
  53. * By default, LayoutFocusTraversalPolicy implicitly transfers focus down-
  54. * cycle. That is, during normal focus traversal, the Component
  55. * traversed after a focus cycle root will be the focus-cycle-root's
  56. * default Component to focus. This behavior can be disabled using the
  57. * <code>setImplicitDownCycleTraversal</code> method.
  58. *
  59. * @param focusCycleRoot a focus cycle root of aComponent
  60. * @param aComponent a (possibly indirect) child of focusCycleRoot, or
  61. * focusCycleRoot itself
  62. * @return the Component that should receive the focus after aComponent, or
  63. * null if no suitable Component can be found
  64. * @throws IllegalArgumentException if focusCycleRoot is not a focus cycle
  65. * root of aComponent, or if either focusCycleRoot or aComponent is
  66. * null
  67. */
  68. public Component getComponentAfter(Container focusCycleRoot,
  69. Component aComponent) {
  70. if (focusCycleRoot == null || aComponent == null) {
  71. throw new IllegalArgumentException("focusCycleRoot and aComponent cannot be null");
  72. }
  73. Comparator comparator = getComparator();
  74. if (comparator instanceof LayoutComparator) {
  75. ((LayoutComparator)comparator).
  76. setComponentOrientation(focusCycleRoot.
  77. getComponentOrientation());
  78. }
  79. return super.getComponentAfter(focusCycleRoot, aComponent);
  80. }
  81. /**
  82. * Returns the Component that should receive the focus before aComponent.
  83. * focusCycleRoot must be a focus cycle root of aComponent.
  84. * <p>
  85. * By default, LayoutFocusTraversalPolicy implicitly transfers focus down-
  86. * cycle. That is, during normal focus traversal, the Component
  87. * traversed after a focus cycle root will be the focus-cycle-root's
  88. * default Component to focus. This behavior can be disabled using the
  89. * <code>setImplicitDownCycleTraversal</code> method.
  90. *
  91. * @param focusCycleRoot a focus cycle root of aComponent
  92. * @param aComponent a (possibly indirect) child of focusCycleRoot, or
  93. * focusCycleRoot itself
  94. * @return the Component that should receive the focus before aComponent,
  95. * or null if no suitable Component can be found
  96. * @throws IllegalArgumentException if focusCycleRoot is not a focus cycle
  97. * root of aComponent, or if either focusCycleRoot or aComponent is
  98. * null
  99. */
  100. public Component getComponentBefore(Container focusCycleRoot,
  101. Component aComponent) {
  102. if (focusCycleRoot == null || aComponent == null) {
  103. throw new IllegalArgumentException("focusCycleRoot and aComponent cannot be null");
  104. }
  105. Comparator comparator = getComparator();
  106. if (comparator instanceof LayoutComparator) {
  107. ((LayoutComparator)comparator).
  108. setComponentOrientation(focusCycleRoot.
  109. getComponentOrientation());
  110. }
  111. return super.getComponentBefore(focusCycleRoot, aComponent);
  112. }
  113. /**
  114. * Returns the first Component in the traversal cycle. This method is used
  115. * to determine the next Component to focus when traversal wraps in the
  116. * forward direction.
  117. *
  118. * @param focusCycleRoot the focus cycle root whose first Component is to
  119. * be returned
  120. * @return the first Component in the traversal cycle when focusCycleRoot
  121. * is the focus cycle root, or null if no suitable Component can be
  122. * found
  123. * @throws IllegalArgumentException if focusCycleRoot is null
  124. */
  125. public Component getFirstComponent(Container focusCycleRoot) {
  126. if (focusCycleRoot == null) {
  127. throw new IllegalArgumentException("focusCycleRoot cannot be null");
  128. }
  129. Comparator comparator = getComparator();
  130. if (comparator instanceof LayoutComparator) {
  131. ((LayoutComparator)comparator).
  132. setComponentOrientation(focusCycleRoot.
  133. getComponentOrientation());
  134. }
  135. return super.getFirstComponent(focusCycleRoot);
  136. }
  137. /**
  138. * Returns the last Component in the traversal cycle. This method is used
  139. * to determine the next Component to focus when traversal wraps in the
  140. * reverse direction.
  141. *
  142. * @param focusCycleRoot the focus cycle root whose last Component is to be
  143. * returned
  144. * @return the last Component in the traversal cycle when focusCycleRoot is
  145. * the focus cycle root, or null if no suitable Component can be
  146. * found
  147. * @throws IllegalArgumentException if focusCycleRoot is null
  148. */
  149. public Component getLastComponent(Container focusCycleRoot) {
  150. if (focusCycleRoot == null) {
  151. throw new IllegalArgumentException("focusCycleRoot cannot be null");
  152. }
  153. Comparator comparator = getComparator();
  154. if (comparator instanceof LayoutComparator) {
  155. ((LayoutComparator)comparator).
  156. setComponentOrientation(focusCycleRoot.
  157. getComponentOrientation());
  158. }
  159. return super.getLastComponent(focusCycleRoot);
  160. }
  161. /**
  162. * Determines whether the specified <code>Component</code>
  163. * is an acceptable choice as the new focus owner.
  164. * This method performs the following sequence of operations:
  165. * <ol>
  166. * <li>Checks whether <code>aComponent</code> is visible, displayable,
  167. * enabled, and focusable. If any of these properties is
  168. * <code>false</code>, this method returns <code>false</code>.
  169. * <li>If <code>aComponent</code> is an instance of <code>JTable</code>,
  170. * returns <code>true</code>.
  171. * <li>If <code>aComponent</code> is an instance of <code>JComboBox</code>,
  172. * then returns the value of
  173. * <code>aComponent.getUI().isFocusTraversable(aComponent)</code>.
  174. * <li>If <code>aComponent</code> is a <code>JComponent</code>
  175. * with a <code>JComponent.WHEN_FOCUSED</code>
  176. * <code>InputMap</code> that is neither <code>null</code>
  177. * nor empty, returns <code>true</code>.
  178. * <li>Returns the value of
  179. * <code>DefaultFocusTraversalPolicy.accept(aComponent)</code>.
  180. * </ol>
  181. *
  182. * @param aComponent the <code>Component</code> whose fitness
  183. * as a focus owner is to be tested
  184. * @see java.awt.Component#isVisible
  185. * @see java.awt.Component#isDisplayable
  186. * @see java.awt.Component#isEnabled
  187. * @see java.awt.Component#isFocusable
  188. * @see javax.swing.plaf.ComboBoxUI#isFocusTraversable
  189. * @see javax.swing.JComponent#getInputMap
  190. * @see java.awt.DefaultFocusTraversalPolicy#accept
  191. * @return <code>true</code> if <code>aComponent</code> is a valid choice
  192. * for a focus owner;
  193. * otherwise <code>false</code>
  194. */
  195. protected boolean accept(Component aComponent) {
  196. if (!super.accept(aComponent)) {
  197. return false;
  198. } else if (aComponent instanceof JTable) {
  199. // JTable only has ancestor focus bindings, we thus force it
  200. // to be focusable by returning true here.
  201. return true;
  202. } else if (aComponent instanceof JComboBox) {
  203. JComboBox box = (JComboBox)aComponent;
  204. return box.getUI().isFocusTraversable(box);
  205. } else if (aComponent instanceof JComponent) {
  206. JComponent jComponent = (JComponent)aComponent;
  207. InputMap inputMap = jComponent.getInputMap(JComponent.WHEN_FOCUSED,
  208. false);
  209. while (inputMap != null && inputMap.size() == 0) {
  210. inputMap = inputMap.getParent();
  211. }
  212. if (inputMap != null) {
  213. return true;
  214. }
  215. // Delegate to the fitnessTestPolicy, this will test for the
  216. // case where the developer has overriden isFocusTraversable to
  217. // return true.
  218. }
  219. return fitnessTestPolicy.accept(aComponent);
  220. }
  221. private void writeObject(ObjectOutputStream out) throws IOException {
  222. out.writeObject(getComparator());
  223. out.writeBoolean(getImplicitDownCycleTraversal());
  224. }
  225. private void readObject(ObjectInputStream in)
  226. throws IOException, ClassNotFoundException
  227. {
  228. setComparator((Comparator)in.readObject());
  229. setImplicitDownCycleTraversal(in.readBoolean());
  230. }
  231. }
  232. // Create our own subclass and change accept to public so that we can call
  233. // accept.
  234. class SwingDefaultFocusTraversalPolicy
  235. extends java.awt.DefaultFocusTraversalPolicy
  236. {
  237. public boolean accept(Component aComponent) {
  238. return super.accept(aComponent);
  239. }
  240. }