/*
* 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) 2008 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.station.screen;
import java.awt.Rectangle;
import java.util.Map;
import bibliothek.gui.dock.ScreenDockStation;
import bibliothek.gui.dock.layout.DockableProperty;
import bibliothek.gui.dock.perspective.Perspective;
import bibliothek.gui.dock.perspective.PerspectiveDockable;
import bibliothek.gui.dock.perspective.PerspectiveStation;
import bibliothek.gui.dock.station.support.ConvertedPlaceholderListItem;
import bibliothek.gui.dock.station.support.PerspectivePlaceholderList;
import bibliothek.gui.dock.station.support.PlaceholderList.Level;
import bibliothek.gui.dock.station.support.PlaceholderListItem;
import bibliothek.gui.dock.station.support.PlaceholderListItemAdapter;
import bibliothek.gui.dock.station.support.PlaceholderMap;
import bibliothek.gui.dock.station.support.PlaceholderMetaMap;
import bibliothek.gui.dock.util.DockUtilities;
import bibliothek.util.Path;
/**
* A representation of a {@link ScreenDockStation} in a {@link Perspective}.
* @author Benjamin Sigg
*/
public class ScreenDockPerspective implements PerspectiveStation{
/** a list of all children and placeholders of this station */
private PerspectivePlaceholderList<ScreenPerspectiveWindow> dockables = new PerspectivePlaceholderList<ScreenPerspectiveWindow>();
/**
* Reads the contents of <code>map</code> and replaces any content of this perspective.
* @param map the layout
* @param children the children of this station
*/
public void read( PlaceholderMap map, final Map<Integer, PerspectiveDockable> children ){
PerspectivePlaceholderList<ScreenPerspectiveWindow> next = new PerspectivePlaceholderList<ScreenPerspectiveWindow>();
next.read( map, new PlaceholderListItemAdapter<PerspectiveDockable, ScreenPerspectiveWindow>(){
@Override
public ScreenPerspectiveWindow convert( ConvertedPlaceholderListItem item ){
if( children == null ){
return null;
}
int id = item.getInt( "id" );
PerspectiveDockable dockable = children.get( id );
if( dockable != null ){
ScreenPerspectiveWindow child = new ScreenPerspectiveWindow( dockable );
dockable.setParent( ScreenDockPerspective.this );
child.setX( item.getInt( "x" ) );
child.setY( item.getInt( "y" ) );
child.setWidth( item.getInt( "width" ) );
child.setHeight( item.getInt( "height" ) );
child.setFullscreen( item.getBoolean( "fullscreen" ) );
return child;
}
return null;
}
});
dockables = next;
}
public PerspectiveDockable getDockable( int index ){
return dockables.dockables().get( index ).asDockable();
}
public int getDockableCount(){
return dockables.dockables().size();
}
public PerspectiveDockable asDockable(){
return null;
}
public PerspectiveStation asStation(){
return this;
}
public String getFactoryID(){
return ScreenDockStationFactory.ID;
}
public void setPlaceholders( PlaceholderMap placeholders ){
if( getDockableCount() > 0 ){
throw new IllegalStateException( "there are already children on this station" );
}
dockables = new PerspectivePlaceholderList<ScreenPerspectiveWindow>( placeholders );
}
public PlaceholderMap getPlaceholders(){
return dockables.toMap();
}
/**
* Converts the content of this perspective to a {@link PlaceholderMap} that can be
* stored persistently.
* @param children unique identifiers for the children of this perspective
* @return the map, not <code>null</code>
*/
public PlaceholderMap toMap( final Map<PerspectiveDockable, Integer> children ){
return dockables.toMap( new PlaceholderListItemAdapter<PerspectiveDockable, ScreenPerspectiveWindow>() {
@Override
public ConvertedPlaceholderListItem convert( int index, ScreenPerspectiveWindow child ) {
if( children == null ){
return null;
}
ConvertedPlaceholderListItem item = new ConvertedPlaceholderListItem();
item.putInt( "id", children.get( child.asDockable() ) );
item.putInt( "x", child.getX() );
item.putInt( "y", child.getY() );
item.putInt( "width", child.getWidth() );
item.putInt( "height", child.getHeight() );
item.putBoolean( "fullscreen", child.isFullscreen() );
Path placeholder = child.asDockable().getPlaceholder();
if( placeholder != null ){
item.putString( "placeholder", placeholder.toString() );
item.setPlaceholder( placeholder );
}
return item;
}
});
}
/**
* Adds <code>dockable</code> with boundaries <code>bounds</code> to this perspective.
* @param dockable the element to add
* @param bounds the boundaries of <code>dockable</code>
*/
public void add( PerspectiveDockable dockable, Rectangle bounds ){
add( dockable, bounds, false );
}
/**
* Adds <code>dockable</code> width boundaries <code>bounds</code> to this perspective
* @param dockable the element to add, not <code>null</code>
* @param bounds the boundaries of <code>dockable</code>
* @param fullscreen whether <code>dockable</code> should be extended to fullscreen mode
*/
public void add( PerspectiveDockable dockable, Rectangle bounds, boolean fullscreen ){
add( dockable, bounds.x, bounds.y, bounds.width, bounds.height, fullscreen );
}
/**
* Adds <code>dockable</code> at location <code>x/y</code> with size <code>width/height</code> to
* this perspective.
* @param dockable the element to add, not <code>null</code>
* @param x the x-coordinate on the screen
* @param y the y-coordinate on the screen
* @param width the width of the window
* @param height the height of the window
*/
public void add( PerspectiveDockable dockable, int x, int y, int width, int height ){
add( dockable, x, y, width, height, false );
}
/**
* Adds <code>dockable</code> at location <code>x/y</code> with size <code>width/height</code> to
* this perspective.
* @param dockable the element to add, not <code>null</code>
* @param x the x-coordinate on the screen
* @param y the y-coordinate on the screen
* @param width the width of the window
* @param height the height of the window
* @param fullscreen whether <code>dockable</code> should be extended to fullscreen mode
*/
public void add( PerspectiveDockable dockable, int x, int y, int width, int height, boolean fullscreen ){
DockUtilities.ensureTreeValidity( this, dockable );
ScreenPerspectiveWindow child = new ScreenPerspectiveWindow( dockable );
dockable.setParent( this );
child.setX( x );
child.setY( y );
child.setWidth( width );
child.setHeight( height );
child.setFullscreen( fullscreen );
dockables.dockables().add( child );
}
/**
* Adds a placeholder for <code>dockable</code> and all its children to this
* station.
* @param dockable the element whose placeholder should be inserted
* @param bounds the location and size of <code>dockable</code>
*/
public void addPlaceholder( PerspectiveDockable dockable, Rectangle bounds ){
addPlaceholder( dockable, bounds.x, bounds.y, bounds.width, bounds.height );
}
/**
* Adds a placeholder for <code>dockable</code> and all its children to this
* station.
* @param dockable the element whose placeholder should be inserted
* @param x the x-coordinate on the screen
* @param y the y-coordinate on the screen
* @param width the width of the window
* @param height the height of the window
*/
public void addPlaceholder( PerspectiveDockable dockable, int x, int y, int width, int height ){
ScreenPerspectiveWindow child = new ScreenPerspectiveWindow( dockable );
child.setX( x );
child.setY( y );
child.setWidth( width );
child.setHeight( height );
child.setFullscreen( false );
dockables.dockables().add( child );
remove( dockable );
}
/**
* Adds <code>placeholder</code> to this station.
* @param placeholder the placeholder to add
* @param bounds the location and size of <code>placeholder</code>
*/
public void addPlaceholder( Path placeholder, Rectangle bounds ){
addPlaceholder( placeholder, bounds.x, bounds.y, bounds.width, bounds.height );
}
/**
* Adds <code>placeholder</code> to this station.
* @param placeholder the placeholder to add
* @param x the x-coordinate on the screen
* @param y the y-coordinate on the screen
* @param width the width of the window
* @param height the height of the window
*/
public void addPlaceholder( Path placeholder, int x, int y, int width, int height ){
int index = dockables.list().size();
dockables.list().insertPlaceholder( index, placeholder );
PlaceholderMetaMap map = dockables.list().getMetaMap( index );
map.putInt( "x", x );
map.putInt( "y", y );
map.putInt( "width", width );
map.putInt( "height", height );
}
/**
* Gets the index of <code>dockable</code>.
* @param dockable some child of this station
* @return the index or -1 if <code>dockable</code> was not found
*/
public int indexOf( PerspectiveDockable dockable ){
int count = 0;
for( ScreenPerspectiveWindow child : dockables.dockables() ){
if( child.asDockable() == dockable ){
return count;
}
count++;
}
return -1;
}
/**
* Removes the child <code>dockable</code> from this station.
* @param dockable the element to remove
* @return <code>true</code> if <code>dockable</code> was removed,
* <code>false</code> otherwise
*/
public boolean remove( PerspectiveDockable dockable ){
int index = indexOf( dockable );
if( index >= 0 ){
remove( index );
return true;
}
return false;
}
/**
* Removes the <code>index</code>'th element of this station.
* @param index the index of the element to remove
* @return the removed element
*/
public PerspectiveDockable remove( int index ){
PlaceholderMetaMap map = dockables.dockables().getMetaMap( index );
ScreenPerspectiveWindow child = dockables.dockables().get( index );
map.putInt( "x", child.getX() );
map.putInt( "y", child.getY() );
map.putInt( "width", child.getWidth() );
map.putInt( "height", child.getHeight() );
dockables.remove( child );
child.dockable.setParent( null );
return child.dockable;
}
public void replace( PerspectiveDockable oldDockable, PerspectiveDockable newDockable ){
int index = indexOf( oldDockable );
if( index < 0 ){
throw new IllegalArgumentException( "oldDockable is not a child of this station" );
}
DockUtilities.ensureTreeValidity( this, newDockable );
ScreenPerspectiveWindow window = dockables.dockables().get( index );
Path placeholder = oldDockable.getPlaceholder();
if( placeholder != null ){
dockables.put( placeholder, window );
}
oldDockable.setParent( null );
newDockable.setParent( this );
window.dockable = newDockable;
if( oldDockable.asStation() != null ){
int listIndex = dockables.levelToBase( index, Level.DOCKABLE );
PerspectivePlaceholderList<ScreenPerspectiveWindow>.Item item = dockables.list().get( listIndex );
item.setPlaceholderMap( oldDockable.asStation().getPlaceholders() );
}
}
/**
* Gets access to the window that shows <code>dockable</code>
* @param dockable the element whose window is requested
* @return the window or <code>null</code> if <code>dockable</code> was not found
*/
public ScreenPerspectiveWindow getWindow( PerspectiveDockable dockable ){
for( ScreenPerspectiveWindow child : dockables.dockables() ){
if( child.asDockable() == dockable ){
return child;
}
}
return null;
}
public DockableProperty getDockableProperty( PerspectiveDockable child, PerspectiveDockable target ){
ScreenPerspectiveWindow window = getWindow( child );
if( window == null ){
throw new IllegalArgumentException( "child is not a child of this station" );
}
Path placeholder = null;
if( target != null ){
placeholder = target.getPlaceholder();
}
else{
placeholder = child.getPlaceholder();
}
return new ScreenDockProperty( window.getX(), window.getY(), window.getWidth(), window.getHeight(), placeholder, window.isFullscreen() );
}
/**
* Represents a child of a {@link ScreenDockPerspective}.
* @author Benjamin Sigg
*/
public static class ScreenPerspectiveWindow implements PlaceholderListItem<PerspectiveDockable>{
private PerspectiveDockable dockable;
private int x;
private int y;
private int width;
private int height;
private boolean fullscreen;
/**
* Creates a new object.
* @param dockable the element which is represented by <code>this</code>
*/
public ScreenPerspectiveWindow( PerspectiveDockable dockable ){
if( dockable == null ){
throw new IllegalArgumentException( "dockable must not be null" );
}
this.dockable = dockable;
}
public PerspectiveDockable asDockable(){
return dockable;
}
/**
* Gets the x-coordinate of this dockable on the screen.
* @return the x-coordinate
*/
public int getX(){
return x;
}
/**
* Sets the x-coordinate of this dockable on the screen.
* @param x the x-coordinate
*/
public void setX( int x ){
this.x = x;
}
/**
* Gets the y-coordinate of this dockable on the screen.
* @return the y-coordinate
*/
public int getY(){
return y;
}
/**
* Sets the y-coordinate of this dockable on the screen.
* @param y the y-coordinate
*/
public void setY( int y ){
this.y = y;
}
/**
* Gets the width of this dockable in pixels.
* @return the width
*/
public int getWidth(){
return width;
}
/**
* Sets the width of this dockable in pixels.
* @param width the width
*/
public void setWidth( int width ){
if( width < 0 ){
throw new IllegalArgumentException( "width must be >= 0: " + width );
}
this.width = width;
}
/**
* Gets the height of this dockable in pixels.
* @return the height
*/
public int getHeight(){
return height;
}
/**
* Sets the height of this dockable in pixels.
* @param height the height
*/
public void setHeight( int height ){
if( height < 0 ){
throw new IllegalArgumentException( "height must be >= 0: " + height );
}
this.height = height;
}
/**
* Tells whether this dockable is shown in fullscreen-mode or not.
* @return <code>true</code> if fullscreen-mode is active
*/
public boolean isFullscreen(){
return fullscreen;
}
/**
* Sets whether this dockable is shown in fullscreen-mode or not.
* @param fullscreen whether to activate fullscreen-mode
*/
public void setFullscreen( boolean fullscreen ){
this.fullscreen = fullscreen;
}
}
}