/*
* 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) 2011 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
* benjamin_sigg@gmx.ch
* CH - Switzerland
*/
package bibliothek.gui.dock.control.focus;
import java.awt.Component;
import java.awt.Window;
import javax.swing.SwingUtilities;
import bibliothek.gui.DockController;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DockElementRepresentative;
import bibliothek.gui.dock.event.FocusVetoListener;
import bibliothek.gui.dock.event.FocusVetoListener.FocusVeto;
/**
* The default implementation of a {@link FocusRequest}, the kind of
* request clients usually will use.
* @author Benjamin Sigg
*/
public class DefaultFocusRequest implements FocusRequest {
/** the element whose child gets the focus, may be <code>null</code> */
private DockElementRepresentative source;
/** the component which get the focus, can be <code>null</code> */
private Component component;
/** whether to force focus transfer always */
private boolean force;
/** whether to ensure that the focus really was transferred */
private boolean ensureFocusSet;
/** like {@link #ensureFocusSet}, but also ensuring that a child of the focused {@link Dockable} gained the focus */
private boolean ensureDockableFocused;
/** whether to execute this request even if the involved {@link Component}s are not visible */
private boolean hardRequest;
/** whether the {@link FocusVetoListener} approved of this request */
private FocusVeto veto;
/** the controller in whose realm this request is called */
private DockController controller;
/**
* Creates a new request for setting the focused {@link Dockable}.
* @param source the item to focus, may be <code>null</code>
* @param force <code>true</code> if this request must ensure that all properties are correct, <code>false</code> if some
* optimizations are allowed. Clients normally can set this argument to <code>false</code>.
*/
public DefaultFocusRequest( DockElementRepresentative source, boolean force ){
this( source, null, force );
}
/**
* Creates a new request for setting the focused {@link Dockable}.
* @param source the item to focus, may be <code>null</code>
* @param component the {@link Component} which triggered this request for example because the user clicked with the mouse on it.
* This request can assume that the focus will automatically be transferred to <code>component</code> by the Swing framework itself.
* Can be <code>null</code>, in which case this request decides on its own which {@link Component} to focus. This request may or may
* not do sanity checks concerning <code>component</code>. An invalid argument will silently be ignored and treated
* as if it would be <code>null</code>.
* @param force <code>true</code> if this request must ensure that all properties are correct, <code>false</code> if some
* optimizations are allowed. Clients normally can set this argument to <code>false</code>.
*/
public DefaultFocusRequest( DockElementRepresentative source, Component component, boolean force ){
this( source, component, force, true, false );
}
/**
* Creates a new request for setting the focused {@link Dockable}.
* @param source the item to focus, may be <code>null</code>
* @param component the {@link Component} which triggered this request for example because the user clicked with the mouse on it.
* This request can assume that the focus will automatically be transferred to <code>component</code> by the Swing framework itself.
* Can be <code>null</code>, in which case this request decides on its own which {@link Component} to focus. This request may or may
* not do sanity checks concerning <code>component</code>. An invalid argument will silently be ignored and treated
* as if it would be <code>null</code>.
* @param force <code>true</code> if this request must ensure that all properties are correct, <code>false</code> if some
* optimizations are allowed. Clients normally can set this argument to <code>false</code>.
* @param ensureFocusSet if <code>true</code>, then this request should make sure that either <code>source</code>
* itself or one of its {@link DockElementRepresentative} is the focus owner
* @param ensureDockableFocused if <code>true</code>, then this method should make sure that <code>source</code>
* is the focus owner. This parameter is stronger that <code>ensureFocusSet</code>
*/
public DefaultFocusRequest( DockElementRepresentative source, Component component, boolean force, boolean ensureFocusSet, boolean ensureDockableFocused ){
this( source, component, force, ensureFocusSet, ensureDockableFocused, false );
}
/**
* Creates a new request for setting the focused {@link Dockable}.
* @param source the item to focus, may be <code>null</code>
* @param component the {@link Component} which triggered this request for example because the user clicked with the mouse on it.
* This request can assume that the focus will automatically be transferred to <code>component</code> by the Swing framework itself.
* Can be <code>null</code>, in which case this request decides on its own which {@link Component} to focus. This request may or may
* not do sanity checks concerning <code>component</code>. An invalid argument will silently be ignored and treated
* as if it would be <code>null</code>.
* @param force <code>true</code> if this request must ensure that all properties are correct, <code>false</code> if some
* optimizations are allowed. Clients normally can set this argument to <code>false</code>.
* @param ensureFocusSet if <code>true</code>, then this request should make sure that either <code>source</code>
* itself or one of its {@link DockElementRepresentative} is the focus owner
* @param ensureDockableFocused if <code>true</code>, then this method should make sure that <code>source</code>
* is the focus owner. This parameter is stronger that <code>ensureFocusSet</code>
* @param hardRequest whether this request should be executed even if the involved {@link Component}s are not
* visible.
*/
public DefaultFocusRequest( DockElementRepresentative source, Component component, boolean force, boolean ensureFocusSet, boolean ensureDockableFocused, boolean hardRequest ){
this.source = source;
this.component = component;
this.force = force;
this.ensureFocusSet = ensureFocusSet;
this.ensureDockableFocused = ensureDockableFocused;
this.hardRequest = hardRequest;
}
public DockElementRepresentative getSource(){
return source;
}
public Component getComponent(){
return component;
}
public int getDelay(){
return 0;
}
public boolean isHardRequest(){
return hardRequest;
}
public boolean acceptable( Component component ){
Dockable dockable = getDockable();
if( ensureDockableFocused && dockable != null ){
return SwingUtilities.isDescendingFrom( component, dockable.getComponent() );
}
return true;
}
public boolean validate( FocusController controller ){
this.controller = controller.getController();
if( force ){
return true;
}
return controller.getFocusedDockable() != getDockable();
}
private Dockable getDockable(){
if( source == null ){
return null;
}
return source.getElement().asDockable();
}
public void veto( FocusVeto veto ){
this.veto = veto;
}
/**
* Tells whether the {@link FocusVetoListener}s approved of this request.
* @return the veto, may be <code>null</code>
*/
public FocusVeto getVeto(){
return veto;
}
public FocusRequest grant( Component component ){
Dockable dockable = getDockable();
if( dockable != null ){
if( ensureFocusSet || ensureDockableFocused ){
return new EnsuringFocusRequest( dockable, ensureDockableFocused, component );
}
}
if( component == null && controller != null ){
Window root = controller.getRootWindowProvider().searchWindow();
if( root != null ){
// if another dockable gains the focus, then it is going to do that
// before this request gets even processed. So this is a backup
// executed to ensure that the application does not lose focus
return new RepeatingFocusRequest( null, root, isHardRequest() );
}
}
return null;
}
}