Bug 552385 - EMFDeleteServiceImpl contradicts model's item providers

Add an extension protocol for conditional deletion support.
Use it in the UI for delete action enablement.

Change-Id: I83cf91ec2792ad5bf1fd658e37dc88b1dc2d3ec1
Signed-off-by: Christian W. Damus <give.a.damus@gmail.com>
diff --git a/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/ConditionalDeleteService.java b/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/ConditionalDeleteService.java
new file mode 100644
index 0000000..b65f506
--- /dev/null
+++ b/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/ConditionalDeleteService.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Christian W. Damus 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:
+ * Christian W. Damus - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.ecp.edit.spi;
+
+import java.util.Collections;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext;
+
+/**
+ * An extension of the {@link DeleteService} protocol that supports conditional deletion,
+ * respecting a model's edit providers when they provide unexecutable commands to veto
+ * deletion. Implementations of this interface <strong>should be registered</strong> as
+ * OSGi services providing {@code DeleteService} because the framework looks for that
+ * service interface but will test whether the implementation also provides this extension.
+ * Whether the extension interface is also declared to OSGi is left to the provider's discretion.
+ *
+ * @since 1.23
+ */
+public interface ConditionalDeleteService extends DeleteService {
+
+	/**
+	 * Queries whether an {@code object} can be deleted. By convention a {@code null} value
+	 * cannot be deleted.
+	 *
+	 * @param object an object to be deleted
+	 * @return {@code false} if the {@code object} cannot be deleted or is {@code null}; {@code true}, otherwise
+	 */
+	default boolean canDelete(Object object) {
+		return canDelete(Collections.singleton(object));
+	}
+
+	/**
+	 * Queries whether <em>all</em> of the given {@code objects} can be deleted.
+	 *
+	 * @param objects a number of objects to be deleted
+	 * @return {@code false} if any of the objects cannot be deleted; {@code true} otherwise, including the case of no
+	 *         {@code objects}
+	 */
+	boolean canDelete(Iterable<?> objects);
+
+	/**
+	 * Obtain a conditional delete service for a given {@code context}, if necessary
+	 * {@linkplain #adapt(DeleteService) adapting} its service implementation.
+	 *
+	 * @param context a form context
+	 * @return the delete service, or an adapter if the actual delete service implementation does not provide
+	 *         the {@link ConditionalDeleteService} protocol or if there isn't a delete service at all (in which case nothing can
+	 *         be deleted)
+	 * 
+	 * @see #adapt(DeleteService)
+	 */
+	static ConditionalDeleteService getDeleteService(EMFFormsViewContext context) {
+		return adapt(context == null ? null : context.getService(DeleteService.class));
+	}
+
+	/**
+	 * Obtain a view of a given {@code service} as conditional delete service, if necessary adapting a service
+	 * implementation that does not provide the {@link ConditionalDeleteService} protocol with a default deletion condition.
+	 * In that case, an object is assumed to be deletable if it is not {@code null} and it is an
+	 * {@link EObject} that has some container from which it can be removed (root elements not logically
+	 * being deletable).
+	 *
+	 * @param service a delete service
+	 * @return the delete service, or an adapter if the actual delete service implementation does not provide
+	 *         the {@link ConditionalDeleteService} protocol or if the original {@code service} is {@code null}
+	 */
+	static ConditionalDeleteService adapt(DeleteService service) {
+		return service == null
+			? DeleteServiceAdapter.NULL
+			: service instanceof ConditionalDeleteService
+				? (ConditionalDeleteService) service
+				: new DeleteServiceAdapter(service);
+	}
+
+}
diff --git a/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/DeleteService.java b/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/DeleteService.java
index d14140b..e222309 100644
--- a/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/DeleteService.java
+++ b/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/DeleteService.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011-2015 EclipseSource Muenchen GmbH and others.
+ * Copyright (c) 2011-2019 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
@@ -10,6 +10,7 @@
  *
  * Contributors:
  * Johannes Faltermeier - initial API and implementation
+ * Christian W. Damus - bug 552385
  ******************************************************************************/
 package org.eclipse.emf.ecp.edit.spi;
 
@@ -18,7 +19,15 @@
 import org.eclipse.emf.ecp.view.spi.context.ViewModelService;
 
 /**
+ * <p>
  * The DeleteService is used by renderers in order to delete objects from the containment tree.
+ * </p>
+ * <p>
+ * <strong>Note</strong> that since the 1.23 release, it is recommended to implement the
+ * {@link ConditionalDeleteService} interface to support conditional deletion, honouring the model's
+ * edit providers when they veto deletion by providing unexecutable commands.
+ * </p>
+ *
  *
  * @author jfaltermeier
  * @since 1.6
diff --git a/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/DeleteServiceAdapter.java b/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/DeleteServiceAdapter.java
new file mode 100644
index 0000000..45f31f9
--- /dev/null
+++ b/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/DeleteServiceAdapter.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Christian W. Damus 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:
+ * Christian W. Damus - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.ecp.edit.spi;
+
+import java.util.Collection;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
+
+/**
+ * An adapter for delete services that do not implement the {@link ConditionalDeleteService} protocol.
+ */
+final class DeleteServiceAdapter implements ConditionalDeleteService {
+
+	/** An adapter for the {@code null} service (when there is no delete service at all). */
+	static final ConditionalDeleteService NULL = new DeleteServiceAdapter(null);
+
+	private final DeleteService delegate;
+
+	/**
+	 * Initializes me with the real delete service.
+	 *
+	 * @param delegate the real delete service
+	 */
+	DeleteServiceAdapter(DeleteService delegate) {
+		super();
+
+		this.delegate = delegate;
+	}
+
+	@Override
+	public void deleteElements(Collection<Object> toDelete) {
+		if (delegate != null) {
+			delegate.deleteElements(toDelete);
+		} else {
+			throw new IllegalStateException("No deletion service available."); //$NON-NLS-1$
+		}
+	}
+
+	@Override
+	public void deleteElement(Object toDelete) {
+		if (delegate != null) {
+			delegate.deleteElement(toDelete);
+		} else {
+			throw new IllegalStateException("No deletion service available."); //$NON-NLS-1$
+		}
+	}
+
+	@Override
+	public void instantiate(ViewModelContext context) {
+		if (delegate != null) {
+			delegate.instantiate(context);
+		}
+	}
+
+	@Override
+	public void dispose() {
+		if (delegate != null) {
+			delegate.dispose();
+		}
+	}
+
+	@Override
+	public int getPriority() {
+		return delegate == null ? Integer.MIN_VALUE : delegate.getPriority();
+	}
+
+	@Override
+	public boolean canDelete(Iterable<?> objects) {
+		// Cannot delete if we have no service to effect the deletion
+		boolean result = delegate != null;
+
+		if (result) {
+			for (final Object next : objects) {
+				// Cannot delete a null or a root object
+				if (next == null || next instanceof EObject && ((EObject) next).eContainer() == null) {
+					result = false;
+					break;
+				}
+			}
+		}
+
+		return result;
+	}
+
+}
diff --git a/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/EMFDeleteServiceImpl.java b/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/EMFDeleteServiceImpl.java
index 98a844f..dad5963 100644
--- a/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/EMFDeleteServiceImpl.java
+++ b/bundles/org.eclipse.emf.ecp.edit/src/org/eclipse/emf/ecp/edit/spi/EMFDeleteServiceImpl.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011-2015 EclipseSource Muenchen GmbH and others.
+ * Copyright (c) 2011-2019 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
@@ -10,11 +10,14 @@
  *
  * Contributors:
  * Johannes Faltermeier - initial API and implementation
