From aedc34d55462a75e329bbf342251ff6504cd117e Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Sun, 19 May 2024 17:56:33 -0400 Subject: Initial import from SVN --- .../java/net/wotonomy/ui/GenericAssociation.java | 373 +++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java (limited to 'projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java') diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java new file mode 100644 index 0000000..3a4ff08 --- /dev/null +++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/GenericAssociation.java @@ -0,0 +1,373 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2001 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.ui; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import net.wotonomy.control.EOKeyValueCoding; +import net.wotonomy.control.EOKeyValueCodingSupport; +import net.wotonomy.control.EOObserverCenter; +import net.wotonomy.foundation.NSArray; + +/** +* GenericAssociation binds one or more properties on an +* observable object to a display group. The controlled +* object is expected to use the ObserverCenter and will +* be observed by this association.

+* +* Bindings for this association are generic: the +* name of the aspect will be treated as a property key +* on the displayed object(s) and synchronized with the +* bound property on the controlled object.

+* +* NOTE: because we cannot assume that the controlled +* object will retain a reference to this association, +* you must explicitly retain a reference to prevent +* the association from getting garbage collected. +* +* @author michael@mpowers.net +* @author $Author: cgruber $ +* @version $Revision: 904 $ +*/ +public class GenericAssociation extends EOAssociation +{ + protected boolean objectModified; + protected Set aspectsModified; + + static final NSArray aspects = + new NSArray( new Object[] { + } ); + static final NSArray aspectSignatures = + new NSArray( new Object[] { + } ); + static final NSArray objectKeysTaken = + new NSArray( new Object[] { + } ); + + /** + * Constructor specifying the object to be controlled by this + * association. Does not establish connection. + */ + public GenericAssociation ( Object anObject ) + { + super( anObject ); + objectModified = false; + aspectsModified = new HashSet(); + } + + /** + * Returns a List of aspect signatures whose contents + * correspond with the aspects list. Each element is + * a string whose characters represent a capability of + * the corresponding aspect. + * An empty signature "" means that the aspect can + * bind without needing a key. + * This implementation returns "A1M" for each + * element in the aspects array. + */ + public static NSArray aspectSignatures () + { + return aspectSignatures; + } + + /** + * Returns a List that describes the aspects supported + * by this class. Each element in the list is the string + * name of the aspect. This implementation returns an + * empty list. + */ + public static NSArray aspects () + { + return aspects; + } + + /** + * Returns a List of EOAssociation subclasses that, + * for the objects that are usable for this association, + * are less suitable than this association. + */ + public static NSArray associationClassesSuperseded () + { + return new NSArray(); + } + + /** + * Returns whether this class can control the specified + * object. + */ + public static boolean isUsableWithObject ( Object anObject ) + { + return true; + } + + /** + * Returns a List of properties of the controlled object + * that are controlled by this class. For example, + * "stringValue", or "selected". + */ + public static NSArray objectKeysTaken () + { + return objectKeysTaken; + } + + /** + * Returns the aspect that is considered primary + * or default. This is typically "value" or somesuch. + */ + public static String primaryAspect () + { + return ""; + } + + /** + * Returns whether this association can bind to the + * specified display group on the specified key for + * the specified aspect. + */ + public boolean canBindAspect ( + String anAspect, EODisplayGroup aDisplayGroup, String aKey) + { + return true; + } + + /** + * Establishes a connection between this association + * and the controlled object. This implementation + * registers with ObserverCenter for change notifications + * from the controlled object. + */ + public void establishConnection () + { + EOObserverCenter.addObserver( this, object() ); + super.establishConnection(); + + // forces update from bindings + subjectChanged(); + } + + /** + * Breaks the connection between this association and + * its object. Override to stop listening for events + * from the object. + */ + public void breakConnection () + { + EOObserverCenter.removeObserver( this, object() ); + super.breakConnection(); + } + + /** + * Overridden to track which observed object is changing. + */ + public void objectWillChange( Object anObject ) + { + if ( object() == anObject ) + { + objectModified = true; + } + else + { + aspectsModified.add( aspectToGroup.allKeysForObject( anObject ) ); + } + } + + /** + * Called when either the selection or the contents + * of an associated display group have changed. + */ + public void subjectChanged () + { + String aspect; + String key; + Object value; + EODisplayGroup displayGroup; + Iterator iterator; + + iterator = aspectsModified.iterator(); + while ( iterator.hasNext() ) + { + aspect = (String) iterator.next(); + key = displayGroupKeyForAspect( aspect ); + displayGroup = displayGroupForAspect( aspect ); + + value = readValueFromDisplayGroupForKey( displayGroup, key ); + writeValueForKey( object(), value, key ); + } + aspectsModified.clear(); + + if ( objectModified ) + { + iterator = aspectToGroup.keySet().iterator(); + while ( iterator.hasNext() ) + { + aspect = (String) iterator.next(); + key = displayGroupKeyForAspect( aspect ); + value = readValueForKey( object(), key ); + displayGroup = displayGroupForAspect( aspect ); + displayGroup.setSelectedObjectValue( value, key ); + } + } + } + + protected Object readValueForKey( Object object, String key ) + { + if ( object instanceof EOKeyValueCoding ) + { + return ((EOKeyValueCoding)object).valueForKey( key ); + } + return EOKeyValueCodingSupport.valueForKey( object, key ); + } + + protected void writeValueForKey( Object object, Object value, String key ) + { + if ( object instanceof EOKeyValueCoding ) + { + ((EOKeyValueCoding)object).takeValueForKey( value, key ); + } + else + { + EOKeyValueCodingSupport.takeValueForKey( object, value, key ); + } + } + + protected Object readValueFromDisplayGroupForKey( + EODisplayGroup displayGroup, String key ) + { + Object value; + + if ( displayGroup.selectedObjects().size() > 1 ) + { + // if there're more than one object selected, set + // the value to blank for all of them. + Object previousValue; + + Iterator indexIterator = displayGroup.selectionIndexes(). + iterator(); + + // get value for the first selected object. + int initialIndex = ( (Integer)indexIterator.next() ).intValue(); + previousValue = displayGroup.valueForObjectAtIndex( + initialIndex, key ); + value = null; + + // go through the rest of the selected objects, compare each + // value with the previous one. continue comparing if two + // values are equal, break the while loop if they're different. + // the final value will be the common value of all selected objects + // if there is one, or be blank if there is not. + while ( indexIterator.hasNext() ) + { + int index = ( (Integer)indexIterator.next() ).intValue(); + Object currentValue = displayGroup.valueForObjectAtIndex( + index, key ); + if ( currentValue != null && !currentValue.equals( previousValue ) ) + { + value = null; + break; + } + else + { + // currentValue is the same as the previous one + value = currentValue; + } + + } // end while + + } else { + + value = displayGroup.selectedObjectValueForKey( key ); + } // end checking size of displayGroup + + return value; + } + + /** + * Writes the value currently in the component + * to the selected object in the display group + * bound to the value aspect. + * @return false if there were problems validating, + * or true to continue. + */ + protected boolean writeValueForAspect( Object value, String aspect ) + { + EODisplayGroup displayGroup = + displayGroupForAspect( aspect ); + if ( displayGroup != null ) + { + String key = displayGroupKeyForAspect( aspect ); + + boolean returnValue = true; + Iterator selectedIterator = displayGroup.selectionIndexes().iterator(); + while ( selectedIterator.hasNext() ) + { + int index = ( (Integer)selectedIterator.next() ).intValue(); + + if ( !displayGroup.setValueForObjectAtIndex( value, index, key ) ) + { + returnValue = false; + } + } + return returnValue; + } + return false; + } + + /** + * Forces this association to cause the object to + * stop editing and validate the user's input. + * @return false if there were problems validating, + * or true to continue. + */ + public boolean endEditing () + { + return false; +//! return writeValueToDisplayGroup(); + } + +} + +/* + * $Log$ + * Revision 1.2 2006/02/18 23:14:35 cgruber + * Update imports and maven dependencies. + * + * Revision 1.1 2006/02/16 13:22:22 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.3 2003/08/06 23:07:52 chochos + * general code cleanup (mostly, removing unused imports) + * + * Revision 1.2 2001/11/08 19:51:24 mpowers + * Draft implementation. + * + * Revision 1.1 2001/11/02 23:15:04 mpowers + * Contributing "generic association". + * + * + */ + -- cgit v1.2.3