package er.modern.directtoweb.components.query;
import com.webobjects.appserver.WOActionResults;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WOResponse;
import com.webobjects.eoaccess.EODatabaseDataSource;
import com.webobjects.eocontrol.EODataSource;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSKeyValueCoding;
import com.webobjects.foundation.NSMutableArray;
import er.ajax.AjaxUtils;
import er.directtoweb.components.ERDCustomQueryComponent;
import er.extensions.eof.ERXQ;
import er.extensions.foundation.ERXArrayUtilities;
import er.extensions.foundation.ERXStringUtilities;
import er.extensions.localization.ERXLocalizer;
import er.modern.directtoweb.delegates.ERMD2WAttributeQueryDelegate;
import er.modern.directtoweb.delegates.ERMD2WAttributeQueryDelegate.ERMD2WQueryComponent;
/**
* Ajax-enabled ad-hoc filtering of lists. Similar to ERDAjaxSearchDisplayGroup,
* but enables filtering over multiple attributes and/or a pop-up list of choices.
*
* Gets displayed when either or both of searchKey and restrictedChoiceKey D2W keys is not null.
*
* @d2wKey searchKey - either a single target key as a string or an array with multiple keys
* @d2wKey restrictedChoiceKey - key path that will return a list of filter choices, note that no "object" will be available!
* @d2wKey keyWhenRelationship - specifies the display key on the choice
* @d2wKey noSelectionString - "no selection" string to show on the restricted choice pop-up
* @d2wKey restrictedChoiceTargetKey - target key path on which to qualify with the choice
* @d2wKey restrictedChoiceRecursionKey - key path from which to retrieve descendant choices, think "allChildrenCategories"
* @d2wKey typeAheadMinimumCharacterCount
*
*/
public class ERMD2WListFilter extends ERDCustomQueryComponent implements
ERMD2WQueryComponent {
private static final long serialVersionUID = 1L;
public interface Keys extends ERDCustomQueryComponent.Keys {
public static final String restrictedChoiceKey = "restrictedChoiceKey";
public static final String keyWhenRelationship = "keyWhenRelationship";
public static final String noSelectionString = "noSelectionString";
public static final String restrictedChoiceTargetKey = "restrictedChoiceTargetKey";
public static final String restrictedChoiceRecursionKey = "restrictedChoiceRecursionKey";
public static final String searchKey = "searchKey";
public static final String typeAheadMinimumCharacterCount = "typeAheadMinimumCharacterCount";
}
private Object _filterChoice;
private String _searchValue;
public Object filterChoiceItem;
public ERMD2WListFilter(WOContext context) {
super(context);
}
@Override
public boolean synchronizesVariablesWithBindings() {
return false;
}
/**
* @return true if searchKey or filterChoices is not null
*/
public boolean shouldShow() {
return d2wContext().valueForKey(Keys.searchKey) != null || d2wContext().valueForKey(Keys.restrictedChoiceKey) != null;
}
// actions
@SuppressWarnings({ "rawtypes", "unchecked" })
public WOActionResults search() {
EOQualifier _qualifier = ERMD2WAttributeQueryDelegate.instance
.buildQualifier(this);
String filterChoicesKey = (String) d2wContext().valueForKey(Keys.restrictedChoiceTargetKey);
if (!ERXStringUtilities.stringIsNullOrEmpty(filterChoicesKey)
&& filterChoice() != null) {
if (d2wContext().valueForKey(Keys.restrictedChoiceRecursionKey) != null) {
String recursionKey = (String) d2wContext()
.valueForKey(Keys.restrictedChoiceRecursionKey);
NSMutableArray deepChoices = new NSMutableArray(filterChoice());
deepChoices.addObjects(NSKeyValueCoding.Utility
.valueForKey(filterChoice(), recursionKey));
_qualifier = ERXQ.and(_qualifier, ERXQ.in(filterChoicesKey, ERXArrayUtilities.flatten(deepChoices)));
} else {
_qualifier = ERXQ.and(_qualifier,
ERXQ.equals(filterChoicesKey, filterChoice()));
}
}
// qualify on the data source if it's a DB data source
if (displayGroup().dataSource() instanceof EODatabaseDataSource) {
EODatabaseDataSource dbds = (EODatabaseDataSource) displayGroup().dataSource();
dbds.setAuxiliaryQualifier(_qualifier);
dbds.fetchSpecification().setUsesDistinct(true);
} else {
displayGroup().setQualifier(_qualifier);
}
displayGroup().fetch();
displayGroup().setCurrentBatchIndex(1);
return null;
}
public void appendToResponse(WOResponse response, WOContext context) {
AjaxUtils.addScriptResourceInHead(context, response, "prototype.js");
super.appendToResponse(response, context);
}
public void setSearchValue(String searchValue) {
_searchValue = searchValue;
}
@Override
public String searchValue() {
return _searchValue;
}
public void setFilterChoice(Object filterChoice) {
_filterChoice = filterChoice;
}
public Object filterChoice() {
return _filterChoice;
}
public String filterChoicesDisplayString() {
String displayKey = (String) d2wContext().valueForKey(Keys.keyWhenRelationship);
return (String) NSKeyValueCoding.Utility.valueForKey(filterChoiceItem, displayKey);
}
public String noSelectionString() {
String noSelectionString = (String) d2wContext().valueForKey(Keys.noSelectionString);
noSelectionString = ERXLocalizer.currentLocalizer().localizedStringForKey(noSelectionString);
return noSelectionString;
}
@SuppressWarnings({ "rawtypes" })
public NSArray filterChoices() {
NSArray filterChoices = NSArray.emptyArray();
if (d2wContext().valueForKey(Keys.restrictedChoiceKey) != null) {
String filterChoicesKey = (String) d2wContext()
.valueForKey(Keys.restrictedChoiceKey);
filterChoices = (NSArray) valueForKeyPath(filterChoicesKey);
}
return filterChoices;
}
@Override
public EODataSource dataSource() {
return displayGroup().dataSource();
}
/**
* @return dynamic CSS class attribute, depending on whether both searchKey
* and filterChoices are to be shown
*/
public String wrapperClass() {
String wrapperClass = "ListFilter";
if (d2wContext().valueForKey(Keys.searchKey) != null && d2wContext().valueForKey(Keys.restrictedChoiceKey) != null) {
wrapperClass = wrapperClass.concat(" ComboListFilter");
}
return wrapperClass;
}
}