+ * Christian W. Damus - bug 552385
  ******************************************************************************/
 package org.eclipse.emf.ecp.edit.spi;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
 
 import org.eclipse.emf.common.command.Command;
 import org.eclipse.emf.ecore.EObject;
@@ -33,47 +36,26 @@
  * @since 1.6
  *
  */
-public class EMFDeleteServiceImpl implements DeleteService {
+public class EMFDeleteServiceImpl implements ConditionalDeleteService {
 
 	private EditingDomain editingDomain;
 
-	/**
-	 * {@inheritDoc}
-	 *
-	 * @see org.eclipse.emf.ecp.view.spi.context.ViewModelService#instantiate(org.eclipse.emf.ecp.view.spi.context.ViewModelContext)
-	 */
 	@Override
 	public void instantiate(ViewModelContext context) {
 		editingDomain = AdapterFactoryEditingDomain
 			.getEditingDomainFor(context.getDomainModel());
 	}
 
-	/**
-	 * {@inheritDoc}
-	 *
-	 * @see org.eclipse.emf.ecp.view.spi.context.ViewModelService#dispose()
-	 */
 	@Override
 	public void dispose() {
 		// no op
 	}
 
-	/**
-	 * {@inheritDoc}
-	 *
-	 * @see org.eclipse.emf.ecp.view.spi.context.ViewModelService#getPriority()
-	 */
 	@Override
 	public int getPriority() {
 		return 1;
 	}
 
-	/**
-	 *
-	 * {@inheritDoc}
-	 *
-	 * @see org.eclipse.emf.ecp.edit.spi.DeleteService#deleteElements(java.util.Collection)
-	 */
 	@Override
 	public void deleteElements(final Collection<Object> toDelete) {
 		if (toDelete == null || toDelete.isEmpty()) {
@@ -127,12 +109,6 @@
 		}
 	}
 
-	/**
-	 *
-	 * {@inheritDoc}
-	 *
-	 * @see org.eclipse.emf.ecp.edit.spi.DeleteService#deleteElement(java.lang.Object)
-	 */
 	@Override
 	public void deleteElement(Object toDelete) {
 		if (toDelete == null) {
@@ -142,4 +118,34 @@
 		deleteElements(Collections.singleton(toDelete));
 	}
 
+	@Override
+	public boolean canDelete(Iterable<?> objects) {
+		boolean result;
+
+		if (editingDomain != null) {
+			Collection<?> collection;
+			if (objects instanceof Collection<?>) {
+				collection = (Collection<?>) objects;
+			} else {
+				collection = StreamSupport.stream(objects.spliterator(), false).collect(Collectors.toList());
+			}
+
+			final Command deleteCommand = DeleteCommand.create(editingDomain, collection);
+			result = deleteCommand.canExecute();
+		} else {
+			// Just see whether any object is a root
+			result = true;
+
+			for (final Object next : objects) {
+				if (next instanceof EObject && ((EObject) next).eContainer() == null) {
+					// Cannot delete a root object
+					result = false;
+					break;
+				}
+			}
+		}
+
+		return result;
+	}
+
 }
diff --git a/bundles/org.eclipse.emf.ecp.ide.editor.view/src/org/eclipse/emf/ecp/ide/editor/view/ViewEditorActionBarContributor.java b/bundles/org.eclipse.emf.ecp.ide.editor.view/src/org/eclipse/emf/ecp/ide/editor/view/ViewEditorActionBarContributor.java
index 5918aa6..780a383 100644
--- a/bundles/org.eclipse.emf.ecp.ide.editor.view/src/org/eclipse/emf/ecp/ide/editor/view/ViewEditorActionBarContributor.java
+++ b/bundles/org.eclipse.emf.ecp.ide.editor.view/src/org/eclipse/emf/ecp/ide/editor/view/ViewEditorActionBarContributor.java
@@ -14,10 +14,9 @@
 package org.eclipse.emf.ecp.ide.editor.view;
 
 import java.util.Collection;
-import java.util.stream.Stream;
 
-import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecp.edit.spi.DeleteService;
+import org.eclipse.emf.ecp.edit.spi.ConditionalDeleteService;
 import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
 import org.eclipse.emf.edit.ui.action.DeleteAction;
 import org.eclipse.emf.edit.ui.action.EditingDomainActionBarContributor;
@@ -92,16 +91,9 @@
 
 		@Override
 		public boolean updateSelection(IStructuredSelection selection) {
-			final DeleteService deleteService = getService(DeleteService.class);
-			if (deleteService == null) {
-				return super.updateSelection(selection);
-			}
+			final ConditionalDeleteService deleteService = ConditionalDeleteService.getDeleteService(getViewModelContext());
 
-			return !selection.isEmpty() && Stream.of(selection.toArray()).noneMatch(this::isRoot);
-		}
-
-		private boolean isRoot(Object object) {
-			return object instanceof EObject && ((EObject) object).eContainer() == null;
+			return !selection.isEmpty() && deleteService.canDelete(selection.toList());
 		}
 
 	}
diff --git a/bundles/org.eclipse.emf.ecp.view.control.multireference/src/org/eclipse/emf/ecp/view/internal/control/multireference/MultiReferenceSWTRenderer.java b/bundles/org.eclipse.emf.ecp.view.control.multireference/src/org/eclipse/emf/ecp/view/internal/control/multireference/MultiReferenceSWTRenderer.java
index ffcd9d3..ed19456 100644
--- a/bundles/org.eclipse.emf.ecp.view.control.multireference/src/org/eclipse/emf/ecp/view/internal/control/multireference/MultiReferenceSWTRenderer.java
+++ b/bundles/org.eclipse.emf.ecp.view.control.multireference/src/org/eclipse/emf/ecp/view/internal/control/multireference/MultiReferenceSWTRenderer.java
@@ -12,7 +12,7 @@
  * Eugen Neufeld - initial API and implementation
  * Lucas Koehler - use data binding services
  * Martin Fleck - bug 487101
- * Christian W. Damus - bugs 527736, 548592
+ * Christian W. Damus - bugs 527736, 548592, 552385
  ******************************************************************************/
 package org.eclipse.emf.ecp.view.internal.control.multireference;
 
@@ -36,6 +36,7 @@
 import org.eclipse.emf.ecore.EStructuralFeature;
 import org.eclipse.emf.ecp.edit.internal.swt.controls.TableViewerColumnBuilder;
 import org.eclipse.emf.ecp.edit.spi.DeleteService;
+import org.eclipse.emf.ecp.edit.spi.ConditionalDeleteService;
 import org.eclipse.emf.ecp.edit.spi.EMFDeleteServiceImpl;
 import org.eclipse.emf.ecp.edit.spi.ReferenceService;
 import org.eclipse.emf.ecp.view.model.common.edit.provider.CustomReflectiveItemProviderAdapterFactory;
@@ -779,7 +780,9 @@
 
 	private void enableDeleteButton(boolean baseEnable, int listSize, int selectionIndex) {
 		if (btnDelete != null && showDeleteButton()) {
-			btnDelete.setEnabled(baseEnable && listSize > 0 && selectionIndex != -1);
+			btnDelete.setEnabled(baseEnable && listSize > 0 && selectionIndex != -1
+				&& ConditionalDeleteService.getDeleteService(getViewModelContext())
+					.canDelete(tableViewer.getStructuredSelection().toList()));
 		}
 	}
 
diff --git a/bundles/org.eclipse.emf.ecp.view.table.ui.swt/src/org/eclipse/emf/ecp/view/spi/table/swt/TableControlSWTRenderer.java b/bundles/org.eclipse.emf.ecp.view.table.ui.swt/src/org/eclipse/emf/ecp/view/spi/table/swt/TableControlSWTRenderer.java
index c2979c7..1e5358f 100644
--- a/bundles/org.eclipse.emf.ecp.view.table.ui.swt/src/org/eclipse/emf/ecp/view/spi/table/swt/TableControlSWTRenderer.java
+++ b/bundles/org.eclipse.emf.ecp.view.table.ui.swt/src/org/eclipse/emf/ecp/view/spi/table/swt/TableControlSWTRenderer.java
@@ -11,7 +11,7 @@
  * Contributors:
  * Eugen Neufeld - initial API and implementation
  * Johannes Faltermeier - refactorings
- * Christian W. Damus - bugs 544116, 544537, 545686, 530314, 547271, 547787, 548592
+ * Christian W. Damus - bugs 544116, 544537, 545686, 530314, 547271, 547787, 548592, 552385
  ******************************************************************************/
 package org.eclipse.emf.ecp.view.spi.table.swt;
 
@@ -63,6 +63,7 @@
 import org.eclipse.emf.ecore.EStructuralFeature.Setting;
 import org.eclipse.emf.ecore.InternalEObject;
 import org.eclipse.emf.ecp.edit.spi.DeleteService;
+import org.eclipse.emf.ecp.edit.spi.ConditionalDeleteService;
 import org.eclipse.emf.ecp.edit.spi.EMFDeleteServiceImpl;
 import org.eclipse.emf.ecp.edit.spi.ReferenceService;
 import org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor;
@@ -633,6 +634,12 @@
 					deleteRowUserConfirmDialog(deletionList, eObject, eStructuralFeature, getAddButton(),
 						getRemoveButton());
 				}
