package er.directtoweb.components.relationships;
import java.util.Enumeration;
import org.apache.log4j.Logger;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSValidation;
import er.directtoweb.components.ERDCustomEditComponent;
import er.extensions.eof.ERXEOControlUtilities;
import er.extensions.foundation.ERXStringUtilities;
/**
* Convenient way to add, edit, remove or delete objects from a to-many relationship.
* Best used for owned relationships with not much info in them.
* <p>
* Displays a list of edit configurations, one for each related object, along
* with a check box that handles the selection for the Delete and Remove buttons.
* If the keypath is not directly off the root object, then the last part will be
* selected as the relationship. Meaning you can edit a customer and have the keypath
* being <code>lastPurchase.items</code>
* <p>
* A know bug is when you add object and have validation failures, the failure display may
* end up with the wrong object.
*
* @binding object eo to edit
* @binding key keypath to the relationship
* @binding destinationEntityName entity name for the destination of the relationship
* @binding hasRemove true if the objects can also be removed (as opposed to just being deleted)
* @binding inspectConfigurationName page configuration to use for the edit component
* @binding task should be "edit"
*/
public class ERDEditToManyRelationship extends ERDCustomEditComponent {
/**
* 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;
/** logging support */
private static final Logger log = Logger.getLogger(ERDEditToManyRelationship.class);
public int index;
public int objectsToAdd = 1;
public EOEnterpriseObject currentObject;
protected NSMutableArray selectedObjects;
/**
* Public constructor.
* @param context the context
*/
public ERDEditToManyRelationship(WOContext context) {
super(context);
}
public String relationshipName() {
return ERXStringUtilities.lastPropertyKeyInKeyPath(key());
}
public String destinationEntityName() {
return (String)valueForBinding("destinationEntityName");
}
public String pageConfiguration() {
return (String)valueForBinding("inspectConfigurationName");
}
@Override
public String task() {
return (String)valueForBinding("task");
}
public boolean isEditing() {
return "edit".equals(task());
}
public NSArray objects() {
return (NSArray) objectKeyPathValue();
}
private EOEnterpriseObject relationshipObject() {
EOEnterpriseObject object = object();
if(!relationshipName().equals(key())) {
object = (EOEnterpriseObject)object.valueForKeyPath(ERXStringUtilities.keyPathWithoutLastProperty(key()));
}
return object;
}
public void removeObject(EOEnterpriseObject objectToRemove) {
relationshipObject().removeObjectFromBothSidesOfRelationshipWithKey(objectToRemove, relationshipName());
}
public void deleteObject(EOEnterpriseObject objectToRemove) {
removeObject(objectToRemove);
if(objectToRemove.editingContext() != null) {
// AK: this is a bit tricky... when we delete and a delete can fail,
// WOApp tries to validate the delete at the and
// of the current RR loop and this triggers an exception
// that can't be caught in the page itself
// so what we do here is delete the object, try to validate and
// is that fails, restore the EC. This isn't sufficient either -
// as reverting deletes doesn't really work well -
// but preferable to simply showing up and exception page.
try {
objectToRemove.editingContext().deleteObject(objectToRemove);
objectToRemove.validateForDelete();
} catch (NSValidation.ValidationException ex) {
validationFailedWithException(ex, objectToRemove, key());
object().editingContext().revert();
}
}
}
public EOEnterpriseObject addObject() {
return ERXEOControlUtilities.createAndAddObjectToRelationship(object().editingContext(), relationshipObject(), relationshipName(), destinationEntityName(), null);
}
public WOComponent removeObjectsAction() {
for(Enumeration objects = selectedObjects().objectEnumerator(); objects.hasMoreElements(); ) {
EOEnterpriseObject eo = (EOEnterpriseObject)objects.nextElement();
removeObject(eo);
}
return context().page();
}
public WOComponent deleteObjectsAction() {
for(Enumeration objects = selectedObjects().objectEnumerator(); objects.hasMoreElements(); ) {
EOEnterpriseObject eo = (EOEnterpriseObject)objects.nextElement();
deleteObject(eo);
}
return context().page();
}
public WOComponent addObjectsAction() {
for(int i = 0; i < objectsToAdd; i++) {
addObject();
}
return context().page();
}
public boolean isSelected() {
return selectedObjects().containsObject(currentObject);
}
public void setIsSelected(boolean selected) {
if(selected && !selectedObjects().containsObject(currentObject)) {
selectedObjects().addObject(currentObject);
} else if(!selected && !selectedObjects().containsObject(currentObject)) {
selectedObjects().removeObject(currentObject);
}
}
public NSMutableArray selectedObjects() {
if(selectedObjects == null) {
selectedObjects = new NSMutableArray();
}
return selectedObjects;
}
public void setSelectedObjects(NSMutableArray value) {
selectedObjects = value;
}
}