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

bibliothek.gui.dock.util.DockProperties Maven / Gradle / Ivy

The newest version!
/*
 * 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
 * [email protected]
 * CH - Switzerland
 */

package bibliothek.gui.dock.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import bibliothek.gui.DockController;

/**
 * A set of properties that are used at different places all over the framework.
 * The map uses a {@link Priority} based system, allowing clients to override
 * behavior of themes or set default values in case a theme does not set one.
 * @author Benjamin Sigg
 */
public class DockProperties {
	/** the map of values */
	private Map, Entry> map = new HashMap, Entry>();

	/** the owner of this map */
	private DockController controller;
	
	/**
	 * Creates a new map.
	 * @param controller the owner of this map
	 */
	public DockProperties( DockController controller ){
		if( controller == null ){
			throw new IllegalArgumentException( "controller must not be null" );
		}
		this.controller = controller;
	}
	
	/**
	 * Gets the owner of this {@link DockProperties}.
	 * @return the owner, not null
	 */
	public DockController getController(){
		return controller;
	}
	
	/**
	 * Sets a value. This is equivalent to calling set( key, value, Priority.CLIENT ).
	 * @param  the type of the value
	 * @param key the key to access the value
	 * @param value the value, can be null
	 */
	public  void set( PropertyKey key, A value ){
		set( key, value, Priority.CLIENT );
	}
	
	/**
	 * Sets a value.
	 * @param  the type of the value
	 * @param key the key to access the value
	 * @param value the value, can be null
	 * @param priority the priority of the new value
	 */
	public  void set( PropertyKey key, A value, Priority priority ){
		Entry entry = getEntry( key, true );
		entry.setValue( value, priority );
		check( entry );
	}
	
	/**
	 * Ensures that the value behind key will never be
	 * changed. Should be used with care: any attempt to set the value afterwards
	 * will be responded with an {@link IllegalStateException}. Most times it
	 * is much better to just use {@link Priority#CLIENT} to mark some setting
	 * as important.
	 * @param  the type of the value
	 * @param key the key to protect
	 */
	public  void finalize( PropertyKey key ){
		Entry entry = getEntry( key, true );
		entry.lock();
	}
	
	/**
	 * Either sets the property key to value or
	 * set the default value for key.
	 * @param  the type of the value
	 * @param key the key to access the value
	 * @param value the new value, if null then the default
	 * value will be set
	 * @param priority the priority of the value to remove
	 */
	public  void setOrRemove( PropertyKey key, A value, Priority priority ){
		if( value == null )
			unset( key, priority );
		else
			set( key, value, priority );
	}
	
	/**
	 * Tells the entry key that the user has never set its value.
	 * This is equivalent to calling unset( key, Priority.CLIENT ).
	 * @param key the key to access the entry
	 */
	public void unset( PropertyKey key ){
		unset( key, Priority.CLIENT );
	}
	
	/**
	 * Tells the entry key that the user has never set its value.
	 * Also removes the old value of the entry.
	 * @param key the key to access the entry
	 * @param priority the priority for which to remove the value
	 */
	public void unset( PropertyKey key, Priority priority ){
	    Entry entry = getEntry( key, true );
	    entry.unsetValue( priority );
        check( entry );
	}
	
	/**
	 * Gets the value accessed by key. If the value in the
	 * properties is not set, then the {@link PropertyKey#getDefault(DockProperties) default}
	 * value is returned.
	 * @param  the type of the value
	 * @param key the key to search
	 * @return the value or null
	 */
	public  A get( PropertyKey key ){
		Entry entry = getEntry( key, true );
		return entry.getValue();
	}
	
	/**
	 * Gets the value of key for the given priority.
	 * @param  the kind of value
	 * @param key some key, not null
	 * @param priority the priority, not null
	 * @return the value, might be null even if {@link #get(PropertyKey)}
	 * returns a non-null value
	 */
	public  A get( PropertyKey key, Priority priority ){
		Entry entry = getEntry( key, false );
		if( entry == null )
			return null;
		return entry.getValue( priority );
	}
	
	/**
	 * Tells whether there is value set for key with priority. 
	 * @param  the kind of value
	 * @param key the key to check
	 * @param priority the priority for which something might be set
	 * @return true if there is a value set
	 */
	public  boolean isSet( PropertyKey key, Priority priority ){
	    Entry entry = getEntry( key, false );
	    if( entry == null )
	        return false;

	    return entry.value.isSet( priority );
	}
	
	/**
	 * Tells whether there is value set for key.
	 * @param  the kind of value
	 * @param key the key to check
	 * @return true if there is a value set
	 */
	public  boolean isSet( PropertyKey key ){
	    Entry entry = getEntry( key, false );
	    if( entry == null )
	        return false;

	    return entry.value.isSomethingSet();
	}
	
	
	
	/**
	 * Adds a listener that will be informed whenever the value accessed
	 * through key changes.
	 * @param  the type of the value
	 * @param key the key that accesses the value
	 * @param listener the new listener
	 */
	public  void addListener( PropertyKey key, DockPropertyListener listener ){
		if( listener == null )
			throw new IllegalArgumentException( "Listener must not be null" );
		getEntry( key, true ).addListener( listener );
	}
	
