/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.awt; import java.io.Serializable; public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy implements Serializable { private static final long serialVersionUID = 486933713763926351L; private boolean implicitDownCycleTraversal = true; public ContainerOrderFocusTraversalPolicy() { } protected boolean accept(Component aComp) { toolkit.lockAWT(); try { // By default, this method will accept a Component if and only if it is // visible[together with parent !!!], displayable, enabled, and focusable. return (aComp.isVisible() && aComp.isDisplayable() && aComp.isEnabled() && aComp.isFocusable()); } finally { toolkit.unlockAWT(); } } public Component getComponentAfter(Container aContainer, Component aComponent) { toolkit.lockAWT(); try { check(aContainer, aComponent); Container provider = findProvider(aContainer, aComponent); if (provider != null) { return getComponent(provider, aComponent, true); } Component nextComp = getComponent(aContainer, aComponent, false, true); return nextComp; } finally { toolkit.unlockAWT(); } } private void check(Container aContainer, Component component) { if (aContainer == null || component == null) { throw new IllegalArgumentException("aContainer and aComponent cannot be null"); } if (aContainer.isFocusCycleRoot()) { Component root = component.getFocusCycleRootAncestor(); if ((root != aContainer) && (component != aContainer)) { throw new IllegalArgumentException("aContainer is not a focus cycle root of aComponent"); } } else if (!aContainer.isFocusTraversalPolicyProvider()) { throw new IllegalArgumentException("aContainer should be focus cycle root or focus traversal policy provider"); } } public Component getComponentBefore(Container aContainer, Component aComponent) { toolkit.lockAWT(); try { check(aContainer, aComponent); Container provider = findProvider(aContainer, aComponent); if (provider != null) { return getComponent(provider, aComponent, false); } Component prevComp = getComponent(aContainer, aComponent, false, false); return prevComp; } finally { toolkit.unlockAWT(); } } /** * if a Component is a child of a focus traversal policy provider, the next * and previous for this Component are determined using this focus traversal * policy provider's FocusTraversalPolicy. */ private Component getComponent(Container provider, Component comp, boolean after) { if (provider.isFocusCycleRoot() || !provider.isFocusTraversalPolicyProvider()) { return null; } FocusTraversalPolicy policy = provider.getFocusTraversalPolicy(); Component nextComp = (after ? policy.getComponentAfter(provider, comp) : policy.getComponentBefore(provider, comp)); Component wrapComp = after ? policy.getFirstComponent(provider) : policy.getLastComponent(provider); if (nextComp == wrapComp) { // don't wrap traversal inside providers: // just go to next/prev component after/before // provider in its root ancestor's cycle Container root = provider.getFocusCycleRootAncestor(); if (root == null) { return null; } FocusTraversalPolicy rootPolicy = root.getFocusTraversalPolicy(); nextComp = (after ? rootPolicy.getComponentAfter(root, provider) : rootPolicy.getComponentBefore(root, provider)); } return nextComp; } /* * Find first FTP provider between comp and its FCR container. * Return null if not found * */ private Container findProvider(Container container, Component comp) { if (!container.isFocusCycleRoot()) { // prevent endless loop: // if container is already a provider don't // call its policy again return null; } Component curComp = comp; while ((curComp != null)) { Container parent = curComp.getRealParent(); if ((parent != null) && parent.isFocusTraversalPolicyProvider()) { return parent; } curComp = parent; } return null; } public Component getDefaultComponent(Container container) { toolkit.lockAWT(); try { return getFirstComponent(container); } finally { toolkit.unlockAWT(); } } public Component getFirstComponent(Container container) { toolkit.lockAWT(); try { if (container == null) { throw new IllegalArgumentException("focusCycleRoot cannot be null"); } Component firstComp = getComponent(container, container, true, true); return firstComp; } finally { toolkit.unlockAWT(); } } /** * return first acceptable component after/before[forward is true/false] * comp[ or comp itself if "include" is true] in "container order" */ private Component getComponent(Container container, Component comp, boolean include, boolean forward) { Component curComp = comp; if (forward) { Component defComp = getFCRDefComp(curComp, container); if (defComp != null) { return defComp; } } if (!include) { curComp = oneStep(container, curComp, forward, true); if (forward) { Component defComp = getDefComp(curComp, container); if (defComp != null) { return defComp; } } } boolean stop = false; while (!stop && (curComp != null) && !accept(curComp)) { if (forward) { Component defComp = getFCRDefComp(curComp, container); if (defComp != null) { return defComp; } } curComp = oneStep(container, curComp, forward, !include); if (forward) { Component defComp = getDefComp(curComp, container); if (defComp != null) { return defComp; } } stop = (curComp == comp);// stop if comp is traversed again } if (curComp == null) { return null; } return accept(curComp) ? curComp : null; } /** * @param comp * @param root * @return default component given by comp's FTP if comp is FTP provider and * is not same as root, null otherwise */ private Component getDefComp(Component comp, Container root) { if (!(comp instanceof Container)) { return null; } Container cont = (Container) comp; boolean isProvider = (!cont.isFocusCycleRoot() && cont.isFocusTraversalPolicyProvider()); if (isProvider && (cont != root)) { return cont.getFocusTraversalPolicy().getDefaultComponent(cont); } return null; } /** * @param comp * @param root * @return default component given by comp's FTP if comp is FCR and implicit * down cycle traversal is true and comp is not same as root, null * otherwise */ private Component getFCRDefComp(Component comp, Container root) { if (!(comp instanceof Container)) { return null; } Container cont = (Container) comp; boolean isFCR = cont.isFocusCycleRoot(); boolean traverseFCR = (isFCR && (cont != root) && getImplicitDownCycleTraversal()); if (traverseFCR) { return cont.getFocusTraversalPolicy().getDefaultComponent(cont); } return null; } private int getInitialIndex(Container parent, boolean forward) { return (forward ? 0 : (parent.getComponentCount() - 1)); } /** * Make one step forward/backward in * container order from comp, do * not take any conditions, such as * accept(), into consideration. Don't * go into FCRs or FTP providers. * @param root * @param comp * @param forward * @return */ private Component oneStep(Container root, Component comp, boolean forward, boolean cycle) { if (root == null || comp == null) { return null; } Container parent = comp.getRealParent(); if (parent == null) { parent = (Container) comp; } boolean same = (parent == comp); int maxIdx = parent.getComponentCount() - 1; if (maxIdx < 0) { return (same ? comp : null); } if (forward && (comp instanceof Container)) { Component firstComp = goDown(root, (Container)comp); if (firstComp != null) { return firstComp; } } int idx = parent.getComponentIndex(comp); if (idx < 0) { // if going back and actual parent is null - wrap traversal parent = null; } idx += (forward ? 1 : -1); Component nextComp = comp; if ((parent != null) && checkIndex(parent, idx)) { nextComp = parent.getComponent(idx); if (!forward && (nextComp instanceof Container)) { // go back & down into container nextComp = getCompInContainer((Container)nextComp, root); } } else { // go up to parent container nextComp = forward ? getCompAfterContainer(parent) : parent; } if (!root.isAncestorOf(nextComp) && (root != nextComp)) { // wrap if trying to get out of root: nextComp = cycle ? wrapTraversal(root, forward) : /*root*/null; } return nextComp; } private Component goDown(Container root, Container cont) { int idx = getInitialIndex(cont, true); if (!canGoDown(root, cont)) { idx = -1;// don't try to go into FCRs or FTPPs(?) // treat them just like containers with // no components inside } if (checkIndex(cont, idx)) { // go down into container first return cont.getComponent(idx); } return null; } private boolean canGoDown(Container root, Container cont) { if ((root == null) || (cont == null)) { return false; } return ((!cont.isFocusCycleRoot() && !cont.isFocusTraversalPolicyProvider()) || (cont == root)); } /** * Find last component inside container * when traversing backward[going down into containers]. * Skip focus cycle roots which are not * same as root. * @param container * @return */ private Component getCompInContainer(Container container, Container root) { Component lastComp = container; while (lastComp instanceof Container) { Container cont = (Container) lastComp; if (!canGoDown(root, cont)) { break; } int idx = getInitialIndex(cont, false); if (!checkIndex(cont, idx)) { break; } lastComp = cont.getComponent(idx); } return lastComp; } /** * Find first component after * container[go up & forward] * @param parent * @return */ private Component getCompAfterContainer(Container container) { Container parent = container; while (parent != null) { parent = container.getRealParent(); Component nextComp = getComp(parent, container, true); if (nextComp != null) { return nextComp; } container = parent; } return null; } /** * Get component before/after "comp" in container * "parent". If there's no such component in * "parent" (comp was first or last) - return null * @param parent * @param container * @return */ private Component getComp(Container parent, Component comp, boolean forward) { if ((parent == null) || (comp == null)) { return null; } int idx = parent.getComponentIndex(comp); if (idx < 0) { return null; } idx += forward ? 1 : -1; if (checkIndex(parent, idx)) { return parent.getComponent(idx); } return null; } private Component wrapTraversal(Container container, boolean forward) { Component comp = forward ? getFirstComponent(container) : getLastComponent(container); return comp; } private boolean checkIndex(Container container, int idx) { return ((idx >= 0) && (idx < container.getComponentCount())); } public Component getLastComponent(Container container) { toolkit.lockAWT(); try { if (container == null) { // awt.10E=focusCycleRoot cannot be null throw new IllegalArgumentException("focusCycleRoot cannot be null"); } int count = container.getComponentCount(); if ( count <= 0) { return accept(container) ? container : null; } Component lastComp = getComponent(container, getCompInContainer(container, container), true, false); return lastComp; } finally { toolkit.unlockAWT(); } } public boolean getImplicitDownCycleTraversal() { toolkit.lockAWT(); try { return implicitDownCycleTraversal; } finally { toolkit.unlockAWT(); } } public void setImplicitDownCycleTraversal(boolean value) { toolkit.lockAWT(); try { implicitDownCycleTraversal = value; } finally { toolkit.unlockAWT(); } } }