Skip to content

Content of file TableControl.java

/*******************************************************************************
 * Copyright (c) 2011-2015 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 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:
 * Eugen Neufeld - initial API and implementation
 *
 *******************************************************************************/
package org.eclipse.emf.ecp.edit.internal.swt.controls;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.databinding.Binding;
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.runtime.Assert;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.databinding.EMFProperties;
import org.eclipse.emf.databinding.EObjectObservableMap;
import org.eclipse.emf.databinding.edit.EMFEditObservables;
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.ecp.edit.internal.swt.Activator;
import org.eclipse.emf.ecp.edit.internal.swt.table.TableColumnConfiguration;
import org.eclipse.emf.ecp.edit.internal.swt.table.TableControlConfiguration;
import org.eclipse.emf.ecp.edit.internal.swt.util.CellEditorFactory;
import org.eclipse.emf.ecp.edit.internal.swt.util.SWTControl;
import org.eclipse.emf.ecp.edit.internal.swt.util.SWTRenderingHelper;
import org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor;
import org.eclipse.emf.ecp.edit.spi.swt.util.ECPDialogExecutor;
import org.eclipse.emf.ecp.view.spi.model.VDiagnostic;
import org.eclipse.emf.ecp.view.spi.renderer.RenderingResultRow;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.RemoveCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.emfforms.spi.localization.LocalizationServiceHelper;
import org.eclipse.jface.databinding.swt.SWTObservables;
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.layout.TableColumnLayout;
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.ColumnViewerEditor;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationListener;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TableViewerEditor;
import org.eclipse.jface.viewers.TableViewerFocusCellManager;
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.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
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.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TableColumn;

/**
 * The class describing a table control.
 *
 * @author Eugen Neufeld
 * @author emueller
 */
// this class is not serialized
@Deprecated
public class TableControl extends SWTControl {

	private static final String FIXED_COLUMNS = "org.eclipse.rap.rwt.fixedColumns"; //$NON-NLS-1$

	private static final String ICON_ADD = "icons/add.png"; //$NON-NLS-1$
	private static final String ICONS_UNSET_REFERENCE = "icons/unset_reference.png"; //$NON-NLS-1$
	private static final String ICONS_UNSET_FEATURE = "icons/unset_feature.png"; //$NON-NLS-1$

	private TableViewer tableViewer;
	private ComposedAdapterFactory composedAdapterFactory;
	private AdapterFactoryItemDelegator adapterFactoryItemDelegator;
	private Button unsetButton;
	private EClass clazz;
	private TableControlConfiguration tableControlConfiguration;
	private boolean editable = true;

	private EReference getTableReference() {
		return (EReference) getFirstStructuralFeature();
	}

	/**
	 *
	 * @param tableControlConfiguration the {@link TableControlConfiguration} to use when creating the table
	 */
	public final void setTableControlConfiguration(TableControlConfiguration tableControlConfiguration) {
		this.tableControlConfiguration = tableControlConfiguration;
	}

	@Override
	protected Binding bindValue() {
		return null;
	}

	/**
	 *
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.emf.ecp.edit.internal.swt.util.ECPControlSWT#createControls(org.eclipse.swt.widgets.Composite)
	 */
	@Override
	public List<RenderingResultRow<Control>> createControls(final Composite parent) {
		final IItemPropertyDescriptor itemPropertyDescriptor = getItemPropertyDescriptor(getFirstSetting());
		if (itemPropertyDescriptor == null) {
			return null;
		}
		parent.addDisposeListener(new DisposeListener() {

			@Override
			public void widgetDisposed(DisposeEvent e) {
				dispose();
			}
		});
		final List<RenderingResultRow<Control>> list = Collections.singletonList(SWTRenderingHelper.INSTANCE
			.getResultRowFactory().createRenderingResultRow(
				createControl(parent)));

		applyValidation(getControl().getDiagnostic());
		return list;

	}

