/*
* Copyright 2008-2011 the original author or authors.
*
* Licensed 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 org.jdal.swing.form;
import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.util.ArrayList;
import javax.swing.JComboBox;
import javax.swing.JScrollPane;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* FocusTraversalProvider for BoxFormBuilder
*
* @author Jose Luis Martin - (jlm@joseluismartin.info)
*/
public class FormFocusTransversalPolicy extends FocusTraversalPolicy {
private static final Log log = LogFactory.getLog(FormFocusTransversalPolicy.class);
ArrayList<Component> components = new ArrayList<Component>();
@Override
public Component getComponentAfter(Container container,
Component component) {
// Fix awt bug looking for ComboBoxEditor instead ComboBox
// see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6205817
if (component.getParent() instanceof JComboBox)
component = component.getParent();
int index = components.indexOf(component);
if (index == -1) { // not owner
Container childContainer = getTopmostProvider(container, component);
if (childContainer == null)
return getFirstComponent(container);
FocusTraversalPolicy ftp = childContainer.getFocusTraversalPolicy();
if (ftp != null && ftp != this) {
Component next = ftp.getComponentAfter(childContainer, component);
if (next != ftp.getFirstComponent(container))
return next;
// child cycle
do {
index = components.indexOf(childContainer);
childContainer = childContainer.getParent();
} while (index == -1 || childContainer == null);
if (index == -1) {
log.warn("I can't figure what is the next component");
return getFirstComponent(container);
}
}
}
index++;
if (index < components.size() && index >= 0) {
Component c = getComponent(index);
if (c.isEnabled() && c.isFocusable())
return c;
else
return getComponentAfter(container, c);
}
return getFirstComponent(container);
}
private Component getComponent(int index) {
Component c = components.get(index);
Container cc = null;
if (c instanceof Container) {
cc = (Container) c;
if (cc.isFocusTraversalPolicyProvider() || cc.isFocusCycleRoot())
c = cc.getFocusTraversalPolicy().getFirstComponent(cc);
else if (cc instanceof JScrollPane) {
if (((JScrollPane) cc).getViewport().getComponentCount() > 0)
c = ((JScrollPane) cc).getViewport().getComponent(0);
}
}
return c != null ? c : cc;
}
@Override
public Component getComponentBefore(Container aContainer,
Component aComponent) {
int index = components.indexOf(aComponent);
index--;
if (index < components.size() && index >= 0) {
Component c = getComponent(index);
if (c.isEnabled())
return c;
else
return getComponentBefore(aContainer, c);
}
return getLastComponent(aContainer);
}
@Override
public Component getDefaultComponent(Container aContainer) {
if (components.size() > 0) {
return getComponent(0);
}
return null;
}
@Override
public Component getFirstComponent(Container aContainer) {
return getDefaultComponent(aContainer);
}
@Override
public Component getLastComponent(Container aContainer) {
if (!components.isEmpty()) {
Component c = components.get(components.size() - 1);
if (c.isEnabled())
return c;
else
return getComponentBefore(aContainer, c);
}
return null;
}
public void add(Component c) {
components.add(c);
}
/**
* @param component
* @return
*/
@SuppressWarnings("unused")
private FocusTraversalPolicy getFocusTraversalPolicyForComponent(Component component) {
Container c = null;
while ((c = component.getParent()) != null) {
if (c.isFocusTraversalPolicyProvider())
return c.getFocusTraversalPolicy();
component = c;
}
return null;
}
Container getTopmostProvider(Container focusCycleRoot, Component aComponent) {
Container aCont = aComponent.getParent();
Container ftp = null;
while (aCont != focusCycleRoot && aCont != null) {
if (aCont.isFocusTraversalPolicyProvider()) {
ftp = aCont;
}
aCont = aCont.getParent();
}
if (aCont == null) {
return null;
}
return ftp;
}
}