All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jclarion.clarion.swing.ClarionFocusTraversalPolicy Maven / Gradle / Ivy

There is a newer version: 1.86
Show newest version
/**
 * Copyright 2010, by Andrew Barnham
 *
 * The contents of this file are subject to
 * GNU Lesser General Public License (LGPL), v.3
 * http://www.gnu.org/licenses/lgpl.txt
 * 
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 */
package org.jclarion.clarion.swing;

import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.awt.Window;
import java.util.Iterator;

import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JRadioButton;
import javax.swing.JRootPane;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
import javax.swing.table.JTableHeader;

import org.jclarion.clarion.AbstractWindowTarget;
import org.jclarion.clarion.control.AbstractControl;
import org.jclarion.clarion.control.OptionControl;
import org.jclarion.clarion.control.RadioControl;

public class ClarionFocusTraversalPolicy extends FocusTraversalPolicy  
{
    @SuppressWarnings("serial")
    private static class SwingContainerOrderFocusTraversalPolicy
        extends java.awt.ContainerOrderFocusTraversalPolicy
    {
        public boolean accept(Component aComponent) {
            return super.accept(aComponent);
        }
    }
    
    private static final SwingContainerOrderFocusTraversalPolicy
        fitnessTestPolicy = new SwingContainerOrderFocusTraversalPolicy();

    private static class MutableBoolean {
        boolean value = false;    
    }    
    
    private static final MutableBoolean found = new MutableBoolean();

    private static class ContainerIterator implements Iterator
    {
        private int start;
        private int stop;
        private int step;
        private Container container;
       
        
        private ContainerIterator(Container c,boolean reverse)
        {
            this.container=c;
            if (!reverse) {
                start=0;
                stop=c.getComponentCount();
                step=1;
            } else {
                start=c.getComponentCount()-1;
                stop=-1;
                step=-1;
            }
        }
        
        @Override
        public boolean hasNext() {
            return start!=stop;
        }

        @Override
        public Component next() {
            if (start==stop) throw new IllegalArgumentException("Waa!");
            Component result=container.getComponent(start);
            start+=step;
            return result;
        }

        @Override
        public void remove() {
        }
        
    }
    
    private static class ContainerIterable implements Iterable
    {
        private Container c;
        private boolean reverse;

        public ContainerIterable(Container c,boolean reverse)
        {
            this.c=c;
            this.reverse=reverse;
        }
        
        @Override
        public Iterator iterator() {
            return new ContainerIterator(c,reverse);
        }
    }

    private AbstractWindowTarget target;
    
    public ClarionFocusTraversalPolicy()
    {
    }

    public ClarionFocusTraversalPolicy(AbstractWindowTarget target)
    {
        this.target=target;
    }
    
    private Iterable getOrder(Container c,boolean reverse)
    {
        if (c instanceof ClarionContentPane) reverse=!reverse;
        return new ContainerIterable(c,reverse);
    }

    public boolean accept(Component scan,Component original) {
        if (scan==null) return true;
        
        
        if (!fitnessTestPolicy.accept(scan)) return false;
        if (scan.getClass().getName().startsWith("com.sun")) return false; 
        if (scan instanceof Window) return false;
        if (scan instanceof JRootPane) return false;
        if (scan instanceof JLayeredPane) return false;
        if (scan instanceof JScrollPane) return false;
        if (scan instanceof JViewport) return false;
        if (scan instanceof JSpinner) return false;
        if (scan instanceof JPanel) return false;
        if (scan instanceof JTableHeader) return false;
        if (scan instanceof JScrollBar) return false;
        if (scan instanceof JInternalFrame) return false;
        if (scan instanceof JMenuBar) return false;
        if (scan instanceof JProgressBar) return false;
        if (scan instanceof JMenuItem) return false;
        if (scan instanceof JLabel) return false;
        if (scan instanceof JTabbedPane) return false;
        if (scan instanceof ClarionCanvas) return false;
        if (scan instanceof JRadioButton) {
            
            // rules for traversal of radios are as follows
            
            // sub rules when nothing is selected - standard handling
            
            // sub rules when something is selected -
            //  a) if traversing in then only select the selected item
            //  b) if traversing within then traverse out
            
            RadioControl rc = (RadioControl)((JComponent)scan).getClientProperty("clarion");
            OptionControl oc = (OptionControl)rc.getParent();
            
            boolean selected=false;
            for (AbstractControl c_child : ((AbstractControl)oc).getChildren()) {
                JRadioButton child = (JRadioButton)c_child.getComponent();
                if (child.isSelected() && child.isVisible() && child.isEnabled()) { 
                    selected=true;
                    break;
                }
            }
            
            if (selected) {
                if (original!=null) {
                    if (original instanceof JRadioButton) {
                        RadioControl c_original = (RadioControl)((JComponent)scan).getClientProperty("clarion");
                        if (oc==c_original.getParent()) return false;
                    }
                }
                if (!((JRadioButton)scan).isSelected()) return false;
            }
        }
        if (scan instanceof BasicInternalFrameTitlePane) return false;
        
        if (scan instanceof JTable) {
        	if (((JTable)scan).getRowCount()==0) return false; 
        }

        if (scan instanceof JComponent) {
            JComponent jc = (JComponent)scan;
            if (jc.getClientProperty("clarionSkipFocus")!=null) return false;
        }
        return true;
    }

