| /* |
| * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| package javax.swing; |
| |
| import java.awt.Component; |
| import java.awt.Container; |
| import java.awt.ComponentOrientation; |
| import java.util.Comparator; |
| import java.io.*; |
| import sun.awt.SunToolkit; |
| |
| |
| /** |
| * A SortingFocusTraversalPolicy which sorts Components based on their size, |
| * position, and orientation. Based on their size and position, Components are |
| * roughly categorized into rows and columns. For a Container with horizontal |
| * orientation, columns run left-to-right or right-to-left, and rows run top- |
| * to-bottom. For a Container with vertical orientation, columns run top-to- |
| * bottom and rows run left-to-right or right-to-left. See |
| * <code>ComponentOrientation</code> for more information. All columns in a |
| * row are fully traversed before proceeding to the next row. |
| * |
| * @author David Mendenhall |
| * |
| * @see java.awt.ComponentOrientation |
| * @since 1.4 |
| */ |
| public class LayoutFocusTraversalPolicy extends SortingFocusTraversalPolicy |
| implements Serializable |
| { |
| // Delegate most of our fitness test to Default so that we only have to |
| // code the algorithm once. |
| private static final SwingDefaultFocusTraversalPolicy fitnessTestPolicy = |
| new SwingDefaultFocusTraversalPolicy(); |
| |
| /** |
| * Constructs a LayoutFocusTraversalPolicy. |
| */ |
| public LayoutFocusTraversalPolicy() { |
| super(new LayoutComparator()); |
| } |
| |
| /** |
| * Constructs a LayoutFocusTraversalPolicy with the passed in |
| * <code>Comparator</code>. |
| */ |
| LayoutFocusTraversalPolicy(Comparator<? super Component> c) { |
| super(c); |
| } |
| |
| /** |
| * Returns the Component that should receive the focus after aComponent. |
| * aContainer must be a focus cycle root of aComponent. |
| * <p> |
| * By default, LayoutFocusTraversalPolicy implicitly transfers focus down- |
| * cycle. That is, during normal focus traversal, the Component |
| * traversed after a focus cycle root will be the focus-cycle-root's |
| * default Component to focus. This behavior can be disabled using the |
| * <code>setImplicitDownCycleTraversal</code> method. |
| * <p> |
| * If aContainer is <a href="../../java/awt/doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus |
| * traversal policy provider</a>, the focus is always transferred down-cycle. |
| * |
| * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider |
| * @param aComponent a (possibly indirect) child of aContainer, or |
| * aContainer itself |
| * @return the Component that should receive the focus after aComponent, or |
| * null if no suitable Component can be found |
| * @throws IllegalArgumentException if aContainer is not a focus cycle |
| * root of aComponent or a focus traversal policy provider, or if either aContainer or |
| * aComponent is null |
| */ |
| public Component getComponentAfter(Container aContainer, |
| Component aComponent) { |
| if (aContainer == null || aComponent == null) { |
| throw new IllegalArgumentException("aContainer and aComponent cannot be null"); |
| } |
| Comparator comparator = getComparator(); |
| if (comparator instanceof LayoutComparator) { |
| ((LayoutComparator)comparator). |
| setComponentOrientation(aContainer. |
| getComponentOrientation()); |
| } |
| return super.getComponentAfter(aContainer, aComponent); |
| } |
| |
| /** |
| * Returns the Component that should receive the focus before aComponent. |
| * aContainer must be a focus cycle root of aComponent. |
| * <p> |
| * By default, LayoutFocusTraversalPolicy implicitly transfers focus down- |
| * cycle. That is, during normal focus traversal, the Component |
| * traversed after a focus cycle root will be the focus-cycle-root's |
| * default Component to focus. This behavior can be disabled using the |
| * <code>setImplicitDownCycleTraversal</code> method. |
| * <p> |
| * If aContainer is <a href="../../java/awt/doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus |
| * traversal policy provider</a>, the focus is always transferred down-cycle. |
| * |
| * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider |
| * @param aComponent a (possibly indirect) child of aContainer, or |
| * aContainer itself |
| * @return the Component that should receive the focus before aComponent, |
| * or null if no suitable Component can be found |
| * @throws IllegalArgumentException if aContainer is not a focus cycle |
| * root of aComponent or a focus traversal policy provider, or if either aContainer or |
| * aComponent is null |
| */ |
| public Component getComponentBefore(Container aContainer, |
| Component aComponent) { |
| if (aContainer == null || aComponent == null) { |
| throw new IllegalArgumentException("aContainer and aComponent cannot be null"); |
| } |
| Comparator comparator = getComparator(); |
| if (comparator instanceof LayoutComparator) { |
| ((LayoutComparator)comparator). |
| setComponentOrientation(aContainer. |
| getComponentOrientation()); |
| } |
| return super.getComponentBefore(aContainer, aComponent); |
| } |
| |
| /** |
| * Returns the first Component in the traversal cycle. This method is used |
| * to determine the next Component to focus when traversal wraps in the |
| * forward direction. |
| * |
| * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider whose |
| * first Component is to be returned |
| * @return the first Component in the traversal cycle of aContainer, |
| * or null if no suitable Component can be found |
| * @throws IllegalArgumentException if aContainer is null |
| */ |
| public Component getFirstComponent(Container aContainer) { |
| if (aContainer == null) { |
| throw new IllegalArgumentException("aContainer cannot be null"); |
| } |
| Comparator comparator = getComparator(); |
| if (comparator instanceof LayoutComparator) { |
| ((LayoutComparator)comparator). |
| setComponentOrientation(aContainer. |
| getComponentOrientation()); |
| } |
| return super.getFirstComponent(aContainer); |
| } |
| |
| /** |
| * Returns the last Component in the traversal cycle. This method is used |
| * to determine the next Component to focus when traversal wraps in the |
| * reverse direction. |
| * |
| * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider whose |
| * last Component is to be returned |
| * @return the last Component in the traversal cycle of aContainer, |
| * or null if no suitable Component can be found |
| * @throws IllegalArgumentException if aContainer is null |
| */ |
| public Component getLastComponent(Container aContainer) { |
| if (aContainer == null) { |
| throw new IllegalArgumentException("aContainer cannot be null"); |
| } |
| Comparator comparator = getComparator(); |
| if (comparator instanceof LayoutComparator) { |
| ((LayoutComparator)comparator). |
| setComponentOrientation(aContainer. |
| getComponentOrientation()); |
| } |
| return super.getLastComponent(aContainer); |
| } |
| |
| /** |
| * Determines whether the specified <code>Component</code> |
| * is an acceptable choice as the new focus owner. |
| * This method performs the following sequence of operations: |
| * <ol> |
| * <li>Checks whether <code>aComponent</code> is visible, displayable, |
| * enabled, and focusable. If any of these properties is |
| * <code>false</code>, this method returns <code>false</code>. |
| * <li>If <code>aComponent</code> is an instance of <code>JTable</code>, |
| * returns <code>true</code>. |
| * <li>If <code>aComponent</code> is an instance of <code>JComboBox</code>, |
| * then returns the value of |
| * <code>aComponent.getUI().isFocusTraversable(aComponent)</code>. |
| * <li>If <code>aComponent</code> is a <code>JComponent</code> |
| * with a <code>JComponent.WHEN_FOCUSED</code> |
| * <code>InputMap</code> that is neither <code>null</code> |
| * nor empty, returns <code>true</code>. |
| * <li>Returns the value of |
| * <code>DefaultFocusTraversalPolicy.accept(aComponent)</code>. |
| * </ol> |
| * |
| * @param aComponent the <code>Component</code> whose fitness |
| * as a focus owner is to be tested |
| * @see java.awt.Component#isVisible |
| * @see java.awt.Component#isDisplayable |
| * @see java.awt.Component#isEnabled |
| * @see java.awt.Component#isFocusable |
| * @see javax.swing.plaf.ComboBoxUI#isFocusTraversable |
| * @see javax.swing.JComponent#getInputMap |
| * @see java.awt.DefaultFocusTraversalPolicy#accept |
| * @return <code>true</code> if <code>aComponent</code> is a valid choice |
| * for a focus owner; |
| * otherwise <code>false</code> |
| */ |
| protected boolean accept(Component aComponent) { |
| if (!super.accept(aComponent)) { |
| return false; |
| } else if (SunToolkit.isInstanceOf(aComponent, "javax.swing.JTable")) { |
| // JTable only has ancestor focus bindings, we thus force it |
| // to be focusable by returning true here. |
| return true; |
| } else if (SunToolkit.isInstanceOf(aComponent, "javax.swing.JComboBox")) { |
| JComboBox box = (JComboBox)aComponent; |
| return box.getUI().isFocusTraversable(box); |
| } else if (aComponent instanceof JComponent) { |
| JComponent jComponent = (JComponent)aComponent; |
| InputMap inputMap = jComponent.getInputMap(JComponent.WHEN_FOCUSED, |
| false); |
| while (inputMap != null && inputMap.size() == 0) { |
| inputMap = inputMap.getParent(); |
| } |
| if (inputMap != null) { |
| return true; |
| } |
| // Delegate to the fitnessTestPolicy, this will test for the |
| // case where the developer has overriden isFocusTraversable to |
| // return true. |
| } |
| return fitnessTestPolicy.accept(aComponent); |
| } |
| |
| private void writeObject(ObjectOutputStream out) throws IOException { |
| out.writeObject(getComparator()); |
| out.writeBoolean(getImplicitDownCycleTraversal()); |
| } |
| private void readObject(ObjectInputStream in) |
| throws IOException, ClassNotFoundException |
| { |
| setComparator((Comparator)in.readObject()); |
| setImplicitDownCycleTraversal(in.readBoolean()); |
| } |
| } |
| |
| // Create our own subclass and change accept to public so that we can call |
| // accept. |
| class SwingDefaultFocusTraversalPolicy |
| extends java.awt.DefaultFocusTraversalPolicy |
| { |
| public boolean accept(Component aComponent) { |
| return super.accept(aComponent); |
| } |
| } |