+
+				@Override
+				public boolean canExecute() {
+					return super.canExecute() && ConditionalDeleteService.getDeleteService(getViewModelContext())
+						.canDelete(getActionContext().getViewer().getStructuredSelection().toList());
+				}
 			};
 
 			actionConfigBuilder
diff --git a/bundles/org.eclipse.emf.ecp.view.treemasterdetail.ui.swt/src/org/eclipse/emf/ecp/view/spi/treemasterdetail/ui/swt/TreeMasterDetailSWTRenderer.java b/bundles/org.eclipse.emf.ecp.view.treemasterdetail.ui.swt/src/org/eclipse/emf/ecp/view/spi/treemasterdetail/ui/swt/TreeMasterDetailSWTRenderer.java
index 7afb40c..2dcfaa2 100644
--- a/bundles/org.eclipse.emf.ecp.view.treemasterdetail.ui.swt/src/org/eclipse/emf/ecp/view/spi/treemasterdetail/ui/swt/TreeMasterDetailSWTRenderer.java
+++ b/bundles/org.eclipse.emf.ecp.view.treemasterdetail.ui.swt/src/org/eclipse/emf/ecp/view/spi/treemasterdetail/ui/swt/TreeMasterDetailSWTRenderer.java
@@ -13,7 +13,7 @@
  * Eugen Neufeld - Refactoring
  * Alexandra Buzila - Refactoring
  * Johannes Faltermeier - integration with validation service