	@Override
	public Composite createControl(final Composite parent) {
		mainSetting = getFirstSetting();
		composedAdapterFactory = new ComposedAdapterFactory(new AdapterFactory[] {
			new ReflectiveItemProviderAdapterFactory(),
			new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE) });

		adapterFactoryItemDelegator = new AdapterFactoryItemDelegator(composedAdapterFactory);

		clazz = getTableReference().getEReferenceType();

		final Composite composite = new Composite(parent, SWT.NONE);
		composite.setLayout(new GridLayout(1, false));
		composite.setBackground(parent.getBackground());

		final Composite titleComposite = new Composite(composite, SWT.NONE);
		titleComposite.setBackground(parent.getBackground());
		GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.BEGINNING)
			.applyTo(titleComposite);
		GridLayoutFactory.fillDefaults().numColumns(3).equalWidth(false).applyTo(titleComposite);

		final Label label = new Label(titleComposite, SWT.NONE);
		label.setBackground(parent.getBackground());
		label.setText(getItemPropertyDescriptor(mainSetting).getDisplayName(null));
		GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).grab(true, false).applyTo(label);

		// VALIDATION
		validationLabel = new Label(titleComposite, SWT.NONE);
		validationLabel.setBackground(parent.getBackground());
		// set the size of the label to the size of the image
		GridDataFactory.fillDefaults().hint(16, 17).applyTo(validationLabel);

		boolean createButtons = true;
		if (tableControlConfiguration != null) {
			createButtons = !tableControlConfiguration.isAddRemoveDisabled();
		}
		if (createButtons) {
			// addButtons
			final Composite buttonComposite = new Composite(titleComposite, SWT.NONE);
			GridDataFactory.fillDefaults().align(SWT.END, SWT.BEGINNING).grab(true, false).applyTo(buttonComposite);
			int numButtons = 2;

			createAddRowButton(clazz, buttonComposite);
			createRemoveRowButton(clazz, buttonComposite);
			if (!isEmbedded() && getTableReference().isUnsettable()) {
				unsetButton = new Button(buttonComposite, SWT.PUSH);
				unsetButton.setToolTipText(getUnsetButtonTooltip());
				unsetButton.setImage(Activator.getImage(ICONS_UNSET_FEATURE));
				numButtons++;
			}
			GridLayoutFactory.fillDefaults().numColumns(numButtons).equalWidth(true).applyTo(buttonComposite);
		}
		final Composite controlComposite = new Composite(composite, SWT.NONE);
		GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL,
			SWT.FILL).applyTo(controlComposite);
		GridLayoutFactory.fillDefaults().numColumns(1).applyTo(controlComposite);

		// delegate to super class
		createContentControl(controlComposite);

		return composite;
	}

	private TableViewer createTableViewer(Composite parent) {
		final TableViewer tableViewer = new TableViewer(parent, SWT.MULTI | SWT.V_SCROLL | SWT.FULL_SELECTION
			| SWT.BORDER);
		tableViewer.getTable().setData(CUSTOM_VARIANT, "org_eclipse_emf_ecp_control_table"); //$NON-NLS-1$
		tableViewer.getTable().setHeaderVisible(true);
		tableViewer.getTable().setLinesVisible(true);

		final TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(tableViewer,
			new ECPFocusCellDrawHighlighter(tableViewer));
		final ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(tableViewer) {
			@Override
			protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
				return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
					|| event.eventType == ColumnViewerEditorActivationEvent.MOUSE_CLICK_SELECTION
					|| event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR
					|| event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
			}
		};

		TableViewerEditor.create(tableViewer, focusCellManager, actSupport, ColumnViewerEditor.TABBING_HORIZONTAL
			| ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR | ColumnViewerEditor.TABBING_VERTICAL
			| ColumnViewerEditor.KEYBOARD_ACTIVATION);

		tableViewer.getTable().setData(FIXED_COLUMNS, new Integer(1));
		ColumnViewerToolTipSupport.enableFor(tableViewer);

		return tableViewer;
	}

	private void createFixedValidationStatusColumn(TableViewer tableViewer,
		final List<EStructuralFeature> structuralFeatures) {
		final TableViewerColumn column = TableViewerColumnBuilder
			.create()
			.setMoveable(false)
			.setText(
				LocalizationServiceHelper.getString(getClass(),
					DepricatedControlMessageKeys.TableControl_ValidationStatusColumn))
			.setWidth(80)
			.build(tableViewer);

		column.setLabelProvider(new ValidationStatusCellLabelProvider(structuralFeatures));
	}

	private EObject getInstanceOf(EClass clazz) {
		return clazz.getEPackage().getEFactoryInstance().create(clazz);
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.eclipse.emf.ecp.edit.internal.swt.util.SWTControl#fillControlComposite(org.eclipse.swt.widgets.Composite)
	 */
	@Override
	protected void fillControlComposite(Composite parent) {
		final Composite composite = new Composite(parent, SWT.NONE);
		GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).hint(1, 200).applyTo(composite);
		tableViewer = createTableViewer(composite);

		final ObservableListContentProvider cp = new ObservableListContentProvider();
		final EObject tempInstance = getInstanceOf(clazz);
		final ECPTableViewerComparator comparator = new ECPTableViewerComparator();
		tableViewer.setComparator(comparator);
		int columnNumber = 0;
		final Map<EStructuralFeature, Boolean> readOnlyConfig = createReadOnlyConfig(clazz);
		final List<EStructuralFeature> structuralFeatures = new ArrayList<EStructuralFeature>();
		structuralFeatures.addAll(readOnlyConfig.keySet());
		if (!getControl().isReadonly()) {
			createFixedValidationStatusColumn(tableViewer, structuralFeatures);
		}

		for (final EStructuralFeature feature : structuralFeatures) {
			final IItemPropertyDescriptor itemPropertyDescriptor = adapterFactoryItemDelegator.getPropertyDescriptor(
				tempInstance, feature);
			if (itemPropertyDescriptor == null) {
				// if we can't render because no edit information is available, do nothing
				continue;
			}

			final CellEditor cellEditor = createCellEditor(tempInstance, feature);
			final TableViewerColumn column = TableViewerColumnBuilder
				.create()
				.setText(itemPropertyDescriptor.getDisplayName(null))
				.setToolTipText(itemPropertyDescriptor.getDescription(null))
				.setResizable(true)
				.setMoveable(false)
				.setStyle(noStyle())
				.setData("width", //$NON-NLS-1$
					ECPCellEditor.class.isInstance(cellEditor) ? ECPCellEditor.class.cast(cellEditor)
						.getColumnWidthWeight() : 100)
				.build(tableViewer);

			column.setLabelProvider(new ECPCellLabelProvider(feature, cellEditor,
				feature.isMany() ? new EObjectObservableMap(cp.getKnownElements(), feature)
					: EMFProperties.value(feature).observeDetail(cp.getKnownElements())));
column.getColumn().addSelectionListener(getSelectionAdapter(comparator, column.getColumn(), columnNumber)); if (!isReadOnlyFeature(readOnlyConfig, feature)) { // remove if no editing needed final EditingSupport observableSupport = new ECPTableEditingSupport(tableViewer, cellEditor, feature); column.setEditingSupport(observableSupport); } columnNumber++; } tableViewer.setContentProvider(cp); final IObservableList list = EMFEditObservables.observeList(getEditingDomain(mainSetting), mainSetting.getEObject(), mainSetting.getEStructuralFeature()); tableViewer.setInput(list); // IMPORTANT: // - the minimumWidth and (non)resizable settings of the ColumnWeightData are not supported properly // - the layout stops resizing columns that have been resized manually by the user (this could be considered a // feature though) final TableColumnLayout layout = new TableColumnLayout(); composite.setLayout(layout); for (int i = 0; i < tableViewer.getTable().getColumns().length; i++) { final Integer storedValue = (Integer) tableViewer.getTable().getColumns()[i].getData("width"); //$NON-NLS-1$ layout.setColumnData(tableViewer.getTable().getColumns()[i], new ColumnWeightData(storedValue == null ? 50 : storedValue)); } } private CellEditor createCellEditor(final EObject tempInstance, final EStructuralFeature feature) { return CellEditorFactory.INSTANCE.getCellEditor(feature, tempInstance, tableViewer.getTable(), getViewModelContext()); } private static boolean isReadOnlyFeature(Map<EStructuralFeature, Boolean> readOnlyConfig, EStructuralFeature feature) { if (readOnlyConfig != null) { final Boolean isReadOnly = readOnlyConfig.get(feature); if (isReadOnly != null) { return isReadOnly; } } return false; } private Map<EStructuralFeature, Boolean> createReadOnlyConfig(EClass clazz) { final Map<EStructuralFeature, Boolean> readOnlyConfig = new LinkedHashMap<EStructuralFeature, Boolean>(); if (tableControlConfiguration != null) { for (final TableColumnConfiguration tcc : tableControlConfiguration.getColumns()) { readOnlyConfig.put(tcc.getColumnAttribute(), tcc.isReadOnly()); } } else { for (final EStructuralFeature feature : clazz.getEStructuralFeatures()) { readOnlyConfig.put(feature, Boolean.FALSE); } } return readOnlyConfig; } private int noStyle() { return SWT.NONE; } @Override protected Button getCustomUnsetButton() { return unsetButton; } private SelectionAdapter getSelectionAdapter(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 Button removeButton; private void createRemoveRowButton(EClass clazz, final Composite buttonComposite) { removeButton = new Button(buttonComposite, SWT.None); final Image image = Activator.getImage(ICONS_UNSET_REFERENCE); removeButton.setImage(image); removeButton.setToolTipText(LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_RemoveSelected) + clazz.getInstanceClass().getSimpleName()); removeButton.addSelectionListener(new SelectionAdapter() { /* * (non-Javadoc) * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ @Override public void widgetSelected(SelectionEvent e) { final IStructuredSelection selection = (IStructuredSelection) tableViewer.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); } }); final List<?> containments = (List<?>) mainSetting.get(true); if (containments.size() <= getTableReference().getLowerBound()) { removeButton.setEnabled(false); } } /** * 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 */ protected void deleteRowUserConfirmDialog(final List<EObject> deletionList) { final MessageDialog dialog = new MessageDialog( tableViewer.getTable().getShell(), LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_Delete), null, LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.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) { return; } deleteRows(deletionList); final List<?> containments = (List<?>) mainSetting.get(true); if (containments.size() < getTableReference().getUpperBound()) { addButton.setEnabled(true); } if (containments.size() <= getTableReference().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 */ protected void deleteRows(List<EObject> deletionList) { final EditingDomain editingDomain = getEditingDomain(mainSetting); final EObject modelElement = mainSetting.getEObject(); editingDomain.getCommandStack().execute( RemoveCommand.create(editingDomain, modelElement, getTableReference(), deletionList)); } /** * 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 */ protected void addRow(EClass clazz) { final EObject modelElement = mainSetting.getEObject(); final EObject instance = clazz.getEPackage().getEFactoryInstance().create(clazz); final EditingDomain editingDomain = getEditingDomain(mainSetting); editingDomain.getCommandStack().execute( AddCommand.create(editingDomain, modelElement, getTableReference(), instance)); } private Button addButton; private Setting mainSetting; private boolean isDisposing; private void createAddRowButton(final EClass clazz, final Composite buttonComposite) { addButton = new Button(buttonComposite, SWT.None); final Image image = Activator.getImage(ICON_ADD); addButton.setImage(image); addButton.setToolTipText(LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_AddInstanceOf) + clazz.getInstanceClass().getSimpleName()); addButton.addSelectionListener(new SelectionAdapter() { /* * (non-Javadoc) * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ @Override public void widgetSelected(SelectionEvent e) { addRow(clazz); final List<?> containments = (List<?>) mainSetting.get(true); if (getTableReference().getUpperBound() != -1 && containments.size() >= getTableReference().getUpperBound()) { addButton.setEnabled(false); } if (containments.size() > getTableReference().getLowerBound()) { removeButton.setEnabled(true); } } }); final List<?> containments = (List<?>) mainSetting.get(true); if (getTableReference().getUpperBound() != -1 && containments.size() >= getTableReference().getUpperBound()) { addButton.setEnabled(false); } } /** * {@inheritDoc} */ @Override public void dispose() { isDisposing = true; super.dispose(); composedAdapterFactory.dispose(); mainSetting = null; adapterFactoryItemDelegator = null; composedAdapterFactory = null; isDisposing = false; } /** * {@inheritDoc} * * @see org.eclipse.emf.ecp.edit.spi.ECPAbstractControl#applyValidation(org.eclipse.emf.ecp.view.spi.model.VDiagnostic) */ @Override protected void applyValidation(VDiagnostic diagnostic) { if (validationLabel == null || validationLabel.isDisposed()) { return; } if (diagnostic != null) { final Image image = getValidationIcon(diagnostic.getHighestSeverity()); validationLabel.setImage(image); validationLabel.setToolTipText(diagnostic.getMessage()); for (final Object object : (Collection<?>) mainSetting.get(true)) { tableViewer.update(object, null); } } } // /** // * {@inheritDoc} // * // * @deprecated // */ // @Deprecated // @Override // public void resetValidation() { // if (validationLabel == null || validationLabel.isDisposed()) { // return; // } // validationLabel.setToolTipText(""); //$NON-NLS-1$ // validationLabel.setImage(null); // tableViewer.refresh(); // } // /** // * {@inheritDoc} // * // * @deprecated // */ // @Deprecated // @Override // public void handleValidation(Diagnostic diagnostic) { // if (diagnostic.getData().isEmpty()) { // return; // } // final Image image = getValidationIcon(diagnostic.getSeverity()); // validationLabel.setImage(image); // validationLabel.setToolTipText(getTableTooltipMessage(diagnostic)); // final EObject object = (EObject) diagnostic.getData().get(0); // tableViewer.update(object, null); // } /** * Returns the message of the validation tool tip shown in the table header. * * @param diagnostic the {@link Diagnostic} to extract the message from * @return the message */ protected String getTableTooltipMessage(Diagnostic diagnostic) { return diagnostic.getMessage(); } /** * Returns the message of the validation tool tip shown in the row. * * @param vDiagnostic the {@link VDiagnostic} to get the message from * @return the message */ protected String getRowTooltipMessage(VDiagnostic vDiagnostic) { return vDiagnostic.getMessage(); } /** * Returns the message of the validation tool tip shown in the cell. * * @param vDiagnostic the {@link VDiagnostic} to get the message from * @return the message */ protected String getCellTooltipMessage(VDiagnostic vDiagnostic) { if (vDiagnostic == null) { return null; } if (vDiagnostic.getDiagnostics().size() == 0) { return vDiagnostic.getMessage(); } final Diagnostic diagnostic = (Diagnostic) vDiagnostic.getDiagnostics().get(0); Diagnostic reason = diagnostic; if (diagnostic.getChildren() != null && diagnostic.getChildren().size() != 0) { reason = diagnostic.getChildren().get(0); } return reason.getMessage(); } /** * {@inheritDoc} * * @deprecated */ @Deprecated @Override public void setEditable(boolean isEditable) { if (addButton != null) { addButton.setVisible(isEditable); } if (removeButton != null) { removeButton.setVisible(isEditable); } editable = isEditable; } /** * @author Jonas * */ private final class ValidationStatusCellLabelProvider extends CellLabelProvider { private final List<EStructuralFeature> structuralFeatures; /** * @param structuralFeatures */ private ValidationStatusCellLabelProvider(List<EStructuralFeature> structuralFeatures) { this.structuralFeatures = structuralFeatures; } @Override public void update(ViewerCell cell) { Integer mostSevere = Diagnostic.OK; final VDiagnostic vDiagnostic = getControl().getDiagnostic(); // for (final Object diagObject : vDiagnostic.getDiagnostics()) { // final Diagnostic diagnostic = (Diagnostic) diagObject; // if (diagnostic.getData().size() == 0) { // continue; // } // if (diagnostic.getData().get(0).equals(cell.getElement())) { // final int currentSeverity = diagnostic.getSeverity(); // if (currentSeverity > mostSevere) { // mostSevere = currentSeverity; // } // } // } 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 StringBuffer tooltip = new StringBuffer(); final VDiagnostic vDiagnostic = getControl().getDiagnostic(); // for (final Object diagObject : vDiagnostic.getDiagnostics()) { // final Diagnostic diagnostic = (Diagnostic) diagObject; // if (diagnostic.getData().size() < 2) { // continue; // } // if (diagnostic.getSeverity() == Diagnostic.OK) { // continue; // } // if (diagnostic.getData().get(0).equals(element) // && structuralFeatures.contains(diagnostic.getData().get(1))) { // if (tooltip.length() > 0) { // tooltip.append("\n"); //$NON-NLS-1$ // } // tooltip.append(diagnostic.getMessage()); // } // } final List<Diagnostic> diagnostics = vDiagnostic.getDiagnostics((EObject) element); for (final Diagnostic diagnostic : diagnostics) { if (tooltip.length() > 0) { tooltip.append("\n"); //$NON-NLS-1$ } tooltip.append(diagnostic.getMessage()); } return tooltip.toString(); } } /** * 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) { if (direction == 0) { return 0; } int rc = 0; final EObject object1 = (EObject) e1; final EObject object2 = (EObject) e2; final EStructuralFeature feat1 = object1.eClass().getEAllStructuralFeatures().get(propertyIndex); final EStructuralFeature feat2 = object2.eClass().getEAllStructuralFeatures().get(propertyIndex); final Object value1 = object1.eGet(feat1); final Object value2 = object2.eGet(feat2); 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; } } /** * 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; /** * 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} */ public ECPCellLabelProvider(EStructuralFeature feature, CellEditor cellEditor, IObservableMap attributeMap) { super(attributeMap); this.feature = feature; this.cellEditor = cellEditor; } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipText(java.lang.Object) */ @Override public String getToolTipText(Object element) { final EObject domainObject = (EObject) element; final StringBuffer tooltip = new StringBuffer(); final VDiagnostic vDiagnostic = getControl().getDiagnostic(); final List<Diagnostic> diagnostics = vDiagnostic.getDiagnostic(domainObject, feature); for (final Diagnostic diagnostic : diagnostics) { if (tooltip.length() > 0) { tooltip.append("\n"); //$NON-NLS-1$ } tooltip.append(diagnostic.getMessage()); } return tooltip.toString(); // final VDiagnostic vDiagnostic = getControl().getDiagnostic(); // for (final Object diagObject : vDiagnostic.getDiagnostics()) { // final Diagnostic diagnostic = (Diagnostic) diagObject; // if (diagnostic.getData().size() < 2) { // continue; // } // if (diagnostic.getData().get(0).equals(element) && diagnostic.getData().get(1).equals(feature)) { // // if (diagnostic.getChildren() != null && diagnostic.getChildren().size() != 0) { // boolean childrenUsefull = false; // for (final Diagnostic diagnostic2 : diagnostic.getChildren()) { // if (diagnostic2.getSeverity() != Diagnostic.OK) { // if (tooltip.length() > 0) { // tooltip.append("\n"); //$NON-NLS-1$ // } // tooltip.append(diagnostic2.getMessage()); // childrenUsefull = true; // } // } // if (!childrenUsefull) { // if (tooltip.length() > 0) { // tooltip.append("\n"); //$NON-NLS-1$ // } // tooltip.append(diagnostic.getMessage()); // } // } else { // if (tooltip.length() > 0) { // tooltip.append("\n"); //$NON-NLS-1$ // } // tooltip.append(diagnostic.getMessage()); // } // } // } // if (tooltip.length() != 0) { // return tooltip.toString(); // } // final Object value = ((EObject) element).eGet(feature); // if (value == null) { // return null; // } // return String.valueOf(value); } @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.setBackground(getBackground(element)); } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object) */ @Override public Color getForeground(Object element) { return null; } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object) */ @Override public Color getBackground(Object element) { if (isDisposing) { return null; } final Integer mostSevere = Diagnostic.OK; final VDiagnostic vDiagnostic = getControl().getDiagnostic(); // for (final Object diagObject : vDiagnostic.getDiagnostics()) { // final Diagnostic diagnostic = (Diagnostic) diagObject; // if (diagnostic.getData().size() < 2) { // continue; // } // if (diagnostic.getData().get(0).equals(element) && diagnostic.getData().get(1).equals(feature)) { // final int currentSeverity = diagnostic.getSeverity(); // if (currentSeverity > mostSevere) { // mostSevere = currentSeverity; // } // } // } final List<Diagnostic> diagnostic = vDiagnostic.getDiagnostic((EObject) element, feature); return getValidationBackgroundColor(diagnostic.size() == 0 ? Diagnostic.OK : diagnostic.get(0) .getSeverity()); } } /* * (non-Javadoc) * @see org.eclipse.emf.ecp.edit.internal.swt.util.SWTControl#getUnsetLabelText() */ @Override protected String getUnsetLabelText() { return LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_NotSetClickToSet); } /* * (non-Javadoc) * @see org.eclipse.emf.ecp.edit.internal.swt.util.SWTControl#getUnsetButtonTooltip() */ @Override protected String getUnsetButtonTooltip() { return LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_Unset); } /* * (non-Javadoc) * @see org.eclipse.emf.ecp.edit.internal.swt.util.SWTControl#getControlForTooltip() */ @Override protected Control[] getControlsForTooltip() { // return new Control[] { tableViewer.getControl() }; return new Control[0]; } /** * {@inheritDoc} * * @deprecated */ @Override @Deprecated public boolean showLabel() { return false; } /** * Implementation of the {@link EditingSupport} for the generic ECP Table. * * @author Eugen Neufeld * */ class ECPTableEditingSupport extends EditingSupport { private final CellEditor cellEditor; private final EStructuralFeature cellFeature; /** * @param viewer */ ECPTableEditingSupport(ColumnViewer viewer, CellEditor cellEditor, EStructuralFeature feature) { super(viewer); this.cellEditor = cellEditor; cellFeature = feature; } 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) { 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 = doCreateElementObservable(cell.getElement(), cell); Assert.isNotNull(model, "doCreateElementObservable(...) 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 doCreateElementObservable(Object element, ViewerCell cell) { return EMFEditObservables.observeValue(getEditingDomain(), (EObject) element, cellFeature); } protected IObservableValue doCreateCellEditorObservable(CellEditor cellEditor) { if (ECPCellEditor.class.isInstance(cellEditor)) { return ((ECPCellEditor) cellEditor).getValueProperty().observe(cellEditor); } return SWTObservables.observeText(cellEditor.getControl(), SWT.FocusOut); } @Override protected final void saveCellEditorValue(CellEditor cellEditor, ViewerCell cell) { if (editingState.isUpdateNeeded()) { editingState.binding.updateTargetToModel(); } } class ColumnViewerEditorActivationListenerHelper extends ColumnViewerEditorActivationListener { @Override public void afterEditorActivated(ColumnViewerEditorActivationEvent event) { // do nothing } @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(); } /** * Checks if an update is really needed. * * @return <code>true</code> if update is really needed, <code>false</code> otherwise. */ boolean isUpdateNeeded() { final Object targetValue = target.getValue(); final Object modelValue = model.getValue(); if (targetValue == null) { return modelValue != null; } return !targetValue.equals(modelValue); } } } }