blob: fba4eb0e2d32559bc431e75d482362684545ac6e [file] [log] [blame]
/**
* Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), 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 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Florian Pirchner - Initial implementation
*/
package org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.internal;
import java.util.Date;
import java.util.Locale;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.osbp.ecview.core.common.context.IViewContext;
import org.eclipse.osbp.ecview.core.common.editpart.IElementEditpart;
import org.eclipse.osbp.ecview.core.common.editpart.IEmbeddableEditpart;
import org.eclipse.osbp.ecview.core.common.filter.IFilterProvidingPresentation;
import org.eclipse.osbp.ecview.core.extension.model.extension.ExtensionModelPackage;
import org.eclipse.osbp.ecview.core.extension.model.extension.YFilterDescriptor;
import org.eclipse.osbp.ecview.core.extension.model.extension.YFilterTableDescriptor;
import org.eclipse.osbp.ecview.core.extension.model.extension.YFilteringComponent;
import org.eclipse.osbp.runtime.common.util.BeanUtils;
import org.eclipse.osbp.runtime.designer.api.IDesignerService.DesignEvent;
import org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common.AbstractEmbeddedWidgetPresenter;
import org.eclipse.osbp.runtime.web.vaadin.components.fields.filter2.FilteringComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This presenter is responsible to render a text field on the given layout.
*/
public class FilteringComponentPresentation<T> extends AbstractEmbeddedWidgetPresenter<FilteringComponent<T>>
implements IFilterProvidingPresentation {
@SuppressWarnings("unused")
private static final Logger LOGGER = LoggerFactory.getLogger(FilteringComponentPresentation.class);
private FilteringComponent<T> layout;
private ModelAccess modelAccess;
private int currentChildIndex;
private Adapter adapter;
private Binding filterBinding;
/**
* The constructor.
*
* @param editpart
* The editpart of that editpart.
*/
public FilteringComponentPresentation(IElementEditpart editpart) {
super((IEmbeddableEditpart) editpart);
this.modelAccess = new ModelAccess((YFilteringComponent) editpart.getModel());
}
@Override
protected void doUpdateLocale(Locale locale) {
// no need to set the locale to the ui elements. Is handled by vaadin
// internally.
// update the captions
applyCaptions();
}
/**
* Applies the labels to the widgets.
*/
protected void applyCaptions() {
}
/**
* Is called to refresh the UI. The element will be removed from the layout
* and added to it again afterwards.
*/
protected void refreshUI() {
// iterate all elements and build the child element
//
currentChildIndex = 0;
unrenderChildren();
renderChildren();
}
private void addFilter(YFilterDescriptor child) {
currentChildIndex++;
switch (child.getType()) {
case COMPARE:
if (isString(child)) {
layout.addCompareTextComponent(child.getPropertyPath(), currentChildIndex);
} else if (isDecimal(child)) {
layout.addCompareDecimalComponent(child.getPropertyPath(), toDecimalType(child), currentChildIndex);
} else if (isDate(child)) {
layout.addCompareDateComponent(child.getPropertyPath(), currentChildIndex);
} else if (isBoolean(child)) {
layout.addCompareBooleanComponent(child.getPropertyPath(), currentChildIndex);
}
break;
case RANGE:
if (isString(child)) {
layout.addBetweenTextComponent(child.getPropertyPath(), currentChildIndex);
} else if (isDecimal(child)) {
layout.addBetweenDecimalComponent(child.getPropertyPath(), toCompareType(child), currentChildIndex);
} else if (isDate(child)) {
layout.addBetweenDateComponent(child.getPropertyPath(), currentChildIndex);
}
break;
}
}
private void addColumn(YFilterTableDescriptor desc) {
layout.addGridColumn(desc.getPropertyPath());
}
private Class<?> getType(YFilterDescriptor child) {
Class<?> rootType = modelAccess.yLayout.getType();
return BeanUtils.getNestedFieldType(rootType, child.getPropertyPath());
}
private boolean isBoolean(YFilterDescriptor child) {
Class<?> type = getType(child);
return type == Boolean.class || type == Boolean.TYPE;
}
private boolean isDate(YFilterDescriptor child) {
Class<?> type = getType(child);
return Date.class.isAssignableFrom(type);
}
private boolean isDecimal(YFilterDescriptor child) {
Class<?> type = getType(child);
return type != String.class && type != Boolean.class && type != Boolean.TYPE
&& (type.isPrimitive() || Number.class.isAssignableFrom(type));
}
private boolean isString(YFilterDescriptor child) {
Class<?> type = getType(child);
return type == String.class;
}
@SuppressWarnings("unchecked")
private <X extends Number & Comparable<?>> Class<X> toCompareType(YFilterDescriptor child) {
return (Class<X>) getType(child);
}
@SuppressWarnings("unchecked")
private Class<? extends Number> toDecimalType(YFilterDescriptor child) {
return (Class<? extends Number>) getType(child);
}
@SuppressWarnings("unchecked")
@Override
public FilteringComponent<T> doCreateWidget(Object parent) {
if (layout == null) {
layout = new FiltersComponentCustom(getViewContext(), (Class<T>) modelAccess.yLayout.getType(),
modelAccess.yLayout.getFilterCols(), modelAccess.yLayout.isHideGrid());
setupComponent(layout, getCastedModel());
associateWidget(layout, modelAccess.yLayout);
if (modelAccess.isCssIdValid()) {
layout.setId(modelAccess.getCssID());
} else {
layout.setId(getEditpart().getId());
}
if (modelAccess.isCssClassValid()) {
layout.addStyleName(modelAccess.getCssClass());
} else {
layout.addStyleName(CSS_CLASS_CONTROL);
}
// creates the binding for the field
createBindings(modelAccess.yLayout, layout);
// initialize all children
refreshUI();
adapter = new Adapter(modelAccess.yLayout);
// create the bean slot eager
getViewContext().createBeanSlot(modelAccess.yLayout.getSelectionBeanSlotName(),
modelAccess.yLayout.getType());
// set the selection into the proper beanslot
layout.setSelectionConsumer((s) -> {
getViewContext().setBean(modelAccess.yLayout.getSelectionBeanSlotName(), s);
});
}
return layout;
}
protected void createBindings(YFilteringComponent yField, FilteringComponent<T> field) {
{
// filter property
UpdateValueStrategy modelToTarget = new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER);
UpdateValueStrategy targetToModel = new UpdateValueStrategy(UpdateValueStrategy.POLICY_ON_REQUEST);
filterBinding = createBindingsByAccessor(castEObject(getModel()),
ExtensionModelPackage.Literals.YFILTERING_COMPONENT__FILTER, layout, "filter", targetToModel,
modelToTarget);
registerBinding(filterBinding);
}
{
// apply filter property
UpdateValueStrategy modelToTarget = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE);
UpdateValueStrategy targetToModel = new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER);
Binding binding = createBindingsByAccessor(castEObject(getModel()),
ExtensionModelPackage.Literals.YFILTERING_COMPONENT__APPLY_FILTER, this, "applyFilter",
targetToModel, modelToTarget);
registerBinding(binding);
}
{
// reset filter property
UpdateValueStrategy modelToTarget = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE);
UpdateValueStrategy targetToModel = new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER);
Binding binding = createBindingsByAccessor(castEObject(getModel()),
ExtensionModelPackage.Literals.YFILTERING_COMPONENT__RESET_FILTER, this, "resetFilter",
targetToModel, modelToTarget);
registerBinding(binding);
}
super.createBindings(yField, field, null);
}
// helper methods for binding
public void setApplyFilter(Object value) {
layout.applyFilters();
}
// helper methods for binding
public Object getApplyFilter() {
return new Date();
}
// helper methods for binding
public void setResetFilter(Object value) {
layout.resetAllFilters();
}
// helper methods for binding
public Object getResetFilter() {
return new Date();
}
protected void renderChildren() {
for (YFilterDescriptor desc : modelAccess.yLayout.getFilterDescriptors()) {
addFilter(desc);
}
for (YFilterTableDescriptor desc : modelAccess.yLayout.getTableDescriptors()) {
addColumn(desc);
}
}
protected void unrenderChildren() {
layout.removeAllComponents();
}
@Override
public Object getFilter() {
return layout.getFilter();
}
@Override
public FilteringComponent<T> getWidget() {
return layout;
}
@Override
public boolean isRendered() {
return layout != null;
}
@Override
protected void internalDispose() {
try {
unrender();
} finally {
super.internalDispose();
}
}
@Override
public void doUnrender() {
if (layout != null) {
filterBinding.dispose();
filterBinding = null;
adapter.dispose();
adapter = null;
// unbind all active bindings
unbind();
// remove assocations
unassociateWidget(layout);
unrenderChildren();
layout.dispose();
layout = null;
}
}
@Override
public void notify(DesignEvent event) {
// nothing to do
}
/**
* An internal helper class.
*/
private static class ModelAccess {
private final YFilteringComponent yLayout;
public ModelAccess(YFilteringComponent yLayout) {
super();
this.yLayout = yLayout;
}
/**
* @return
* @see org.eclipse.osbp.ecview.core.ui.core.model.core.YCssAble#getCssClass()
*/
public String getCssClass() {
return yLayout.getCssClass();
}
/**
* Returns true, if the css class is not null and not empty.
*
* @return
*/
public boolean isCssClassValid() {
return getCssClass() != null && !getCssClass().equals("");
}
/**
* @return
* @see org.eclipse.osbp.ecview.core.ui.core.model.core.YCssAble#getCssID()
*/
public String getCssID() {
return yLayout.getCssID();
}
/**
* Returns true, if the css id is not null and not empty.
*
* @return
*/
public boolean isCssIdValid() {
return getCssID() != null && !getCssID().equals("");
}
}
class Adapter extends AdapterImpl {
final YFilteringComponent component;
Adapter(YFilteringComponent component) {
this.component = component;
component.eAdapters().add(this);
}
@Override
public void notifyChanged(Notification msg) {
if (msg.getFeature() == ExtensionModelPackage.Literals.YFILTERING_COMPONENT__FILTER_DESCRIPTORS) {
refreshUI();
} else if (msg.getFeature() == ExtensionModelPackage.Literals.YFILTERING_COMPONENT__TABLE_DESCRIPTORS) {
refreshUI();
}
}
void dispose() {
component.eAdapters().remove(this);
}
}
@SuppressWarnings("serial")
class FiltersComponentCustom extends FilteringComponent<T> {
public FiltersComponentCustom(IViewContext viewContext, Class<T> type, boolean hideGrid) {
super(viewContext, type, hideGrid);
}
public FiltersComponentCustom(IViewContext viewContext, Class<T> rootType, int filterCols, boolean hideGrid) {
super(viewContext, rootType, filterCols, hideGrid);
}
private Object resetFilters;
private Object applyFilters;
// binding support
public Object getResetFilters() {
return resetFilters;
}
// binding support
public void setResetFilters(Object resetFilters) {
this.resetFilters = resetFilters;
super.resetAllFilters();
}
// binding support
public Object getApplyFilters() {
return applyFilters;
}
public void applyFilters() {
super.applyFilters();
// invoke the filter binding to update the model
filterBinding.updateTargetToModel();
}
// binding support
public void setApplyFilters(Object applyFilters) {
this.applyFilters = applyFilters;
// invoke the filter binding to update the model
filterBinding.updateTargetToModel();
}
}
}