All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bibliothek.gui.dock.disable.ActionDisablingStrategyObserver Maven / Gradle / Ivy

/*
 * 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) 2012 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
 * [email protected]
 * CH - Switzerland
 */
package bibliothek.gui.dock.disable;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import bibliothek.gui.DockController;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DockElement;
import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.event.DockHierarchyEvent;
import bibliothek.gui.dock.event.DockHierarchyListener;
import bibliothek.gui.dock.util.PropertyValue;

/**
 * This class offers a convenient way to connect a {@link DockAction} with the current
 * {@link DisablingStrategy}. It only requires the {@link DockAction} to call {@link #bind(Dockable)}
 * and {@link #unbind(Dockable)} in order to observe a {@link Dockable}.  
 * @author Benjamin Sigg
 */
public abstract class ActionDisablingStrategyObserver {
	private DockAction action;

	/** all the observers that are currently monitoring {@link Dockable}s to find {@link DockController}s */
	private Map dockables = new HashMap();

	/** all the observers that are currently monitoring {@link DockController}s. */
	/* This might be a little overkill, but it's the way to ensure correctness in even the strangest settings */
	private Map controllers = new HashMap( 1 );
	
	/**
	 * Creates a new observer.
	 * @param action the action whose disabled state will be monitored.
	 */
	public ActionDisablingStrategyObserver( DockAction action ){
		if( action == null ){
			throw new IllegalArgumentException( "action must not be null" );
		}
		this.action = action;
	}
	
	/**
	 * Must be called to inform this observer that dockable is to be observed. Can be
	 * called multiple times.
	 * @param dockable the item to observe
	 */
	public void bind( Dockable dockable ){
		DockableObserver observer = dockables.get( dockable );
		if( observer == null ){
			observer = new DockableObserver( dockable );
			dockables.put( dockable, observer );
		}
		observer.inc();
	}
	
	/**
	 * Must be called to inform this observer that dockable is no longer to be observed. 
	 * Can be called multiple times.
	 * @param dockable the item to observe
	 */
	public void unbind( Dockable dockable ){
		DockableObserver observer = dockables.get( dockable );
		if( observer != null ){
			observer.dec();
			if( observer.destroy() ){
				dockables.remove( dockable );
			}
		}
	}
	
	private void set( DockController oldController, DockController newController, Dockable dockable ){
		if( oldController != newController ){
			if( oldController != null ){
				ControllerObserver observer = controllers.get( oldController );
				observer.remove( dockable );
				if( observer.destroy() ){
					controllers.remove( oldController );
				}
			}
			if( newController != null ){
				ControllerObserver observer = controllers.get( newController );
				if( observer == null ){
					observer = new ControllerObserver( newController );
					controllers.put( newController, observer );
				}
				observer.add( dockable );
			}
		}
	}
	
	/**
	 * Called if the disabled state of the action changed.
	 * @param dockable the dockable for which the state changed
	 * @param disabled the new state
	 */
	protected abstract void setDisabled( Dockable dockable, boolean disabled );
	
	/**
	 * Called if an entire set of {@link Dockable}s changed their state.
	 * @param dockable the items that changed their state
	 * @param disabled the new state
	 */
	protected abstract void setDisabled( Set dockable, boolean disabled );
	
	/**
	 * Tells whether the action of dockable is disabled.
	 * @param dockable the element whose action state is searched
	 * @return true if the action is disabled, false otherwise
	 */
	public boolean isDisabled( Dockable dockable ){
		DockController controller = dockable.getController();
		if( controller != null ){
			ControllerObserver observer = controllers.get( controller );
			if( observer != null ){
				return observer.isDisabled( dockable );
			}
		}
		return false;
	}
	
	/**
	 * Observes a single {@link Dockable} to find its current {@link DockController}.
	 * @author Benjamin Sigg
	 */
	private class DockableObserver implements DockHierarchyListener{
		private Dockable dockable;
		private DockController controller;
		private int count = 0;
		
		public DockableObserver( Dockable dockable ){
			this.dockable = dockable;
			dockable.addDockHierarchyListener( this );
			DockController controller = dockable.getController();
			if( controller != null ){
				bind( controller );
			}
		}
		
		private void bind( DockController controller ){
			set( this.controller, controller, dockable );
			this.controller = controller;
		}
		
		public void inc(){
			count++;
		}
		
		public void dec(){
			count--;
		}
		
		public boolean destroy(){
			if( count <= 0 ){
				dockable.removeDockHierarchyListener( this );
				bind( null );
				return true;
			}
			return false;
		}
		
		public void controllerChanged( DockHierarchyEvent event ){
			bind( dockable.getController() );
		}
		
		public void hierarchyChanged( DockHierarchyEvent event ){
			// ignore	
		}
	}
	
	/**
	 * Observers a {@link DockController} to find its current {@link DisablingStrategy} and uses
	 * the strategy to get the state of several {@link Dockable}s.
	 * @author Benjamin Sigg
	 */
	private class ControllerObserver extends PropertyValue implements DisablingStrategyListener{
		private Set dockables = new HashSet();
		
		public ControllerObserver( DockController controller ){
			super( DisablingStrategy.STRATEGY );
			setProperties( controller );
		}
		
		@Override
		protected void valueChanged( DisablingStrategy oldValue, DisablingStrategy newValue ){
			if( oldValue != null ){
				oldValue.removeDisablingStrategyListener( this );
			}
			if( newValue != null ){
				newValue.addDisablingStrategyListener( this );
				
				Set enabled = new HashSet();
				Set disabled = new HashSet();
				
				for( Dockable item : dockables ){
					if( newValue.isDisabled( item, action )){
						disabled.add( item );
					}
					else{
						enabled.add( item );
					}
				}
				
				if( !enabled.isEmpty() ){
					setDisabled( enabled, false );
				}
				if( !disabled.isEmpty() ){
					setDisabled( disabled, false );
				}
			}
			else{
				setDisabled(  dockables, false );
			}
		}
		
		public void changed( DockElement item ){
			Dockable dockable = item.asDockable();
			if( dockable != null && dockables.contains( dockable )){
				setDisabled( dockable, getValue().isDisabled( dockable, action ) );
			}
		}
		
		public boolean isDisabled( Dockable dockable ){
			DisablingStrategy strategy = getValue();
			if( strategy != null ){
				return strategy.isDisabled( dockable, action );
			}
			return false;
		}
		
		public void add( Dockable dockable ){
			DisablingStrategy strategy = getValue();
			if( strategy != null ){
				setDisabled( dockable, strategy.isDisabled( dockable, action ) );
			}
			dockables.add( dockable );
		}
		
		public void remove( Dockable dockable ){
			setDisabled( dockable, false );
			dockables.remove( dockable );
		}
		
		public boolean destroy(){
			if( dockables.isEmpty() ){
				setProperties( (DockController)null );
				return true;
			}
			return false;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy