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: package java.awt;
019:
020: import java.io.Serializable;
021:
022: import org.apache.harmony.awt.internal.nls.Messages;
023:
024: public class ContainerOrderFocusTraversalPolicy extends
025: FocusTraversalPolicy implements Serializable {
026: private static final long serialVersionUID = 486933713763926351L;
027:
028: private boolean implicitDownCycleTraversal = true;
029:
030: public ContainerOrderFocusTraversalPolicy() {
031: }
032:
033: protected boolean accept(Component aComp) {
034: toolkit.lockAWT();
035: try {
036: // By default, this method will accept a Component if and only if it is
037: // visible[together with parent !!!], displayable, enabled, and focusable.
038: return (aComp.isVisible() && aComp.isDisplayable()
039: && aComp.isEnabled() && aComp.isFocusable());
040: } finally {
041: toolkit.unlockAWT();
042: }
043: }
044:
045: @Override
046: public Component getComponentAfter(Container aContainer,
047: Component aComponent) {
048: toolkit.lockAWT();
049: try {
050: check(aContainer, aComponent);
051: Container provider = findProvider(aContainer, aComponent);
052: if (provider != null) {
053: return getComponent(provider, aComponent, true);
054: }
055: Component nextComp = getComponent(aContainer, aComponent,
056: false, true);
057: return nextComp;
058: } finally {
059: toolkit.unlockAWT();
060: }
061: }
062:
063: private void check(Container aContainer, Component component) {
064: if (aContainer == null || component == null) {
065: // awt.10B=aContainer and aComponent cannot be null
066: throw new IllegalArgumentException(Messages
067: .getString("awt.10B")); //$NON-NLS-1$
068: }
069:
070: if (aContainer.isFocusCycleRoot()) {
071: Component root = component.getFocusCycleRootAncestor();
072: if ((root != aContainer) && (component != aContainer)) {
073: // awt.10C=aContainer is not a focus cycle root of aComponent
074: throw new IllegalArgumentException(Messages
075: .getString("awt.10C")); //$NON-NLS-1$
076: }
077: } else if (!aContainer.isFocusTraversalPolicyProvider()) {
078: // awt.10D=aContainer should be focus cycle root or focus traversal policy provider
079: throw new IllegalArgumentException(Messages
080: .getString("awt.10D")); //$NON-NLS-1$
081: }
082: }
083:
084: @Override
085: public Component getComponentBefore(Container aContainer,
086: Component aComponent) {
087: toolkit.lockAWT();
088: try {
089: check(aContainer, aComponent);
090: Container provider = findProvider(aContainer, aComponent);
091: if (provider != null) {
092: return getComponent(provider, aComponent, false);
093: }
094: Component prevComp = getComponent(aContainer, aComponent,
095: false, false);
096: return prevComp;
097: } finally {
098: toolkit.unlockAWT();
099: }
100: }
101:
102: /**
103: * if a Component is a child of a focus traversal policy provider, the next
104: * and previous for this Component are determined using this focus traversal
105: * policy provider's FocusTraversalPolicy.
106: */
107: private Component getComponent(Container provider, Component comp,
108: boolean after) {
109: if (provider.isFocusCycleRoot()
110: || !provider.isFocusTraversalPolicyProvider()) {
111:
112: return null;
113: }
114: FocusTraversalPolicy policy = provider
115: .getFocusTraversalPolicy();
116: Component nextComp = (after ? policy.getComponentAfter(
117: provider, comp) : policy.getComponentBefore(provider,
118: comp));
119: Component wrapComp = after ? policy.getFirstComponent(provider)
120: : policy.getLastComponent(provider);
121: if (nextComp == wrapComp) {
122: // don't wrap traversal inside providers:
123: // just go to next/prev component after/before
124: // provider in its root ancestor's cycle
125: Container root = provider.getFocusCycleRootAncestor();
126: if (root == null) {
127: return null;
128: }
129: FocusTraversalPolicy rootPolicy = root
130: .getFocusTraversalPolicy();
131: nextComp = (after ? rootPolicy.getComponentAfter(root,
132: provider) : rootPolicy.getComponentBefore(root,
133: provider));
134: }
135: return nextComp;
136: }
137:
138: /*
139: * Find first FTP provider between comp and its FCR container.
140: * Return null if not found
141: *
142: */
143: private Container findProvider(Container container, Component comp) {
144: if (!container.isFocusCycleRoot()) {
145: // prevent endless loop:
146: // if container is already a provider don't
147: // call its policy again
148: return null;
149: }
150: Component curComp = comp;
151: while ((curComp != null)) {
152: Container parent = curComp.getRealParent();
153: if ((parent != null)
154: && parent.isFocusTraversalPolicyProvider()) {
155: return parent;
156: }
157: curComp = parent;
158: }
159: return null;
160: }
161:
162: @Override
163: public Component getDefaultComponent(Container container) {
164: toolkit.lockAWT();
165: try {
166: return getFirstComponent(container);
167: } finally {
168: toolkit.unlockAWT();
169: }
170: }
171:
172: @Override
173: public Component getFirstComponent(Container container) {
174: toolkit.lockAWT();
175: try {
176: if (container == null) {
177: // awt.10E=focusCycleRoot cannot be null
178: throw new IllegalArgumentException(Messages
179: .getString("awt.10E")); //$NON-NLS-1$
180: }
181: Component firstComp = getComponent(container, container,
182: true, true);
183: return firstComp;
184: } finally {
185: toolkit.unlockAWT();
186: }
187: }
188:
189: /**
190: * return first acceptable component after/before[forward is true/false]
191: * comp[ or comp itself if "include" is true] in "container order"
192: */
193: private Component getComponent(Container container, Component comp,
194: boolean include, boolean forward) {
195: Component curComp = comp;
196:
197: if (forward) {
198: Component defComp = getFCRDefComp(curComp, container);
199: if (defComp != null) {
200: return defComp;
201: }
202: }
203: if (!include) {
204: curComp = oneStep(container, curComp, forward, true);
205: if (forward) {
206: Component defComp = getDefComp(curComp, container);
207: if (defComp != null) {
208: return defComp;
209: }
210: }
211: }
212: boolean stop = false;
213: while (!stop && (curComp != null) && !accept(curComp)) {
214: if (forward) {
215: Component defComp = getFCRDefComp(curComp, container);
216: if (defComp != null) {
217: return defComp;
218: }
219: }
220: curComp = oneStep(container, curComp, forward, !include);
221: if (forward) {
222: Component defComp = getDefComp(curComp, container);
223: if (defComp != null) {
224: return defComp;
225: }
226: }
227: stop = (curComp == comp);// stop if comp is traversed again
228:
229: }
230:
231: if (curComp == null) {
232: return null;
233: }
234: return accept(curComp) ? curComp : null;
235: }
236:
237: /**
238: * @param comp
239: * @param root
240: * @return default component given by comp's FTP if comp is FTP provider and
241: * is not same as root, null otherwise
242: */
243: private Component getDefComp(Component comp, Container root) {
244: if (!(comp instanceof Container)) {
245: return null;
246: }
247: Container cont = (Container) comp;
248: boolean isProvider = (!cont.isFocusCycleRoot() && cont
249: .isFocusTraversalPolicyProvider());
250: if (isProvider && (cont != root)) {
251: return cont.getFocusTraversalPolicy().getDefaultComponent(
252: cont);
253: }
254: return null;
255: }
256:
257: /**
258: * @param comp
259: * @param root
260: * @return default component given by comp's FTP if comp is FCR and implicit
261: * down cycle traversal is true and comp is not same as root, null
262: * otherwise
263: */
264: private Component getFCRDefComp(Component comp, Container root) {
265: if (!(comp instanceof Container)) {
266: return null;
267: }
268: Container cont = (Container) comp;
269: boolean isFCR = cont.isFocusCycleRoot();
270: boolean traverseFCR = (isFCR && (cont != root) && getImplicitDownCycleTraversal());
271: if (traverseFCR) {
272: return cont.getFocusTraversalPolicy().getDefaultComponent(
273: cont);
274: }
275: return null;
276:
277: }
278:
279: private int getInitialIndex(Container parent, boolean forward) {
280: return (forward ? 0 : (parent.getComponentCount() - 1));
281: }
282:
283: /**
284: * Make one step forward/backward in
285: * container order from comp, do
286: * not take any conditions, such as
287: * accept(), into consideration. Don't
288: * go into FCRs or FTP providers.
289: * @param root
290: * @param comp
291: * @param forward
292: * @return
293: */
294: private Component oneStep(Container root, Component comp,
295: boolean forward, boolean cycle) {
296: if (root == null || comp == null) {
297: return null;
298: }
299: Container parent = comp.getRealParent();
300: if (parent == null) {
301: parent = (Container) comp;
302: }
303:
304: boolean same = (parent == comp);
305: int maxIdx = parent.getComponentCount() - 1;
306: if (maxIdx < 0) {
307: return (same ? comp : null);
308: }
309:
310: if (forward && (comp instanceof Container)) {
311: Component firstComp = goDown(root, (Container) comp);
312: if (firstComp != null) {
313: return firstComp;
314: }
315: }
316:
317: int idx = parent.getComponentIndex(comp);
318:
319: if (idx < 0) {
320: // if going back and actual parent is null - wrap traversal
321: parent = null;
322: }
323: idx += (forward ? 1 : -1);
324: Component nextComp = comp;
325: if ((parent != null) && checkIndex(parent, idx)) {
326: nextComp = parent.getComponent(idx);
327: if (!forward && (nextComp instanceof Container)) {
328: // go back & down into container
329: nextComp = getCompInContainer((Container) nextComp,
330: root);
331: }
332: } else {
333: // go up to parent container
334: nextComp = forward ? getCompAfterContainer(parent) : parent;
335: }
336:
337: if (!root.isAncestorOf(nextComp) && (root != nextComp)) {
338: // wrap if trying to get out of root:
339: nextComp = cycle ? wrapTraversal(root, forward)
340: : /*root*/null;
341: }
342: return nextComp;
343:
344: }
345:
346: private Component goDown(Container root, Container cont) {
347: int idx = getInitialIndex(cont, true);
348: if (!canGoDown(root, cont)) {
349: idx = -1;// don't try to go into FCRs or FTPPs(?)
350: // treat them just like containers with
351: // no components inside
352: }
353: if (checkIndex(cont, idx)) {
354: // go down into container first
355: return cont.getComponent(idx);
356: }
357: return null;
358: }
359:
360: private boolean canGoDown(Container root, Container cont) {
361: if ((root == null) || (cont == null)) {
362: return false;
363: }
364: return ((!cont.isFocusCycleRoot() && !cont
365: .isFocusTraversalPolicyProvider()) || (cont == root));
366: }
367:
368: /**
369: * Find last component inside container
370: * when traversing backward[going down into containers].
371: * Skip focus cycle roots which are not
372: * same as root.
373: * @param container
374: * @return
375: */
376: private Component getCompInContainer(Container container,
377: Container root) {
378: Component lastComp = container;
379: while (lastComp instanceof Container) {
380: Container cont = (Container) lastComp;
381: if (!canGoDown(root, cont)) {
382: break;
383: }
384: int idx = getInitialIndex(cont, false);
385: if (!checkIndex(cont, idx)) {
386: break;
387: }
388: lastComp = cont.getComponent(idx);
389: }
390:
391: return lastComp;
392: }
393:
394: /**
395: * Find first component after
396: * container[go up & forward]
397: * @param parent
398: * @return
399: */
400: private Component getCompAfterContainer(Container container) {
401: Container parent = container;
402: while (parent != null) {
403: parent = container.getRealParent();
404: Component nextComp = getComp(parent, container, true);
405: if (nextComp != null) {
406: return nextComp;
407: }
408: container = parent;
409: }
410:
411: return null;
412: }
413:
414: /**
415: * Get component before/after "comp" in container
416: * "parent". If there's no such component in
417: * "parent" (comp was first or last) - return null
418: * @param parent
419: * @param container
420: * @return
421: */
422: private Component getComp(Container parent, Component comp,
423: boolean forward) {
424: if ((parent == null) || (comp == null)) {
425: return null;
426: }
427: int idx = parent.getComponentIndex(comp);
428: if (idx < 0) {
429: return null;
430: }
431: idx += forward ? 1 : -1;
432: if (checkIndex(parent, idx)) {
433: return parent.getComponent(idx);
434: }
435: return null;
436: }
437:
438: private Component wrapTraversal(Container container, boolean forward) {
439: Component comp = forward ? getFirstComponent(container)
440: : getLastComponent(container);
441: return comp;
442: }
443:
444: private boolean checkIndex(Container container, int idx) {
445: return ((idx >= 0) && (idx < container.getComponentCount()));
446: }
447:
448: @Override
449: public Component getLastComponent(Container container) {
450: toolkit.lockAWT();
451: try {
452: if (container == null) {
453: // awt.10E=focusCycleRoot cannot be null
454: throw new IllegalArgumentException(Messages
455: .getString("awt.10E")); //$NON-NLS-1$
456: }
457: int count = container.getComponentCount();
458: if (count <= 0) {
459: return accept(container) ? container : null;
460: }
461: Component lastComp = getComponent(container,
462: getCompInContainer(container, container), true,
463: false);
464: return lastComp;
465: } finally {
466: toolkit.unlockAWT();
467: }
468: }
469:
470: public boolean getImplicitDownCycleTraversal() {
471: toolkit.lockAWT();
472: try {
473: return implicitDownCycleTraversal;
474: } finally {
475: toolkit.unlockAWT();
476: }
477: }
478:
479: public void setImplicitDownCycleTraversal(boolean value) {
480: toolkit.lockAWT();
481: try {
482: implicitDownCycleTraversal = value;
483: } finally {
484: toolkit.unlockAWT();
485: }
486: }
487:
488: }
|