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
|
* Angelegt wurde Sie für die Auflistung der aktuellen News
|
||||||
* und Veranstalungen auf einer Navigationsseite.
|
* und Veranstalungen auf einer Navigationsseite.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.arsdigita.london.navigation.ui.object;
|
package com.arsdigita.london.navigation.ui.object;
|
||||||
|
|
||||||
import com.arsdigita.london.navigation.Navigation;
|
import com.arsdigita.london.navigation.Navigation;
|
||||||
|
|
@ -31,42 +29,42 @@ import java.util.Map;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A complex object list
|
* A complex object list
|
||||||
*/
|
*/
|
||||||
public class ComplexObjectList extends AbstractObjectList {
|
public class ComplexObjectList extends AbstractObjectList {
|
||||||
|
|
||||||
public static final String CUSTOM_NAME = "customName";
|
public static final String CUSTOM_NAME = "customName";
|
||||||
protected String m_customName = null;
|
protected String m_customName = null;
|
||||||
protected String m_filter = null;
|
protected String m_filter = null;
|
||||||
protected Map m_filterParameters = new HashMap();
|
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) {
|
public void setCustomName(String name) {
|
||||||
m_customName = name;
|
m_customName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCustomName() {
|
public String getCustomName() {
|
||||||
return m_customName;
|
return m_customName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hinzufügen eines SQL-Filter zur Abfrage
|
* Hinzufügen eines SQL-Filter zur Abfrage
|
||||||
* Verarbeitet einen boolschen Filter, der SQL-konform Formatiert ist.
|
* Verarbeitet einen boolschen Filter, der SQL-konform Formatiert ist.
|
||||||
* Siehe PostgreSQL-Handbuch zur where-Klausel
|
* Siehe PostgreSQL-Handbuch zur where-Klausel
|
||||||
|
* @param sqlfilter
|
||||||
*/
|
*/
|
||||||
public void setSQLFilter(String sqlfilter) {
|
public void setSQLFilter(String sqlfilter) {
|
||||||
|
|
||||||
m_filter = sqlfilter;
|
m_filter = sqlfilter;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParameter(String parameterName, Object value) {
|
public void setParameter(String parameterName, Object value) {
|
||||||
|
|
||||||
m_filterParameters.put(parameterName, value);
|
m_filterParameters.put(parameterName, value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCustomAttribute(final String attribute) {
|
public String getCustomAttribute(final String attribute) {
|
||||||
|
|
@ -76,53 +74,56 @@ public class ComplexObjectList extends AbstractObjectList {
|
||||||
public void addCustomAttribute(final String attribute, final String value) {
|
public void addCustomAttribute(final String attribute, final String value) {
|
||||||
m_customAttributes.put(attribute, value);
|
m_customAttributes.put(attribute, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Diese Methode überschreibt die Methode aus der Eltern-Klasse, um
|
/* Diese Methode überschreibt die Methode aus der Eltern-Klasse, um
|
||||||
* die SQL-Filter berücksichtigen zu können
|
* die SQL-Filter berücksichtigen zu können
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected DataCollection getObjects( HttpServletRequest request, HttpServletResponse response ) {
|
protected DataCollection getObjects(HttpServletRequest request,
|
||||||
DataCollection objects = super.getObjects( request, response );
|
HttpServletResponse response) {
|
||||||
|
DataCollection objects = super.getObjects(request, response);
|
||||||
|
|
||||||
// Setze den Filter
|
// Setze den Filter
|
||||||
if(m_filter != null) {
|
if (m_filter != null) {
|
||||||
|
|
||||||
FilterFactory fact = objects.getFilterFactory();
|
FilterFactory fact = objects.getFilterFactory();
|
||||||
Filter sql = fact.simple(m_filter);
|
Filter sql = fact.simple(m_filter);
|
||||||
|
|
||||||
// Setze die Parameter
|
// Setze die Parameter
|
||||||
Iterator params = m_filterParameters.entrySet().iterator();
|
Iterator params = m_filterParameters.entrySet().iterator();
|
||||||
while(params.hasNext()) {
|
while (params.hasNext()) {
|
||||||
|
|
||||||
Map.Entry entry = (Map.Entry) params.next();
|
Map.Entry entry = (Map.Entry) params.next();
|
||||||
String param = (String) entry.getKey();
|
String param = (String) entry.getKey();
|
||||||
Object value = (Object) entry.getValue();
|
Object value = (Object) entry.getValue();
|
||||||
if(value != null) sql.set(param, value);
|
if (value != null) {
|
||||||
|
sql.set(param, value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
objects.addFilter(sql);
|
objects.addFilter(sql);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Diese Methode wird vom Servlet aufgerufen */
|
/* 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");
|
Element content = Navigation.newElement("complexObjectList");
|
||||||
|
|
||||||
if (m_customName != null) {
|
if (m_customName != null) {
|
||||||
content.addAttribute(CUSTOM_NAME, m_customName);
|
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.addAttribute(attribute.getKey(), attribute.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
content.addContent(generateObjectListXML(request, response));
|
content.addContent(generateObjectListXML(request, response));
|
||||||
|
|
||||||
return content;
|
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.bebop.dhtml_editor=FCKeditor
|
||||||
|
|
||||||
waf.categorization.show_internal_name=true
|
waf.categorization.show_internal_name=true
|
||||||
|
waf.categorization.supported_languages=de,en
|
||||||
|
|
||||||
waf.dispatcher.default_expiry=3600
|
waf.dispatcher.default_expiry=3600
|
||||||
;
|
;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue