blob: d275533c908e406fe1cf1563c33f7f07de090ee6 [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 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.ecview.extension.grid.presentation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.eclipse.core.databinding.Binding;
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.core.databinding.observable.value.WritableValue;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
import org.eclipse.e4.ui.model.application.ui.advanced.impl.PerspectiveImpl;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.databinding.EMFObservables;
import org.eclipse.emf.databinding.EMFProperties;
import org.eclipse.emf.ecore.EStructuralFeature;
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.editpart.IFieldEditpart;
import org.eclipse.osbp.ecview.core.common.model.binding.YBindingEndpoint;
import org.eclipse.osbp.ecview.core.common.model.core.YConverter;
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.YField;
import org.eclipse.osbp.ecview.core.databinding.emf.model.ECViewModelBindable;
import org.eclipse.osbp.ecview.core.extension.model.extension.YSearchField;
import org.eclipse.osbp.ecview.core.extension.model.extension.YSelectionType;
import org.eclipse.osbp.ecview.core.ui.core.editparts.extension.ISearchFieldEditpart;
import org.eclipse.osbp.ecview.core.util.emf.ModelUtil;
import org.eclipse.osbp.ecview.extension.grid.CxGrid;
import org.eclipse.osbp.ecview.extension.grid.CxGridCellStyleGenerator;
import org.eclipse.osbp.ecview.extension.grid.CxGridColumn;
import org.eclipse.osbp.ecview.extension.grid.CxGridFactory;
import org.eclipse.osbp.ecview.extension.grid.CxGridFooterRow;
import org.eclipse.osbp.ecview.extension.grid.CxGridGroupable;
import org.eclipse.osbp.ecview.extension.grid.CxGridGroupedCell;
import org.eclipse.osbp.ecview.extension.grid.CxGridHeaderRow;
import org.eclipse.osbp.ecview.extension.grid.CxGridMetaCell;
import org.eclipse.osbp.ecview.extension.grid.CxGridPackage;
import org.eclipse.osbp.ecview.extension.grid.CxGridSortable;
import org.eclipse.osbp.ecview.extension.grid.editparts.IGridCellStyleGeneratorEditpart;
import org.eclipse.osbp.ecview.extension.grid.editparts.IGridColumnEditpart;
import org.eclipse.osbp.ecview.extension.grid.editparts.IGridEditpart;
import org.eclipse.osbp.ecview.extension.grid.editparts.presentation.IGridPresentation;
import org.eclipse.osbp.ecview.extension.grid.memento.CxGridMemento;
import org.eclipse.osbp.ecview.extension.grid.memento.CxGridMementoColumn;
import org.eclipse.osbp.ecview.extension.grid.memento.CxGridMementoFactory;
import org.eclipse.osbp.ecview.extension.grid.memento.CxGridMementoSortable;
import org.eclipse.osbp.ecview.extension.grid.renderer.CxGridNestedConverter;
import org.eclipse.osbp.runtime.common.annotations.DtoUtils;
import org.eclipse.osbp.runtime.common.dispose.AbstractDisposable;
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.II18nService;
import org.eclipse.osbp.runtime.common.state.ISharedStateContext;
import org.eclipse.osbp.runtime.designer.api.IDesignerService.IDesignListener;
import org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.IBindingManager;
import org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common.AbstractEmbeddedWidgetPresenter;
import org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.internal.util.Util;
import org.eclipse.osbp.runtime.web.vaadin.common.data.BeanServiceLazyLoadingContainer;
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.INestedPropertyAble;
import org.eclipse.osbp.runtime.web.vaadin.components.fields.search.ISearchField;
import org.eclipse.osbp.runtime.web.vaadin.databinding.VaadinProperties;
import org.eclipse.osbp.runtime.web.vaadin.databinding.values.IVaadinObservableList;
import org.eclipse.osbp.runtime.web.vaadin.databinding.values.IVaadinObservableValue;
import org.eclipse.osbp.runtime.web.vaadin.databinding.values.SetToListAdapter;
import org.eclipse.osbp.ui.api.user.IUser;
import org.eclipse.osbp.ui.api.useraccess.IUserAccessService;
import org.eclipse.osbp.ui.api.useraccess.AbstractAuthorization.Action;
import org.eclipse.osbp.ui.api.useraccess.AbstractAuthorization.Group;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vaadin.data.Container;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.fieldgroup.FieldGroup.CommitEvent;
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
import com.vaadin.data.sort.Sort;
import com.vaadin.data.sort.SortOrder;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.filter.And;
import com.vaadin.data.util.filter.Compare;
import com.vaadin.event.SortEvent;
import com.vaadin.shared.data.sort.SortDirection;
import com.vaadin.ui.Component;
import com.vaadin.ui.Field;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.Column;
import com.vaadin.ui.Grid.ColumnReorderEvent;
import com.vaadin.ui.Grid.ColumnVisibilityChangeEvent;
import com.vaadin.ui.Grid.FooterRow;
import com.vaadin.ui.Grid.HeaderRow;
import com.vaadin.ui.renderers.Renderer;
/**
* This presenter is responsible to render a text field on the given layout.
*/
public class GridPresentation extends AbstractEmbeddedWidgetPresenter<Grid> implements IGridPresentation<Grid>, // NOSONAR
IDesignListener {
/** The Constant LOGGER. */
private static final Logger LOGGER = LoggerFactory.getLogger(GridPresentation.class);
/** The grid. */
private CustomGrid grid;
/** The model access. */
private ModelAccess modelAccess;
/** The user changed handler. */
private UserChangedHandler userChangedHandler = new UserChangedHandler();
/** The create columns. */
private boolean createColumns;
/** The columns. */
private Set<ColumnWrapper> columns = new HashSet<>();
/** The grouping headers. */
private Map<CxGridHeaderRow, HeaderRow> groupingHeaders = new HashMap<>();
/** The grouping footers. */
private Map<CxGridFooterRow, FooterRow> groupingFooters = new HashMap<>();
/** The filtering header. */
private HeaderRow filteringHeader;
/** The filtering header fields. */
private Map<CxGridColumn, ISearchFieldEditpart> filteringHeaderFields = new HashMap<>();
/** The selection binding. */
private Binding selectionBinding;
/** The filter changed tracker. */
// to handle changed filters
private WritableValue filterChangedTracker;
/** The current memento. */
private CxGridMemento currentMemento;
/** The cell filters. */
private GridCellFilter cellFilters;
/**
* The constructor.
*
* @param editpart
* The editpart of that editpart.
*/
public GridPresentation(IElementEditpart editpart) {
super((IGridEditpart) editpart);
this.modelAccess = new ModelAccess((CxGrid) editpart.getModel());
}
/*
* (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 (createColumns) {
createColumns();
}
Util.applyCaptions(getI18nService(), modelAccess.getLabel(), modelAccess.getLabelI18nKey(), getLocale(), grid);
grid.setEditorCancelCaption(Util.getCaption(getI18nService(), "Cancel",
modelAccess.yField.getEditorCancelI18nLabelKey(), getLocale()));
grid.setEditorSaveCaption(
Util.getCaption(getI18nService(), "Save", modelAccess.yField.getEditorSaveI18nLabelKey(), getLocale()));
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.ecview.extension.grid.editparts.presentation.
* IGridPresentation#setFilter(java.util.Map)
*/
@Override
public void setFilter(Map<String, Object> filter) {
List<Container.Filter> filters = new ArrayList<>();
for (Map.Entry<String, Object> entry : filter.entrySet()) {
filters.add(new Compare.Equal(entry.getKey(), entry.getValue()));
}
Container.Filterable filterable = (Container.Filterable) grid.getContainerDataSource();
filterable.removeAllContainerFilters();
filterable.addContainerFilter(new And(filters.toArray(new Container.Filter[filters.size()])));
}
/**
* Applies the column setting to the grid.
*/
protected void createColumns() {
resetHeader();
resetFooter();
// reset the column reference in the editparts
for (CxGridColumn cxColumn : modelAccess.yField.getColumns()) {
IGridColumnEditpart editpart = ModelUtil.getEditpart(getViewContext(), cxColumn);
editpart.setColumnReference(null);
}
// set the visible columns and icons
List<String> visibleColumns = new ArrayList<>();
List<CxGridColumn> visibleColumnObjs = new ArrayList<>();
Collection<?> propertyIds = grid.getContainerDataSource().getContainerPropertyIds();
for (CxGridColumn cxColumn : modelAccess.yField.getColumns()) {
if (!cxColumn.isHidden()
&& (propertyIds.contains(cxColumn.getPropertyPath()) || isNestedColumn(cxColumn))) {
visibleColumns.add(cxColumn.getPropertyPath());
visibleColumnObjs.add(cxColumn);
if(cxColumn.getLabelI18nKey() == null || cxColumn.getLabelI18nKey().equals("")){
cxColumn.setLabelI18nKey(cxColumn.getPropertyPath());
}
YConverter converter = cxColumn.getConverter();
if (converter instanceof CxGridNestedConverter) {
CxGridNestedConverter nestedConverter = (CxGridNestedConverter) converter;
}
}
}
if (visibleColumns.size() > 0) {
// reset all columns
grid.removeAllColumns();
}
// add nested properties
if (grid.getContainerDataSource() instanceof INestedPropertyAble) {
INestedPropertyAble<?> container = (INestedPropertyAble<?>) grid.getContainerDataSource();
for (String property : visibleColumns) {
if (property.contains(".")) {
container.addNestedContainerProperty(property);
}
}
}
if (visibleColumns.size() > 0) {
// create the columns based on the model or the persist at user
//
visibleColumns = getColumnOrder(visibleColumns);
grid.setColumns(visibleColumns.toArray(new Object[visibleColumns.size()]));
grid.setColumnOrder(visibleColumns.toArray(new Object[visibleColumns.size()]));
// traverse the columns again and set other properties
for (CxGridColumn cxColumn : modelAccess.yField.getColumns()) {
if (!cxColumn.isHidden()
&& (propertyIds.contains(cxColumn.getPropertyPath()) || isNestedColumn(cxColumn))) {
String columnId = cxColumn.getPropertyPath();
IGridColumnEditpart editpart = ModelUtil.getEditpart(getViewContext(), cxColumn);
Grid.Column column = grid.getColumn(columnId);
editpart.setColumnReference(new ColumnWrapper(cxColumn, column));
editpart.initializeColumn();
}
}
// #479 TODO (JCD): Not needed anymore. Gridxmi provides now all the columns even when no attribute is defined in the grammar
// } else {
// // Previous saved column order
// List<String> columnOrderUser = getColumnOrderUser();
// // Column order exists at user properties
// if ((columnOrderUser != null) && !(columnOrderUser.isEmpty())){
// try {
// /* required before the setColumnOrder to equalize this column order with the state column order.
// * Otherwise the column order list will be increased by the state column order list
// * which produce a IllegalArgumentException and therefore a initial column order. */
// removeNotUsedColumns();
// grid.setColumnOrder(columnOrderUser.toArray());
// } catch (IllegalArgumentException e) {
// // In case of an incomplete setting of the column order by the user properties
// createInitialColumnOrder();
// /* required after the creation of a initial column order that creates the columns
// * based on all existing field names. */
// removeNotUsedColumns();
// }
// } else {
// // Otherwise new column order is created based on the filed names
// createInitialColumnOrder();
// /* required after the creation of a initial column order that creates the columns
// * based on all existing field names. */
// removeNotUsedColumns();
// }
//
}
// #479 TODO (JCD): Not needed anymore. Unauthorized columns were managed at the creation of the grid.
// hideUnauthorizedColumns();
updateCellStyleGenerator();
createHeaderMetaCells();
createFilteringHeader();
createFooterMetaCells();
createSortOrder();
}
private List<String> getColumnOrder(List<String> visibleColumns) {
List<String> columnOrderUser = getColumnOrderUser();
if ( null == columnOrderUser || visibleColumns.size() != columnOrderUser.size()) {
return visibleColumns;
}
boolean unchangedColumns = true;
for (String columnOrderUserItem : columnOrderUser){
boolean containsFlag = visibleColumns.contains(columnOrderUserItem);
unchangedColumns = unchangedColumns && containsFlag;
}
if (unchangedColumns) {
return columnOrderUser;
}
return visibleColumns;
}
@SuppressWarnings("unchecked")
private List<String> getColumnOrderUser() {
IUser user = getViewContext().getService(IUser.class.getName());
String gridName = modelAccess.yField.getProperties().get("GRIDSOURCE_ID");
return (List<String>) user.getProperty(gridName);
}
private void removeNotUsedColumns() {
// remove not used fields
for (Grid.Column col : new ArrayList<>(grid.getColumns())) {
String propId = (String) col.getPropertyId();
if (!propId.contains(".")) {
// only check not nested fields
Class<?> rootType = modelAccess.yField.getType();
if (DtoUtils.isIdField(rootType, propId) || DtoUtils.isVersionField(rootType, propId)
|| DtoUtils.isDisposeField(rootType, propId) || DtoUtils.isDirtyField(rootType, propId)) {
grid.removeColumn(propId);
}
}
}
}
// TODO (JCD) delete if it is clear that the gridsource_xmi solution works.
// private void hideUnauthorizedColumns() {
// IUserAccessService userAccessService = getViewContext().getService(IUserAccessService.class.getName());
// Class<?> dtoObjectClass = modelAccess.yField.getType();
// for (Grid.Column column : new ArrayList<>(grid.getColumns())) {
// String dtoProperty = (String) column.getPropertyId();
// columnPermission(userAccessService, dtoObjectClass, column, dtoProperty);
// }
// }
//
// private void columnPermission(IUserAccessService userAccessService, Class<?> dtoObjectClass, Column column, String dtoProperty) {
// if (dtoProperty.split("\\.").length > 1) {
// String refName = dtoProperty.split("\\.")[0];
// String newDtoProperty = dtoProperty.substring(dtoProperty.indexOf(".") + 1);
// for (java.lang.reflect.Field ref : DtoUtils.getOwnerDomainReferences(dtoObjectClass)){
// if (refName.equals(ref.getName())){
// Class<?> newDtoObjectClass = ref.getType();
// columnPermission(userAccessService, newDtoObjectClass, column, newDtoProperty);
// break;
// }
// }
// } else {
// column.setHidden(false);
// column.setEditable(false);
// if (userAccessService == null) {
// column.setHidden(true);
// } else {
// String dtoName = dtoObjectClass.getCanonicalName();
// boolean dtoGrant = userAccessService.isGranted(Group.DTO, Action.READABLE, dtoName);
// boolean beanGrant = userAccessService.isGranted(Group.BEAN, Action.READABLE, dtoName);
// boolean columnHidden = true;
// boolean columnEditable = false;
// boolean columnEnabled = false;
// if (dtoGrant) {
// columnHidden = userAccessService.isVetoed(Group.DTO, Action.INVISIBLE ,dtoName, dtoProperty);
// columnEditable = !userAccessService.isVetoed(Group.DTO, Action.NONEDITABLE ,dtoName, dtoProperty);
// columnEnabled = !userAccessService.isVetoed(Group.DTO, Action.DISABLED ,dtoName, dtoProperty);
// } else if (beanGrant) {
// columnHidden = userAccessService.isVetoed(Group.BEAN, Action.INVISIBLE, dtoName, dtoProperty);
// columnEditable = !userAccessService.isVetoed(Group.BEAN, Action.NONEDITABLE ,dtoName, dtoProperty);
// columnEnabled = !userAccessService.isVetoed(Group.BEAN, Action.DISABLED ,dtoName, dtoProperty);
// }
// if (!columnHidden) {
// if(column.isEditable()) {
// // do not set editable true, if editable false
// column.setEditable(columnEditable && columnEnabled);
// }
// } else {
// if(!column.isHidden()){
// // do not unhide hidden columns
// column.setHidden(columnHidden);
// }
// }
//
// }
// }
// }
//
private void createInitialColumnOrder() {
Class<?> rootType = modelAccess.yField.getType();
// order columns by field order in rootType
List<String> fieldNames = DtoUtils.getFieldNames(rootType);
for (Iterator<String> iterator = fieldNames.iterator(); iterator.hasNext();) {
String name = iterator.next();
if (grid.getColumn(name) == null) {
iterator.remove();
}
}
grid.setColumnOrder(fieldNames.toArray(new Object[fieldNames.size()]));
}
/**
* Creates the sort order.
*/
protected void createSortOrder() {
CxGrid cxGrid = modelAccess.yField;
if (cxGrid.getSortOrder().size() > 0) {
Sort sort = null;
for (CxGridSortable memSort : cxGrid.getSortOrder()) {
if (sort == null) {
sort = Sort.by(memSort.getColumn().getPropertyId(), toDirection(memSort));
} else {
sort = sort.then(memSort.getColumn().getPropertyId(), toDirection(memSort));
}
}
grid.sort(sort);
}
}
/**
* Creates the header meta cells.
*/
protected void createHeaderMetaCells() {
resetHeader();
// create the new header
CxGrid cxGrid = modelAccess.yField;
for (CxGridHeaderRow cxHeader : cxGrid.getHeaders()) {
boolean addedCells = false;
HeaderRow headerRow = grid.prependHeaderRow();
groupingHeaders.put(cxHeader, headerRow);
// create the grouping headers
//
for (CxGridGroupedCell groupingColumn : cxHeader.getGroupings()) {
Collection<CxGridGroupable> hiddenColumns = new ArrayList<>();
for (CxGridGroupable groupable : groupingColumn.getGroupables()){
if ((groupable instanceof CxGridColumn) && (((CxGridColumn)groupable).isHidden())){
hiddenColumns.add(groupable);
}
}
// groupingColumn.getGroupables().clear();
groupingColumn.getGroupables().removeAll(hiddenColumns);
if (groupingColumn.getGroupables().size() <= 1) {
continue;
}
addedCells = true;
List<Grid.HeaderCell> headerCells = getCells(headerRow, groupingColumn);
Grid.HeaderCell cell = headerRow.join(headerCells.toArray(new Grid.HeaderCell[headerCells.size()]));
// apply the caption of the cell
String caption = Util.getCaption(getI18nService(), groupingColumn.getLabel(),
groupingColumn.getLabelI18nKey(), getLocale());
if (groupingColumn.isUseHTML()) {
cell.setHtml(caption);
} else {
cell.setText(caption);
}
}
if (!addedCells) {
grid.removeHeaderRow(headerRow);
}
// create the custom cells
//
for (CxGridMetaCell cxCell : cxHeader.getCustomCells()) {
Grid.HeaderCell cell = headerRow.getCell(cxCell.getTarget().getPropertyId());
if (cell == null) {
continue;
}
if (cxCell.getElement() != null) {
IEmbeddableEditpart ep = ModelUtil.getEditpart(getViewContext(), cxCell.getElement());
if (ep != null) {
Component component = (Component) ep.render(null);
cell.setComponent(component);
}
} else {
String caption = Util.getCaption(getI18nService(), cxCell.getLabel(), cxCell.getLabelI18nKey(),
getLocale());
if (cxCell.isUseHTML()) {
cell.setHtml(caption);
} else {
cell.setText(caption);
}
}
}
}
}
/**
* Reset header.
*/
protected void resetHeader() {
// reset the old header
for (int i = 0; i < groupingHeaders.size(); i++) {
grid.removeHeaderRow(i);
}
groupingHeaders.clear();
// dispose the cell component field
//
for (CxGridHeaderRow cxHeader : modelAccess.yField.getHeaders()) {
for (CxGridMetaCell cxCell : cxHeader.getCustomCells()) {
if (cxCell.getElement() != null) {
IEmbeddableEditpart ep = ModelUtil.findEditpart(cxCell.getElement());
if (ep != null && !ep.isDisposed()) {
ep.requestDispose();
}
}
}
}
}
/**
* Reset filter.
*/
protected void resetFilter() {
// dispose all the rendered search fields
for (ISearchFieldEditpart ep : filteringHeaderFields.values()) {
ep.dispose();
}
filteringHeaderFields.clear();
if (cellFilters != null) {
cellFilters.destroy();
cellFilters = null;
} else {
// reset the old header
if (filteringHeader != null) {
grid.removeHeaderRow(filteringHeader);
}
}
filteringHeader = null;
}
/**
* Creates the filtering header.
*/
protected void createFilteringHeader() {
resetFilter();
CxGrid cxGrid = modelAccess.yField;
if (!cxGrid.isFilteringVisible()) {
return;
}
if (cxGrid.isCustomFilters()) {
createCustomFilters(cxGrid);
} else {
createAutoFilters();
}
}
/**
* Creates the auto filters.
*/
protected void createAutoFilters() {
cellFilters = new GridCellFilter(grid);
for (CxGridColumn cxColumn : modelAccess.yField.getColumns()) {
if (!cxColumn.isHidden()){
Class<?> propertyType = cxColumn.getType();
String propertyPath = cxColumn.getPropertyPath();
String filterPropertyPath = cxColumn.getPropertyPath();
if (cxColumn.isEditsDto()) {
// if the column edits a dto, its property path points to
// the dto. Eg. person.country.
// So we need to use a special path for filtering which
// points
// to the domainkey. person.country.isoCode
filterPropertyPath = cxColumn.getFilterPropertyPathForEditsDto();
}
if (Number.class.isAssignableFrom(propertyType) || isPrimitiveNumber(propertyType)) {
cellFilters.setNumberFilter(propertyPath, filterPropertyPath);
} else if (propertyType == String.class) {
cellFilters.setTextFilter(propertyPath, filterPropertyPath, true, false, null);
} else if (propertyType == Date.class) {
cellFilters.setDateFilter(propertyPath, filterPropertyPath);
// otherwise the column is to wide
if (grid.getColumn(propertyPath)!=null){
grid.getColumn(propertyPath).setMaximumWidth(175);
}
} else if (propertyType == Boolean.class || propertyType == Boolean.TYPE) {
cellFilters.setBooleanFilter(propertyPath, filterPropertyPath);
} else if (propertyType.isEnum()) {
cellFilters.setComboBoxFilter(propertyPath, filterPropertyPath,
Arrays.asList(propertyType.getEnumConstants()));
} else if (DtoUtils.getDomainKeyField(propertyType) != null) {
cellFilters.setDtoFilter(propertyPath, propertyType, "");
}
}
}
}
/**
* Checks if is primitive number.
*
* @param propertyType
* the property type
* @return true, if is primitive number
*/
private boolean isPrimitiveNumber(Class<?> propertyType) {
return propertyType == Byte.TYPE || propertyType == Double.TYPE || propertyType == Float.TYPE
|| propertyType == Integer.TYPE || propertyType == Long.TYPE || propertyType == Short.TYPE;
}
/**
* Creates the custom filters.
*
* @param cxGrid
* the cx grid
*/
protected void createCustomFilters(CxGrid cxGrid) {
filteringHeader = grid.appendHeaderRow();
for (CxGridColumn cxColumn : cxGrid.getColumns()) {
Grid.HeaderCell cell = filteringHeader.getCell(cxColumn.getPropertyId());
if (cell == null) {
continue;
}
// render the search field
YSearchField cxSearchField = cxColumn.getSearchField();
if (cxSearchField != null) {
ISearchFieldEditpart editpart = ModelUtil.getEditpart(getViewContext(), cxSearchField);
filteringHeaderFields.put(cxColumn, editpart);
ISearchField component = (ISearchField) editpart.render(null);
component.bindFilterChanged(filterChangedTracker);
cell.setComponent((Component) component);
}
}
}
/**
* Refresh filter.
*
* @return the object
*/
private Object refreshFilter() {
Set<Container.Filter> filters = new HashSet<>();
for (ISearchFieldEditpart ep : filteringHeaderFields.values()) {
Container.Filter f = (Container.Filter) ep.getFilter();
if (f != null) {
filters.add(f);
}
}
try {
Container.Filterable filterable = (Container.Filterable) grid.getContainerDataSource();
filterable.removeAllContainerFilters();
filterable.addContainerFilter(new And(filters.toArray(new Container.Filter[filters.size()])));
} catch (Exception e) {
LOGGER.error("{}", e);
}
return null;
}
/**
* Creates the footer meta cells.
*/
protected void createFooterMetaCells() {
resetFooter();
// create the new header
CxGrid cxGrid = modelAccess.yField;
for (CxGridFooterRow cxFooter : cxGrid.getFooters()) {
FooterRow footerRow = grid.appendFooterRow();
groupingFooters.put(cxFooter, footerRow);
for (CxGridGroupedCell groupingColumn : cxFooter.getGroupings()) {
List<Grid.FooterCell> footerCells = getCells(footerRow, groupingColumn);
Grid.FooterCell cell = footerRow.join(footerCells.toArray(new Grid.FooterCell[footerCells.size()]));
// apply the caption of the cell
String caption = Util.getCaption(getI18nService(), groupingColumn.getLabel(),
groupingColumn.getLabelI18nKey(), getLocale());
if (groupingColumn.isUseHTML()) {
cell.setHtml(caption);
} else {
cell.setText(caption);
}
}
// create the custom cells
//
for (CxGridMetaCell cxCell : cxFooter.getCustomCells()) {
Grid.FooterCell cell = footerRow.getCell(cxCell.getTarget().getPropertyId());
if (cell == null) {
continue;
}
if (cxCell.getElement() != null) {
IEmbeddableEditpart ep = ModelUtil.getEditpart(getViewContext(), cxCell.getElement());
if (ep != null) {
Component component = (Component) ep.render(null);
cell.setComponent(component);
}
} else {
String caption = Util.getCaption(getI18nService(), cxCell.getLabel(), cxCell.getLabelI18nKey(),
getLocale());
if (cxCell.isUseHTML()) {
cell.setHtml(caption);
} else {
cell.setText(caption);
}
}
}
}
}
/**
* Reset footer.
*/
protected void resetFooter() {
// reset the old header
for (FooterRow header : groupingFooters.values()) {
grid.removeFooterRow(header);
}
groupingFooters.clear();
// dispose the cell component field
//
for (CxGridFooterRow cxFooter : modelAccess.yField.getFooters()) {
for (CxGridMetaCell cxCell : cxFooter.getCustomCells()) {
if (cxCell.getElement() != null) {
IEmbeddableEditpart ep = ModelUtil.findEditpart(cxCell.getElement());
if (ep != null && !ep.isDisposed()) {
ep.requestDispose();
}
}
}
}
}
/**
* Gets the cells.
*
* @param row
* the row
* @param groupingColumn
* the grouping column
* @return the cells
*/
private List<Grid.HeaderCell> getCells(HeaderRow row, CxGridGroupedCell groupingColumn) {
List<Grid.HeaderCell> cells = new ArrayList<>();
for (CxGridGroupable column : groupingColumn.getGroupables()) {
if (column instanceof CxGridColumn) {
// if it is a column, then use the property id to get the cell
//
String id = ((CxGridColumn) column).getPropertyId();
Grid.HeaderCell cell = row.getCell(id);
if (cell != null) {
cells.add(cell);
}
} else if (column instanceof CxGridGroupedCell) {
// if it is a grouped cell, then collect all properties of it
//
cells.addAll(getCells(row, (CxGridGroupedCell) column));
}
}
return cells;
}
/**
* Gets the cells.
*
* @param row
* the row
* @param groupingColumn
* the grouping column
* @return the cells
*/
private List<Grid.FooterCell> getCells(FooterRow row, CxGridGroupedCell groupingColumn) {
List<Grid.FooterCell> cells = new ArrayList<>();
for (CxGridGroupable column : groupingColumn.getGroupables()) {
if (column instanceof CxGridColumn) {
// if it is a column, then use the property id to get the cell
//
String id = ((CxGridColumn) column).getPropertyId();
Grid.FooterCell cell = row.getCell(id);
if (cell != null) {
cells.add(cell);
}
} else if (column instanceof CxGridGroupedCell) {
// if it is a grouped cell, then collect all properties of it
//
cells.addAll(getCells(row, (CxGridGroupedCell) column));
}
}
return cells;
}
/**
* Checks if is nested column.
*
* @param cxColumn
* the cx column
* @return true, if is nested column
*/
protected boolean isNestedColumn(CxGridColumn cxColumn) {
return cxColumn.getPropertyPath() != null && cxColumn.getPropertyPath().contains(".");
}
/**
* Returns the column header.
*
* @param cxColumn
* the cx column
* @return the column header
*/
private String getColumnHeader(CxGridColumn cxColumn) {
String result = null;
II18nService service = getI18nService();
if (service != null && cxColumn.getLabelI18nKey() != null) {
result = service.getValue(cxColumn.getLabelI18nKey(), getLocale());
}
if (result == null || result.equals("")) {
result = cxColumn.getLabel();
}
if (result == null || result.equals("")) {
result = cxColumn.getPropertyPath();
}
return result;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common.
* AbstractVaadinWidgetPresenter#doCreateWidget(java.lang.Object)
*/
@SuppressWarnings({ "unchecked", "rawtypes", "serial" })
@Override
public Grid doCreateWidget(Object parent) {
if (grid == null) {
// tracks changes in the filters
filterChangedTracker = new WritableValue();
filterChangedTracker.addValueChangeListener(e -> refreshFilter());
CxGrid cxGrid = modelAccess.yField;
grid = new CustomGrid();
setupComponent(grid, getCastedModel());
associateWidget(grid, cxGrid);
if (modelAccess.isCssIdValid()) {
grid.setId(modelAccess.getCssID());
} else {
grid.setId(getEditpart().getId());
}
if (modelAccess.isCssClassValid()) {
grid.addStyleName(modelAccess.getCssClass());
} else {
grid.addStyleName(CSS_CLASS_CONTROL);
}
cxGrid.eAdapters().add(new AdapterImpl() {
@Override
public void notifyChanged(Notification msg) {
if (msg.getFeature() == CxGridPackage.Literals.CX_GRID__SELECTION) {
Class<?> bean = modelAccess.yField.getType();
if (bean != null) {
IEventDispatcher eventDispatcher = getViewContext()
.getService(IEventDispatcher.class.getName());
if (eventDispatcher == null) {
return;
}
MPerspective perspective = getViewContext().getService(MPerspective.class.getName());
EventDispatcherEvent evnt = new EventDispatcherEvent(perspective,EventDispatcherCommand.SELECT, bean.getName(), toString());
if (msg.getNewValue() != null) {
evnt.addItem(EventDispatcherDataTag.ID, DtoUtils.getIdValue(msg.getNewValue()));
eventDispatcher.sendEvent(evnt);
/**
* this doesn't work for updates on the dto as grid completely removes content and sends this event with null dto
*/
// } else {
// evnt.addItem(EventDispatcherDataTag.ID, null);
}
}
}
}
});
createColumns = false;
if (cxGrid.getType() == String.class) {
IndexedContainer datasource = new IndexedContainer();
grid.setContainerDataSource(datasource);
} else {
if (cxGrid.getType() != null) {
IBeanSearchService<?> service = null;
IBeanSearchServiceFactory factory = getViewContext()
.getService(IBeanSearchServiceFactory.class.getName());
if (factory != null) {
service = factory.createService(cxGrid.getType());
}
if (cxGrid.isUseBeanService() && service != null) {
ISharedStateContext sharedState = getViewContext()
.getService(ISharedStateContext.class.getName());
IEventDispatcher eventDispatcher = (IEventDispatcher) getViewContext()
.getService(IEventDispatcher.class.getName());
BeanServiceLazyLoadingContainer<?> datasource = new BeanServiceLazyLoadingContainer(service,
cxGrid.getType(), sharedState, eventDispatcher);
grid.setContainerDataSource(datasource);
} else {
DeepResolvingBeanItemContainer datasource = new DeepResolvingBeanItemContainer(
cxGrid.getType());
grid.setContainerDataSource(datasource);
}
createColumns = 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" });
grid.setContainerDataSource(container);
}
}
// updates the selection type
updateSelectionType();
// creates the binding for the field
createBindings(cxGrid, grid);
if (modelAccess.isCssClassValid()) {
grid.addStyleName(modelAccess.getCssClass());
}
// notify field about save
grid.getEditorFieldGroup().addCommitHandler(new FieldGroup.CommitHandler() {
@Override
public void preCommit(CommitEvent commitEvent) throws CommitException {
}
@Override
public void postCommit(CommitEvent commitEvent) throws CommitException {
Object itemId = grid.getEditedItemId();
modelAccess.yField.setEditorSaved(itemId);
grid.refreshRows(itemId);
}
});
// persists the changed column width into the user properties map
grid.addColumnResizeListener(new Grid.ColumnResizeListener() {
@Override
public void columnResize(com.vaadin.ui.Grid.ColumnResizeEvent event) {
CxGrid cxGrid = modelAccess.yField;
String gridName = cxGrid.getProperties().get("GRIDSOURCE_ID");
// Get the new width of the resized column
double width = event.getColumn().getWidth();
// Get the property ID of the resized column
Object columnId = event.getColumn().getPropertyId();
IUser user = getViewContext().getService(IUser.class.getName());
user.addToProperties(gridName + "." + columnId.toString(), String.valueOf(width));
}
});
// persists the changed column width into the user properties map
grid.addColumnReorderListener(new Grid.ColumnReorderListener() {
@Override
public void columnReorder(ColumnReorderEvent event) {
CxGrid cxGrid = modelAccess.yField;
String gridName = cxGrid.getProperties().get("GRIDSOURCE_ID");
IUser user = getViewContext().getService(IUser.class.getName());
List<Column> gridColumns = grid.getColumns();
List<Object> columnPropertyIds = new ArrayList<>();
for(Column column : gridColumns){
Object propertyId = column.getPropertyId();
columnPropertyIds.add(propertyId);
}
user.addToProperties(gridName, columnPropertyIds);
}
});
// Must be immediate to send the resize events immediately
grid.setImmediate(true);
applyCaptions();
// DO NOT MOVE THE FOLLOWING CODE LINES!
// The setting of the COLUMN WIDTHS and the COLUMN ORDER 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());
String gridName = cxGrid.getProperties().get("GRIDSOURCE_ID");
// Temporarily deactivate to test memento ########### TODO #############
// COLUMN WIDTH
List<Column> gridColumns = grid.getColumns();
for (Column column : gridColumns) {
String columnWidthStr = user.getColumnUtil().getColumnWidth(gridName + "." + column.getPropertyId());
if (columnWidthStr != null){
column.setWidth(Double.parseDouble(columnWidthStr));
}
}
// COLUMN ORDER
Object[] columnOrder = ((List<String>) user.getProperty(gridName)).toArray();
try {
grid.setColumnOrder(columnOrder);
} catch (IllegalArgumentException e) {
// In case of an incomplete setting of the column order by the user properties
createInitialColumnOrder();
}
removeNotUsedColumns();
setupUserCallbacks(cxGrid);
}
return grid;
}
/**
* // * Creates a predefined filter for the grid. // * // * @return //
*/
// private Filter createFilter() {
// CxGrid grid = modelAccess.yField;
// if (grid.getFilters().isEmpty()) {
// return null;
// }
//
// List<Filter> filters = new ArrayList<>();
// for (YFilter yFilter : grid.getFilters()) {
// Filter filter = new Compare.Equal(yFilter.getPropertyPath(),
// yFilter.getFilterValue());
// filters.add(filter);
// }
// return new And(filters.toArray(new Filter[filters.size()]));
// }
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common.
* AbstractVaadinWidgetPresenter#castEObject(java.lang.Object)
*/
@Override
protected CxGrid castEObject(Object model) {
return (CxGrid) super.castEObject(model);
}
/**
* Creates the bindings.
*
* @param yGrid
* the y grid
* @param widget
* the widget
*/
@SuppressWarnings("rawtypes")
protected void createBindings(CxGrid yGrid, Grid widget) {
super.createBindings(yGrid, widget, null);
// bind the editorEnabled property
IVaadinObservableValue editorEnabledUiObservable = VaadinProperties.accessor(Grid.class, "editorEnabled")
.observe(widget);
IObservableValue editorEnabledModelObservable = EMFObservables.observeValue(castEObject(yGrid),
CxGridPackage.eINSTANCE.getCxGrid_EditorEnabled());
registerBinding(createBindings(editorEnabledUiObservable, editorEnabledModelObservable));
// bind the footerVisible property
IVaadinObservableValue footerVisibleUiObservable = VaadinProperties.accessor(Grid.class, "footerVisible")
.observe(widget);
IObservableValue footerVisibleModelObservable = EMFObservables.observeValue(castEObject(yGrid),
CxGridPackage.eINSTANCE.getCxGrid_FooterVisible());
registerBinding(createBindings(footerVisibleUiObservable, footerVisibleModelObservable));
// add a value change listener to update the memento
footerVisibleModelObservable.addValueChangeListener(e -> {
if (currentMemento == null || currentMemento.isFooterVisible() != grid.isFooterVisible()) {
updateMemento();
}
});
// bind the headerVisible property
IVaadinObservableValue headerVisibleUiObservable = VaadinProperties.accessor(Grid.class, "headerVisible")
.observe(widget);
IObservableValue headerVisibleModelObservable = EMFObservables.observeValue(castEObject(yGrid),
CxGridPackage.eINSTANCE.getCxGrid_HeaderVisible());
registerBinding(createBindings(headerVisibleUiObservable, headerVisibleModelObservable));
// add a value change listener to update the memento
headerVisibleModelObservable.addValueChangeListener(e -> {
if (currentMemento == null || currentMemento.isHeaderVisible() != grid.isHeaderVisible()) {
updateMemento();
}
});
// bind the columnReorderingAllowed property
IVaadinObservableValue columnReorderingAllowedUiObservable = VaadinProperties
.accessor(Grid.class, "columnReorderingAllowed").observe(widget);
IObservableValue columnReorderingAllowedModelObservable = EMFObservables.observeValue(castEObject(yGrid),
CxGridPackage.eINSTANCE.getCxGrid_ColumnReorderingAllowed());
registerBinding(createBindings(columnReorderingAllowedUiObservable, columnReorderingAllowedModelObservable));
// bind the editorEnabled property
IVaadinObservableValue refreshUiObservable = VaadinProperties.accessor(CustomGrid.class, "refresh")
.observe(widget);
IObservableValue refreshModelObservable = EMFObservables.observeValue(castEObject(yGrid),
CxGridPackage.eINSTANCE.getCxGrid_SetLastRefreshTime());
registerBinding(createBindings(refreshUiObservable, refreshModelObservable));
if (!modelAccess.yField.isUseBeanService()) {
// if use bean service, the container is responsible to collect
// data. So we must not have a binding from the container to the
// YGrid#collection attribute.
Container.Indexed container = grid.getContainerDataSource();
// bind the rows
registerBinding(createBindings_ContainerContents(castEObject(getModel()),
CxGridPackage.Literals.CX_GRID__COLLECTION, (Container.ItemSetChangeNotifier) container,
yGrid.getType()));
}
// update the selection binding
updateSelectionBinding();
}
/**
* Updates the selection binding for the grid.
*/
protected void updateSelectionBinding() {
CxGrid yGrid = modelAccess.yField;
if (selectionBinding != null) {
unregisterBinding(selectionBinding);
selectionBinding = null;
}
// create the model binding from widget to ECView-model
if (yGrid.getSelectionType() == YSelectionType.MULTI) {
selectionBinding = createBindingsMultiSelection(castEObject(getModel()),
CxGridPackage.Literals.CX_GRID__MULTI_SELECTION, grid, yGrid.getType());
// create the model binding from widget to ECView-model
registerBinding(selectionBinding);
} else {
// create the model binding from widget to ECView-model
selectionBinding = createBindingsSingleSelection(castEObject(getModel()),
CxGridPackage.Literals.CX_GRID__SELECTION, grid, yGrid.getType());
registerBinding(selectionBinding);
}
}
@Override
public void updateSelectionType() {
if (modelAccess.yField.getSelectionType() == YSelectionType.MULTI) {
grid.setSelectionMode(Grid.SelectionMode.MULTI);
} else {
grid.setSelectionModel(new CustomSelectionModel());
}
updateSelectionBinding();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.osbp.ecview.core.common.presentation.IWidgetPresentation#
* getWidget()
*/
@Override
public Grid getWidget() {
return grid;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.osbp.ecview.core.common.presentation.IWidgetPresentation#
* isRendered()
*/
@Override
public boolean isRendered() {
return grid != null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common.
* AbstractVaadinWidgetPresenter#internalDispose()
*/
@Override
protected void internalDispose() {
try {
unrender();
} finally {
super.internalDispose();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.common.
* AbstractVaadinWidgetPresenter#doUnrender()
*/
@Override
public void doUnrender() {
if (grid != null) {
// unbind all active bindings
unbind();
// remove assocations
unassociateWidget(grid);
resetFooter();
resetHeader();
resetFilter();
currentMemento = null;
grid = null;
}
}
/**
* Creates the bindings single selection.
*
* @param model
* the model
* @param modelFeature
* the model feature
* @param field
* the field
* @param collectionType
* the collection type
* @return the binding
*/
protected Binding createBindingsSingleSelection(CxGrid model, EStructuralFeature modelFeature, final Grid field,
Class<?> collectionType) {
IBindingManager bindingManager = getViewContext()
.getService(org.eclipse.osbp.ecview.core.common.binding.IECViewBindingManager.class.getName());
if (bindingManager != null) {
// bind the value of yText to textRidget
IObservableValue modelObservable = EMFProperties.value(modelFeature).observe(model);
IVaadinObservableValue uiObservable = VaadinProperties.propertyGridSelectionValueProperty(collectionType)
.observe(field);
final Binding binding = bindingManager.bindValue(uiObservable, modelObservable, null, null);
return binding;
}
return null;
}
/**
* Creates the bindings multi selection.
*
* @param model
* the model
* @param modelFeature
* the model feature
* @param field
* the field
* @param collectionType
* the collection type
* @return the binding
*/
protected Binding createBindingsMultiSelection(CxGrid model, EStructuralFeature modelFeature, final Grid field,
Class<?> collectionType) {
IBindingManager bindingManager = getViewContext()
.getService(org.eclipse.osbp.ecview.core.common.binding.IECViewBindingManager.class.getName());
if (bindingManager != null) {
// bind the value of yText to textRidget
IObservableList modelObservable = EMFProperties.list(modelFeature).observe(model);
IVaadinObservableList uiObservable = new SetToListAdapter(
VaadinProperties.propertyGridSelectionSetPropertyAsSet(collectionType).observe(field), field);
final Binding binding = bindingManager.bindList(uiObservable, modelObservable, null, null);
return binding;
}
return null;
}
/**
* Is used by the editpart to update the header.
*/
@Override
public void updateHeader() {
createHeaderMetaCells();
updateMemento();
}
/**
* Is used by the editpart to update the footer.
*/
@Override
public void updateFooter() {
createFooterMetaCells();
updateMemento();
}
/**
* Is used by the editpart to update the columns.
*/
@Override
public void updateColumns() {
createColumns();
updateMemento();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.ecview.extension.grid.editparts.presentation.
* IGridPresentation#updateFilter()
*/
@Override
public void updateFilter() {
createFilteringHeader();
updateMemento();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.ecview.extension.grid.editparts.presentation.
* IGridPresentation#updateCellStyleGenerator()
*/
@Override
public void updateCellStyleGenerator() {
CxGridCellStyleGenerator cxGenerator = modelAccess.yField.getCellStyleGenerator();
if (cxGenerator != null) {
IGridCellStyleGeneratorEditpart ep = ModelUtil.getEditpart(getViewContext(), cxGenerator);
Grid.CellStyleGenerator generator = (Grid.CellStyleGenerator) ep.getDelegate();
grid.setCellStyleGenerator(generator);
} else {
grid.setCellStyleGenerator(null);
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.osbp.runtime.common.memento.IMementoHandler#applyMemento(java
* .lang.Object)
*/
@Override
public void applyMemento(Object value) {
boolean isRendered = isRendered();
try {
if (isRendered) {
// unrender the grid to increase performance
getEditpart().requestUnrender();
}
doApplyMemento(value);
} finally {
if (isRendered) {
// render the grid again
getEditpart().requestRender();
}
}
}
/**
* Do apply memento.
*
* @param value
* the value
*/
protected void doApplyMemento(Object value) {
CxGrid cxGrid = modelAccess.yField;
CxGridMemento cxMemento = (CxGridMemento) value;
currentMemento = cxMemento;
// apply the grid properties
//
cxGrid.setEditorEnabled(cxMemento.isEditorEnabled());
cxGrid.setFilteringVisible(cxMemento.isFilterVisible());
cxGrid.setHeaderVisible(cxMemento.isHeaderVisible());
cxGrid.setFooterVisible(cxMemento.isFooterVisible());
// apply the columns to the grid and the setting to each column
//
List<CxGridColumn> tempColumns = new ArrayList<>(cxGrid.getColumns());
List<CxGridColumn> cxOrderedColumns = new ArrayList<>(cxGrid.getColumns().size());
for (CxGridMementoColumn memColumn : cxMemento.getColumns()) {
CxGridColumn cxColumn = findCxColumn(memColumn.getPropertyId());
if (cxColumn != null) {
// add the columns in the order of the memento
cxOrderedColumns.add(cxColumn);
tempColumns.remove(cxColumn);
cxColumn.setEditable(memColumn.isEditable());
cxColumn.setHidden(memColumn.isHidden());
cxColumn.setHideable(memColumn.isHideable());
cxColumn.setSortable(memColumn.isSortable());
cxColumn.setExpandRatio(memColumn.getExpandRatio());
if (memColumn.getWidth() > 0) {
cxColumn.setWidth(memColumn.getWidth());
}
}
}
// set all columns that are not in the memento as hidden
//
for (CxGridColumn cxColumn : tempColumns) {
cxColumn.setHideable(true);
cxColumn.setHidden(true);
}
// set the new columns to the grid
cxGrid.getColumns().clear();
cxGrid.getColumns().addAll(cxOrderedColumns);
// update the sortorder
//
List<CxGridSortable> cxSortables = new ArrayList<>(cxMemento.getSortOrders().size());
if (cxMemento.getSortOrders().size() > 0) {
for (CxGridMementoSortable memSort : cxMemento.getSortOrders()) {
CxGridColumn cxColumn = findCxColumn(memSort.getColumn().getPropertyId());
if (cxColumn != null) {
CxGridSortable cxSortable = CxGridFactory.eINSTANCE.createCxGridSortable();
cxSortable.setColumn(cxColumn);
cxSortable.setDescending(memSort.isDescending());
cxSortables.add(cxSortable);
}
}
cxGrid.getSortOrder().addAll(cxSortables);
}
}
/**
* To direction.
*
* @param cxSortable
* the cx sortable
* @return the sort direction
*/
private SortDirection toDirection(CxGridSortable cxSortable) {
return cxSortable.isDescending() ? SortDirection.DESCENDING : SortDirection.ASCENDING;
}
/**
* Gets the memento.
*
* @return the memento
*/
private Object getMemento() {
CxGridMemento cxMemento = CxGridMementoFactory.eINSTANCE.createCxGridMemento();
currentMemento = cxMemento;
cxMemento.setId(getMementoId());
cxMemento.setGridId(getCastedModel().getId());
cxMemento.setEditorEnabled(grid.isEditorEnabled());
cxMemento.setHeaderVisible(grid.isHeaderVisible());
cxMemento.setFooterVisible(grid.isFooterVisible());
cxMemento.setFilterVisible(filteringHeader != null);
Map<Object, CxGridMementoColumn> tempColumns = new HashMap<>();
for (Grid.Column column : grid.getColumns()) {
CxGridMementoColumn cxColumn = CxGridMementoFactory.eINSTANCE.createCxGridMementoColumn();
cxColumn.setEditable(column.isEditable());
cxColumn.setExpandRatio(column.getExpandRatio());
cxColumn.setHideable(column.isHidable());
cxColumn.setHidden(column.isHidden());
cxColumn.setSortable(column.isSortable());
cxColumn.setWidth((int) column.getWidth());
cxColumn.setPropertyId((String) column.getPropertyId());
cxMemento.getColumns().add(cxColumn);
tempColumns.put(cxColumn.getPropertyId(), cxColumn);
}
for (SortOrder sortOrder : grid.getSortOrder()) {
CxGridMementoSortable cxSortable = CxGridMementoFactory.eINSTANCE.createCxGridMementoSortable();
CxGridMementoColumn cxColumn = tempColumns.get(sortOrder.getPropertyId());
if (cxColumn == null) {
LOGGER.warn("Column is not available :" + sortOrder.getPropertyId());
continue;
}
cxSortable.setColumn(cxColumn);
cxSortable.setDescending(sortOrder.getDirection() == SortDirection.DESCENDING);
cxMemento.getSortOrders().add(cxSortable);
}
return cxMemento;
}
/**
* Gets the memento id.
*
* @return the memento id
*/
protected String getMementoId() {
return castEObject(getCastedModel()).getMementoId();
}
/**
* Handles the memento, if it is enabled by the grid.
*
* @param cxGrid
* the new up user callbacks
*/
protected void setupUserCallbacks(CxGrid cxGrid) {
// then add listeners to the grid
//
grid.addColumnReorderListener(e -> {
if (e.isUserOriginated()) {
userChangedHandler.userChangedColumnOrder();
updateMemento();
}
});
grid.addColumnVisibilityChangeListener(e -> {
if (e.isUserOriginated()) {
userChangedHandler.userChangedColumnVisibility(e);
updateMemento();
}
});
grid.addSortListener(e -> {
if (e.isUserOriginated()) {
userChangedHandler.userChangedSortOrder(e);
updateMemento();
}
});
}
/**
* Find column wrapper.
*
* @param column
* the column
* @return the column wrapper
*/
private ColumnWrapper findColumnWrapper(Grid.Column column) {
return columns.stream().filter(e -> e.column == column).findFirst().orElse(null);
}
/**
* Find column wrapper.
*
* @param propertyId
* the property id
* @return the column wrapper
*/
private ColumnWrapper findColumnWrapper(String propertyId) {
return columns.stream().filter(e -> e.column.getPropertyId().equals(propertyId)).findFirst().orElse(null);
}
/**
* Find cx column.
*
* @param propertyId
* the property id
* @return the cx grid column
*/
private CxGridColumn findCxColumn(String propertyId) {
CxGrid cxGrid = modelAccess.yField;
return cxGrid.getColumns().stream().filter(e -> e.getPropertyId().equals(propertyId)).findFirst().orElse(null);
}
/**
* Updates the memento.
*/
protected void updateMemento() {
if (modelAccess.yField.isMementoEnabled()) {
IGridEditpart ep = (IGridEditpart) getEditpart();
ep.saveMemento(getMemento());
}
}
/*
* (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(CxGridPackage.Literals.CX_GRID__COLLECTION).observe(getModel());
}
/**
* Returns the observable to observe the selection.
*
* @param yEndpoint
* the y endpoint
* @return the i observable value
*/
@SuppressWarnings("restriction")
protected IObservableValue internalGetSelectionEndpoint(YEmbeddableSelectionEndpoint yEndpoint) {
String attributePath = ECViewModelBindable.getAttributePath(CxGridPackage.Literals.CX_GRID__SELECTION,
yEndpoint.getAttributePath());
// return the observable value
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(CxGridPackage.Literals.CX_GRID__SELECTION).observe(getModel());
}
/**
* An internal helper class.
*/
private static class ModelAccess {
/** The y field. */
private final CxGrid yField;
/**
* Instantiates a new model access.
*
* @param yLayout
* the y layout
*/
public ModelAccess(CxGrid yLayout) {
super();
this.yField = yLayout;
}
/**
* 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.getLabel();
}
/**
* Returns the label I18n key.
*
* @return the label i18n key
*/
public String getLabelI18nKey() {
return yField.getLabelI18nKey();
}
}
/**
* The Class ColumnWrapper.
*/
private class ColumnWrapper extends AbstractDisposable implements IGridColumnEditpart.ColumnReference {
/** The cx column. */
private CxGridColumn cxColumn;
/** The column. */
private Grid.Column column;
/**
* Instantiates a new column wrapper.
*
* @param cxColumn
* the cx column
* @param column
* the column
*/
public ColumnWrapper(CxGridColumn cxColumn, Grid.Column column) {
super();
this.cxColumn = cxColumn;
this.column = column;
columns.add(this);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.osbp.ecview.extension.grid.editparts.IGridColumnEditpart.
* ColumnReference#setConverter(java.lang.Object)
*/
@Override
public void setConverter(Object converter) {
if (converter != null && converter instanceof Converter) {
column.setConverter((Converter<?, ?>) converter);
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.osbp.ecview.extension.grid.editparts.IGridColumnEditpart.
* ColumnReference#setRenderer(java.lang.Object, java.lang.Object)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void setRenderer(Object renderer, Object converter) {
if (renderer == null) {
LOGGER.debug("Null renderer not allowed");
return;
}
if (converter == null) {
column.setRenderer((Renderer) renderer);
} else {
column.setRenderer((Renderer) renderer, (Converter) converter);
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.osbp.ecview.extension.grid.editparts.IGridColumnEditpart.
* ColumnReference#updateProperties()
*/
@Override
public void updateProperties() {
column.setHeaderCaption(getColumnHeader(cxColumn));
column.setHidden(cxColumn.isHidden());
column.setHidable(cxColumn.isHideable());
column.setEditable(cxColumn.isEditable());
if (cxColumn.getMinWidthPixels() > -1) {
column.setMinimumWidth(cxColumn.getMinWidthPixels());
}
if (cxColumn.getMaxWidthPixels() > 0) {
column.setMaximumWidth(cxColumn.getMaxWidthPixels());
}
if (cxColumn.getWidth() > -1) {
column.setWidth(cxColumn.getWidth());
} else {
column.setWidthUndefined();
}
column.setSortable(cxColumn.isSortable());
if (cxColumn.getExpandRatio() > -1) {
column.setExpandRatio(cxColumn.getExpandRatio());
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.osbp.ecview.extension.grid.editparts.IGridColumnEditpart.
* ColumnReference#updateEditorField()
*/
@Override
public void updateEditorField() {
if (!cxColumn.isEditable()) {
column.setEditorField(null);
} else {
YField cxField = cxColumn.getEditorField();
Field<?> field = null;
if (cxField != null) {
IFieldEditpart editpart = ModelUtil.getEditpart(getViewContext(), cxField);
field = (Field<?>) editpart.render(null);
field.setSizeFull();
}
column.setEditorField(field);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.osbp.runtime.common.dispose.AbstractDisposable#
* internalDispose()
*/
@Override
protected void internalDispose() {
// remove this column from the cached columns
columns.remove(this);
YField cxField = cxColumn.getEditorField();
if (cxField != null) {
IFieldEditpart editpart = ModelUtil.findEditpart(cxField);
if (editpart != null) {
editpart.dispose();
}
}
}
}
/**
* The Class UserChangedHandler.
*/
private class UserChangedHandler {
/**
* User changed sort order.
*
* @param e
* the e
*/
private void userChangedSortOrder(SortEvent e) {
List<CxGridSortable> cxSortOrder = new ArrayList<>();
for (SortOrder sortOrder : e.getSortOrder()) {
ColumnWrapper wrapper = findColumnWrapper((String) sortOrder.getPropertyId());
CxGridSortable cxSortable = CxGridFactory.eINSTANCE.createCxGridSortable();
cxSortOrder.add(cxSortable);
if (wrapper != null) {
cxSortable.setColumn(wrapper.cxColumn);
}
cxSortable.setDescending(sortOrder.getDirection() == SortDirection.DESCENDING);
}
CxGrid cxGrid = modelAccess.yField;
try {
cxGrid.eSetDeliver(false);
modelAccess.yField.getSortOrder().clear();
modelAccess.yField.getSortOrder().addAll(cxSortOrder);
} finally {
cxGrid.eSetDeliver(true);
}
}
/**
* User changed column visibility.
*
* @param e
* the e
*/
private void userChangedColumnVisibility(ColumnVisibilityChangeEvent e) {
Grid.Column affected = e.getColumn();
ColumnWrapper wrapper = findColumnWrapper(affected);
if (wrapper == null) {
LOGGER.warn("No column available for " + affected.getHeaderCaption());
return;
}
CxGrid cxGrid = modelAccess.yField;
try {
cxGrid.eSetDeliver(false);
// update the column in the model
CxGridColumn cxColumn = wrapper.cxColumn;
cxColumn.setHidden(e.isHidden());
} finally {
cxGrid.eSetDeliver(true);
}
}
/**
* User changed column order.
*/
private void userChangedColumnOrder() {
List<CxGridColumn> cxColumns = new ArrayList<>();
for (Grid.Column column : grid.getColumns()) {
ColumnWrapper wrapper = findColumnWrapper(column);
if (wrapper != null) {
cxColumns.add(wrapper.cxColumn);
}
}
CxGrid cxGrid = modelAccess.yField;
try {
cxGrid.eSetDeliver(false);
cxGrid.getColumns().clear();
cxGrid.getColumns().addAll(cxColumns);
} finally {
cxGrid.eSetDeliver(true);
}
}
}
/**
* The Class CustomTextField.
*/
@SuppressWarnings("serial")
public class CustomGrid extends Grid {
// only required to be able to create a binding between
// org.eclipse.osbp.ecview.extension.grid.CxGrid and com.vaadin.ui.Grid
// to call this method which refresh the grid.
public long getRefresh() {
return 0;
}
// only required to be able to create a binding between
// org.eclipse.osbp.ecview.extension.grid.CxGrid and com.vaadin.ui.Grid
// to call this method which refresh the grid.
public void setRefresh(long time) {
List<SortOrder> sort = getSortOrder();
clearSortOrder();
setSortOrder(sort);
}
}
@SuppressWarnings("serial")
public class CustomSelectionModel extends Grid.SingleSelectionModel {
@Override
public boolean isSelected(Object itemId) {
boolean result = super.isSelected(itemId);
if (!result) {
Object selectedItemId = getSelectedRow();
if (selectedItemId != null && itemId != selectedItemId) {
Object id1 = DtoUtils.getIdValue(itemId);
Object id2 = DtoUtils.getIdValue(selectedItemId);
result = Objects.equals(id1, id2);
if (result) {
reset();
select(itemId);
}
}
}
return result;
}
}
}