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

bibliothek.gui.dock.focus.DockFocusTraversalPolicy Maven / Gradle / Ivy

The newest version!
/*
 * Bibliothek - DockingFrames
 * Library built on Java/Swing, allows the user to "drag and drop"
 * panels containing any Swing-Component the developer likes to add.
 * 
 * Copyright (C) 2007 Benjamin Sigg
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * Benjamin Sigg
 * [email protected]
 * CH - Switzerland
 */
package bibliothek.gui.dock.focus;

import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;

/**
 * A {@link FocusTraversalPolicy} that uses the algorithms of a {@link SimplifiedFocusTraversalPolicy}
 * to do its work. This policy ensures that only valid {@link Component}s
 * are selected, and it respects the constraints for nested policies.
 * @author Benjamin Sigg
 */
public class DockFocusTraversalPolicy extends FocusTraversalPolicy {
    /** the delegate used to determine the next or previous component */
    private SimplifiedFocusTraversalPolicy policy;

    /** whether this policy should try to create real circles or not */
    private boolean circle;

    /** detects recursion in the {@link #getComponentBefore(Container, Component)} method */
    private boolean recursionComponentBefore = false;

    /** detects recursion in the {@link #getComponentAfter(Container, Component)} method */
    private boolean recursionComponentAfter = false;

    /** detects recursion in the {@link #getDefaultComponent(Container)} method */
    private boolean recursionDefaultComponent = false;

    /**
     * Creates a new policy.
     * @param policy the delegate providing algorithms for this policy
     * @param circle if true then this policy does not respect
     * the exact description of the functionality of {@link FocusTraversalPolicy}
     * in order to ensure that getComponentAfter( getComponentBefore( x )) == x and
     * getComponentBefore( getComponentAfter( x )) == x.
     */
    public DockFocusTraversalPolicy( SimplifiedFocusTraversalPolicy policy, boolean circle ){
        if( policy == null )
            throw new IllegalArgumentException( "policy must not be null" );

        this.policy = policy;
        this.circle = circle;
    }

    /**
     * Tells whether component can be focused or not.
     * @param component some {@link Component} which might gain the focus.
     * @return true if component is allowed to
     * gain the focus, false otherwise
     */
    protected boolean accept( Component component ){
        return component.isFocusable() &&
        component.isEnabled() &&
        component.isDisplayable() &&
        component.isShowing();
    }

    @Override
    public Component getComponentAfter( Container container, Component component ) {
        if( recursionComponentAfter ){
            return policy.getAfter( container, component );
        }

        try{
            recursionComponentAfter = true;

            Component next = after( component );

            while( true ){
                if( next == component )
                    return null;

                if( next == null )
                    return null;

                if( next instanceof Container ){
                    Container nextContainer = (Container)next;
                    if( !nextContainer.isFocusCycleRoot() && nextContainer.isFocusTraversalPolicyProvider() ){
                        Component selected;
                        if( circle )
                            selected = nextContainer.getFocusTraversalPolicy().getFirstComponent( nextContainer );
                        else
                            selected = nextContainer.getFocusTraversalPolicy().getDefaultComponent( nextContainer );

                        if( selected == next )
                            return next;
                        next = selected;
                        continue;
                    }
                }

                if( accept( next ))
                    return next;

                next = after( next );
            }
        }
        finally{
            recursionComponentAfter = false;
        }
    }

    /**
     * Searches the next {@link Component} which might gain the focus. This
     * method searches recursively through the tree of {@link Component}s, but
     * does not loop.
     * @param component the currently focused {@link Component}.
     * @return the next {@link Component} which might gain the focus
     */
    protected Component after( Component component ){
        Container provider = getRootOrProvider( component );
        if( provider == null )
            return null;

        FocusTraversalPolicy providerPolicy = getFocusTraversalPolicy( provider );
        if( providerPolicy == null )
            return null;

        Component result = providerPolicy.getComponentAfter( provider, component );

        if( provider.isFocusCycleRoot() ){
            return result;
        }
        else{ // is policy provider
            if( providerPolicy == this ){
                if( result == null || policy.getFirst( provider ) == result ){
                    result = after( provider );
                }
            }
            else{
                if( result == null || providerPolicy.getFirstComponent( provider ) == result ){
                    result = after( provider );
                }
            }
            if( result == component )
            	return null;
            return result;
        }
    }

    @Override
    public Component getComponentBefore( Container container, Component component ) {
        if( recursionComponentBefore ){
            return policy.getBefore( container, component );
        }
        try{
            recursionComponentBefore = true;

            Component previous = before( component );

            while( true ){
                if( previous == component )
                    return null;

                if( previous == null )
                    return null;

                if( previous instanceof Container ){
                    Container previousContainer = (Container)previous;
                    if( !previousContainer.isFocusCycleRoot() && previousContainer.isFocusTraversalPolicyProvider() ){
                        Component selected;
                        if( circle )
                            selected = previousContainer.getFocusTraversalPolicy().getLastComponent( previousContainer );
                        else
                            selected = previousContainer.getFocusTraversalPolicy().getDefaultComponent( previousContainer );

                        if( selected == previous )
                            return previous;
                        previous = selected;
                        continue;
                    }
                }

                if( accept( previous ))
                    return previous;

                previous = after( previous );
            }
        }
        finally{
            recursionComponentBefore = false;
        }
    }


    /**
     * Searches the previous {@link Component} which might gain the focus. This
     * method searches recursively through the tree of {@link Component}s, but
     * does not loop.
     * @param component the currently focused {@link Component}.
     * @return the previous {@link Component} which might gain the focus
     */
    protected Component before( Component component ){
        Container provider = getRootOrProvider( component );
        FocusTraversalPolicy providerPolicy = getFocusTraversalPolicy( provider );

        Component result = providerPolicy.getComponentBefore( provider, component );

        if( provider.isFocusCycleRoot() ){
            return result;
        }
        else{ // is policy provider
            if( providerPolicy == this ){
                if( result == null || policy.getLast( provider ) == result ){
                    result = before( provider );
                }
            }
            else{
                if( result == null || providerPolicy.getLastComponent( provider ) == result ){
                    result = before( provider );
                }
            }
            if( result == component )
            	return null;
            return result;
        }
    }

    @Override
    public Component getDefaultComponent( Container container ) {
        if( recursionDefaultComponent ){
            return policy.getDefault( container );
        }
        try{
            recursionDefaultComponent = true;

            FocusTraversalPolicy providerPolicy = getFocusTraversalPolicy( container );
            Component component = providerPolicy.getDefaultComponent( container );
            
            if( component == container )
                return component;

            if( component instanceof Container ){
                Container ccontainer = (Container)component;
                if( ccontainer.isFocusCycleRoot() || ccontainer.isFocusTraversalPolicyProvider() ){
                    Component result = getDefaultComponent( ccontainer );
                    if( result != null )
                        return result;
                }
            }

            return component;
        }
        finally{
            recursionDefaultComponent = false;
        }
    }

    @Override
    public Component getFirstComponent( Container container ) {
        FocusTraversalPolicy providerPolicy = getFocusTraversalPolicy( container );
        
        Component component = providerPolicy.getDefaultComponent( container );

        if( component == container )
            return component;

        if( component instanceof Container ){
            Container ccontainer = (Container)component;
            if( ccontainer.isFocusCycleRoot() || ccontainer.isFocusTraversalPolicyProvider() ){
                Component result = getFirstComponent( ccontainer );
                if( result != null )
                    return result;
            }
        }

        return component;
    }

    @Override
    public Component getLastComponent( Container container ) {
        FocusTraversalPolicy providerPolicy = getFocusTraversalPolicy( container );
        Component component = providerPolicy.getDefaultComponent( container );

        if( component == container )
            return component;

        if( component instanceof Container ){
            Container ccontainer = (Container)component;
            if( ccontainer.isFocusCycleRoot() || ccontainer.isFocusTraversalPolicyProvider() ){
                Component result = getLastComponent( ccontainer );
                if( result != null )
                    return result;
            }
        }

        return component;
    }

    /**
     * Searches the first parent of component that is either
     * a {@link Container#isFocusCycleRoot() focus cycle root} or
     * a {@link Container#isFocusTraversalPolicyProvider() policy provider}.
     * @param component some component
     * @return some parent or null
     */
    protected Container getRootOrProvider( Component component ){
        Container container = component.getParent();

        while( container != null ){
            if( container.isFocusCycleRoot() || container.isFocusTraversalPolicyProvider() )
                return container;

            container = container.getParent();
        }

        return null;
    }

    /**
     * Searches the {@link FocusTraversalPolicy} which should be used by
     * provider. This method searches for a focus cycle root or
     * policy provider whose traversal policy is {@link Container#isFocusTraversalPolicySet() set}.
     * @param provider a focus cycle root or policy provider whose 
     * {@link SimplifiedFocusTraversalPolicy} is searched.
     * @return the policy of provider or null
     */
    protected FocusTraversalPolicy getFocusTraversalPolicy( Container provider ){
        while( provider != null ){
            if( provider.isFocusCycleRoot() || provider.isFocusTraversalPolicyProvider() ){
                if( provider.isFocusTraversalPolicySet() ){
                    return provider.getFocusTraversalPolicy();
                }
            }

            provider = provider.getParent();
        }

        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy