diff options
75 files changed, 3135 insertions, 286 deletions
diff --git a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOAwareCommandStack.java b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOAwareCommandStack.java index e57e64cadac..a94616e64a5 100644 --- a/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOAwareCommandStack.java +++ b/extraplugins/cdo/org.eclipse.papyrus.cdo.core/src/org/eclipse/papyrus/cdo/core/resource/CDOAwareCommandStack.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2013 CEA LIST. + * Copyright (c) 2013, 2014 CEA LIST and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,6 +8,7 @@ * * Contributors: * CEA LIST - Initial API and implementation + * Christian W. Damus (CEA) - bug 402525 *****************************************************************************/ package org.eclipse.papyrus.cdo.core.resource; @@ -19,7 +20,7 @@ import org.eclipse.emf.cdo.eresource.EresourcePackage; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.transaction.ResourceSetChangeEvent; -import org.eclipse.papyrus.commands.NotifyingWorkspaceCommandStack; +import org.eclipse.papyrus.commands.NestingNotifyingWorkspaceCommandStack; import com.google.common.collect.Sets; @@ -28,12 +29,21 @@ import com.google.common.collect.Sets; * A CDO-specific command-stack that attaches undo contexts describing object-level * details of the scope of a change. */ -public class CDOAwareCommandStack extends NotifyingWorkspaceCommandStack { +public class CDOAwareCommandStack extends NestingNotifyingWorkspaceCommandStack { public CDOAwareCommandStack(IOperationHistory history) { super(history); } + protected CDOAwareCommandStack(boolean nested, IOperationHistory history) { + super(nested, history); + } + + @Override + protected NestingNotifyingWorkspaceCommandStack createNestedCommandStack(IOperationHistory history) { + return new CDOAwareCommandStack(true, history); + } + @Override protected void hookUndoContexts(IUndoableOperation operation, ResourceSetChangeEvent event) { super.hookUndoContexts(operation, event); diff --git a/features/papyrus-tests-features/org.eclipse.papyrus.tests.infra.feature/feature.xml b/features/papyrus-tests-features/org.eclipse.papyrus.tests.infra.feature/feature.xml index fa00df248a4..c33130f0ba8 100644 --- a/features/papyrus-tests-features/org.eclipse.papyrus.tests.infra.feature/feature.xml +++ b/features/papyrus-tests-features/org.eclipse.papyrus.tests.infra.feature/feature.xml @@ -1,20 +1,39 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?><feature id="org.eclipse.papyrus.tests.infra.feature" label="%featureName" provider-name="%providerName" version="1.0.0.qualifier">
-
- <copyright url="http://www.eclipse.org/legal/epl-v10.html">
- Copyright (c) 2008-2012 CEA LIST, Atos Origin, Conselleria de
-Infraestructuras y Transporte, Generalitat de la Comunitat Valenciana
-and others
-All rights reserved. This program and the accompanying materials
-are made available under the terms of the Eclipse Public License
-v1.0
-which accompanies this distribution, and is available at
-http://www.eclipse.org/legal/epl-v10.html
- </copyright>
-
- <license url="%licenseURL">
- %license
- </license>
-
- <plugin download-size="0" fragment="true" id="org.eclipse.papyrus.extendedtypes.tests" install-size="0" unpack="false" version="0.0.0"/>
-
-</feature>
\ No newline at end of file +<?xml version="1.0" encoding="UTF-8"?> +<feature + id="org.eclipse.papyrus.tests.infra.feature" + label="%featureName" + version="1.0.0.qualifier" + provider-name="%providerName"> + + <copyright url="http://www.eclipse.org/legal/epl-v10.html"> + Copyright (c) 2008-2014 CEA LIST, Atos Origin, Conselleria de +Infraestructuras y Transporte, Generalitat de la Comunitat Valenciana +and others +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License +v1.0 +which accompanies this distribution, and is available at +http://www.eclipse.org/legal/epl-v10.html + </copyright> + + <license url="%licenseURL"> + %license + </license> + + <plugin + id="org.eclipse.papyrus.extendedtypes.tests" + download-size="0" + install-size="0" + version="0.0.0" + fragment="true" + unpack="false"/> + + <plugin + id="org.eclipse.papyrus.infra.gmfdiag.commands.tests" + download-size="0" + install-size="0" + version="0.0.0" + fragment="true" + unpack="false"/> + +</feature> diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/NestingTransactionalCommandStack.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/NestingTransactionalCommandStack.java new file mode 100644 index 00000000000..87976894389 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/NestingTransactionalCommandStack.java @@ -0,0 +1,263 @@ +/***************************************************************************** + * Copyright (c) 2013, 2014 CEA LIST and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation + * Christian W. Damus (CEA) - adapted for self-nesting behaviour + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.core.resource; + +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.command.CompoundCommand; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.RollbackException; +import org.eclipse.emf.transaction.impl.InternalTransaction; +import org.eclipse.emf.transaction.impl.TransactionalCommandStackImpl; +import org.eclipse.emf.transaction.util.ConditionalRedoCommand; + + +public class NestingTransactionalCommandStack extends TransactionalCommandStackImpl { + + private NestingTransactionalCommandStack childCommandStack; + + private final boolean nested; + + private boolean executing; + + public NestingTransactionalCommandStack() { + this(false); + } + + protected NestingTransactionalCommandStack(boolean nested) { + this.nested = nested; + } + + protected NestingTransactionalCommandStack getTopMostCommandStack() { + if(childCommandStack == null) { + return this; + } + return childCommandStack.getTopMostCommandStack(); + } + + protected void startNestedTransaction(Command command) { + if(childCommandStack != null) { + //Forwards to the current stack + childCommandStack.startNestedTransaction(command); + } else { + //Start a new nested transaction in a new nested Stack + childCommandStack = new NestingTransactionalCommandStack(true); + childCommandStack.setEditingDomain(getDomain()); + + childCommandStack.execute(command); + } + } + + public void commit() { + if(childCommandStack != null) { + disposeLastCommandStack(); + } + } + + private boolean disposeLastCommandStack() { + if(childCommandStack == null) { + //I'm the last command stack + dispose(); + return true; + } + + //Propagates + if(childCommandStack.disposeLastCommandStack()) { + childCommandStack = null; + } + + return false; + } + + public void rollback() { + if(childCommandStack != null) { + while(canUndo()) { + undo(); + } + disposeLastCommandStack(); + } + } + + @Override + public void execute(Command command) { + if(childCommandStack == null) { + if(!executing) { + executing = true; + + try { + super.execute(command); + } finally { + executing = false; + } + } else { + // Re-entrant command execution goes on a nested stack + try { + startNestedTransaction(command); + commit(); + } catch (OperationCanceledException e) { + rollback(); + // Propagate + throw e; + } + } + } else { + childCommandStack.execute(command); + } + } + + @Override + protected void handleError(Exception exception) { + if(nested && (exception instanceof RollbackException)) { + //A nested transaction rolled back + RollbackException rbe = (RollbackException)exception; + if(rbe.getStatus().getSeverity() == IStatus.CANCEL) { + // Propagate + throw new OperationCanceledException(); + } + } + + if(exception instanceof OperationCanceledException) { + rollback(); + // Propagate + throw (OperationCanceledException)exception; + } else { + super.handleError(exception); + } + } + + @Override + public Command getMostRecentCommand() { + if(childCommandStack == null) { + return super.getMostRecentCommand(); + } else { + return childCommandStack.getMostRecentCommand(); + } + } + + @Override + public Command getRedoCommand() { + if(childCommandStack == null) { + return super.getRedoCommand(); + } else { + return childCommandStack.getRedoCommand(); + } + } + + @Override + public Command getUndoCommand() { + if(childCommandStack == null) { + return super.getUndoCommand(); + } else { + return childCommandStack.getUndoCommand(); + } + } + + @Override + public void undo() { + if(childCommandStack == null) { + super.undo(); + } else { + childCommandStack.undo(); + } + } + + @Override + public boolean canUndo() { + if(childCommandStack == null) { + return super.canUndo(); + } else { + return childCommandStack.canUndo(); + } + } + + @Override + public boolean canRedo() { + if(childCommandStack == null) { + return super.canRedo(); + } else { + return childCommandStack.canRedo(); + } + } + + @Override + public void redo() { + if(childCommandStack == null) { + super.redo(); + } else { + childCommandStack.redo(); + } + } + + @Override + protected void doExecute(Command command, Map<?, ?> options) throws InterruptedException, RollbackException { + InternalTransaction tx = createTransaction(command, options); + boolean completed = false; + + try { + basicExecute(command); + + // new in EMF 2.4: AbortExecutionException can cause the + // command not to be added to the undo stack + completed = mostRecentCommand == command; + + // commit the transaction now + tx.commit(); + } catch (OperationCanceledException e) { + // snuff the exception, because this is expected (user asked to + // cancel the model change). We will rollback, below + if(nested) { + // Propagate to the nesting context + throw e; + } + } finally { + if((tx != null) && (tx.isActive())) { + // roll back (some exception, possibly being thrown now or + // an operation cancel, has occurred) + rollback(tx); + handleRollback(command, null); + } else { + // the transaction has already incorporated the triggers + // into its change description, so the recording command + // doesn't need them again + if(!(command instanceof RecordingCommand) && completed) { + Command triggerCommand = tx.getTriggers(); + + if(triggerCommand != null) { + // replace the executed command by a compound of the + // original and the trigger commands + CompoundCommand compound = new ConditionalRedoCommand.Compound(); + compound.append(mostRecentCommand); + compound.append(triggerCommand); + mostRecentCommand = compound; + commandList.set(top, mostRecentCommand); + } + } + } + } + } + + @Override + protected void basicExecute(Command command) { + try { + super.basicExecute(command); + } catch (OperationCanceledException e) { + // Ensure disposal of the command (when handleException() propagates a cancel, we will miss the chance) + command.dispose(); + throw e; + } + } +} diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/TransactionalEditingDomainManager.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/TransactionalEditingDomainManager.java index 845968f067a..73dd38fc2da 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/TransactionalEditingDomainManager.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/TransactionalEditingDomainManager.java @@ -1,7 +1,6 @@ /*****************************************************************************
- * Copyright (c) 2011-2012 Atos.
+ * Copyright (c) 2011, 2014 Atos, CEA, and others.
*
- *
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -9,6 +8,7 @@ *
* Contributors:
* Mathieu Velten mathieu.velten@atos.net - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.infra.core.resource;
@@ -99,7 +99,8 @@ public class TransactionalEditingDomainManager { // NotifyingWorkspaceCommandStack stack = new NotifyingWorkspaceCommandStack(CheckedOperationHistory.getInstance());
// stack.setResourceUndoContextPolicy(IResourceUndoContextPolicy.DEFAULT);
- TransactionalEditingDomain result = new TransactionalEditingDomainImpl(new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE), resourceSet);
+ NestingTransactionalCommandStack stack = new NestingTransactionalCommandStack();
+ TransactionalEditingDomain result = new TransactionalEditingDomainImpl(new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE), stack, resourceSet);
WorkspaceEditingDomainFactory.INSTANCE.mapResourceSet(result);
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainProvider.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainProvider.java index 19233543070..d9fe778ec6d 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainProvider.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainProvider.java @@ -1,7 +1,6 @@ /*****************************************************************************
- * Copyright (c) 2011 Atos Origin.
+ * Copyright (c) 2011, 2014 Atos Origin, CEA, and others.
*
- *
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -9,6 +8,7 @@ *
* Contributors:
* Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
@@ -19,6 +19,7 @@ import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.emf.workspace.IResourceUndoContextPolicy;
import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory;
import org.eclipse.papyrus.commands.CheckedOperationHistory;
+import org.eclipse.papyrus.commands.NestingNotifyingWorkspaceCommandStack;
import org.eclipse.papyrus.commands.NotifyingWorkspaceCommandStack;
import org.eclipse.papyrus.infra.core.resource.ITransactionalEditingDomainProvider;
@@ -32,7 +33,7 @@ import org.eclipse.papyrus.infra.core.resource.ITransactionalEditingDomainProvid public class PapyrusROTransactionalEditingDomainProvider implements ITransactionalEditingDomainProvider {
public TransactionalEditingDomain createTransactionalEditingDomain(ResourceSet resourceSet) {
- NotifyingWorkspaceCommandStack stack = new NotifyingWorkspaceCommandStack(CheckedOperationHistory.getInstance());
+ NotifyingWorkspaceCommandStack stack = new NestingNotifyingWorkspaceCommandStack(CheckedOperationHistory.getInstance());
stack.setResourceUndoContextPolicy(IResourceUndoContextPolicy.DEFAULT);
TransactionalEditingDomain result = new PapyrusROTransactionalEditingDomain(new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE), stack, resourceSet);
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF index b2fdcac9a08..b4c9fd570ce 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF @@ -30,6 +30,7 @@ Require-Bundle: org.eclipse.ui, org.eclipse.gmf.runtime.emf.type.core;bundle-version="1.7.0",
com.google.guava;bundle-version="11.0.0"
Export-Package: org.eclipse.papyrus.infra.emf,
+ org.eclipse.papyrus.infra.emf.adapters,
org.eclipse.papyrus.infra.emf.commands,
org.eclipse.papyrus.infra.emf.databinding,
org.eclipse.papyrus.infra.emf.dialog,
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/plugin.xml b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/plugin.xml index a5a77a29959..d9b6cb0f5d1 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/plugin.xml +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/plugin.xml @@ -57,5 +57,15 @@ </elementType>
</binding>
</extension>
+ <extension
+ point="org.eclipse.core.runtime.adapters">
+ <factory
+ adaptableType="org.eclipse.emf.ecore.EObject"
+ class="org.eclipse.papyrus.infra.emf.adapters.EObjectAdapterFactory">
+ <adapter
+ type="org.eclipse.papyrus.infra.widgets.creation.IAtomicOperationExecutor">
+ </adapter>
+ </factory>
+ </extension>
</plugin>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/adapters/EObjectAdapterFactory.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/adapters/EObjectAdapterFactory.java new file mode 100644 index 00000000000..e16b485fc3b --- /dev/null +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/adapters/EObjectAdapterFactory.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.emf.adapters; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.util.TransactionUtil; +import org.eclipse.papyrus.infra.emf.dialog.NestedEditingDialogContext; +import org.eclipse.papyrus.infra.widgets.creation.IAtomicOperationExecutor; + + +/** + * This is the EObjectAdapterFactory type. Enjoy. + */ +public class EObjectAdapterFactory implements IAdapterFactory { + + private final Class<?>[] adapterTypes = { IAtomicOperationExecutor.class }; + + public EObjectAdapterFactory() { + super(); + } + + public Object getAdapter(Object adaptable, @SuppressWarnings("rawtypes") Class adapterType) { + Object result = null; + + if(adaptable instanceof EObject) { + if(adapterType == IAtomicOperationExecutor.class) { + TransactionalEditingDomain domain = TransactionUtil.getEditingDomain((EObject)adaptable); + if(domain == null) { + ResourceSet rset = NestedEditingDialogContext.getInstance().getResourceSet(); + if(rset != null) { + domain = TransactionUtil.getEditingDomain(rset); + } + } + if(domain != null) { + result = new EMFAtomicOperationExecutor(domain); + } + } + } + + return result; + } + + @SuppressWarnings("rawtypes") + public Class[] getAdapterList() { + return adapterTypes; + } + + // + // Nested types + // + + private static final class EMFAtomicOperationExecutor extends IAtomicOperationExecutor.Default { + + private final TransactionalEditingDomain domain; + + EMFAtomicOperationExecutor(TransactionalEditingDomain domain) { + this.domain = domain; + } + + @Override + public void execute(final Runnable operation, String label) { + domain.getCommandStack().execute(new RecordingCommand(domain, label) { + + @Override + protected void doExecute() { + operation.run(); + } + }); + } + } +} diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/databinding/EMFObservableList.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/databinding/EMFObservableList.java index 6af566f79ad..beb832a0015 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/databinding/EMFObservableList.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/databinding/EMFObservableList.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.databinding;
@@ -17,6 +19,7 @@ import java.util.List; import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.ObservableList;
import org.eclipse.emf.common.command.Command;
@@ -41,7 +44,7 @@ import org.eclipse.papyrus.infra.widgets.editors.ICommitListener; * @author Camille Letavernier
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
-public class EMFObservableList extends ObservableList implements ICommitListener, IChangeListener {
+public class EMFObservableList extends ObservableList implements ICommitListener, IChangeListener, IObserving {
/**
* The list of commands that haven't been executed yet
@@ -106,6 +109,10 @@ public class EMFObservableList extends ObservableList implements ICommitListener }
}
+ public Object getObserved() {
+ return source;
+ }
+
@Override
public synchronized void dispose() {
if(concreteList instanceof IObservableList) {
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/dialog/NestedEditingDialogContext.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/dialog/NestedEditingDialogContext.java new file mode 100644 index 00000000000..813e5524574 --- /dev/null +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/dialog/NestedEditingDialogContext.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.emf.dialog; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; + +/** + * A tracker of nested editing-dialog context information required by various components that have no direct access to the context. + */ +public class NestedEditingDialogContext { + + private static final NestedEditingDialogContext INSTANCE = new NestedEditingDialogContext(); + + private final ThreadLocal<Integer> nesting = new ThreadLocal<Integer>(); + + private final ThreadLocal<ResourceSet> resourceSet = new ThreadLocal<ResourceSet>(); + + public static NestedEditingDialogContext getInstance() { + return INSTANCE; + } + + /** + * Queries whether the current editing dialog is nested in (created by) a higher-level dialog editing some other object. + * + * @return whether the current thread is presenting a nested editing dialog + */ + public boolean isNested() { + Integer depth = nesting.get(); + return (depth != null) && (depth.intValue() > 0); + } + + /** + * Signals entry of an editing dialog context (the current thread is now presenting a dialog). Must be matched by a subsequent + * call to {@linkplain #exit() exit} the context. + * + * @see #exit() + */ + public void enter() { + Integer depth = nesting.get(); + if((depth == null) || (depth.intValue() < 1)) { + depth = 1; + } else { + depth = depth.intValue() + 1; + } + nesting.set(depth); + } + + /** + * Signals the end of an editing dialog context (the current thread is no longer presenting a dialog). Must match an earlier + * call to {@linkplain #enter() enter} the context. + * + * @see #enter() + */ + public void exit() { + Integer depth = nesting.get(); + if(depth != null) { + if(depth.intValue() <= 1) { + depth = null; + } else { + depth = depth.intValue() - 1; + } + nesting.set(depth); + } + } + + /** + * Obtains the resource set in the editing-dialog context of the current thread. + * + * @return the current contextual resource set + */ + public ResourceSet getResourceSet() { + return resourceSet.get(); + } + + /** + * Determines, if possible, the resource set containing the given {@code context} object being edited and pushes it onto the + * current thread's context stack. + * + * @param context + * the object currently being edited in a dialog + * + * @return the resource set that was previously the context (which may be the same as the new one being pushed). This + * must be {@linkplain #pop(ResourceSet) popped} from the context subsequently + * + * @see #pop(ResourceSet) + */ + public ResourceSet push(Object context) { + final ResourceSet previous = resourceSet.get(); + + if(context instanceof EObject) { + Resource res = ((EObject)context).eResource(); + if(res != null) { + ResourceSet current = res.getResourceSet(); + if(current != null) { + // put it in context + resourceSet.set(current); + } + } + } + + return previous; + } + + /** + * Pops the current resource set from the context, restoring the given resource set that was returned by a previous {@linkplain #push(Object) + * push}, even if it was {@code null}. + * + * @param previous + * a resource set returned by an earlier push (may be {@code null}) + * + * @see #push(Object) + */ + public void pop(ResourceSet previous) { + if(previous == null) { + resourceSet.remove(); + } else { + resourceSet.set(previous); + } + } +} diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands/src/org/eclipse/papyrus/commands/NestingNotifyingWorkspaceCommandStack.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands/src/org/eclipse/papyrus/commands/NestingNotifyingWorkspaceCommandStack.java new file mode 100644 index 00000000000..d35ce4035e3 --- /dev/null +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands/src/org/eclipse/papyrus/commands/NestingNotifyingWorkspaceCommandStack.java @@ -0,0 +1,231 @@ +/***************************************************************************** + * Copyright (c) 2013, 2014 CEA LIST and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation + * Christian W. Damus (CEA) - adapted for self-nesting behaviour + * + *****************************************************************************/ +package org.eclipse.papyrus.commands; + +import org.eclipse.core.commands.operations.IOperationHistory; +import org.eclipse.core.commands.operations.IUndoContext; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.transaction.RollbackException; + + +public class NestingNotifyingWorkspaceCommandStack extends NotifyingWorkspaceCommandStack { + + private NestingNotifyingWorkspaceCommandStack childCommandStack; + + private final boolean nested; + + private boolean executing; + + protected IUndoContext defaultUndoContext; + + public NestingNotifyingWorkspaceCommandStack(IOperationHistory history) { + this(false, history, null); + } + + protected NestingNotifyingWorkspaceCommandStack(boolean nested, IOperationHistory history, IUndoContext defaultUndoContext) { + super(history); + this.nested = nested; + this.defaultUndoContext = defaultUndoContext; + } + + protected NestingNotifyingWorkspaceCommandStack(boolean nested, IOperationHistory history) { + this(nested, history, computeNestedUndoContext()); + } + + private static IUndoContext computeNestedUndoContext() { + return new IUndoContext() { + + public boolean matches(IUndoContext context) { + return context == this; + } + + public String getLabel() { + return "Nested Undo Context"; + } + }; + } + + @Override + public IUndoContext getDefaultUndoContext() { + if(defaultUndoContext == null) { + return super.getDefaultUndoContext(); + } + return defaultUndoContext; + } + + protected NestingNotifyingWorkspaceCommandStack getTopMostCommandStack() { + if(childCommandStack == null) { + return this; + } + return childCommandStack.getTopMostCommandStack(); + } + + protected void startNestedTransaction(Command command) { + if(childCommandStack != null) { + //Forwards to the current stack + childCommandStack.startNestedTransaction(command); + } else { + //Start a new nested transaction in a new nested Stack + childCommandStack = createNestedCommandStack(getOperationHistory()); + childCommandStack.setEditingDomain(getDomain()); + + childCommandStack.execute(command); + } + } + + protected NestingNotifyingWorkspaceCommandStack createNestedCommandStack(IOperationHistory history) { + return new NestingNotifyingWorkspaceCommandStack(true, history); + } + + public void commit() { + if(childCommandStack != null) { + disposeLastCommandStack(); + } + } + + private boolean disposeLastCommandStack() { + if(childCommandStack == null) { + //I'm the last command stack + dispose(); + return true; + } + + //Propagates + if(childCommandStack.disposeLastCommandStack()) { + childCommandStack = null; + } + + return false; + } + + public void rollback() { + if(childCommandStack != null) { + while (canUndo()) { + undo(); + } + disposeLastCommandStack(); + } + } + + @Override + public void execute(Command command) { + if(childCommandStack == null) { + if(!executing) { + executing = true; + + try { + super.execute(command); + } finally { + executing = false; + } + } else { + // Re-entrant command execution goes on a nested stack + try { + startNestedTransaction(command); + commit(); + } catch (OperationCanceledException e) { + rollback(); + // Propagate + throw e; + } + } + } else { + childCommandStack.execute(command); + } + } + + @Override + protected void handleError(Exception exception) { + if (nested && (exception instanceof RollbackException)) { + //A nested transaction rolled back + RollbackException rbe = (RollbackException) exception; + if (rbe.getStatus().getSeverity() == IStatus.CANCEL) { + // Propagate + throw new OperationCanceledException(); + } + } + + if (exception instanceof OperationCanceledException) { + rollback(); + } else { + super.handleError(exception); + } + } + + @Override + public Command getMostRecentCommand() { + if(childCommandStack == null) { + return super.getMostRecentCommand(); + } else { + return childCommandStack.getMostRecentCommand(); + } + } + + @Override + public Command getRedoCommand() { + if(childCommandStack == null) { + return super.getRedoCommand(); + } else { + return childCommandStack.getRedoCommand(); + } + } + + @Override + public Command getUndoCommand() { + if(childCommandStack == null) { + return super.getUndoCommand(); + } else { + return childCommandStack.getUndoCommand(); + } + } + + @Override + public void undo() { + if(childCommandStack == null) { + super.undo(); + } else { + childCommandStack.undo(); + } + } + + @Override + public boolean canUndo() { + if(childCommandStack == null) { + return super.canUndo(); + } else { + return childCommandStack.canUndo(); + } + } + + @Override + public boolean canRedo() { + if(childCommandStack == null) { + return super.canRedo(); + } else { + return childCommandStack.canRedo(); + } + } + + @Override + public void redo() { + if(childCommandStack == null) { + super.redo(); + } else { + childCommandStack.redo(); + } + } + +} diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands/src/org/eclipse/papyrus/commands/NotifyingWorkspaceCommandStack.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands/src/org/eclipse/papyrus/commands/NotifyingWorkspaceCommandStack.java index 854f1a86d94..da6fbbfae6d 100644 --- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands/src/org/eclipse/papyrus/commands/NotifyingWorkspaceCommandStack.java +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands/src/org/eclipse/papyrus/commands/NotifyingWorkspaceCommandStack.java @@ -1,7 +1,6 @@ /*****************************************************************************
- * Copyright (c) 2011, 2013 Atos, CEA, and others.
+ * Copyright (c) 2011, 2014 Atos, CEA, and others.
*
- *
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,6 +10,7 @@ * Mathieu Velten (Atos) - Initial API and implementation
* Arthur Daussy (Atos) - 363826: [Model Explorer] Drag and drop and undo, incorrect behavior
* Christian W. Damus (CEA) - 404220: Add contexts for tracking objects changed by operations (CDO)
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.commands;
@@ -181,7 +181,7 @@ implements IWorkspaceCommandStack { }
// Documentation copied from the method specification
- public final IUndoContext getDefaultUndoContext() {
+ public IUndoContext getDefaultUndoContext() {
return defaultContext;
}
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/databinding/custom/AbstractCustomStyleObservableValue.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/databinding/custom/AbstractCustomStyleObservableValue.java index af7a984bf13..406b4a0f6cf 100644 --- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/databinding/custom/AbstractCustomStyleObservableValue.java +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/databinding/custom/AbstractCustomStyleObservableValue.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,11 +8,14 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.gmfdiag.common.databinding.custom;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.core.databinding.observable.value.ValueDiff;
import org.eclipse.emf.common.command.Command;
@@ -31,7 +34,7 @@ import org.eclipse.papyrus.uml.tools.databinding.CommandBasedObservableValue; * @author Camille Letavernier
*
*/
-public abstract class AbstractCustomStyleObservableValue extends AbstractObservableValue implements CommandBasedObservableValue, IChangeListener {
+public abstract class AbstractCustomStyleObservableValue extends AbstractObservableValue implements CommandBasedObservableValue, IChangeListener, IObserving {
protected View source;
@@ -104,6 +107,11 @@ public abstract class AbstractCustomStyleObservableValue extends AbstractObserva public Command getCommand(Object value) {
return new CustomStyleValueCommand(source, value, styleClass, styleFeature, styleName);
}
+
+ @Override
+ public Object getObserved() {
+ return source;
+ }
@Override
public void dispose() {
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/editpolicies/XYLayoutWithConstrainedResizedEditPolicy.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/editpolicies/XYLayoutWithConstrainedResizedEditPolicy.java index 87d508506f5..aa77b8fa7f1 100644 --- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/editpolicies/XYLayoutWithConstrainedResizedEditPolicy.java +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/editpolicies/XYLayoutWithConstrainedResizedEditPolicy.java @@ -86,24 +86,26 @@ public class XYLayoutWithConstrainedResizedEditPolicy extends XYLayoutEditPolicy double spacing = drep.getGridSpacing();
final double max_value = spacing * 20;
final SnapToHelper helper = (SnapToHelper)getHost().getAdapter(SnapToHelper.class);
- final LayoutHelper layoutHelper = new LayoutHelper();
- while(add < max_value) {//we define a max value to do test
- Rectangle LOCAL_BOUNDS = BOUNDS.getCopy();
- LOCAL_BOUNDS.translate(add, add);
- Rectangle tmp_rect = getBoundsOffest(req, LOCAL_BOUNDS, viewDescriptor);
- final PrecisionRectangle resultRect = new PrecisionRectangle(tmp_rect);
- resultRect.setWidth(-1);
- resultRect.setHeight(-1);
- PrecisionPoint res1 = new PrecisionPoint(tmp_rect.getLocation());
- helper.snapPoint(request, PositionConstants.NORTH_WEST, res1.getPreciseCopy(), res1);
- final Point pt = layoutHelper.validatePosition(getHostFigure(), resultRect.setLocation(res1));
- if(couldBeSnaped) {
- if(pt.equals(resultRect.getLocation())) {
- rect.setLocation(resultRect.getLocation());
- break;
- } else {
- add += spacing;
- continue;
+ if(helper != null) {
+ final LayoutHelper layoutHelper = new LayoutHelper();
+ while(add < max_value) {//we define a max value to do test
+ Rectangle LOCAL_BOUNDS = BOUNDS.getCopy();
+ LOCAL_BOUNDS.translate(add, add);
+ Rectangle tmp_rect = getBoundsOffest(req, LOCAL_BOUNDS, viewDescriptor);
+ final PrecisionRectangle resultRect = new PrecisionRectangle(tmp_rect);
+ resultRect.setWidth(-1);
+ resultRect.setHeight(-1);
+ PrecisionPoint res1 = new PrecisionPoint(tmp_rect.getLocation());
+ helper.snapPoint(request, PositionConstants.NORTH_WEST, res1.getPreciseCopy(), res1);
+ final Point pt = layoutHelper.validatePosition(getHostFigure(), resultRect.setLocation(res1));
+ if(couldBeSnaped) {
+ if(pt.equals(resultRect.getLocation())) {
+ rect.setLocation(resultRect.getLocation());
+ break;
+ } else {
+ add += spacing;
+ continue;
+ }
}
}
}
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/handler/TransactionalCommandHandler.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/handler/TransactionalCommandHandler.java new file mode 100644 index 00000000000..539f4eb8662 --- /dev/null +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/handler/TransactionalCommandHandler.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.nattable.handler; + +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.nebula.widgets.nattable.command.ILayerCommand; +import org.eclipse.nebula.widgets.nattable.command.ILayerCommandHandler; +import org.eclipse.nebula.widgets.nattable.command.VisualRefreshCommand; +import org.eclipse.nebula.widgets.nattable.layer.ILayer; +import org.eclipse.swt.widgets.Display; + + +/** + * A base layer command handler that executes commands on a {@link TransactionalEditingDomain}'s command-stack. + * This ensures atomic undo/redo of all model changes performed by the command. + */ +public abstract class TransactionalCommandHandler<T extends ILayerCommand> implements ILayerCommandHandler<T> { + + private final TransactionalEditingDomain domain; + + private String label; + + public TransactionalCommandHandler(TransactionalEditingDomain domain) { + this.domain = domain; + } + + public TransactionalCommandHandler(TransactionalEditingDomain domain, String label) { + this.domain = domain; + + this.label = label; + } + + public String getLabel() { + return (label != null) ? label : "Table Command"; + } + + public void setLabel(String label) { + this.label = label; + } + + @Override + public final boolean doCommand(final ILayer targetLayer, final T command) { + final boolean[] result = { false }; + + if(command.convertToTargetLayer(targetLayer)) { + domain.getCommandStack().execute(new RecordingCommand(domain, getLabel()) { + + @Override + protected void doExecute() { + ExecutionStatusKind status = doCommand(command); + + result[0] = status.isOK(); + + if(status.isRollback()) { + // Refresh the visual presentation of the layer because stereotype applications + // may have updated some cells + Display.getCurrent().asyncExec(new Runnable() { + + @Override + public void run() { + targetLayer.doCommand(new VisualRefreshCommand()); + } + }); + + // Roll back any changes that we made along the way + throw new OperationCanceledException(); + } + } + }); + } + + return result[0]; + } + + protected abstract ExecutionStatusKind doCommand(T command); + + // + // Nested types + // + + protected enum ExecutionStatusKind { + /** Command failed and should be rolled back so that it will not appear on the stack. */ + FAIL_ROLLBACK(false, true), + /** Command succeeded and should appear on the stack. */ + OK_COMPLETE(true, false), + /** Command succeeded but should be rolled back so that it will not appear on the stack. */ + OK_ROLLBACK(true, true); + + private final boolean ok; + + private final boolean rollback; + + private ExecutionStatusKind(boolean ok, boolean rollback) { + this.ok = ok; + this.rollback = rollback; + } + + public boolean isOK() { + return ok; + } + + public boolean isRollback() { + return rollback; + } + } +} diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/handler/TransactionalEditCellCommandHandler.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/handler/TransactionalEditCellCommandHandler.java new file mode 100644 index 00000000000..c32a105d93e --- /dev/null +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/handler/TransactionalEditCellCommandHandler.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * Dirk Fauth <dirk.fauth@gmail.com> - Initial API and implementation of EditController class + * + */ +package org.eclipse.papyrus.infra.nattable.handler; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.window.Window; +import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; +import org.eclipse.nebula.widgets.nattable.config.IEditableRule; +import org.eclipse.nebula.widgets.nattable.edit.ActiveCellEditorRegistry; +import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes; +import org.eclipse.nebula.widgets.nattable.edit.EditTypeEnum; +import org.eclipse.nebula.widgets.nattable.edit.InlineEditHandler; +import org.eclipse.nebula.widgets.nattable.edit.command.EditCellCommand; +import org.eclipse.nebula.widgets.nattable.edit.command.UpdateDataCommand; +import org.eclipse.nebula.widgets.nattable.edit.editor.ICellEditor; +import org.eclipse.nebula.widgets.nattable.edit.gui.CellEditDialogFactory; +import org.eclipse.nebula.widgets.nattable.edit.gui.ICellEditDialog; +import org.eclipse.nebula.widgets.nattable.layer.ILayer; +import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; +import org.eclipse.nebula.widgets.nattable.style.DisplayMode; +import org.eclipse.nebula.widgets.nattable.widget.EditModeEnum; +import org.eclipse.papyrus.infra.nattable.Activator; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + + +/** + * A variant of the {@link EditCellCommand} handler that executes changes on a {@link TransactionalEditingDomain}'s command-stack. + */ +public class TransactionalEditCellCommandHandler extends TransactionalCommandHandler<EditCellCommand> { + + public TransactionalEditCellCommandHandler(TransactionalEditingDomain domain) { + this(domain, "Edit Table Cell"); + } + + public TransactionalEditCellCommandHandler(TransactionalEditingDomain domain, String label) { + super(domain, label); + } + + @Override + public Class<EditCellCommand> getCommandClass() { + return EditCellCommand.class; + } + + protected ExecutionStatusKind doCommand(EditCellCommand command) { + ILayerCell cell = command.getCell(); + Composite parent = command.getParent(); + IConfigRegistry configRegistry = command.getConfigRegistry(); + + IEditableRule rule = (IEditableRule)configRegistry.getConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, DisplayMode.EDIT, cell.getConfigLabels().getLabels()); + + if(rule.isEditable(cell, configRegistry)) { + return editCell(cell, parent, cell.getDataValue(), configRegistry); + } + + return ExecutionStatusKind.FAIL_ROLLBACK; + } + + // From Nebula EditController (with minor tweaks) + protected ExecutionStatusKind editCell(ILayerCell cell, Composite parent, Object initialCanonicalValue, IConfigRegistry configRegistry) { + ExecutionStatusKind result = ExecutionStatusKind.FAIL_ROLLBACK; + + try { + Rectangle cellBounds = cell.getBounds(); + ILayer layer = cell.getLayer(); + + int columnPosition = cell.getColumnPosition(); + int rowPosition = cell.getRowPosition(); + + List<String> configLabels = cell.getConfigLabels().getLabels(); + + ICellEditor cellEditor = (ICellEditor)configRegistry.getConfigAttribute(EditConfigAttributes.CELL_EDITOR, DisplayMode.EDIT, configLabels); + + // Try to open an in-line editor before falling back to a dialog + if(cellEditor.openInline(configRegistry, configLabels)) { + MyInlineEditHandler editHandler = new MyInlineEditHandler(layer, columnPosition, rowPosition); + + Rectangle editorBounds = layer.getLayerPainter().adjustCellBounds(columnPosition, rowPosition, new Rectangle(cellBounds.x, cellBounds.y, cellBounds.width, cellBounds.height)); + + cellEditor.activateCell(parent, initialCanonicalValue, EditModeEnum.INLINE, editHandler, cell, configRegistry); + + Control editorControl = cellEditor.getEditorControl(); + if((editorControl != null) && (!(editorControl.isDisposed()))) { + editorControl.setBounds(editorBounds); + + cellEditor.addEditorControlListeners(); + ActiveCellEditorRegistry.registerActiveCellEditor(cellEditor); + } + + // Command succeeded but should not appear on the undo stack because we haven't completed an edit (only activated the cell editor), + // unless the cell editor is like the CheckBoxCellEditor that commits upon activation + result = editHandler.isCommitted() ? ExecutionStatusKind.OK_COMPLETE : ExecutionStatusKind.OK_ROLLBACK; + } else { + // The dialog case + List<ILayerCell> cells = new ArrayList<ILayerCell>(1); + cells.add(cell); + result = editCells(cells, parent, initialCanonicalValue, configRegistry); + } + } catch (OperationCanceledException e) { + // OK. The user cancelled a dialog or some such + result = ExecutionStatusKind.FAIL_ROLLBACK; + } catch (Exception e) { + Activator.log.error("Uncaught exception in table cell editor activation.", e); //$NON-NLS-1$ + } + + return result; + } + + // From Nebula EditController (with minor tweaks) + protected ExecutionStatusKind editCells(List<ILayerCell> cells, Composite parent, Object initialCanonicalValue, IConfigRegistry configRegistry) { + if((cells == null) || (cells.isEmpty())) { + return ExecutionStatusKind.FAIL_ROLLBACK; + } + + ICellEditor cellEditor = (ICellEditor)configRegistry.getConfigAttribute(EditConfigAttributes.CELL_EDITOR, DisplayMode.EDIT, ((ILayerCell)cells.get(0)).getConfigLabels().getLabels()); + + if((cells.size() != 1) && ((cells.size() <= 1) || !(supportMultiEdit(cells, cellEditor, configRegistry)))) { + return ExecutionStatusKind.FAIL_ROLLBACK; + } + + ExecutionStatusKind result = ExecutionStatusKind.FAIL_ROLLBACK; + + ICellEditDialog dialog = CellEditDialogFactory.createCellEditDialog((parent != null) ? parent.getShell() : null, initialCanonicalValue, (ILayerCell)cells.get(0), cellEditor, configRegistry); + + int returnValue = dialog.open(); + + if(returnValue == Window.OK) { + // The edit was completed and should appear on the undo stack + result = ExecutionStatusKind.OK_COMPLETE; + + for(ILayerCell selectedCell : cells) { + Object editorValue = dialog.getCommittedValue(); + if(dialog.getEditType() != EditTypeEnum.SET) { + editorValue = dialog.calculateValue(selectedCell.getDataValue(), editorValue); + } + ILayer layer = selectedCell.getLayer(); + + layer.doCommand(new UpdateDataCommand(layer, selectedCell.getColumnPosition(), selectedCell.getRowPosition(), editorValue)); + } + } + + return result; + } + + // From Nebula EditController (with minor tweaks) + private static boolean supportMultiEdit(List<ILayerCell> cells, ICellEditor cellEditor, IConfigRegistry configRegistry) { + for(ILayerCell cell : cells) { + if(!(cellEditor.supportMultiEdit(configRegistry, cell.getConfigLabels().getLabels()))) { + return false; + } + } + return true; + } + + // + // Nested types + // + + private static class MyInlineEditHandler extends InlineEditHandler { + + private boolean committed; + + MyInlineEditHandler(ILayer layer, int columnPosition, int rowPosition) { + super(layer, columnPosition, rowPosition); + } + + @Override + public boolean commit(Object canonicalValue, MoveDirectionEnum direction) { + boolean result = super.commit(canonicalValue, direction); + + committed = result || committed; + + return result; + } + + boolean isCommitted() { + return committed; + } + } +} diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/layer/PapyrusGridLayer.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/layer/PapyrusGridLayer.java index f0dc17d9864..0194de0f87e 100644 --- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/layer/PapyrusGridLayer.java +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/layer/PapyrusGridLayer.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 CEA LIST and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,13 +9,18 @@ *
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.infra.nattable.layer;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.nebula.widgets.nattable.command.ILayerCommandHandler;
+import org.eclipse.nebula.widgets.nattable.edit.command.EditCellCommand;
import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.papyrus.infra.nattable.configuration.PapyrusGridLayerConfiguration;
+import org.eclipse.papyrus.infra.nattable.handler.TransactionalEditCellCommandHandler;
/**
* This grid layer ovverride the default edition behavior
@@ -25,6 +30,8 @@ import org.eclipse.papyrus.infra.nattable.configuration.PapyrusGridLayerConfigur */
public class PapyrusGridLayer extends GridLayer {
+ private final TransactionalEditingDomain domain;
+
/**
*
* Constructor.
@@ -34,8 +41,10 @@ public class PapyrusGridLayer extends GridLayer { * @param rowHeaderLayer
* @param cornerLayer
*/
- public PapyrusGridLayer(ILayer bodyLayer, ILayer columnHeaderLayer, ILayer rowHeaderLayer, ILayer cornerLayer) {
+ public PapyrusGridLayer(TransactionalEditingDomain domain, ILayer bodyLayer, ILayer columnHeaderLayer, ILayer rowHeaderLayer, ILayer cornerLayer) {
super(bodyLayer, columnHeaderLayer, rowHeaderLayer, cornerLayer);
+
+ this.domain = domain;
}
/**
@@ -48,8 +57,10 @@ public class PapyrusGridLayer extends GridLayer { * @param cornerLayer
* @param useDefaultConfiguration
*/
- public PapyrusGridLayer(ILayer bodyLayer, ILayer columnHeaderLayer, ILayer rowHeaderLayer, ILayer cornerLayer, boolean useDefaultConfiguration) {
+ public PapyrusGridLayer(TransactionalEditingDomain domain, ILayer bodyLayer, ILayer columnHeaderLayer, ILayer rowHeaderLayer, ILayer cornerLayer, boolean useDefaultConfiguration) {
super(bodyLayer, columnHeaderLayer, rowHeaderLayer, cornerLayer, useDefaultConfiguration);
+
+ this.domain = domain;
}
/**
@@ -58,8 +69,10 @@ public class PapyrusGridLayer extends GridLayer { *
* @param useDefaultConfiguration
*/
- public PapyrusGridLayer(boolean useDefaultConfiguration) {
+ public PapyrusGridLayer(TransactionalEditingDomain domain, boolean useDefaultConfiguration) {
super(useDefaultConfiguration);
+
+ this.domain = domain;
}
@Override
@@ -71,7 +84,14 @@ public class PapyrusGridLayer extends GridLayer { }
}
+ @Override
+ public void registerCommandHandler(ILayerCommandHandler<?> commandHandler) {
+ // Override the default edit handler
+ if(commandHandler.getCommandClass() == EditCellCommand.class) {
+ commandHandler = new TransactionalEditCellCommandHandler(domain);
+ }
-
+ super.registerCommandHandler(commandHandler);
+ }
}
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/manager/table/AbstractNattableWidgetManager.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/manager/table/AbstractNattableWidgetManager.java index b4bf438bb2b..8cde6c07269 100644 --- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/manager/table/AbstractNattableWidgetManager.java +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/manager/table/AbstractNattableWidgetManager.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2014 CEA LIST and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,6 +9,7 @@ *
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.infra.nattable.manager.table;
@@ -17,6 +18,7 @@ import java.util.List; import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.ui.dnd.LocalTransfer;
+import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
@@ -182,7 +184,7 @@ public abstract class AbstractNattableWidgetManager implements INattableModelMan final IDataProvider cornerDataProvider = new DefaultCornerDataProvider(this.columnHeaderDataProvider, this.rowHeaderDataProvider);
final CornerLayer cornerLayer = new CornerLayer(new DataLayer(cornerDataProvider), this.rowHeaderLayerStack, this.columnHeaderLayerStack);
cornerLayer.addConfiguration(new CornerConfiguration(this));
- this.gridLayer = new PapyrusGridLayer(this.bodyLayerStack, this.columnHeaderLayerStack, this.rowHeaderLayerStack, cornerLayer);
+ this.gridLayer = new PapyrusGridLayer(TransactionUtil.getEditingDomain(tableContext), this.bodyLayerStack, this.columnHeaderLayerStack, this.rowHeaderLayerStack, cornerLayer);
this.gridLayer.addConfiguration(new DefaultPrintBindings());
this.natTable = new NatTable(parent, this.gridLayer, false);
diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/painter/CustomCheckBoxPainter.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/painter/CustomCheckBoxPainter.java index 449d7ffeb47..e3c566b7d81 100644 --- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/painter/CustomCheckBoxPainter.java +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/painter/CustomCheckBoxPainter.java @@ -30,6 +30,11 @@ import org.eclipse.swt.graphics.Rectangle; public class CustomCheckBoxPainter extends CheckBoxPainter {
/**
+ * the text painter used to paint N/A
+ */
+ private TextPainter textPainter = new CustomizedCellPainter();
+
+ /**
*
* @see org.eclipse.nebula.widgets.nattable.painter.cell.ImagePainter#getCellPainterAt(int, int,
* org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell, org.eclipse.swt.graphics.GC, org.eclipse.swt.graphics.Rectangle,
@@ -48,8 +53,7 @@ public class CustomCheckBoxPainter extends CheckBoxPainter { try {
isChecked(cell, configRegistry);
} catch (Exception e) {
- TextPainter painter = new CustomizedCellPainter();
- return painter.getCellPainterAt(x, y, cell, gc, bounds, configRegistry);
+ return this;
}
return super.getCellPainterAt(x, y, cell, gc, bounds, configRegistry);
}
@@ -69,8 +73,7 @@ public class CustomCheckBoxPainter extends CheckBoxPainter { try {
isChecked(cell, configRegistry);
} catch (Exception e) {
- TextPainter painter = new CustomizedCellPainter();
- painter.paintCell(cell, gc, bounds, configRegistry);
+ this.textPainter.paintCell(cell, gc, bounds, configRegistry);
return;
}
super.paintCell(cell, gc, bounds, configRegistry);
@@ -91,8 +94,7 @@ public class CustomCheckBoxPainter extends CheckBoxPainter { try {
isChecked(cell, configRegistry);
} catch (Exception e) {
- TextPainter painter = new CustomizedCellPainter();
- return painter.getPreferredWidth(cell, gc, configRegistry);
+ return textPainter.getPreferredWidth(cell, gc, configRegistry);
}
return super.getPreferredWidth(cell, gc, configRegistry);
}
@@ -112,8 +114,7 @@ public class CustomCheckBoxPainter extends CheckBoxPainter { try {
isChecked(cell, configRegistry);
} catch (Exception e) {
- TextPainter painter = new CustomizedCellPainter();
- return painter.getPreferredHeight(cell, gc, configRegistry);
+ return textPainter.getPreferredHeight(cell, gc, configRegistry);
}
return super.getPreferredHeight(cell, gc, configRegistry);
}
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/BooleanEditionFactory.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/BooleanEditionFactory.java index 8f326b0d196..28e586aa906 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/BooleanEditionFactory.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/BooleanEditionFactory.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 CEA LIST and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,6 +9,7 @@ *
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.creation;
@@ -71,16 +72,9 @@ public class BooleanEditionFactory extends StringEditionFactory { super(title, label, new BooleanInputValidator());
}
- /**
- *
- * @see org.eclipse.papyrus.infra.widgets.creation.StringEditionFactory#createObject(org.eclipse.swt.widgets.Control)
- *
- * @param widget
- * @return
- */
@Override
- public Object createObject(Control widget) {
- String txt = super.createObject(widget).toString();
+ public Object createObject(Control widget, Object context) {
+ String txt = super.createObject(widget, context).toString();
if(txt != null) {
return Boolean.parseBoolean(txt);
}
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/IAtomicOperationExecutor.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/IAtomicOperationExecutor.java new file mode 100644 index 00000000000..dc69d248b2b --- /dev/null +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/IAtomicOperationExecutor.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.widgets.creation; + +import java.util.concurrent.Callable; + +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.papyrus.infra.widgets.Activator; + + +/** + * An interface that ensures execution of model changes as an atomic unit that is potentially undoable and redoable, such as on a "command stack" + * (whatever form it may take). + */ +public interface IAtomicOperationExecutor { + + IAtomicOperationExecutor DEFAULT = new Default(); + + /** + * Execute a runnable (an operation returning no result). + * + * @param operation + * the operation to execute + * @param label + * an optional label to associate with the operation for presentation in, for example, the Edit menu's Undo/Redo operations + */ + void execute(Runnable operation, String label); + + /** + * Execute a callable (an operation returning a result). + * + * @param operation + * the operation to execute + * @param label + * an optional label to associate with the operation for presentation in, for example, the Edit menu's Undo/Redo operations + * @return the {@code operation}'s result + */ + <V> V execute(Callable<V> operation, String label); + + // + // Nested types + // + + class Default implements IAtomicOperationExecutor { + + public void execute(final Runnable operation, String label) { + try { + operation.run(); + } catch (OperationCanceledException e) { + // We cannot really implement cancel because there is not command/transaction to roll back + } + } + + public <V> V execute(final Callable<V> operation, String label) { + class CallableWrapper implements Runnable { + + V result; + + @Override + public void run() { + try { + result = operation.call(); + } catch (OperationCanceledException e) { + // Don't trap this one + throw e; + } catch (Exception e) { + Activator.log.error("Callable operation failed.", e); //$NON-NLS-1$ + throw new OperationCanceledException(); // roll back + } + } + } + + CallableWrapper wrapper = new CallableWrapper(); + + execute(wrapper, label); + + return wrapper.result; + } + + } +} diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/IntegerEditionFactory.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/IntegerEditionFactory.java index 3f2c4b05b43..a254d03cda8 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/IntegerEditionFactory.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/IntegerEditionFactory.java @@ -1,7 +1,6 @@ /*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 CEA LIST and others.
*
- *
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -9,6 +8,7 @@ *
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.creation;
@@ -69,16 +69,9 @@ public class IntegerEditionFactory extends StringEditionFactory { this(title, label, new IntegerInputValidator());
}
- /**
- *
- * @see org.eclipse.papyrus.infra.widgets.creation.StringEditionFactory#createObject(org.eclipse.swt.widgets.Control)
- *
- * @param widget
- * @return
- */
@Override
- public Object createObject(Control widget) {
- String txt = super.createObject(widget).toString();
+ public Object createObject(Control widget, Object context) {
+ String txt = super.createObject(widget, context).toString();
if(txt != null) {
return Integer.parseInt(txt);
}
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/ReferenceValueFactory.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/ReferenceValueFactory.java index 25586368f79..f6fac32bac1 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/ReferenceValueFactory.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/ReferenceValueFactory.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.creation;
@@ -50,10 +52,13 @@ public interface ReferenceValueFactory { * @param widget
* The widget calling this factory. It can be used for example to retrieve
* the Display for opening a Dialog
+ * @param context
+ * The object being edited, in which context the new object is to be created and which will as a result have a reference to the new object.
+ * If there is no context object (creation of a free-floating object) or it cannot be determined, this may be {@code null}
* @return
* The newly created object, or null if no object has been created
*/
- public Object createObject(Control widget);
+ public Object createObject(Control widget, Object context);
/**
* The objects have been validated (For example, the user pressed "Ok")
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/StringEditionFactory.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/StringEditionFactory.java index 837eaddffe9..cadc95e9bc0 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/StringEditionFactory.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/StringEditionFactory.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.creation;
@@ -90,7 +92,7 @@ public class StringEditionFactory implements ReferenceValueFactory { return true;
}
- public Object createObject(Control widget) {
+ public Object createObject(Control widget, Object context) {
InputDialog dialog = new InputDialog(widget.getShell(), title, label, "", validator); //$NON-NLS-1$
if(contentProvider != null) {
dialog.setContentProvider(contentProvider);
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/UnlimitedNaturalEditionFactory.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/UnlimitedNaturalEditionFactory.java index 1b17b27193f..66e4780188c 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/UnlimitedNaturalEditionFactory.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/creation/UnlimitedNaturalEditionFactory.java @@ -1,7 +1,6 @@ /*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 CEA LIST and others.
*
- *
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -9,6 +8,7 @@ *
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.creation;
@@ -73,16 +73,9 @@ public class UnlimitedNaturalEditionFactory extends StringEditionFactory { super(title, label, validator);
}
- /**
- *
- * @see org.eclipse.papyrus.infra.widgets.creation.StringEditionFactory#createObject(org.eclipse.swt.widgets.Control)
- *
- * @param widget
- * @return
- */
@Override
- public Object createObject(Control widget) {
- String txt = super.createObject(widget).toString();
+ public Object createObject(Control widget, Object context) {
+ String txt = super.createObject(widget, context).toString();
if(UnlimitedNaturalValidator.INFINITE_STAR.equals(txt)) {
txt = UnlimitedNaturalValidator.INFINITE_MINUS_ONE;
}
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractEditor.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractEditor.java index 4526632711c..28b7d8c9ee8 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractEditor.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractEditor.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.editors;
@@ -17,6 +19,9 @@ import java.util.Set; import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.conversion.IConverter;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.papyrus.infra.widgets.creation.IAtomicOperationExecutor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
@@ -363,4 +368,34 @@ public abstract class AbstractEditor extends Composite implements DisposeListene dispose();
}
+ /**
+ * Obtains the most appropriate operation executor for the object being edited.
+ *
+ * @param context the object being edited
+ * @return the executor to use to run operations (never {@code null})
+ */
+ public IAtomicOperationExecutor getOperationExecutor(Object context) {
+ IAtomicOperationExecutor result;
+ if(context instanceof IAdaptable) {
+ result = (IAtomicOperationExecutor)((IAdaptable)context).getAdapter(IAtomicOperationExecutor.class);
+ } else if (context != null) {
+ result = (IAtomicOperationExecutor)Platform.getAdapterManager().getAdapter(context, IAtomicOperationExecutor.class);
+ } else {
+ // We can't adapt null, of course, so we will have to settle for the default executor
+ result = null;
+ }
+
+ if (result == null) {
+ result = IAtomicOperationExecutor.DEFAULT;
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries the model element that I edit.
+ *
+ * @return the contextual model element
+ */
+ protected abstract Object getContextElement();
}
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractListEditor.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractListEditor.java index f91c35bdb5e..857a0d72062 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractListEditor.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractListEditor.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,11 +8,14 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.editors;
import org.eclipse.core.databinding.UpdateListStrategy;
import org.eclipse.core.databinding.conversion.IConverter;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.swt.widgets.Composite;
@@ -142,4 +145,10 @@ public abstract class AbstractListEditor extends AbstractEditor { binding = getBindingContext().bindList(widgetObservable, modelProperty, targetToModelStrategy, modelToTargetStrategy);
}
+
+ protected Object getContextElement() {
+ // Our observables for features of EMF objects are expected to implement IObserving because
+ // the observe the value of the object's feature
+ return (modelProperty instanceof IObserving) ? ((IObserving)modelProperty).getObserved() : null;
+ }
}
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractValueEditor.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractValueEditor.java index 503b9a52bf0..150eb611907 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractValueEditor.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/AbstractValueEditor.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.editors;
@@ -15,6 +17,7 @@ import org.eclipse.core.databinding.UpdateValueStrategy; import org.eclipse.core.databinding.conversion.IConverter;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.swt.widgets.Composite;
@@ -172,4 +175,11 @@ public abstract class AbstractValueEditor extends AbstractEditor { * The current value for this editor
*/
public abstract Object getValue();
+
+ @Override
+ protected Object getContextElement() {
+ // Our observables for features of EMF objects are expected to implement IObserving because
+ // the observe the value of the object's feature
+ return (modelProperty instanceof IObserving) ? ((IObserving)modelProperty).getObserved() : null;
+ }
}
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/CompactMultipleValueEditor.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/CompactMultipleValueEditor.java index 44c5728e5cb..97e812c23f2 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/CompactMultipleValueEditor.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/CompactMultipleValueEditor.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.editors;
@@ -229,6 +231,7 @@ public class CompactMultipleValueEditor extends AbstractListEditor implements IC * {@inheritDoc} Handles the event when the edit button is pressed
*/
public void widgetSelected(SelectionEvent e) {
+ dialog.setContextElement(getContextElement());
dialog.setInitialSelections(modelProperty.toArray());
int returnCode = dialog.open();
if(returnCode == Window.CANCEL) {
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueEditor.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueEditor.java index 5a5411df9e2..b0694e00bb4 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueEditor.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueEditor.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.editors;
@@ -18,6 +20,7 @@ import org.eclipse.core.databinding.observable.ChangeEvent; import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
@@ -25,6 +28,7 @@ import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
import org.eclipse.papyrus.infra.widgets.Activator;
import org.eclipse.papyrus.infra.widgets.creation.ReferenceValueFactory;
import org.eclipse.papyrus.infra.widgets.messages.Messages;
@@ -399,45 +403,67 @@ public class MultipleValueEditor extends AbstractListEditor implements Selection * Handle add Action
*/
protected void addAction() {
+ final Object context = getContextElement();
+
if(directCreation) {
if(referenceFactory != null && referenceFactory.canCreateObject()) {
- Object newElement = referenceFactory.createObject(this);
- if(newElement != null) {
- modelProperty.add(newElement);
- commit();
- }
+ getOperationExecutor(context).execute(new Runnable() {
+
+ @Override
+ public void run() {
+ Object newElement = referenceFactory.createObject(MultipleValueEditor.this, context);
+ if(newElement == null) {
+ // Cancel the operation
+ throw new OperationCanceledException();
+ }
+
+ modelProperty.add(newElement);
+ commit();
+ }
+ }, NLS.bind(Messages.MultipleValueEditor_addOperation, labelText));
}
return;
}
- String dialogLabel = label == null ? null : label.getText();
- MultipleValueSelectorDialog dialog = createMultipleValueSelectorDialog(getParent(), selector, ordered, unique, dialogLabel);
- dialog.setLabelProvider((ILabelProvider)treeViewer.getLabelProvider());
- dialog.setFactory(referenceFactory);
- dialog.setUpperBound(upperBound);
-
- if(modelProperty != null) {
- dialog.setInitialSelections(modelProperty.toArray());
- } else {
- dialog.setInitialSelections(new Object[0]);
- }
+ getOperationExecutor(context).execute(new Runnable() {
+
+ @Override
+ public void run() {
+ String dialogLabel = label == null ? null : label.getText();
+ MultipleValueSelectorDialog dialog = createMultipleValueSelectorDialog(getParent(), selector, ordered, unique, dialogLabel);
+ dialog.setLabelProvider((ILabelProvider)treeViewer.getLabelProvider());
+ dialog.setFactory(referenceFactory);
+ dialog.setUpperBound(upperBound);
+ dialog.setContextElement(context);
+
+ if(modelProperty != null) {
+ dialog.setInitialSelections(modelProperty.toArray());
+ } else {
+ dialog.setInitialSelections(new Object[0]);
+ }
- int returnCode = dialog.open();
- if(returnCode == Window.CANCEL) {
- return;
- }
+ int returnCode = dialog.open();
+ if(returnCode == Window.CANCEL) {
+ // Clear out the element selector in case we open this dialog again
+ selector.clearTemporaryElements();
+
+ // Roll back whatever has been done, so far
+ throw new OperationCanceledException();
+ }
- modelProperty.clear();
+ modelProperty.clear();
- Object[] result = dialog.getResult();
- if(result == null) {
- return;
- }
+ Object[] result = dialog.getResult();
+ if(result == null) {
+ return;
+ }
- modelProperty.addAll(Arrays.asList(result));
+ modelProperty.addAll(Arrays.asList(result));
- commit();
+ commit();
+ }
+ }, NLS.bind(Messages.MultipleValueEditor_addOperation, labelText));
}
@Override
@@ -513,19 +539,26 @@ public class MultipleValueEditor extends AbstractListEditor implements Selection TreeItem selectedItem = treeViewer.getTree().getSelection()[0];
Tree parentTree = selectedItem.getParent();
- int index = parentTree.indexOf(selectedItem);
-
- Object currentValue = selection.getFirstElement();
- Object newValue = referenceFactory.edit(this.edit, selection.getFirstElement());
-
- if(newValue != currentValue && newValue != null) {
- modelProperty.remove(index);
- modelProperty.add(index, newValue);
-
- //commit(); // The commit only occurs in the case where we modify the list (We don't commit direct edition on objects)
- }
+ final int index = parentTree.indexOf(selectedItem);
+ final Object currentValue = selection.getFirstElement();
+
+ getOperationExecutor(currentValue).execute(new Runnable() {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void run() {
+ Object newValue = referenceFactory.edit(MultipleValueEditor.this.edit, currentValue);
+
+ if(newValue != currentValue && newValue != null) {
+ modelProperty.remove(index);
+ modelProperty.add(index, newValue);
+
+ //commit(); // The commit only occurs in the case where we modify the list (We don't commit direct edition on objects)
+ }
- commit();
+ commit();
+ }
+ }, NLS.bind(Messages.MultipleValueEditor_editOperation, labelText));
}
/**
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueSelectorDialog.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueSelectorDialog.java index dc5eeecdad0..cd2c84d8b5b 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueSelectorDialog.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueSelectorDialog.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.editors;
@@ -19,6 +21,7 @@ import java.util.LinkedList; import java.util.Set;
import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProvider;
@@ -47,10 +50,15 @@ import org.eclipse.ui.dialogs.SelectionDialog; /**
* Object Chooser. Defines a standard popup for selecting
- * multiple values.
+ * multiple values. If this dialog is used to select or create model
+ * elements to be added to or removed from some element that is being
+ * edited, then it is important to
+ * {@linkplain #setContextElement(Object) set that contextual element}
+ * in this dialog.
*
* @author Camille Letavernier
*
+ * @see #setContextElement(Object)
*/
public class MultipleValueSelectorDialog extends SelectionDialog implements ISelectionChangedListener, IDoubleClickListener, IElementSelectionListener, SelectionListener {
@@ -150,6 +158,11 @@ public class MultipleValueSelectorDialog extends SelectionDialog implements ISel * The factory for creating new elements
*/
protected ReferenceValueFactory factory;
+
+ /**
+ * The model element being edited (if any), to which elements are to be added or removed.
+ */
+ protected Object contextElement;
/**
* The list of newly created objects
@@ -534,7 +547,15 @@ public class MultipleValueSelectorDialog extends SelectionDialog implements ISel return;
}
- Object newObject = factory.createObject(this.create);
+ Object newObject;
+
+ try {
+ newObject = factory.createObject(this.create, contextElement);
+ } catch (OperationCanceledException e) {
+ // The user cancelled and we rolled back pending model changes
+ newObject = null;
+ }
+
if(newObject == null) {
return;
}
@@ -703,6 +724,25 @@ public class MultipleValueSelectorDialog extends SelectionDialog implements ISel this.upperBound = upperBound;
}
+ /**
+ * Sets the optional context of the element that is being edited, in which others will be added and removed.
+ *
+ * @param contextElement
+ * the model element that is being edited
+ */
+ public void setContextElement(Object contextElement) {
+ this.contextElement = contextElement;
+ }
+
+ /**
+ * Queries the optional context of the element that is being edited, in which others will be added and removed.
+ *
+ * @return the model element that is being edited
+ */
+ public Object getContextElement() {
+ return contextElement;
+ }
+
@Override
public boolean close() {
selector.removeElementSelectionListener(this);
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/ReferenceDialog.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/ReferenceDialog.java index 86a70c761e9..84c2234678b 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/ReferenceDialog.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/ReferenceDialog.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.editors;
@@ -16,9 +18,11 @@ import java.util.Collections; import java.util.List;
import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
import org.eclipse.papyrus.infra.widgets.Activator;
import org.eclipse.papyrus.infra.widgets.creation.ReferenceValueFactory;
import org.eclipse.papyrus.infra.widgets.databinding.CLabelObservableValue;
@@ -213,14 +217,22 @@ public class ReferenceDialog extends AbstractValueEditor implements SelectionLis */
protected void createAction() {
if(valueFactory != null && valueFactory.canCreateObject()) {
- Object value = valueFactory.createObject(createInstanceButton);
- if(value == null) {
- return;
- }
- Collection<Object> validatedObjects = valueFactory.validateObjects(Collections.singleton(value));
- if(!validatedObjects.isEmpty()) {
- setValue(validatedObjects.iterator().next());
- }
+ final Object context = getContextElement();
+ getOperationExecutor(context).execute(new Runnable() {
+
+ @Override
+ public void run() {
+ Object value = valueFactory.createObject(createInstanceButton, context);
+ if(value == null) {
+ // Cancel the operation
+ throw new OperationCanceledException();
+ }
+ Collection<Object> validatedObjects = valueFactory.validateObjects(Collections.singleton(value));
+ if(!validatedObjects.isEmpty()) {
+ setValue(validatedObjects.iterator().next());
+ }
+ }
+ }, NLS.bind(Messages.ReferenceDialog_setOperation, labelText));
}
}
@@ -229,13 +241,19 @@ public class ReferenceDialog extends AbstractValueEditor implements SelectionLis * that is currently selected
*/
protected void editAction() {
- Object currentValue = getValue();
+ final Object currentValue = getValue();
if(currentValue != null && valueFactory != null && valueFactory.canEdit()) {
- Object newValue = valueFactory.edit(editInstanceButton, getValue());
- if(newValue != currentValue) {
- setValue(newValue);
- }
- updateLabel();
+ getOperationExecutor(currentValue).execute(new Runnable() {
+
+ @Override
+ public void run() {
+ Object newValue = valueFactory.edit(editInstanceButton, currentValue);
+ if(newValue != currentValue) {
+ setValue(newValue);
+ }
+ updateLabel();
+ }
+ }, NLS.bind(Messages.ReferenceDialog_editOperation, labelText));
}
}
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/messages/Messages.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/messages/Messages.java index 7944870de3e..82dcdde6ce7 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/messages/Messages.java +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/messages/Messages.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.messages;
@@ -32,6 +34,10 @@ public class Messages extends NLS { /** The Multiple value editor_ add elements. */
public static String MultipleValueEditor_AddElements;
+ public static String MultipleValueEditor_addOperation;
+
+ public static String MultipleValueEditor_editOperation;
+
/** The Multiple value editor_ edit selected value */
public static String MultipleValueEditor_EditSelectedValue;
@@ -61,6 +67,8 @@ public class Messages extends NLS { public static String ReferenceDialog_CreateANewObject;
+ public static String ReferenceDialog_editOperation;
+
public static String ReferenceDialog_EditTheCurrentValue;
/** The Reference dialog_ edit value */
@@ -69,6 +77,8 @@ public class Messages extends NLS { /** The Reference dialog_ select value */
public static String ReferenceDialog_SelectValue;
+ public static String ReferenceDialog_setOperation;
+
/** The Reference dialog_ unset */
public static String ReferenceDialog_Unset;
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/messages/messages.properties b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/messages/messages.properties index a5cdb982258..a9fbdf92c68 100644 --- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/messages/messages.properties +++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/messages/messages.properties @@ -1,8 +1,24 @@ -BooleanInputValidator_NotABoolean=The actual entry is not an Boolean.
+###############################################################################
+# Copyright (c) 2010, 2014 CEA LIST and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+# Christian W. Damus (CEA) - bug 402525
+#
+###############################################################################
+
+BooleanInputValidator_NotABoolean=The actual entry is not a Boolean.
IntegerInputValidator_NotAnIntegerMessage=The actual entry is not an Integer.
RealInputValidator_NotaRealMessage=The actual entry is not a Real.
UnlimitedNaturalInputValidator_NotAnUnlimitedNaturalMessage=The actual entry is not an UnlimitedNatural. An UnlimitedNatural must be either -1, * or >= 0
MultipleValueEditor_AddElements=Add elements
+MultipleValueEditor_addOperation=Add {0}
+MultipleValueEditor_editOperation=Edit {0}
MultipleValueEditor_EditSelectedValue=Edit the selected value
MultipleValueEditor_MoveSelectedElementsDown=Move selected elements down
MultipleValueEditor_MoveSelectedElementsUp=Move selected elements up
@@ -13,9 +29,11 @@ MultipleValueSelectorDialog_RemoveAllElements=Remove all elements MultipleValueSelectorDialog_CreateNewElement=Create a new element
MultipleValueSelectorDialog_DeleteNewElement=Deletes a newly created element
ReferenceDialog_CreateANewObject=Create a new object
+ReferenceDialog_editOperation=Edit {0}
ReferenceDialog_EditTheCurrentValue=Edit the current value
ReferenceDialog_EditValue=Edit the reference value
ReferenceDialog_SelectValue=Select the value for this reference
+ReferenceDialog_setOperation=Set {0}
ReferenceDialog_Unset=<Undefined>
ReferenceDialog_UnsetValue=Unset the reference value
ReferenceDialogObservable_Unchanged=<Unchanged>
diff --git a/plugins/sysml/diagram/org.eclipse.papyrus.sysml.diagram.common/src-common-gmf/org/eclipse/papyrus/gmf/diagram/common/edit/policy/DefaultXYLayoutEditPolicy.java b/plugins/sysml/diagram/org.eclipse.papyrus.sysml.diagram.common/src-common-gmf/org/eclipse/papyrus/gmf/diagram/common/edit/policy/DefaultXYLayoutEditPolicy.java index 29bf93747f3..2ad1e4c7118 100644 --- a/plugins/sysml/diagram/org.eclipse.papyrus.sysml.diagram.common/src-common-gmf/org/eclipse/papyrus/gmf/diagram/common/edit/policy/DefaultXYLayoutEditPolicy.java +++ b/plugins/sysml/diagram/org.eclipse.papyrus.sysml.diagram.common/src-common-gmf/org/eclipse/papyrus/gmf/diagram/common/edit/policy/DefaultXYLayoutEditPolicy.java @@ -40,8 +40,6 @@ import org.eclipse.papyrus.infra.gmfdiag.common.editpolicies.XYLayoutWithConstra */ public class DefaultXYLayoutEditPolicy extends XYLayoutWithConstrainedResizedEditPolicy { - protected double spacing = 80; - /** * Called in response to a <tt>REQ_CREATE</tt> request. Returns a command * to set each created element bounds and auto-size properties. @@ -64,33 +62,35 @@ public class DefaultXYLayoutEditPolicy extends XYLayoutWithConstrainedResizedEdi while(iter.hasNext()) { CreateViewRequest.ViewDescriptor viewDescriptor = (CreateViewRequest.ViewDescriptor)iter.next(); Rectangle rect = getBoundsOffest(req, BOUNDS, viewDescriptor); - + //see bug 427129: Figures newly created via the palette should be snapped to grid if "snap to grid" is activated if(couldBeSnaped) { //this code fix the bug in some case... int add = 0; DiagramRootEditPart drep = (DiagramRootEditPart)getHost().getRoot(); double spacing = drep.getGridSpacing(); - final double max_value = spacing*20; + final double max_value = spacing * 20; final SnapToHelper helper = (SnapToHelper)getHost().getAdapter(SnapToHelper.class); - final LayoutHelper layoutHelper = new LayoutHelper(); - while(add < max_value) {//we define a max value to do test - Rectangle LOCAL_BOUNDS = BOUNDS.getCopy(); - LOCAL_BOUNDS.translate(add, add); - Rectangle tmp_rect = getBoundsOffest(req, LOCAL_BOUNDS, viewDescriptor); - final PrecisionRectangle resultRect = new PrecisionRectangle(tmp_rect); - resultRect.setWidth(-1); - resultRect.setHeight(-1); - PrecisionPoint res1 = new PrecisionPoint(tmp_rect.getLocation()); - helper.snapPoint(request, PositionConstants.NORTH_WEST, res1.getPreciseCopy(), res1); - final Point pt = layoutHelper.validatePosition(getHostFigure(), resultRect.setLocation(res1)); - if(couldBeSnaped) { - if(pt.equals(resultRect.getLocation())) { - rect.setLocation(resultRect.getLocation()); - break; - } else { - add +=spacing; - continue; + if(helper != null) { + final LayoutHelper layoutHelper = new LayoutHelper(); + while(add < max_value) {//we define a max value to do test + Rectangle LOCAL_BOUNDS = BOUNDS.getCopy(); + LOCAL_BOUNDS.translate(add, add); + Rectangle tmp_rect = getBoundsOffest(req, LOCAL_BOUNDS, viewDescriptor); + final PrecisionRectangle resultRect = new PrecisionRectangle(tmp_rect); + resultRect.setWidth(-1); + resultRect.setHeight(-1); + PrecisionPoint res1 = new PrecisionPoint(tmp_rect.getLocation()); + helper.snapPoint(request, PositionConstants.NORTH_WEST, res1.getPreciseCopy(), res1); + final Point pt = layoutHelper.validatePosition(getHostFigure(), resultRect.setLocation(res1)); + if(couldBeSnaped) { + if(pt.equals(resultRect.getLocation())) { + rect.setLocation(resultRect.getLocation()); + break; + } else { + add += spacing; + continue; + } } } } diff --git a/plugins/sysml/org.eclipse.papyrus.sysml.service.types/src/org/eclipse/papyrus/sysml/service/types/helper/advice/PropertyEditHelperAdvice.java b/plugins/sysml/org.eclipse.papyrus.sysml.service.types/src/org/eclipse/papyrus/sysml/service/types/helper/advice/PropertyEditHelperAdvice.java index 8b6dda12852..d028b869d48 100644 --- a/plugins/sysml/org.eclipse.papyrus.sysml.service.types/src/org/eclipse/papyrus/sysml/service/types/helper/advice/PropertyEditHelperAdvice.java +++ b/plugins/sysml/org.eclipse.papyrus.sysml.service.types/src/org/eclipse/papyrus/sysml/service/types/helper/advice/PropertyEditHelperAdvice.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011-2012 CEA LIST.
+ * Copyright (c) 2011-2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -9,6 +9,7 @@ * Contributors:
*
* CEA LIST - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.sysml.service.types.helper.advice;
@@ -49,10 +50,12 @@ import org.eclipse.papyrus.sysml.service.types.utils.ConnectorUtils; import org.eclipse.papyrus.uml.diagram.common.util.CrossReferencerUtil;
import org.eclipse.papyrus.uml.service.types.utils.ElementUtil;
import org.eclipse.papyrus.uml.service.types.utils.NamedElementHelper;
+import org.eclipse.papyrus.uml.tools.utils.PackageUtil;
import org.eclipse.swt.widgets.Display;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Connector;
import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Port;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Type;
@@ -195,11 +198,15 @@ public class PropertyEditHelperAdvice extends AbstractEditHelperAdvice { * @return
*/
private ICommand getDestroyAssociatedNestedConnectorCommand(Property property, ICommand command) {
- List<Connector> instancesFilteredByType = org.eclipse.papyrus.uml.tools.utils.ElementUtil.getInstancesFilteredByType(property.getModel(), Connector.class, null);
- List<Connector> connectorToDestroy = ConnectorUtils.filterConnectorByPropertyInNestedConnectorEnd(instancesFilteredByType, (Property)property);
- for(Connector connector : connectorToDestroy) {
- ICommand destroyConnectorCommand = getDestroyConnectorCommand(connector);
- command = CompositeCommand.compose(command, destroyConnectorCommand);
+ Package rootPackage = PackageUtil.getRootPackage(property);
+ // When creating a property in a new-element dialog, it is not attached to the model, yet. So, there will be no need to worry about connectors
+ if(rootPackage != null) {
+ List<Connector> instancesFilteredByType = org.eclipse.papyrus.uml.tools.utils.ElementUtil.getInstancesFilteredByType(rootPackage, Connector.class, null);
+ List<Connector> connectorToDestroy = ConnectorUtils.filterConnectorByPropertyInNestedConnectorEnd(instancesFilteredByType, (Property)property);
+ for(Connector connector : connectorToDestroy) {
+ ICommand destroyConnectorCommand = getDestroyConnectorCommand(connector);
+ command = CompositeCommand.compose(command, destroyConnectorCommand);
+ }
}
return command;
}
diff --git a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.profile/custom-src/org/eclipse/papyrus/uml/diagram/profile/custom/commands/CustomSemanticCreateCommand.java b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.profile/custom-src/org/eclipse/papyrus/uml/diagram/profile/custom/commands/CustomSemanticCreateCommand.java index a317c0e993a..0b7e5758236 100644 --- a/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.profile/custom-src/org/eclipse/papyrus/uml/diagram/profile/custom/commands/CustomSemanticCreateCommand.java +++ b/plugins/uml/diagram/org.eclipse.papyrus.uml.diagram.profile/custom-src/org/eclipse/papyrus/uml/diagram/profile/custom/commands/CustomSemanticCreateCommand.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,15 +9,13 @@ *
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.profile.custom.commands;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -34,7 +32,6 @@ import org.eclipse.gmf.runtime.common.core.command.CompositeCommand; import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
import org.eclipse.gmf.runtime.emf.type.core.requests.SetRequest;
-import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForEObject;
@@ -46,7 +43,6 @@ import org.eclipse.papyrus.uml.diagram.profile.custom.messages.Messages; import org.eclipse.papyrus.uml.diagram.profile.custom.requests.CustomCreateElementRequestAdapter;
import org.eclipse.papyrus.uml.tools.providers.UMLMetaclassContentProvider;
import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
import org.eclipse.uml2.uml.ElementImport;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.PackageableElement;
@@ -125,6 +121,7 @@ public class CustomSemanticCreateCommand extends AbstractTransactionalCommand { // }
// }
final MultipleValueSelectorDialog dialog = new MultipleValueSelectorDialog(Display.getDefault().getActiveShell(), selector, Messages.CustomSemanticCreateCommand_SelectMetaclass, true, false, -1);
+ dialog.setContextElement(profile);
dialog.setLabelProvider(labelProvider);
dialog.setInitialElementSelections(alreadyImportedElement);
diff --git a/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/config/UMLFeatureCellEditorConfig.java b/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/config/UMLFeatureCellEditorConfig.java index a70adb0d6b9..e1d35d290b5 100644 --- a/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/config/UMLFeatureCellEditorConfig.java +++ b/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/config/UMLFeatureCellEditorConfig.java @@ -1,3 +1,16 @@ +/*****************************************************************************
+ * Copyright (c) 2013, 2014 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
+ *****************************************************************************/
package org.eclipse.papyrus.uml.nattable.config;
import org.eclipse.emf.ecore.EClassifier;
@@ -35,7 +48,6 @@ import org.eclipse.papyrus.uml.nattable.editor.MultiReferenceCellEditor; import org.eclipse.papyrus.uml.nattable.editor.MultiStringCellEditor;
import org.eclipse.papyrus.uml.nattable.editor.MultiUnlimitedNaturalCellEditor;
import org.eclipse.papyrus.uml.nattable.editor.SingleReferenceValueCellEditor;
-import org.eclipse.papyrus.uml.nattable.editor.StereotypeApplierCellEditorWrapper;
import org.eclipse.papyrus.uml.nattable.editor.StereotypeApplierDialogCellEditorWrapper;
import org.eclipse.papyrus.uml.nattable.utils.UMLTableUtils;
import org.eclipse.papyrus.uml.nattable.validator.RealDataValidator;
@@ -168,13 +180,11 @@ public class UMLFeatureCellEditorConfig extends EStructuralFeatureEditorConfig { editor = super.getICellEditor(table, axisElement, elementProvider);
break;
}
- // to apply required stereotype before edition
+ // to apply required stereotype before editing in a dialog (which we can reasonably encapsulate in a command)
// see bug 426709: [Table 2][Stereotype] Papyrus Table must allows to edit stereotype properties even if the required stereotypes is not yet applied
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=426709
if(editor instanceof AbstractDialogCellEditor) {
editor = new StereotypeApplierDialogCellEditorWrapper((AbstractDialogCellEditor)editor, axisElement, elementProvider);
- } else if(editor instanceof ICellEditor) {
- editor = new StereotypeApplierCellEditorWrapper(editor, axisElement, elementProvider);
}
return editor;
}
diff --git a/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/dataprovider/UMLStereotypeSingleEnumerationComboBoxDataProvider.java b/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/dataprovider/UMLStereotypeSingleEnumerationComboBoxDataProvider.java index 93b8eb48afb..68f27d1a11d 100644 --- a/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/dataprovider/UMLStereotypeSingleEnumerationComboBoxDataProvider.java +++ b/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/dataprovider/UMLStereotypeSingleEnumerationComboBoxDataProvider.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2014 CEA LIST and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,6 +9,7 @@ *
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.uml.nattable.dataprovider;
@@ -18,8 +19,6 @@ import java.util.List; import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.nebula.widgets.nattable.edit.editor.IComboBoxDataProvider;
import org.eclipse.papyrus.infra.nattable.manager.table.ITableAxisElementProvider;
import org.eclipse.papyrus.infra.nattable.utils.AxisUtils;
@@ -84,12 +83,10 @@ public class UMLStereotypeSingleEnumerationComboBoxDataProvider implements IComb if(modelElement != null) {
final String id = AxisUtils.getPropertyId(this.axisElement);
final Property property = UMLTableUtils.getRealStereotypeProperty(modelElement, id);
- final List<Stereotype> ste = UMLTableUtils.getAppliedStereotypesWithThisProperty(modelElement, id);
+ final List<Stereotype> ste = UMLTableUtils.getApplicableStereotypesWithThisProperty(modelElement, id);
if(ste.size() == 1) {
final Stereotype current = ste.get(0);
- final EObject steAppl = modelElement.getStereotypeApplication(current);
- final EStructuralFeature feature = steAppl.eClass().getEStructuralFeature(property.getName());
- final EEnum eenum = (EEnum)feature.getEType();
+ final EEnum eenum = (EEnum)current.getProfile().getDefinition(property.getType());
for(final EEnumLiteral instances : eenum.getELiterals()) {
literals.add(instances.getInstance());
}
diff --git a/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/editor/AbstractUMLMultiValueCellEditor.java b/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/editor/AbstractUMLMultiValueCellEditor.java index 663d4a014ee..5f85ce1f968 100644 --- a/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/editor/AbstractUMLMultiValueCellEditor.java +++ b/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/editor/AbstractUMLMultiValueCellEditor.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 CEA LIST and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,6 +9,7 @@ *
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.uml.nattable.editor;
@@ -167,6 +168,7 @@ public abstract class AbstractUMLMultiValueCellEditor extends AbstractDialogCell }
};
+ dialog.setContextElement(realEditedObject);
dialog.setLabelProvider(new UMLLabelProvider());
if(value != null && value instanceof Collection) {
Collection<?> coll = (Collection<?>)value;
diff --git a/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/editor/StereotypeApplierCellEditorWrapper.java b/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/editor/StereotypeApplierCellEditorWrapper.java index c7871b0a79a..92fb2474b5b 100644 --- a/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/editor/StereotypeApplierCellEditorWrapper.java +++ b/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/editor/StereotypeApplierCellEditorWrapper.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2014 CEA LIST.
+ * Copyright (c) 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -9,6 +9,7 @@ * Contributors:
*
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.uml.nattable.editor;
diff --git a/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/manager/cell/StereotypePropertyCellManager.java b/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/manager/cell/StereotypePropertyCellManager.java index df1a74c8e4d..d9ec5e502d9 100644 --- a/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/manager/cell/StereotypePropertyCellManager.java +++ b/plugins/uml/nattable/org.eclipse.papyrus.uml.nattable/src/org/eclipse/papyrus/uml/nattable/manager/cell/StereotypePropertyCellManager.java @@ -1,6 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
- *
+ * Copyright (c) 2012, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -9,6 +8,7 @@ *
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
*
*****************************************************************************/
package org.eclipse.papyrus.uml.nattable.manager.cell;
@@ -20,11 +20,13 @@ import java.util.List; import java.util.Map;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.osgi.util.NLS;
@@ -41,6 +43,7 @@ import org.eclipse.papyrus.uml.nattable.messages.Messages; import org.eclipse.papyrus.uml.nattable.paste.StereotypeApplicationStructure;
import org.eclipse.papyrus.uml.nattable.utils.Constants;
import org.eclipse.papyrus.uml.nattable.utils.UMLTableUtils;
+import org.eclipse.papyrus.uml.tools.commands.ApplyStereotypeCommand;
import org.eclipse.papyrus.uml.tools.utils.EnumerationUtil;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Enumeration;
@@ -192,6 +195,27 @@ public class StereotypePropertyCellManager extends UMLFeatureCellManager { final Property prop = UMLTableUtils.getRealStereotypeProperty(el, id);
final List<Stereotype> stereotypes = UMLTableUtils.getAppliedStereotypesWithThisProperty(el, id);
if(prop != null) {
+ if (stereotypes.isEmpty()) {
+ // Must first apply the stereotype
+ return new RecordingCommand(domain, "Set Value") {
+
+ @Override
+ protected void doExecute() {
+ if (!applyRequiredStereotype(domain, el, id)) {
+ throw new OperationCanceledException();
+ } else {
+ // Now recursively execute the set-string-value command
+ Command command = getSetValueCommand(domain, columnElement, rowElement, newValue, tableManager);
+ if (command == null || !command.canExecute()) {
+ throw new OperationCanceledException();
+ } else {
+ domain.getCommandStack().execute(command);
+ }
+ }
+ }
+ };
+ }
+
if(stereotypes.size() == 1) {
final EObject stereotypeApplication = el.getStereotypeApplication(stereotypes.get(0));
final EStructuralFeature steApFeature = stereotypeApplication.eClass().getEStructuralFeature(prop.getName());
@@ -226,6 +250,27 @@ public class StereotypePropertyCellManager extends UMLFeatureCellManager { EObject stereotypeApplication = null;
EStructuralFeature steApFeature = null;
if(prop != null) {
+ if (stereotypes.isEmpty()) {
+ // Must first apply the stereotype
+ return new RecordingCommand(domain, "Set Value") {
+
+ @Override
+ protected void doExecute() {
+ if (!applyRequiredStereotype(domain, el, id)) {
+ throw new OperationCanceledException();
+ } else {
+ // Now recursively execute the set-string-value command
+ Command command = getSetStringValueCommand(domain, columnElement, rowElement, newValue, valueSolver, tableManager);
+ if (command == null || !command.canExecute()) {
+ throw new OperationCanceledException();
+ } else {
+ domain.getCommandStack().execute(command);
+ }
+ }
+ }
+ };
+ }
+
if(stereotypes.size() == 1) {
stereotypeApplication = el.getStereotypeApplication(stereotypes.get(0));
switch(UMLTableUtils.getAppliedStereotypesWithThisProperty(el, id).size()) {
@@ -369,4 +414,24 @@ public class StereotypePropertyCellManager extends UMLFeatureCellManager { createStringResolutionProblem(tableManager, columnElement, rowElement, valueAsString, solvedValue, sharedMap);
}
+
+ /**
+ *
+ * @param el
+ * an element of the model
+ * @param propertyId
+ * the id of the edited property
+ * @return <code>true</code> if a stereotype has been applied
+ */
+ private static boolean applyRequiredStereotype(TransactionalEditingDomain domain, final Element el, final String propertyId) {
+ if(UMLTableUtils.getAppliedStereotypesWithThisProperty(el, propertyId).size() == 0) {
+ final List<Stereotype> stereotypesList = UMLTableUtils.getApplicableStereotypesWithThisProperty(el, propertyId);
+ if(stereotypesList.size() == 1) {
+ final ApplyStereotypeCommand applyCommand = new ApplyStereotypeCommand(el, stereotypesList.get(0), domain);
+ domain.getCommandStack().execute(applyCommand);
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/creation/ExpressionLanguageFactory.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/creation/ExpressionLanguageFactory.java index 81733dab260..b26c5153e5a 100644 --- a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/creation/ExpressionLanguageFactory.java +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/creation/ExpressionLanguageFactory.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.properties.creation;
@@ -85,8 +87,8 @@ public class ExpressionLanguageFactory extends StringEditionFactory { }
@Override
- public Object createObject(Control widget) {
- String languageName = (String)super.createObject(widget);
+ public Object createObject(Control widget, Object context) {
+ String languageName = (String)super.createObject(widget, context);
if(languageName == null) {
return null;
}
diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/creation/MessageValueSpecificationFactory.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/creation/MessageValueSpecificationFactory.java index 9dd2731de73..070f4417d43 100644 --- a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/creation/MessageValueSpecificationFactory.java +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/creation/MessageValueSpecificationFactory.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.properties.creation;
@@ -92,11 +94,8 @@ public class MessageValueSpecificationFactory extends EcorePropertyEditorFactory return result;
}
- /**
- * {@inheritDoc}
- */
@Override
- public Object createObject(Control widget) {
+ protected Object doCreateObject(Control widget, Object context) {
EClass eClass = chooseEClass(widget);
if(eClass == null) {
return null;
@@ -114,7 +113,7 @@ public class MessageValueSpecificationFactory extends EcorePropertyEditorFactory }
}
- return super.createObject(widget, instance);
+ return createObject(widget, context, instance);
}
/**
diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/databinding/StereotypeAppearanceObservableValue.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/databinding/StereotypeAppearanceObservableValue.java index ce3d31856d4..f70c0403b32 100644 --- a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/databinding/StereotypeAppearanceObservableValue.java +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/databinding/StereotypeAppearanceObservableValue.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.properties.databinding;
@@ -22,6 +24,7 @@ import static org.eclipse.papyrus.uml.properties.util.StereotypeAppearanceConsta import static org.eclipse.papyrus.uml.properties.util.StereotypeAppearanceConstants.VERTICAL;
import org.eclipse.core.databinding.observable.Diffs;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.core.internal.databinding.Util;
import org.eclipse.emf.common.notify.Adapter;
@@ -44,7 +47,7 @@ import org.eclipse.uml2.uml.Stereotype; *
* @author Camille Letavernier
*/
-public class StereotypeAppearanceObservableValue extends AbstractObservableValue {
+public class StereotypeAppearanceObservableValue extends AbstractObservableValue implements IObserving {
/**
* The name of the property being observed
@@ -270,11 +273,14 @@ public class StereotypeAppearanceObservableValue extends AbstractObservableValue domain.getCommandStack().execute(command);
}
+ public Object getObserved() {
+ return diagramElement;
+ }
+
/**
* @see org.eclipse.core.databinding.observable.AbstractObservable#dispose()
*
*/
-
@Override
public synchronized void dispose() {
if(diagramElement != null && diagramElementListener != null) {
diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/databinding/StereotypeApplicationObservableList.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/databinding/StereotypeApplicationObservableList.java index 49e65474e3a..78b252087ad 100644 --- a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/databinding/StereotypeApplicationObservableList.java +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/databinding/StereotypeApplicationObservableList.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.properties.databinding;
@@ -15,6 +17,7 @@ import java.util.Collection; import java.util.LinkedList;
import java.util.List;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.list.ListDiff;
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
import org.eclipse.core.databinding.observable.list.WritableList;
@@ -38,7 +41,7 @@ import org.eclipse.uml2.uml.Stereotype; *
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
-public class StereotypeApplicationObservableList extends WritableList implements ICommitListener {
+public class StereotypeApplicationObservableList extends WritableList implements ICommitListener, IObserving {
private Element umlSource;
@@ -279,6 +282,10 @@ public class StereotypeApplicationObservableList extends WritableList implements throw new UnsupportedOperationException();
}
+ public Object getObserved() {
+ return umlSource;
+ }
+
@Override
public void dispose() {
super.dispose();
diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/expression/ExpressionList.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/expression/ExpressionList.java index 0ff668e7adf..774df66875e 100644 --- a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/expression/ExpressionList.java +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/expression/ExpressionList.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.properties.expression;
@@ -17,6 +19,7 @@ import java.util.List; import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.papyrus.infra.widgets.editors.AbstractEditor;
@@ -36,7 +39,7 @@ import org.eclipse.papyrus.infra.widgets.editors.ICommitListener; *
* @author Camille Letavernier
*/
-public class ExpressionList extends WritableList implements IChangeListener, ICommitListener {
+public class ExpressionList extends WritableList implements IChangeListener, ICommitListener, IObserving {
private List<Expression> expressions;
@@ -165,6 +168,13 @@ public class ExpressionList extends WritableList implements IChangeListener, ICo languages.add(language);
}
+
+ public Object getObserved() {
+ return //
+ (languages instanceof IObserving) ? ((IObserving)languages).getObserved() : //
+ (bodies instanceof IObserving) ? ((IObserving)bodies).getObserved() : //
+ null;
+ }
/**
* A helper class to aggregate the expression body and language in a single
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/PackageUtil.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/PackageUtil.java index 81ce8faf333..f8f000c683d 100644 --- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/PackageUtil.java +++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/PackageUtil.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2008, 2009 CEA LIST. + * Copyright (c) 2008, 2014 CEA LIST and others. * * * All rights reserved. This program and the accompanying materials @@ -10,6 +10,7 @@ * Contributors: * Remi SCHNEKENBURGER (CEA LIST) Remi.schnekenburger@cea.fr - Initial API and implementation * Yann TANGUY (CEA LIST) yann.tanguy@cea.fr + * Christian W. Damus (CEA) - bug 402525 * *****************************************************************************/ package org.eclipse.papyrus.uml.tools.utils; @@ -138,7 +139,8 @@ public class PackageUtil { * @return the top {@link Package} for the specified element */ public static Package getRootPackage(Element element) { - return getRootPackage(element.getNearestPackage()); + Package nearest = element.getNearestPackage(); + return (nearest == null) ? null : getRootPackage(nearest); } /** diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ExtensionRequiredObservableValue.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ExtensionRequiredObservableValue.java index cfab0f2c6aa..01385fa79f0 100644 --- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ExtensionRequiredObservableValue.java +++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ExtensionRequiredObservableValue.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 CEA LIST and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,12 +9,14 @@ *
* Contributors:
* Camille Letavernier (camille.letavernier@cea.fr) - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
*
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.databinding;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.core.databinding.observable.value.ValueDiff;
import org.eclipse.emf.edit.domain.EditingDomain;
@@ -29,7 +31,7 @@ import org.eclipse.uml2.uml.Extension; * @author Camille Letavernier
*
*/
-public class ExtensionRequiredObservableValue extends AbstractObservableValue implements IChangeListener {
+public class ExtensionRequiredObservableValue extends AbstractObservableValue implements IChangeListener, IObserving {
private Extension extension;
@@ -70,6 +72,10 @@ public class ExtensionRequiredObservableValue extends AbstractObservableValue im observable.setValue(required ? MultiplicityParser.ONE : MultiplicityParser.OPTIONAL);
currentValue = required;
}
+
+ public Object getObserved() {
+ return extension;
+ }
@Override
public void dispose() {
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageExpressionObservableValue.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageExpressionObservableValue.java index ddba5d70bd4..6f7fff680d0 100644 --- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageExpressionObservableValue.java +++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageExpressionObservableValue.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,9 +8,12 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.databinding;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.edit.domain.EditingDomain;
@@ -23,7 +26,7 @@ import org.eclipse.uml2.uml.Image; *
* @author Camille Letavernier
*/
-public class ImageExpressionObservableValue extends AbstractObservableValue {
+public class ImageExpressionObservableValue extends AbstractObservableValue implements IObserving {
private Image image;
@@ -70,4 +73,7 @@ public class ImageExpressionObservableValue extends AbstractObservableValue { }
}
+ public Object getObserved() {
+ return image;
+ }
}
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageKindObservableValue.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageKindObservableValue.java index 45db2817a2c..6957029ef32 100644 --- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageKindObservableValue.java +++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageKindObservableValue.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,9 +8,12 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.databinding;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.edit.domain.EditingDomain;
@@ -25,7 +28,7 @@ import org.eclipse.uml2.uml.Image; * @author Camille Letavernier
*
*/
-public class ImageKindObservableValue extends AbstractObservableValue {
+public class ImageKindObservableValue extends AbstractObservableValue implements IObserving {
/**
* The kind of image display
@@ -95,4 +98,7 @@ public class ImageKindObservableValue extends AbstractObservableValue { }
}
+ public Object getObserved() {
+ return image;
+ }
}
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageNameObservableValue.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageNameObservableValue.java index 2b355c02960..7af527ad018 100644 --- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageNameObservableValue.java +++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ImageNameObservableValue.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,9 +8,12 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.databinding;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.edit.domain.EditingDomain;
@@ -23,7 +26,7 @@ import org.eclipse.uml2.uml.Image; *
* @author Camille Letavernier
*/
-public class ImageNameObservableValue extends AbstractObservableValue {
+public class ImageNameObservableValue extends AbstractObservableValue implements IObserving {
private Image image;
@@ -70,4 +73,7 @@ public class ImageNameObservableValue extends AbstractObservableValue { }
}
+ public Object getObserved() {
+ return image;
+ }
}
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/MultiplicityObservableValue.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/MultiplicityObservableValue.java index 9303602b5ce..e62380f34b5 100644 --- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/MultiplicityObservableValue.java +++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/MultiplicityObservableValue.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,12 +8,15 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.databinding;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.IObservable;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.ValueDiff;
@@ -40,7 +43,7 @@ import org.eclipse.uml2.uml.UMLPackage; *
* @author Camille Letavernier
*/
-public class MultiplicityObservableValue extends AbstractObservableValue implements IChangeListener, CommandBasedObservableValue, AggregatedObservable {
+public class MultiplicityObservableValue extends AbstractObservableValue implements IChangeListener, CommandBasedObservableValue, AggregatedObservable, IObserving {
private IObservableValue lowerBound, upperBound, lowerValue, upperValue, lowerValueSpecification, upperValueSpecification;
@@ -135,6 +138,10 @@ public class MultiplicityObservableValue extends AbstractObservableValue impleme }
}
+ public Object getObserved() {
+ return eObject;
+ }
+
@Override
public synchronized void dispose() {
lowerValue.removeChangeListener(this);
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/NavigationObservableValue.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/NavigationObservableValue.java index d2fff73971a..f2308f0b186 100644 --- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/NavigationObservableValue.java +++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/NavigationObservableValue.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.databinding;
@@ -19,6 +21,7 @@ import org.eclipse.core.databinding.observable.ChangeEvent; import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.IObservable;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.emf.common.command.Command;
@@ -45,7 +48,7 @@ import org.eclipse.uml2.uml.UMLPackage; *
* @author Camille Letavernier
*/
-public class NavigationObservableValue extends AbstractObservableValue implements IChangeListener, CommandBasedObservableValue, AggregatedObservable {
+public class NavigationObservableValue extends AbstractObservableValue implements IChangeListener, CommandBasedObservableValue, AggregatedObservable, IObserving {
private Property memberEnd;
@@ -89,6 +92,10 @@ public class NavigationObservableValue extends AbstractObservableValue implement Command command = getCommand(value);
domain.getCommandStack().execute(command);
}
+
+ public Object getObserved() {
+ return memberEnd;
+ }
@Override
public synchronized void dispose() {
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/OwnerObservableValue.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/OwnerObservableValue.java index 7c8dea6a61b..1fab72a0498 100644 --- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/OwnerObservableValue.java +++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/OwnerObservableValue.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.databinding;
@@ -18,6 +20,7 @@ import org.eclipse.core.databinding.observable.ChangeEvent; import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.IObservable;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
import org.eclipse.emf.common.command.Command;
@@ -57,7 +60,7 @@ import org.eclipse.uml2.uml.UMLPackage; *
* @author Camille Letavernier
*/
-public class OwnerObservableValue extends AbstractObservableValue implements IChangeListener, AggregatedObservable, CommandBasedObservableValue {
+public class OwnerObservableValue extends AbstractObservableValue implements IChangeListener, AggregatedObservable, CommandBasedObservableValue, IObserving {
private Property memberEnd;
@@ -111,6 +114,10 @@ public class OwnerObservableValue extends AbstractObservableValue implements ICh domain.getCommandStack().execute(command);
}
+ public Object getObserved() {
+ return memberEnd;
+ }
+
@Override
public synchronized void dispose() {
super.dispose();
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ProfileApplicationObservableList.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ProfileApplicationObservableList.java index 6f24f4c45bf..56b221f3d5e 100644 --- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ProfileApplicationObservableList.java +++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ProfileApplicationObservableList.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.databinding;
@@ -15,6 +17,7 @@ import java.util.Collection; import java.util.LinkedList;
import java.util.List;
+import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.list.ListDiff;
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
import org.eclipse.core.databinding.observable.list.WritableList;
@@ -37,7 +40,7 @@ import org.eclipse.uml2.uml.Profile; * @author Camille Letavernier
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
-public class ProfileApplicationObservableList extends WritableList implements ICommitListener {
+public class ProfileApplicationObservableList extends WritableList implements ICommitListener, IObserving {
private Package umlSource;
@@ -124,6 +127,10 @@ public class ProfileApplicationObservableList extends WritableList implements IC };
}
+ public Object getObserved() {
+ return umlSource;
+ }
+
@Override
public synchronized void dispose() {
super.dispose();
diff --git a/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/creation/EcorePropertyEditorFactory.java b/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/creation/EcorePropertyEditorFactory.java index f9da5ab4928..e17e7831e6b 100644 --- a/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/creation/EcorePropertyEditorFactory.java +++ b/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/creation/EcorePropertyEditorFactory.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.views.properties.creation;
@@ -16,17 +18,23 @@ import java.util.Collections; import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.window.Window;
+import org.eclipse.papyrus.infra.emf.dialog.NestedEditingDialogContext;
import org.eclipse.papyrus.infra.emf.utils.EClassNameComparator;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.infra.widgets.providers.IStaticContentProvider;
import org.eclipse.papyrus.views.properties.Activator;
+import org.eclipse.papyrus.views.properties.contexts.View;
import org.eclipse.papyrus.views.properties.messages.Messages;
import org.eclipse.papyrus.views.properties.providers.CreateInFeatureContentProvider;
import org.eclipse.swt.SWT;
@@ -185,17 +193,67 @@ public class EcorePropertyEditorFactory extends PropertyEditorFactory { * {@inheritDoc}
*/
@Override
- public Object createObject(Control widget) {
+ public final Object createObject(Control widget, Object context) {
+ Object result;
+
+ final ResourceSet previous = NestedEditingDialogContext.getInstance().push(context);
+
+ try {
+ result = doCreateObject(widget, context);
+ } finally {
+ NestedEditingDialogContext.getInstance().pop(previous);
+ }
+
+ return result;
+ }
+
+ protected Object doCreateObject(Control widget, Object context) {
Object instance;
+
if(referenceIn.isContainment()) {
instance = simpleCreateObject(widget);
} else {
instance = createObjectInDifferentContainer(widget);
}
- return super.createObject(widget, instance);
+ return createObject(widget, context, instance);
}
+ @Override
+ protected Object doEdit(final Control widget, final Object source, final Set<View> views, final String dialogTitle) {
+ Object result;
+
+ try {
+ NestedEditingDialogContext.getInstance().enter();
+ try {
+ result = getOperationExecutor(source).execute(new Callable<Object>() {
+ public Object call() throws Exception {
+ return basicDoEdit(widget, source, views, dialogTitle);
+ }
+ }, dialogTitle);
+ } finally {
+ NestedEditingDialogContext.getInstance().exit();
+ }
+ } catch (OperationCanceledException e) {
+ if(!NestedEditingDialogContext.getInstance().isNested()) {
+ // Propagate to the caller if not in a nested edit dialog
+ throw e;
+ }
+ result = null;
+ }
+
+ return result;
+ }
+
+ protected final Object basicDoEdit(Control widget, Object source, Set<View> views, String dialogTitle) {
+ return super.doEdit(widget, source, views, dialogTitle);
+ }
+
+ @Override
+ protected void handleEditCancelled(Control widget, Object source) {
+ throw new OperationCanceledException();
+ }
+
protected EObject simpleCreateObject(Control widget) {
EClass eClass = chooseEClass(widget);
if(eClass == null) {
@@ -212,7 +270,14 @@ public class EcorePropertyEditorFactory extends PropertyEditorFactory { return null;
}
- containerContentProvider.inputChanged(null, null, instance);
+ // Try to get the current resource set for a wide scope of places to put a new element
+ Object containerInput = NestedEditingDialogContext.getInstance().getResourceSet();
+ if (containerInput == null) {
+ // Only have the object that we've created for context
+ containerInput = instance;
+ }
+
+ containerContentProvider.inputChanged(null, null, containerInput);
referenceContentProvider.setType(instance.eClass());
CreateInDialog dialog = new CreateInDialog(widget.getShell(), instance);
dialog.setProviders(containerContentProvider, referenceContentProvider, containerLabelProvider, referenceLabelProvider);
diff --git a/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/creation/PropertyEditorFactory.java b/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/creation/PropertyEditorFactory.java index 4e86109ca2b..93eb38b7ef1 100644 --- a/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/creation/PropertyEditorFactory.java +++ b/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/creation/PropertyEditorFactory.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,15 +8,20 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.views.properties.creation;
import java.util.Collection;
import java.util.Set;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
+import org.eclipse.papyrus.infra.widgets.creation.IAtomicOperationExecutor;
import org.eclipse.papyrus.infra.widgets.creation.ReferenceValueFactory;
import org.eclipse.papyrus.views.properties.contexts.View;
import org.eclipse.papyrus.views.properties.messages.Messages;
@@ -51,15 +56,18 @@ public class PropertyEditorFactory implements ReferenceValueFactory { * Return a null value. Implementors should override when object creation
* needs to be supported. Implementors may rely on {@link #createObject(Control, Object)}
*
- * @see org.eclipse.papyrus.infra.widgets.creation.ReferenceValueFactory#createObject(org.eclipse.swt.widgets.Control)
- * @see #createObject(org.eclipse.swt.widgets.Control, Object)
- *
* @param widget
* The widget from which this method is called. May be used to retrieve the current shell
+ * @param context
+ * The object being edited, in which context the new object is to be created and which will as a result have a reference to the new object.
+ * If there is no context object (creation of a free-floating object) or it cannot be determined, this may be {@code null}
* @return
* The newly created object
+ *
+ * @see ReferenceValueFactory#createObject(Control, Object)
+ * @see #createObject(Control, Object, Object)
*/
- public Object createObject(Control widget) {
+ public Object createObject(Control widget, Object context) {
return null;
}
@@ -72,12 +80,15 @@ public class PropertyEditorFactory implements ReferenceValueFactory { *
* @param widget
* The widget used to open the dialog
+ * @param context
+ * The object being edited, in which context the new object is to be created and which will as a result have a reference to the new object.
+ * If there is no context object (creation of a free-floating object) or it cannot be determined, this may be {@code null}
* @param source
* The created EObject. If null, nothing will happen
* @return
* The source EObject, which potential in-place modifications
*/
- protected Object createObject(Control widget, Object source) {
+ protected Object createObject(Control widget, Object context, Object source) {
if(source == null) {
return null;
}
@@ -87,15 +98,7 @@ public class PropertyEditorFactory implements ReferenceValueFactory { ViewConstraintEngine constraintEngine = ConfigurationManager.getInstance().getConstraintEngine();
Set<View> views = constraintEngine.getViews(selection);
if(!views.isEmpty()) {
- EditionDialog dialog = new EditionDialog(widget.getShell(), true);
- dialog.setViews(views);
- dialog.setInput(source);
- dialog.setTitle(getCreationDialogTitle());
-
- int result = dialog.open();
- if(result != Window.OK) {
- return null;
- }
+ return doEdit(widget, source, views, getCreationDialogTitle());
}
return source;
@@ -134,17 +137,30 @@ public class PropertyEditorFactory implements ReferenceValueFactory { Set<View> views = constraintEngine.getViews(selection);
if(!views.isEmpty()) {
- EditionDialog dialog = new EditionDialog(widget.getShell());
- dialog.setTitle(getEditionDialogTitle(source));
- dialog.setViews(views);
- dialog.setInput(source);
-
- dialog.open();
+ return doEdit(widget, source, views, getEditionDialogTitle(source));
}
return source;
}
+ protected Object doEdit(Control widget, Object source, Set<View> views, String dialogTitle) {
+ EditionDialog dialog = new EditionDialog(widget.getShell(), true);
+ dialog.setTitle(dialogTitle);
+ dialog.setViews(views);
+ dialog.setInput(source);
+
+ if (dialog.open() != Window.OK) {
+ handleEditCancelled(widget, source);
+ return null;
+ }
+
+ return source;
+ }
+
+ protected void handleEditCancelled(Control widget, Object source) {
+ // Pass
+ }
+
/**
* The standard Property Editor Factory cannot instantiate new objects.
* However, subclasses may override this method to return true if they
@@ -173,4 +189,25 @@ public class PropertyEditorFactory implements ReferenceValueFactory { public String getEditionDialogTitle(Object objectToEdit) {
return "Edit an element";
}
+
+ /**
+ * Obtains the most appropriate operation executor for the object being edited.
+ *
+ * @param context the object being edited
+ * @return the executor to use to run operations (never {@code null})
+ */
+ public IAtomicOperationExecutor getOperationExecutor(Object context) {
+ IAtomicOperationExecutor result;
+ if(context instanceof IAdaptable) {
+ result = (IAtomicOperationExecutor)((IAdaptable)context).getAdapter(IAtomicOperationExecutor.class);
+ } else {
+ result = (IAtomicOperationExecutor)Platform.getAdapterManager().getAdapter(context, IAtomicOperationExecutor.class);
+ }
+
+ if (result == null) {
+ result = IAtomicOperationExecutor.DEFAULT;
+ }
+
+ return result;
+ }
}
diff --git a/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/modelelement/EMFModelElement.java b/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/modelelement/EMFModelElement.java index cf40594c4ef..ed4cfe5f47c 100644 --- a/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/modelelement/EMFModelElement.java +++ b/plugins/views/properties/org.eclipse.papyrus.views.properties/src/org/eclipse/papyrus/views/properties/modelelement/EMFModelElement.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@ *
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.views.properties.modelelement;
@@ -27,10 +29,12 @@ import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.emf.databinding.EMFObservableList;
import org.eclipse.papyrus.infra.emf.databinding.EMFObservableValue;
+import org.eclipse.papyrus.infra.emf.dialog.NestedEditingDialogContext;
import org.eclipse.papyrus.infra.emf.providers.EMFContentProvider;
import org.eclipse.papyrus.infra.emf.providers.EMFLabelProvider;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForEObject;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceSet;
import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
import org.eclipse.papyrus.infra.widgets.creation.ReferenceValueFactory;
import org.eclipse.papyrus.infra.widgets.providers.IStaticContentProvider;
@@ -199,7 +203,10 @@ public class EMFModelElement extends AbstractModelElement { @Override
public ILabelProvider getLabelProvider(String propertyPath) {
try {
- return ServiceUtilsForEObject.getInstance().getServiceRegistry(source).getService(LabelProviderService.class).getLabelProvider();
+ LabelProviderService lpSvc = (source.eResource() != null) //
+ ? ServiceUtilsForEObject.getInstance().getService(LabelProviderService.class, source) //
+ : ServiceUtilsForResourceSet.getInstance().getService(LabelProviderService.class, NestedEditingDialogContext.getInstance().getResourceSet());
+ return lpSvc.getLabelProvider();
} catch (ServiceException ex) {
Activator.log.error(ex);
return new EMFLabelProvider();
diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.infra.core.tests/test/org/eclipse/papyrus/infra/core/resource/Bug402525.ecore b/tests/junit/plugins/core/org.eclipse.papyrus.infra.core.tests/test/org/eclipse/papyrus/infra/core/resource/Bug402525.ecore new file mode 100644 index 00000000000..8dea18de3e8 --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.infra.core.tests/test/org/eclipse/papyrus/infra/core/resource/Bug402525.ecore @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="bug402525" nsURI="http://www.eclipse.org/schema/Papyrus/tests/bug402525" + nsPrefix="bug"> + <eClassifiers xsi:type="ecore:EClass" name="Foo"/> +</ecore:EPackage> diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.infra.core.tests/test/org/eclipse/papyrus/infra/core/resource/NestingTransactionalCommandStackTest.java b/tests/junit/plugins/core/org.eclipse.papyrus.infra.core.tests/test/org/eclipse/papyrus/infra/core/resource/NestingTransactionalCommandStackTest.java new file mode 100644 index 00000000000..c64b9923fb7 --- /dev/null +++ b/tests/junit/plugins/core/org.eclipse.papyrus.infra.core.tests/test/org/eclipse/papyrus/infra/core/resource/NestingTransactionalCommandStackTest.java @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.infra.core.resource; + +import static org.hamcrest.CoreMatchers.both; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; + +import java.net.URL; +import java.util.concurrent.Callable; + +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.command.CommandStack; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EcoreFactory; +import org.eclipse.emf.ecore.EcorePackage; +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.edit.provider.ComposedAdapterFactory; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalCommandStack; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.base.Objects; + + +/** + * Test suite for the {@link NestingTransactionalCommandStack} class. + */ +public class NestingTransactionalCommandStackTest { + + // No API signatures but the most basic are required for nesting + private CommandStack fixture; + + private TransactionalEditingDomain domain; + + private ResourceSet rset; + + private EPackage testPackage; + + private EClass foo; + + public NestingTransactionalCommandStackTest() { + super(); + } + + // + // Test cases + // + + @Test + public void testCompleteUnnestedCommand() { + Callable<EAttribute> createAttribute = createAttribute(); + + int oldFeatureCount = foo.getEStructuralFeatures().size(); + + // Create two attributes + EAttribute attr1 = execute(createAttribute); + EAttribute attr2 = execute(createAttribute); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount + 2)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr1)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr2)); + + // Undo only undoes one of them + Command undone = undo(); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount + 1)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr1)); + assertThat(foo.getEStructuralFeatures(), not(hasItem(attr2))); + + // Redo is sane + Command redone = redo(); + assertThat(redone, sameInstance(undone)); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount + 2)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr1)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr2)); + } + + @Test + public void testCancelUnnestedCommand() { + Callable<EAttribute> createAttribute = createAttribute(2); + + int oldFeatureCount = foo.getEStructuralFeatures().size(); + + // Try to create two attributes (second one cancels) + EAttribute attr1 = execute(createAttribute); + EAttribute attr2 = execute(createAttribute); + assertThat(attr2, nullValue()); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount + 1)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr1)); + assertThat(foo.getEStructuralFeature("attribute2"), nullValue()); //$NON-NLS-1$ + + // Undo is sane + Command undone = undo(); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount)); + assertThat(foo.getEStructuralFeatures(), not(hasItem(attr1))); + assertThat(foo.getEStructuralFeature("attribute2"), nullValue()); //$NON-NLS-1$ + + // Redo is sane + Command redone = redo(); + assertThat(redone, sameInstance(undone)); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount + 1)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr1)); + assertThat(foo.getEStructuralFeature("attribute2"), nullValue()); //$NON-NLS-1$ + } + + @Test + public void testCompleteNestedCommand() { + final int FEATURES = 2; + Callable<EClass> createClass = createClass(FEATURES); + + int oldClassifierCount = testPackage.getEClassifiers().size(); + + EClass clas = execute(createClass); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount + 1)); + assertThat(testPackage.getEClassifiers(), hasItem(clas)); + assertThat(clas.getEStructuralFeatures().size(), is(FEATURES)); + assertThat(clas.getEStructuralFeature("attribute1"), notNullValue()); //$NON-NLS-1$ + assertThat(clas.getEStructuralFeature("attribute2"), notNullValue()); //$NON-NLS-1$ + + // Undo is sane and there is only one command to undo + Command undone = undo(); + assertThat(fixture.canUndo(), is(false)); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount)); + assertThat(testPackage.getEClassifiers(), not(hasItem(clas))); + + // Redo is sane + Command redone = redo(); + assertThat(redone, sameInstance(undone)); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount + 1)); + assertThat(testPackage.getEClassifiers(), hasItem(clas)); + assertThat(clas.getEStructuralFeatures().size(), is(FEATURES)); + assertThat(clas.getEStructuralFeature("attribute1"), notNullValue()); //$NON-NLS-1$ + assertThat(clas.getEStructuralFeature("attribute2"), notNullValue()); //$NON-NLS-1$ + } + + @Test + public void testCancelNestedCommand() { + final int FEATURES = 2; + Callable<EClass> createClass = createClass(FEATURES, 2, FEATURES); + + int oldClassifierCount = testPackage.getEClassifiers().size(); + + // Try to create two classes (second one cancels) + EClass class1 = execute(createClass); + EClass class2 = execute(createClass); + assertThat(class2, nullValue()); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount + 1)); + assertThat(testPackage.getEClassifiers(), hasItem(class1)); + assertThat(class1.getEStructuralFeatures().size(), is(FEATURES)); + assertThat(class1.getEStructuralFeature("attribute1"), notNullValue()); //$NON-NLS-1$ + assertThat(class1.getEStructuralFeature("attribute2"), notNullValue()); //$NON-NLS-1$ + + // Undo is sane and there is only one command to undo + Command undone = undo(); + assertThat(fixture.canUndo(), is(false)); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount)); + assertThat(testPackage.getEClassifiers(), not(hasItem(class1))); + + // Redo is sane + Command redone = redo(); + assertThat(redone, sameInstance(undone)); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount + 1)); + assertThat(testPackage.getEClassifiers(), hasItem(class1)); + assertThat(class1.getEStructuralFeatures().size(), is(FEATURES)); + assertThat(class1.getEStructuralFeature("attribute1"), notNullValue()); //$NON-NLS-1$ + assertThat(class1.getEStructuralFeature("attribute2"), notNullValue()); //$NON-NLS-1$ + } + + @Test + public void testCompleteTripleNestedCommand() { + final int CLASSES = 2; + final int FEATURES = 2; + + Callable<EPackage> createPackage = createPackage(CLASSES, FEATURES); + + int oldPackageCount = testPackage.getESubpackages().size(); + + EPackage pkg = execute(createPackage); + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount + 1)); + assertThat(testPackage.getESubpackages(), hasItem(pkg)); + assertThat(pkg.getEClassifiers().size(), is(CLASSES)); + assertThat(pkg.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class1")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + assertThat(pkg.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class2")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + // Undo is sane and there is only one command to undo + Command undone = undo(); + assertThat(fixture.canUndo(), is(false)); + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount)); + assertThat(testPackage.getESubpackages(), not(hasItem(pkg))); + assertThat(pkg.getName(), nullValue()); + assertThat(pkg.getEClassifiers().size(), is(0)); + assertThat(pkg.getEClassifiers().size(), is(0)); + + // Redo is sane + Command redone = redo(); + assertThat(redone, sameInstance(undone)); + assertThat(fixture.canRedo(), is(false)); + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount + 1)); + assertThat(testPackage.getESubpackages(), hasItem(pkg)); + assertThat(pkg, named("package1")); //$NON-NLS-1$ + assertThat(pkg.getEClassifiers().size(), is(CLASSES)); + assertThat(pkg.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class1")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + assertThat(pkg.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class2")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + @Test + public void testCancelTripleNestedCommand() { + final int CLASSES = 2; + final int FEATURES = 2; + + Callable<EPackage> createPackage = createPackage(CLASSES, FEATURES, 2, CLASSES, FEATURES); + + int oldPackageCount = testPackage.getESubpackages().size(); + + // Try to create two packages (second one cancels) + EPackage pkg1 = execute(createPackage); + EPackage pkg2 = execute(createPackage); + + // the first package is complete + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount + 1)); + assertThat(testPackage.getESubpackages(), hasItem(pkg1)); + assertThat(pkg1, named("package1")); //$NON-NLS-1$ + assertThat(pkg1.getEClassifiers().size(), is(CLASSES)); + assertThat(pkg1.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class1")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + assertThat(pkg1.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class2")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + // there is no second package + assertThat(pkg2, nullValue()); + + // Undo is sane and there is only one command to undo + Command undone = undo(); + assertThat(fixture.canUndo(), is(false)); + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount)); + assertThat(testPackage.getESubpackages(), not(hasItem(pkg1))); + assertThat(pkg1.getName(), nullValue()); + assertThat(pkg1.getEClassifiers().size(), is(0)); + + // Redo is sane + Command redone = redo(); + assertThat(fixture.canRedo(), is(false)); + assertThat(redone, sameInstance(undone)); + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount + 1)); + assertThat(testPackage.getESubpackages(), hasItem(pkg1)); + assertThat(pkg1, named("package1")); //$NON-NLS-1$ + assertThat(pkg1.getEClassifiers().size(), is(CLASSES)); + assertThat(pkg1.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class1")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + assertThat(pkg1.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class2")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + // + // Test framework + // + + @Before + public void createFixture() { + rset = new ResourceSetImpl(); + fixture = new NestingTransactionalCommandStack(); + AdapterFactory adapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE); + domain = new TransactionalEditingDomainImpl(adapterFactory, (TransactionalCommandStack)fixture, rset); + + URL testModelURL = getClass().getResource("bug402525.ecore"); //$NON-NLS-1$ + Resource testModel = rset.getResource(URI.createURI(testModelURL.toExternalForm(), true), true); + testPackage = (EPackage)testModel.getContents().get(0); + foo = (EClass)testPackage.getEClassifier("Foo"); //$NON-NLS-1$ + } + + @After + public void destroyFixture() { + // This disposes the command stack for us + domain.dispose(); + domain = null; + fixture = null; + + dispose(rset); + rset = null; + } + + void dispose(ResourceSet rset) { + for(Resource next : rset.getResources()) { + next.unload(); + next.eAdapters().clear(); + } + + rset.getResources().clear(); + rset.eAdapters().clear(); + } + + <V> V execute(final Callable<V> operation) { + class TestCommand extends RecordingCommand { + + V result; + + TestCommand() { + super(domain); + } + + @Override + protected void doExecute() { + try { + result = operation.call(); + } catch (OperationCanceledException e) { + // Pass it on + throw e; + } catch (Exception e) { + e.printStackTrace(); + fail("Uncaught exception in operation: " + e.getLocalizedMessage()); //$NON-NLS-1$ + } + } + } + + TestCommand command = new TestCommand(); + fixture.execute(command); + return command.result; + } + + Command undo() { + assertThat("Cannot undo", fixture.canUndo()); //$NON-NLS-1$ + Command result = fixture.getUndoCommand(); + fixture.undo(); + return result; + } + + Command redo() { + assertThat("Cannot redo", fixture.canRedo()); //$NON-NLS-1$ + Command result = fixture.getRedoCommand(); + fixture.redo(); + return result; + } + + Callable<EAttribute> createAttribute() { + return createAttribute(0); + } + + Callable<EAttribute> createAttribute(int cancelOn) { + return createAttribute(foo, cancelOn); + } + + Callable<EAttribute> createAttribute(final EClass owner, final int cancelOn) { + return new Callable<EAttribute>() { + + int i = 0; + + public EAttribute call() throws Exception { + String name = nextName(); + + EAttribute attr = EcoreFactory.eINSTANCE.createEAttribute(); + owner.getEStructuralFeatures().add(attr); + attr.setName(name); + attr.setEType(EcorePackage.Literals.ESTRING); + + checkCancel(); + + return attr; + } + + private String nextName() { + i = i + 1; + return "attribute" + i; //$NON-NLS-1$ + } + + private void checkCancel() { + if(i == cancelOn) { + throw new OperationCanceledException(); + } + } + }; + } + + Callable<EClass> createClass(int attributes) { + return createClass(attributes, 0, 0); + } + + Callable<EClass> createClass(int attributes, int cancelOn, int cancelAttributesOn) { + return createClass(testPackage, attributes, cancelOn, cancelAttributesOn); + } + + Callable<EClass> createClass(final EPackage owner, final int attributes, final int cancelOn, final int cancelAttributesOn) { + return new Callable<EClass>() { + + int i = 0; + + public EClass call() throws Exception { + String name = nextName(); + + EClass clas = EcoreFactory.eINSTANCE.createEClass(); + owner.getEClassifiers().add(clas); + clas.setName(name); + + Callable<?> createAttribute = createAttribute(clas, checkCancelAttributes()); + for(int i = 0; i < attributes; i++) { + // Nested command + execute(createAttribute); + } + + return clas; + } + + private String nextName() { + i = i + 1; + return "Class" + i; //$NON-NLS-1$ + } + + private int checkCancelAttributes() { + return (i == cancelOn) ? cancelAttributesOn : 0; + } + }; + } + + Callable<EPackage> createPackage(int classes, int attributes) { + return createPackage(classes, attributes, 0, 0, 0); + } + + Callable<EPackage> createPackage(final int classes, final int attributes, final int cancelOn, final int cancelClassesOn, final int cancelAttributesOn) { + return new Callable<EPackage>() { + + int i = 0; + + public EPackage call() throws Exception { + String name = nextName(); + + EPackage pkg = EcoreFactory.eINSTANCE.createEPackage(); + testPackage.getESubpackages().add(pkg); + pkg.setName(name); + + Callable<?> createClass = createClass(pkg, attributes, checkCancelClasses(), cancelAttributesOn); + for(int i = 0; i < classes; i++) { + // Nested command + execute(createClass); + } + + return pkg; + } + + private String nextName() { + i = i + 1; + return "package" + i; //$NON-NLS-1$ + } + + private int checkCancelClasses() { + return (i == cancelOn) ? cancelClassesOn : 0; + } + }; + } + + Matcher<ENamedElement> named(final String name) { + return new BaseMatcher<ENamedElement>() { + + public void describeTo(Description desc) { + desc.appendText("is named \"").appendValue(name).appendText("\""); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public boolean matches(Object o) { + return (o instanceof ENamedElement) && Objects.equal(((ENamedElement)o).getName(), name); + } + }; + } + + Matcher<EClass> featureCount(final int count) { + return new BaseMatcher<EClass>() { + + public void describeTo(Description desc) { + desc.appendText("has ").appendValue(count).appendText(" features"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public boolean matches(Object o) { + return (o instanceof EClass) && (((EClass)o).getEStructuralFeatures().size() == count); + } + }; + } + + Matcher<EClass> hasFeature(final String name) { + return new BaseMatcher<EClass>() { + + public void describeTo(Description desc) { + desc.appendText("has a \"").appendValue(name).appendText("\" feature"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public boolean matches(Object o) { + return (o instanceof EClass) && (((EClass)o).getEStructuralFeature(name) != null); + } + }; + } +} diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.infra.core.tests/test/org/eclipse/papyrus/infra/core/tests/AllTests.java b/tests/junit/plugins/core/org.eclipse.papyrus.infra.core.tests/test/org/eclipse/papyrus/infra/core/tests/AllTests.java index 9670eb13bbc..1d389ba9ad7 100644 --- a/tests/junit/plugins/core/org.eclipse.papyrus.infra.core.tests/test/org/eclipse/papyrus/infra/core/tests/AllTests.java +++ b/tests/junit/plugins/core/org.eclipse.papyrus.infra.core.tests/test/org/eclipse/papyrus/infra/core/tests/AllTests.java @@ -1,5 +1,5 @@ /*****************************************************************************
- * Copyright (c) 2010, 2013 CEA LIST and others.
+ * Copyright (c) 2010, 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -9,6 +9,7 @@ * Contributors:
* Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation
* Christian W. Damus (CEA LIST) - add test for AdapterUtils
+ * Christian W. Damus (CEA) - bug 402525
*****************************************************************************/
package org.eclipse.papyrus.infra.core.tests;
@@ -16,6 +17,7 @@ import org.eclipse.papyrus.infra.core.contentoutline.NestedEditorDelegatedOutlin import org.eclipse.papyrus.infra.core.lifecycleevents.LifeCycleEventsProviderTest;
import org.eclipse.papyrus.infra.core.resource.AbstractModelWithSharedResourceTest;
import org.eclipse.papyrus.infra.core.resource.ModelSetTest;
+import org.eclipse.papyrus.infra.core.resource.NestingTransactionalCommandStackTest;
import org.eclipse.papyrus.infra.core.services.ComposedServiceTest;
import org.eclipse.papyrus.infra.core.services.ServicesRegistryTest;
import org.eclipse.papyrus.infra.core.utils.AdapterUtilsTest;
@@ -28,7 +30,7 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class)
@SuiteClasses({
// {oep.resource}
-ModelSetTest.class, AbstractModelWithSharedResourceTest.class,
+ModelSetTest.class, AbstractModelWithSharedResourceTest.class, NestingTransactionalCommandStackTest.class,
// {oep}.core.services
ComposedServiceTest.class, ServicesRegistryTest.class,
// {oep}.core.lifecycleevents
diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.tests/META-INF/MANIFEST.MF b/tests/junit/plugins/core/org.eclipse.papyrus.tests/META-INF/MANIFEST.MF index 6aeaa83921f..b4c29f16401 100644 --- a/tests/junit/plugins/core/org.eclipse.papyrus.tests/META-INF/MANIFEST.MF +++ b/tests/junit/plugins/core/org.eclipse.papyrus.tests/META-INF/MANIFEST.MF @@ -42,9 +42,10 @@ Require-Bundle: org.eclipse.ui, org.eclipse.papyrus.infra.nattable.model.editor.tests;bundle-version="1.0.0",
org.eclipse.papyrus.uml.diagram.sequence.tests;bundle-version="1.0.0",
org.eclipse.papyrus.uml.diagram.interactionoverview.tests;bundle-version="1.0.0",
- org.eclipse.papyrus.uml.diagram.composite.tests;bundle-version="1.0.0",
+ org.eclipse.papyrus.uml.diagram.composite.tests;bundle-version="1.0.0",
org.eclipse.papyrus.infra.gmfdiag.css.tests;bundle-version="1.0.0",
- org.eclipse.papyrus.infra.extendedtypes.tests;bundle-version="1.0.0"
+ org.eclipse.papyrus.infra.extendedtypes.tests;bundle-version="1.0.0",
+ org.eclipse.papyrus.infra.gmfdiag.commands;bundle-version="1.0.0"
Bundle-Vendor: %providerName
Bundle-ActivationPolicy: lazy
Bundle-Version: 1.0.0.qualifier
diff --git a/tests/junit/plugins/core/org.eclipse.papyrus.tests/test/org/eclipse/papyrus/tests/AllTests.java b/tests/junit/plugins/core/org.eclipse.papyrus.tests/test/org/eclipse/papyrus/tests/AllTests.java index 510de5a6616..bea80b1597d 100644 --- a/tests/junit/plugins/core/org.eclipse.papyrus.tests/test/org/eclipse/papyrus/tests/AllTests.java +++ b/tests/junit/plugins/core/org.eclipse.papyrus.tests/test/org/eclipse/papyrus/tests/AllTests.java @@ -1,6 +1,6 @@ /*****************************************************************************
- * Copyright (c) 2010 CEA LIST.
- *
+ * Copyright (c) 2010, 2014 CEA LIST and others.
+ *
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -8,6 +8,8 @@ *
* Contributors:
* Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
*****************************************************************************/
package org.eclipse.papyrus.tests;
@@ -50,6 +52,7 @@ public class AllTests { suiteClasses.add(new FragmentTestSuiteClass(org.eclipse.papyrus.infra.emf.Activator.PLUGIN_ID, "org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceTest"));
suiteClasses.add(new PluginTestSuiteClass(org.eclipse.papyrus.infra.extendedtypes.tests.AllTests.class));
// suiteClasses.add(new PluginTestSuiteClass(org.eclipse.papyrus.infra.services.openelement.tests.AllTests.class));
+ suiteClasses.add(new FragmentTestSuiteClass(org.eclipse.papyrus.commands.Activator.PLUGIN_ID, "org.eclipse.papyrus.infra.gmfdiag.commands.tests.AllTests"));
/* views */
suiteClasses.add(new PluginTestSuiteClass(org.eclipse.papyrus.views.modelexplorer.tests.AllTests.class));
@@ -87,7 +90,7 @@ public class AllTests { suiteClasses.add(new PluginTestSuiteClass(org.eclipse.papyrus.uml.diagram.composite.test.AllTests.class));
//suiteClasses.add(new PluginTestSuiteClass(org.eclipse.papyrus.uml.diagram.sequence.tests.AllTests.class)); //Disabled. They currently do not run on Hudson
// suiteClasses.add(new PluginTestSuiteClass(org.eclipse.papyrus.uml.diagram.interactionoverview.tests.AllTests.class)); //Disabled. They currently do not run on Hudson
- //
+ //
//nattable tests
suiteClasses.add(new PluginTestSuiteClass(org.eclipse.papyrus.uml.nattable.tests.tests.AllTests.class));
diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/.classpath b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/.classpath new file mode 100644 index 00000000000..64c5e31b7a2 --- /dev/null +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/.project b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/.project new file mode 100644 index 00000000000..a7434ea3fe4 --- /dev/null +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.papyrus.infra.gmfdiag.commands.tests</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/.settings/org.eclipse.jdt.core.prefs b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..3eff40b8b33 --- /dev/null +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Mon Nov 08 19:25:55 CET 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/META-INF/MANIFEST.MF b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..0afee83d834 --- /dev/null +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-Vendor: %providerName +Bundle-SymbolicName: org.eclipse.papyrus.infra.gmfdiag.commands.tests +Bundle-Version: 1.0.0.qualifier +Bundle-Localization: fragment +Fragment-Host: org.eclipse.papyrus.infra.gmfdiag.commands;bundle-version="1.0.0" +Require-Bundle: org.junit;bundle-version="4.10.0", + com.google.guava;bundle-version="11.0.0", + org.eclipse.papyrus.infra.emf.readonly;bundle-version="1.0.0" +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Export-Package: org.eclipse.papyrus.infra.gmfdiag.commands.tests diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/about.html b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/about.html new file mode 100644 index 00000000000..d35d5aed64c --- /dev/null +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/about.html @@ -0,0 +1,28 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> +<title>About</title> +</head> +<body lang="EN-US"> +<h2>About This Content</h2> + +<p>June 5, 2007</p> +<h3>License</h3> + +<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>. +For purposes of the EPL, "Program" will mean the Content.</p> + +<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p> + +</body> +</html> diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/build.properties b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/build.properties new file mode 100644 index 00000000000..6f802cf9614 --- /dev/null +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/build.properties @@ -0,0 +1,8 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + fragment.properties,\ + org.eclipse.papyrus.infra.gmfdiag.commands.tests.launch,\ + about.html +src.includes = about.html diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/fragment.properties b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/fragment.properties new file mode 100644 index 00000000000..6242c967488 --- /dev/null +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/fragment.properties @@ -0,0 +1,14 @@ +################################################################################# +# Copyright (c) 2014 CEA and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# +# Christian W. Damus (CEA) - initial API and Implementation. +# +################################################################################## +pluginName=Papyrus GMF Diagram Commands Infrastructure Tests (Incubation) +providerName=Eclipse Modeling Project diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/org.eclipse.papyrus.infra.gmfdiag.commands.tests.launch b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/org.eclipse.papyrus.infra.gmfdiag.commands.tests.launch new file mode 100644 index 00000000000..5afacf2f348 --- /dev/null +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/org.eclipse.papyrus.infra.gmfdiag.commands.tests.launch @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig"> +<booleanAttribute key="append.args" value="true"/> +<booleanAttribute key="askclear" value="false"/> +<booleanAttribute key="automaticAdd" value="true"/> +<booleanAttribute key="automaticValidate" value="false"/> +<stringAttribute key="bootstrap" value=""/> +<stringAttribute key="checked" value="[NONE]"/> +<booleanAttribute key="clearConfig" value="true"/> +<booleanAttribute key="clearws" value="true"/> +<booleanAttribute key="clearwslog" value="false"/> +<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/> +<booleanAttribute key="default" value="true"/> +<booleanAttribute key="includeOptional" value="true"/> +<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/> +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> +<listEntry value="/org.eclipse.papyrus.infra.gmfdiag.commands.tests/src/org/eclipse/papyrus/infra/gmfdiag/commands/tests/AllTests.java"/> +</listAttribute> +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> +<listEntry value="1"/> +</listAttribute> +<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/> +<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.6"/> +<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.papyrus.infra.gmfdiag.commands.tests.AllTests"/> +<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/> +<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.papyrus.infra.gmfdiag.commands.tests"/> +<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/> +<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dosgi.requiredJavaVersion=1.5 -Xms40m -Xmx1024m -XX:PermSize=256M -XX:MaxPermSize=512M"/> +<stringAttribute key="pde.version" value="3.3"/> +<stringAttribute key="product" value="org.eclipse.platform.ide"/> +<booleanAttribute key="run_in_ui_thread" value="true"/> +<booleanAttribute key="show_selected_only" value="false"/> +<booleanAttribute key="tracing" value="false"/> +<booleanAttribute key="useCustomFeatures" value="false"/> +<booleanAttribute key="useDefaultConfig" value="true"/> +<booleanAttribute key="useDefaultConfigArea" value="false"/> +<booleanAttribute key="useProduct" value="true"/> +</launchConfiguration> diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/src/org/eclipse/papyrus/commands/Bug402525.ecore b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/src/org/eclipse/papyrus/commands/Bug402525.ecore new file mode 100644 index 00000000000..8dea18de3e8 --- /dev/null +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/src/org/eclipse/papyrus/commands/Bug402525.ecore @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="bug402525" nsURI="http://www.eclipse.org/schema/Papyrus/tests/bug402525" + nsPrefix="bug"> + <eClassifiers xsi:type="ecore:EClass" name="Foo"/> +</ecore:EPackage> diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/src/org/eclipse/papyrus/commands/NestingNotifyingWorkspaceCommandStackTest.java b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/src/org/eclipse/papyrus/commands/NestingNotifyingWorkspaceCommandStackTest.java new file mode 100644 index 00000000000..925cc1b4c0b --- /dev/null +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/src/org/eclipse/papyrus/commands/NestingNotifyingWorkspaceCommandStackTest.java @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2014 CEA and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - Initial API and implementation + * + */ +package org.eclipse.papyrus.commands; + +import static org.hamcrest.CoreMatchers.both; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; + +import java.net.URL; +import java.util.concurrent.Callable; + +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.command.CommandStack; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EcoreFactory; +import org.eclipse.emf.ecore.EcorePackage; +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.edit.provider.ComposedAdapterFactory; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalCommandStack; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.papyrus.infra.emf.readonly.PapyrusROTransactionalEditingDomain; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.base.Objects; + + +/** + * Test suite for the {@link NestingNotifyingWorkspaceCommandStack} class. + */ +public class NestingNotifyingWorkspaceCommandStackTest { + + // No API signatures but the most basic are required for nesting + private CommandStack fixture; + + private TransactionalEditingDomain domain; + + private ResourceSet rset; + + private EPackage testPackage; + + private EClass foo; + + public NestingNotifyingWorkspaceCommandStackTest() { + super(); + } + + // + // Test cases + // + + @Test + public void testCompleteUnnestedCommand() { + Callable<EAttribute> createAttribute = createAttribute(); + + int oldFeatureCount = foo.getEStructuralFeatures().size(); + + // Create two attributes + EAttribute attr1 = execute(createAttribute); + EAttribute attr2 = execute(createAttribute); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount + 2)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr1)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr2)); + + // Undo only undoes one of them + Command undone = undo(); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount + 1)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr1)); + assertThat(foo.getEStructuralFeatures(), not(hasItem(attr2))); + + // Redo is sane + Command redone = redo(); + assertThat(redone, sameInstance(undone)); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount + 2)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr1)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr2)); + } + + @Test + public void testCancelUnnestedCommand() { + Callable<EAttribute> createAttribute = createAttribute(2); + + int oldFeatureCount = foo.getEStructuralFeatures().size(); + + // Try to create two attributes (second one cancels) + EAttribute attr1 = execute(createAttribute); + EAttribute attr2 = execute(createAttribute); + assertThat(attr2, nullValue()); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount + 1)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr1)); + assertThat(foo.getEStructuralFeature("attribute2"), nullValue()); //$NON-NLS-1$ + + // Undo is sane + Command undone = undo(); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount)); + assertThat(foo.getEStructuralFeatures(), not(hasItem(attr1))); + assertThat(foo.getEStructuralFeature("attribute2"), nullValue()); //$NON-NLS-1$ + + // Redo is sane + Command redone = redo(); + assertThat(redone, sameInstance(undone)); + assertThat(foo.getEStructuralFeatures().size(), is(oldFeatureCount + 1)); + assertThat(foo.getEStructuralFeatures(), hasItem(attr1)); + assertThat(foo.getEStructuralFeature("attribute2"), nullValue()); //$NON-NLS-1$ + } + + @Test + public void testCompleteNestedCommand() { + final int FEATURES = 2; + Callable<EClass> createClass = createClass(FEATURES); + + int oldClassifierCount = testPackage.getEClassifiers().size(); + + EClass clas = execute(createClass); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount + 1)); + assertThat(testPackage.getEClassifiers(), hasItem(clas)); + assertThat(clas.getEStructuralFeatures().size(), is(FEATURES)); + assertThat(clas.getEStructuralFeature("attribute1"), notNullValue()); //$NON-NLS-1$ + assertThat(clas.getEStructuralFeature("attribute2"), notNullValue()); //$NON-NLS-1$ + + // Undo is sane and there is only one command to undo + Command undone = undo(); + assertThat(fixture.canUndo(), is(false)); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount)); + assertThat(testPackage.getEClassifiers(), not(hasItem(clas))); + + // Redo is sane + Command redone = redo(); + assertThat(redone, sameInstance(undone)); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount + 1)); + assertThat(testPackage.getEClassifiers(), hasItem(clas)); + assertThat(clas.getEStructuralFeatures().size(), is(FEATURES)); + assertThat(clas.getEStructuralFeature("attribute1"), notNullValue()); //$NON-NLS-1$ + assertThat(clas.getEStructuralFeature("attribute2"), notNullValue()); //$NON-NLS-1$ + } + + @Test + public void testCancelNestedCommand() { + final int FEATURES = 2; + Callable<EClass> createClass = createClass(FEATURES, 2, FEATURES); + + int oldClassifierCount = testPackage.getEClassifiers().size(); + + // Try to create two classes (second one cancels) + EClass class1 = execute(createClass); + EClass class2 = execute(createClass); + assertThat(class2, nullValue()); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount + 1)); + assertThat(testPackage.getEClassifiers(), hasItem(class1)); + assertThat(class1.getEStructuralFeatures().size(), is(FEATURES)); + assertThat(class1.getEStructuralFeature("attribute1"), notNullValue()); //$NON-NLS-1$ + assertThat(class1.getEStructuralFeature("attribute2"), notNullValue()); //$NON-NLS-1$ + + // Undo is sane and there is only one command to undo + Command undone = undo(); + assertThat(fixture.canUndo(), is(false)); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount)); + assertThat(testPackage.getEClassifiers(), not(hasItem(class1))); + + // Redo is sane + Command redone = redo(); + assertThat(redone, sameInstance(undone)); + assertThat(testPackage.getEClassifiers().size(), is(oldClassifierCount + 1)); + assertThat(testPackage.getEClassifiers(), hasItem(class1)); + assertThat(class1.getEStructuralFeatures().size(), is(FEATURES)); + assertThat(class1.getEStructuralFeature("attribute1"), notNullValue()); //$NON-NLS-1$ + assertThat(class1.getEStructuralFeature("attribute2"), notNullValue()); //$NON-NLS-1$ + } + + @Test + public void testCompleteTripleNestedCommand() { + final int CLASSES = 2; + final int FEATURES = 2; + + Callable<EPackage> createPackage = createPackage(CLASSES, FEATURES); + + int oldPackageCount = testPackage.getESubpackages().size(); + + EPackage pkg = execute(createPackage); + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount + 1)); + assertThat(testPackage.getESubpackages(), hasItem(pkg)); + assertThat(pkg.getEClassifiers().size(), is(CLASSES)); + assertThat(pkg.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class1")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + assertThat(pkg.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class2")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + // Undo is sane and there is only one command to undo + Command undone = undo(); + assertThat(fixture.canUndo(), is(false)); + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount)); + assertThat(testPackage.getESubpackages(), not(hasItem(pkg))); + assertThat(pkg.getName(), nullValue()); + assertThat(pkg.getEClassifiers().size(), is(0)); + assertThat(pkg.getEClassifiers().size(), is(0)); + + // Redo is sane + Command redone = redo(); + assertThat(redone, sameInstance(undone)); + assertThat(fixture.canRedo(), is(false)); + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount + 1)); + assertThat(testPackage.getESubpackages(), hasItem(pkg)); + assertThat(pkg, named("package1")); //$NON-NLS-1$ + assertThat(pkg.getEClassifiers().size(), is(CLASSES)); + assertThat(pkg.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class1")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + assertThat(pkg.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class2")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + @Test + public void testCancelTripleNestedCommand() { + final int CLASSES = 2; + final int FEATURES = 2; + + Callable<EPackage> createPackage = createPackage(CLASSES, FEATURES, 2, CLASSES, FEATURES); + + int oldPackageCount = testPackage.getESubpackages().size(); + + // Try to create two packages (second one cancels) + EPackage pkg1 = execute(createPackage); + EPackage pkg2 = execute(createPackage); + + // the first package is complete + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount + 1)); + assertThat(testPackage.getESubpackages(), hasItem(pkg1)); + assertThat(pkg1, named("package1")); //$NON-NLS-1$ + assertThat(pkg1.getEClassifiers().size(), is(CLASSES)); + assertThat(pkg1.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class1")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + assertThat(pkg1.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class2")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + // there is no second package + assertThat(pkg2, nullValue()); + + // Undo is sane and there is only one command to undo + Command undone = undo(); + assertThat(fixture.canUndo(), is(false)); + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount)); + assertThat(testPackage.getESubpackages(), not(hasItem(pkg1))); + assertThat(pkg1.getName(), nullValue()); + assertThat(pkg1.getEClassifiers().size(), is(0)); + + // Redo is sane + Command redone = redo(); + assertThat(fixture.canRedo(), is(false)); + assertThat(redone, sameInstance(undone)); + assertThat(testPackage.getESubpackages().size(), is(oldPackageCount + 1)); + assertThat(testPackage.getESubpackages(), hasItem(pkg1)); + assertThat(pkg1, named("package1")); //$NON-NLS-1$ + assertThat(pkg1.getEClassifiers().size(), is(CLASSES)); + assertThat(pkg1.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class1")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + assertThat(pkg1.getEClassifiers(), hasItem(both(featureCount(FEATURES)).and(named("Class2")).and(hasFeature("attribute1")).and(hasFeature("attribute2")))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + // + // Test framework + // + + @Before + public void createFixture() { + rset = new ResourceSetImpl(); + fixture = new NestingNotifyingWorkspaceCommandStack(CheckedOperationHistory.getInstance()); + AdapterFactory adapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE); + domain = new PapyrusROTransactionalEditingDomain(adapterFactory, (TransactionalCommandStack)fixture, rset); + + URL testModelURL = getClass().getResource("bug402525.ecore"); //$NON-NLS-1$ + Resource testModel = rset.getResource(URI.createURI(testModelURL.toExternalForm(), true), true); + testPackage = (EPackage)testModel.getContents().get(0); + foo = (EClass)testPackage.getEClassifier("Foo"); //$NON-NLS-1$ + } + + @After + public void destroyFixture() { + // This disposes the command stack for us + domain.dispose(); + domain = null; + fixture = null; + + dispose(rset); + rset = null; + } + + void dispose(ResourceSet rset) { + for(Resource next : rset.getResources()) { + next.unload(); + next.eAdapters().clear(); + } + + rset.getResources().clear(); + rset.eAdapters().clear(); + } + + <V> V execute(final Callable<V> operation) { + class TestCommand extends RecordingCommand { + + V result; + + TestCommand() { + super(domain); + } + + @Override + protected void doExecute() { + try { + result = operation.call(); + } catch (OperationCanceledException e) { + // Pass it on + throw e; + } catch (Exception e) { + e.printStackTrace(); + fail("Uncaught exception in operation: " + e.getLocalizedMessage()); //$NON-NLS-1$ + } + } + } + + TestCommand command = new TestCommand(); + fixture.execute(command); + return command.result; + } + + Command undo() { + assertThat("Cannot undo", fixture.canUndo()); //$NON-NLS-1$ + Command result = fixture.getUndoCommand(); + fixture.undo(); + return result; + } + + Command redo() { + assertThat("Cannot redo", fixture.canRedo()); //$NON-NLS-1$ + Command result = fixture.getRedoCommand(); + fixture.redo(); + return result; + } + + Callable<EAttribute> createAttribute() { + return createAttribute(0); + } + + Callable<EAttribute> createAttribute(int cancelOn) { + return createAttribute(foo, cancelOn); + } + + Callable<EAttribute> createAttribute(final EClass owner, final int cancelOn) { + return new Callable<EAttribute>() { + + int i = 0; + + public EAttribute call() throws Exception { + String name = nextName(); + + EAttribute attr = EcoreFactory.eINSTANCE.createEAttribute(); + owner.getEStructuralFeatures().add(attr); + attr.setName(name); + attr.setEType(EcorePackage.Literals.ESTRING); + + checkCancel(); + + return attr; + } + + private String nextName() { + i = i + 1; + return "attribute" + i; //$NON-NLS-1$ + } + + private void checkCancel() { + if(i == cancelOn) { + throw new OperationCanceledException(); + } + } + }; + } + + Callable<EClass> createClass(int attributes) { + return createClass(attributes, 0, 0); + } + + Callable<EClass> createClass(int attributes, int cancelOn, int cancelAttributesOn) { + return createClass(testPackage, attributes, cancelOn, cancelAttributesOn); + } + + Callable<EClass> createClass(final EPackage owner, final int attributes, final int cancelOn, final int cancelAttributesOn) { + return new Callable<EClass>() { + + int i = 0; + + public EClass call() throws Exception { + String name = nextName(); + + EClass clas = EcoreFactory.eINSTANCE.createEClass(); + owner.getEClassifiers().add(clas); + clas.setName(name); + + Callable<?> createAttribute = createAttribute(clas, checkCancelAttributes()); + for(int i = 0; i < attributes; i++) { + // Nested command + execute(createAttribute); + } + + return clas; + } + + private String nextName() { + i = i + 1; + return "Class" + i; //$NON-NLS-1$ + } + + private int checkCancelAttributes() { + return (i == cancelOn) ? cancelAttributesOn : 0; + } + }; + } + + Callable<EPackage> createPackage(int classes, int attributes) { + return createPackage(classes, attributes, 0, 0, 0); + } + + Callable<EPackage> createPackage(final int classes, final int attributes, final int cancelOn, final int cancelClassesOn, final int cancelAttributesOn) { + return new Callable<EPackage>() { + + int i = 0; + + public EPackage call() throws Exception { + String name = nextName(); + + EPackage pkg = EcoreFactory.eINSTANCE.createEPackage(); + testPackage.getESubpackages().add(pkg); + pkg.setName(name); + + Callable<?> createClass = createClass(pkg, attributes, checkCancelClasses(), cancelAttributesOn); + for(int i = 0; i < classes; i++) { + // Nested command + execute(createClass); + } + + return pkg; + } + + private String nextName() { + i = i + 1; + return "package" + i; //$NON-NLS-1$ + } + + private int checkCancelClasses() { + return (i == cancelOn) ? cancelClassesOn : 0; + } + }; + } + + Matcher<ENamedElement> named(final String name) { + return new BaseMatcher<ENamedElement>() { + + public void describeTo(Description desc) { + desc.appendText("is named \"").appendValue(name).appendText("\""); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public boolean matches(Object o) { + return (o instanceof ENamedElement) && Objects.equal(((ENamedElement)o).getName(), name); + } + }; + } + + Matcher<EClass> featureCount(final int count) { + return new BaseMatcher<EClass>() { + + public void describeTo(Description desc) { + desc.appendText("has ").appendValue(count).appendText(" features"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public boolean matches(Object o) { + return (o instanceof EClass) && (((EClass)o).getEStructuralFeatures().size() == count); + } + }; + } + + Matcher<EClass> hasFeature(final String name) { + return new BaseMatcher<EClass>() { + + public void describeTo(Description desc) { + desc.appendText("has a \"").appendValue(name).appendText("\" feature"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public boolean matches(Object o) { + return (o instanceof EClass) && (((EClass)o).getEStructuralFeature(name) != null); + } + }; + } +} diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/src/org/eclipse/papyrus/infra/gmfdiag/commands/tests/AllTests.java b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/src/org/eclipse/papyrus/infra/gmfdiag/commands/tests/AllTests.java new file mode 100644 index 00000000000..ecce7998eb4 --- /dev/null +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.commands.tests/src/org/eclipse/papyrus/infra/gmfdiag/commands/tests/AllTests.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 CEA LIST and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus (CEA) - initial API and implementation + */ +package org.eclipse.papyrus.infra.gmfdiag.commands.tests; + +import org.eclipse.papyrus.commands.NestingNotifyingWorkspaceCommandStackTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + + +/** + * Master test suite for this test fragment. + */ +@RunWith(Suite.class) +@SuiteClasses({ +// {oep.commands} +NestingNotifyingWorkspaceCommandStackTest.class }) +public class AllTests { + +} |