Skip to content

Content of file EnumCellEditor.java

/*******************************************************************************
 * Copyright (c) 2017 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:
 * Edgar Mueller - initial API and implementation
 *******************************************************************************/
package org.eclipse.emf.ecp.view.spi.table.swt;

import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.property.INativePropertyListener;
import org.eclipse.core.databinding.property.ISimplePropertyListener;
import org.eclipse.core.databinding.property.value.IValueProperty;
import org.eclipse.core.databinding.property.value.SimpleValueProperty;
import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.emf.databinding.EMFUpdateValueStrategy;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecp.edit.spi.swt.table.ECPEnumCellEditor;
import org.eclipse.emf.ecp.view.internal.core.swt.ComboUtil;
import org.eclipse.emf.ecp.view.internal.core.swt.MatchItemComboViewer;
import org.eclipse.emf.ecp.view.internal.table.swt.FigureUtilities;
import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
import org.eclipse.emfforms.common.Optional;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;

/**
 * Generic {@link org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor ECPCellEditor} which is
 * applicable for all {@link EAttribute EAttributes} with a Single {@link EEnum} data type.
 *
 * @since 1.13
 * @deprecated Use {@link ItemProviderEnumCellEditor} instead
 */
@Deprecated
public class EnumCellEditor extends ECPEnumCellEditor {

	private static final String EMPTY = ""; //$NON-NLS-1$
	private EEnum eEnum;
	private MatchItemComboViewer viewer;
	private int minWidth;
	private String text;
	private EnumCellEditorLabelProvider labelProvider;

	/**
	 * Default constructor.
	 *
	 * @param parent the parent
	 */
	public EnumCellEditor(Composite parent) {
		super(parent);
	}

	/**
	 * Constructor allowing to specify a SWT style.
	 *
	 * @param parent the parent
	 * @param style the SWT style
	 */
	public EnumCellEditor(Composite parent, int style) {
		super(parent, style);
	}

	/**
	 *
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor#getValueProperty()
	 */
	@Override
	public IValueProperty getValueProperty() {
		return new ComboValueProperty();
	}

	/**
	 *
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor#instantiate(org.eclipse.emf.ecore.EStructuralFeature,
	 *      org.eclipse.emf.ecp.view.spi.context.ViewModelContext)
	 */
	@Override
	public void instantiate(EStructuralFeature feature, ViewModelContext viewModelContext) {

		final EAttribute attribute = EAttribute.class.cast(feature);
		eEnum = EEnum.class.cast(attribute.getEAttributeType());
		final int literalsSize = getELiterals().size();
		viewer.getCCombo().setVisibleItemCount(literalsSize <= 25 ? literalsSize : 25);
		final Point emptyViewerSize = viewer.getCCombo().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
		minWidth = 50;
		for (final EEnumLiteral literal : getELiterals()) {
			final String string = literal.getInstance().getLiteral();
			final int newWidth = FigureUtilities.getTextWidth(string, viewer.getCCombo().getFont());
			if (newWidth > minWidth) {
				minWidth = newWidth;
			}
		}
		minWidth += emptyViewerSize.x;
	}

	/**
	 *
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor#getFormatedString(java.lang.Object)
	 */
	@Override
	public String getFormatedString(Object value) {
		if (value != null) {
			final Enumerator enumerator = (Enumerator) value;
			return enumerator.getLiteral();
		}
		return EMPTY;
	}