	/**
	 * Removes an earlier added listener.
	 * @param  the type of value observed by the listener
	 * @param key the key to access the observed entry
	 * @param listener the listener to remove
	 */
	public  void removeListener( PropertyKey key, DockPropertyListener listener ){
		Entry entry = getEntry( key, false );
		if( entry != null ){
			entry.removeListener( listener );
			check( entry );
		}
	}
	
	/**
	 * Gets the entry for key.
	 * @param  the type of the entry
	 * @param key the name of the entry
	 * @param createIfNull true if null is not a valid 
	 * result. 
	 * @return the entry or null, but only if createIfNull
	 * is false
	 */
	@SuppressWarnings( "unchecked" )
	private  Entry getEntry( PropertyKey key, boolean createIfNull ){
		Entry entry = map.get( key );
		if( entry == null && createIfNull ){
			entry = new Entry( key );
			map.put( key, entry );
		}
		return (Entry)entry;
	}
	
	/**
	 * Checks whether entry has to be stored any longer.
	 * @param entry the entry that may be deleted
	 */
	private void check( Entry entry ){
		if( entry.removeable() ){
			map.remove( entry.getKey() );
		}
	}
	
	/**
	 * An entry that contains key, listeners and a value.
	 * @author Benjamin Sigg
	 *
	 * @param  the type of the value
	 */
	private class Entry{
		/** the name of this entry */
		private PropertyKey key;
		/** listeners to this entry */
		private List> listeners = new ArrayList>();
		/** the value stored in this entry */
		private NullPriorityValue value = new NullPriorityValue();
		
		/** default value of this entry */
		private A defaultValue;
		/** whether the default value was ever needed and has been set */
		private boolean defaultValueSet = false;

		/** whether changes of this entry are allowed */
		private boolean locked = false;
		
		/**
		 * Creates a new entry.
		 * @param key the name of this entry
		 */
		public Entry( PropertyKey key ){
		    this.key = key;
		}
		
		/**
		 * If called makes this entry immutable.
		 */
		public void lock(){
			locked = true;
		}
		
		/**
		 * Sets the new value of this entry.
		 * @param value the new value
		 * @param priority the priority of the new value
		 */
		@SuppressWarnings( "unchecked" )
		public void setValue( A value, Priority priority ){
			if( locked ){
				throw new IllegalStateException( "this entry is immutable" );
			}
			
			A oldValue = getValue();
			this.value.set( priority, value );
			A newValue = getValue();
			
			if( (oldValue == null && newValue != null) ||
				(oldValue != null && newValue == null) ||
				(oldValue != null && !oldValue.equals( newValue ))){
			
				for( DockPropertyListener listener : (DockPropertyListener[])listeners.toArray( new DockPropertyListener[ listeners.size() ] ))
					listener.propertyChanged( DockProperties.this, key, oldValue, newValue );
			}
		}
		
		/**
		 * Removes a value from this entry
		 * @param priority the priority of the value to unset
		 */
		@SuppressWarnings("unchecked")
		public void unsetValue( Priority priority ){
			if( locked ){
				throw new IllegalStateException( "this entry is immutable" );
			}
			
			A oldValue = getValue();
			this.value.unset( priority );
			A newValue = getValue();
			
			if( (oldValue == null && newValue != null) ||
				(oldValue != null && newValue == null) ||
				(oldValue != null && !oldValue.equals( newValue ))){
			
				for( DockPropertyListener listener : (DockPropertyListener[])listeners.toArray( new DockPropertyListener[ listeners.size() ] ))
					listener.propertyChanged( DockProperties.this, key, oldValue, newValue );
			}
		}
		
		/**
		 * Gets the value of this entry.
		 * @return the value
		 */
		public A getValue(){
			A value = this.value.get();
			
			if( value == null && (!this.value.isSomethingSet() || key.isNullValueReplacedByDefault()) ){
				return getDefault();
			}
			return value;
		}
		
		/**
		 * Gets the value stored for priority.
		 * @param priority the priority, not null
		 * @return the value, might be null
		 */
		public A getValue( Priority priority ){
			return value.get( priority );
		}
		
		/**
		 * Gets the default value of this property.
		 * @return the default value, may be null
		 */
		public A getDefault(){
			if( !defaultValueSet ){
				defaultValue = key.getDefault( DockProperties.this );
				defaultValueSet = true;
			}
			return defaultValue;
		}
		
		/**
		 * Gets the name of this entry.
		 * @return the name
		 */
		public PropertyKey getKey(){
			return key;
		}
		
		/**
		 * Adds a new listener to this entry.
		 * @param listener the new listener
		 */
		public void addListener( DockPropertyListener listener ){
			listeners.add( listener );
		}
		
		/**
		 * Removes a listener from this entry.
		 * @param listener the listener to remove
		 */
		public void removeListener( DockPropertyListener listener ){
			listeners.remove( listener );
		}
		
		/**
		 * Tells whether this entry is needed any longer or not.
		 * @return true if this entry can be deleted safely.
		 */
		public boolean removeable(){
			if( locked )
				return false;
			
			if( !listeners.isEmpty() )
				return false;
			
			if( defaultValueSet || value.isSomethingSet() )
				return false;
			
			return true;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy