### Eclipse Workspace Patch 1.0 #P org.eclipse.gmf.tests.runtime.diagram.ui Index: src/org/eclipse/gmf/tests/runtime/diagram/ui/AllTests.java =================================================================== RCS file: /cvsroot/technology/org.eclipse.gmf/tests/org.eclipse.gmf.tests.runtime.diagram.ui/src/org/eclipse/gmf/tests/runtime/diagram/ui/AllTests.java,v retrieving revision 1.17 diff -u -r1.17 AllTests.java --- src/org/eclipse/gmf/tests/runtime/diagram/ui/AllTests.java 21 Feb 2006 16:07:13 -0000 1.17 +++ src/org/eclipse/gmf/tests/runtime/diagram/ui/AllTests.java 22 Mar 2006 19:55:27 -0000 @@ -73,6 +73,7 @@ suite.addTest(RequestTests.suite()); suite.addTest(ConnectionToolTests.suite()); suite.addTest(CopyToImageUtilTests.suite()); + suite.addTest(DiagramEditingDomainTestCase.suite()); return suite; } Index: src/org/eclipse/gmf/tests/runtime/diagram/ui/DiagramEditingDomainTestCase.java =================================================================== RCS file: src/org/eclipse/gmf/tests/runtime/diagram/ui/DiagramEditingDomainTestCase.java diff -N src/org/eclipse/gmf/tests/runtime/diagram/ui/DiagramEditingDomainTestCase.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/gmf/tests/runtime/diagram/ui/DiagramEditingDomainTestCase.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,119 @@ +package org.eclipse.gmf.tests.runtime.diagram.ui; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EcoreFactory; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.transaction.ResourceSetChangeEvent; +import org.eclipse.emf.transaction.ResourceSetListenerImpl; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.gmf.runtime.common.core.command.CommandResult; +import org.eclipse.gmf.runtime.diagram.core.DiagramEditingDomainFactory; +import org.eclipse.gmf.runtime.diagram.core.listener.DiagramEventBroker; +import org.eclipse.gmf.runtime.diagram.core.listener.NotificationListener; +import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand; + + +public class DiagramEditingDomainTestCase + extends TestCase { + + EClass eCls; + + public void testDiagramEventBrokerAsSpecialListener() { + final TransactionalEditingDomain domain = DiagramEditingDomainFactory.getInstance().createEditingDomain(); + final Resource r = domain.getResourceSet().createResource(URI.createURI("file:///foo.logic2")); + eCls = EcoreFactory.eINSTANCE.createEClass(); + eCls.setName(""); + + // Set up the resource contents. + try { + new AbstractTransactionalCommand(domain, "Setup", null) { + protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) + throws ExecutionException { + + r.getContents().add(eCls); + + return CommandResult.newOKCommandResult(); + } + }.execute(new NullProgressMonitor(),null); + } catch (ExecutionException e) { + fail(); + } + + DiagramEventBroker.startListening(domain); + DiagramEventBroker.getInstance(domain).addNotificationListener(eCls, new NotificationListener() { + public void notifyChanged(Notification notification) { + if (notification.getNotifier() == eCls && notification.getFeature() == EcorePackage.eINSTANCE.getENamedElement_Name()) { + try { + new AbstractTransactionalCommand(domain, "Add Attribute", null) { + protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) + throws ExecutionException { + + eCls.getEStructuralFeatures().add(EcoreFactory.eINSTANCE.createEAttribute()); + + return CommandResult.newOKCommandResult(); + } + + }.execute(new NullProgressMonitor(),null); + } catch (ExecutionException e) { + fail(); + } + } + } + }); + + AbstractTransactionalCommand cmd = new AbstractTransactionalCommand(domain, "Set Name", null) { + protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) + throws ExecutionException { + eCls.setName("foo"); + + return CommandResult.newOKCommandResult(); + } + }; + + final boolean[] regularListenerWasCalled = new boolean[1]; + final boolean[] notificationsWereEmpty = new boolean[1]; + regularListenerWasCalled[0] = false; + notificationsWereEmpty[0] = true; + + domain.addResourceSetListener(new ResourceSetListenerImpl() { + public boolean isPostcommitOnly() { + return true; + } + + public void resourceSetChanged(ResourceSetChangeEvent event) { + regularListenerWasCalled[0] = true; + notificationsWereEmpty[0] = event.getNotifications().isEmpty(); + } + }); + + try { + cmd.execute(new NullProgressMonitor(),null); + cmd.undo(new NullProgressMonitor(),null); + cmd.redo(new NullProgressMonitor(), null); + cmd.undo(new NullProgressMonitor(),null); + cmd.redo(new NullProgressMonitor(),null); + } catch (ExecutionException e) { + fail(); + } + + assertSame(eCls.eResource(),r); + assertEquals(3,eCls.getEStructuralFeatures().size()); + assertTrue(regularListenerWasCalled[0]); + assertFalse(notificationsWereEmpty[0]); + } + + public static Test suite() { + return new TestSuite(DiagramEditingDomainTestCase.class); + } +} #P org.eclipse.gmf.runtime.diagram.core Index: src/org/eclipse/gmf/runtime/diagram/core/DiagramEditingDomainFactory.java =================================================================== RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.runtime.diagram.core/src/org/eclipse/gmf/runtime/diagram/core/DiagramEditingDomainFactory.java,v retrieving revision 1.1 diff -u -r1.1 DiagramEditingDomainFactory.java --- src/org/eclipse/gmf/runtime/diagram/core/DiagramEditingDomainFactory.java 1 Mar 2006 22:49:10 -0000 1.1 +++ src/org/eclipse/gmf/runtime/diagram/core/DiagramEditingDomainFactory.java 22 Mar 2006 19:55:28 -0000 @@ -11,9 +11,32 @@ package org.eclipse.gmf.runtime.diagram.core; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.commands.operations.IOperationHistory; +import org.eclipse.core.commands.operations.OperationHistoryFactory; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.edit.provider.ComposedAdapterFactory; +import org.eclipse.emf.transaction.ResourceSetChangeEvent; +import org.eclipse.emf.transaction.ResourceSetListener; +import org.eclipse.emf.transaction.RollbackException; +import org.eclipse.emf.transaction.Transaction; +import org.eclipse.emf.transaction.TransactionalCommandStack; import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.impl.FilterManager; +import org.eclipse.emf.transaction.impl.InternalTransaction; +import org.eclipse.emf.transaction.impl.ReadWriteValidatorImpl; +import org.eclipse.emf.transaction.impl.TransactionValidator; +import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl; +import org.eclipse.emf.transaction.util.CompositeChangeDescription; import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory; +import org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl; import org.eclipse.gmf.runtime.diagram.core.internal.listener.NotationSemProc; +import org.eclipse.gmf.runtime.diagram.core.listener.DiagramEventBroker; import org.eclipse.gmf.runtime.emf.core.GMFEditingDomainFactory; @@ -21,13 +44,116 @@ * Factory for {@link TransactionalEditingDomain}s that are properly configured * to support a GMF diagram application. This factory should be preferred over * the {@link GMFEditingDomainFactory} because it attaches a listener required - * to update the notation model after changes to the semantic model. + * to update the notation model after changes to the semantic model. Also, it + * handles special use cases involving the DiagramEventBroker. * * @author cmahoney */ public class DiagramEditingDomainFactory extends GMFEditingDomainFactory { + + private static class DiagramEditingDomain extends TransactionalEditingDomainImpl { + // The following variable acts as a special latch for the DiagramEventBroker + // listener so that we can allow it to execute in a write transaction context + // while handling a post-commit event. + private InternalTransaction originatingTransaction = null; + private DiagramEventBroker deb = null; + + public void addResourceSetListener(ResourceSetListener l) { + if (l.getClass() == DiagramEventBroker.class) { + assert deb == null; + deb = (DiagramEventBroker)l; + } + + super.addResourceSetListener(l); + } + + public void removeResourceSetListener(ResourceSetListener l) { + if (l.getClass() == DiagramEventBroker.class) { + assert deb != null; + deb = null; + } + + super.removeResourceSetListener(l); + } + + public DiagramEditingDomain(AdapterFactory adapterFactory, ResourceSet resourceSet) { + super(adapterFactory, resourceSet); + } + + public DiagramEditingDomain(AdapterFactory adapterFactory, TransactionalCommandStack stack, ResourceSet resourceSet) { + super(adapterFactory, stack, resourceSet); + } + + public DiagramEditingDomain(AdapterFactory adapterFactory, TransactionalCommandStack stack) { + super(adapterFactory, stack); + } + public DiagramEditingDomain(AdapterFactory adapterFactory) { + super(adapterFactory); + } + + protected void postcommit(InternalTransaction tx) { + try { + List notifications = getValidator().getNotificationsForPostcommit(tx); + + if (deb != null && notifications != null && !notifications.isEmpty()) { + TransactionValidator originalValidator = null; + + // Set the latch if it has not yet been set + if (originatingTransaction == null) { + originatingTransaction = tx; + originalValidator = getValidator(); + setValidator(new ReadWriteValidatorImpl()); + } else { + // In this case we must copy over the notifications and change + // descriptions to the originatingTransaction. + ((CompositeChangeDescription)originatingTransaction.getChangeDescription()).add(tx.getChangeDescription()); + originatingTransaction.getNotifications().addAll(notifications); + } + + try { + ArrayList cache = new ArrayList(notifications.size()); + + List filtered = FilterManager.getInstance().select( + notifications, + deb.getFilter(), + cache); + + HashMap options = new HashMap(originatingTransaction.getOptions()); + options.put(Transaction.OPTION_NO_UNDO, Boolean.FALSE); + InternalTransaction newTx = startTransaction(false, options); + deb.resourceSetChanged( + new ResourceSetChangeEvent( + this, + tx, + filtered)); + + newTx.commit(); + } catch (RollbackException e) { + // Do nothing in the rollback case, we have no change descriptions + // or notifications to propagate. + } finally { + // Undo the latch if we are top-most in the recursion. + if (originatingTransaction == tx) { + originatingTransaction = null; + getValidator().dispose(); + setValidator(originalValidator); + } + } + } + } catch (InterruptedException e) { + // Simply fall-through in this case and allow the post commit listeners + // to be notified. + } + + // We will only call super on the top-most in the recursion. + if (originatingTransaction == null) { + super.postcommit(tx); + } + } + } + /** * The single shared instance of the GMF diagram editing domain factory. */ @@ -50,4 +176,45 @@ domain.addResourceSetListener(new NotationSemProc()); } + public TransactionalEditingDomain createEditingDomain() { + TransactionalEditingDomain result = createEditingDomain(OperationHistoryFactory.getOperationHistory()); + configure(result); + return result; + } + + public TransactionalEditingDomain createEditingDomain(IOperationHistory history) { + WorkspaceCommandStackImpl stack = new WorkspaceCommandStackImpl(history); + + TransactionalEditingDomain result = new DiagramEditingDomain( + new ComposedAdapterFactory( + ComposedAdapterFactory.Descriptor.Registry.INSTANCE), + stack); + + mapResourceSet(result); + + configure(result); + return result; + } + + public TransactionalEditingDomain createEditingDomain(ResourceSet rset) { + TransactionalEditingDomain result = createEditingDomain( + rset, + OperationHistoryFactory.getOperationHistory()); + configure(result); + return result; + } + + public TransactionalEditingDomain createEditingDomain(ResourceSet rset, IOperationHistory history) { + WorkspaceCommandStackImpl stack = new WorkspaceCommandStackImpl(history); + + TransactionalEditingDomain result = new DiagramEditingDomain( + new ComposedAdapterFactory( + ComposedAdapterFactory.Descriptor.Registry.INSTANCE), + stack, + rset); + + mapResourceSet(result); + configure(result); + return result; + } } Index: src/org/eclipse/gmf/runtime/diagram/core/listener/DiagramEventBroker.java =================================================================== RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.runtime.diagram.core/src/org/eclipse/gmf/runtime/diagram/core/listener/DiagramEventBroker.java,v retrieving revision 1.10 diff -u -r1.10 DiagramEventBroker.java --- src/org/eclipse/gmf/runtime/diagram/core/listener/DiagramEventBroker.java 9 Mar 2006 20:51:39 -0000 1.10 +++ src/org/eclipse/gmf/runtime/diagram/core/listener/DiagramEventBroker.java 22 Mar 2006 19:55:29 -0000 @@ -322,7 +322,7 @@ Collection listenerList = getInterestedNotificationListeners(event, true); CompoundCommand cc = new CompoundCommand(); - preparePersistCommand(event,cc); + //preparePersistCommand(event,cc); if (!listenerList.isEmpty()) { List listenersSnapShot = new ArrayList(listenerList); if (!listenerList.isEmpty()) { @@ -583,9 +583,13 @@ } return listenerSet; } - + public boolean isAggregatePrecommitListener() { - return true; + return true; + } + + public boolean isPrecommitOnly() { + return true; } /** @@ -636,10 +640,24 @@ * the event to handle */ private void handleElementEvent(Notification event) { - EObject element = (EObject) event.getNotifier(); - if (element != null) { - fireNotification(event); - } + if (!event.isTouch()) { + EObject element = (EObject) event.getNotifier(); + while (element != null && !(element instanceof View)) { + element = element.eContainer(); + } + if (element != null && + (NotationPackage.eINSTANCE.getView_TransientChildren()==element.eContainingFeature() || + NotationPackage.eINSTANCE.getDiagram_TransientEdges()==element.eContainingFeature())) { + if (!NotificationFilter.READ.matches(event)) { + ViewUtil.persistElement((View) element); + } + } + } + + EObject element = (EObject) event.getNotifier(); + if (element != null) { + fireNotification(event); + } } /** Index: src/org/eclipse/gmf/runtime/diagram/core/util/ViewUtil.java =================================================================== RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.runtime.diagram.core/src/org/eclipse/gmf/runtime/diagram/core/util/ViewUtil.java,v retrieving revision 1.13 diff -u -r1.13 ViewUtil.java --- src/org/eclipse/gmf/runtime/diagram/core/util/ViewUtil.java 20 Mar 2006 21:06:44 -0000 1.13 +++ src/org/eclipse/gmf/runtime/diagram/core/util/ViewUtil.java 22 Mar 2006 19:55:29 -0000 @@ -99,6 +99,7 @@ new PersistElementCommand(editingDomain, viewToPersist); try { pvc.execute( new NullProgressMonitor(), null ); + } catch (ExecutionException e) { Trace.catching(DiagramPlugin.getInstance(), DiagramDebugOptions.EXCEPTIONS_CATCHING, #P org.eclipse.gmf.runtime.emf.commands.core Index: src/org/eclipse/gmf/runtime/emf/commands/core/command/AbstractTransactionalCommand.java =================================================================== RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.runtime.emf.commands.core/src/org/eclipse/gmf/runtime/emf/commands/core/command/AbstractTransactionalCommand.java,v retrieving revision 1.1 diff -u -r1.1 AbstractTransactionalCommand.java --- src/org/eclipse/gmf/runtime/emf/commands/core/command/AbstractTransactionalCommand.java 13 Feb 2006 19:11:05 -0000 1.1 +++ src/org/eclipse/gmf/runtime/emf/commands/core/command/AbstractTransactionalCommand.java 22 Mar 2006 19:55:30 -0000 @@ -30,7 +30,9 @@ import org.eclipse.core.runtime.Status; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.transaction.Transaction; import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.util.CompositeChangeDescription; import org.eclipse.emf.workspace.AbstractEMFOperation; import org.eclipse.emf.workspace.util.WorkspaceSynchronizer; import org.eclipse.gmf.runtime.common.core.command.CMValidator; @@ -222,6 +224,22 @@ IProgressMonitor monitor, IAdaptable info) throws ExecutionException; + protected void didUndo(Transaction tx) { + // We will amalgamate any change description that were added by the DiagramEditingDomain's + // special post-commit listener. See DiagramEditingDomainFactory for more details. + if (tx.getChangeDescription() != null && !tx.getChangeDescription().isEmpty()) { + ((CompositeChangeDescription)getChange()).add(tx.getChangeDescription()); + } + } + + protected void didRedo(Transaction tx) { + // We will amalgamate any change description that were added by the DiagramEditingDomain's + // special post-commit listener. See DiagramEditingDomainFactory for more details. + if (tx.getChangeDescription() != null && !tx.getChangeDescription().isEmpty()) { + ((CompositeChangeDescription)getChange()).add(tx.getChangeDescription()); + } + } + /** * Delegates to {@link #doExecuteWithResult(IProgressMonitor, IAdaptable)} * to perform the model changes. Sets the command result and calls #P org.eclipse.gmf.runtime.emf.core.compatibility Index: src/org/eclipse/gmf/runtime/emf/core/internal/domain/MSLUndoInterval.java =================================================================== RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.runtime.emf.core.compatibility/src/org/eclipse/gmf/runtime/emf/core/internal/domain/MSLUndoInterval.java,v retrieving revision 1.2 diff -u -r1.2 MSLUndoInterval.java --- src/org/eclipse/gmf/runtime/emf/core/internal/domain/MSLUndoInterval.java 16 Mar 2006 17:43:34 -0000 1.2 +++ src/org/eclipse/gmf/runtime/emf/core/internal/domain/MSLUndoInterval.java 22 Mar 2006 19:55:32 -0000 @@ -15,7 +15,7 @@ import org.eclipse.emf.transaction.RollbackException; import org.eclipse.emf.transaction.Transaction; import org.eclipse.emf.transaction.TransactionChangeDescription; -import org.eclipse.emf.transaction.impl.TransactionalCommandStackImpl; +import org.eclipse.emf.transaction.impl.TransactionImpl; import org.eclipse.emf.transaction.util.CompositeChangeDescription; import org.eclipse.gmf.runtime.emf.core.edit.MUndoInterval; import org.eclipse.gmf.runtime.emf.core.exceptions.MSLRuntimeException; @@ -42,7 +42,7 @@ static { UNDO_REDO_OPTIONS = new java.util.HashMap( - TransactionalCommandStackImpl.UNDO_REDO_OPTIONS); + TransactionImpl.DEFAULT_UNDO_REDO_OPTIONS); // add the unprotected option because MSL allows undo/redo in a // read action (read-only transaction) Index: src/org/eclipse/gmf/runtime/emf/core/internal/domain/MSLEditingDomain.java =================================================================== RCS file: /cvsroot/technology/org.eclipse.gmf/plugins/org.eclipse.gmf.runtime.emf.core.compatibility/src/org/eclipse/gmf/runtime/emf/core/internal/domain/MSLEditingDomain.java,v retrieving revision 1.3 diff -u -r1.3 MSLEditingDomain.java --- src/org/eclipse/gmf/runtime/emf/core/internal/domain/MSLEditingDomain.java 15 Mar 2006 17:21:49 -0000 1.3 +++ src/org/eclipse/gmf/runtime/emf/core/internal/domain/MSLEditingDomain.java 22 Mar 2006 19:55:32 -0000 @@ -69,6 +69,7 @@ import org.eclipse.emf.transaction.impl.InternalTransaction; import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain; import org.eclipse.emf.transaction.impl.TransactionChangeRecorder; +import org.eclipse.emf.transaction.impl.TransactionImpl; import org.eclipse.emf.transaction.impl.TransactionValidator; import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl; import org.eclipse.gmf.runtime.common.core.util.Trace; @@ -2347,4 +2348,8 @@ public TransactionalEditingDomain getDelegate() { return delegate; } + + public Map getUndoRedoOptions() { + return TransactionImpl.DEFAULT_UNDO_REDO_OPTIONS; + } } \ No newline at end of file