    @Override
    public Component getComponentAfter(Container aContainer,
                                       Component aComponent) {
        if (aContainer == null || aComponent == null) {
            throw new IllegalArgumentException("aContainer and aComponent cannot be null");
        }
        if (!aContainer.isFocusTraversalPolicyProvider() && !aContainer.isFocusCycleRoot()) {
            throw new IllegalArgumentException("aContainer should be focus cycle root or focus traversal policy provider");
        } else if (aContainer.isFocusCycleRoot() && !aComponent.isFocusCycleRoot(aContainer)) {
            throw new IllegalArgumentException("aContainer is not a focus cycle root of aComponent");
        }

        synchronized(aContainer.getTreeLock()) {
            found.value = false;
            Component retval = getComponentAfter(aContainer,aComponent,aComponent,found);
            if (retval != null) {
                return retval;
            } else if (found.value) {
                return getFirstComponent(aContainer);
            } else {
                return null;
            }
        }
    }

    private Component getComponentAfter(Container aContainer,
            Component aOriginal,
            Component aComponent,
            MutableBoolean found) 
    {
        if (!(aContainer.isVisible() && aContainer.isDisplayable())) {
            return null;
        }

        if (found.value) {
            if (accept(aContainer,aOriginal)) {
                return aContainer;
            }
        } else if (aContainer == aComponent) {
            found.value = true;
        }

        for ( Component comp : getOrder(aContainer,false) ) {
            if ((comp instanceof Container) &&
                    !((Container)comp).isFocusCycleRoot()) {
                Component retval = null;
                if (((Container)comp).isFocusTraversalPolicyProvider()) {
                    Container cont = (Container) comp;
                    FocusTraversalPolicy policy = cont.getFocusTraversalPolicy();
                    if (found.value) {
                        retval = policy.getDefaultComponent(cont);
                    } else {
                        found.value = cont.isAncestorOf(aComponent);                    
                        if (found.value)  {
                            if (aComponent == policy.getLastComponent(cont)) {
                                // Reached last component, going to wrap - should switch to next provider
                                retval = null;
                            } else {
                                retval = policy.getComponentAfter(cont, aComponent);
                            }
                        }
                    }
                } else {
                    retval = getComponentAfter((Container)comp,
                         aOriginal,
                         aComponent,
                         found);
                }   
                if (retval != null) {
                    return retval;
                }
            } else if (found.value) {
                if (accept(comp,aOriginal)) {
                    return comp;
                }
            } else if (comp == aComponent) {
                found.value = true;
            }

            if (found.value &&
                    getImplicitDownCycleTraversal() &&
                    (comp instanceof Container) &&
                    ((Container)comp).isFocusCycleRoot())
            {
                Container cont = (Container)comp;
                Component retval = cont.getFocusTraversalPolicy().
                getDefaultComponent(cont);
                if (retval != null) {
                    return retval;
                }
            }
        }

        return null;
    }
    
    @Override
    public Component getComponentBefore(Container aContainer,
                                        Component aComponent) {
        if (aContainer == null || aComponent == null) {
            throw new IllegalArgumentException("aContainer and aComponent cannot be null");
        }
        if (!aContainer.isFocusTraversalPolicyProvider() && !aContainer.isFocusCycleRoot()) {
            throw new IllegalArgumentException("aContainer should be focus cycle root or focus traversal policy provider");
        } else if (aContainer.isFocusCycleRoot() && !aComponent.isFocusCycleRoot(aContainer)) {
            throw new IllegalArgumentException("aContainer is not a focus cycle root of aComponent");
        }
        synchronized(aContainer.getTreeLock()) {
            found.value = false;
            Component retval = getComponentBefore(aContainer, aComponent,aComponent,
                                                  found);
            if (retval != null) {
                return retval;
            } else if (found.value) {
                return getLastComponent(aContainer);
            } else {
                return null;
            }
        }
    }

