Customizable object list.
git-svn-id: https://svn.libreccm.org/ccm/trunk@810 8810af33-2d31-482b-a856-94f89814c4dfmaster
parent
a1a7e209dc
commit
1d9cd2d691
|
|
@ -0,0 +1,189 @@
|
|||
package com.arsdigita.london.navigation.ui.object;
|
||||
|
||||
import com.arsdigita.xml.Element;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A filter for the {@link CustomizableObjectList}. The {@code CompareFilter}
|
||||
* filters the object list using a provided value and a operator. Valid
|
||||
* operators defined in the {@link Operators} enumeration.
|
||||
*
|
||||
* @author Jens Pelzetter
|
||||
*/
|
||||
public class CompareFilter implements Filter {
|
||||
|
||||
private static final String ALL = "--ALL--";
|
||||
private final String property;
|
||||
private final String label;
|
||||
private final boolean allOption;
|
||||
private final boolean allOptionIsDefault;
|
||||
private final boolean propertyIsNumeric;
|
||||
private Map<String, Option> options = new LinkedHashMap<String, Option>();
|
||||
private String value;
|
||||
|
||||
protected CompareFilter(final String property,
|
||||
final String label,
|
||||
final boolean allOption,
|
||||
final boolean allOptionIsDefault,
|
||||
final boolean propertyIsNumeric) {
|
||||
this.property = property;
|
||||
this.label = label;
|
||||
this.allOption = allOption;
|
||||
this.allOptionIsDefault = allOptionIsDefault;
|
||||
this.propertyIsNumeric = propertyIsNumeric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public CompareFilter addOption(final String label, final String value) {
|
||||
return addOption(label, Operators.EQ, value);
|
||||
}
|
||||
|
||||
public CompareFilter addOption(final String label,
|
||||
final Operators operator,
|
||||
final String value) {
|
||||
Option option;
|
||||
option = new Option(label, operator, value);
|
||||
options.put(label, option);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilter() {
|
||||
Option selectedOption;
|
||||
StringBuffer filter;
|
||||
|
||||
if ((value == null) || value.isEmpty()) {
|
||||
if (allOptionIsDefault) {
|
||||
value = ALL;
|
||||
} else {
|
||||
value =
|
||||
new ArrayList<Option>(options.values()).get(0).getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
if (ALL.equals(value)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
selectedOption = options.get(value);
|
||||
|
||||
if (selectedOption == null) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unknown option '%s' selected for CompareFilter for property '%s'.",
|
||||
value,
|
||||
property));
|
||||
}
|
||||
|
||||
filter = new StringBuffer();
|
||||
filter.append(property);
|
||||
|
||||
switch (selectedOption.getOperator()) {
|
||||
case EQ:
|
||||
filter.append(" = ");
|
||||
break;
|
||||
case LT:
|
||||
filter.append(" < ");
|
||||
break;
|
||||
case GT:
|
||||
filter.append(" > ");
|
||||
break;
|
||||
case LTEQ:
|
||||
filter.append(" <= ");
|
||||
break;
|
||||
case GTEQ:
|
||||
filter.append(" >= ");
|
||||
break;
|
||||
}
|
||||
|
||||
if (propertyIsNumeric) {
|
||||
filter.append(selectedOption.getValue());
|
||||
} else {
|
||||
filter.append('\'');
|
||||
filter.append(selectedOption.getValue());
|
||||
filter.append('\'');
|
||||
}
|
||||
|
||||
return filter.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element getXml() {
|
||||
Element filter;
|
||||
String selected;
|
||||
|
||||
filter = new Element("compareFilter");
|
||||
|
||||
if ((value == null) || value.isEmpty()) {
|
||||
if (allOptionIsDefault) {
|
||||
selected = ALL;
|
||||
} else {
|
||||
List<Option> optionsList =
|
||||
new ArrayList<Option>(options.values());
|
||||
selected = optionsList.get(0).getLabel();
|
||||
}
|
||||
} else {
|
||||
selected = value;
|
||||
}
|
||||
|
||||
filter.addAttribute("label", label);
|
||||
filter.addAttribute("selected", selected);
|
||||
|
||||
if (allOption) {
|
||||
Element option;
|
||||
|
||||
option = filter.newChildElement("option");
|
||||
option.addAttribute(label, ALL);
|
||||
}
|
||||
|
||||
Element option;
|
||||
for (Map.Entry<String, Option> entry : options.entrySet()) {
|
||||
option = filter.newChildElement("option");
|
||||
option.addAttribute("label", entry.getValue().getLabel());
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
public enum Operators {
|
||||
|
||||
EQ, //equal, '{@code =}'
|
||||
LT, //less than, '{@code <}'
|
||||
GT, //greater than, '{@code >}'
|
||||
LTEQ, //less than or equal, '{@code <=}'
|
||||
GTEQ //greater than or equal, '{@code >=}'
|
||||
}
|
||||
|
||||
public class Option {
|
||||
|
||||
private final String label;
|
||||
private final Operators operator;
|
||||
private final String value;
|
||||
|
||||
public Option(final String label,
|
||||
final Operators operator,
|
||||
final String value) {
|
||||
this.label = label;
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public Operators getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,8 +11,6 @@
|
|||
* Angelegt wurde Sie für die Auflistung der aktuellen News
|
||||
* und Veranstalungen auf einer Navigationsseite.
|
||||
*/
|
||||
|
||||
|
||||
package com.arsdigita.london.navigation.ui.object;
|
||||
|
||||
import com.arsdigita.london.navigation.Navigation;
|
||||
|
|
@ -31,42 +29,42 @@ import java.util.Map;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* A complex object list
|
||||
*/
|
||||
public class ComplexObjectList extends AbstractObjectList {
|
||||
|
||||
|
||||
public static final String CUSTOM_NAME = "customName";
|
||||
protected String m_customName = null;
|
||||
protected String m_filter = null;
|
||||
protected Map m_filterParameters = new HashMap();
|
||||
protected Map<String, String> m_customAttributes =
|
||||
new HashMap<String, String>();
|
||||
|
||||
private Map<String, String> m_customAttributes = new HashMap<String, String>();
|
||||
|
||||
public void setCustomName(String name) {
|
||||
m_customName = name;
|
||||
}
|
||||
|
||||
|
||||
public String getCustomName() {
|
||||
return m_customName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hinzufügen eines SQL-Filter zur Abfrage
|
||||
* Verarbeitet einen boolschen Filter, der SQL-konform Formatiert ist.
|
||||
* Siehe PostgreSQL-Handbuch zur where-Klausel
|
||||
* @param sqlfilter
|
||||
*/
|
||||
public void setSQLFilter(String sqlfilter) {
|
||||
|
||||
|
||||
m_filter = sqlfilter;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setParameter(String parameterName, Object value) {
|
||||
|
||||
|
||||
m_filterParameters.put(parameterName, value);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public String getCustomAttribute(final String attribute) {
|
||||
|
|
@ -76,53 +74,56 @@ public class ComplexObjectList extends AbstractObjectList {
|
|||
public void addCustomAttribute(final String attribute, final String value) {
|
||||
m_customAttributes.put(attribute, value);
|
||||
}
|
||||
|
||||
/* Diese Methode überschreibt die Methode aus der Eltern-Klasse, um
|
||||
* die SQL-Filter berücksichtigen zu können
|
||||
*/
|
||||
|
||||
/* Diese Methode überschreibt die Methode aus der Eltern-Klasse, um
|
||||
* die SQL-Filter berücksichtigen zu können
|
||||
*/
|
||||
@Override
|
||||
protected DataCollection getObjects( HttpServletRequest request, HttpServletResponse response ) {
|
||||
DataCollection objects = super.getObjects( request, response );
|
||||
|
||||
protected DataCollection getObjects(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
DataCollection objects = super.getObjects(request, response);
|
||||
|
||||
// Setze den Filter
|
||||
if(m_filter != null) {
|
||||
|
||||
if (m_filter != null) {
|
||||
|
||||
FilterFactory fact = objects.getFilterFactory();
|
||||
Filter sql = fact.simple(m_filter);
|
||||
|
||||
|
||||
// Setze die Parameter
|
||||
Iterator params = m_filterParameters.entrySet().iterator();
|
||||
while(params.hasNext()) {
|
||||
|
||||
while (params.hasNext()) {
|
||||
|
||||
Map.Entry entry = (Map.Entry) params.next();
|
||||
String param = (String) entry.getKey();
|
||||
Object value = (Object) entry.getValue();
|
||||
if(value != null) sql.set(param, value);
|
||||
|
||||
if (value != null) {
|
||||
sql.set(param, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
objects.addFilter(sql);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
|
||||
/* Diese Methode wird vom Servlet aufgerufen */
|
||||
public Element generateXML(HttpServletRequest request, HttpServletResponse response) {
|
||||
public Element generateXML(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
Element content = Navigation.newElement("complexObjectList");
|
||||
|
||||
|
||||
if (m_customName != null) {
|
||||
content.addAttribute(CUSTOM_NAME, m_customName);
|
||||
}
|
||||
|
||||
for(Map.Entry<String, String> attribute : m_customAttributes.entrySet()) {
|
||||
for (Map.Entry<String, String> attribute : m_customAttributes.entrySet()) {
|
||||
content.addAttribute(attribute.getKey(), attribute.getValue());
|
||||
}
|
||||
|
||||
|
||||
content.addContent(generateObjectListXML(request, response));
|
||||
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,324 @@
|
|||
package com.arsdigita.london.navigation.ui.object;
|
||||
|
||||
import com.arsdigita.london.navigation.Navigation;
|
||||
import com.arsdigita.persistence.DataCollection;
|
||||
import com.arsdigita.xml.Element;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* An object list variant which can be filtered and sorted by the visitor of
|
||||
* the website. The available filters and sort options are added in a JSP
|
||||
* template. There are three kinds of filters yet:
|
||||
* </p>
|
||||
* <dl>
|
||||
* <dt><code>TextFilter</code></dt>
|
||||
* <dd>This filter filters the object list using a user provided string, which
|
||||
* is put into the <code>WHERE</code> clause with <code>LIKE</code> operator.
|
||||
* You might use this filter to allow the visitor to filter an object list for
|
||||
* items with a specific name.</dd>
|
||||
* <dt><code>SelectFilter</code></dt>
|
||||
* <dd>This filter traverses through the objects displayed by the list and
|
||||
* determines all distinct values of a property. The visitor can choose one
|
||||
* of this values, and the displayed list will only contain items which where
|
||||
* the property has the selected value.</dd>
|
||||
* <dt><code>CompareFilter</code></dt>
|
||||
* <dd>This filter also provides selectable options. But these options
|
||||
* can be configured by the developer in the template.</dd>
|
||||
* </dl>
|
||||
* <p>
|
||||
* If there is more than one filter, the values of all filters are combined
|
||||
* using <code>AND</code>.
|
||||
* </p>
|
||||
* <p>
|
||||
* This object list class was developed for displaying list of items from
|
||||
* the Sci modules (SciPublications and SciOrganization). For example, we use
|
||||
* this list to provide lists of publications which be filtered for publications
|
||||
* from a specific year, for a specific author and for a specific title. The
|
||||
* list can be sorted by the titles of the publications, the years of the
|
||||
* publications and the (surnames of the) authors of the publications.
|
||||
* </p>
|
||||
* <p>
|
||||
* As an example how to use this object list in a JSP template here are the
|
||||
* relevant parts from the template for the publication list:
|
||||
* </p>
|
||||
* <pre>
|
||||
* {@code
|
||||
* ...
|
||||
* <define:component name="itemList"
|
||||
classname="com.arsdigita.london.navigation.ui.object.CustomizableObjectList"/>
|
||||
* ...
|
||||
* <jsp:scriptlet>
|
||||
CustomizableObjectList objList = (CustomizableObjectList) itemList;
|
||||
objList.setDefinition(new CMSDataCollectionDefinition());
|
||||
objList.setRenderer(new CMSDataCollectionRenderer());
|
||||
objList.getDefinition().setObjectType("com.arsdigita.cms.contenttypes.Publication");
|
||||
objList.getDefinition().setDescendCategories(false);
|
||||
objList.addTextFilter("title", "title");
|
||||
objList.addTextFilter("authors.surname", "author");
|
||||
objList.addSelectFilter("yearOfPublication", "year", true, true, true, true);
|
||||
objList.addSortField("title", "title asc");
|
||||
objList.addSortField("yearAsc", "yearOfPublication asc");
|
||||
objList.addSortField("yearDesc", "yearOfPublication desc");
|
||||
objList.addSortField("authors", "authors.surname asc, authors.givenname asc");
|
||||
objList.getDefinition().addOrder(objList.getOrder(request.getParameter("sort")));
|
||||
|
||||
objList.getRenderer().setPageSize(20);
|
||||
objList.getRenderer().setSpecializeObjects(true);
|
||||
|
||||
</jsp:scriptlet>
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* You may notice the line
|
||||
* <code>objList.getDefinition().addOrder(objList.getOrder(request.getParameter("sort")));</code>.
|
||||
* This line may looks a bit weird to you. The reason is that it is not possible
|
||||
* to access the <code>DataCollectionDefinition</code> from the methods in this
|
||||
* class. If you try call the <code>addOrder()</code> from within this class
|
||||
* you will cause an locking error.
|
||||
* </p>
|
||||
* @author Jens Pelzetter
|
||||
* @version $Id$
|
||||
* @see Filter
|
||||
* @see TextFilter
|
||||
* @see SelectFilter
|
||||
* @see CompareFilter
|
||||
*/
|
||||
public class CustomizableObjectList extends ComplexObjectList {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(
|
||||
CustomizableObjectList.class);
|
||||
/**
|
||||
* The filters for the list. We use an {@link LinkedHashMap} here to
|
||||
* preserve the insertation order.
|
||||
*
|
||||
*/
|
||||
private final Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
|
||||
/**
|
||||
* The available sort fields. We use an {@link LinkedHashMap} here to
|
||||
* preserve the insertation order.
|
||||
*
|
||||
*/
|
||||
private final Map<String, String> sortFields = new LinkedHashMap<String, String>();
|
||||
/**
|
||||
* Sort by which property?
|
||||
*/
|
||||
private String sortBy = null;
|
||||
|
||||
/**
|
||||
* Adds a new text filter to the list.
|
||||
*
|
||||
* @param property The property to filter using the new filter.
|
||||
* @param label The label of the filter and its component.
|
||||
* @see TextFilter#TextFilter(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public void addTextFilter(final String property, final String label) {
|
||||
TextFilter filter;
|
||||
|
||||
filter = new TextFilter(property, label);
|
||||
filters.put(label, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new compare filter to the list.
|
||||
*
|
||||
* @param property The property to filter using the new filter.
|
||||
* @param label The label of the filter and its component.
|
||||
* @param allOption Add an <em>all</em> option to the filter.
|
||||
* @param allOptionIsDefault Is the all option the default?
|
||||
* @param propertyIsNumeric Is the property to filter numeric?
|
||||
* @return The new filter. Options can be added to the filter by calling
|
||||
* the {@link CompareFilter#addOption(java.lang.String, java.lang.String)} or
|
||||
* the {@link CompareFilter#addOption(java.lang.String, com.arsdigita.london.navigation.ui.object.CompareFilter.Operators, java.lang.String)}
|
||||
* method.
|
||||
* @see CompareFilter#CompareFilter(java.lang.String, java.lang.String, boolean, boolean, boolean)
|
||||
*
|
||||
*/
|
||||
public CompareFilter addCompareFilter(final String property,
|
||||
final String label,
|
||||
final boolean allOption,
|
||||
final boolean allOptionIsDefault,
|
||||
final boolean propertyIsNumeric) {
|
||||
CompareFilter filter;
|
||||
|
||||
filter = new CompareFilter(property,
|
||||
label,
|
||||
allOption,
|
||||
allOptionIsDefault,
|
||||
propertyIsNumeric);
|
||||
filters.put(label, filter);
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a select filter.
|
||||
*
|
||||
* @param property The property to filter.
|
||||
* @param label The label of the filter.
|
||||
* @param reverseOptions Reverse the order of the options.
|
||||
* @param allOption Add an all option?
|
||||
* @param allOptionIsDefault Is the all option the default.
|
||||
* @param propertyIsNumeric Is the property numeric?
|
||||
* @see SelectFilter#SelectFilter(java.lang.String, java.lang.String, com.arsdigita.london.navigation.ui.object.CustomizableObjectList, boolean, boolean, boolean, boolean)
|
||||
*/
|
||||
public void addSelectFilter(final String property,
|
||||
final String label,
|
||||
final boolean reverseOptions,
|
||||
final boolean allOption,
|
||||
final boolean allOptionIsDefault,
|
||||
final boolean propertyIsNumeric) {
|
||||
SelectFilter filter;
|
||||
|
||||
filter = new SelectFilter(property,
|
||||
label,
|
||||
this,
|
||||
reverseOptions,
|
||||
allOption,
|
||||
allOptionIsDefault,
|
||||
propertyIsNumeric);
|
||||
filters.put(label, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a sort field option.
|
||||
*
|
||||
* @param label The label of the sort field.
|
||||
* @param property The property to sort by.
|
||||
*/
|
||||
public void addSortField(final String label, final String property) {
|
||||
sortFields.put(label, property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which property is currently used for sorting.
|
||||
*
|
||||
* @param id The id of the sort field to sort by.
|
||||
* @return The property to sort by.
|
||||
*/
|
||||
public String getOrder(final String id) {
|
||||
String order = sortFields.get(id);
|
||||
if ((order == null) || order.isEmpty()) {
|
||||
return new ArrayList<String>(sortFields.values()).get(0);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* This overwritten version of the <code>getObjects</code> method evaluates
|
||||
* the parameters in HTTP request for the filters and creates an
|
||||
* appropriate SQL filter and sets this filter.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected DataCollection getObjects(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
//Set filters (using the SQL)
|
||||
StringBuilder sqlFilters = new StringBuilder();
|
||||
for (Map.Entry<String, Filter> filterEntry : filters.entrySet()) {
|
||||
if ((filterEntry.getValue().getFilter() == null)
|
||||
|| (filterEntry.getValue().getFilter().isEmpty())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sqlFilters.length() > 0) {
|
||||
sqlFilters.append(" AND ");
|
||||
}
|
||||
sqlFilters.append(filterEntry.getValue().getFilter());
|
||||
}
|
||||
|
||||
logger.debug(String.format("filters: %s", sqlFilters));
|
||||
if (sqlFilters.length() > 0) {
|
||||
setSQLFilter(sqlFilters.toString());
|
||||
}
|
||||
|
||||
DataCollection objects = super.getObjects(request, response);
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Generates the XML for the list. The root element for the list is
|
||||
* <code>customizableObjectList</code>. The available filters are
|
||||
* put into a <code>filters</code> element.
|
||||
* </p>
|
||||
* <p>
|
||||
* The available sort fields are put into a <code>sortFields</code> element.
|
||||
* This element has also an attribute indicating the current selected sort
|
||||
* field.
|
||||
* </p>
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Element generateXML(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
//Some stuff for the list (copied from ComplexObjectList)
|
||||
Element content = Navigation.newElement("customizableObjectList");
|
||||
|
||||
if (m_customName != null) {
|
||||
content.addAttribute(CUSTOM_NAME, m_customName);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> attribute : m_customAttributes.entrySet()) {
|
||||
content.addAttribute(attribute.getKey(), attribute.getValue());
|
||||
}
|
||||
|
||||
Element filterElems = content.newChildElement("filters");
|
||||
for (Map.Entry<String, Filter> filterEntry : filters.entrySet()) {
|
||||
filterElems.addContent(filterEntry.getValue().getXml());
|
||||
}
|
||||
|
||||
//Look for values for the filters and the sort fields in the HTTP
|
||||
//request. We are not using the Bebop parameters for two reasons:
|
||||
//- They have to be registered very early, so we can't add new parameters
|
||||
// from a JSP.
|
||||
//- The HttpRequest is available here.
|
||||
//So we use the HTTP request directly, which allows use to use a
|
||||
//dedicated parameter for each of the filters.
|
||||
for (Map.Entry<String, Filter> filterEntry : filters.entrySet()) {
|
||||
String value = request.getParameter(filterEntry.getKey());
|
||||
|
||||
if ((value != null) && !value.isEmpty()) {
|
||||
filterEntry.getValue().setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
//Look for a sort parameter. If one is found, use one to sort the data
|
||||
//collection (if it is a valid value). If no sort parameter is found,
|
||||
//use the first sort field as default.
|
||||
String sortByKey = request.getParameter("sort");
|
||||
sortBy = sortFields.get(sortByKey);
|
||||
if (((sortBy == null)
|
||||
|| sortBy.isEmpty()
|
||||
|| !sortFields.containsKey(sortBy))
|
||||
&& !sortFields.isEmpty()) {
|
||||
sortByKey = new ArrayList<String>(sortFields.keySet()).get(0);
|
||||
sortBy = new ArrayList<String>(sortFields.values()).get(0);
|
||||
}
|
||||
|
||||
Element sortFieldElems = content.newChildElement("sortFields");
|
||||
sortFieldElems.addAttribute("sortBy", sortByKey);
|
||||
for (Map.Entry<String, String> sortField : sortFields.entrySet()) {
|
||||
Element sortFieldElem = sortFieldElems.newChildElement("sortField");
|
||||
sortFieldElem.addAttribute("label", sortField.getKey());
|
||||
}
|
||||
|
||||
//Add object list
|
||||
content.addContent(generateObjectListXML(request, response));
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.arsdigita.london.navigation.ui.object;
|
||||
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
/**
|
||||
* Implementations of these interface are used by the
|
||||
* {@link CustomizableObjectList} for filtering the objects in the list.
|
||||
*
|
||||
* @author Jens Pelzetter
|
||||
* @version $Id$
|
||||
* @see CustomizableObjectList
|
||||
*/
|
||||
interface Filter {
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The SQL filter for filtering the object list.
|
||||
*/
|
||||
String getFilter();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return XML representing the input component for the filter.
|
||||
*/
|
||||
Element getXml();
|
||||
|
||||
/**
|
||||
* Used to set the value of the filter if the HTTP request contains a value
|
||||
* for the filter.
|
||||
*
|
||||
* @param value The value from the input component.
|
||||
*/
|
||||
void setValue(String value);
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
package com.arsdigita.london.navigation.ui.object;
|
||||
|
||||
import com.arsdigita.persistence.DataCollection;
|
||||
import com.arsdigita.persistence.DataObject;
|
||||
import com.arsdigita.xml.Element;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This filter allows the user to filter the object list for a specific value
|
||||
* of a property. The selectable values are determined by traversing
|
||||
* through all objects of the list (before the list is processed by the
|
||||
* paginator) and using each distinct value of the property as option.
|
||||
*
|
||||
* @author Jens Pelzetter
|
||||
*/
|
||||
public class SelectFilter implements Filter {
|
||||
|
||||
public static final String ALL = "--ALL--";
|
||||
private final String property;
|
||||
private final String label;
|
||||
private final CustomizableObjectList objectList;
|
||||
private final boolean allOption;
|
||||
private final boolean allOptionIsDefault;
|
||||
private final boolean reverseOptions;
|
||||
private final boolean propertyIsNumeric;
|
||||
//private Map<String, String> options = new HashMap<String, String>();
|
||||
private String value;
|
||||
|
||||
protected SelectFilter(final String property,
|
||||
final String label,
|
||||
final CustomizableObjectList objectList,
|
||||
final boolean reverseOptions,
|
||||
final boolean allOption,
|
||||
final boolean allOptionIsDefault,
|
||||
final boolean propertyIsNumeric) {
|
||||
this.property = property;
|
||||
this.label = label;
|
||||
this.objectList = objectList;
|
||||
this.reverseOptions = reverseOptions;
|
||||
this.allOption = allOption;
|
||||
this.allOptionIsDefault = allOptionIsDefault;
|
||||
this.propertyIsNumeric = propertyIsNumeric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilter() {
|
||||
List<String> options;
|
||||
|
||||
options = getOptions();
|
||||
if ((value == null) || value.isEmpty()) {
|
||||
if (allOptionIsDefault) {
|
||||
value = ALL;
|
||||
} else {
|
||||
value = options.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (ALL.equals(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (propertyIsNumeric) {
|
||||
return String.format("%s = %s", property, value);
|
||||
|
||||
} else {
|
||||
return String.format("%s = '%s'", property, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element getXml() {
|
||||
Element filter;
|
||||
Element optionElem;
|
||||
String selected;
|
||||
List<String> options;
|
||||
|
||||
options = getOptions();
|
||||
|
||||
filter = new Element("selectFilter");
|
||||
|
||||
if ((value == null) || value.isEmpty()) {
|
||||
if (allOptionIsDefault) {
|
||||
selected = ALL;
|
||||
} else {
|
||||
selected = options.get(0);
|
||||
}
|
||||
} else {
|
||||
selected = value;
|
||||
}
|
||||
|
||||
filter.addAttribute("label", label);
|
||||
filter.addAttribute("selected", selected);
|
||||
|
||||
if (allOption) {
|
||||
optionElem = filter.newChildElement("option");
|
||||
optionElem.addAttribute(label, ALL);
|
||||
}
|
||||
|
||||
for (String optionStr : options) {
|
||||
optionElem = filter.newChildElement("option");
|
||||
optionElem.addAttribute("label", optionStr);
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
private List<String> getOptions() {
|
||||
DataCollection objects;
|
||||
DataObject dobj;
|
||||
String option;
|
||||
Set<String> optionsSet;
|
||||
List<String> options;
|
||||
|
||||
objects = objectList.getDefinition().getDataCollection(objectList.
|
||||
getModel());
|
||||
|
||||
optionsSet = new HashSet<String>();
|
||||
|
||||
while (objects.next()) {
|
||||
dobj = objects.getDataObject();
|
||||
|
||||
option = (dobj.get(property)).toString();
|
||||
optionsSet.add(option);
|
||||
}
|
||||
|
||||
options = new ArrayList<String>(optionsSet);
|
||||
Collections.sort(options);
|
||||
if (reverseOptions) {
|
||||
Collections.reverse(options);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.arsdigita.london.navigation.ui.object;
|
||||
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Filter used by the {@link CustomizableObjectList}. These filter is usually
|
||||
* rendered as a input box. The SQL filter created by this filter looks like
|
||||
* this:
|
||||
* </p>
|
||||
* <p>
|
||||
* {@code property LIKE 'value'}
|
||||
* </p>
|
||||
* @author Jens Pelzetter
|
||||
*/
|
||||
public class TextFilter implements Filter {
|
||||
|
||||
private final String property;
|
||||
private final String label;
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Creates a new text filter. The constructor should only be invoked by the
|
||||
* {@link CustomizableObjectList}.
|
||||
*
|
||||
* @param property The property which is used by this filter.
|
||||
* @param label The label for the input component of the filter.
|
||||
*/
|
||||
protected TextFilter(final String property, final String label) {
|
||||
this.property = property;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilter() {
|
||||
if ((value == null) || value.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
/*return String.format("(lower(%s) LIKE lower('%%%s%%'))",
|
||||
property, value);*/
|
||||
|
||||
return String.format("(lower(%s) LIKE lower('%%%s%%')) OR (lower(%s) LIKE lower('%%%s%%'))",
|
||||
property, value,
|
||||
property, firstToUpper(value));
|
||||
}
|
||||
}
|
||||
|
||||
private String firstToUpper(final String str) {
|
||||
char[] chars;
|
||||
|
||||
chars = str.toCharArray();
|
||||
|
||||
chars[0] = Character.toUpperCase(chars[0]);
|
||||
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element getXml() {
|
||||
Element textFilter ;
|
||||
|
||||
textFilter = new Element("textFilter");
|
||||
|
||||
textFilter.addAttribute("label", label);
|
||||
if ((value != null) && !value.isEmpty()) {
|
||||
textFilter.addAttribute("value", value);
|
||||
}
|
||||
|
||||
return textFilter;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ waf.bebop.base_page=com.arsdigita.aplaws.ui.SimplePage
|
|||
#waf.bebop.dhtml_editor=FCKeditor
|
||||
|
||||
waf.categorization.show_internal_name=true
|
||||
waf.categorization.supported_languages=de,en
|
||||
|
||||
waf.dispatcher.default_expiry=3600
|
||||
;
|
||||
|
|
|
|||
Loading…
Reference in New Issue