	/**
	 *
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor#getColumnWidthWeight()
	 */
	@Override
	public int getColumnWidthWeight() {
		return 100;
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor#getMinWidth()
	 */
	@Override
	public int getMinWidth() {
		return minWidth;
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor#getImage(java.lang.Object)
	 */
	@Override
	public Image getImage(Object value) {
		return null;
	}

	/**
	 *
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor#getTargetToModelStrategy(org.eclipse.core.databinding.DataBindingContext)
	 */
	@Override
	public UpdateValueStrategy getTargetToModelStrategy(DataBindingContext databindingContext) {
		return new TargetToModelStrategy();
	}

	/**
	 *
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor#getModelToTargetStrategy(org.eclipse.core.databinding.DataBindingContext)
	 */
	@Override
	public UpdateValueStrategy getModelToTargetStrategy(DataBindingContext databindingContext) {
		return new ModelToTargetStrategy();
	}

	/**
	 *
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.jface.viewers.CellEditor#getLayoutData()
	 */
	@Override
	public LayoutData getLayoutData() {
		final LayoutData data = new LayoutData();
		data.minimumWidth = 0;
		return data;
	}

	/**
	 *
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor#setEditable(boolean)
	 */
	@Override
	public void setEditable(boolean editable) {
		viewer.getCCombo().setEnabled(editable);
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.jface.viewers.CellEditor#createControl(org.eclipse.swt.widgets.Composite)
	 */
	@Override
	protected Control createControl(Composite parent) {
		viewer = new MatchItemComboViewer(new CCombo(parent, SWT.NONE)) {
			@Override
			public void onEnter() {
				final int selectedIndex = ComboUtil.getClosestMatchIndex(getCCombo().getItems(),
					getBuffer().asString());
				if (!getBuffer().isEmpty() && selectedIndex > -1) {
					final String closestMatch = getCCombo().getItems()[selectedIndex];
					final Optional<SelectedEnumeratorMapping> selectedMappping = SelectedEnumeratorMapping
						.findLiteral((SelectedEnumeratorMapping[]) getInput(), closestMatch);
					if (selectedMappping.isPresent()) {
						setSelection(new StructuredSelection(selectedMappping.get()));
					}

				} else {
					setClosestMatch(getCCombo().getText());
				}

				focusLost();
			}

			/**
			 * {@inheritDoc}
			 *
			 * @see org.eclipse.emf.ecp.view.internal.core.swt.MatchItemComboViewer#onEscape()
			 */
			@Override
			protected void onEscape() {
				EnumCellEditor.this.fireCancelEditor();
			}
		};

		final CCombo combo = viewer.getCCombo();

		GridDataFactory.fillDefaults().grab(true, false).applyTo(combo);
		labelProvider = new EnumCellEditorLabelProvider();
		viewer.setContentProvider(ArrayContentProvider.getInstance());
		viewer.setLabelProvider(labelProvider);
		return combo;
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.jface.viewers.CellEditor#doGetValue()
	 */
	@Override
	protected Object doGetValue() {
		return viewer.getInput();
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.jface.viewers.CellEditor#doSetFocus()
	 */
	@Override
	protected void doSetFocus() {
		final CCombo combo = viewer.getCCombo();
		if (combo == null || combo.isDisposed()) {
			return;
		}
		combo.setFocus();
		// Remove text selection and move the cursor to the end.
		final String text = combo.getText();
		if (text != null) {
			combo.setSelection(new Point(text.length(), text.length()));
		}
	}

	/**
	 *
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.jface.viewers.CellEditor#activate(org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent)
	 */
	@Override
	public void activate(ColumnViewerEditorActivationEvent actEvent) {
		super.activate(actEvent);
		if (actEvent.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED) {
			final CCombo control = (CCombo) getControl();
			if (control != null && Character.isLetterOrDigit(actEvent.character)) {
				viewer.getBuffer().reset();
				// key pressed is not fired during activation
				viewer.getBuffer().addLast(actEvent.character);
			}
		}
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.jface.viewers.CellEditor#deactivate()
	 */
	@Override
	public void deactivate() {
		final CCombo control = (CCombo) getControl();

		if (control != null && !control.isDisposed()) {
			text = control.getText();
			text = text == null ? EMPTY : text;
		}

		final SelectedEnumeratorMapping[] selectedMapping = (SelectedEnumeratorMapping[]) viewer.getInput();
		if (selectedMapping != null) {
			final Optional<SelectedEnumeratorMapping> sel = SelectedEnumeratorMapping.findLiteral(selectedMapping,
				text);
			if (sel.isPresent()) {
				sel.get().setSelected(true);
				viewer.setSelection(new StructuredSelection(sel.get()));
			}
		}

		text = EMPTY;
		viewer.getBuffer().reset();

		// As the same cell editor is used for all the rows.
		// We need to reset the value to avoid the values are cached.
		if (control != null && !control.isDisposed()) {
			control.setText(""); //$NON-NLS-1$
		}
		super.deactivate();
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see org.eclipse.jface.viewers.CellEditor#doSetValue(java.lang.Object)
	 */
	@Override
	protected void doSetValue(Object value) {
		viewer.setInput(value);
	}

	private String getComboText(SelectedEnumeratorMapping[] input) {
		final Optional<Enumerator> selected = SelectedEnumeratorMapping.findSelected(input);
		if (selected.isPresent()) {
			return selected.get().getLiteral();
		}
		return EMPTY;
	}

	/**
	 * Returns the {@link EEnum} is cell editor responsible for.
	 *
	 * @return the enum
	 */
	@Override
	public EEnum getEEnum() {
		return eEnum;
	}

	/**
	 * Label provider for the drop down.
	 *
	 *
	 */
	private class EnumCellEditorLabelProvider extends LabelProvider {

		/**
		 * {@inheritDoc}
		 *
		 * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
		 */
		@Override
		public String getText(Object element) {
			final SelectedEnumeratorMapping mapping = (SelectedEnumeratorMapping) element;
			return mapping.getEnumerator().getLiteral();
		}
	}

	/**
	 * Target to model update strategy.
	 *
	 *
	 */
	private class TargetToModelStrategy extends EMFUpdateValueStrategy {
		/*
		 * (non-Javadoc)
		 * @see org.eclipse.core.databinding.UpdateValueStrategy#convert(java.lang.Object)
		 */
		@Override
		public Object convert(Object value) {
			final SelectedEnumeratorMapping[] mapping = (SelectedEnumeratorMapping[]) value;
			final Optional<Enumerator> selected = SelectedEnumeratorMapping.findSelected(mapping);
			return selected.orNull();
		}
	}

	/**
	 * Model to target update strategy.
	 *
	 *
	 */
	private class ModelToTargetStrategy extends EMFUpdateValueStrategy {

		@Override
		public Object convert(Object value) {
			final Enumerator enumerator = (Enumerator) value;
			final SelectedEnumeratorMapping[] mapping = SelectedEnumeratorMapping.createFromList(getELiterals());
			SelectedEnumeratorMapping.select(mapping, enumerator);
			return mapping;
		}
	}

	/**
	 * Value property working on the combo.
	 *
	 */
	private class ComboValueProperty extends SimpleValueProperty {

		@Override
		public Object getValueType() {
			return CCombo.class;
		}

		@Override
		protected Object doGetValue(Object source) {
			return EnumCellEditor.this.getValue();
		}

		@Override
		protected void doSetValue(Object source, Object value) {

			EnumCellEditor.this.doSetValue(value);
		}

		@Override
		public IObservableValue observe(Object source) {
			return new ComboObservableValue();
		}

		@Override
		public INativePropertyListener adaptListener(ISimplePropertyListener listener) {
			return null;
		}
	}

	/**
	 * Observable value for the combo.
	 *
	 */
	private class ComboObservableValue extends AbstractObservableValue {

		private final EnumSelectionAdapter selectionAdapter;

		/**
		 * Default Constructor.
		 */
		ComboObservableValue() {
			selectionAdapter = new EnumSelectionAdapter();
			viewer.addSelectionChangedListener(selectionAdapter);
		}

		/**
		 * {@inheritDoc}
		 *
		 * @see org.eclipse.core.databinding.observable.value.IObservableValue#getValueType()
		 */
		@Override
		public Object getValueType() {
			return null;
		}

		/**
		 * {@inheritDoc}
		 *
		 * @see org.eclipse.core.databinding.observable.value.AbstractObservableValue#doGetValue()
		 */
		@Override
		protected Object doGetValue() {
			return viewer.getInput();
		}

		/**
		 * {@inheritDoc}
		 *
		 * @see org.eclipse.core.databinding.observable.value.AbstractObservableValue#doSetValue(java.lang.Object)
		 */
		@Override
		protected void doSetValue(Object value) {
			viewer.setInput(value);
			viewer.getCCombo().setText(getComboText((SelectedEnumeratorMapping[]) value));
		}

		/**
		 * {@inheritDoc}
		 *
		 * @see org.eclipse.core.databinding.observable.AbstractObservable#dispose()
		 */
		@Override
		public synchronized void dispose() {
			viewer.removeSelectionChangedListener(selectionAdapter);
			super.dispose();
		}

		/**
		 * Selection adapter for the combo.
		 *
		 *
		 */
		private class EnumSelectionAdapter implements ISelectionChangedListener {

			@Override
			public void selectionChanged(SelectionChangedEvent event) {
				final SelectedEnumeratorMapping mapping = (SelectedEnumeratorMapping) ((IStructuredSelection) event
					.getSelection())
						.getFirstElement();
				if (mapping == null) {
					return;
				}
				final SelectedEnumeratorMapping[] allMapping = (SelectedEnumeratorMapping[]) viewer.getInput();
				SelectedEnumeratorMapping.deselectAll(allMapping);
				mapping.setSelected(!mapping.isSelected());
				viewer.getCCombo().setText(getComboText((SelectedEnumeratorMapping[]) viewer.getInput()));
				viewer.update(mapping, null);
				fireValueChange(Diffs.createValueDiff(!mapping.isSelected(), mapping.isSelected()));
} } } }