    private Component getComponentBefore(Container aContainer,Component aOriginal,
            Component aComponent,
            MutableBoolean found) 
    {
        if (!(aContainer.isVisible() && aContainer.isDisplayable())) {
            return null;
        }

        for ( Component comp : getOrder(aContainer,true) ) {
            if (comp == aComponent) {
                found.value = true;
            } else if ((comp instanceof Container) &&
                    !((Container)comp).isFocusCycleRoot()) {
                Component retval = null;
                if (((Container)comp).isFocusTraversalPolicyProvider()) {
                    Container cont = (Container) comp;
                    FocusTraversalPolicy policy = cont.getFocusTraversalPolicy();
                    if (found.value) {
                        retval = policy.getLastComponent(cont);
                    } else {
                        found.value = cont.isAncestorOf(aComponent);                    
                        if (found.value) {
                            if (aComponent == policy.getFirstComponent(cont)) {
                                retval = null;
                            } else {
                                retval = policy.getComponentBefore(cont, aComponent);
                            }
                        }
                    }
                } else {
                    retval = getComponentBefore((Container)comp,aOriginal,
                         aComponent,
                         found);
                }
                if (retval != null) {
                    return retval;
                }
            } else if (found.value) {
                if (accept(comp,aOriginal)) {
                    return comp;
                }
            }
        }

        if (found.value) {
            if (accept(aContainer,aOriginal)) {
                return aContainer;
            }
        } else if (aContainer == aComponent) {
            found.value = true;
        }

        return null;
    }
    
    @Override
    public Component getFirstComponent(Container aContainer) {
        if (aContainer == null) {
            throw new IllegalArgumentException("aContainer cannot be null");
        }

        synchronized(aContainer.getTreeLock()) {
            if (!(aContainer.isVisible() &&
                  aContainer.isDisplayable()))
            {
                return null;
            }

            if (accept(aContainer,null)) {
                return aContainer;
            }

            for ( Component comp : getOrder(aContainer,false) ) {
                if (comp instanceof Container &&
                        !((Container)comp).isFocusCycleRoot())
                {
                    Component retval = null;
                    Container cont = (Container)comp;
                    if (cont.isFocusTraversalPolicyProvider()) {
                        FocusTraversalPolicy policy = cont.getFocusTraversalPolicy();
                        retval = policy.getDefaultComponent(cont);
                    } else {
                        retval = getFirstComponent((Container)comp);
                    }
                    if (retval != null) {
                        return retval;
                    }
                } else if (accept(comp,null)) {
                    return comp;
                }
            }
        }

        if (aContainer instanceof JRootPane) return aContainer;
        return null;            
    }

    @Override
    public Component getLastComponent(Container aContainer) {
        if (aContainer == null) {
            throw new IllegalArgumentException("aContainer cannot be null");
        }
        synchronized(aContainer.getTreeLock()) {
            if (!(aContainer.isVisible() &&
                  aContainer.isDisplayable()))
        {
                return null;
            }

            for ( Component comp : getOrder(aContainer,true) ) {
                if (comp instanceof Container &&
                        !((Container)comp).isFocusCycleRoot())
                {
                    Component retval = null;
                    Container cont = (Container)comp;
                    if (cont.isFocusTraversalPolicyProvider()) {
                        FocusTraversalPolicy policy = cont.getFocusTraversalPolicy();
                        retval = policy.getLastComponent(cont);
                    } else {
                        retval = getLastComponent((Container)comp);
                    }
                    if (retval != null) {
                        return retval;
                    }
                } else if (accept(comp,null)) {
                    return comp;
                }
            }

            if (accept(aContainer,null)) {
                return aContainer;
            }
        }

        return null;            
    }

    public boolean getImplicitDownCycleTraversal() {
        return true;
    }

    @Override
    public Component getDefaultComponent(Container container) {
        if (target!=null && target.getInitialSelectControl()!=null) {
            Component c = target.getInitialSelectControl().getComponent();
            if (c!=null && accept(c,null)) {
                target.setInitialSelectControl(null);
                return c;
            }
        }
        return getFirstComponent(container);
    }

    @Override
    public Component getInitialComponent(Window window) {
        if (target!=null && target.getInitialSelectControl()!=null) {
            Component c = target.getInitialSelectControl().getComponent();
            if (c!=null && accept(c,null)) {
                target.setInitialSelectControl(null);
                return c;
            }
        }
        return super.getInitialComponent(window);
    }

    
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy