/*
* 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) 2012 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.layout.location;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.layout.DockableProperty;
import bibliothek.gui.dock.station.Combiner;
import bibliothek.gui.dock.station.support.PlaceholderMap;
import bibliothek.util.Path;
/**
* The default implementation of an {@link AsideRequest}, it does not modify any properties or
* layouts.
* @author Benjamin Sigg
*/
public class DefaultAsideRequest implements AsideRequest{
/** The location of an existing {@link Dockable} */
private DockableProperty location;
/** The unique identifier of the new {@link Dockable} */
private Path placeholder;
/** The parent of the current {@link DockStation} or {@link Combiner} */
private DockStation parent;
/** The {@link DockStation} or {@link Combiner} that is handled by this request */
private Forward current;
/** The new location of the element */
private DockableProperty resultingLocation;
/** The new layout of the non-existing station */
private PlaceholderMap resultingLayout;
/** Whether any of the <code>answer</code> methods have been called */
private boolean hasAnswer = false;
/** If there was a call to any <code>forward</code> method, then this is the answer to that call */
private AsideAnswer successorAnswer;
/**
* Creates a new {@link AsideRequest}
* @param location the location of an existing {@link Dockable}, must not be <code>null</code>
* @param placeholder the unique identifier of the {@link Dockable} to insert, the algorithms work much better if
* this arguments is not <code>null</code>
*/
public DefaultAsideRequest( DockableProperty location, Path placeholder ){
this.location = location;
this.placeholder = placeholder;
}
/**
* Creates a new {@link AsideRequest} which is used to examine the next child {@link DockStation}.
* @param location the location on the child station
* @return the new aside request, must not be <code>null</code> nor <code>this</code>
*/
protected DefaultAsideRequest createForwardRequest( DockableProperty location ){
return new DefaultAsideRequest( location, getPlaceholder() );
}
public DockableProperty getLocation(){
return location;
}
public Path getPlaceholder(){
return placeholder;
}
public PlaceholderMap getLayout(){
return current.getLayout();
}
public DockStation getParentStation(){
return parent;
}
/**
* Sets the result of {@link #getParentStation()}.
* @param parent the {@link DockStation} that should be used as parent station
*/
protected void setParentStation( DockStation parent ){
this.parent = parent;
}
public void answer(){
answer( (DockableProperty)null );
}
public void answer( DockableProperty location ){
hasAnswer = true;
resultingLocation = location;
}
public void answer( PlaceholderMap station ){
hasAnswer = true;
resultingLayout = station;
}
public void answer( DockableProperty location, PlaceholderMap station ){
answer( location );
answer( station );
}
/**
* Sets all the information required to process a {@link DockStation} or {@link Combiner}.
* @param current the current item to work with
*/
protected void setCurrent( Forward current ){
this.current = current;
this.resultingLayout = current.getLayout();
}
public AsideAnswer execute( DockStation station ){
setCurrent( new DockStationForward( station ) );
return execute();
}
/**
* Makes a call to {@link DockStation#aside(AsideRequest)} or {@link Combiner#aside(AsideRequest)}. This method
* should be called only once.
* @return the location and layout of the {@link Dockable} that is to be inserted
*/
protected AsideAnswer execute(){
if( hasAnswer ){
throw new IllegalStateException( "this request is already used, it cannot be executed a second time" );
}
current.execute( this );
if( hasAnswer ){
hasAnswer = true;
DockableProperty location = answerLocation( successorAnswer );
return new DefaultAsideAnswer( false, location, resultingLayout );
}
else{
return new DefaultAsideAnswer( true, null, null );
}
}
private DockableProperty answerLocation( AsideAnswer successor ){
if( successor == null || successor.getLocation() == null ){
return resultingLocation;
}
if( resultingLocation == null ){
return successor.getLocation();
}
DockableProperty last = resultingLocation;
while( last.getSuccessor() != null ){
last = last.getSuccessor();
}
last.setSuccessor( successor.getLocation() );
return resultingLocation;
}
public AsideAnswer forward( DockStation station ){
return forward( new DockStationForward( station ));
}
public AsideAnswer forward( Combiner combiner ){
return forward( new CombinerForward( combiner, null ));
}
public AsideAnswer forward( Combiner combiner, PlaceholderMap layout ){
return forward( new CombinerForward( combiner, layout ));
}
protected AsideAnswer forward( Forward forward ){
DockableProperty successor = null;
if( location != null ){
successor = location.getSuccessor();
}
DefaultAsideRequest request = createForwardRequest( successor );
request.setCurrent( forward );
request.setParentStation( current.getStation() );
successorAnswer = request.execute();
return successorAnswer;
}
/**
* All the information required to create a new request and forward the call to a
* new {@link DockStation} or {@link Combiner}.
* @author Benjamin Sigg
*/
protected interface Forward{
/**
* Gets the layout of the current station.
* @return the layout, may be <code>null</code>
*/
public PlaceholderMap getLayout();
/**
* Gets <code>this</code> as {@link DockStation}, if <code>this</code> represents
* a station.
* @return the station or <code>null</code>
*/
public DockStation getStation();
/**
* Calls the <code>aside</code> method of the item represented by this {@link Forward}.
* @param request information about the location of an element and of its new neighbor
*/
public void execute( AsideRequest request );
}
/**
* An adapter mapping {@link DockStation} to {@link Forward}.
* @author Benjamin Sigg
*/
protected static class DockStationForward implements Forward{
private DockStation station;
public DockStationForward( DockStation station ){
this.station = station;
}
public PlaceholderMap getLayout(){
return null;
}
public void execute( AsideRequest request ){
station.aside( request );
}
public DockStation getStation(){
return station;
}
}
/**
* An adapter mapping {@link Combiner} to {@link Forward}.
* @author Benjamin Sigg
*/
protected static class CombinerForward implements Forward{
private Combiner combiner;
private PlaceholderMap layout;
public CombinerForward( Combiner combiner, PlaceholderMap layout ){
this.combiner = combiner;
this.layout = layout;
}
public PlaceholderMap getLayout(){
return layout;
}
public void execute( AsideRequest request ){
combiner.aside( request );
}
public DockStation getStation(){
return null;
}
}
}