blob: e362d78e71b4b14503d8a03cc54f437b8103314d [file] [log] [blame]
/*******************************************************************************
* <copyright>
*
* Copyright (c) 2005, 2011 SAP AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API, implementation and documentation
* mwenz - Bug 351053 - Remove the need for WorkspaceCommandStackImpl
*
* </copyright>
*
*******************************************************************************/
package org.eclipse.graphiti.ui.tests;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.easymock.EasyMock;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl;
import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory;
import org.eclipse.gef.commands.Command;
import org.eclipse.graphiti.dt.IDiagramTypeProvider;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.context.IAddContext;
import org.eclipse.graphiti.features.context.IContext;
import org.eclipse.graphiti.features.context.ICustomContext;
import org.eclipse.graphiti.features.context.IDeleteContext;
import org.eclipse.graphiti.features.context.IDirectEditingContext;
import org.eclipse.graphiti.features.custom.AbstractCustomFeature;
import org.eclipse.graphiti.features.impl.AbstractAddShapeFeature;
import org.eclipse.graphiti.features.impl.AbstractDirectEditingFeature;
import org.eclipse.graphiti.internal.command.CommandContainer;
import org.eclipse.graphiti.internal.command.DirectEditingFeatureCommandWithContext;
import org.eclipse.graphiti.internal.command.GenericFeatureCommandWithContext;
import org.eclipse.graphiti.internal.command.ICommand;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.tb.IContextEntry;
import org.eclipse.graphiti.tb.IToolBehaviorProvider;
import org.eclipse.graphiti.tests.reuse.GFAbstractTestCase;
import org.eclipse.graphiti.ui.editor.DiagramEditorFactory;
import org.eclipse.graphiti.ui.features.DefaultDeleteFeature;
import org.eclipse.graphiti.ui.internal.command.AddModelObjectCommand;
import org.eclipse.graphiti.ui.internal.command.ContextEntryCommand;
import org.eclipse.graphiti.ui.internal.command.GefCommandWrapper;
import org.eclipse.graphiti.ui.internal.config.IConfigurationProvider;
import org.eclipse.graphiti.ui.internal.editor.GFCommandStack;
import org.eclipse.jface.viewers.StructuredSelection;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@SuppressWarnings("restriction")
public class CommandStackTest extends GFAbstractTestCase {
private TransactionalEditingDomain editingDomain;
private GFCommandStack commandStack;
private IConfigurationProvider configurationProvider;
@BeforeClass
public static void prepareClass() {
}
@Before
public void beforeTest() {
editingDomain = DiagramEditorFactory.createResourceSetAndEditingDomain();
configurationProvider = initConfigurationProviderForHasDoneChangesTests(editingDomain);
commandStack = new GFCommandStack(configurationProvider, editingDomain);
}
@After
public void afterTest() {
editingDomain.dispose();
}
/**
* Tests that direct editing features that do not change anything don't make
* the command stack dirty. This functionality is e.g. needed when switching
* to direct editing directly after creating a new object and the user
* simply takes over the default name; the null change must not end up in
* the command stack because that would cause an undo that does nothing and
* the user needs to press undo twice in order to undo the create (without
* any feedback for the first undo).
*/
@Test
public void testHasDoneChangesForDirectEditing() {
TestDirectEditingFeature feature = new TestDirectEditingFeature(configurationProvider.getFeatureProvider());
IDirectEditingContext context = EasyMock.createNiceMock(IDirectEditingContext.class);
EasyMock.replay(context);
DirectEditingFeatureCommandWithContext featureCommand = new DirectEditingFeatureCommandWithContext(feature, context, "Initial",
null);
executeAndCheck(featureCommand, commandStack, editingDomain);
}
@Test
public void testHasDoneChangesForCustomFeature() {
TestCustomFeature feature = new TestCustomFeature(configurationProvider.getFeatureProvider());
ICustomContext context = EasyMock.createNiceMock(ICustomContext.class);
EasyMock.replay(context);
GenericFeatureCommandWithContext featureCommand = new GenericFeatureCommandWithContext(feature, context);
CommandContainer commandContainer = new CommandContainer(configurationProvider.getFeatureProvider());
commandContainer.add(featureCommand);
executeAndCheck(commandContainer, commandStack, editingDomain);
}
@Test
public void testHasDoneChangesForAddObject() {
IAddContext context = EasyMock.createNiceMock(IAddContext.class);
EasyMock.replay(context);
// Feature is set via EasyMock in init method
AddModelObjectCommand featureCommand = new AddModelObjectCommand(configurationProvider, null,
new StructuredSelection(new Object()), new Rectangle());
executeAndCheck(featureCommand, commandStack);
}
@Test
public void testHasDoneChangesForContextEntry() {
IContext context = EasyMock.createNiceMock(IContext.class);
EasyMock.replay(context);
IContextEntry contextEntry = EasyMock.createNiceMock(IContextEntry.class);
EasyMock.expect(contextEntry.getFeature()).andReturn(new TestDeleteFeature(configurationProvider.getFeatureProvider())).anyTimes();
EasyMock.expect(contextEntry.getContext()).andReturn(context).anyTimes();
EasyMock.replay(contextEntry);
ContextEntryCommand featureCommand = new ContextEntryCommand(contextEntry);
executeAndCheck(featureCommand, commandStack);
editingDomain.dispose();
}
@Test
public void testCanUsePlainTransactionalCommandStack() {
// Test for https://bugs.eclipse.org/bugs/show_bug.cgi?id=351053
// Create an editing domain with a plain transactional command stack (Graphiti services create a
// GFWorkspaceCommandStackImpl which is also a Workspace command stack)
ResourceSet resourceSet = new ResourceSetImpl();
TransactionalEditingDomainImpl editingDomain = new TransactionalEditingDomainImpl(new ComposedAdapterFactory(
ComposedAdapterFactory.Descriptor.Registry.INSTANCE), resourceSet);
WorkspaceEditingDomainFactory.INSTANCE.mapResourceSet(editingDomain);
// Create command stack using this editing domain
GFCommandStack commandStack = new GFCommandStack(configurationProvider, editingDomain);
// Create test feature and context
TestStandardTransactionalEditingDomainFeature feature = new TestStandardTransactionalEditingDomainFeature(
configurationProvider.getFeatureProvider());
ICustomContext context = EasyMock.createNiceMock(ICustomContext.class);
EasyMock.replay(context);
// Prepare execution and do it
GenericFeatureCommandWithContext featureCommand = new GenericFeatureCommandWithContext(feature, context);
CommandContainer commandContainer = new CommandContainer(configurationProvider.getFeatureProvider());
commandContainer.add(featureCommand);
GefCommandWrapper commandWrapper = new GefCommandWrapper(featureCommand, editingDomain);
commandStack.execute(commandWrapper);
// Check
assertTrue("Feature was not executed", feature.wasExecuted);
// Clean-up local stuff
editingDomain.dispose();
}
private IConfigurationProvider initConfigurationProviderForHasDoneChangesTests(TransactionalEditingDomain editingDomain) {
IToolBehaviorProvider toolBehaviorProvider = EasyMock.createNiceMock(IToolBehaviorProvider.class);
EasyMock.replay(toolBehaviorProvider);
IDiagramTypeProvider diagramTypeProvider = EasyMock.createNiceMock(IDiagramTypeProvider.class);
IFeatureProvider featureProvider = EasyMock.createNiceMock(IFeatureProvider.class);
EasyMock.expect(featureProvider.getDiagramTypeProvider()).andReturn(diagramTypeProvider).anyTimes();
EasyMock.expect(featureProvider.getAddFeature((IAddContext) EasyMock.notNull()))
.andReturn(new TestAddObjectFeature(featureProvider)).anyTimes();
EasyMock.replay(featureProvider);
EasyMock.expect(diagramTypeProvider.getCurrentToolBehaviorProvider()).andReturn(toolBehaviorProvider).anyTimes();
EasyMock.expect(diagramTypeProvider.getFeatureProvider()).andReturn(featureProvider).anyTimes();
EasyMock.replay(diagramTypeProvider);
IConfigurationProvider configurationProvider = EasyMock.createNiceMock(IConfigurationProvider.class);
EasyMock.expect(configurationProvider.getDiagramTypeProvider()).andReturn(diagramTypeProvider).anyTimes();
EasyMock.replay(configurationProvider);
return configurationProvider;
}
private void executeAndCheck(ICommand featureCommand, GFCommandStack commandStack, TransactionalEditingDomain editingDomain) {
GefCommandWrapper commandWrapper = new GefCommandWrapper(featureCommand, editingDomain);
commandStack.execute(commandWrapper);
assertNull("Direct editing command must not appear in command stack", commandStack.getUndoCommand());
}
private void executeAndCheck(Command command, GFCommandStack commandStack) {
commandStack.execute(command);
assertNull("Direct editing command must not appear in command stack", commandStack.getUndoCommand());
}
private class TestDirectEditingFeature extends AbstractDirectEditingFeature {
public TestDirectEditingFeature(IFeatureProvider featureProvider) {
super(featureProvider);
}
@Override
public int getEditingType() {
return TYPE_TEXT;
}
@Override
public String getInitialValue(IDirectEditingContext context) {
return "Initial";
}
@Override
public void setValue(String value, IDirectEditingContext context) {
// Do nothing
}
}
private class TestCustomFeature extends AbstractCustomFeature {
public TestCustomFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canExecute(ICustomContext context) {
return true;
}
@Override
public void execute(ICustomContext context) {
// Do nothing
}
@Override
public boolean hasDoneChanges() {
return false;
}
}
private class TestAddObjectFeature extends AbstractAddShapeFeature {
public TestAddObjectFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canAdd(IAddContext context) {
return true;
}
@Override
public PictogramElement add(IAddContext context) {
// Do nothing
return null;
}
@Override
public boolean hasDoneChanges() {
return false;
}
}
private class TestDeleteFeature extends DefaultDeleteFeature {
public TestDeleteFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canDelete(IDeleteContext context) {
return true;
}
@Override
public void delete(IDeleteContext context) {
// Do nothing
}
@Override
public boolean hasDoneChanges() {
return false;
}
}
private class TestStandardTransactionalEditingDomainFeature extends AbstractCustomFeature {
public boolean wasExecuted = false;
public TestStandardTransactionalEditingDomainFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canExecute(ICustomContext context) {
return true;
}
@Override
public void execute(ICustomContext context) {
wasExecuted = true;
}
}
}