/* * 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 * benjamin_sigg@gmx.ch * CH - Switzerland */ package bibliothek.gui.dock.station.flap; import java.util.Map; import bibliothek.gui.Dockable; import bibliothek.gui.dock.FlapDockStation; 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.PlaceholderListItem; import bibliothek.gui.dock.station.support.PlaceholderListItemAdapter; import bibliothek.gui.dock.station.support.PlaceholderMap; import bibliothek.gui.dock.util.DockUtilities; import bibliothek.util.Path; /** * A representation of a {@link FlapDockStation} in a {@link Perspective}.<br> * <b>Note:</b> while this perspective allows to set the <code>hold</code> and <code>size</code> * property of a dockable, the final decision of how these properties look like are made * by the {@link FlapLayoutManager} that is installed on the {@link FlapDockStation} which shows * the real {@link Dockable}s. * @author Benjamin Sigg */ public class FlapDockPerspective implements PerspectiveDockable, PerspectiveStation{ /** the owner of this dockable */ private PerspectiveStation parent; /** all the children of this station */ private PerspectivePlaceholderList<Item> dockables = new PerspectivePlaceholderList<Item>(); private boolean defaultHold = false; private int defaultSize = 150; /** * Updates the content of this perspective by reading the contents of <code>map</code>. * @param map the placeholders * @param children the possible children of this perspective */ public void read( PlaceholderMap map, final Map<Integer, PerspectiveDockable> children ){ dockables.read( map, new PlaceholderListItemAdapter<PerspectiveDockable, Item>(){ @Override public Item convert( ConvertedPlaceholderListItem item ){ if( children == null ){ return null; } int id = item.getInt( "id" ); PerspectiveDockable dockable = children.get( id ); if( dockable != null ){ boolean hold = item.getBoolean( "hold" ); int size = item.getInt( "size" ); Item element = new Item(); element.dockable = dockable; element.hold = hold; element.size = size; dockable.setParent( FlapDockPerspective.this ); return element; } return null; } }); } public void setPlaceholders( PlaceholderMap placeholders ){ if( getDockableCount() > 0 ){ throw new IllegalStateException( "there are already children present on this station" ); } dockables = new PerspectivePlaceholderList<Item>( placeholders ); } public PlaceholderMap getPlaceholders(){ return dockables.toMap(); } public PlaceholderMap toMap( final Map<PerspectiveDockable, Integer> children ){ return dockables.toMap( new PlaceholderListItemAdapter<PerspectiveDockable, Item>(){ @Override public ConvertedPlaceholderListItem convert( int index, Item dockable ){ ConvertedPlaceholderListItem item = new ConvertedPlaceholderListItem(); item.putInt( "id", children.get( dockable.asDockable() ) ); item.putInt( "index", index ); item.putBoolean( "hold", dockable.hold ); item.putInt( "size", dockable.size ); Path placeholder = item.getPlaceholder(); if( placeholder != null ){ item.putString( "placeholder", placeholder.toString() ); item.setPlaceholder( placeholder ); } return item; } }); } /** * Gets the default size of the window of newly added {@link Dockable}s. * @return the default size */ public int getDefaultSize(){ return defaultSize; } /** * Sets the default size of the window of newly added {@link Dockable}s. Changing * this property has no effect on {@link Dockable}s that were already added to this * station. * @param defaultSize the default size, at least 0 */ public void setDefaultSize( int defaultSize ){ if( defaultSize < 0 ){ throw new IllegalArgumentException( "defaultSize must be at least 0: " + defaultSize ); } this.defaultSize = defaultSize; } /** * Tells whether newly added {@link Dockable}s normally remain open even if they loose the * focus. * @return <code>true</code> if the elements remain open */ public boolean isDefaultHold(){ return defaultHold; } /** * Sets whether newly added {@link Dockable}s remain open even if they lost the focus. * @param defaultHold <code>true</code> if the elements should remain open */ public void setDefaultHold( boolean defaultHold ){ this.defaultHold = defaultHold; } /** * Adds a placeholder for <code>dockable</code> and all its children at * location <code>index</code> to the list of dockables. * @param index the location of <code>dockable</code> * @param dockable the element which is stored as placeholder */ public void insertPlaceholder( int index, PerspectiveDockable dockable ){ Item item = new Item(); item.dockable = dockable; dockables.dockables().add( index, item ); dockables.dockables().remove( index ); } /** * Adds <code>placeholder</code> at location <code>index</code> in the list of items. * @param index the location of <code>placeholder</code> * @param placeholder the placeholder to add, not <code>null</code> */ public void insertPlaceholder( int index, Path placeholder ){ dockables.list().insertPlaceholder( index, placeholder ); } /** * Adds a placeholder for <code>dockable</code> and all its children to the end * of the list of dockables. * @param dockable the element which is stored as placeholder */ public void addPlaceholder( PerspectiveDockable dockable ){ insertPlaceholder( getDockableCount(), dockable ); } /** * Adds <code>placeholder</code> at the end of the list of items. * @param placeholder the placeholder to add, not <code>null</code> */ public void addPlaceholder( Path placeholder ){ insertPlaceholder( dockables.list().size(), placeholder ); } /** * Adds <code>dockable</code> at the end of the list of children. * @param dockable the new element */ public void add( PerspectiveDockable dockable ){ add( dockable, defaultHold, defaultSize ); } /** * Adds <code>dockable</code> at the end of the list of children. * @param dockable the new element * @param hold whether <code>dockable</code> should remain open even if the focus is lost * @param size the preferred size of <code>dockable</code> */ public void add( PerspectiveDockable dockable, boolean hold, int size ){ insert( getDockableCount(), dockable, hold, size ); } /** * Adds a {@link Dockable} to this station. * @param index the location of the new child * @param dockable the new child, not <code>null</code>, must not have a parent */ public void insert( int index, PerspectiveDockable dockable ){ insert( index, dockable, defaultHold, defaultSize ); } /** * Adds <code>dockable</code> to this station. * @param index the location of <code>dockable</code> * @param dockable the new element * @param hold whether <code>dockable</code> should remain open even if the focus is lost * @param size the preferred size of <code>dockable</code> */ public void insert( int index, PerspectiveDockable dockable, boolean hold, int size ){ insert( index, dockable, hold, size, false ); } private void insert( int index, PerspectiveDockable dockable, boolean hold, int size, boolean temporary ){ if( size < 0 ){ throw new IllegalArgumentException( "size must be >= 0" ); } DockUtilities.ensureTreeValidity( this, dockable ); Item item = new Item(); item.dockable = dockable; item.hold = hold; item.size = size; dockables.dockables().add( index, item ); dockable.setParent( this ); } /** * Removes the <code>index</code>'th element of this perspective. * @param index the location of the element to remove * @return the element that was removed */ public PerspectiveDockable remove( int index ){ Item item = dockables.dockables().get( index ); dockables.remove( item ); item.dockable.setParent( null ); return item.dockable; } public boolean remove( PerspectiveDockable dockable ){ int index = indexOf( dockable ); if( index >= 0 ){ remove( index ); return true; } return false; } 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 ); boolean hold = isHold( oldDockable ); int size = getSize( oldDockable ); remove( index ); insert( index, newDockable, hold, size ); } /** * Gets the current index of <code>dockable</code>. * @param dockable some dockable to search * @return the index or -1 if not found */ public int indexOf( PerspectiveDockable dockable ){ int count = 0; for( Item item : dockables.dockables() ){ if( item.asDockable() == dockable ){ return count; } count++; } return -1; } /** * Sets whether <code>dockable</code> should stay open even if it lost focus. * @param dockable the element whose state changes * @param hold whether to keep <code>dockable</code> open * @throws IllegalArgumentException if <code>dockable</code> is not known to this * station */ public void setHold( PerspectiveDockable dockable, boolean hold ){ item( dockable ).hold = hold; } /** * Tells whether <code>dockable</code> should stay open even if it lost focus. * @param dockable the element whose state is requested * @return <code>true</code> if <code>dockable</code> should remain open * @throws IllegalArgumentException if <code>dockable</code> is not known to this * station */ public boolean isHold( PerspectiveDockable dockable ){ return item( dockable ).hold; } /** * Sets the preferred size of the window that shows <code>dockable</code>. * @param dockable some child of this station * @param size the preferred size, at least 0 * @throws IllegalArgumentException if either <code>dockable</code> is not a child * of this station or if <code>size</code> is less than 0 */ public void setSize( PerspectiveDockable dockable, int size ){ if( size < 0 ){ throw new IllegalArgumentException( "size must be >= 0: " + size ); } item( dockable ).size = size; } /** * Gets the preferred size of the window that shows <code>dockable</code>. * @param dockable some child of this station * @return the preferred size * @throws IllegalArgumentException if <code>dockable</code> is not known to this station */ public int getSize( PerspectiveDockable dockable ){ return item( dockable ).size; } public DockableProperty getDockableProperty( PerspectiveDockable child, PerspectiveDockable target ){ int index = indexOf( child ); boolean hold = isHold( child ); int size = getSize( child ); Path placeholder = null; if( target != null ){ placeholder = target.getPlaceholder(); } else{ placeholder = child.getPlaceholder(); } return new FlapDockProperty( index, hold, size, placeholder ); } private Item item( PerspectiveDockable dockable ){ int index = indexOf( dockable ); if( index < 0 ){ throw new IllegalArgumentException( "not a child of this station: " + dockable ); } return dockables.dockables().get( index ); } public void setParent( PerspectiveStation parent ){ this.parent = parent; } public PerspectiveStation getParent(){ return parent; } public Path getPlaceholder(){ return null; } public PerspectiveDockable asDockable(){ return this; } public PerspectiveStation asStation(){ return this; } public String getFactoryID(){ return FlapDockStationFactory.ID; } public PerspectiveDockable getDockable( int index ){ return dockables.dockables().get( index ).dockable; } public int getDockableCount(){ return dockables.dockables().size(); } /** * Represents a single child of this perspective * @author Benjamin Sigg */ private static class Item implements PlaceholderListItem<PerspectiveDockable>{ /** the child */ public PerspectiveDockable dockable; /** whether the child is pinned down */ public boolean hold; /** the preferred size of the window of the child */ public int size; public PerspectiveDockable asDockable(){ return dockable; } } }