View | Details | Raw Unified | Return to bug 132367 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/gmf/tests/runtime/diagram/ui/AllTests.java (+1 lines)
Lines 73-78 Link Here
73
		suite.addTest(RequestTests.suite());
73
		suite.addTest(RequestTests.suite());
74
		suite.addTest(ConnectionToolTests.suite());
74
		suite.addTest(ConnectionToolTests.suite());
75
        suite.addTest(CopyToImageUtilTests.suite());
75
        suite.addTest(CopyToImageUtilTests.suite());
76
        suite.addTest(DiagramEditingDomainTestCase.suite());
76
		
77
		
77
		return suite;
78
		return suite;
78
	}
79
	}
(-)src/org/eclipse/gmf/tests/runtime/diagram/ui/DiagramEditingDomainTestCase.java (+119 lines)
Added Link Here
1
package org.eclipse.gmf.tests.runtime.diagram.ui;
2
3
import junit.framework.Test;
4
import junit.framework.TestCase;
5
import junit.framework.TestSuite;
6
7
import org.eclipse.core.commands.ExecutionException;
8
import org.eclipse.core.runtime.IAdaptable;
9
import org.eclipse.core.runtime.IProgressMonitor;
10
import org.eclipse.core.runtime.NullProgressMonitor;
11
import org.eclipse.emf.common.notify.Notification;
12
import org.eclipse.emf.common.util.URI;
13
import org.eclipse.emf.ecore.EClass;
14
import org.eclipse.emf.ecore.EcoreFactory;
15
import org.eclipse.emf.ecore.EcorePackage;
16
import org.eclipse.emf.ecore.resource.Resource;
17
import org.eclipse.emf.transaction.ResourceSetChangeEvent;
18
import org.eclipse.emf.transaction.ResourceSetListenerImpl;
19
import org.eclipse.emf.transaction.TransactionalEditingDomain;
20
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
21
import org.eclipse.gmf.runtime.diagram.core.DiagramEditingDomainFactory;
22
import org.eclipse.gmf.runtime.diagram.core.listener.DiagramEventBroker;
23
import org.eclipse.gmf.runtime.diagram.core.listener.NotificationListener;
24
import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
25
26
27
public class DiagramEditingDomainTestCase
28
	extends TestCase {
29
30
	EClass eCls;
31
	
32
	public void testDiagramEventBrokerAsSpecialListener() {
33
		final TransactionalEditingDomain domain = DiagramEditingDomainFactory.getInstance().createEditingDomain();
34
		final Resource r = domain.getResourceSet().createResource(URI.createURI("file:///foo.logic2"));
35
		eCls = EcoreFactory.eINSTANCE.createEClass();
36
		eCls.setName("");
37
		
38
		// Set up the resource contents.
39
		try {
40
			new AbstractTransactionalCommand(domain, "Setup", null) {
41
				protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info)
42
					throws ExecutionException {
43
					
44
					r.getContents().add(eCls);
45
					
46
					return CommandResult.newOKCommandResult();
47
				}
48
			}.execute(new NullProgressMonitor(),null);
49
		} catch (ExecutionException e) {
50
			fail();
51
		}
52
		
53
		DiagramEventBroker.startListening(domain);
54
		DiagramEventBroker.getInstance(domain).addNotificationListener(eCls, new NotificationListener() {
55
			public void notifyChanged(Notification notification) {
56
				if (notification.getNotifier() == eCls && notification.getFeature() == EcorePackage.eINSTANCE.getENamedElement_Name()) {
57
					try {
58
						new AbstractTransactionalCommand(domain, "Add Attribute", null) {
59
							protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info)
60
								throws ExecutionException {
61
								
62
								eCls.getEStructuralFeatures().add(EcoreFactory.eINSTANCE.createEAttribute());
63
								
64
								return CommandResult.newOKCommandResult();
65
							}
66
							
67
						}.execute(new NullProgressMonitor(),null);
68
					} catch (ExecutionException e) {
69
						fail();
70
					}
71
				}
72
			}
73
		});
74
		
75
		AbstractTransactionalCommand cmd = new AbstractTransactionalCommand(domain, "Set Name", null) {
76
			protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info)
77
				throws ExecutionException {
78
				eCls.setName("foo");
79
				
80
				return CommandResult.newOKCommandResult();
81
			}
82
		};
83
		
84
		final boolean[] regularListenerWasCalled = new boolean[1];
85
		final boolean[] notificationsWereEmpty = new boolean[1];
86
		regularListenerWasCalled[0] = false;
87
		notificationsWereEmpty[0] = true;
88
		
89
		domain.addResourceSetListener(new ResourceSetListenerImpl() {
90
			public boolean isPostcommitOnly() {
91
				return true;
92
			}
93
			
94
			public void resourceSetChanged(ResourceSetChangeEvent event) {
95
				regularListenerWasCalled[0] = true;
96
				notificationsWereEmpty[0] = event.getNotifications().isEmpty();
97
			}
98
		});
99
		
100
		try {
101
			cmd.execute(new NullProgressMonitor(),null);
102
			cmd.undo(new NullProgressMonitor(),null);
103
			cmd.redo(new NullProgressMonitor(), null);
104
			cmd.undo(new NullProgressMonitor(),null);
105
			cmd.redo(new NullProgressMonitor(),null);
106
		} catch (ExecutionException e) {
107
			fail();
108
		}
109
110
		assertSame(eCls.eResource(),r);
111
		assertEquals(3,eCls.getEStructuralFeatures().size());
112
		assertTrue(regularListenerWasCalled[0]);
113
		assertFalse(notificationsWereEmpty[0]);
114
	}
115
116
	public static Test suite() {
117
		return new TestSuite(DiagramEditingDomainTestCase.class);
118
	}
119
}
(-)src/org/eclipse/gmf/runtime/diagram/core/DiagramEditingDomainFactory.java (-1 / +168 lines)
Lines 11-19 Link Here
11
11
12
package org.eclipse.gmf.runtime.diagram.core;
12
package org.eclipse.gmf.runtime.diagram.core;
13
13
14
import java.util.ArrayList;
15
import java.util.HashMap;
16
import java.util.List;
17
import java.util.Map;
18
19
import org.eclipse.core.commands.operations.IOperationHistory;
20
import org.eclipse.core.commands.operations.OperationHistoryFactory;
21
import org.eclipse.emf.common.notify.AdapterFactory;
22
import org.eclipse.emf.ecore.resource.ResourceSet;
23
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
24
import org.eclipse.emf.transaction.ResourceSetChangeEvent;
25
import org.eclipse.emf.transaction.ResourceSetListener;
26
import org.eclipse.emf.transaction.RollbackException;
27
import org.eclipse.emf.transaction.Transaction;
28
import org.eclipse.emf.transaction.TransactionalCommandStack;
14
import org.eclipse.emf.transaction.TransactionalEditingDomain;
29
import org.eclipse.emf.transaction.TransactionalEditingDomain;
30
import org.eclipse.emf.transaction.impl.FilterManager;
31
import org.eclipse.emf.transaction.impl.InternalTransaction;
32
import org.eclipse.emf.transaction.impl.ReadWriteValidatorImpl;
33
import org.eclipse.emf.transaction.impl.TransactionValidator;
34
import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl;
35
import org.eclipse.emf.transaction.util.CompositeChangeDescription;
15
import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory;
36
import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory;
37
import org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl;
16
import org.eclipse.gmf.runtime.diagram.core.internal.listener.NotationSemProc;
38
import org.eclipse.gmf.runtime.diagram.core.internal.listener.NotationSemProc;
39
import org.eclipse.gmf.runtime.diagram.core.listener.DiagramEventBroker;
17
import org.eclipse.gmf.runtime.emf.core.GMFEditingDomainFactory;
40
import org.eclipse.gmf.runtime.emf.core.GMFEditingDomainFactory;
18
41
19
42
Lines 21-33 Link Here
21
 * Factory for {@link TransactionalEditingDomain}s that are properly configured
44
 * Factory for {@link TransactionalEditingDomain}s that are properly configured
22
 * to support a GMF diagram application. This factory should be preferred over
45
 * to support a GMF diagram application. This factory should be preferred over
23
 * the {@link GMFEditingDomainFactory} because it attaches a listener required
46
 * the {@link GMFEditingDomainFactory} because it attaches a listener required
24
 * to update the notation model after changes to the semantic model.
47
 * to update the notation model after changes to the semantic model. Also, it
48
 * handles special use cases involving the DiagramEventBroker.
25
 * 
49
 * 
26
 * @author cmahoney
50
 * @author cmahoney
27
 */
51
 */
28
public class DiagramEditingDomainFactory
52
public class DiagramEditingDomainFactory
29
    extends GMFEditingDomainFactory {
53
    extends GMFEditingDomainFactory {
54
	
55
	private static class DiagramEditingDomain extends TransactionalEditingDomainImpl {
56
		// The following variable acts as a special latch for the DiagramEventBroker
57
		//  listener so that we can allow it to execute in a write transaction context
58
		//  while handling a post-commit event.
59
		private InternalTransaction originatingTransaction = null;
60
		private DiagramEventBroker deb = null;
61
		
62
		public void addResourceSetListener(ResourceSetListener l) {
63
			if (l.getClass() == DiagramEventBroker.class) {
64
				assert deb == null;
65
				deb = (DiagramEventBroker)l;
66
			}
67
			
68
			super.addResourceSetListener(l);
69
		}
70
		
71
		public void removeResourceSetListener(ResourceSetListener l) {
72
			if (l.getClass() == DiagramEventBroker.class) {
73
				assert deb != null;
74
				deb = null;
75
			}
76
			
77
			super.removeResourceSetListener(l);
78
		}
79
		
80
		public DiagramEditingDomain(AdapterFactory adapterFactory, ResourceSet resourceSet) {
81
			super(adapterFactory, resourceSet);
82
		}
83
84
		public DiagramEditingDomain(AdapterFactory adapterFactory, TransactionalCommandStack stack, ResourceSet resourceSet) {
85
			super(adapterFactory, stack, resourceSet);
86
		}
87
88
		public DiagramEditingDomain(AdapterFactory adapterFactory, TransactionalCommandStack stack) {
89
			super(adapterFactory, stack);
90
		}
30
91
92
		public DiagramEditingDomain(AdapterFactory adapterFactory) {
93
			super(adapterFactory);
94
		}
95
		
96
		protected void postcommit(InternalTransaction tx) {
97
			try {
98
				List notifications = getValidator().getNotificationsForPostcommit(tx);
99
				
100
				if (deb != null && notifications != null && !notifications.isEmpty()) {	
101
					TransactionValidator originalValidator = null;
102
					
103
					// Set the latch if it has not yet been set
104
					if (originatingTransaction == null) {
105
						originatingTransaction = tx;
106
						originalValidator = getValidator();
107
						setValidator(new ReadWriteValidatorImpl());
108
					} else {
109
						// In this case we must copy over the notifications and change
110
						//  descriptions to the originatingTransaction.
111
						((CompositeChangeDescription)originatingTransaction.getChangeDescription()).add(tx.getChangeDescription());
112
						originatingTransaction.getNotifications().addAll(notifications);
113
					}
114
					
115
					try {
116
						ArrayList cache = new ArrayList(notifications.size());
117
						
118
						List filtered = FilterManager.getInstance().select(
119
							notifications,
120
							deb.getFilter(),
121
							cache);
122
						
123
						HashMap options = new HashMap(originatingTransaction.getOptions());
124
						options.put(Transaction.OPTION_NO_UNDO, Boolean.FALSE);
125
						InternalTransaction newTx = startTransaction(false, options);
126
						deb.resourceSetChanged(
127
							new ResourceSetChangeEvent(
128
								this,
129
								tx,
130
								filtered));
131
132
						newTx.commit();
133
					} catch (RollbackException e) {
134
						// Do nothing in the rollback case, we have no change descriptions
135
						//  or notifications to propagate.
136
					} finally {
137
						// Undo the latch if we are top-most in the recursion.
138
						if (originatingTransaction == tx) {
139
							originatingTransaction = null;
140
							getValidator().dispose();
141
							setValidator(originalValidator);
142
						}
143
					}
144
				}
145
			} catch (InterruptedException e) {
146
				// Simply fall-through in this case and allow the post commit listeners
147
				//  to be notified.
148
			}
149
			
150
			// We will only call super on the top-most in the recursion.
151
			if (originatingTransaction == null) {
152
				super.postcommit(tx);
153
			}
154
		}
155
	}
156
	
31
    /**
157
    /**
32
     * The single shared instance of the GMF diagram editing domain factory.
158
     * The single shared instance of the GMF diagram editing domain factory.
33
     */
159
     */
Lines 50-53 Link Here
50
        domain.addResourceSetListener(new NotationSemProc());
176
        domain.addResourceSetListener(new NotationSemProc());
51
    }
177
    }
52
178
179
    public TransactionalEditingDomain createEditingDomain() {
180
		TransactionalEditingDomain result = createEditingDomain(OperationHistoryFactory.getOperationHistory());
181
		configure(result);
182
		return result;
183
    }
184
    
185
    public TransactionalEditingDomain createEditingDomain(IOperationHistory history) {
186
		WorkspaceCommandStackImpl stack = new WorkspaceCommandStackImpl(history);
187
		
188
		TransactionalEditingDomain result = new DiagramEditingDomain(
189
			new ComposedAdapterFactory(
190
				ComposedAdapterFactory.Descriptor.Registry.INSTANCE),
191
			stack);
192
		
193
		mapResourceSet(result);
194
		
195
		configure(result);
196
		return result;
197
    }
198
    
199
    public TransactionalEditingDomain createEditingDomain(ResourceSet rset) {
200
		TransactionalEditingDomain result = createEditingDomain(
201
			rset,
202
			OperationHistoryFactory.getOperationHistory());
203
		configure(result);
204
		return result;
205
    }
206
    
207
    public TransactionalEditingDomain createEditingDomain(ResourceSet rset, IOperationHistory history) {
208
		WorkspaceCommandStackImpl stack = new WorkspaceCommandStackImpl(history);
209
		
210
		TransactionalEditingDomain result = new DiagramEditingDomain(
211
			new ComposedAdapterFactory(
212
				ComposedAdapterFactory.Descriptor.Registry.INSTANCE),
213
			stack,
214
			rset);
215
		
216
		mapResourceSet(result);
217
		configure(result);
218
		return result;
219
    }
53
}
220
}
(-)src/org/eclipse/gmf/runtime/diagram/core/listener/DiagramEventBroker.java (-7 / +25 lines)
Lines 322-328 Link Here
322
        Collection listenerList = getInterestedNotificationListeners(event,
322
        Collection listenerList = getInterestedNotificationListeners(event,
323
            true);
323
            true);
324
        CompoundCommand cc = new CompoundCommand();
324
        CompoundCommand cc = new CompoundCommand();
325
        preparePersistCommand(event,cc);
325
        //preparePersistCommand(event,cc);
326
        if (!listenerList.isEmpty()) {
326
        if (!listenerList.isEmpty()) {
327
            List listenersSnapShot = new ArrayList(listenerList);
327
            List listenersSnapShot = new ArrayList(listenerList);
328
            if (!listenerList.isEmpty()) {
328
            if (!listenerList.isEmpty()) {
Lines 583-591 Link Here
583
        }
583
        }
584
        return listenerSet;
584
        return listenerSet;
585
    }
585
    }
586
586
    
587
    public boolean isAggregatePrecommitListener() {
587
    public boolean isAggregatePrecommitListener() {
588
        return true;
588
    	return true;
589
    }
590
    
591
    public boolean isPrecommitOnly() {
592
    	return true;
589
    }
593
    }
590
594
591
    /**
595
    /**
Lines 636-645 Link Here
636
     *            the event to handle
640
     *            the event to handle
637
     */
641
     */
638
    private void handleElementEvent(Notification event) {
642
    private void handleElementEvent(Notification event) {
639
       EObject element = (EObject) event.getNotifier();
643
		if (!event.isTouch()) {
640
        if (element != null) {
644
			EObject element = (EObject) event.getNotifier();
641
            fireNotification(event);
645
			while (element != null && !(element instanceof View)) {
642
        }
646
				element = element.eContainer();
647
			}
648
			if (element != null && 
649
                (NotationPackage.eINSTANCE.getView_TransientChildren()==element.eContainingFeature() ||
650
                 NotationPackage.eINSTANCE.getDiagram_TransientEdges()==element.eContainingFeature())) {
651
                if (!NotificationFilter.READ.matches(event)) {
652
                    ViewUtil.persistElement((View) element);
653
                }
654
			}
655
		}
656
657
		EObject element = (EObject) event.getNotifier();
658
		if (element != null) {
659
			fireNotification(event);
660
		}
643
    }
661
    }
644
662
645
    /**
663
    /**
(-)src/org/eclipse/gmf/runtime/diagram/core/util/ViewUtil.java (+1 lines)
Lines 99-104 Link Here
99
					new PersistElementCommand(editingDomain, viewToPersist);
99
					new PersistElementCommand(editingDomain, viewToPersist);
100
                try {
100
                try {
101
                    pvc.execute( new NullProgressMonitor(), null );
101
                    pvc.execute( new NullProgressMonitor(), null );
102
                    
102
                } catch (ExecutionException e) {
103
                } catch (ExecutionException e) {
103
                    Trace.catching(DiagramPlugin.getInstance(),
104
                    Trace.catching(DiagramPlugin.getInstance(),
104
                        DiagramDebugOptions.EXCEPTIONS_CATCHING,
105
                        DiagramDebugOptions.EXCEPTIONS_CATCHING,
(-)src/org/eclipse/gmf/runtime/emf/commands/core/command/AbstractTransactionalCommand.java (+18 lines)
Lines 30-36 Link Here
30
import org.eclipse.core.runtime.Status;
30
import org.eclipse.core.runtime.Status;
31
import org.eclipse.emf.ecore.EObject;
31
import org.eclipse.emf.ecore.EObject;
32
import org.eclipse.emf.ecore.resource.Resource;
32
import org.eclipse.emf.ecore.resource.Resource;
33
import org.eclipse.emf.transaction.Transaction;
33
import org.eclipse.emf.transaction.TransactionalEditingDomain;
34
import org.eclipse.emf.transaction.TransactionalEditingDomain;
35
import org.eclipse.emf.transaction.util.CompositeChangeDescription;
34
import org.eclipse.emf.workspace.AbstractEMFOperation;
36
import org.eclipse.emf.workspace.AbstractEMFOperation;
35
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
37
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
36
import org.eclipse.gmf.runtime.common.core.command.CMValidator;
38
import org.eclipse.gmf.runtime.common.core.command.CMValidator;
Lines 222-227 Link Here
222
            IProgressMonitor monitor, IAdaptable info)
224
            IProgressMonitor monitor, IAdaptable info)
223
        throws ExecutionException;
225
        throws ExecutionException;
224
226
227
    protected void didUndo(Transaction tx) {
228
    	// We will amalgamate any change description that were added by the DiagramEditingDomain's
229
    	//  special post-commit listener. See DiagramEditingDomainFactory for more details.
230
    	if (tx.getChangeDescription() != null && !tx.getChangeDescription().isEmpty()) {
231
    		((CompositeChangeDescription)getChange()).add(tx.getChangeDescription());
232
    	}
233
    }
234
    
235
    protected void didRedo(Transaction tx) {
236
    	// We will amalgamate any change description that were added by the DiagramEditingDomain's
237
    	//  special post-commit listener. See DiagramEditingDomainFactory for more details.
238
    	if (tx.getChangeDescription() != null && !tx.getChangeDescription().isEmpty()) {
239
    		((CompositeChangeDescription)getChange()).add(tx.getChangeDescription());
240
    	}
241
    }
242
    
225
    /**
243
    /**
226
     * Delegates to {@link #doExecuteWithResult(IProgressMonitor, IAdaptable)}
244
     * Delegates to {@link #doExecuteWithResult(IProgressMonitor, IAdaptable)}
227
     * to perform the model changes. Sets the command result and calls
245
     * to perform the model changes. Sets the command result and calls
(-)src/org/eclipse/gmf/runtime/emf/core/internal/domain/MSLUndoInterval.java (-2 / +2 lines)
Lines 15-21 Link Here
15
import org.eclipse.emf.transaction.RollbackException;
15
import org.eclipse.emf.transaction.RollbackException;
16
import org.eclipse.emf.transaction.Transaction;
16
import org.eclipse.emf.transaction.Transaction;
17
import org.eclipse.emf.transaction.TransactionChangeDescription;
17
import org.eclipse.emf.transaction.TransactionChangeDescription;
18
import org.eclipse.emf.transaction.impl.TransactionalCommandStackImpl;
18
import org.eclipse.emf.transaction.impl.TransactionImpl;
19
import org.eclipse.emf.transaction.util.CompositeChangeDescription;
19
import org.eclipse.emf.transaction.util.CompositeChangeDescription;
20
import org.eclipse.gmf.runtime.emf.core.edit.MUndoInterval;
20
import org.eclipse.gmf.runtime.emf.core.edit.MUndoInterval;
21
import org.eclipse.gmf.runtime.emf.core.exceptions.MSLRuntimeException;
21
import org.eclipse.gmf.runtime.emf.core.exceptions.MSLRuntimeException;
Lines 42-48 Link Here
42
	
42
	
43
	static {
43
	static {
44
		UNDO_REDO_OPTIONS = new java.util.HashMap(
44
		UNDO_REDO_OPTIONS = new java.util.HashMap(
45
			TransactionalCommandStackImpl.UNDO_REDO_OPTIONS);
45
			TransactionImpl.DEFAULT_UNDO_REDO_OPTIONS);
46
		
46
		
47
		// add the unprotected option because MSL allows undo/redo in a
47
		// add the unprotected option because MSL allows undo/redo in a
48
		//     read action (read-only transaction)
48
		//     read action (read-only transaction)
(-)src/org/eclipse/gmf/runtime/emf/core/internal/domain/MSLEditingDomain.java (+5 lines)
Lines 69-74 Link Here
69
import org.eclipse.emf.transaction.impl.InternalTransaction;
69
import org.eclipse.emf.transaction.impl.InternalTransaction;
70
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
70
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
71
import org.eclipse.emf.transaction.impl.TransactionChangeRecorder;
71
import org.eclipse.emf.transaction.impl.TransactionChangeRecorder;
72
import org.eclipse.emf.transaction.impl.TransactionImpl;
72
import org.eclipse.emf.transaction.impl.TransactionValidator;
73
import org.eclipse.emf.transaction.impl.TransactionValidator;
73
import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl;
74
import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl;
74
import org.eclipse.gmf.runtime.common.core.util.Trace;
75
import org.eclipse.gmf.runtime.common.core.util.Trace;
Lines 2347-2350 Link Here
2347
    public TransactionalEditingDomain getDelegate() {
2348
    public TransactionalEditingDomain getDelegate() {
2348
        return delegate;
2349
        return delegate;
2349
    }
2350
    }
2351
2352
	public Map getUndoRedoOptions() {
2353
		return TransactionImpl.DEFAULT_UNDO_REDO_OPTIONS;
2354
	}
2350
}
2355
}

Return to bug 132367