blob: b925b6746dca4bc355947be06bd07515b01bc35b [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.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.core.databinding.observable.IObservable;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.databinding.EMFProperties;
import org.eclipse.osbp.blob.component.BlobComponent;
import org.eclipse.osbp.dsl.semantic.dto.util.NamingConventionsUtil;
import org.eclipse.osbp.ecview.core.common.editpart.IConverterEditpart;
import org.eclipse.osbp.ecview.core.common.editpart.IElementEditpart;
import org.eclipse.osbp.ecview.core.common.editpart.emf.ElementEditpart;
import org.eclipse.osbp.ecview.core.common.filter.IFilterablePresentation;
import org.eclipse.osbp.ecview.core.common.filter.IRefreshRowsPresentation;
import org.eclipse.osbp.ecview.core.common.model.binding.YBindingEndpoint;
import org.eclipse.osbp.ecview.core.common.model.core.YEmbeddableBindingEndpoint;
import org.eclipse.osbp.ecview.core.common.model.core.YEmbeddableCollectionEndpoint;
import org.eclipse.osbp.ecview.core.common.model.core.YEmbeddableMultiSelectionEndpoint;
import org.eclipse.osbp.ecview.core.common.model.core.YEmbeddableSelectionEndpoint;
import org.eclipse.osbp.ecview.core.common.model.core.YFlatAlignment;
import org.eclipse.osbp.ecview.core.common.model.datatypes.YDatadescription;
import org.eclipse.osbp.ecview.core.common.notification.ILifecycleHandler;
import org.eclipse.osbp.ecview.core.common.presentation.DelegatingConverterFactory;
import org.eclipse.osbp.ecview.core.databinding.emf.model.ECViewModelBindable;
import org.eclipse.osbp.ecview.core.extension.model.extension.ExtensionModelPackage;
import org.eclipse.osbp.ecview.core.extension.model.extension.YColumn;
import org.eclipse.osbp.ecview.core.extension.model.extension.YSelectionType;
import org.eclipse.osbp.ecview.core.extension.model.extension.YSortColumn;
import org.eclipse.osbp.ecview.core.extension.model.extension.YTable;
import org.eclipse.osbp.ecview.core.ui.core.editparts.extension.ITableEditpart;
import org.eclipse.osbp.runtime.common.annotations.DtoUtils;
import org.eclipse.osbp.runtime.common.annotations.PropertiesUtil;
import org.eclipse.osbp.runtime.common.event.EventDispatcherEvent;
import org.eclipse.osbp.runtime.common.event.EventDispatcherEvent.EventDispatcherCommand;
import org.eclipse.osbp.runtime.common.event.EventDispatcherEvent.EventDispatcherDataTag;
import org.eclipse.osbp.runtime.common.event.IEventDispatcher;
import org.eclipse.osbp.runtime.common.i18n.I18nUtil;
import org.eclipse.osbp.runtime.common.i18n.II18nService;
import org.eclipse.osbp.runtime.common.layouting.IPropertyConstants;
import org.eclipse.osbp.runtime.common.state.ISharedStateContext;
import org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common.AbstractFieldWidgetPresenter;
import org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.internal.util.Util;
import org.eclipse.osbp.runtime.web.vaadin.common.converter.StringToFormattedNumberConverter;
import org.eclipse.osbp.runtime.web.vaadin.common.data.BeanServiceLazyLoadingContainer;
import org.eclipse.osbp.runtime.web.vaadin.common.data.DeepResolvingBeanItem;
import org.eclipse.osbp.runtime.web.vaadin.common.data.DeepResolvingBeanItemContainer;
import org.eclipse.osbp.runtime.web.vaadin.common.data.IBeanSearchService;
import org.eclipse.osbp.runtime.web.vaadin.common.data.IBeanSearchServiceFactory;
import org.eclipse.osbp.runtime.web.vaadin.common.data.IBeanToUniqueHashIdProvider;
import org.eclipse.osbp.runtime.web.vaadin.common.data.ILazyRefreshFilterable;
import org.eclipse.osbp.runtime.web.vaadin.common.data.INestedPropertyAble;
import org.eclipse.osbp.runtime.web.vaadin.common.resource.IResourceProvider;
import org.eclipse.osbp.ui.api.customfields.IBlobService;
import org.eclipse.osbp.ui.api.user.IUser;
import org.eclipse.osbp.xtext.datamart.common.olap.DerivedMember;
import org.eclipse.osbp.xtext.table.common.CellSetIndexedContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vaadin.data.Container;
import com.vaadin.data.Container.Filter;
import com.vaadin.data.Container.Filterable;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.converter.ConverterUtil;
import com.vaadin.server.ErrorMessage;
import com.vaadin.server.Resource;
import com.vaadin.server.ThemeResource;
import com.vaadin.ui.AbstractSelect.ItemCaptionMode;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.Field;
import com.vaadin.ui.Table;
import com.vaadin.ui.Table.Align;
import com.vaadin.ui.Table.ColumnCollapseEvent;
import com.vaadin.ui.Table.ColumnReorderEvent;
import com.vaadin.ui.Table.ColumnResizeEvent;
import com.vaadin.ui.Table.RowHeaderMode;
import com.vaadin.ui.UI;
/**
* This presenter is responsible to render a table on the given layout.
*/
@SuppressWarnings({ "restriction", "serial" })
public class TablePresentation extends AbstractFieldWidgetPresenter<Component>
implements IFilterablePresentation, IRefreshRowsPresentation, IEventDispatcher.Receiver {
private final static Logger log = LoggerFactory.getLogger("eventdispatcher");
/** The model access. */
private final ModelAccess modelAccess;
/** The table. */
private Table table;
/** The property. */
@SuppressWarnings("rawtypes")
private ObjectProperty property;
/** The apply columns. */
private boolean applyColumns;
private boolean containerReadonly;
private AdapterCustom adapter;
private IEventDispatcher eventDispatcher;
private IBlobService blobService;
private ILifecycleHandler handler;
private final String WIDTH_KEY = "width";
private final String COLLAPSED_KEY = "collapsed";
private final String COLUMNS_KEY = "columns";
private String topic;
/**
* Constructor.
*
* @param editpart
* The editpart of that presenter
*/
public TablePresentation(IElementEditpart editpart) {
super((ITableEditpart) editpart);
this.modelAccess = new ModelAccess((YTable) editpart.getModel());
adapter = new AdapterCustom();
this.modelAccess.yField.eAdapters().add(adapter);
}
/**
* {@inheritDoc}
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Component doCreateWidget(Object parent) {
if (table == null) {
table = new CustomTable();
table.addStyleName(CSS_CLASS_CONTROL);
table.setMultiSelect(modelAccess.yField.getSelectionType() == YSelectionType.MULTI);
table.setSelectable(true);
table.setColumnReorderingAllowed(true);
if(modelAccess.yField.getPageLength() > 0) {
table.setPageLength(modelAccess.yField.getPageLength());
}
setupComponent(table, getCastedModel());
Class<?> bean = modelAccess.yField.getType();
if (bean != null) {
eventDispatcher = getViewContext().getService(IEventDispatcher.class.getName());
log.debug("tablepresentation eventdispatcher:{}", eventDispatcher);
blobService = getViewContext().getService(IBlobService.class.getName());
topic = NamingConventionsUtil.toFqnEntityName(bean.getName());
log.debug("tablepresentation eventdispatcher topic:{}", topic);
}
table.addValueChangeListener(new ValueChangeListener() {
@Override
public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) {
MPerspective perspective = getViewContext().getService(MPerspective.class.getName());
EventDispatcherEvent evnt = new EventDispatcherEvent(perspective, EventDispatcherCommand.SELECT, topic + "."
+ DtoUtils.getIdField(bean).getName(),
toString());
Object value = table.getValue();
log.debug("tablepresentation eventdispatcher value:{}", value);
if (value != null) {
if (table.getContainerDataSource() instanceof DeepResolvingBeanItemContainer) {
DeepResolvingBeanItemContainer container = (DeepResolvingBeanItemContainer) table
.getContainerDataSource();
log.debug("tablepresentation eventdispatcher DeepResolvingBeanItemContainer:{}",
container);
DeepResolvingBeanItem<?> item = container.getItem(value);
if (item != null) {
log.debug(
"tablepresentation eventdispatcher DeepResolvingBeanItemContainer id is:{}",
DtoUtils.getIdValue(item.getBean()));
evnt.addItem(EventDispatcherDataTag.ID, DtoUtils.getIdValue(item.getBean()));
eventDispatcher.sendEvent(evnt);
} else {
log.debug(
"tablepresentation eventdispatcher DeepResolvingBeanItemContainer item is null");
}
} else {
log.debug(
"tablepresentation eventdispatcher container is no DeepResolvingBeanItemContainer");
}
} else {
evnt.addItem(EventDispatcherDataTag.ID, null);
eventDispatcher.sendEvent(evnt);
}
}
});
// persists the changed column width into the user properties map
table.addColumnResizeListener(new Table.ColumnResizeListener() {
@Override
public void columnResize(ColumnResizeEvent event) {
YTable ytable = modelAccess.yField;
String tableName = ytable.getId();
// Get the new width of the resized column
int width = event.getCurrentWidth();
// Get the property ID of the resized column
Object columnId = event.getPropertyId();
IUser user = getViewContext().getService(IUser.class.getName());
user.addToProperties(tableName + "." + columnId.toString() + "." + WIDTH_KEY,
String.valueOf(width));
user.persistProperties();
}
});
// persists the changed column order into the user properties map
table.addColumnReorderListener(new Table.ColumnReorderListener() {
@Override
public void columnReorder(ColumnReorderEvent event) {
YTable ytable = modelAccess.yField;
String tableName = ytable.getId();
Object source = event.getSource();
// if (source instanceof CustomTable){
if (source instanceof Table) {
Object[] visibleColumns = ((Table) source).getVisibleColumns();
// if (source instanceof CustomTable){
// Object[] visibleColumns = ((CustomTable)
// source).getVisibleColumns();
String propertyKey = tableName + "." + COLUMNS_KEY;
IUser user = getViewContext().getService(IUser.class.getName());
if (visibleColumns != null) {
user.addToProperties(propertyKey, visibleColumns);
user.persistProperties();
}
}
}
});
// persists the collapsed columns into the user properties map
table.addColumnCollapseListener(new Table.ColumnCollapseListener() {
@Override
public void columnCollapseStateChange(ColumnCollapseEvent event) {
YTable ytable = modelAccess.yField;
String tableName = ytable.getId();
// Get the ID of the column collapse event
Object columnId = event.getPropertyId();
Object source = event.getSource();
IUser user = getViewContext().getService(IUser.class.getName());
String propertyKey = tableName + "." + columnId.toString() + "." + COLLAPSED_KEY;
if (source instanceof CustomTable) {
if (((CustomTable) source).isColumnCollapsed(columnId)) {
user.addToProperties(propertyKey, "true");
user.persistProperties();
} else {
user.removeFromProperties(propertyKey);
user.persistProperties();
}
}
}
});
// Must be immediate to send the resize events immediately
table.setImmediate(true);
associateWidget(table, modelAccess.yField);
if (modelAccess.isCssIdValid()) {
table.setId(modelAccess.getCssID());
} else {
table.setId(getEditpart().getId());
}
if (table.isMultiSelect()) {
property = new ObjectProperty(new HashSet(), Set.class);
} else {
if (modelAccess.yField.getType() != null) {
property = new ObjectProperty(null, modelAccess.yField.getType());
} else {
property = new ObjectProperty(null, Object.class);
}
}
table.setPropertyDataSource(property);
applyColumns = false;
if (modelAccess.yField.getType() == String.class) {
IndexedContainer datasource = new IndexedContainer();
table.setContainerDataSource(datasource);
table.setItemCaptionMode(ItemCaptionMode.ID);
} else {
if (modelAccess.yField.getType() != null) {
IBeanSearchService<?> service = null;
IBeanSearchServiceFactory factory = getViewContext()
.getService(IBeanSearchServiceFactory.class.getName());
if (factory != null) {
service = factory.createService(modelAccess.yField.getType());
}
if (modelAccess.yField.isUseBeanService() && service != null) {
ISharedStateContext sharedState = getViewContext()
.getService(ISharedStateContext.class.getName());
BeanServiceLazyLoadingContainer<?> datasource = new BeanServiceLazyLoadingContainer(service,
modelAccess.yField.getType(), sharedState);
table.setContainerDataSource(datasource);
containerReadonly = true;
} else {
DeepResolvingBeanItemContainer datasource = new DeepResolvingBeanItemContainer(
modelAccess.yField.getType());
table.setContainerDataSource(datasource);
}
applyColumns = true;
} else {
IndexedContainer container = new IndexedContainer();
container.addContainerProperty("for", String.class, null);
container.addContainerProperty("preview", String.class, null);
container.addItem(new String[] { "Some value", "other" });
table.setContainerDataSource(container);
}
}
String itemImageProperty = modelAccess.yField.getItemImageProperty();
if (itemImageProperty != null && !itemImageProperty.equals("")) {
table.setItemIconPropertyId(itemImageProperty);
table.setRowHeaderMode(RowHeaderMode.EXPLICIT);
}
applyCaptions();
// creates the binding for the field
createBindings(modelAccess.yField, table);
if (modelAccess.isCssClassValid()) {
table.addStyleName(modelAccess.getCssClass());
}
// DO NOT MOVE THE FOLLOWING CODE LINES!
// The setting of the column widths from the persisted user
// properties only works after the call of "applyCaptions()"
// due to the possible new creation of the columns in it.
IUser user = getViewContext().getService(IUser.class.getName());
if (user != null) {
for (Object propertyId : table.getContainerDataSource().getContainerPropertyIds()) {
String tableId = modelAccess.yField.getId();
String columnWidthStr = user.getColumnUtil()
.getColumnWidth(tableId + "." + propertyId + "." + WIDTH_KEY);
if (columnWidthStr != null) {
table.setColumnWidth(propertyId, Integer.parseInt(columnWidthStr));
}
String collapsedColumn = user.getColumnUtil()
.getColumnCollapsed(tableId + "." + propertyId + "." + COLLAPSED_KEY);
if (collapsedColumn != null) {
table.setColumnCollapsed(propertyId, true);
} else {
table.setColumnCollapsed(propertyId, false);
}
if (table.getContainerDataSource() instanceof CellSetIndexedContainer){
Map<Object, Integer> visibleColumnsMap = user.getColumnUtil().getVisibleColumns(this.getClass().getCanonicalName() + ".columns");
if (visibleColumnsMap != null){
boolean unmodifiedVisibleColumns = true;
for (Object visibleColumnKey : visibleColumnsMap.keySet()) {
CellSetIndexedContainer container = (CellSetIndexedContainer) table.getContainerDataSource();
// creates a hash code by the column position members
int membersHash = 0;
if (container != null) {
List<DerivedMember> members = container.getColumnPosition(visibleColumnKey).getMembers();
for (DerivedMember member : members) {
membersHash += (member.getUniqueName() != null) ? member.getUniqueName().hashCode() : member.hashCode();
}
}
if (membersHash != visibleColumnsMap.get(visibleColumnKey)) {
unmodifiedVisibleColumns = false;
break;
}
}
if (unmodifiedVisibleColumns) {
try {
Object[] visibleColumns = visibleColumnsMap.values().toArray();
table.setVisibleColumns(visibleColumns );
} catch (IllegalArgumentException e) {
// this occurs if a saved column is no longer existing due to model changes
}
}
}
}
}
}
initializeField(table);
eventDispatcher.addEventReceiver(this);
}
return table;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.ecview.core.common.filter.IRefreshRowsPresentation#
* refreshRows()
*/
@Override
public void refreshRows() {
if (isRendered()) {
table.refreshRowCache();
}
}
/**
* Applies the column setting to the table.
*/
@SuppressWarnings("unchecked")
protected void applyColumns() {
Class<?> type = modelAccess.yField.getType();
// set the visible columns and icons
List<String> columns = new ArrayList<>();
Collection<?> propertyIds = table.getContainerDataSource().getContainerPropertyIds();
if (!modelAccess.yField.getColumns().isEmpty()) {
for (YColumn yColumn : modelAccess.yField.getColumns()) {
if (yColumn.isVisible() && propertyIds.contains(yColumn.getPropertyPath()) || isNestedColumn(yColumn)) {
columns.add(yColumn.getPropertyPath());
}
}
// add nested properties
if (table.getContainerDataSource() instanceof INestedPropertyAble) {
INestedPropertyAble<?> container = (INestedPropertyAble<?>) table.getContainerDataSource();
for (String property : columns) {
if (property.contains(".")) {
container.addNestedContainerProperty(property);
}
}
}
table.setVisibleColumns(columns.toArray(new Object[columns.size()]));
table.setColumnCollapsingAllowed(true);
II18nService i18nService = getViewContext().getService(II18nService.class.getName());
IResourceProvider resourceProvider = (IResourceProvider) getViewContext()
.getService(IResourceProvider.class.getName());
// traverse the columns again and set other properties
for (YColumn yColumn : modelAccess.yField.getColumns()) {
if (yColumn.isVisible()
&& (propertyIds.contains(yColumn.getPropertyPath()) || isNestedColumn(yColumn))) {
String columnId = yColumn.getPropertyPath();
table.setColumnHeader(columnId, getColumnHeader(yColumn));
table.setColumnAlignment(columnId, toAlign(yColumn.getAlignment()));
table.setColumnCollapsed(columnId, yColumn.isCollapsed());
table.setColumnCollapsible(columnId, yColumn.isCollapsible());
if (yColumn.getExpandRatio() >= 0) {
table.setColumnExpandRatio(columnId, yColumn.getExpandRatio());
}
// Boolean check to display a checkbox instead of the
// boolean value as String.
if (yColumn.getType() == Boolean.class) {
// check to avoid an IllegalArgumentException adding an
// already existing ColumnGenerator.
if (table.getColumnGenerator(columnId) == null) {
table.addGeneratedColumn(columnId, new Table.ColumnGenerator() {
@Override
public Component generateCell(Table source, Object itemId, Object columnId) {
Item item = table.getItem(itemId);
CheckBox box = new CheckBox();
box.setEnabled(false);
Boolean value = (Boolean) item.getItemProperty(columnId).getValue();
box.setValue(value);
return box;
}
});
}
}
// --------------
if (yColumn.getIcon() != null && !yColumn.getIcon().equals("")) {
if (i18nService != null) {
String translation = i18nService.getValue(yColumn.getIcon(), UI.getCurrent().getLocale());
if (translation != null && !translation.equals("")) {
Resource icon = resourceProvider.getResource(translation);
if (icon != null) {
table.setColumnIcon(columnId, icon);
}
}
} else {
table.setColumnIcon(columnId, resourceProvider.getResource(yColumn.getIcon()));
}
}
// Blob check to display a blob image
if ((yColumn.getType() == String.class)
&& ((yColumn.getProperties() != null) || (!yColumn.getProperties().isEmpty()))) {
Stream<Entry<String, String>> propertyStream = yColumn.getProperties().stream()
.filter(prop -> prop.getKey().equalsIgnoreCase(IPropertyConstants.PROPERTY_BLOB));
// Only if one 'Blob' or 'blob' property entry exists
if (propertyStream.count() == 1) {
String displayResolution = yColumn.getProperties().stream()
.filter(prop -> prop.getKey().equalsIgnoreCase(IPropertyConstants.PROPERTY_BLOB))
.map(p -> p.getValue()).collect(Collectors.joining());
// check to avoid an IllegalArgumentException adding
// an
// already existing ColumnGenerator.
if (table.getColumnGenerator(columnId) == null) {
table.addGeneratedColumn(columnId, new Table.ColumnGenerator() {
@Override
public Component generateCell(Table source, Object itemId, Object columnId) {
Item item = table.getItem(itemId);
return new BlobComponent(blobService,
(String) item.getItemProperty(columnId).getValue(),
Integer.parseInt(displayResolution));
}
});
}
}
}
}
}
// apply the converters
//
for (YColumn yColumn : modelAccess.yField.getColumns()) {
if (yColumn.getConverter() == null) {
// try to derive the converter from the datatype property at
// field level
String columnId = yColumn.getPropertyPath();
Class<?> resultClass = table.getContainerDataSource().getType(columnId);
if (Number.class.isAssignableFrom(resultClass)
&& PropertiesUtil.hasKey(type, columnId, "decimalformat")) {
String format = PropertiesUtil.getValue(type, columnId, "decimalformat");
if (format != null && !format.isEmpty()) {
table.setConverter(columnId, new StringToFormattedNumberConverter(format,
(Class<? extends Number>) resultClass));
}
}
} else {
@SuppressWarnings("rawtypes")
Converter converter = (Converter) DelegatingConverterFactory.getInstance().createConverter(
getViewContext(),
(IConverterEditpart) ElementEditpart.getEditpart(getViewContext(), yColumn.getConverter()));
if (converter != null) {
String columnId = yColumn.getPropertyPath();
table.setConverter(columnId, converter);
}
}
}
}
// apply the sort order
applySortOrder();
applyCellStyles();
}
@SuppressWarnings("serial")
protected void applyCellStyles() {
table.setCellStyleGenerator(new Table.CellStyleGenerator() {
@Override
public String getStyle(Table source, Object itemId, Object propertyId) {
if (itemId == null || propertyId == null) {
return "";
}
if (Number.class.isAssignableFrom(source.getContainerDataSource().getType(propertyId))) {
return " v-align-right";
}
return "";
}
});
}
protected void applySortOrder() {
if (!modelAccess.yField.getSortOrder().isEmpty()
&& table.getContainerDataSource() instanceof Container.Sortable) {
List<String> sortCol = new ArrayList<>();
List<Boolean> sortDirection = new ArrayList<>();
for (YSortColumn yColumn : modelAccess.yField.getSortOrder()) {
// add the nested sort columns to the container
if (isNestedColumn(yColumn)) {
if (table.getContainerDataSource() instanceof INestedPropertyAble) {
INestedPropertyAble<?> container = (INestedPropertyAble<?>) table.getContainerDataSource();
container.addNestedContainerProperty(yColumn.getPropertyPath());
}
}
sortCol.add(yColumn.getPropertyPath());
sortDirection.add(yColumn.isAsc());
}
Container.Sortable sortable = (Container.Sortable) table.getContainerDataSource();
boolean[] asc = new boolean[sortDirection.size()];
for (int i = 0; i < sortDirection.size(); i++) {
asc[i] = sortDirection.get(i);
}
sortable.sort(sortCol.toArray(new String[sortCol.size()]), asc);
if (!sortCol.isEmpty()) {
table.setSortContainerPropertyId(sortCol.get(0));
table.setSortAscending(asc[0]);
}
}
}
public void doSort() {
if (table != null) {
table.sort();
}
}
/**
* Gets the dirty property.
*
* @param type
* the type
* @return the dirty property
*/
protected String getDirtyProperty(Class<?> type) {
String temp = null;
java.lang.reflect.Field dirtyField = DtoUtils.getDirtyField(type);
if (dirtyField != null) {
temp = dirtyField.getName();
}
return temp;
}
/**
* Checks if is nested column.
*
* @param yColumn
* the y column
* @return true, if is nested column
*/
protected boolean isNestedColumn(YColumn yColumn) {
return yColumn.getPropertyPath() != null && yColumn.getPropertyPath().contains(".");
}
/**
* Checks if is nested column.
*
* @param yColumn
* the y column
* @return true, if is nested column
*/
protected boolean isNestedColumn(YSortColumn yColumn) {
return yColumn.getPropertyPath() != null && yColumn.getPropertyPath().contains(".");
}
/**
* Returns the column header.
*
* @param yColumn
* the y column
* @return the column header
*/
private String getColumnHeader(YColumn yColumn) {
YDatadescription yDt = yColumn.getDatadescription();
if (yDt == null) {
return yColumn.getPropertyPath();
}
String result = null;
II18nService service = getI18nService();
if (service != null && yDt.getLabelI18nKey() != null) {
result = service.getValue(yDt.getLabelI18nKey(), getLocale());
}
if (result == null || result.equals("")) {
result = yDt.getLabel();
}
if (result == null || result.equals("")) {
result = yColumn.getPropertyPath();
}
return result;
}
/**
* To align.
*
* @param alignment
* the alignment
* @return the align
*/
private Align toAlign(YFlatAlignment alignment) {
switch (alignment) {
case LEFT:
return Align.LEFT;
case CENTER:
return Align.CENTER;
case RIGHT:
return Align.RIGHT;
}
return Align.LEFT;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common.
* AbstractVaadinWidgetPresenter#doUpdateLocale(java.util.Locale)
*/
@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() {
// applies the column properties
if (applyColumns) {
applyColumns();
}
Util.applyCaptions(getI18nService(), modelAccess.getLabel(), modelAccess.getLabelI18nKey(), getLocale(), table);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.ecview.core.common.filter.IFilterablePresentation#
* applyFilter(java.lang.Object)
*/
@Override
public void applyFilter(Object filter) {
Container container = table.getContainerDataSource();
if (container instanceof Container.Filterable) {
Container.Filterable filterable = (Filterable) container;
filterable.removeAllContainerFilters();
if (filter != null) {
filterable.addContainerFilter((Filter) filter);
} else if (container instanceof ILazyRefreshFilterable) {
ILazyRefreshFilterable lazyFilterable = (ILazyRefreshFilterable) container;
lazyFilterable.removeAllContainerFilters();
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common.
* AbstractFieldWidgetPresenter#doGetField()
*/
@Override
protected Field<?> doGetField() {
return table;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common.
* AbstractVaadinWidgetPresenter
* #internalGetObservableEndpoint(org.eclipse.osbp
* .ecview.core.common.model.core.YEmbeddableBindingEndpoint)
*/
@Override
protected IObservable internalGetObservableEndpoint(YEmbeddableBindingEndpoint bindableValue) {
if (bindableValue == null) {
throw new IllegalArgumentException("BindableValue must not be null!");
}
if (bindableValue instanceof YEmbeddableCollectionEndpoint) {
addAutoBindingEndpoint((YBindingEndpoint) bindableValue);
return internalGetCollectionEndpoint();
} else if (bindableValue instanceof YEmbeddableSelectionEndpoint) {
return internalGetSelectionEndpoint((YEmbeddableSelectionEndpoint) bindableValue);
} else if (bindableValue instanceof YEmbeddableMultiSelectionEndpoint) {
return internalGetMultiSelectionEndpoint();
}
throw new IllegalArgumentException("Not a valid input: " + bindableValue);
}
/**
* Returns the observable to observe the collection.
*
* @return the i observable list
*/
protected IObservableList internalGetCollectionEndpoint() {
// return the observable value for text
return EMFProperties.list(ExtensionModelPackage.Literals.YTABLE__COLLECTION).observe(getModel());
}
/**
* Returns the observable to observe the selection.
*
* @param yEndpoint
* the y endpoint
* @return the i observable value
*/
protected IObservableValue internalGetSelectionEndpoint(YEmbeddableSelectionEndpoint yEndpoint) {
String attributePath = ECViewModelBindable.getAttributePath(ExtensionModelPackage.Literals.YTABLE__SELECTION,
yEndpoint.getAttributePath());
// return the observable value for text
return ECViewModelBindable.observeValue(castEObject(getModel()), attributePath, modelAccess.yField.getType(),
modelAccess.yField.getEmfNsURI());
}
/**
* Returns the observable to observe the selection.
*
* @return the i observable list
*/
protected IObservableList internalGetMultiSelectionEndpoint() {
// return the observable value for text
return EMFProperties.list(ExtensionModelPackage.Literals.YTABLE__MULTI_SELECTION).observe(getModel());
}
/**
* Creates the bindings for the given values.
*
* @param yField
* the y field
* @param field
* the field
*/
protected void createBindings(YTable yField, Table field) {
// create the model binding from ridget to ECView-model
registerBinding(createBindingsContainerContents(castEObject(getModel()),
ExtensionModelPackage.Literals.YTABLE__COLLECTION, field, yField.getType(), containerReadonly));
// create the model binding from ridget to ECView-model
if (modelAccess.yField.getSelectionType() == YSelectionType.MULTI) {
// create the model binding from ridget to ECView-model
registerBinding(createBindingsMultiSelection(castEObject(getModel()),
ExtensionModelPackage.Literals.YTABLE__MULTI_SELECTION, field, yField.getType()));
} else {
// create the model binding from ridget to ECView-model
registerBinding(createBindingsSelection(castEObject(getModel()),
ExtensionModelPackage.Literals.YTABLE__SELECTION, field, yField.getType()));
}
super.createBindings(yField, field, null);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.osbp.ecview.core.common.presentation.IWidgetPresentation#
* getWidget()
*/
@Override
public Component getWidget() {
return table;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.osbp.ecview.core.common.presentation.IWidgetPresentation#
* isRendered()
*/
@Override
public boolean isRendered() {
return table != null;
}
/**
* {@inheritDoc}
*/
@Override
public void doUnrender() {
if (table != null) {
// unbind all active bindings
unbind();
Component parent = (table.getParent());
if (parent != null && parent instanceof ComponentContainer) {
((ComponentContainer) parent).removeComponent(table);
}
// remove assocations
unassociateWidget(table);
eventDispatcher.removeEventReceiver(this);
table = null;
}
}
/**
* {@inheritDoc}
*/
@Override
protected void internalDispose() {
try {
unrender();
modelAccess.yField.eAdapters().remove(adapter);
} finally {
super.internalDispose();
}
}
/**
* A helper class.
*/
private static class ModelAccess {
/** The y field. */
private final YTable yField;
/**
* Instantiates a new model access.
*
* @param yField
* the y field
*/
public ModelAccess(YTable yField) {
super();
this.yField = yField;
}
/**
* Gets the css class.
*
* @return the css class
* @see org.eclipse.osbp.ecview.core.ui.core.model.core.YCssAble#getCssClass()
*/
public String getCssClass() {
return yField.getCssClass();
}
/**
* Returns true, if the css class is not null and not empty.
*
* @return true, if is css class valid
*/
public boolean isCssClassValid() {
return getCssClass() != null && !getCssClass().equals("");
}
/**
* Gets the css id.
*
* @return the css id
* @see org.eclipse.osbp.ecview.core.ui.core.model.core.YCssAble#getCssID()
*/
public String getCssID() {
return yField.getCssID();
}
/**
* Returns true, if the css id is not null and not empty.
*
* @return true, if is css id valid
*/
public boolean isCssIdValid() {
return getCssID() != null && !getCssID().equals("");
}
/**
* Returns the label.
*
* @return the label
*/
public String getLabel() {
return yField.getDatadescription() != null ? yField.getDatadescription().getLabel() : null;
}
/**
* Returns the label.
*
* @return the label i18n key
*/
public String getLabelI18nKey() {
return yField.getDatadescription() != null ? yField.getDatadescription().getLabelI18nKey() : null;
}
}
/**
* Converts the string value of the item icon property to
* {@link ThemeResource}.
*/
@SuppressWarnings("serial")
private class CustomTable extends Table {
/** The item icon property id. */
private Object itemIconPropertyId;
private String itemIdHash;
private boolean updateMode;
private Timer sortTimer;
private boolean isSorting;
@SuppressWarnings("unchecked")
CustomTable() {
addValueChangeListener(e -> {
if (getContainerDataSource() instanceof IBeanToUniqueHashIdProvider) {
IBeanToUniqueHashIdProvider<Object> hashIdProvider = (IBeanToUniqueHashIdProvider<Object>) getContainerDataSource();
Object selection = e.getProperty().getValue();
this.itemIdHash = hashIdProvider.getUniqueHashId(selection);
}
});
addItemSetChangeListener(e -> {
if (isSorting || getSortContainerPropertyId() == null || getUI() == null) {
return;
}
if (sortTimer != null) {
sortTimer.cancel();
}
sortTimer = new Timer();
sortTimer.schedule(new TimerTask() {
@Override
public void run() {
try {
isSorting = true;
getUI().accessSynchronously(() -> {
sort();
if (modelAccess.yField.isScrollToBottom()) {
setCurrentPageFirstItemIndex(size() - 1);
}
});
} finally {
isSorting = false;
}
}
}, 125);
});
}
/*
* (non-Javadoc)
*
* @see
* com.vaadin.ui.AbstractSelect#setItemIconPropertyId(java.lang.Object)
*/
@Override
public void setItemIconPropertyId(Object propertyId) throws IllegalArgumentException {
if (propertyId == null) {
super.setItemIconPropertyId(propertyId);
} else if (!getContainerPropertyIds().contains(propertyId)) {
// super.setItemIconPropertyId(propertyId);
} else if (String.class.isAssignableFrom(getType(propertyId))) {
itemIconPropertyId = propertyId;
} else {
super.setItemIconPropertyId(propertyId);
}
}
/*
* (non-Javadoc)
*
* @see com.vaadin.ui.AbstractSelect#getItemIconPropertyId()
*/
@Override
public Object getItemIconPropertyId() {
return itemIconPropertyId != null ? itemIconPropertyId : super.getItemIconPropertyId();
}
/*
* (non-Javadoc)
*
* @see com.vaadin.ui.AbstractSelect#getItemIcon(java.lang.Object)
*/
@Override
public Resource getItemIcon(Object itemId) {
if (itemIconPropertyId == null) {
return super.getItemIcon(itemId);
} else {
final Property<?> ip = getContainerProperty(itemId, getItemIconPropertyId());
if (ip == null) {
return null;
}
final Object icon = ip.getValue();
if (icon instanceof String) {
return new ThemeResource((String) icon);
}
}
return null;
}
/*
* (non-Javadoc)
*
* @see com.vaadin.ui.Table#formatPropertyValue(java.lang.Object,
* java.lang.Object, com.vaadin.data.Property)
*/
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
protected String formatPropertyValue(Object rowId, Object colId, Property<?> property) {
if (property == null) {
return "";
}
Converter<String, Object> converter = null;
if (hasConverter(colId)) {
converter = getConverter(colId);
} else {
converter = (Converter) ConverterUtil.getConverter(String.class, property.getType(), getSession());
}
Object value = property.getValue();
if (converter != null) {
return converter.convertToPresentation(value, String.class, getLocale());
} else {
if (value instanceof Enum<?>) {
return I18nUtil.translateEnum(getI18nService(), value, getLocale());
} else if (value instanceof Boolean) {
return I18nUtil.translateBoolean(getI18nService(), (Boolean) value, getLocale());
} else if (value instanceof Number) {
return I18nUtil.translateNumber(getI18nService(), (Number) value, getLocale());
}
}
return (null != value) ? value.toString() : "";
}
/*
* (non-Javadoc)
*
* @see com.vaadin.ui.AbstractField#getErrorMessage()
*/
@Override
public ErrorMessage getErrorMessage() {
if (isDisposed()) {
// after disposal, Vaadin will call this method once.
return null;
}
ErrorMessage message = super.getErrorMessage();
reportValidationError(message);
return message;
}
/*
* (non-Javadoc)
*
* @see com.vaadin.ui.AbstractField#focus()
*/
@Override
public void focus() {
super.focus();
setValue(getCurrentPageFirstItemId());
}
@Override
@SuppressWarnings("unchecked")
public void setContainerDataSource(Container newDataSource) {
super.setContainerDataSource(newDataSource);
if (getContainerDataSource() instanceof DeepResolvingBeanItemContainer) {
@SuppressWarnings("rawtypes")
final DeepResolvingBeanItemContainer ds = (DeepResolvingBeanItemContainer) getContainerDataSource();
ds.addItemSetChangeListener(e -> {
// lazy update the table selection
if (!updateMode && itemIdHash != null) {
updateMode = true;
final String targetItemIdHash = itemIdHash;
getUI().accessSynchronously(() -> {
for (Object itemId : e.getContainer().getItemIds()) {
if (targetItemIdHash.equals(ds.getUniqueHashId(itemId))) {
table.setValue(itemId);
break;
}
}
updateMode = false;
});
}
});
}
}
}
private class AdapterCustom extends AdapterImpl {
@Override
public void notifyChanged(Notification notification) {
int featureId = notification.getFeatureID(YTable.class);
switch (notification.getEventType()) {
case Notification.SET:
if (featureId == ExtensionModelPackage.YTABLE__DO_SORT) {
doSort();
}
break;
default:
}
}
}
@Override
public void receiveEvent(EventDispatcherEvent event) {
switch (event.getCommand()) {
case REFRESH:
case SAVE:
if(event.getTopic().equals(topic)) {
refreshRows();
}
break;
case DELETE:
// we have to remove the item manually
if(event.getTopic().equals(topic)) {
for(Object item:table.getItemIds()) {
if(event.getData().get(EventDispatcherDataTag.ID).equals(DtoUtils.getIdValue(item))) {
table.removeItem(item);
refreshRows();
break;
}
}
}
break;
default:
break;
}
}
}