/*
* 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) 2007 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;
import java.awt.Component;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import bibliothek.gui.DockController;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.displayer.DisplayerRequest;
import bibliothek.gui.dock.themes.DefaultDisplayerFactoryValue;
import bibliothek.gui.dock.title.DockTitle;
import bibliothek.gui.dock.util.extension.Extension;
/**
* A set of {@link DockableDisplayer}s. Clients may
* {@link #fetch(Dockable, DockTitle) fetch} a new displayer at any time. They
* should {@link #release(DockableDisplayer) release} a displayer which
* is no longer used. The collection ensures that various properties of the
* displayers are set in the proper order.
* @author Benjamin Sigg
*/
public class DisplayerCollection implements Iterable<DockableDisplayer>{
/** the station for which displayers are created */
private DockStation station;
/** the current controller, all displayer should know this controller */
private DockController controller;
/** a factory used to create new displayers */
private DisplayerFactory factory;
/** the set of displayers that are fetched but not released */
private List<Handle> displayers = new ArrayList<Handle>();
/** list of listeners added to each {@link DockableDisplayer} known to this collection */
private List<DockableDisplayerListener> listeners = new ArrayList<DockableDisplayerListener>();
private String displayerId;
/**
* Creates a new collection
* @param station the station for which {@link DockableDisplayer} will be created
* @param factory the factory that is initially used to create displayers
* @param displayerId an identifier depending on <code>station</code>, this identifier is forwarded to
* {@link Extension}s allowing them an easy solution to filter uninteresting requests
*/
public DisplayerCollection( DockStation station, DisplayerFactory factory, String displayerId ){
if( station == null )
throw new IllegalArgumentException( "Station must not be null" );
if( factory == null )
throw new IllegalArgumentException( "Factory must not be null" );
if( displayerId == null ){
throw new IllegalArgumentException( "displayerId must not be null" );
}
this.station = station;
this.factory = factory;
this.displayerId = displayerId;
}
/**
* Creates a new collection
* @param station the station for which {@link DockableDisplayer}s will be created
* @param factory the factory that is used create displayers
* @param displayerId an identifier depending on <code>station</code>, this identifier is forwarded to
* {@link Extension}s allowing them an easy solution to filter uninteresting requests
*/
public DisplayerCollection( DockStation station, final DefaultDisplayerFactoryValue factory, String displayerId ){
this( station, new DisplayerFactory(){
public void request( DisplayerRequest request ){
factory.request( request );
}
}, displayerId );
}
/**
* Adds <code>listener</code> to all {@link DockableDisplayer}s that are
* in this collection.
* @param listener a new listener, not <code>null</code>
*/
public void addDockableDisplayerListener( DockableDisplayerListener listener ){
listeners.add( listener );
for( DockableDisplayer displayer : this ){
displayer.addDockableDisplayerListener( listener );
}
}
/**
* Removes <code>listener</code> from all {@link DockableDisplayer}s
* that are in this collection.
* @param listener the listener to remove
*/
public void removeDockableDisplayerListener( DockableDisplayerListener listener ){
listeners.remove( listener );
for( DockableDisplayer displayer : this ){
displayer.removeDockableDisplayerListener( listener );
}
}
/**
* Tells whether <code>component</code> is the root component of any {@link DockableDisplayer}.
* @param component the component to search
* @return <code>true</code> if at least one {@link DockableDisplayer#getComponent()} returns <code>component</code>
*/
public boolean isDisplayerComponent( Component component ){
for( DockableDisplayer displayer : this ){
if( displayer.getComponent() == component ){
return true;
}
}
return false;
}
public Iterator<DockableDisplayer> iterator() {
return new Iterator<DockableDisplayer>(){
private Iterator<Handle> handles = displayers.iterator();
public boolean hasNext(){
return handles.hasNext();
}
public DockableDisplayer next(){
return handles.next().getAnswer();
}
public void remove(){
handles.remove();
}
};
}
/**
* Creates a new {@link DockableDisplayer} using the {@link #setFactory(DisplayerFactory) factory}
* of this collection. This method also sets the {@link DockableDisplayer#setTitle(DockTitle) title},
* {@link DockableDisplayer#setStation(DockStation) station}
* and the {@link DockableDisplayer#setController(DockController) controller} property of
* the displayer.<br>
* If the displayer is no longer needed, then it should be {@link #release(DockableDisplayer) released}
* @param dockable the Dockable which will be shown on the displayer.
* @param title the title which will be shown on the displayer, might be <code>null</code>
* @return the new displayer
*/
public DockableDisplayer fetch( Dockable dockable, DockTitle title ){
Handle handle = new Handle( dockable );
handle.setController( controller );
handle.request( title );
DockableDisplayer displayer = handle.getAnswer();
displayer.setDockable( dockable );
displayer.setTitle( title );
displayer.setStation( station );
displayers.add( handle );
for( DockableDisplayerListener listener : listeners )
displayer.addDockableDisplayerListener( listener );
return displayer;
}
/**
* Releases a displayer that was created by this collection.
* @param displayer the displayer to release
*/
public void release( DockableDisplayer displayer ){
for( DockableDisplayerListener listener : listeners ){
displayer.removeDockableDisplayerListener( listener );
}
Iterator<DockableDisplayer> iter = iterator();
while( iter.hasNext() ){
if( iter.next() == displayer ){
iter.remove();
}
}
displayer.setTitle( null );
displayer.setDockable( null );
displayer.setStation( null );
displayer.setController( null );
}
/**
* Sets the factory that will create new {@link DockableDisplayer} when
* needed.
* @param factory the new factory, not <code>null</code>
*/
public void setFactory( DisplayerFactory factory ){
if( factory == null )
throw new IllegalArgumentException( "Factory must not be null" );
this.factory = factory;
}
/**
* Sets the current {@link DockController}, that controller will be made
* known to all {@link DockableDisplayer} created by this collection.
* @param controller the new controller, can be <code>null</code>
*/
public void setController( DockController controller ){
if( this.controller != controller ){
this.controller = controller;
for( Handle handle : displayers ){
handle.setController( controller );
}
}
}
/**
* A {@link Handle} handles the {@link DockableDisplayer} of one {@link Dockable}
* @author Benjamin Sigg
*/
private class Handle extends DisplayerRequest {
public Handle( Dockable target ){
super( station, target, new DisplayerFactory(){
public void request( DisplayerRequest request ){
DisplayerCollection.this.factory.request( request );
}
}, displayerId );
}
@Override
public void setController( DockController controller ){
super.setController( controller );
DockableDisplayer displayer = getAnswer();
if( displayer != null ){
displayer.setController( null );
}
}
@Override
protected void answer( DockableDisplayer previousResource, DockableDisplayer newResource ){
if( previousResource != null ){
previousResource.setController( null );
}
if( newResource != null ){
newResource.setController( getController() );
}
}
}
}