- * Christian W. Damus - bugs 543376, 545460, 527686, 548592
+ * Christian W. Damus - bugs 543376, 545460, 527686, 548592, 552385
  ******************************************************************************/
 package org.eclipse.emf.ecp.view.spi.treemasterdetail.ui.swt;
 
@@ -50,6 +50,7 @@
 import org.eclipse.emf.ecp.common.spi.ChildrenDescriptorCollector;
 import org.eclipse.emf.ecp.edit.internal.swt.util.OverlayImageDescriptor;
 import org.eclipse.emf.ecp.edit.spi.DeleteService;
+import org.eclipse.emf.ecp.edit.spi.ConditionalDeleteService;
 import org.eclipse.emf.ecp.edit.spi.EMFDeleteServiceImpl;
 import org.eclipse.emf.ecp.edit.spi.ReferenceService;
 import org.eclipse.emf.ecp.edit.spi.swt.util.SWTValidationHelper;
@@ -866,6 +867,7 @@
 			.getBundle()
 			.getResource(deleteImagePath)));
 		deleteAction.setText("Delete"); //$NON-NLS-1$
+		deleteAction.setEnabled(ConditionalDeleteService.getDeleteService(getViewModelContext()).canDelete(selection.toList()));
 		manager.add(deleteAction);
 	}
 
diff --git a/tests/org.eclipse.emf.ecp.edit.swt.test/src/org/eclipse/emf/ecp/edit/internal/swt/util/DeleteServiceAdapter_PTest.java b/tests/org.eclipse.emf.ecp.edit.swt.test/src/org/eclipse/emf/ecp/edit/internal/swt/util/DeleteServiceAdapter_PTest.java
new file mode 100644
index 0000000..b249e5f
--- /dev/null
+++ b/tests/org.eclipse.emf.ecp.edit.swt.test/src/org/eclipse/emf/ecp/edit/internal/swt/util/DeleteServiceAdapter_PTest.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Christian W. Damus 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:
+ * Christian W. Damus - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.ecp.edit.internal.swt.util;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.verify;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.eclipse.emf.ecp.edit.spi.DeleteService;
+import org.eclipse.emf.ecp.edit.spi.ConditionalDeleteService;
+import org.eclipse.emf.emfstore.bowling.BowlingFactory;
+import org.eclipse.emf.emfstore.bowling.League;
+import org.eclipse.emf.emfstore.bowling.Player;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+/**
+ * Tests for the {@code DeleteServiceAdapter} class via the {@link ConditionalDeleteService} APIs that provide instances of it.
+ */
+@SuppressWarnings("nls")
+@RunWith(MockitoJUnitRunner.class)
+public class DeleteServiceAdapter_PTest {
+
+	private League league;
+	private Player player;
+
+	@Mock
+	private DeleteService delegate;
+
+	@Mock
+	private ConditionalDeleteService cdelegate;
+
+	/**
+	 * Test the null adapter (the adapter for an absent delete service).
+	 */
+	@Test
+	public void test_canDelete_null() {
+		final ConditionalDeleteService service = ConditionalDeleteService.adapt(null);
+
+		final Collection<?> objects = Arrays.asList(player, league);
+		assertThat("can delete without delegate", service.canDelete(player), is(false));
+		assertThat("can delete without delegate", service.canDelete(objects), is(false));
+	}
+
+	@Test
+	public void test_canDelete_single() {
+		final ConditionalDeleteService service = ConditionalDeleteService.adapt(delegate);
+
+		assertThat(service.canDelete(player), is(true));
+		assertThat(service.canDelete(league), is(false));
+	}
+
+	@Test
+	public void test_canDelete_multiple() {
+		final ConditionalDeleteService service = ConditionalDeleteService.adapt(delegate);
+
+		assertThat(service.canDelete(Arrays.asList(player)), is(true));
+		assertThat(service.canDelete(Arrays.asList(player, league)), is(false));
+	}
+
+	@Test
+	public void test_canDelete_single2() {
+		final ConditionalDeleteService service = ConditionalDeleteService.adapt(cdelegate);
+
+		service.canDelete(player);
+
+		verify(cdelegate).canDelete(player);
+	}
+
+	@Test
+	public void test_canDelete_multiple2() {
+		final ConditionalDeleteService service = ConditionalDeleteService.adapt(cdelegate);
+
+		final Collection<?> objects = Arrays.asList(player, league);
+		service.canDelete(objects);
+
+		verify(cdelegate).canDelete(objects);
+	}
+
+	@Test
+	public void test_deleteElement() {
+		final ConditionalDeleteService service = ConditionalDeleteService.adapt(delegate);
+
+		service.deleteElement(player);
+
+		verify(delegate).deleteElement(player);
+	}
+
+	@Test
+	public void test_deleteElementse() {
+		final ConditionalDeleteService service = ConditionalDeleteService.adapt(delegate);
+
+		final Collection<Object> objects = Arrays.asList(player, league);
+		service.deleteElements(objects);
+
+		verify(delegate).deleteElements(objects);
+	}
+
+	//
+	// Test framework
+	//
+
+	@Before
+	public void createModel() {
+		league = BowlingFactory.eINSTANCE.createLeague();
+		player = BowlingFactory.eINSTANCE.createPlayer();
+
+		league.getPlayers().add(player);
+	}
+
+}
diff --git a/tests/org.eclipse.emf.ecp.edit.swt.test/src/org/eclipse/emf/ecp/edit/internal/swt/util/EMFDeleteSerivceImpl_PTest.java b/tests/org.eclipse.emf.ecp.edit.swt.test/src/org/eclipse/emf/ecp/edit/internal/swt/util/EMFDeleteSerivceImpl_PTest.java
index b3289f0..0344274 100644
--- a/tests/org.eclipse.emf.ecp.edit.swt.test/src/org/eclipse/emf/ecp/edit/internal/swt/util/EMFDeleteSerivceImpl_PTest.java
+++ b/tests/org.eclipse.emf.ecp.edit.swt.test/src/org/eclipse/emf/ecp/edit/internal/swt/util/EMFDeleteSerivceImpl_PTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011-2015 EclipseSource Muenchen GmbH and others.
+ * Copyright (c) 2011-2019 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
@@ -10,9 +10,12 @@
  *
  * Contributors:
  * jfaltermeier - initial API and implementation
