/* Wotonomy: OpenStep design patterns for pure Java applications. Copyright (C) 2000 Intersect Software Corporation 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, see http://www.gnu.org */ package net.wotonomy.control.internal; import net.wotonomy.control.EOObserverCenter; import net.wotonomy.foundation.NSMutableDictionary; import net.wotonomy.foundation.internal.Introspector; /** * A Surrogate is a special object that can be used in a display * group when you wish to emulate other objects or modify their * behaviors. Because it is a Map, it makes use of Introspector's * ability to treat keys in a map as if they were properties to * implement the following features. * * * @author michael@mpowers.net * @date $Date: 2006-02-18 17:46:44 -0500 (Sat, 18 Feb 2006) $ * @revision $Revision: 900 $ */ public class Surrogate extends NSMutableDictionary { protected Object[] delegates; protected Object defaultValue; /** * Default constructor with no delegate object and no default value. */ public Surrogate() { delegates = null; defaultValue = null; } /** * Constructor specifying a delegate object. */ public Surrogate( Object[] aDelegateArray ) { setDelegates( aDelegateArray ); } /** * Constructor specifying a default value. */ public Surrogate( Object aDefault ) { setDefaultValue( aDefault ); } /** * Constructor specifying a delegate object and a default value. */ public Surrogate( Object[] aDelegateArray, Object aDefault ) { setDelegates( aDelegateArray ); setDefaultValue( aDefault ); } /** * Returns the first delegate object, or null if no delegates exist. */ public Object getDelegate() { if ( delegates == null ) return null; if ( delegates.length == 0 ) return null; return delegates[0]; } /** * Sets the delegate object list to contain only the * specified object. */ public void setDelegate( Object aDelegate ) { setDelegates( new Object[] { aDelegate } ); } /** * Returns the list of delegates in the order in which * they are consulted. */ public Object[] getDelegates() { if ( delegates == null ) delegates = new Object[0]; return delegates; } /** * Sets the list of delegates in the order in which they * will be consulted. */ public void setDelegates( Object[] aDelegateArray ) { delegates = aDelegateArray; } /** * Returns the current default value, or null if no default exists. */ public Object getDefaultValue() { return defaultValue; } /** * Sets the default value. */ public void setDefaultValue( Object aDefault ) { defaultValue = aDefault; } /** * Called by get to retrieve a value from the internal map. * This implementation simply calls super.get(). */ public Object directGet( Object aKey ) { return super.get( aKey ); } /** * Called by put to retrieve a value from the internal map. * This implementation simply calls super.put(). */ public Object directPut( Object aKey, Object aValue ) { return super.put( aKey, aValue ); } /** * Overridden to consult each delegate before * checking the internal list of keys. No matching * key is found, returns the default object, or * null if no default object exists. */ public Object get( Object aKey ) { // check all delegates in order int i, j; Object[] list = getDelegates(); String[] properties; for ( i = 0; i < list.length; i++ ) { // for each delegate properties = Introspector.getReadPropertiesForObject( list[i] ); for ( j = 0; j < properties.length; j++ ) { // if delegate has property if ( properties[j].equals( aKey ) ) { // use this delegate return Introspector.get( list[i], aKey.toString() ); } } } // return from internal map Object result = directGet( aKey ); if ( result == null ) { // if not in map, return default object result = getDefaultValue(); } return result; } /** * Overridden to attempt to write each delegate, writing to * only the first successful delegate, before storing the * value in the internal map. */ public Object put( Object aKey, Object aValue ) { // check all delegates in order int i, j; Object[] list = getDelegates(); String[] properties; for ( i = 0; i < list.length; i++ ) { // for each delegate properties = Introspector.getWritePropertiesForObject( list[i] ); for ( j = 0; j < properties.length; j++ ) { // if delegate has property if ( properties[j].equals( aKey ) ) { // use this delegate EOObserverCenter.notifyObserversObjectWillChange( list[i] ); return Introspector.set( list[i], aKey.toString(), aValue ); } } } // set on internal map EOObserverCenter.notifyObserversObjectWillChange( this ); return directPut( aKey, aValue ); } /** * Overridden to compare by reference. */ public boolean equals( Object anObject ) { return ( this == anObject ); } } /* * $Log$ * Revision 1.1 2006/02/18 22:46:44 cgruber * Add Surrogate map from .util into control's internal package, and fix imports. * * Revision 1.1 2006/02/16 13:22:22 cgruber * Check in all sources in eclipse-friendly maven-enabled packages. * * Revision 1.1.1.1 2000/12/21 15:52:21 mpowers * Contributing wotonomy. * * Revision 1.2 2000/12/20 16:25:48 michael * Added log to all files. * * */