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

bibliothek.gui.dock.control.DefaultFocusController Maven / Gradle / Ivy

There is a newer version: 1.1.2p6a
Show 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) 2010 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.control;

import java.awt.Component;
import java.awt.EventQueue;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Stack;

import javax.swing.FocusManager;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import bibliothek.gui.DockController;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DockElementRepresentative;
import bibliothek.gui.dock.control.focus.AbstractFocusController;
import bibliothek.gui.dock.control.focus.FocusController;
import bibliothek.gui.dock.control.focus.FocusStrategy;
import bibliothek.gui.dock.event.FocusVetoListener.FocusVeto;
import bibliothek.gui.dock.title.DockTitle;

/**
 * Default implementation of {@link FocusController}.
 * @author Benjamin Sigg
 */
public class DefaultFocusController extends AbstractFocusController {

    /** the Dockable which has currently the focus, can be null */
    private Dockable focusedDockable = null;
    
    /** true while the controller actively changes the focus */
    private boolean onFocusing = false;
    
    /** whether the focus is to be transfered in the near future */
    private boolean focusingPending = false;
    
    /** the element whose focus may be set in the near future */
    private Component focusingComponent;
    
    /** whether to ensure that the focus is set in the near future */
    private boolean focusingEnsure;
    
    /**
     * Creates a new focus-controller
     * @param controller the owner of this controller
     */
    public DefaultFocusController( DockController controller ){
    	super( controller );
    }
    
    public boolean isOnFocusing(){
	    return onFocusing;
    }
    
    public Dockable getFocusedDockable(){
    	return focusedDockable;
    }
    
    public FocusVeto checkFocusedDockable( DockElementRepresentative source ){
    	if( source == null ){
    		return null;
    	}
    	Dockable dockable = source.getElement().asDockable();
    	if( dockable == null ){
    		return null;
    	}
    	
    	FocusVeto veto;
    	if( source instanceof DockTitle ){
    		veto = fireVetoTitle( (DockTitle)source );
    	}
    	else{
    		veto = fireVetoDockable( dockable );
    	}
    	if( veto == null ){
    		return FocusVeto.NONE;
    	}
    	return veto;
    }
    
    public FocusVeto setFocusedDockable( DockElementRepresentative source, Component component, boolean force, boolean ensureFocusSet, boolean ensureDockableFocused ){
    	// ignore more than one call
    	if( onFocusing || isFrozen() )
    		return null;
    	
    	FocusVeto veto = checkFocusedDockable( source );
    	if( veto != null && veto != FocusVeto.NONE ){
    		return veto;
    	}
    	
    	Dockable focusedDockable = null;
    	if( source != null ){
    		focusedDockable = source.getElement().asDockable();
    	}
    	
    	try{
	        onFocusing = true;
	        
	        if( force || this.focusedDockable != focusedDockable ){
	            Dockable oldFocused = this.focusedDockable;
	            this.focusedDockable = focusedDockable;
	            
	            if( ensureFocusSet || ensureDockableFocused ){
	            	if( EventQueue.isDispatchThread() ){
	            		if( !focusingPending ){
	            			focusingPending = true;
		            	    SwingUtilities.invokeLater( new Runnable(){
	    	                    public void run() {
	    	                    	focusingPending = false;
	    	                        ensureFocusSet( focusingEnsure, focusingComponent );
	    	                        focusingComponent = null;
	    	                    }
	    	                });
		                }
	            		focusingEnsure = ensureDockableFocused;
	            		focusingComponent = component;
	            	}
	                else{
	                    // we are in the wrong Thread, but we can try...
	                    ensureFocusSet( ensureDockableFocused, component );
	                }
	            }
	            
	            if( oldFocused != focusedDockable )
	                fireDockableFocused( oldFocused, focusedDockable );
	        }
    	}
    	finally{
    		onFocusing = false;
    	}
    	
    	return FocusVeto.NONE;
    }
    
    public void ensureFocusSet( boolean dockableOnly ){
    	ensureFocusSet( dockableOnly, null );
    }
    
    private void ensureFocusSet( boolean dockableOnly, Component component ){
    	if( isFrozen() ){
    		return;
    	}

        Dockable focusedDockable = this.focusedDockable;
        if( focusedDockable != null ){
            Stack front = new Stack();            
            
            Dockable temp = focusedDockable;
            
            while( temp != null ){
                DockStation parent = temp.getDockParent();
                if( parent != null )
                    front.push( temp );
                
                temp = parent == null ? null : parent.asDockable();
            }
            
            while( !front.isEmpty() ){
                Dockable element = front.pop();
                element.getDockParent().setFrontDockable( element );
            }
        
            if( !dockableOnly ){
	            DockTitle[] titles = focusedDockable.listBoundTitles();
	            Component focused = FocusManager.getCurrentManager().getFocusOwner();
	            if( focused != null ){
	                if( SwingUtilities.isDescendingFrom( focused, focusedDockable.getComponent() ) )
	                    return;
	                
	                for( DockTitle title : titles )
	                    if( SwingUtilities.isDescendingFrom( focused, title.getComponent() ))
	                        return;
	            }
            }
            
            boolean preset = component != null;
            FocusStrategy strategy = getStrategy();
            if( strategy != null ){
            	Component replacement = strategy.getFocusComponent( focusedDockable, component );
            	if( replacement != null ){
            		if( replacement != component ){
            			component = replacement;
            			preset = false;
            		}
            	}
            	else{
            		preset = false;
            	}
            }
            
            if( component == null ){
            	component = focusedDockable.getComponent();
            }
            
            if( component.isFocusable() ){
                component.requestFocus();
                component.requestFocusInWindow();
                focus( component, 10, 20 );
            }
            else if( !preset ){
                KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent( component );
            }
        }
    }
    
    /**
     * Ensures that component has the focus and is on the 
     * active window. This is done by waiting delay milliseconds
     * and then checking the current focus owner. If the owner is not component,
     * then the focus is transfered. Checking stops after component
     * is found to be the focus owner, or loops failures were reported.
* Note: this awkward method to change the focus is necessary because on some * systems - like Linux - Java does not handle focus very well. * @param component the component which should have the focus * @param delay how much time to wait between two checks of the focus * @param loops how many times to check */ private void focus( final Component component, int delay, final int loops ){ final Timer timer = new Timer( delay, null ); timer.addActionListener( new ActionListener(){ private int remaining = loops; public void actionPerformed( ActionEvent e ) { remaining--; KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); if( manager.getPermanentFocusOwner() != component ){ manager.clearGlobalFocusOwner(); component.requestFocus(); if( remaining > 0 ){ timer.restart(); } } } }); timer.setRepeats( false ); timer.start(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy