/*
* Copyright (C) NetStruxr, Inc. All rights reserved.
*
* This software is published under the terms of the NetStruxr
* Public Software License version 0.5, a copy of which has been
* included with this distribution in the LICENSE.NPL file. */
package er.directtoweb.pages;
import java.util.Enumeration;
import org.apache.log4j.Logger;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.directtoweb.EditRelationshipPageInterface;
import com.webobjects.eoaccess.EODatabaseDataSource;
import com.webobjects.eoaccess.EOUtilities;
import com.webobjects.eocontrol.EODataSource;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSSet;
import er.directtoweb.delegates.ERDBranchDelegate;
import er.directtoweb.interfaces.ERDPickPageInterface;
import er.extensions.appserver.ERXDisplayGroup;
import er.extensions.eof.ERXEC;
import er.extensions.eof.ERXEOControlUtilities;
import er.extensions.foundation.ERXValueUtilities;
/**
* Allows the selection of one or more objects from a set of EOs. Can also be used directly as a
* EditRelationshipPage for editing to-one and to-many relationships.
* @d2wKey showActions
* @d2wKey singleSelection
* @d2wKey restrictedChoiceKey
* @d2wKey restrictingFetchSpecification
*/
// FIXME: Need a formal protocol for cancel vs. selection.
public class ERD2WPickListPage extends ERD2WListPage implements ERDPickPageInterface, EditRelationshipPageInterface {
/**
* 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 */
public static final Logger log = Logger.getLogger(ERD2WPickListPage.class);
/**
* IE sometimes won't submit the form if it only has checkboxes, we bind
* this to a WOHiddenField.
*/
public String dummy;
/** Caches if we are in single selection mode. */
public Boolean _singleSelection;
/** These are set when we are in edit-relationship mode. */
public EOEnterpriseObject _masterObject;
public String _relationshipKey;
/**
* Public constructor.
*
* @param context
* current context
*/
public ERD2WPickListPage(WOContext context) {
super(context);
}
/**
* Determines if the cancel button should be shown.
*
* @return if we have a nextPage set
*/
@Override
public boolean showCancel() {
return ((!(nextPageDelegate() instanceof ERDBranchDelegate)) && nextPage() != null) || cancelPage() !=null;
}
public boolean checked() {
return selectedObjects().containsObject(object());
}
public void setChecked(boolean newChecked) {
NSMutableArray selectedObjects = selectedObjects().mutableClone();
if (newChecked) {
if (!selectedObjects.containsObject(object())) {
selectedObjects.addObject(object());
}
} else {
selectedObjects.removeObject(object());
}
setSelectedObjects(selectedObjects);
}
@Override
public NSArray selectedObjects() {
return super.selectedObjects();
}
@Override
public void setSelectedObjects(NSArray selectedObjects) {
super.setSelectedObjects(selectedObjects);
}
// FIXME: Not using cancel page at the moment. Only matters if not using a
// branch delegate.
private WOComponent _cancelPage;
public WOComponent cancelPage() {
return _cancelPage;
}
public void setCancelPage(WOComponent cp) {
_cancelPage = cp;
}
@Override
public WOComponent backAction() {
if(_masterObject != null) {
EOEditingContext ec = _masterObject.editingContext();
ec.lock();
try {
_masterObject.takeValueForKey(singleSelection() ? selectedObjects().lastObject() : selectedObjects(), _relationshipKey);
ec.saveChanges();
} finally {
ec.unlock();
}
}
return super.backAction();
}
public void setChoices(NSArray choices) {
displayGroup().setObjectArray(choices);
}
// Called by ERD2WListPage before the display group is updated
@Override
protected void willUpdate() {
super.willUpdate();
}
// Called by ERD2WListPage after the display group is updated
@Override
protected void didUpdate() {
super.didUpdate();
// update our selection, so that we don't have any objects selected that are not visible on any page
if ( selectedObjects().count() > 0 && filteredObjects().count() > 0 ) {
// once intersectingElements() is more efficient, we can use that
//int preIntersectCount = selectedObjects().count();
//NSArray newSelection = ERXArrayUtilities.intersectingElements(selectedObjects(), filteredObjects());
NSSet selectedSet = new NSSet (selectedObjects());
NSSet filteredSet = new NSSet (filteredObjects());
int preIntersectCount = selectedSet.count();
NSSet newSelection = selectedSet.setByIntersectingSet(filteredSet);
if (newSelection.count() != preIntersectCount) {
setSelectedObjects(newSelection.allObjects());
}
}
}
public boolean showSelectionActions() {
return filteredObjects().count() > 0 && ERXValueUtilities.booleanValue(d2wContext().valueForKey("showActions"));
}
/**
* The display group's objects, filtered by the display group qualifier (if any)
*/
public NSArray filteredObjects() {
if (displayGroup() instanceof ERXDisplayGroup) {
ERXDisplayGroup dg = (ERXDisplayGroup) displayGroup();
return dg.filteredObjects();
}
return displayGroup().qualifier() == null ? displayGroup().allObjects() : EOQualifier.filteredArrayWithQualifier(displayGroup().allObjects(), displayGroup().qualifier());
}
public WOComponent selectAll() {
NSMutableArray selectedObjects = new NSMutableArray();
NSArray list = filteredObjects();
for (Enumeration e = list.objectEnumerator(); e.hasMoreElements();) {
selectedObjects.addObject(e.nextElement());
}
setSelectedObjects(selectedObjects);
return context().page();
}
public WOComponent selectAllOnPage() {
NSMutableArray selectedObjects = new NSMutableArray();
NSArray list = displayGroup().displayedObjects();
for (Enumeration e = list.objectEnumerator(); e.hasMoreElements();) {
selectedObjects.addObject(e.nextElement());
}
setSelectedObjects(selectedObjects);
return context().page();
}
public WOComponent unselectAll() {
NSMutableArray selectedObjects = new NSMutableArray();
setSelectedObjects(selectedObjects);
return context().page();
}
public boolean singleSelection() {
if (_singleSelection == null) {
_singleSelection = ERXValueUtilities.booleanValue(d2wContext().valueForKey("singleSelection")) ? Boolean.TRUE : Boolean.FALSE;
}
return _singleSelection.booleanValue();
}
public String selectionWidgetName() {
return singleSelection() ? "WORadioButton" : "WOCheckBox";
}
public void setMasterObjectAndRelationshipKey(EOEnterpriseObject eo, String relationshipName) {
EOEditingContext ec = ERXEC.newEditingContext(eo.editingContext(), false);
setEditingContext(ec);
_masterObject = EOUtilities.localInstanceOfObject(ec, eo);
_relationshipKey = relationshipName;
setObject(_masterObject);
_singleSelection = _masterObject.classDescription().toManyRelationshipKeys().containsObject(_relationshipKey) ? Boolean.FALSE : Boolean.TRUE;
d2wContext().takeValueForKey(_singleSelection, "singleSelection");
EODataSource ds;
String restrictedChoiceKey = (String)d2wContext().valueForKeyPath("restrictedChoiceKey");
if(restrictedChoiceKey != null && restrictedChoiceKey.length() > 0) {
Object choices = d2wContext().valueForKeyPath(restrictedChoiceKey);
ds = ERXEOControlUtilities.dataSourceForArray((NSArray)choices);
} else {
ds = new EODatabaseDataSource(ec, d2wContext().entity().name(), (String)d2wContext().valueForKeyPath("restrictingFetchSpecification"));
}
setDataSource(ds);
Object relationshipValue = _masterObject.valueForKey(relationshipName);
NSArray objects;
if(relationshipValue instanceof NSArray) {
objects = (NSArray)relationshipValue;
} else if(relationshipValue != null) {
objects = new NSArray(relationshipValue);
} else {
objects = NSArray.EmptyArray;
}
setSelectedObjects(objects);
}
}