001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /**
019: * @author Anton Avtamonov
020: * @version $Revision$
021: */package javax.swing;
022:
023: import java.awt.Component;
024: import java.awt.ComponentOrientation;
025: import java.awt.Container;
026: import java.awt.DefaultFocusTraversalPolicy;
027: import java.awt.Point;
028: import java.io.Serializable;
029: import java.util.Comparator;
030:
031: import org.apache.harmony.x.swing.internal.nls.Messages;
032:
033: public class LayoutFocusTraversalPolicy extends
034: SortingFocusTraversalPolicy implements Serializable {
035: private static final long serialVersionUID = 3761404205428127289L;
036:
037: private final InternalDefaultFocusTraversalPolicy defaultPolicy = new InternalDefaultFocusTraversalPolicy();
038:
039: public LayoutFocusTraversalPolicy() {
040: setComparator(new LayoutComparator());
041: }
042:
043: public Component getComponentBefore(final Container focusCycleRoot,
044: final Component component) {
045: if (focusCycleRoot == null) {
046: throw new IllegalArgumentException(Messages
047: .getString("swing.4E")); //$NON-NLS-1$
048: }
049: if (component == null) {
050: throw new IllegalArgumentException(Messages
051: .getString("swing.4F")); //$NON-NLS-1$
052: }
053: ((LayoutComparator) getComparator())
054: .setOrientation(focusCycleRoot
055: .getComponentOrientation());
056: return super .getComponentBefore(focusCycleRoot, component);
057: }
058:
059: public Component getComponentAfter(final Container focusCycleRoot,
060: final Component component) {
061: if (focusCycleRoot == null) {
062: throw new IllegalArgumentException(Messages
063: .getString("swing.4E")); //$NON-NLS-1$
064: }
065: if (component == null) {
066: throw new IllegalArgumentException(Messages
067: .getString("swing.4F")); //$NON-NLS-1$
068: }
069: ((LayoutComparator) getComparator())
070: .setOrientation(focusCycleRoot
071: .getComponentOrientation());
072: return super .getComponentAfter(focusCycleRoot, component);
073: }
074:
075: public Component getLastComponent(final Container focusCycleRoot) {
076: if (focusCycleRoot == null) {
077: throw new IllegalArgumentException(Messages
078: .getString("swing.4E")); //$NON-NLS-1$
079: }
080: ((LayoutComparator) getComparator())
081: .setOrientation(focusCycleRoot
082: .getComponentOrientation());
083: return super .getLastComponent(focusCycleRoot);
084: }
085:
086: public Component getFirstComponent(final Container focusCycleRoot) {
087: if (focusCycleRoot == null) {
088: throw new IllegalArgumentException(Messages
089: .getString("swing.4E")); //$NON-NLS-1$
090: }
091: ((LayoutComparator) getComparator())
092: .setOrientation(focusCycleRoot
093: .getComponentOrientation());
094: return super .getFirstComponent(focusCycleRoot);
095: }
096:
097: protected boolean accept(final Component candidate) {
098: if (!super .accept(candidate)) {
099: return false;
100: }
101:
102: if (candidate instanceof JMenu || candidate instanceof JMenuBar) {
103:
104: return false;
105: }
106:
107: if (candidate instanceof JTable) {
108: return true;
109: }
110:
111: if (candidate instanceof JComboBox) {
112: return ((JComboBox) candidate).getUI().isFocusTraversable(
113: (JComboBox) candidate);
114: }
115:
116: if (candidate instanceof JComponent) {
117: InputMap whenFocusedMap = ((JComponent) candidate)
118: .getInputMap(JComponent.WHEN_FOCUSED, false);
119:
120: if (whenFocusedMap != null
121: && whenFocusedMap.allKeys().length > 0) {
122: return true;
123: }
124: }
125:
126: return defaultPolicy.accept(candidate);
127: }
128:
129: // The comparator intention is to order components geometrically.
130: // Provided order must be 'natural' - like components appeared on the screen -
131: // so that the user traverses components as they are layed out.
132: private static class LayoutComparator implements Comparator {
133: private ComponentOrientation orientation;
134:
135: public void setOrientation(final ComponentOrientation co) {
136: orientation = co;
137: }
138:
139: public int compare(final Object o1, final Object o2) {
140: Component c1 = (Component) o1;
141: Component c2 = (Component) o2;
142:
143: if (orientation.isHorizontal()
144: && orientation.isLeftToRight()) {
145: return LTCompare(c1, c2);
146: } else if (orientation.isHorizontal()
147: && !orientation.isLeftToRight()) {
148: return RTCompare(c1, c2);
149: } else if (!orientation.isHorizontal()
150: && orientation.isLeftToRight()) {
151: return TLCompare(c1, c2);
152: } else if (!orientation.isHorizontal()
153: && !orientation.isLeftToRight()) {
154: return TRCompare(c1, c2);
155: }
156:
157: throw new IllegalStateException(Messages
158: .getString("swing.50")); //$NON-NLS-1$
159: }
160:
161: private int LTCompare(final Component c1, final Component c2) {
162: if (onTheSameRow(c1, c2)) {
163: if (onTheSameColumn(c1, c2)) {
164: return 0;
165: } else {
166: Point diff = SwingUtilities.convertPoint(c1, 0, 0,
167: c2);
168: return diff.x;
169: }
170: } else {
171: Point diff = SwingUtilities.convertPoint(c1, 0, 0, c2);
172: return diff.y;
173: }
174: }
175:
176: private int RTCompare(final Component c1, final Component c2) {
177: if (onTheSameRow(c1, c2)) {
178: if (onTheSameColumn(c1, c2)) {
179: return 0;
180: } else {
181: Point diff = SwingUtilities.convertPoint(c2, 0, 0,
182: c1);
183: return diff.x;
184: }
185: } else {
186: Point diff = SwingUtilities.convertPoint(c1, 0, 0, c2);
187: return diff.y;
188: }
189: }
190:
191: private int TLCompare(final Component c1, final Component c2) {
192: if (onTheSameColumn(c1, c2)) {
193: if (onTheSameRow(c1, c2)) {
194: return 0;
195: } else {
196: Point diff = SwingUtilities.convertPoint(c1, 0, 0,
197: c2);
198: return diff.y;
199: }
200: } else {
201: Point diff = SwingUtilities.convertPoint(c1, 0, 0, c2);
202: return diff.x;
203: }
204: }
205:
206: private int TRCompare(final Component c1, final Component c2) {
207: if (onTheSameColumn(c1, c2)) {
208: if (onTheSameRow(c1, c2)) {
209: return 0;
210: } else {
211: Point diff = SwingUtilities.convertPoint(c1, 0, 0,
212: c2);
213: return diff.y;
214: }
215: } else {
216: Point diff = SwingUtilities.convertPoint(c2, 0, 0, c1);
217: return diff.x;
218: }
219: }
220:
221: private boolean onTheSameRow(final Component c1,
222: final Component c2) {
223: if (c1.getSize().getHeight() > c2.getSize().getHeight()) {
224: Point diff = SwingUtilities.convertPoint(c2, 0,
225: (int) (c2.getSize().getHeight() / 2), c1);
226: if (diff.y >= 0 && diff.y <= c1.getSize().getHeight()) {
227: return true;
228: }
229: } else {
230: Point diff = SwingUtilities.convertPoint(c1, 0,
231: (int) (c1.getSize().getHeight() / 2), c2);
232: if (diff.y >= 0 && diff.y <= c2.getSize().getHeight()) {
233: return true;
234: }
235: }
236:
237: return false;
238: }
239:
240: private boolean onTheSameColumn(final Component c1,
241: final Component c2) {
242: if (c1.getSize().getWidth() > c2.getSize().getWidth()) {
243: Point diff = SwingUtilities.convertPoint(c2, (int) (c2
244: .getSize().getWidth() / 2), 0, c1);
245: if (diff.x >= 0 && diff.x <= c1.getSize().getWidth()) {
246: return true;
247: }
248: } else {
249: Point diff = SwingUtilities.convertPoint(c1, (int) (c1
250: .getSize().getWidth() / 2), 0, c2);
251: if (diff.x >= 0 && diff.x <= c2.getSize().getWidth()) {
252: return true;
253: }
254: }
255:
256: return false;
257: }
258: }
259:
260: private class InternalDefaultFocusTraversalPolicy extends
261: DefaultFocusTraversalPolicy {
262: public boolean accept(final Component candidate) {
263: return super.accept(candidate);
264: }
265: }
266: }
|