/*
* 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.facile.action;
import java.util.Iterator;
import bibliothek.gui.dock.action.AbstractDockActionSource;
import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.LocationHint;
import bibliothek.gui.dock.common.action.CAction;
import bibliothek.gui.dock.common.event.CDockableAdapter;
import bibliothek.gui.dock.common.event.CDockablePropertyListener;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.event.DockActionSourceListener;
import bibliothek.util.FrameworkOnly;
/**
* An action source using {@link CDockable#getAction(String)} to determine which
* action to use. If <code>getAction</code> returns <code>null</code>, then
* a default action can be used. This action source also allows to disable any
* action.
* @author Benjamin Sigg
*/
@FrameworkOnly
public class KeyedActionSource extends AbstractDockActionSource {
/** the observed element */
private CDockable dockable;
/** the key of the action to handle */
private String key;
/** the default action to be used if {@link CDockable#getAction(String)} returns <code>null</code> */
private DockAction defaultAction;
/** the location of this source */
private LocationHint hint = LocationHint.UNKNOWN;
/** whether to show an action at all or not */
private boolean visible = true;
/** whether {@link #propertyListener} is added to {@link #dockable} */
private boolean propertyListenerInstalled = false;
/** a listener observing {@link #dockable} */
private CDockablePropertyListener propertyListener = new CDockableAdapter(){
public void actionChanged( CDockable dockable, String key, CAction oldAction, CAction newAction ){
if( visible ){
boolean shown = (oldAction != null) || (defaultAction != null);
boolean showing = (newAction != null) || (defaultAction != null);
if( shown && !showing )
fireRemoved( 0, 0 );
else if( !shown && showing )
fireAdded( 0, 0 );
else if( shown && showing ){
visible = false;
fireRemoved( 0, 0 );
visible = true;
fireAdded( 0, 0 );
}
}
}
};
/**
* Creates a new action source
* @param dockable the element for which this source is used
* @param key the key for calling {@link CDockable#getAction(String)}
*/
public KeyedActionSource( CDockable dockable, String key ){
if( dockable == null )
throw new IllegalArgumentException( "dockable must not be null" );
if( key == null )
throw new IllegalArgumentException( "key must not be null" );
this.dockable = dockable;
this.key = key;
}
/**
* Gets the key which is used for calling {@link CDockable#getAction(String)}
* @return the key, not <code>null</code>
*/
public String getKey(){
return key;
}
@Override
public void addDockActionSourceListener( DockActionSourceListener listener ){
super.addDockActionSourceListener( listener );
if( visible && !propertyListenerInstalled && !listeners.isEmpty() ){
dockable.addCDockablePropertyListener( propertyListener );
propertyListenerInstalled = true;
}
}
@Override
public void removeDockActionSourceListener( DockActionSourceListener listener ){
super.removeDockActionSourceListener( listener );
if( visible && propertyListenerInstalled && listeners.isEmpty() ){
dockable.removeCDockablePropertyListener( propertyListener );
propertyListenerInstalled = false;
}
}
/**
* Detaches the listeners this {@link DockActionSource} added to
* other objects.
*/
public void destroy(){
if( propertyListenerInstalled ){
dockable.removeCDockablePropertyListener( propertyListener );
propertyListenerInstalled = false;
}
}
/**
* Changes whether any actions are shown or not.
* @param visible the new state
*/
public void setVisible( boolean visible ){
if( this.visible != visible ){
int current = getDockActionCount();
this.visible = visible;
if( visible ){
if( !propertyListenerInstalled && !listeners.isEmpty() ){
dockable.addCDockablePropertyListener( propertyListener );
propertyListenerInstalled = true;
}
}
else{
if( propertyListenerInstalled ){
dockable.removeCDockablePropertyListener( propertyListener );
propertyListenerInstalled = false;
}
}
int updated = getDockActionCount();
if( current < updated )
fireAdded( 0, 0 );
else if( current > updated )
fireRemoved( 0, 0 );
}
}
/**
* Sets the default action of this source. The default action
* is used if {@link CDockable#getAction(String)} returns
* <code>null</code>.
* @param defaultAction the default action, may be <code>null</code>
*/
public void setDefaultAction( DockAction defaultAction ){
if( visible ){
if( dockable.getAction( key ) == null ){
visible = false;
fireRemoved( 0, 0 );
this.defaultAction = defaultAction;
visible = true;
fireAdded( 1, 1 );
}
else{
this.defaultAction = defaultAction;
}
}
else{
this.defaultAction = defaultAction;
}
}
/**
* Gets the default action of this source.
* @return the default action, can be <code>null</code>
*/
public DockAction getDefaultAction(){
return defaultAction;
}
/**
* Gets the action that is currently to be shown.
* @return the current action or <code>null</code> if invisible or not available.
*/
private DockAction currentAction(){
if( !visible )
return null;
CAction result = dockable.getAction( key );
if( result == null ){
return defaultAction;
}
return result.intern();
}
public DockAction getDockAction( int index ){
if( index != 0 )
throw new IllegalArgumentException( "only index=0 supported" );
return currentAction();
}
public int getDockActionCount(){
if( currentAction() != null )
return 1;
else
return 0;
}
public LocationHint getLocationHint(){
return hint;
}
public Iterator<DockAction> iterator(){
return new Iterator<DockAction>(){
private DockAction action = currentAction();
public boolean hasNext(){
return action != null;
}
public DockAction next(){
if( action == null )
throw new IllegalStateException( "no elements left" );
DockAction result = action;
action = null;
return result;
}
public void remove(){
throw new UnsupportedOperationException();
}
};
}
}