+ * Christian W. Damus - bug 552385
  ******************************************************************************/
 package org.eclipse.emf.ecp.edit.internal.swt.util;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
@@ -21,19 +24,25 @@
 import static org.mockito.Mockito.when;
 
 import java.util.Arrays;
+import java.util.Collection;
 
 import org.eclipse.emf.common.command.BasicCommandStack;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.UnexecutableCommand;
 import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.resource.ResourceSet;
 import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
 import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
-import org.eclipse.emf.ecp.edit.spi.DeleteService;
+import org.eclipse.emf.ecp.edit.spi.ConditionalDeleteService;
 import org.eclipse.emf.ecp.edit.spi.EMFDeleteServiceImpl;
 import org.eclipse.emf.ecp.test.university.Address;
 import org.eclipse.emf.ecp.test.university.Professor;
 import org.eclipse.emf.ecp.test.university.UniversityFactory;
 import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
+import org.eclipse.emf.edit.command.OverrideableCommand;
+import org.eclipse.emf.edit.command.RemoveCommand;
 import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
 import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
 import org.eclipse.emf.emfstore.bowling.BowlingFactory;
@@ -48,10 +57,12 @@
  * @author jfaltermeier
  *
  */
+@SuppressWarnings("nls")
 public class EMFDeleteSerivceImpl_PTest {
 
-	private DeleteService deleteService;
+	private ConditionalDeleteService deleteService;
 	private AdapterFactoryEditingDomain domain;
+	private ViewModelContext context;
 	private Resource resource;
 	private League league;
 	private Game game;
@@ -60,13 +71,25 @@
 	private Player player3;
 	private Tournament tournament;
 
+	private EObject denyDeletion;
+
 	@Before
 	public void setUp() {
 		final ResourceSet resourceSet = new ResourceSetImpl();
 		resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new XMIResourceFactoryImpl()); //$NON-NLS-1$
 		domain = new AdapterFactoryEditingDomain(
 			new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE),
-			new BasicCommandStack(), resourceSet);
+			new BasicCommandStack(), resourceSet) {
+
+			@Override
+			public Command createOverrideCommand(OverrideableCommand command) {
+				if (denyDeletion != null && command instanceof RemoveCommand
+					&& ((RemoveCommand) command).getCollection().contains(denyDeletion)) {
+					return UnexecutableCommand.INSTANCE;
+				}
+				return super.createOverrideCommand(command);
+			}
+		};
 		resourceSet.eAdapters().add(new AdapterFactoryEditingDomain.EditingDomainProvider(domain));
 		resource = resourceSet.createResource(URI.createURI("VIRTUAL_URI")); //$NON-NLS-1$
 
@@ -91,7 +114,7 @@
 		game.setPlayer(player1);
 
 		deleteService = new EMFDeleteServiceImpl();
-		final ViewModelContext context = mock(ViewModelContext.class);
+		context = mock(ViewModelContext.class);
 		when(context.getDomainModel()).thenReturn(league);
 		deleteService.instantiate(context);
 	}
@@ -143,4 +166,40 @@
 		assertSame(address1, professor.getAddresses().get(0));
 	}
 
+	@Test
+	public void testCanDeleteElement() {
+		assertThat("can delete returns false", deleteService.canDelete(player1), is(true));
+
+		denyDeletion = player1;
+		assertThat("can delete returns true", deleteService.canDelete(player1), is(false));
+	}
+
+	@Test
+	public void testCanDeleteElements() {
+		final Collection<?> objects = Arrays.asList(player1, player2);
+
+		assertThat("can delete returns false", deleteService.canDelete(objects), is(true));
+
+		denyDeletion = player2; // Not the first one
+		assertThat("can delete returns true", deleteService.canDelete(objects), is(false));
+	}
+
+	@Test
+	public void testCanDeleteNoEditingDomain() {
+		// Disconnect everything from the editing domain
+		resource.getContents().clear();
+		resource.getResourceSet().eAdapters().clear();
+		resource.getResourceSet().getResources().clear();
+		resource.unload();
+		resource.eAdapters().clear();
+
+		// Re-initialize to forget the editing domain
+		deleteService.dispose();
+		deleteService.instantiate(context);
+
+		assertThat("cannot delete a contained object", deleteService.canDelete(player1), is(true));
+
+		assertThat("can delete a root object", deleteService.canDelete(league), is(false));
+	}
+
 }
diff --git a/tests/org.eclipse.emf.ecp.view.control.multireference.tests/AllPluginTests for view.control.multireference.launch b/tests/org.eclipse.emf.ecp.view.control.multireference.tests/AllPluginTests for view.control.multireference.launch
index 07c47aa..5b8ea3a 100644
--- a/tests/org.eclipse.emf.ecp.view.control.multireference.tests/AllPluginTests for view.control.multireference.launch
+++ b/tests/org.eclipse.emf.ecp.view.control.multireference.tests/AllPluginTests for view.control.multireference.launch
@@ -24,6 +24,7 @@
 <booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
 <stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
 <stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
 <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.emf.ecp.view.control.multireference.tests.AllPluginTests"/>
 <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
@@ -32,8 +33,8 @@
 <stringAttribute key="pde.version" value="3.3"/>
 <stringAttribute key="product" value="org.eclipse.platform.ide"/>
 <booleanAttribute key="run_in_ui_thread" value="true"/>
-<stringAttribute key="selected_target_plugins" value="com.ibm.icu@default:default,javax.annotation@default:default,javax.inject@default:default,org.apache.batik.constants@default:default,org.apache.batik.css*1.10.0.v20180703-1553@default:default,org.apache.batik.i18n@default:default,org.apache.batik.util*1.10.0.v20180703-1553@default:default,org.apache.commons.codec@default:default,org.apache.commons.jxpath@default:default,org.apache.commons.logging*1.1.1.v201101211721@default:default,org.apache.commons.logging*1.2.0.v20180409-1502@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.scr@1:true,org.apache.xmlgraphics@default:default,org.eclipse.compare.core@default:default,org.eclipse.core.commands@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.databinding*1.7.100.v20181030-1443@default:default,org.eclipse.core.databinding.observable*1.6.300.v20180827-2028@default:default,org.eclipse.core.databinding.property*1.6.300.v20180827-2028@default:default,org.eclipse.core.expressions@default:default,org.eclipse.core.filesystem.linux.x86_64@default:false,org.eclipse.core.filesystem@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.resources@default:default,org.eclipse.core.runtime@default:true,org.eclipse.e4.core.commands@default:default,org.eclipse.e4.core.contexts@default:default,org.eclipse.e4.core.di.annotations@default:default,org.eclipse.e4.core.di.extensions.supplier@default:default,org.eclipse.e4.core.di.extensions@default:default,org.eclipse.e4.core.di@default:default,org.eclipse.e4.core.services@default:default,org.eclipse.e4.emf.xpath@default:default,org.eclipse.e4.ui.bindings@default:default,org.eclipse.e4.ui.css.core@default:default,org.eclipse.e4.ui.css.swt.theme@default:default,org.eclipse.e4.ui.css.swt@default:default,org.eclipse.e4.ui.di@default:default,org.eclipse.e4.ui.model.workbench@default:default,org.eclipse.e4.ui.services@default:default,org.eclipse.e4.ui.swt.gtk@default:false,org.eclipse.e4.ui.widgets@default:default,org.eclipse.e4.ui.workbench.addons.swt@default:default,org.eclipse.e4.ui.workbench.renderers.swt@default:default,org.eclipse.e4.ui.workbench.swt@default:default,org.eclipse.e4.ui.workbench3@default:default,org.eclipse.e4.ui.workbench@default:default,org.eclipse.emf.common.ui@default:default,org.eclipse.emf.common@default:default,org.eclipse.emf.databinding.edit@default:default,org.eclipse.emf.databinding@default:default,org.eclipse.emf.ecore.change@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.emf.edit.ui@default:default,org.eclipse.emf.edit@default:default,org.eclipse.emf.emfstore.client@default:default,org.eclipse.emf.emfstore.common.model@default:default,org.eclipse.emf.emfstore.common@default:default,org.eclipse.emf.emfstore.examplemodel.edit@default:default,org.eclipse.emf.emfstore.examplemodel@default:default,org.eclipse.emf.emfstore.migration@default:default,org.eclipse.emf.emfstore.server.model@default:default,org.eclipse.emf.emfstore.server@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.help@default:default,org.eclipse.jface.databinding@default:default,org.eclipse.jface@default:default,org.eclipse.net4j.util@default:default,org.eclipse.osgi.compatibility.state@default:false,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.eclipse.swt.gtk.linux.x86_64@default:false,org.eclipse.swt@default:default,org.eclipse.team.core@default:default,org.eclipse.ui.forms@default:default,org.eclipse.ui.trace@default:default,org.eclipse.ui.views@default:default,org.eclipse.ui.workbench@default:default,org.eclipse.ui@default:default,org.hamcrest.core*1.3.0.v201303031735@default:default,org.hamcrest.core*1.3.0.v20180420-1519@default:default,org.hamcrest.library@default:default,org.junit@default:default,org.mockito.mockito-core-hamcrest-modified@default:default,org.objenesis@default:default,org.w3c.css.sac@default:default,org.w3c.dom.events@default:default,org.w3c.dom.smil*1.0.1.v200903091627@default:default,org.w3c.dom.svg@default:default"/>
-<stringAttribute key="selected_workspace_plugins" value="org.eclipse.emf.ecp.common.ui@default:default,org.eclipse.emf.ecp.common@default:default,org.eclipse.emf.ecp.core@default:default,org.eclipse.emf.ecp.edit.swt@default:default,org.eclipse.emf.ecp.edit@default:default,org.eclipse.emf.ecp.editor.e3@default:default,org.eclipse.emf.ecp.emfstore.core@default:default,org.eclipse.emf.ecp.explorereditorbridge@default:default,org.eclipse.emf.ecp.test.common@default:default,org.eclipse.emf.ecp.ui.view.swt@default:default,org.eclipse.emf.ecp.ui.view.test@default:default,org.eclipse.emf.ecp.ui.view@default:default,org.eclipse.emf.ecp.ui@default:default,org.eclipse.emf.ecp.view.context@default:default,org.eclipse.emf.ecp.view.control.multireference.tests@default:false,org.eclipse.emf.ecp.view.control.multireference@default:default,org.eclipse.emf.ecp.view.core.swt@default:default,org.eclipse.emf.ecp.view.group.model@default:default,org.eclipse.emf.ecp.view.migrator@default:default,org.eclipse.emf.ecp.view.model.common@default:default,org.eclipse.emf.ecp.view.model.provider.generator@default:default,org.eclipse.emf.ecp.view.model.provider.xmi@default:default,org.eclipse.emf.ecp.view.model@default:default,org.eclipse.emf.ecp.view.swt.layout@default:default,org.eclipse.emf.ecp.view.table.model.test@default:false,org.eclipse.emf.ecp.view.table.model@default:default,org.eclipse.emf.ecp.view.template.model@default:default,org.eclipse.emf.ecp.view.test.common.swt@default:default,org.eclipse.emf.ecp.view.test.common@default:default,org.eclipse.emf.ecp.view.util.swt@default:default,org.eclipse.emf.ecp.view.validation@default:default,org.eclipse.emf.ecp.view.vertical.model@default:default,org.eclipse.emfforms.common.prevalidation@default:default,org.eclipse.emfforms.common.validation@default:default,org.eclipse.emfforms.common@default:default,org.eclipse.emfforms.core.bazaar@default:default,org.eclipse.emfforms.core.services.databinding.testmodel@default:default,org.eclipse.emfforms.core.services.domainexpander.default@default:default,org.eclipse.emfforms.core.services.domainexpander.table@default:default,org.eclipse.emfforms.core.services.editsupport@default:default,org.eclipse.emfforms.core.services.emf@default:default,org.eclipse.emfforms.core.services.emfspecificservice@default:default,org.eclipse.emfforms.core.services.legacy@default:default,org.eclipse.emfforms.core.services.locale.default@default:default,org.eclipse.emfforms.core.services.mappingprovider.default@default:default,org.eclipse.emfforms.core.services.mappingprovider.table@default:default,org.eclipse.emfforms.core.services.structuralchange.default@default:default,org.eclipse.emfforms.core.services.structuralchange@default:default,org.eclipse.emfforms.core.services@default:default,org.eclipse.emfforms.localization@default:default,org.eclipse.emfforms.swt.core.di@default:default,org.eclipse.emfforms.swt.core@default:default,org.eclipse.emfforms.view.annotation.model@default:default,org.eclipse.emfforms.view.multisegment.model@default:default"/>
+<stringAttribute key="selected_target_plugins" value="com.ibm.icu@default:default,javax.annotation@default:default,javax.inject@default:default,org.apache.batik.constants*1.11.0.v20190515-0436@default:default,org.apache.batik.css*1.11.0.v20190515-0436@default:default,org.apache.batik.i18n*1.11.0.v20190515-0436@default:default,org.apache.batik.util*1.11.0.v20190515-0436@default:default,org.apache.commons.codec@default:default,org.apache.commons.jxpath@default:default,org.apache.commons.logging*1.1.1.v201101211721@default:default,org.apache.commons.logging*1.2.0.v20180409-1502@default:default,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.scr@1:true,org.apache.xmlgraphics@default:default,org.eclipse.compare.core@default:default,org.eclipse.core.commands@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.databinding.observable@default:default,org.eclipse.core.databinding.property@default:default,org.eclipse.core.databinding@default:default,org.eclipse.core.expressions@default:default,org.eclipse.core.filesystem.macosx@default:default,org.eclipse.core.filesystem@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.resources@default:default,org.eclipse.core.runtime@default:true,org.eclipse.e4.core.commands@default:default,org.eclipse.e4.core.contexts@default:default,org.eclipse.e4.core.di.annotations@default:default,org.eclipse.e4.core.di.extensions.supplier@default:default,org.eclipse.e4.core.di.extensions@default:default,org.eclipse.e4.core.di@default:default,org.eclipse.e4.core.services@default:default,org.eclipse.e4.emf.xpath@default:default,org.eclipse.e4.ui.bindings@default:default,org.eclipse.e4.ui.css.core@default:default,org.eclipse.e4.ui.css.swt.theme@default:default,org.eclipse.e4.ui.css.swt@default:default,org.eclipse.e4.ui.di@default:default,org.eclipse.e4.ui.dialogs@default:default,org.eclipse.e4.ui.model.workbench@default:default,org.eclipse.e4.ui.services@default:default,org.eclipse.e4.ui.widgets@default:default,org.eclipse.e4.ui.workbench.addons.swt@default:default,org.eclipse.e4.ui.workbench.renderers.swt@default:default,org.eclipse.e4.ui.workbench.swt@default:default,org.eclipse.e4.ui.workbench3@default:default,org.eclipse.e4.ui.workbench@default:default,org.eclipse.emf.common.ui@default:default,org.eclipse.emf.common@default:default,org.eclipse.emf.databinding.edit@default:default,org.eclipse.emf.databinding@default:default,org.eclipse.emf.ecore.change@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.emf.edit.ui@default:default,org.eclipse.emf.edit@default:default,org.eclipse.emf.emfstore.client@default:default,org.eclipse.emf.emfstore.common.model@default:default,org.eclipse.emf.emfstore.common@default:default,org.eclipse.emf.emfstore.examplemodel.edit@default:default,org.eclipse.emf.emfstore.examplemodel@default:default,org.eclipse.emf.emfstore.migration@default:default,org.eclipse.emf.emfstore.server.model@default:default,org.eclipse.emf.emfstore.server@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.help@default:default,org.eclipse.jface.databinding@default:default,org.eclipse.jface.text@default:default,org.eclipse.jface@default:default,org.eclipse.net4j.util@default:default,org.eclipse.osgi.compatibility.state@default:false,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.eclipse.swt.cocoa.macosx.x86_64@default:default,org.eclipse.swt@default:default,org.eclipse.team.core@default:default,org.eclipse.text@default:default,org.eclipse.ui.forms@default:default,org.eclipse.ui.trace@default:default,org.eclipse.ui.views@default:default,org.eclipse.ui.workbench@default:default,org.eclipse.ui@default:default,org.hamcrest.core@default:default,org.hamcrest.library@default:default,org.junit@default:default,org.mockito.mockito-core-hamcrest-modified@default:default,org.objenesis@default:default,org.w3c.css.sac@default:default,org.w3c.dom.events@default:default,org.w3c.dom.smil*1.0.1.v200903091627@default:default,org.w3c.dom.svg@default:default"/>
+<stringAttribute key="selected_workspace_plugins" value="org.eclipse.emf.ecp.common.ui@default:default,org.eclipse.emf.ecp.common@default:default,org.eclipse.emf.ecp.core@default:default,org.eclipse.emf.ecp.edit.swt@default:default,org.eclipse.emf.ecp.edit@default:default,org.eclipse.emf.ecp.editor.e3@default:default,org.eclipse.emf.ecp.emfstore.core@default:default,org.eclipse.emf.ecp.explorereditorbridge@default:default,org.eclipse.emf.ecp.test.common@default:default,org.eclipse.emf.ecp.ui.view.swt@default:default,org.eclipse.emf.ecp.ui.view.test@default:default,org.eclipse.emf.ecp.ui.view@default:default,org.eclipse.emf.ecp.ui@default:default,org.eclipse.emf.ecp.view.context@default:default,org.eclipse.emf.ecp.view.control.multireference.tests@default:false,org.eclipse.emf.ecp.view.control.multireference@default:default,org.eclipse.emf.ecp.view.core.swt@default:default,org.eclipse.emf.ecp.view.group.model@default:default,org.eclipse.emf.ecp.view.label.model@default:default,org.eclipse.emf.ecp.view.migrator@default:default,org.eclipse.emf.ecp.view.model.common.di@default:default,org.eclipse.emf.ecp.view.model.common@default:default,org.eclipse.emf.ecp.view.model.provider.generator@default:default,org.eclipse.emf.ecp.view.model.provider.xmi@default:default,org.eclipse.emf.ecp.view.model@default:default,org.eclipse.emf.ecp.view.swt.layout@default:default,org.eclipse.emf.ecp.view.table.model.test@default:false,org.eclipse.emf.ecp.view.table.model@default:default,org.eclipse.emf.ecp.view.template.model@default:default,org.eclipse.emf.ecp.view.template.service@default:default,org.eclipse.emf.ecp.view.test.common.swt@default:default,org.eclipse.emf.ecp.view.test.common@default:default,org.eclipse.emf.ecp.view.util.swt@default:default,org.eclipse.emf.ecp.view.validation@default:default,org.eclipse.emf.ecp.view.vertical.model@default:default,org.eclipse.emfforms.common.prevalidation@default:default,org.eclipse.emfforms.common.validation@default:default,org.eclipse.emfforms.common@default:default,org.eclipse.emfforms.core.bazaar@default:default,org.eclipse.emfforms.core.services.databinding.testmodel@default:default,org.eclipse.emfforms.core.services.domainexpander.default@default:default,org.eclipse.emfforms.core.services.domainexpander.table@default:default,org.eclipse.emfforms.core.services.editsupport@default:default,org.eclipse.emfforms.core.services.emf@default:default,org.eclipse.emfforms.core.services.emfspecificservice@default:default,org.eclipse.emfforms.core.services.legacy@default:default,org.eclipse.emfforms.core.services.locale.default@default:default,org.eclipse.emfforms.core.services.mappingprovider.default@default:default,org.eclipse.emfforms.core.services.mappingprovider.table@default:default,org.eclipse.emfforms.core.services.segments@default:default,org.eclipse.emfforms.core.services.structuralchange.default@default:default,org.eclipse.emfforms.core.services.structuralchange@default:default,org.eclipse.emfforms.core.services@default:default,org.eclipse.emfforms.localization@default:default,org.eclipse.emfforms.swt.core.di@default:default,org.eclipse.emfforms.swt.core@default:default,org.eclipse.emfforms.view.annotation.model@default:default,org.eclipse.emfforms.view.multisegment.model@default:default"/>
 <booleanAttribute key="show_selected_only" value="false"/>
 <booleanAttribute key="tracing" value="false"/>
 <booleanAttribute key="useCustomFeatures" value="false"/>
diff --git a/tests/org.eclipse.emf.ecp.view.control.multireference.tests/src/org/eclipse/emf/ecp/view/internal/control/multireference/MultiReferenceRenderer_PTest.java b/tests/org.eclipse.emf.ecp.view.control.multireference.tests/src/org/eclipse/emf/ecp/view/internal/control/multireference/MultiReferenceRenderer_PTest.java
index 3861602..95a846d 100644
--- a/tests/org.eclipse.emf.ecp.view.control.multireference.tests/src/org/eclipse/emf/ecp/view/internal/control/multireference/MultiReferenceRenderer_PTest.java
+++ b/tests/org.eclipse.emf.ecp.view.control.multireference.tests/src/org/eclipse/emf/ecp/view/internal/control/multireference/MultiReferenceRenderer_PTest.java
@@ -10,7 +10,7 @@
  *
  * Contributors:
  * Lucas Koehler - initial API and implementation
- * Christian W. Damus - bug 527736
+ * Christian W. Damus - bugs 527736, 552385
  ******************************************************************************/
 package org.eclipse.emf.ecp.view.internal.control.multireference;
 
@@ -56,6 +56,8 @@
 import org.eclipse.emf.ecore.EcoreFactory;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecp.edit.spi.DeleteService;
+import org.eclipse.emf.ecp.edit.spi.EMFDeleteServiceImpl;
 import org.eclipse.emf.ecp.view.model.common.AbstractGridCell.Alignment;
 import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
 import org.eclipse.emf.ecp.view.spi.model.VControl;
@@ -177,6 +179,8 @@
 
 		when(viewContext.getDomainModel()).thenReturn(eObject);
 		when(viewContext.getViewModel()).thenReturn(vControl);
+		// Required for delete button enablement
+		when(viewContext.getService(DeleteService.class)).thenReturn(new EMFDeleteServiceImpl());
 
 		when(vControl.getDomainModelReference()).thenReturn(domainModelReference);