1 /* 2 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing; 26 27 import java.awt.FocusTraversalPolicy; 28 import java.awt.Component; 29 import java.awt.Container; 30 import java.awt.Window; 31 import java.util.HashMap; 32 import java.util.HashSet; 33 import java.io.*; 34 35 36 /** 37 * A FocusTraversalPolicy which provides support for legacy applications which 38 * handle focus traversal via JComponent.setNextFocusableComponent or by 39 * installing a custom DefaultFocusManager. If a specific traversal has not 40 * been hard coded, then that traversal is provided either by the custom 41 * DefaultFocusManager, or by a wrapped FocusTraversalPolicy instance. 42 * 43 * @author David Mendenhall 44 */ 45 @SuppressWarnings("serial") // JDK-implementation class 46 final class LegacyGlueFocusTraversalPolicy extends FocusTraversalPolicy 47 implements Serializable 48 { 49 private transient FocusTraversalPolicy delegatePolicy; 50 private transient DefaultFocusManager delegateManager; 51 52 private HashMap<Component, Component> forwardMap = new HashMap<Component, Component>(), 53 backwardMap = new HashMap<Component, Component>(); 54 55 LegacyGlueFocusTraversalPolicy(FocusTraversalPolicy delegatePolicy) { 56 this.delegatePolicy = delegatePolicy; 57 } 58 LegacyGlueFocusTraversalPolicy(DefaultFocusManager delegateManager) { 59 this.delegateManager = delegateManager; 60 } 61 62 void setNextFocusableComponent(Component left, Component right) { 63 forwardMap.put(left, right); 64 backwardMap.put(right, left); 65 } 66 void unsetNextFocusableComponent(Component left, Component right) { 67 forwardMap.remove(left); 68 backwardMap.remove(right); 69 } 70 71 public Component getComponentAfter(Container focusCycleRoot, 72 Component aComponent) { 73 Component hardCoded = aComponent, prevHardCoded; 74 HashSet<Component> sanity = new HashSet<Component>(); 75 76 do { 77 prevHardCoded = hardCoded; 78 hardCoded = forwardMap.get(hardCoded); 79 if (hardCoded == null) { 80 if (delegatePolicy != null && 81 prevHardCoded.isFocusCycleRoot(focusCycleRoot)) { 82 return delegatePolicy.getComponentAfter(focusCycleRoot, 83 prevHardCoded); 84 } else if (delegateManager != null) { 85 return delegateManager. 86 getComponentAfter(focusCycleRoot, aComponent); 87 } else { 88 return null; 89 } 90 } 91 if (sanity.contains(hardCoded)) { 92 // cycle detected; bail 93 return null; 94 } 95 sanity.add(hardCoded); 96 } while (!accept(hardCoded)); 97 98 return hardCoded; 99 } 100 public Component getComponentBefore(Container focusCycleRoot, 101 Component aComponent) { 102 Component hardCoded = aComponent, prevHardCoded; 103 HashSet<Component> sanity = new HashSet<Component>(); 104 105 do { 106 prevHardCoded = hardCoded; 107 hardCoded = backwardMap.get(hardCoded); 108 if (hardCoded == null) { 109 if (delegatePolicy != null && 110 prevHardCoded.isFocusCycleRoot(focusCycleRoot)) { 111 return delegatePolicy.getComponentBefore(focusCycleRoot, 112 prevHardCoded); 113 } else if (delegateManager != null) { 114 return delegateManager. 115 getComponentBefore(focusCycleRoot, aComponent); 116 } else { 117 return null; 118 } 119 } 120 if (sanity.contains(hardCoded)) { 121 // cycle detected; bail 122 return null; 123 } 124 sanity.add(hardCoded); 125 } while (!accept(hardCoded)); 126 127 return hardCoded; 128 } 129 public Component getFirstComponent(Container focusCycleRoot) { 130 if (delegatePolicy != null) { 131 return delegatePolicy.getFirstComponent(focusCycleRoot); 132 } else if (delegateManager != null) { 133 return delegateManager.getFirstComponent(focusCycleRoot); 134 } else { 135 return null; 136 } 137 } 138 public Component getLastComponent(Container focusCycleRoot) { 139 if (delegatePolicy != null) { 140 return delegatePolicy.getLastComponent(focusCycleRoot); 141 } else if (delegateManager != null) { 142 return delegateManager.getLastComponent(focusCycleRoot); 143 } else { 144 return null; 145 } 146 } 147 public Component getDefaultComponent(Container focusCycleRoot) { 148 if (delegatePolicy != null) { 149 return delegatePolicy.getDefaultComponent(focusCycleRoot); 150 } else { 151 return getFirstComponent(focusCycleRoot); 152 } 153 } 154 private boolean accept(Component aComponent) { 155 if (!(aComponent.isVisible() && aComponent.isDisplayable() && 156 aComponent.isFocusable() && aComponent.isEnabled())) { 157 return false; 158 } 159 160 // Verify that the Component is recursively enabled. Disabling a 161 // heavyweight Container disables its children, whereas disabling 162 // a lightweight Container does not. 163 if (!(aComponent instanceof Window)) { 164 for (Container enableTest = aComponent.getParent(); 165 enableTest != null; 166 enableTest = enableTest.getParent()) 167 { 168 if (!(enableTest.isEnabled() || enableTest.isLightweight())) { 169 return false; 170 } 171 if (enableTest instanceof Window) { 172 break; 173 } 174 } 175 } 176 177 return true; 178 } 179 private void writeObject(ObjectOutputStream out) throws IOException { 180 out.defaultWriteObject(); 181 182 if (delegatePolicy instanceof Serializable) { 183 out.writeObject(delegatePolicy); 184 } else { 185 out.writeObject(null); 186 } 187 188 if (delegateManager instanceof Serializable) { 189 out.writeObject(delegateManager); 190 } else { 191 out.writeObject(null); 192 } 193 } 194 private void readObject(ObjectInputStream in) 195 throws IOException, ClassNotFoundException 196 { 197 in.defaultReadObject(); 198 delegatePolicy = (FocusTraversalPolicy)in.readObject(); 199 delegateManager = (DefaultFocusManager)in.readObject(); 200 } 201 }