View Javadoc
1   /*
2    * Copyright (c) 2000, 2008, 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  final class LegacyGlueFocusTraversalPolicy extends FocusTraversalPolicy
46      implements Serializable
47  {
48      private transient FocusTraversalPolicy delegatePolicy;
49      private transient DefaultFocusManager delegateManager;
50  
51      private HashMap<Component, Component> forwardMap = new HashMap<Component, Component>(),
52          backwardMap = new HashMap<Component, Component>();
53  
54      LegacyGlueFocusTraversalPolicy(FocusTraversalPolicy delegatePolicy) {
55          this.delegatePolicy = delegatePolicy;
56      }
57      LegacyGlueFocusTraversalPolicy(DefaultFocusManager delegateManager) {
58          this.delegateManager = delegateManager;
59      }
60  
61      void setNextFocusableComponent(Component left, Component right) {
62          forwardMap.put(left, right);
63          backwardMap.put(right, left);
64      }
65      void unsetNextFocusableComponent(Component left, Component right) {
66          forwardMap.remove(left);
67          backwardMap.remove(right);
68      }
69  
70      public Component getComponentAfter(Container focusCycleRoot,
71                                         Component aComponent) {
72          Component hardCoded = aComponent, prevHardCoded;
73          HashSet<Component> sanity = new HashSet<Component>();
74  
75          do {
76              prevHardCoded = hardCoded;
77              hardCoded = forwardMap.get(hardCoded);
78              if (hardCoded == null) {
79                  if (delegatePolicy != null &&
80                      prevHardCoded.isFocusCycleRoot(focusCycleRoot)) {
81                      return delegatePolicy.getComponentAfter(focusCycleRoot,
82                                                              prevHardCoded);
83                  } else if (delegateManager != null) {
84                      return delegateManager.
85                          getComponentAfter(focusCycleRoot, aComponent);
86                  } else {
87                      return null;
88                  }
89              }
90              if (sanity.contains(hardCoded)) {
91                  // cycle detected; bail
92                  return null;
93              }
94              sanity.add(hardCoded);
95          } while (!accept(hardCoded));
96  
97          return hardCoded;
98      }
99      public Component getComponentBefore(Container focusCycleRoot,
100                                         Component aComponent) {
101         Component hardCoded = aComponent, prevHardCoded;
102         HashSet<Component> sanity = new HashSet<Component>();
103 
104         do {
105             prevHardCoded = hardCoded;
106             hardCoded = backwardMap.get(hardCoded);
107             if (hardCoded == null) {
108                 if (delegatePolicy != null &&
109                     prevHardCoded.isFocusCycleRoot(focusCycleRoot)) {
110                     return delegatePolicy.getComponentBefore(focusCycleRoot,
111                                                        prevHardCoded);
112                 } else if (delegateManager != null) {
113                     return delegateManager.
114                         getComponentBefore(focusCycleRoot, aComponent);
115                 } else {
116                     return null;
117                 }
118             }
119             if (sanity.contains(hardCoded)) {
120                 // cycle detected; bail
121                 return null;
122             }
123             sanity.add(hardCoded);
124         } while (!accept(hardCoded));
125 
126         return hardCoded;
127     }
128     public Component getFirstComponent(Container focusCycleRoot) {
129         if (delegatePolicy != null) {
130             return delegatePolicy.getFirstComponent(focusCycleRoot);
131         } else if (delegateManager != null) {
132             return delegateManager.getFirstComponent(focusCycleRoot);
133         } else {
134             return null;
135         }
136     }
137     public Component getLastComponent(Container focusCycleRoot) {
138         if (delegatePolicy != null) {
139             return delegatePolicy.getLastComponent(focusCycleRoot);
140         } else if (delegateManager != null) {
141             return delegateManager.getLastComponent(focusCycleRoot);
142         } else {
143             return null;
144         }
145     }
146     public Component getDefaultComponent(Container focusCycleRoot) {
147         if (delegatePolicy != null) {
148             return delegatePolicy.getDefaultComponent(focusCycleRoot);
149         } else {
150             return getFirstComponent(focusCycleRoot);
151         }
152     }
153     private boolean accept(Component aComponent) {
154         if (!(aComponent.isVisible() && aComponent.isDisplayable() &&
155               aComponent.isFocusable() && aComponent.isEnabled())) {
156             return false;
157         }
158 
159         // Verify that the Component is recursively enabled. Disabling a
160         // heavyweight Container disables its children, whereas disabling
161         // a lightweight Container does not.
162         if (!(aComponent instanceof Window)) {
163             for (Container enableTest = aComponent.getParent();
164                  enableTest != null;
165                  enableTest = enableTest.getParent())
166             {
167                 if (!(enableTest.isEnabled() || enableTest.isLightweight())) {
168                     return false;
169                 }
170                 if (enableTest instanceof Window) {
171                     break;
172                 }
173             }
174         }
175 
176         return true;
177     }
178     private void writeObject(ObjectOutputStream out) throws IOException {
179         out.defaultWriteObject();
180 
181         if (delegatePolicy instanceof Serializable) {
182             out.writeObject(delegatePolicy);
183         } else {
184             out.writeObject(null);
185         }
186 
187         if (delegateManager instanceof Serializable) {
188             out.writeObject(delegateManager);
189         } else {
190             out.writeObject(null);
191         }
192     }
193     private void readObject(ObjectInputStream in)
194         throws IOException, ClassNotFoundException
195     {
196         in.defaultReadObject();
197         delegatePolicy = (FocusTraversalPolicy)in.readObject();
198         delegateManager = (DefaultFocusManager)in.readObject();
199     }
200 }