Java tutorial
/******************************************************************************* * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Eugen Neufeld - initial API and implementation * Johannes Faltermeier - refactorings ******************************************************************************/ package org.eclipse.emf.ecp.view.spi.table.swt; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.inject.Inject; import org.eclipse.core.databinding.Binding; import org.eclipse.core.databinding.observable.IObserving; import org.eclipse.core.databinding.observable.Observables; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.map.IObservableMap; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.core.databinding.property.value.IValueProperty; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.databinding.EMFDataBindingContext; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecp.edit.internal.swt.util.CellEditorFactory; import org.eclipse.emf.ecp.edit.spi.DeleteService; import org.eclipse.emf.ecp.edit.spi.EMFDeleteServiceImpl; import org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor; import org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditorComparator; import org.eclipse.emf.ecp.edit.spi.swt.util.ECPDialogExecutor; import org.eclipse.emf.ecp.view.internal.table.swt.CellReadOnlyTesterHelper; import org.eclipse.emf.ecp.view.internal.table.swt.MessageKeys; import org.eclipse.emf.ecp.view.internal.table.swt.TableConfigurationHelper; import org.eclipse.emf.ecp.view.spi.context.ViewModelContext; import org.eclipse.emf.ecp.view.spi.core.swt.AbstractControlSWTRenderer; import org.eclipse.emf.ecp.view.spi.model.DiagnosticMessageExtractor; import org.eclipse.emf.ecp.view.spi.model.VDiagnostic; import org.eclipse.emf.ecp.view.spi.model.VDomainModelReference; import org.eclipse.emf.ecp.view.spi.model.reporting.StatusReport; import org.eclipse.emf.ecp.view.spi.provider.ECPTooltipModifierHelper; import org.eclipse.emf.ecp.view.spi.renderer.NoPropertyDescriptorFoundExeption; import org.eclipse.emf.ecp.view.spi.renderer.NoRendererFoundException; import org.eclipse.emf.ecp.view.spi.swt.reporting.RenderingFailedReport; import org.eclipse.emf.ecp.view.spi.table.model.VTableControl; import org.eclipse.emf.ecp.view.spi.table.model.VTableDomainModelReference; import org.eclipse.emf.ecp.view.spi.util.swt.ImageRegistryService; import org.eclipse.emf.ecp.view.template.model.VTStyleProperty; import org.eclipse.emf.ecp.view.template.model.VTViewTemplateProvider; import org.eclipse.emf.ecp.view.template.style.background.model.VTBackgroundFactory; import org.eclipse.emf.ecp.view.template.style.background.model.VTBackgroundStyleProperty; import org.eclipse.emf.ecp.view.template.style.fontProperties.model.VTFontPropertiesFactory; import org.eclipse.emf.ecp.view.template.style.fontProperties.model.VTFontPropertiesStyleProperty; import org.eclipse.emf.ecp.view.template.style.tableValidation.model.VTTableValidationFactory; import org.eclipse.emf.ecp.view.template.style.tableValidation.model.VTTableValidationStyleProperty; import org.eclipse.emf.edit.command.AddCommand; import org.eclipse.emf.edit.command.RemoveCommand; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emfforms.spi.common.report.AbstractReport; import org.eclipse.emfforms.spi.common.report.ReportService; import org.eclipse.emfforms.spi.core.services.databinding.DatabindingFailedException; import org.eclipse.emfforms.spi.core.services.databinding.DatabindingFailedReport; import org.eclipse.emfforms.spi.core.services.databinding.EMFFormsDatabinding; import org.eclipse.emfforms.spi.core.services.databinding.emf.EMFFormsDatabindingEMF; import org.eclipse.emfforms.spi.core.services.editsupport.EMFFormsEditSupport; import org.eclipse.emfforms.spi.core.services.label.EMFFormsLabelProvider; import org.eclipse.emfforms.spi.core.services.label.NoLabelFoundException; import org.eclipse.emfforms.spi.localization.LocalizationServiceHelper; import org.eclipse.emfforms.spi.swt.core.layout.GridDescriptionFactory; import org.eclipse.emfforms.spi.swt.core.layout.SWTGridCell; import org.eclipse.emfforms.spi.swt.core.layout.SWTGridDescription; import org.eclipse.emfforms.spi.swt.table.ButtonBarBuilder; import org.eclipse.emfforms.spi.swt.table.CellLabelProviderFactory; import org.eclipse.emfforms.spi.swt.table.EditingSupportCreator; import org.eclipse.emfforms.spi.swt.table.TableViewerComposite; import org.eclipse.emfforms.spi.swt.table.TableViewerCompositeBuilder; import org.eclipse.emfforms.spi.swt.table.TableViewerCreator; import org.eclipse.emfforms.spi.swt.table.TableViewerFactory; import org.eclipse.emfforms.spi.swt.table.TableViewerSWTBuilder; import org.eclipse.jface.databinding.swt.WidgetProperties; import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; import org.eclipse.jface.databinding.viewers.ObservableMapCellLabelProvider; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogLabelKeys; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CellLabelProvider; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; import org.eclipse.jface.viewers.ColumnViewerEditorActivationListener; import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.IColorProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.osgi.framework.FrameworkUtil; /** * SWT Renderer for Table Control. * * @author Eugen Neufeld * @author Johannes Faltermeier * */ public class TableControlSWTRenderer extends AbstractControlSWTRenderer<VTableControl> { private static final String FIXED_COLUMNS = "org.eclipse.rap.rwt.fixedColumns"; //$NON-NLS-1$ private static final String TABLE_CUSTOM_VARIANT = "org_eclipse_emf_ecp_control_table"; //$NON-NLS-1$ private static final String ICON_ADD = "icons/add.png"; //$NON-NLS-1$ private static final String ICON_DELETE = "icons/delete.png"; //$NON-NLS-1$ private final Map<Integer, ECPCellEditorComparator> columnIndexToComparatorMap = new LinkedHashMap<Integer, ECPCellEditorComparator>(); private final ImageRegistryService imageRegistryService; private final EMFDataBindingContext viewModelDBC; private final EMFFormsEditSupport emfFormsEditSupport; private SWTGridDescription rendererGridDescription; private TableViewer tableViewer; private Label validationIcon; private Button addButton; private Button removeButton; /** * Default constructor. * * @param vElement the view model element to be rendered * @param viewContext the view context * @param emfFormsDatabinding The {@link EMFFormsDatabinding} * @param emfFormsLabelProvider The {@link EMFFormsLabelProvider} * @param reportService The {@link ReportService} * @param vtViewTemplateProvider The {@link VTViewTemplateProvider} * @param imageRegistryService The {@link ImageRegistryService} * @param emfFormsEditSupport The {@link EMFFormsEditSupport} * @since 1.8 */ @Inject // BEGIN COMPLEX CODE public TableControlSWTRenderer(VTableControl vElement, ViewModelContext viewContext, ReportService reportService, EMFFormsDatabindingEMF emfFormsDatabinding, EMFFormsLabelProvider emfFormsLabelProvider, VTViewTemplateProvider vtViewTemplateProvider, ImageRegistryService imageRegistryService, EMFFormsEditSupport emfFormsEditSupport) { // END COMPLEX CODE super(vElement, viewContext, reportService, emfFormsDatabinding, emfFormsLabelProvider, vtViewTemplateProvider); this.imageRegistryService = imageRegistryService; this.emfFormsEditSupport = emfFormsEditSupport; viewModelDBC = new EMFDataBindingContext(); } @Override public SWTGridDescription getGridDescription(SWTGridDescription gridDescription) { if (rendererGridDescription == null) { rendererGridDescription = GridDescriptionFactory.INSTANCE.createSimpleGrid(1, 1, this); } return rendererGridDescription; } /** * * {@inheritDoc} * * @see org.eclipse.emf.ecp.view.spi.core.swt.AbstractControlSWTRenderer#getEMFFormsDatabinding() * @since 1.8 */ @Override protected EMFFormsDatabindingEMF getEMFFormsDatabinding() { return (EMFFormsDatabindingEMF) super.getEMFFormsDatabinding(); } @Override protected Control renderControl(SWTGridCell gridCell, final Composite parent) throws NoRendererFoundException, NoPropertyDescriptorFoundExeption { try { /* get the list-setting which is displayed */ final VDomainModelReference dmrToCheck = getDMRToMultiReference(); final Setting setting = getEMFFormsDatabinding().getSetting(dmrToCheck, getViewModelContext().getDomainModel()); final EObject eObject = setting.getEObject(); final EStructuralFeature structuralFeature = setting.getEStructuralFeature(); final EClass clazz = ((EReference) structuralFeature).getEReferenceType(); /* get the observable list */ final IObservableList list = getEMFFormsDatabinding().getObservableList(dmrToCheck, getViewModelContext().getDomainModel()); /* get the label text/tooltip */ final IObservableValue labelText = getLabelText(dmrToCheck, false); final IObservableValue labelTooltipText = getLabelTooltipText(dmrToCheck, false); /* content provider */ final ObservableListContentProvider cp = new ObservableListContentProvider(); final ECPTableViewerComparator comparator = new ECPTableViewerComparator(); /* render */ final TableViewerCompositeBuilder compositeBuilder = new TableControlSWTRendererCompositeBuilder(); final TableViewerSWTBuilder tableViewerSWTBuilder = TableViewerFactory .fillDefaults(parent, SWT.NONE, list, labelText, labelTooltipText) .customizeCompositeStructure(compositeBuilder) .customizeButtons( new TableControlSWTRendererButtonBarBuilder(structuralFeature, clazz, eObject)) .customizeTableViewerCreation(new TableControlSWTRendererTableViewerCreator()) .customizeContentProvider(cp).customizeComparator(comparator); /* add columns */ int regularColumnsStartIndex = 0; /* validation column */ if (!getVElement().isReadonly()) { regularColumnsStartIndex++; createFixedValidationStatusColumn(tableViewerSWTBuilder); } addColumns(tableViewerSWTBuilder, clazz, cp); final TableViewerComposite tableViewerComposite = tableViewerSWTBuilder.create(); /* setup selection changes listener */ tableViewerComposite.getTableViewer().addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { viewerSelectionChanged(event); } }); /* setup sorting via column selection */ setupSorting(comparator, regularColumnsStartIndex, tableViewerComposite); /* get validation icon */ setupValidation(tableViewerComposite); setTableViewer(tableViewerComposite.getTableViewer()); // FIXME doesn't work with table with panel // setLayoutData(compositeBuilder.getViewerComposite()); GridData.class .cast(compositeBuilder.getViewerComposite().getLayoutData()).heightHint = getTableHeightHint(); return tableViewerComposite; } catch (final DatabindingFailedException ex) { getReportService().report(new RenderingFailedReport(ex)); final Label errorLabel = new Label(parent, SWT.NONE); errorLabel.setText(ex.getMessage()); return errorLabel; } } /** * Adds the table columns to the {@link TableViewerSWTBuilder}. * * @param tableViewerSWTBuilder the builder * @param clazz the {@EClass} of the rendered object * @param cp the content provider * */ private void addColumns(TableViewerSWTBuilder tableViewerSWTBuilder, EClass clazz, ObservableListContentProvider cp) { InternalEObject tempInstance = null; if (!clazz.isAbstract() && !clazz.isInterface()) { tempInstance = getInstanceOf(clazz); } final VTableDomainModelReference tableDomainModelReference = VTableDomainModelReference.class .cast(getVElement().getDomainModelReference()); /* regular columns */ for (final VDomainModelReference dmr : tableDomainModelReference.getColumnDomainModelReferences()) { try { if (dmr == null) { continue; } final IObservableValue text = getLabelText(dmr, true); final IObservableValue tooltip = getLabelTooltipText(dmr, true); final IValueProperty valueProperty = getEMFFormsDatabinding().getValueProperty(dmr, getViewModelContext().getDomainModel()); final EStructuralFeature eStructuralFeature = (EStructuralFeature) valueProperty.getValueType(); final IObservableMap observableMap = valueProperty.observeDetail(cp.getKnownElements()); final TableControlEditingSupportAndLabelProvider labelProvider = new TableControlEditingSupportAndLabelProvider( tempInstance, eStructuralFeature, dmr, valueProperty, observableMap, tableDomainModelReference.getColumnDomainModelReferences().indexOf(dmr)); final EditingSupportCreator editingSupportCreator = TableConfigurationHelper .isReadOnly(getVElement(), dmr) ? null : labelProvider; // TODO ugly: we need this temporary cell editor so early just to get size information final CellEditor tempCellEditor = createCellEditor(tempInstance, eStructuralFeature, new Table(new Shell(), SWT.NONE)); final int weight = ECPCellEditor.class.isInstance(tempCellEditor) ? ECPCellEditor.class.cast(tempCellEditor).getColumnWidthWeight() : 100; final int minWidth = ECPCellEditor.class.isInstance(tempCellEditor) ? ECPCellEditor.class.cast(tempCellEditor).getMinWidth() : 0; tableViewerSWTBuilder.addColumn(true, false, SWT.NONE, weight, minWidth, text, tooltip, labelProvider, editingSupportCreator, null); } catch (final DatabindingFailedException ex) { getReportService().report(new RenderingFailedReport(ex)); continue; } } } private void setupValidation(final TableViewerComposite tableViewerComposite) { if (tableViewerComposite.getValidationControls().isPresent()) { final List<Control> validationControls = tableViewerComposite.getValidationControls().get(); if (validationControls.size() == 1 && Label.class.isInstance(validationControls.get(0))) { validationIcon = (Label) validationControls.get(0); } } } private void setupSorting(final ECPTableViewerComparator comparator, int regularColumnsStartIndex, final TableViewerComposite tableViewerComposite) { for (int i = regularColumnsStartIndex; i < tableViewerComposite.getTableViewer().getTable() .getColumns().length; i++) { final TableColumn tableColumn = tableViewerComposite.getTableViewer().getTable().getColumns()[i]; tableColumn.addSelectionListener(getSelectionAdapter(tableViewerComposite.getTableViewer(), comparator, tableColumn, i - regularColumnsStartIndex)); } } private IObservableValue getLabelText(VDomainModelReference dmrToCheck, boolean forColumn) { final EMFFormsLabelProvider labelService = getEMFFormsLabelProvider(); if (forColumn) { try { return labelService.getDisplayName(dmrToCheck); } catch (final NoLabelFoundException e) { // FIXME Expectation? getReportService().report(new RenderingFailedReport(e)); return Observables.constantObservableValue(e.getMessage(), String.class); } } switch (getVElement().getLabelAlignment()) { case NONE: return Observables.constantObservableValue("", String.class); //$NON-NLS-1$ default: try { return labelService.getDisplayName(dmrToCheck, getViewModelContext().getDomainModel()); } catch (final NoLabelFoundException e) { // FIXME Expectation? getReportService().report(new RenderingFailedReport(e)); return Observables.constantObservableValue(e.getMessage(), String.class); } } } private IObservableValue getLabelTooltipText(VDomainModelReference dmrToCheck, boolean forColumn) { switch (getVElement().getLabelAlignment()) { case NONE: return Observables.constantObservableValue("", String.class); //$NON-NLS-1$ default: final EMFFormsLabelProvider labelService = getEMFFormsLabelProvider(); try { if (forColumn) { return labelService.getDescription(dmrToCheck); } return labelService.getDescription(dmrToCheck, getViewModelContext().getDomainModel()); } catch (final NoLabelFoundException e) { // FIXME Expectation? getReportService().report(new RenderingFailedReport(e)); return Observables.constantObservableValue(e.toString(), String.class); } } } /** * @return the {@link VDomainModelReference} which ends at the table setting */ private VDomainModelReference getDMRToMultiReference() { final VTableDomainModelReference tableDomainModelReference = (VTableDomainModelReference) getVElement() .getDomainModelReference(); final VDomainModelReference dmrToCheck = tableDomainModelReference.getDomainModelReference() == null ? tableDomainModelReference : tableDomainModelReference.getDomainModelReference(); return dmrToCheck; } /** * Allows to add additional buttons to the button bar of the table control. * <p> * The default implementation does not add additional buttons. * </p> * * @param buttonComposite the composite where the buttons are added * @return the total number of buttons added */ protected int addButtonsToButtonBar(Composite buttonComposite) { return 0; } /** * Creates and returns the composite which will be the parent for the table viewer. * * @param composite the parent composite including the title/button bar * @return the parent for the table viewer */ protected Composite createControlComposite(Composite composite) { final Composite controlComposite = new Composite(composite, SWT.NONE); GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).hint(1, getTableHeightHint()) .applyTo(controlComposite); GridLayoutFactory.fillDefaults().numColumns(1).applyTo(controlComposite); return controlComposite; } /** * Returns the preferred height for the table. This will be passed to the layoutdata. * * @return the height in px */ protected int getTableHeightHint() { if (getVElement().isReadonly() && tableViewer != null && tableViewer.getTable() != null) { final Table table = tableViewer.getTable(); final int itemHeight = table.getItemHeight(); // show one empty row if table does not contain any items final int itemCount = Math.max(table.getItemCount(), 1); final int headerHeight = table.getHeaderVisible() ? table.getHeaderHeight() : 0; // 4px needed as a buffer to avoid scrollbars final int tableHeight = itemHeight * itemCount + headerHeight + 4; return Math.min(tableHeight, 200); } return 200; } /** * Returns the table viewer. * * @return the viewer */ protected TableViewer getTableViewer() { return tableViewer; } /** * Sets the table viewer. * * @param tableViewer the viewer */ protected void setTableViewer(TableViewer tableViewer) { this.tableViewer = tableViewer; } // FIXME needed? // /** // * Applies the layout data to the given composite. // * // * @param composite the composite to which the layout data is applied // * // */ // private void setLayoutData(Composite composite) { // GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).hint(1, getTableHeightHint()) // .applyTo(composite); // } /** * This method gets called when the selection on the {@link TableViewer} (see {@link #getTableViewer()}) has * changed. * <p> * If you override this method make sure to call super. * </p> * * @param event the {@link SelectionChangedEvent} */ protected void viewerSelectionChanged(SelectionChangedEvent event) { if (event.getSelection().isEmpty()) { if (getRemoveButton() != null) { getRemoveButton().setEnabled(false); } } else { if (getRemoveButton() != null) { getRemoveButton().setEnabled(true); } } } private SelectionAdapter getSelectionAdapter(final TableViewer tableViewer, final ECPTableViewerComparator comparator, final TableColumn column, final int index) { final SelectionAdapter selectionAdapter = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { comparator.setColumn(index); final int dir = comparator.getDirection(); tableViewer.getTable().setSortDirection(dir); tableViewer.getTable().setSortColumn(column); tableViewer.refresh(); } }; return selectionAdapter; } private void createFixedValidationStatusColumn(TableViewerSWTBuilder tableViewerSWTBuilder) { final VTTableValidationStyleProperty tableValidationStyleProperty = getTableValidationStyleProperty(); final int columnWidth = tableValidationStyleProperty.getColumnWidth(); final String columnName = tableValidationStyleProperty.getColumnName(); final String imagePath = tableValidationStyleProperty.getImagePath(); Image image = null; if (imagePath != null && !imagePath.isEmpty()) { try { image = getImage(new File(imagePath).toURI().toURL()); } catch (final MalformedURLException ex) { getReportService().report(new AbstractReport(ex)); } } tableViewerSWTBuilder.addColumn(true, false, SWT.NONE, 0, columnWidth, columnName, columnName, new ValidationStatusCellLabelProvider(getVElement()), null, image); } /** * Retrieve images from the {@link ImageRegistryService} using an {@link URL}. * * @param url The {@link URL} pointing to the image * @return The retrieved Image * @since 1.6 */ protected Image getImage(URL url) { return imageRegistryService.getImage(url); } /** * Retrieve images from the {@link ImageRegistryService} using a bundle relative path. * * @param path The bundle relative path pointing to the image * @return The retrieved Image * @since 1.6 */ protected Image getImage(String path) { return imageRegistryService.getImage(FrameworkUtil.getBundle(TableControlSWTRenderer.class), path); } private VTTableValidationStyleProperty getTableValidationStyleProperty() { VTTableValidationStyleProperty tableValidationStyleProperties = getStyleProperty( VTTableValidationStyleProperty.class); if (tableValidationStyleProperties == null) { tableValidationStyleProperties = getDefaultTableValidationStyleProperty(); } return tableValidationStyleProperties; } private VTTableValidationStyleProperty getDefaultTableValidationStyleProperty() { final VTTableValidationStyleProperty tableValidationProp = VTTableValidationFactory.eINSTANCE .createTableValidationStyleProperty(); tableValidationProp.setColumnWidth(80); tableValidationProp.setColumnName(LocalizationServiceHelper.getString(TableControlSWTRenderer.class, MessageKeys.TableControl_ValidationStatusColumn)); tableValidationProp.setImagePath(null); return tableValidationProp; } private VTBackgroundStyleProperty getBackgroundStyleProperty() { VTBackgroundStyleProperty styleProperty = getStyleProperty(VTBackgroundStyleProperty.class); if (styleProperty == null) { styleProperty = getDefaultBackgroundStyleProperty(); } return styleProperty; } private VTBackgroundStyleProperty getDefaultBackgroundStyleProperty() { return VTBackgroundFactory.eINSTANCE.createBackgroundStyleProperty(); } private VTFontPropertiesStyleProperty getFontPropertiesStyleProperty() { VTFontPropertiesStyleProperty styleProperty = getStyleProperty(VTFontPropertiesStyleProperty.class); if (styleProperty == null) { styleProperty = getDefaultFontPropertiesStyleProperty(); } return styleProperty; } private VTFontPropertiesStyleProperty getDefaultFontPropertiesStyleProperty() { final VTFontPropertiesStyleProperty property = VTFontPropertiesFactory.eINSTANCE .createFontPropertiesStyleProperty(); property.setColorHEX("000000"); //$NON-NLS-1$ return property; } /** * Returns a {@link VTStyleProperty} of the given class or <code>null</code> if none was found. * * @param stylePropertyClass the style property class * @return the property or <code>null</code> */ private <SP extends VTStyleProperty> SP getStyleProperty(Class<SP> stylePropertyClass) { final Set<VTStyleProperty> styleProperties = getVTViewTemplateProvider().getStyleProperties(getVElement(), getViewModelContext()); for (final VTStyleProperty styleProperty : styleProperties) { if (stylePropertyClass.isInstance(styleProperty)) { return stylePropertyClass.cast(styleProperty); } } return null; } private Color getSWTColor(String colorHex) { final String redString = colorHex.substring(0, 2); final String greenString = colorHex.substring(2, 4); final String blueString = colorHex.substring(4, 6); final int red = Integer.parseInt(redString, 16); final int green = Integer.parseInt(greenString, 16); final int blue = Integer.parseInt(blueString, 16); return new Color(Display.getDefault(), red, green, blue); } /** * This is called in order to setup the editing support for a table column. * * @param tempInstance the temporary input instance of the table * @param feature the feature of the column * @param table the table/parent * @return the cell editor * @since 1.8 */ protected CellEditor createCellEditor(final EObject tempInstance, final EStructuralFeature feature, Table table) { return CellEditorFactory.INSTANCE.getCellEditor(feature, tempInstance, table, getViewModelContext()); } private InternalEObject getInstanceOf(EClass clazz) { return InternalEObject.class.cast(clazz.getEPackage().getEFactoryInstance().create(clazz)); } private Button createRemoveRowButton(EClass clazz, final Composite buttonComposite, final EObject eObject, final EStructuralFeature structuralFeature) { removeButton = new Button(buttonComposite, SWT.None); final Image image = getImage(ICON_DELETE); removeButton.setImage(image); removeButton.setEnabled(false); final String instanceName = clazz.getInstanceClass() == null ? "" //$NON-NLS-1$ : clazz.getInstanceClass().getSimpleName(); removeButton.setToolTipText(String.format(LocalizationServiceHelper.getString(TableControlSWTRenderer.class, MessageKeys.TableControl_RemoveSelected), instanceName)); final List<?> containments = (List<?>) eObject.eGet(structuralFeature, true); if (containments.size() <= structuralFeature.getLowerBound()) { removeButton.setEnabled(false); } return removeButton; } private Button createAddRowButton(final EClass clazz, final Composite buttonComposite, final EObject eObject, final EStructuralFeature structuralFeature) { addButton = new Button(buttonComposite, SWT.None); final Image image = getImage(ICON_ADD); addButton.setImage(image); final String instanceName = clazz.getInstanceClass() == null ? "" //$NON-NLS-1$ : clazz.getInstanceClass().getSimpleName(); addButton.setToolTipText(String.format(LocalizationServiceHelper.getString(TableControlSWTRenderer.class, MessageKeys.TableControl_AddInstanceOf), instanceName)); final List<?> containments = (List<?>) eObject.eGet(structuralFeature, true); if (structuralFeature.getUpperBound() != -1 && containments.size() >= structuralFeature.getUpperBound()) { addButton.setEnabled(false); } return addButton; } /** * This method shows a user confirmation dialog when the user attempts to delete a row in the table. * * @param deletionList the list of selected EObjects to delete * @param eObject The containment reference {@link EObject} * @param structuralFeature The containment reference {@link EStructuralFeature} * @param addButton the add button * @param removeButton the remove button * @since 1.6 */ protected void deleteRowUserConfirmDialog(final List<EObject> deletionList, final EObject eObject, final EStructuralFeature structuralFeature, final Button addButton, final Button removeButton) { final MessageDialog dialog = new MessageDialog(addButton.getShell(), LocalizationServiceHelper.getString(TableControlSWTRenderer.class, MessageKeys.TableControl_Delete), null, LocalizationServiceHelper.getString(TableControlSWTRenderer.class, MessageKeys.TableControl_DeleteAreYouSure), MessageDialog.CONFIRM, new String[] { JFaceResources.getString(IDialogLabelKeys.YES_LABEL_KEY), JFaceResources.getString(IDialogLabelKeys.NO_LABEL_KEY) }, 0); new ECPDialogExecutor(dialog) { @Override public void handleResult(int codeResult) { if (codeResult == IDialogConstants.CANCEL_ID || codeResult == SWT.DEFAULT) { // SWT.DEFAULT is return by closing a message dialog return; } deleteRows(deletionList, eObject, structuralFeature); final List<?> containments = (List<?>) eObject.eGet(structuralFeature, true); if (containments.size() < structuralFeature.getUpperBound()) { addButton.setEnabled(true); } if (containments.size() <= structuralFeature.getLowerBound()) { removeButton.setEnabled(false); } } }.execute(); } /** * This is called by {@link #deleteRowUserConfirmDialog(List)} after the user confirmed to delete the selected * elements. * * @param deletionList the list of {@link EObject EObjects} to delete * @param eObject The containment reference {@link EObject} * @param structuralFeature The containment reference {@link EStructuralFeature} * @since 1.6 */ protected void deleteRows(List<EObject> deletionList, final EObject eObject, final EStructuralFeature structuralFeature) { final EditingDomain editingDomain = getEditingDomain(eObject); /* assured by #isApplicable */ final EReference reference = EReference.class.cast(structuralFeature); final List<Object> toDelete = new ArrayList<Object>(deletionList); if (reference.isContainment()) { DeleteService deleteService = getViewModelContext().getService(DeleteService.class); if (deleteService == null) { /* * #getService(Class<?>) will report to the reportservice if it could not be found * Use Default */ deleteService = new EMFDeleteServiceImpl(); } deleteService.deleteElements(toDelete); } else { removeElements(editingDomain, eObject, reference, toDelete); } } private void removeElements(EditingDomain editingDomain, Object source, EStructuralFeature feature, Collection<Object> toRemove) { final Command removeCommand = RemoveCommand.create(editingDomain, source, feature, toRemove); if (removeCommand.canExecute()) { if (editingDomain.getCommandStack() == null) { removeCommand.execute(); } else { editingDomain.getCommandStack().execute(removeCommand); } } } /** * This method is called to add a new entry in the domain model and thus to create a new row in the table. The * element to create is defined by the provided class. * You can override this method but you have to call super nonetheless. * * @param clazz the {@link EClass} defining the EObject to create * @param eObject The containment reference {@link EObject} * @param structuralFeature The containment reference {@link EStructuralFeature} * @since 1.6 */ protected void addRow(EClass clazz, EObject eObject, EStructuralFeature structuralFeature) { if (clazz.isAbstract() || clazz.isInterface()) { getReportService() .report(new StatusReport(new Status(IStatus.WARNING, "org.eclipse.emf.ecp.view.table.ui.swt", //$NON-NLS-1$ String.format("The class %1$s is abstract or an interface.", clazz.getName())))); //$NON-NLS-1$ } final EObject instance = clazz.getEPackage().getEFactoryInstance().create(clazz); final EditingDomain editingDomain = getEditingDomain(eObject); if (editingDomain == null) { } editingDomain.getCommandStack() .execute(AddCommand.create(editingDomain, eObject, structuralFeature, instance)); } @Override protected void applyValidation() { Display.getDefault().asyncExec(new ApplyValidationRunnable()); } /** * Returns the add button created by the framework. * * @return the addButton * @since 1.6 */ protected Button getAddButton() { return addButton; } /** * Returns the remove button created by the framework. * * @return the removeButton * @since 1.6 */ protected Button getRemoveButton() { return removeButton; } /** * {@inheritDoc} * * @see org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer#applyEnable() */ @Override protected void applyEnable() { if (getAddButton() != null) { getAddButton().setVisible(getVElement().isEnabled() && !getVElement().isReadonly()); } if (getRemoveButton() != null) { getRemoveButton().setVisible(getVElement().isEnabled() && !getVElement().isReadonly()); } } /** * {@inheritDoc} * * @see org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer#applyReadOnly() */ @Override protected void applyReadOnly() { if (getAddButton() != null) { getAddButton().setVisible(getVElement().isEnabled() && !getVElement().isReadonly()); } if (getRemoveButton() != null) { getRemoveButton().setVisible(getVElement().isEnabled() && !getVElement().isReadonly()); } } /** * {@inheritDoc} * * @see org.eclipse.emfforms.spi.swt.core.AbstractSWTRenderer#dispose() */ @Override protected void dispose() { rendererGridDescription = null; viewModelDBC.dispose(); super.dispose(); } /** * Get called by the {@link ECPTableViewerComparator} in order to compare the given objects. * * @param viewer the tavle viewer * @param e1 the first object of the comparison * @param e2 the second object of the comparison * @param propertyIndex index of the selection column. the index is aligned with the index of the associated column * domain model reference * @param direction {@link SWT#NONE}, {@link SWT#UP} or {@link SWT#DOWN} according to the indication displayed at * the table column. * @return a negative number if the first element is less than the * second element; the value <code>0</code> if the first element is * equal to the second element; and a positive number if the first * element is greater than the second element * @since 1.8 */ protected int compare(Viewer viewer, Object e1, Object e2, int direction, int propertyIndex) { if (direction == 0) { return 0; } int rc = 0; final EObject object1 = (EObject) e1; final EObject object2 = (EObject) e2; Object value1; Object value2; final VDomainModelReference dmr = ((VTableDomainModelReference) getVElement().getDomainModelReference()) .getColumnDomainModelReferences().get(propertyIndex); final EMFFormsDatabinding emfFormsDatabinding = getEMFFormsDatabinding(); try { final IObservableValue observableValue1 = emfFormsDatabinding.getObservableValue(dmr, object1); final EStructuralFeature structuralFeature1 = (EStructuralFeature) observableValue1.getValueType(); final EObject observed1 = (EObject) ((IObserving) observableValue1).getObserved(); value1 = observed1.eGet(structuralFeature1, true); observableValue1.dispose(); } catch (final DatabindingFailedException ex) { value1 = null; } try { final IObservableValue observableValue2 = emfFormsDatabinding.getObservableValue(dmr, object2); final EStructuralFeature structuralFeature2 = (EStructuralFeature) observableValue2.getValueType(); final EObject observed2 = (EObject) ((IObserving) observableValue2).getObserved(); value2 = observed2.eGet(structuralFeature2, true); observableValue2.dispose(); } catch (final DatabindingFailedException ex) { value2 = null; } if (columnIndexToComparatorMap.containsKey(propertyIndex)) { return columnIndexToComparatorMap.get(propertyIndex).compare(value1, value2, direction); } if (value1 == null) { rc = 1; } else if (value2 == null) { rc = -1; } else { rc = value1.toString().compareTo(value2.toString()); } // If descending order, flip the direction if (direction == 2) { rc = -rc; } return rc; } /** * Runnable which is called by {@link TableControlSWTRenderer#applyValidation() applyValidation}. * */ private final class ApplyValidationRunnable implements Runnable { @Override public void run() { // triggered due to another validation rule before this control is rendered if (validationIcon == null) { return; } // validation rule triggered after the control was disposed if (validationIcon.isDisposed()) { return; } // no diagnostic set if (getVElement().getDiagnostic() == null) { return; } final VTableDomainModelReference tableDMR = (VTableDomainModelReference) getVElement() .getDomainModelReference(); IObservableValue observableValue; try { if (tableDMR.getDomainModelReference() != null) { observableValue = getEMFFormsDatabinding().getObservableValue( tableDMR.getDomainModelReference(), getViewModelContext().getDomainModel()); } else { observableValue = getEMFFormsDatabinding().getObservableValue(tableDMR, getViewModelContext().getDomainModel()); } } catch (final DatabindingFailedException ex) { getReportService().report(new DatabindingFailedReport(ex)); return; } final EStructuralFeature structuralFeature = (EStructuralFeature) observableValue.getValueType(); final EObject eObject = (EObject) ((IObserving) observableValue).getObserved(); observableValue.dispose(); validationIcon.setImage(getValidationIcon(getVElement().getDiagnostic().getHighestSeverity())); validationIcon.setToolTipText( ECPTooltipModifierHelper.modifyString(getVElement().getDiagnostic().getMessage(), null)); final Collection<?> collection = (Collection<?>) eObject.eGet(structuralFeature, true); if (!collection.isEmpty()) { for (final Object object : collection) { tableViewer.update(object, null); } } } } /** * Implements {@link EditingSupportCreator} and {@link CellLabelProviderFactory} for the table control swt renderer. * * This allows us to access the actual cell editor from the cell label provider. * * @author Johannes Faltermeier * */ private final class TableControlEditingSupportAndLabelProvider implements EditingSupportCreator, CellLabelProviderFactory { private final InternalEObject tempInstance; private final EStructuralFeature eStructuralFeature; private final VDomainModelReference dmr; private final IValueProperty valueProperty; private final IObservableMap observableMap; private CellEditor cellEditor; private ECPTableEditingSupport observableSupport; private boolean initialized; private final int indexOfColumn; private TableControlEditingSupportAndLabelProvider(InternalEObject tempInstance, EStructuralFeature eStructuralFeature, VDomainModelReference dmr, IValueProperty valueProperty, IObservableMap observableMap, int indexOfColumn) { this.tempInstance = tempInstance; this.eStructuralFeature = eStructuralFeature; this.dmr = dmr; this.valueProperty = valueProperty; this.observableMap = observableMap; this.indexOfColumn = indexOfColumn; } @Override public EditingSupport createEditingSupport(TableViewer tableViewer) { if (!initialized) { init(tableViewer); } return observableSupport; } private void init(TableViewer tableViewer) { cellEditor = createCellEditor(tempInstance, eStructuralFeature, tableViewer.getTable()); if (ECPCellEditorComparator.class.isInstance(cellEditor)) { columnIndexToComparatorMap.put(indexOfColumn, ECPCellEditorComparator.class.cast(cellEditor)); } observableSupport = new ECPTableEditingSupport(tableViewer, cellEditor, getVElement(), dmr, valueProperty); initialized = true; } @Override public CellLabelProvider createCellLabelProvider(TableViewer table) { if (!initialized) { init(table); } return new ECPCellLabelProvider(eStructuralFeature, cellEditor, observableMap, getVElement(), dmr, table.getTable()); } } /** * {@link TableViewerCreator} for the table control swt renderer. It will create a TableViewer with the expected * custum cariant data and the correct style properties as defined in the template model. * */ private final class TableControlSWTRendererTableViewerCreator implements TableViewerCreator { @Override public TableViewer createTableViewer(Composite parent) { tableViewer = new TableViewer(parent, SWT.MULTI | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER); tableViewer.getTable().setData(CUSTOM_VARIANT, TABLE_CUSTOM_VARIANT); tableViewer.getTable().setHeaderVisible(true); tableViewer.getTable().setLinesVisible(true); /* Set background color */ final VTBackgroundStyleProperty backgroundStyleProperty = getBackgroundStyleProperty(); if (backgroundStyleProperty.getColor() != null) { tableViewer.getTable().setBackground(getSWTColor(backgroundStyleProperty.getColor())); } /* Set foreground color */ final VTFontPropertiesStyleProperty fontPropertiesStyleProperty = getFontPropertiesStyleProperty(); if (fontPropertiesStyleProperty.getColorHEX() != null) { tableViewer.getTable().setForeground(getSWTColor(fontPropertiesStyleProperty.getColorHEX())); } tableViewer.getTable().setData(FIXED_COLUMNS, new Integer(1)); return tableViewer; } } /** * {@link ButtonBarBuilder} for the table control swt renderer. It will call the existing template methods which * allows subclasses to change the buttons. * */ private final class TableControlSWTRendererButtonBarBuilder implements ButtonBarBuilder { private final EStructuralFeature structuralFeature; private final EClass clazz; private final EObject eObject; private TableControlSWTRendererButtonBarBuilder(EStructuralFeature structuralFeature, EClass clazz, EObject eObject) { this.structuralFeature = structuralFeature; this.clazz = clazz; this.eObject = eObject; } @Override public void fillButtonComposite(Composite buttonComposite, TableViewer viewer) { int numButtons = addButtonsToButtonBar(buttonComposite); if (!getVElement().isAddRemoveDisabled()) { addButton = createAddRowButton(clazz, buttonComposite, eObject, structuralFeature); removeButton = createRemoveRowButton(clazz, buttonComposite, eObject, structuralFeature); numButtons = numButtons + 2; initButtons(addButton, removeButton, viewer); } GridLayoutFactory.fillDefaults().numColumns(numButtons).equalWidth(false).applyTo(buttonComposite); } private void initButtons(final Button addButton, final Button removeButton, final TableViewer viewer) { addButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { addRow(clazz, eObject, structuralFeature); final List<?> containments = (List<?>) eObject.eGet(structuralFeature, true); if (structuralFeature.getUpperBound() != -1 && containments.size() >= structuralFeature.getUpperBound()) { addButton.setEnabled(false); } if (containments.size() > structuralFeature.getLowerBound()) { addButton.setEnabled(true); } } }); removeButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { final IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); if (selection == null || selection.getFirstElement() == null) { return; } final List<EObject> deletionList = new ArrayList<EObject>(); final Iterator<?> iterator = selection.iterator(); while (iterator.hasNext()) { deletionList.add((EObject) iterator.next()); } deleteRowUserConfirmDialog(deletionList, eObject, structuralFeature, addButton, removeButton); } }); } @Override public Object createNewElement(Button button) { throw new UnsupportedOperationException(); } } /** * {@link org.eclipse.emfforms.spi.swt.table.TableViewerCompositeBuilder TableViewerCompositeBuilder} which calls * the existing template method to create the validation label. * */ @SuppressWarnings("restriction") private final class TableControlSWTRendererCompositeBuilder extends org.eclipse.emfforms.internal.swt.table.DefaultTableViewerCompositeBuilder { @Override protected Label createValidationLabel(Composite topComposite) { final Label validationLabel = createValidationIcon(topComposite); GridDataFactory.fillDefaults().hint(16, 17).grab(false, false).applyTo(validationLabel); return validationLabel; } @Override protected Composite createViewerComposite(Composite composite) { return createControlComposite(composite); } } /** * The {@link ViewerComparator} for this table which allows 3 states for sort order: * none, up and down. * * @author Eugen Neufeld * */ private class ECPTableViewerComparator extends ViewerComparator { private int propertyIndex; private static final int NONE = 0; private int direction = NONE; ECPTableViewerComparator() { propertyIndex = 0; direction = NONE; } public int getDirection() { switch (direction) { case 0: return SWT.NONE; case 1: return SWT.UP; case 2: return SWT.DOWN; default: return SWT.NONE; } } public void setColumn(int column) { if (column == propertyIndex) { // Same column as last sort; toggle the direction direction = (direction + 1) % 3; } else { // New column; do an ascending sort propertyIndex = column; direction = 1; } } @Override public int compare(Viewer viewer, Object e1, Object e2) { return TableControlSWTRenderer.this.compare(viewer, e1, e2, direction, propertyIndex); } } /** * ECP specficic cell label provider that does also implement {@link IColorProvider} in * order to correctly. * * @author emueller * */ public class ECPCellLabelProvider extends ObservableMapCellLabelProvider implements IColorProvider { private final EStructuralFeature feature; private final CellEditor cellEditor; private final VTableControl vTableControl; private final VDomainModelReference dmr; private final Table table; /** * Constructor. * * @param feature * the {@link EStructuralFeature} the cell is bound to * @param cellEditor * the {@link CellEditor} instance * @param attributeMap * an {@link IObservableMap} instance that is passed to the {@link ObservableMapCellLabelProvider} * @param vTableControl the {@link VTableControl} * @param dmr the {@link VDomainModelReference} for this cell * @param table the swt table * @since 1.6 */ public ECPCellLabelProvider(EStructuralFeature feature, CellEditor cellEditor, IObservableMap attributeMap, VTableControl vTableControl, VDomainModelReference dmr, Table table) { super(attributeMap); this.vTableControl = vTableControl; this.feature = feature; this.cellEditor = cellEditor; this.dmr = dmr; this.table = table; } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipText(java.lang.Object) */ @Override public String getToolTipText(Object element) { final EObject domainObject = (EObject) element; IObservableValue observableValue; try { observableValue = getEMFFormsDatabinding().getObservableValue(dmr, domainObject); } catch (final DatabindingFailedException ex) { getReportService().report(new DatabindingFailedReport(ex)); return null; } final EStructuralFeature structuralFeature = (EStructuralFeature) observableValue.getValueType(); final EObject eObject = (EObject) ((IObserving) observableValue).getObserved(); final Setting setting = ((InternalEObject) eObject).eSetting(structuralFeature); observableValue.dispose(); final VDiagnostic vDiagnostic = vTableControl.getDiagnostic(); if (vDiagnostic != null) { final String message = DiagnosticMessageExtractor .getMessage(vDiagnostic.getDiagnostic(domainObject, feature)); if (message != null && !message.isEmpty()) { return ECPTooltipModifierHelper.modifyString(message, setting); } } final Object value = eObject.eGet(structuralFeature, true); if (value == null) { return null; } return ECPTooltipModifierHelper.modifyString(String.valueOf(value), setting); } @Override public void update(ViewerCell cell) { final EObject element = (EObject) cell.getElement(); final Object value = attributeMaps[0].get(element); if (ECPCellEditor.class.isInstance(cellEditor)) { final ECPCellEditor ecpCellEditor = (ECPCellEditor) cellEditor; final String text = ecpCellEditor.getFormatedString(value); cell.setText(text == null ? "" : text); //$NON-NLS-1$ cell.setImage(ecpCellEditor.getImage(value)); } else { cell.setText(value == null ? "" : value.toString()); //$NON-NLS-1$ cell.getControl().setData(CUSTOM_VARIANT, "org_eclipse_emf_ecp_edit_cellEditor_string"); //$NON-NLS-1$ } cell.setForeground(getForeground(element)); cell.setBackground(getBackground(element)); } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object) */ @Override public Color getForeground(Object element) { return table.getForeground(); } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object) */ @Override public Color getBackground(Object element) { final VDiagnostic vDiagnostic = vTableControl.getDiagnostic(); if (vDiagnostic == null) { return getValidationBackgroundColor(Diagnostic.OK); } final List<Diagnostic> diagnostic = vDiagnostic.getDiagnostic((EObject) element, feature); return getValidationBackgroundColor( diagnostic.size() == 0 ? Diagnostic.OK : diagnostic.get(0).getSeverity()); } } /** * Implementation of the {@link EditingSupport} for the generic ECP Table. * * @author Eugen Neufeld * */ private class ECPTableEditingSupport extends EditingSupport { private final CellEditor cellEditor; private final VTableControl tableControl; private final IValueProperty valueProperty; private final VDomainModelReference domainModelReference; /** * @param viewer */ ECPTableEditingSupport(ColumnViewer viewer, CellEditor cellEditor, VTableControl tableControl, VDomainModelReference domainModelReference, IValueProperty valueProperty) { super(viewer); this.cellEditor = cellEditor; this.tableControl = tableControl; this.valueProperty = valueProperty; this.domainModelReference = domainModelReference; } private EditingState editingState; private final ColumnViewerEditorActivationListenerHelper activationListener = new ColumnViewerEditorActivationListenerHelper(); /** * Default implementation always returns <code>true</code>. * * @see org.eclipse.jface.viewers.EditingSupport#canEdit(java.lang.Object) */ @Override protected boolean canEdit(Object element) { boolean editable = tableControl.isEnabled() && !tableControl.isReadonly(); final IObservableValue observableValue = valueProperty.observe(element); final EObject eObject = (EObject) ((IObserving) observableValue).getObserved(); final EStructuralFeature structuralFeature = (EStructuralFeature) observableValue.getValueType(); final Setting setting = ((InternalEObject) eObject).eSetting(structuralFeature); editable &= emfFormsEditSupport.canSetProperty(domainModelReference, (EObject) element); editable &= !CellReadOnlyTesterHelper.getInstance().isReadOnly(getVElement(), setting); if (ECPCellEditor.class.isInstance(cellEditor)) { ECPCellEditor.class.cast(cellEditor).setEditable(editable); return true; } return editable; } /** * Default implementation always returns <code>null</code> as this will be * handled by the Binding. * * @see org.eclipse.jface.viewers.EditingSupport#getValue(java.lang.Object) */ @Override protected Object getValue(Object element) { // no op return null; } /** * Default implementation does nothing as this will be handled by the * Binding. * * @see org.eclipse.jface.viewers.EditingSupport#setValue(java.lang.Object, java.lang.Object) */ @Override protected void setValue(Object element, Object value) { // no op } /** * Creates a {@link Binding} between the editor and the element to be * edited. Invokes {@link #doCreateCellEditorObservable(CellEditor)}, * {@link #doCreateElementObservable(Object, ViewerCell)}, and then * {@link #createBinding(IObservableValue, IObservableValue)}. */ @Override protected void initializeCellEditorValue(CellEditor cellEditor, ViewerCell cell) { final IObservableValue target = doCreateCellEditorObservable(cellEditor); Assert.isNotNull(target, "doCreateCellEditorObservable(...) did not return an observable"); //$NON-NLS-1$ final IObservableValue model = valueProperty.observe(cell.getElement()); Assert.isNotNull(model, "The databinding service did not return an observable"); //$NON-NLS-1$ final Binding binding = createBinding(target, model); Assert.isNotNull(binding, "createBinding(...) did not return a binding"); //$NON-NLS-1$ editingState = new EditingState(binding, target, model); getViewer().getColumnViewerEditor().addEditorActivationListener(activationListener); } @Override protected CellEditor getCellEditor(Object element) { return cellEditor; } protected Binding createBinding(IObservableValue target, IObservableValue model) { if (ECPCellEditor.class.isInstance(cellEditor)) { return getDataBindingContext().bindValue(target, model, ((ECPCellEditor) cellEditor).getTargetToModelStrategy(getDataBindingContext()), ((ECPCellEditor) cellEditor).getModelToTargetStrategy(getDataBindingContext())); } return getDataBindingContext().bindValue(target, model); } protected IObservableValue doCreateCellEditorObservable(CellEditor cellEditor) { if (ECPCellEditor.class.isInstance(cellEditor)) { return ((ECPCellEditor) cellEditor).getValueProperty().observe(cellEditor); } return WidgetProperties.text(SWT.FocusOut).observe(cellEditor.getControl()); } @Override protected final void saveCellEditorValue(CellEditor cellEditor, ViewerCell cell) { editingState.binding.updateTargetToModel(); } /** * A ColumnViewerEditorActivationListener to reset the cells after focus lost. * * @author Eugen Neufeld * */ private class ColumnViewerEditorActivationListenerHelper extends ColumnViewerEditorActivationListener { @Override public void afterEditorActivated(ColumnViewerEditorActivationEvent event) { // set colors for cell editor final Control control = cellEditor.getControl(); if (control == null || control.isDisposed()) { return; } control.setBackground(getViewer().getControl().getBackground()); control.setForeground(getViewer().getControl().getForeground()); } @Override public void afterEditorDeactivated(ColumnViewerEditorDeactivationEvent event) { editingState.dispose(); editingState = null; getViewer().getColumnViewerEditor().removeEditorActivationListener(this); final ViewerCell focusCell = getViewer().getColumnViewerEditor().getFocusCell(); if (focusCell != null) { getViewer().update(focusCell.getElement(), null); } } @Override public void beforeEditorActivated(ColumnViewerEditorActivationEvent event) { // do nothing } @Override public void beforeEditorDeactivated(ColumnViewerEditorDeactivationEvent event) { // do nothing } } /** * Maintains references to objects that only live for the length of the edit * cycle. */ class EditingState { private final IObservableValue target; private final IObservableValue model; private final Binding binding; EditingState(Binding binding, IObservableValue target, IObservableValue model) { this.binding = binding; this.target = target; this.model = model; } void dispose() { binding.dispose(); target.dispose(); model.dispose(); } } } /** * The {@link CellLabelProvider} to update the validation status on the cells. * * @author Eugen Neufeld * */ private class ValidationStatusCellLabelProvider extends CellLabelProvider { private final VTableControl vTableControl; ValidationStatusCellLabelProvider(VTableControl vTableControl) { this.vTableControl = vTableControl; } @Override public void update(ViewerCell cell) { Integer mostSevere = Diagnostic.OK; final VDiagnostic vDiagnostic = vTableControl.getDiagnostic(); if (vDiagnostic == null) { return; } final List<Diagnostic> diagnostics = vDiagnostic.getDiagnostics((EObject) cell.getElement()); if (diagnostics.size() != 0) { mostSevere = diagnostics.get(0).getSeverity(); } cell.setImage(getValidationIcon(mostSevere)); } @Override public String getToolTipText(Object element) { final VDiagnostic vDiagnostic = vTableControl.getDiagnostic(); if (vDiagnostic == null) { return null; } final String message = DiagnosticMessageExtractor .getMessage(vDiagnostic.getDiagnostics((EObject) element)); return ECPTooltipModifierHelper.modifyString(message, null); } } }