package bibliothek.gui.dock.common.location;
import java.util.List;
import bibliothek.gui.DockController;
import bibliothek.gui.dock.common.CLocation;
import bibliothek.gui.dock.layout.DockableProperty;
import bibliothek.gui.dock.station.flap.FlapDockProperty;
import bibliothek.gui.dock.station.screen.ScreenDockProperty;
import bibliothek.gui.dock.station.split.SplitDockFullScreenProperty;
import bibliothek.gui.dock.station.split.SplitDockPathProperty;
import bibliothek.gui.dock.station.split.SplitDockPlaceholderProperty;
import bibliothek.gui.dock.station.split.SplitDockProperty;
import bibliothek.gui.dock.station.stack.StackDockProperty;
import bibliothek.gui.dock.util.extension.ExtensionName;
import bibliothek.util.Path;
/**
* The default implementation of {@link CLocationExpandStrategy}. This strategy
* just contains a list for all known {@link DockableProperty}s and can react
* to each property accordingly
* @author Benjamin Sigg
*/
public class DefaultExpandStrategy implements CLocationExpandStrategy{
/**
* Unique id of an extension of {@link CLocationExpandStrategy}s that are utilized before this strategy
* is used.
*/
public static final Path STRATEGY_EXTENSION = new Path( "dock.expandStrategy" );
/** Name of a parameter pointing to <code>this</code> in an {@link ExtensionName} */
public static final String EXTENSION_PARAM = "strategy";
/** Extensions that will be asked for providing a {@link CLocation} before <code>this</code> is evaluated */
private List<CLocationExpandStrategy> extensions;
/**
* Creates a new expand strategy loading extensions if available.
* @param controller the controller in whose realm this strategy is used
*/
public DefaultExpandStrategy( DockController controller ){
extensions = controller.getExtensions().load( new ExtensionName<CLocationExpandStrategy>( STRATEGY_EXTENSION, CLocationExpandStrategy.class, EXTENSION_PARAM, this ) );
}
public CLocation expand( CLocation location, DockableProperty property ){
for( CLocationExpandStrategy extension : extensions ){
CLocation result = extension.expand( location, property );
if( result != null ){
return result;
}
}
if( property instanceof FlapDockProperty ){
return expand( location, (FlapDockProperty)property );
}
if( property instanceof ScreenDockProperty ){
return expand( location, (ScreenDockProperty)property );
}
if( property instanceof SplitDockFullScreenProperty ){
return expand( location, (SplitDockFullScreenProperty)property );
}
if( property instanceof SplitDockPathProperty ){
return expand( location, (SplitDockPathProperty)property );
}
if( property instanceof SplitDockPlaceholderProperty ){
return expand( location, (SplitDockPlaceholderProperty)property );
}
if( property instanceof SplitDockProperty ){
return expand( location, (SplitDockProperty)property );
}
if( property instanceof StackDockProperty ){
return expand( location, (StackDockProperty)property );
}
return null;
}
/**
* Creates a new location by creating the child location of <code>location</code> using
* <code>property</code> for that step.
* @param location the location to expand
* @param property the property that is the source of the next location
* @return the new location or <code>null</code> if no conversion is possible
*/
protected CLocation expand( CLocation location, FlapDockProperty property ){
if( !(location instanceof CFlapLocation) ){
location = new CFlapLocation( location );
}
return new CFlapIndexLocation( (CFlapLocation)location, property.getIndex() );
}
/**
* Creates a new location by creating the child location of <code>location</code> using
* <code>property</code> for that step.
* @param location the location to expand
* @param property the property that is the source of the next location
* @return the new location or <code>null</code> if no conversion is possible
*/
protected CLocation expand( CLocation location, ScreenDockProperty property ){
if( property.isFullscreen() ){
return new CMaximalExternalizedLocation( location, property.getX(), property.getY(), property.getWidth(), property.getHeight() );
}
else{
return new CExternalizedLocation( location, property.getX(), property.getY(), property.getWidth(), property.getHeight() );
}
}
/**
* Creates a new location by creating the child location of <code>location</code> using
* <code>property</code> for that step.
* @param location the location to expand
* @param property the property that is the source of the next location
* @return the new location or <code>null</code> if no conversion is possible
*/
protected CLocation expand( CLocation location, SplitDockFullScreenProperty property ){
// as this property is never created by the framework itself, there is no point
// in handling it.
return null;
}
/**
* Creates a new location by creating the child location of <code>location</code> using
* <code>property</code> for that step.
* @param location the location to expand
* @param property the property that is the source of the next location
* @return the new location or <code>null</code> if no conversion is possible
*/
protected CLocation expand( CLocation location, SplitDockPathProperty property ){
if( !(location instanceof CSplitLocation )){
location = new CSplitLocation( location );
}
CSplitLocation split = (CSplitLocation)location;
if( property.size() > 0 ){
AbstractTreeLocation tree = null;
SplitDockPathProperty.Node node = property.getNode( 0 );
switch( node.getLocation() ){
case BOTTOM:
tree = split.south( node.getSize(), node.getId() );
break;
case LEFT:
tree = split.west( node.getSize(), node.getId() );
break;
case RIGHT:
tree = split.east( node.getSize(), node.getId() );
break;
case TOP:
tree = split.north( node.getSize(), node.getId() );
break;
}
for( int i = 1, n = property.size(); i<n; i++ ){
node = property.getNode( i );
switch( node.getLocation() ){
case BOTTOM:
tree = tree.south( node.getSize(), node.getId() );
break;
case LEFT:
tree = tree.west( node.getSize(), node.getId() );
break;
case RIGHT:
tree = tree.east( node.getSize(), node.getId() );
break;
case TOP:
tree = tree.north( node.getSize(), node.getId() );
break;
}
}
location = tree.leaf( property.getLeafId() );
}
else{
location = split.rectangle( 0, 0, 1, 1 );
}
return location;
}
/**
* Creates a new location by creating the child location of <code>location</code> using
* <code>property</code> for that step.
* @param location the location to expand
* @param property the property that is the source of the next location
* @return the new location or <code>null</code> if no conversion is possible
*/
protected CLocation expand( CLocation location, SplitDockPlaceholderProperty property ){
return expand( location, property.getBackup() );
}
/**
* Creates a new location by creating the child location of <code>location</code> using
* <code>property</code> for that step.
* @param location the location to expand
* @param property the property that is the source of the next location
* @return the new location or <code>null</code> if no conversion is possible
*/
protected CLocation expand( CLocation location, SplitDockProperty property ){
if( !(location instanceof CSplitLocation )){
location = new CSplitLocation( location );
}
return new CRectangleLocation( (CSplitLocation)location, property.getX(), property.getY(), property.getWidth(), property.getHeight() );
}
/**
* Creates a new location by creating the child location of <code>location</code> using
* <code>property</code> for that step.
* @param location the location to expand
* @param property the property that is the source of the next location
* @return the new location or <code>null</code> if no conversion is possible
*/
protected CLocation expand( CLocation location, StackDockProperty property ){
return new CStackLocation( location, property.getIndex() );
}
}