/* 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. * * */