| /** |
| * |
| * 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()); |
| } |
| |
| } |