/*
* 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.common.intern.ui;
import java.util.*;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.event.CControlListener;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.color.ColorTransmitter;
import bibliothek.gui.dock.util.UIBridge;
import bibliothek.gui.dock.util.UIValue;
/**
* An {@link UITransmitter} listens to some kind of map
* and updates some {@link UIValue}s when the contents of that map change.
* @author Benjamin Sigg
* @param <V> the kind of value that is described by the {@link UIValue}
* @param <U> the kind of {@link UIValue} used in this transmitter
*/
public abstract class UITransmitter<V, U extends UIValue<V>> implements UIBridge<V, U> {
private CControl control;
private Set<String> keys = new HashSet<String>();
private Map<String, List<U>> values = new HashMap<String, List<U>>();
private Listener listener = new Listener();
/**
* Creates a new {@link ColorTransmitter}.
* @param keys the keys which should be monitored by this transmitter
*/
public UITransmitter( String... keys ){
for( String key : keys )
this.keys.add( key );
}
public void add( String id, U value ) {
if( keys.contains( id )){
boolean empty = values.isEmpty();
List<U> list = values.get( id );
if( list == null ){
list = new LinkedList<U>();
values.put( id, list );
}
list.add( value );
if( empty )
setListening( true );
}
}
public void remove( String id, U value ) {
if( keys.contains( id )){
boolean empty = values.isEmpty();
List<U> list = values.get( id );
list.remove( value );
if( list.isEmpty() ){
values.remove( id );
}
if( !empty && values.isEmpty() )
setListening( false );
}
}
/**
* Sets the {@link CControl} which should be observed for new {@link CDockable}s
* by this transmitter.
* @param control the observed control, can be <code>null</code>
*/
public void setControl( CControl control ) {
if( !values.isEmpty() )
setListening( false );
this.control = control;
if( !values.isEmpty() )
setListening( true );
}
/**
* Adds or removes all listeners from the {@link CControl}.
* @param listening <code>true</code> if the listeners are to be
* added, <code>false</code> if they have to be removed
*/
private void setListening( boolean listening ){
if( this.control != null ){
if( listening ){
control.addControlListener( listener );
for( int i = 0, n = control.getCDockableCount(); i<n; i++ )
connect( control.getCDockable( i ) );
}
else{
this.control.removeControlListener( listener );
for( int i = 0, n = this.control.getCDockableCount(); i<n; i++ )
disconnect( control.getCDockable( i ) );
}
}
}
public void set( String id, V value, U observer ) {
if( keys.contains( id )){
value = get( value, id, observer );
}
observer.set( value );
}
/**
* Called when a value needs to be set whose key has been registered at
* this {@link UITransmitter}.
* @param value the original value
* @param id the key of the value
* @param observer the destination for the value
* @return the value that should be set to <code>observer</code>
*/
protected abstract V get( V value, String id, U observer );
/**
* Called when a value in an observed map has changed.
* @param dockable the owner of the map
* @param key the name of the changed value
* @param value the new value in the map, can be <code>null</code>
*/
protected abstract void update( CDockable dockable, String key, V value );
/**
* Gets the {@link CDockable} which is associated with <code>observer</code>.
* @param observer some observer
* @return the associated dockable or <code>null</code>
*/
protected abstract CDockable getDockable( U observer );
/**
* Transmits <code>value</code> to all {@link UIValue}s which
* listen to the given id and which are associated with <code>dockable</code>.
* @param id the id of the changed value
* @param value the new value, might be <code>null</code>
* @param dockable the associated dockable, might be <code>null</code>
*/
protected void set( String id, V value, CDockable dockable ){
List<U> list = values.get( id );
if( list != null ){
for( U observer : list ){
if( dockable == getDockable( observer )){
observer.set( value );
}
}
}
}
/**
* Adds a listener to <code>dockable</code> and calls
* {@link #update(CDockable, String, Object)} whenever some value
* needs an update.
* @param dockable the element to observe
*/
protected abstract void connect( CDockable dockable );
/**
* Removes a listener from <code>dockable</code>.
* @param dockable the element from which a listener should be removed
*/
protected abstract void disconnect( CDockable dockable );
/**
* A listener that gets informed when new maps join or some color in a map
* changes.
* @author Benjamin Sigg
*/
private class Listener implements CControlListener{
public void added( CControl control, CDockable dockable ) {
// ignore
}
public void removed( CControl control, CDockable dockable ) {
// ignore
}
public void closed( CControl control, CDockable dockable ) {
disconnect( dockable );
}
public void opened( CControl control, CDockable dockable ) {
connect( dockable );
}
}
}