blob: aa0bdb0b7189b5e507cf1a78654f9e50d3d192ad [file] [log] [blame]
/**
*
* Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Florian Pirchner - Initial implementation
*
*/
package org.eclipse.osbp.ecview.extension.grid.presentation;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.eclipse.osbp.runtime.common.annotations.DtoUtils;
import org.eclipse.osbp.runtime.web.vaadin.common.data.filter.JoinFilter;
import org.vaadin.gridutil.cell.CellFilterComponent;
import org.vaadin.gridutil.cell.RangeCellFilterComponent;
import com.vaadin.data.Item;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.fieldgroup.FieldGroup.CommitEvent;
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
import com.vaadin.data.fieldgroup.FieldGroup.CommitHandler;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.converter.StringToBigDecimalConverter;
import com.vaadin.data.util.converter.StringToBigIntegerConverter;
import com.vaadin.data.util.converter.StringToDoubleConverter;
import com.vaadin.data.util.converter.StringToFloatConverter;
import com.vaadin.data.util.converter.StringToIntegerConverter;
import com.vaadin.data.util.converter.StringToLongConverter;
import com.vaadin.data.util.filter.Between;
import com.vaadin.data.util.filter.Compare.Equal;
import com.vaadin.data.util.filter.Or;
import com.vaadin.data.util.filter.SimpleStringFilter;
import com.vaadin.event.FieldEvents.TextChangeEvent;
import com.vaadin.event.FieldEvents.TextChangeListener;
import com.vaadin.server.FontAwesome;
import com.vaadin.server.FontIcon;
import com.vaadin.shared.ui.datefield.Resolution;
import com.vaadin.ui.AbstractSelect.ItemCaptionMode;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.DateField;
import com.vaadin.ui.Grid;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.TextField;
import com.vaadin.ui.themes.ValoTheme;
/**
* The Class GridCellFilter.
*/
@SuppressWarnings("serial")
public class GridCellFilter extends org.vaadin.gridutil.cell.GridCellFilter {
protected static final String STYLENAME_GRIDCELLFILTER = "gridcellfilter";
/** The grid. */
private Grid grid;
/**
* Instantiates a new grid cell filter.
*
* @param grid
* the grid
*/
public GridCellFilter(Grid grid) {
super(grid);
this.grid = grid;
}
/**
* Sets the dto filter.
*
* @param columnId
* the column id
* @param dtoClass
* the dto class
* @param inputPrompt
* the input prompt
* @return the text field
*/
public TextField setDtoFilter(final Object columnId, final Class<?> dtoClass, final String inputPrompt) {
CellFilterComponent<TextField> filter = new CellFilterComponent<TextField>() {
private static final long serialVersionUID = 1L;
private String domainKeyPropertyId;
private String domainDescriptionPropertyId;
TextField textField = new TextField();
@Override
public TextField layoutComponent() {
Field domainKeyField = DtoUtils.getDomainKeyField(dtoClass);
if (domainKeyField != null) {
domainKeyPropertyId = domainKeyField.getName();
}
Field domainDescriptionField = DtoUtils.getDomainDescriptionField(dtoClass);
if (domainDescriptionField != null) {
domainDescriptionPropertyId = domainDescriptionField.getName();
}
this.textField.setImmediate(true);
this.textField.setInputPrompt(inputPrompt);
this.textField.addStyleName(ValoTheme.TEXTFIELD_TINY);
this.textField.addTextChangeListener(new TextChangeListener() {
private static final long serialVersionUID = -3567212620627878001L;
@Override
public void textChange(final TextChangeEvent event) {
if (event.getText() != null && event.getText().length() > 0) {
if (isValid(domainKeyPropertyId) && isValid(domainDescriptionPropertyId)) {
// filter for key or description
SimpleStringFilter numberFilter = new SimpleStringFilter(domainKeyPropertyId,
event.getText(), true, false);
SimpleStringFilter descriptionFilter = new SimpleStringFilter(
domainDescriptionPropertyId, event.getText(), true, false);
Or or = new Or(numberFilter, descriptionFilter);
replaceFilter(new JoinFilter((String) columnId, or), columnId);
} else if (isValid(domainKeyPropertyId)) {
// filter for key
SimpleStringFilter numberFilter = new SimpleStringFilter(domainKeyPropertyId,
event.getText(), true, false);
replaceFilter(new JoinFilter((String) columnId, numberFilter), columnId);
}
} else {
removeFilter(columnId);
}
}
private boolean isValid(String value) {
return value != null && !value.equals("");
}
});
return this.textField;
}
@Override
public void clearFilter() {
this.textField.clear();
}
};
setCustomFilter(columnId, filter);
return filter.getComponent();
}
/**
* assign a <b>SimpleStringFilter</b> to grid for given columnId<br>
* could also be used for NumberField when you would like to do filter by
* startWith for example
*
* @param columnId
* id of property
* @param filterProperty
* property used to filter
* @param ignoreCase
* property of SimpleStringFilter
* @param onlyMatchPrefix
* property of SimpleStringFilter
* @param inputPrompt
* hint for user
* @return generated TextField
*/
public TextField setTextFilter(final Object columnId, final Object filterProperty, final boolean ignoreCase,
final boolean onlyMatchPrefix, final String inputPrompt) {
CellFilterComponent<TextField> filter = new CellFilterComponent<TextField>() {
private static final long serialVersionUID = 1L;
TextField textField = new TextField();
@Override
public TextField layoutComponent() {
this.textField.setImmediate(true);
this.textField.setInputPrompt(inputPrompt);
this.textField.addStyleName("gridcellfilter");
this.textField.addStyleName(ValoTheme.TEXTFIELD_TINY);
this.textField.addTextChangeListener(new TextChangeListener() {
private static final long serialVersionUID = -3567212620627878001L;
@Override
public void textChange(final TextChangeEvent event) {
if (event.getText() != null && event.getText().length() > 0) {
replaceFilter(new SimpleStringFilter(filterProperty, event.getText(), ignoreCase,
onlyMatchPrefix), columnId);
} else {
removeFilter(columnId);
}
}
});
return this.textField;
}
@Override
public void clearFilter() {
this.textField.clear();
}
};
setCustomFilter(columnId, filter);
return filter.getComponent();
}
/**
* assign a <b>EqualFilter</b> to grid for given columnId
*
* @param columnId
* id of property
* @param filterPropertyPath
* path for filtering
* @return drawn comboBox in order to add some custom styles
*/
public ComboBox setBooleanFilter(final Object columnId, final String filterPropertyPath) {
CellFilterComponent<ComboBox> filter = new CellFilterComponent<ComboBox>() {
private static final long serialVersionUID = 1L;
ComboBox comboBox = new ComboBox();
@SuppressWarnings("unchecked")
private Item genItem(final Boolean value) {
Item item = this.comboBox.getItem(this.comboBox.addItem());
item.getItemProperty("icon").setValue(value ? FontAwesome.CHECK_SQUARE : FontAwesome.TIMES);
item.getItemProperty("value").setValue(value);
item.getItemProperty("caption").setValue(value.toString());
return item;
}
@Override
public ComboBox layoutComponent() {
this.comboBox.addContainerProperty("icon", FontIcon.class, null);
this.comboBox.addContainerProperty("value", Boolean.class, null);
this.comboBox.addContainerProperty("caption", String.class, null);
this.comboBox.setItemCaptionMode(ItemCaptionMode.PROPERTY);
this.comboBox.setItemCaptionPropertyId("caption");
this.comboBox.setItemIconPropertyId("icon");
genItem(Boolean.TRUE);
genItem(Boolean.FALSE);
this.comboBox.setNullSelectionAllowed(true);
this.comboBox.setImmediate(true);
this.comboBox.addStyleName(STYLENAME_GRIDCELLFILTER);
this.comboBox.addStyleName(ValoTheme.COMBOBOX_TINY);
this.comboBox.addValueChangeListener(new ValueChangeListener() {
private static final long serialVersionUID = 75672745825037750L;
@Override
public void valueChange(final ValueChangeEvent event) {
Integer internalId = (Integer) comboBox.getValue();
if (internalId != null && internalId > 0) {
replaceFilter(
new Equal(filterPropertyPath, internalId.equals(1) ? Boolean.TRUE : Boolean.FALSE),
columnId);
} else {
removeFilter(columnId);
}
}
});
return this.comboBox;
}
@Override
public void clearFilter() {
this.comboBox.setValue(null);
}
};
setCustomFilter(columnId, filter);
return filter.getComponent();
}
/**
* assign a <b>EqualFilter</b> to grid for given columnId
*
* @param columnId
* id of property
* @param filterPropertyPath
* path for filtering
* @param list
* selection for ComboBox
* @return drawn comboBox in order to add some custom styles
*/
public ComboBox setComboBoxFilter(final Object columnId, String filterPropertyPath, final List<?> list) {
CellFilterComponent<ComboBox> filter = new CellFilterComponent<ComboBox>() {
private static final long serialVersionUID = 1L;
ComboBox comboBox = new ComboBox();
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public ComboBox layoutComponent() {
BeanItemContainer container = new BeanItemContainer(list.get(0).getClass(), list);
this.comboBox.setNullSelectionAllowed(true);
this.comboBox.setImmediate(true);
this.comboBox.setContainerDataSource(container);
this.comboBox.addStyleName(STYLENAME_GRIDCELLFILTER);
this.comboBox.addStyleName(ValoTheme.COMBOBOX_TINY);
this.comboBox.addValueChangeListener(new ValueChangeListener() {
private static final long serialVersionUID = 4657429154535483528L;
@Override
public void valueChange(final ValueChangeEvent event) {
if (comboBox.getValue() != null) {
replaceFilter(new Equal(filterPropertyPath, comboBox.getValue()), columnId);
} else {
removeFilter(columnId);
}
}
});
return this.comboBox;
}
@Override
public void clearFilter() {
this.comboBox.setValue(null);
}
};
setCustomFilter(columnId, filter);
return filter.getComponent();
}
private final static Date MIN_DATE_VALUE = new Date(0); // 1970-01-01
// 00:00:00
private final static Date MAX_DATE_VALUE = new Date(32503676399000L); // 2999-12-31
// 23:59:59
/**
* assign a <b>BetweenFilter</b> to grid for given columnId<br>
*
* @param columnId
* id of property
* @param filterPropertyPath
* path for filtering
* @return FieldGroup that holds both TextFields (smallest and biggest as
* propertyId)
*/
public FieldGroup setDateFilter(final Object columnId, String filterPropertyPath) {
RangeCellFilterComponent<HorizontalLayout> filter = new RangeCellFilterComponent<HorizontalLayout>() {
/**
*
*/
private static final long serialVersionUID = 1L;
private DateField genDateField(final String propertyId) {
final DateField dateField = new DateField();
getFieldGroup().bind(dateField, propertyId);
dateField.setWidth("100%");
dateField.setImmediate(true);
dateField.setInvalidAllowed(false);
dateField.setInvalidCommitted(false);
dateField.setResolution(Resolution.DAY);
dateField.addStyleName(STYLENAME_GRIDCELLFILTER);
dateField.addStyleName(ValoTheme.DATEFIELD_TINY);
dateField.addValueChangeListener(new ValueChangeListener() {
private static final long serialVersionUID = 9147606627660840906L;
@Override
public void valueChange(final ValueChangeEvent event) {
try {
if (dateField.isValid()) {
dateField.setComponentError(null);
getFieldGroup().commit();
}
} catch (CommitException e) {
}
}
});
return dateField;
}
@Override
public HorizontalLayout layoutComponent() {
getFieldGroup().setItemDataSource(genPropertysetItem(Date.class));
DateField smallest = genDateField("smallest");
DateField biggest = genDateField("biggest");
getHLayout().addComponent(smallest);
getHLayout().addComponent(biggest);
getHLayout().setExpandRatio(smallest, 1);
getHLayout().setExpandRatio(biggest, 1);
initCommitHandler();
return getHLayout();
}
private void initCommitHandler() {
getFieldGroup().addCommitHandler(new CommitHandler() {
private static final long serialVersionUID = 2617591142986829655L;
@Override
public void preCommit(final CommitEvent commitEvent) throws CommitException {
}
private Date fixTiming(Date date, boolean beginning) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.MILLISECOND, beginning ? 0 : 999);
calendar.set(Calendar.SECOND, beginning ? 0 : 99);
calendar.set(Calendar.MINUTE, beginning ? 0 : 59);
calendar.set(Calendar.HOUR, beginning ? 0 : 23);
return calendar.getTime();
}
@Override
public void postCommit(final CommitEvent commitEvent) throws CommitException {
Date smallestValue = (Date) getFieldGroup().getItemDataSource().getItemProperty("smallest")
.getValue();
Date biggestValue = (Date) getFieldGroup().getItemDataSource().getItemProperty("biggest")
.getValue();
if (smallestValue != null || biggestValue != null) {
replaceFilter(
new Between(filterPropertyPath,
smallestValue != null ? fixTiming(smallestValue, true) : MIN_DATE_VALUE,
biggestValue != null ? fixTiming(biggestValue, false) : MAX_DATE_VALUE),
columnId);
} else {
removeFilter(columnId);
}
}
});
}
@Override
public void clearFilter() {
getFieldGroup().clear();
}
};
setCustomFilter(columnId, filter);
return filter.getFieldGroup();
}
/**
* assign a <b>BetweenFilter</b> to grid for given columnId<br>
* only supports type of <b>Integer, Double, Float, BigInteger and
* BigDecimal</b>
*
* @param columnId
* id of property
* @param filterPropertyPath
* path for filtering
* @return FieldGroup that holds both TextFields (smallest and biggest as
* propertyId)
*/
public FieldGroup setNumberFilter(final Object columnId, final String filterPropertyPath) {
final Class<?> type = this.grid.getContainerDataSource().getType(columnId);
RangeCellFilterComponent<HorizontalLayout> filter = new RangeCellFilterComponent<HorizontalLayout>() {
private static final long serialVersionUID = 1L;
@SuppressWarnings("rawtypes")
private Converter getConverter() {
if (type == Integer.class) {
return new StringToIntegerConverter();
} else if (type == Double.class) {
return new StringToDoubleConverter();
} else if (type == Float.class) {
return new StringToFloatConverter();
} else if (type == BigInteger.class) {
return new StringToBigIntegerConverter();
} else if (type == BigDecimal.class) {
return new StringToBigDecimalConverter();
} else {
return new StringToLongConverter();
}
}
@SuppressWarnings("unchecked")
private TextField genNumberField(final String propertyId) {
final TextField field = new TextField();
getFieldGroup().bind(field, propertyId);
field.setWidth("100%");
field.setImmediate(true);
field.setInvalidAllowed(false);
field.setInvalidCommitted(false);
field.setNullSettingAllowed(true);
field.setNullRepresentation("");
field.setConverter(getConverter());
field.addStyleName(STYLENAME_GRIDCELLFILTER);
field.addStyleName(ValoTheme.TEXTFIELD_TINY);
field.addValueChangeListener(new ValueChangeListener() {
private static final long serialVersionUID = -8404344833239596320L;
@Override
public void valueChange(final ValueChangeEvent event) {
try {
if (field.isValid()) {
field.setComponentError(null);
getFieldGroup().commit();
}
} catch (CommitException e) {
}
}
});
return field;
}
@Override
public HorizontalLayout layoutComponent() {
getFieldGroup().setItemDataSource(genPropertysetItem(type));
TextField smallest = genNumberField("smallest");
TextField biggest = genNumberField("biggest");
getHLayout().addComponent(smallest);
getHLayout().addComponent(biggest);
getHLayout().setExpandRatio(smallest, 1);
getHLayout().setExpandRatio(biggest, 1);
initCommitHandler();
return getHLayout();
}
// BigInteger and BigDecimal is a bit dirty
public Number getValue(final boolean max) {
if (type == Integer.class) {
return max ? Integer.MAX_VALUE : Integer.MIN_VALUE;
} else if (type == Double.class) {
return max ? Double.MAX_VALUE : Double.MIN_VALUE;
} else if (type == Float.class) {
return max ? Float.MAX_VALUE : Float.MIN_VALUE;
} else if (type == BigInteger.class) {
return max ? new BigInteger(String.valueOf(Long.MAX_VALUE))
: new BigInteger(String.valueOf(Long.MIN_VALUE));
} else if (type == BigDecimal.class) {
return max ? new BigDecimal(String.valueOf(Long.MAX_VALUE))
: new BigDecimal(String.valueOf(Long.MIN_VALUE));
} else {
return max ? Long.MAX_VALUE : Long.MIN_VALUE;
}
}
private void initCommitHandler() {
getFieldGroup().addCommitHandler(new CommitHandler() {
private static final long serialVersionUID = -2912534421548359666L;
@Override
public void preCommit(final CommitEvent commitEvent) throws CommitException {
}
@SuppressWarnings("rawtypes")
@Override
public void postCommit(final CommitEvent commitEvent) throws CommitException {
Object smallestValue = getFieldGroup().getItemDataSource().getItemProperty("smallest")
.getValue();
Object biggestValue = getFieldGroup().getItemDataSource().getItemProperty("biggest").getValue();
if (smallestValue != null || biggestValue != null) {
if (smallestValue != null && biggestValue != null && smallestValue.equals(biggestValue)) {
replaceFilter(new Equal(filterPropertyPath, smallestValue), columnId);
} else {
replaceFilter(
new Between(filterPropertyPath,
(Comparable) (smallestValue != null ? smallestValue : getValue(false)),
(Comparable) (biggestValue != null ? biggestValue : getValue(true))),
columnId);
}
} else {
removeFilter(columnId);
}
}
});
}
@Override
public void clearFilter() {
getFieldGroup().clear();
}
};
setCustomFilter(columnId, filter);
return filter.getFieldGroup();
}
/**
* Destroys the filter.
*/
public void destroy() {
grid.removeHeaderRow(getFilterRow());
}
}