1. /*
  2. * @(#)LayoutFocusTraversalPolicy.java 1.10 03/12/19
  3. *
  4. * Copyright 2004 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.10, 12/19/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. * aContainer 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. * <p>
  59. * If aContainer is <a href="doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus
  60. * traversal policy provider</a>, the focus is always transferred down-cycle.
  61. *
  62. * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider
  63. * @param aComponent a (possibly indirect) child of aContainer, or
  64. * aContainer itself
  65. * @return the Component that should receive the focus after aComponent, or
  66. * null if no suitable Component can be found
  67. * @throws IllegalArgumentException if aContainer is not a focus cycle
  68. * root of aComponent or a focus traversal policy provider, or if either aContainer or
  69. * aComponent is null
  70. */
  71. public Component getComponentAfter(Container aContainer,
  72. Component aComponent) {
  73. if (aContainer == null || aComponent == null) {
  74. throw new IllegalArgumentException("aContainer and aComponent cannot be null");
  75. }
  76. Comparator comparator = getComparator();
  77. if (comparator instanceof LayoutComparator) {
  78. ((LayoutComparator)comparator).
  79. setComponentOrientation(aContainer.
  80. getComponentOrientation());
  81. }
  82. return super.getComponentAfter(aContainer, aComponent);
  83. }
  84. /**
  85. * Returns the Component that should receive the focus before aComponent.
  86. * aContainer must be a focus cycle root of aComponent.
  87. * <p>
  88. * By default, LayoutFocusTraversalPolicy implicitly transfers focus down-
  89. * cycle. That is, during normal focus traversal, the Component
  90. * traversed after a focus cycle root will be the focus-cycle-root's
  91. * default Component to focus. This behavior can be disabled using the
  92. * <code>setImplicitDownCycleTraversal</code> method.
  93. * <p>
  94. * If aContainer is <a href="doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus
  95. * traversal policy provider</a>, the focus is always transferred down-cycle.
  96. *
  97. * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider
  98. * @param aComponent a (possibly indirect) child of aContainer, or
  99. * aContainer itself
  100. * @return the Component that should receive the focus before aComponent,
  101. * or null if no suitable Component can be found
  102. * @throws IllegalArgumentException if aContainer is not a focus cycle
  103. * root of aComponent or a focus traversal policy provider, or if either aContainer or
  104. * aComponent is null
  105. */
  106. public Component getComponentBefore(Container aContainer,
  107. Component aComponent) {
  108. if (aContainer == null || aComponent == null) {
  109. throw new IllegalArgumentException("aContainer and aComponent cannot be null");
  110. }
  111. Comparator comparator = getComparator();
  112. if (comparator instanceof LayoutComparator) {
  113. ((LayoutComparator)comparator).
  114. setComponentOrientation(aContainer.
  115. getComponentOrientation());
  116. }
  117. return super.getComponentBefore(aContainer, aComponent);
  118. }
  119. /**
  120. * Returns the first Component in the traversal cycle. This method is used
  121. * to determine the next Component to focus when traversal wraps in the
  122. * forward direction.
  123. *
  124. * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider whose
  125. * first Component is to be returned
  126. * @return the first Component in the traversal cycle of aContainer,
  127. * or null if no suitable Component can be found
  128. * @throws IllegalArgumentException if aContainer is null
  129. */
  130. public Component getFirstComponent(Container aContainer) {
  131. if (aContainer == null) {
  132. throw new IllegalArgumentException("aContainer cannot be null");
  133. }
  134. Comparator comparator = getComparator();
  135. if (comparator instanceof LayoutComparator) {
  136. ((LayoutComparator)comparator).
  137. setComponentOrientation(aContainer.
  138. getComponentOrientation());
  139. }
  140. return super.getFirstComponent(aContainer);
  141. }
  142. /**
  143. * Returns the last Component in the traversal cycle. This method is used
  144. * to determine the next Component to focus when traversal wraps in the
  145. * reverse direction.
  146. *
  147. * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider whose
  148. * last Component is to be returned
  149. * @return the last Component in the traversal cycle of aContainer,
  150. * or null if no suitable Component can be found
  151. * @throws IllegalArgumentException if aContainer is null
  152. */
  153. public Component getLastComponent(Container aContainer) {
  154. if (aContainer == null) {
  155. throw new IllegalArgumentException("aContainer cannot be null");
  156. }
  157. Comparator comparator = getComparator();
  158. if (comparator instanceof LayoutComparator) {
  159. ((LayoutComparator)comparator).
  160. setComponentOrientation(aContainer.
  161. getComponentOrientation());
  162. }
  163. return super.getLastComponent(aContainer);
  164. }
  165. /**
  166. * Determines whether the specified <code>Component</code>
  167. * is an acceptable choice as the new focus owner.
  168. * This method performs the following sequence of operations:
  169. * <ol>
  170. * <li>Checks whether <code>aComponent</code> is visible, displayable,
  171. * enabled, and focusable. If any of these properties is
  172. * <code>false</code>, this method returns <code>false</code>.
  173. * <li>If <code>aComponent</code> is an instance of <code>JTable</code>,
  174. * returns <code>true</code>.
  175. * <li>If <code>aComponent</code> is an instance of <code>JComboBox</code>,
  176. * then returns the value of
  177. * <code>aComponent.getUI().isFocusTraversable(aComponent)</code>.
  178. * <li>If <code>aComponent</code> is a <code>JComponent</code>
  179. * with a <code>JComponent.WHEN_FOCUSED</code>
  180. * <code>InputMap</code> that is neither <code>null</code>
  181. * nor empty, returns <code>true</code>.
  182. * <li>Returns the value of
  183. * <code>DefaultFocusTraversalPolicy.accept(aComponent)</code>.
  184. * </ol>
  185. *
  186. * @param aComponent the <code>Component</code> whose fitness
  187. * as a focus owner is to be tested
  188. * @see java.awt.Component#isVisible
  189. * @see java.awt.Component#isDisplayable
  190. * @see java.awt.Component#isEnabled
  191. * @see java.awt.Component#isFocusable
  192. * @see javax.swing.plaf.ComboBoxUI#isFocusTraversable
  193. * @see javax.swing.JComponent#getInputMap
  194. * @see java.awt.DefaultFocusTraversalPolicy#accept
  195. * @return <code>true</code> if <code>aComponent</code> is a valid choice
  196. * for a focus owner;
  197. * otherwise <code>false</code>
  198. */
  199. protected boolean accept(Component aComponent) {
  200. if (!super.accept(aComponent)) {
  201. return false;
  202. } else if (aComponent instanceof JTable) {
  203. // JTable only has ancestor focus bindings, we thus force it
  204. // to be focusable by returning true here.
  205. return true;
  206. } else if (aComponent instanceof JComboBox) {
  207. JComboBox box = (JComboBox)aComponent;
  208. return box.getUI().isFocusTraversable(box);
  209. } else if (aComponent instanceof JComponent) {
  210. JComponent jComponent = (JComponent)aComponent;
  211. InputMap inputMap = jComponent.getInputMap(JComponent.WHEN_FOCUSED,
  212. false);
  213. while (inputMap != null && inputMap.size() == 0) {
  214. inputMap = inputMap.getParent();
  215. }
  216. if (inputMap != null) {
  217. return true;
  218. }
  219. // Delegate to the fitnessTestPolicy, this will test for the
  220. // case where the developer has overriden isFocusTraversable to
  221. // return true.
  222. }
  223. return fitnessTestPolicy.accept(aComponent);
  224. }
  225. private void writeObject(ObjectOutputStream out) throws IOException {
  226. out.writeObject(getComparator());
  227. out.writeBoolean(getImplicitDownCycleTraversal());
  228. }
  229. private void readObject(ObjectInputStream in)
  230. throws IOException, ClassNotFoundException
  231. {
  232. setComparator((Comparator)in.readObject());
  233. setImplicitDownCycleTraversal(in.readBoolean());
  234. }
  235. }
  236. // Create our own subclass and change accept to public so that we can call
  237. // accept.
  238. class SwingDefaultFocusTraversalPolicy
  239. extends java.awt.DefaultFocusTraversalPolicy
  240. {
  241. public boolean accept(Component aComponent) {
  242. return super.accept(aComponent);
  243. }
  244. }