package er.extensions.woextensions; import com.webobjects.appserver.WOContext; import com.webobjects.eocontrol.EOEnterpriseObject; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSKeyValueCoding; import com.webobjects.foundation.NSKeyValueCodingAdditions; import com.webobjects.foundation.NSMutableArray; import er.extensions.components.ERXArrayChooser; import er.extensions.eof.ERXEOControlUtilities; /** * Back port from WO 5 WOExtensions. This component is binding compatible, but not source compatible. * <p> * It can also handle non-relationships, you must set the possibleChoices to an NSArray and * relationshipName to a property name. It works whether the object is an EO or not. The name could/should probably * change because it handles not only relationships, but it was wrongly named n the first place... */ public class WOToManyRelationship extends ERXArrayChooser { /** * Do I need to update serialVersionUID? * See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the * <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a> */ private static final long serialVersionUID = 1L; protected NSArray _selections; public WOToManyRelationship(WOContext aContext) { super(aContext); } @Override public void reset() { super.reset(); _selections = null; } public void updateSourceObject(NSArray newValues) { Object realSourceObject = realSourceObject(); String realRelationshipKey = realRelationshipKey(); newValues = newValues != null ? newValues : NSArray.EmptyArray; if (realSourceObject instanceof EOEnterpriseObject && // only add/remove if we have an EO and handle a relationship ((EOEnterpriseObject) realSourceObject).classDescriptionForDestinationKey(realRelationshipKey) != null) { EOEnterpriseObject eo = (EOEnterpriseObject) realSourceObject; NSArray currentValues = (NSArray) eo.valueForKey(realRelationshipKey); currentValues = currentValues != null ? currentValues : NSArray.EmptyArray; for (int i = currentValues.count() - 1; i >= 0; i--) { EOEnterpriseObject o = (EOEnterpriseObject) currentValues.objectAtIndex(i); if (newValues.indexOfIdenticalObject(o) == NSArray.NotFound) { // not found eo.removeObjectFromBothSidesOfRelationshipWithKey(o, realRelationshipKey); } } for (int i = newValues.count() - 1; i >= 0; i--) { EOEnterpriseObject o = (EOEnterpriseObject) newValues.objectAtIndex(i); if (currentValues.indexOfIdenticalObject(o) == NSArray.NotFound) { // not found eo.addObjectToBothSidesOfRelationshipWithKey(o, realRelationshipKey); } } } else { // NOTE ak: this implementation is different from what JavaWOExtensions do. // There, the existing array is fetched and added to/removed from. Here, we simply set the // new array. I changed this because it looked like a bad idea to change the array without // the sourceObjects's knowledge. NSKeyValueCoding.Utility.takeValueForKey(realSourceObject, (newValues instanceof NSMutableArray) ? newValues : newValues.mutableClone(), realRelationshipKey); } } public void setSelections(NSArray selections) { // set selections to nil if it's an empty array if ((selections == null) || (selections.count() == 0)) { // deal with isMandatory if (isMandatory() && (theList().count() > 0)) { Object anObject = theList().objectAtIndex(0); selections = new NSArray(anObject); } else { selections = null; } } _selections = selections; updateSourceObject(selections); } @Override public NSArray currentValues() { NSArray current = selections(); return current == null ? NSArray.EmptyArray : current; } public NSArray selections() { if (_selections == null) { NSArray oldValues = (NSArray) NSKeyValueCodingAdditions.Utility.valueForKeyPath(sourceObject(), relationshipKey()); if(oldValues != null) { if(oldValues.lastObject() instanceof EOEnterpriseObject) { oldValues = ERXEOControlUtilities.localInstancesOfObjects(editingContext(), oldValues); } } setSelections(oldValues); // deal with isMandatory if ((_selections == null) && isMandatory()) { if (theList().count() > 0) { Object anObject = theList().objectAtIndex(0); setSelections(new NSArray(anObject)); } } } return _selections; } @Override protected boolean isSingleSelection() { return false; } }