Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 240775
Collapse All | Expand All

(-)src/org/eclipse/emf/workspace/ResourceUndoContext.java (-115 / +19 lines)
Lines 1-7 Link Here
1
/**
1
/**
2
 * <copyright>
2
 * <copyright>
3
 *
3
 *
4
 * Copyright (c) 2005, 2008 IBM Corporation and others.
4
 * Copyright (c) 2005, 2008 IBM Corporation, Zeligsoft Inc., and others.
5
 * All rights reserved.   This program and the accompanying materials
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
7
 * which accompanies this distribution, and is available at
Lines 9-14 Link Here
9
 *
9
 *
10
 * Contributors:
10
 * Contributors:
11
 *   IBM - Initial API and implementation
11
 *   IBM - Initial API and implementation
12
 *   Zeligsoft - Bug 240775
12
 *
13
 *
13
 * </copyright>
14
 * </copyright>
14
 *
15
 *
Lines 16-22 Link Here
16
 */
17
 */
17
package org.eclipse.emf.workspace;
18
package org.eclipse.emf.workspace;
18
19
19
import java.util.Collection;
20
import java.util.Collections;
20
import java.util.Collections;
21
import java.util.List;
21
import java.util.List;
22
import java.util.Set;
22
import java.util.Set;
Lines 24-31 Link Here
24
import org.eclipse.core.commands.operations.IUndoContext;
24
import org.eclipse.core.commands.operations.IUndoContext;
25
import org.eclipse.core.commands.operations.IUndoableOperation;
25
import org.eclipse.core.commands.operations.IUndoableOperation;
26
import org.eclipse.emf.common.notify.Notification;
26
import org.eclipse.emf.common.notify.Notification;
27
import org.eclipse.emf.ecore.EObject;
28
import org.eclipse.emf.ecore.EReference;
29
import org.eclipse.emf.ecore.resource.Resource;
27
import org.eclipse.emf.ecore.resource.Resource;
30
import org.eclipse.emf.transaction.TransactionalEditingDomain;
28
import org.eclipse.emf.transaction.TransactionalEditingDomain;
31
import org.eclipse.emf.workspace.internal.l10n.Messages;
29
import org.eclipse.emf.workspace.internal.l10n.Messages;
Lines 123-171 Link Here
123
	 * Analyzes a list of notifications to extract the set of {@link Resource}s
121
	 * Analyzes a list of notifications to extract the set of {@link Resource}s
124
	 * affected by the changes.
122
	 * affected by the changes.
125
	 * 
123
	 * 
126
	 * @param notifications a list of {@link Notification}s indicating changes
124
	 * @param notifications
127
	 *     in a resource set
125
	 *            a list of {@link Notification}s indicating changes in a
128
	 *     
126
	 *            resource set
129
	 * @return the resources affected by the specified notifications.
127
	 * 
130
	 *     The resulting set should be treated as unmodifiable
128
	 * @return the resources affected by the specified notifications. The
129
	 *         resulting set should be treated as unmodifiable
130
	 * 
131
	 * @deprecated Since the 1.3 release, use the
132
	 *             {@link IResourceUndoContextPolicy#getContextResources(IUndoableOperation, List)}
133
	 *             method of the editing domain's resource undo-context policy,
134
	 *             instead
131
	 */
135
	 */
132
	public static Set<Resource> getAffectedResources(
136
	public static Set<Resource> getAffectedResources(
133
			List<? extends Notification> notifications) {
137
			List<? extends Notification> notifications) {
134
		
138
135
		Set<Resource> result;
139
		// the default implementation never considers the operation, so a
136
		
140
		// null value will not hurt it
137
		if (notifications.isEmpty()) {
141
		return IResourceUndoContextPolicy.DEFAULT.getContextResources(null,
138
			result = Collections.emptySet();
142
			notifications);
139
		} else {
140
			result = new java.util.HashSet<Resource>();
141
			
142
			for (Notification next : notifications) {
143
				Object notifier = next.getNotifier();
144
				
145
				if (notifier instanceof Resource) {
146
					result.add((Resource) notifier);
147
				} else if (notifier instanceof EObject) {
148
					EObject eobj = (EObject) notifier;
149
                    Resource resource = eobj.eResource();
150
                    
151
                    if (resource != null) {
152
                        result.add(resource);
153
                    }
154
					
155
					// if the reference has an opposite, then we will get the
156
					//   notification from the other end, anyway
157
					final Object feature = next.getFeature();
158
					if ((feature instanceof EReference)
159
							&& (((EReference) feature).getEOpposite() == null)) {
160
						handleCrossResourceReference(result, next);
161
					}
162
				}
163
			}
164
		}
165
		
166
		return result;
167
	}
143
	}
168
	
144
169
	/**
145
	/**
170
	 * Extracts the set of EMF {@link Resource}s affected by the specified
146
	 * Extracts the set of EMF {@link Resource}s affected by the specified
171
	 * operation, from the <code>ResourceUndoContext</code>s attached to it.
147
	 * operation, from the <code>ResourceUndoContext</code>s attached to it.
Lines 194-271 Link Here
194
		return result;
170
		return result;
195
	}
171
	}
196
	
172
	
197
	/**
198
	 * Handles notifications that can potentially represent cross-resource
199
	 * references.  Helper to the {@link #getAffectedResources(List)} method.
200
	 * 
201
	 * @param resources collects the affected resources
202
	 * @param notification a potential cross-resource reference change notification
203
	 */
204
	private static void handleCrossResourceReference(
205
			Set<Resource> resources,
206
			Notification notification) {
207
		
208
		Object oldValue = notification.getOldValue();
209
		Object newValue = notification.getNewValue();
210
        Resource resource;
211
		
212
		switch (notification.getEventType()) {
213
		case Notification.SET:
214
		case Notification.UNSET:
215
			if (oldValue != null) {
216
                resource = ((EObject) oldValue).eResource();
217
                
218
                if (resource != null) {
219
                    resources.add(resource);
220
                }
221
			}
222
			if (newValue != null) {
223
                resource = ((EObject) newValue).eResource();
224
                
225
                if (resource != null) {
226
                    resources.add(resource);
227
                }
228
			}
229
			break;
230
		case Notification.ADD:
231
            resource = ((EObject) newValue).eResource();
232
            
233
            if (resource != null) {
234
                resources.add(resource);
235
            }
236
			break;
237
		case Notification.ADD_MANY: {
238
		    @SuppressWarnings("unchecked")
239
		    Collection<EObject> newReferences = (Collection<EObject>) newValue;
240
			for (EObject next : newReferences) {
241
                resource = next.eResource();
242
                
243
                if (resource != null) {
244
                    resources.add(resource);
245
                }
246
			}
247
			break;}
248
		case Notification.REMOVE:
249
            resource = ((EObject) oldValue).eResource();
250
            
251
            if (resource != null) {
252
                resources.add(resource);
253
            }
254
			break;
255
		case Notification.REMOVE_MANY: {
256
            @SuppressWarnings("unchecked")
257
            Collection<EObject> oldReferences = (Collection<EObject>) oldValue;
258
            for (EObject next : oldReferences) {
259
                resource = next.eResource();
260
                
261
                if (resource != null) {
262
                    resources.add(resource);
263
                }
264
			}
265
			break;}
266
		}
267
	}
268
	
269
	@Override
173
	@Override
270
	public String toString() {
174
	public String toString() {
271
	    return getLabel();
175
	    return getLabel();
(-)src/org/eclipse/emf/workspace/WorkspaceEditingDomainFactory.java (-6 / +31 lines)
Lines 1-7 Link Here
1
/**
1
/**
2
 * <copyright>
2
 * <copyright>
3
 *
3
 *
4
 * Copyright (c) 2005, 2007 IBM Corporation and others.
4
 * Copyright (c) 2005, 2008 IBM Corporation, Zeligoft Inc., and others.
5
 * All rights reserved.   This program and the accompanying materials
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
7
 * which accompanies this distribution, and is available at
Lines 9-14 Link Here
9
 *
9
 *
10
 * Contributors:
10
 * Contributors:
11
 *   IBM - Initial API and implementation
11
 *   IBM - Initial API and implementation
12
 *   Zeligsoft - Bug 240775
12
 *
13
 *
13
 * </copyright>
14
 * </copyright>
14
 *
15
 *
Lines 25-33 Link Here
25
import org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl;
26
import org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl;
26
27
27
/**
28
/**
28
 * Factory for creating transactional editing domains that delegate
29
 * <p>
29
 * command execution, undo, and redo to an {@link IOperationHistory}.
30
 * Factory for creating transactional editing domains that delegate command
30
 *
31
 * execution, undo, and redo to an {@link IOperationHistory}.
32
 * </p>
33
 * <p>
34
 * Since the 1.3 release, the determination of how {@link ResourceUndoContext}s
35
 * are attached to undoable operations is
36
 * {@linkplain #getResourceUndoContextPolicy() customizable} using the new
37
 * {@link IResourceUndoContextPolicy} API.
38
 * </p>
39
 * 
31
 * @author Christian W. Damus (cdamus)
40
 * @author Christian W. Damus (cdamus)
32
 */
41
 */
33
public class WorkspaceEditingDomainFactory extends TransactionalEditingDomainImpl.FactoryImpl {
42
public class WorkspaceEditingDomainFactory extends TransactionalEditingDomainImpl.FactoryImpl {
Lines 52-58 Link Here
52
	 * @return the new editing domain
61
	 * @return the new editing domain
53
	 */
62
	 */
54
	@Override
63
	@Override
55
	public TransactionalEditingDomain createEditingDomain() {
64
	public synchronized TransactionalEditingDomain createEditingDomain() {
56
		return createEditingDomain(OperationHistoryFactory.getOperationHistory());
65
		return createEditingDomain(OperationHistoryFactory.getOperationHistory());
57
	}
66
	}
58
67
Lines 65-71 Link Here
65
	 * @return the new editing domain
74
	 * @return the new editing domain
66
	 */
75
	 */
67
	@Override
76
	@Override
68
	public TransactionalEditingDomain createEditingDomain(ResourceSet rset) {
77
	public synchronized TransactionalEditingDomain createEditingDomain(ResourceSet rset) {
69
		return createEditingDomain(
78
		return createEditingDomain(
70
				rset,
79
				rset,
71
				OperationHistoryFactory.getOperationHistory());
80
				OperationHistoryFactory.getOperationHistory());
Lines 81-86 Link Here
81
	 */
90
	 */
82
	public TransactionalEditingDomain createEditingDomain(IOperationHistory history) {
91
	public TransactionalEditingDomain createEditingDomain(IOperationHistory history) {
83
		WorkspaceCommandStackImpl stack = new WorkspaceCommandStackImpl(history);
92
		WorkspaceCommandStackImpl stack = new WorkspaceCommandStackImpl(history);
93
		stack.setResourceUndoContextPolicy(getResourceUndoContextPolicy());
84
		
94
		
85
		TransactionalEditingDomain result = new TransactionalEditingDomainImpl(
95
		TransactionalEditingDomain result = new TransactionalEditingDomainImpl(
86
			new ComposedAdapterFactory(
96
			new ComposedAdapterFactory(
Lines 103-108 Link Here
103
	 */
113
	 */
104
	public TransactionalEditingDomain createEditingDomain(ResourceSet rset, IOperationHistory history) {
114
	public TransactionalEditingDomain createEditingDomain(ResourceSet rset, IOperationHistory history) {
105
		WorkspaceCommandStackImpl stack = new WorkspaceCommandStackImpl(history);
115
		WorkspaceCommandStackImpl stack = new WorkspaceCommandStackImpl(history);
116
		stack.setResourceUndoContextPolicy(getResourceUndoContextPolicy());
106
		
117
		
107
		TransactionalEditingDomain result = new TransactionalEditingDomainImpl(
118
		TransactionalEditingDomain result = new TransactionalEditingDomainImpl(
108
			new ComposedAdapterFactory(
119
			new ComposedAdapterFactory(
Lines 114-117 Link Here
114
		
125
		
115
		return result;
126
		return result;
116
	}
127
	}
128
	
129
	/**
130
	 * Obtains a resource undo-context policy to apply to the editing domain, to
131
	 * determine how to attach {@link ResourceUndoContext}s to operations in the
132
	 * associated history.  May be overridden by clients to supply a non-default
133
	 * implementation.
134
	 * 
135
	 * @return the resource undo-context policy
136
	 * 
137
	 * @since 1.3
138
	 */
139
	protected IResourceUndoContextPolicy getResourceUndoContextPolicy() {
140
		return IResourceUndoContextPolicy.DEFAULT;
141
	}
117
}
142
}
(-)src/org/eclipse/emf/workspace/impl/WorkspaceCommandStackImpl.java (-30 / +69 lines)
Lines 11-17 Link Here
11
 *   IBM - Initial API and implementation
11
 *   IBM - Initial API and implementation
12
 *   Fabrice Dubach - Bug 214325 Fix isSaveNeeded() logic
12
 *   Fabrice Dubach - Bug 214325 Fix isSaveNeeded() logic
13
 *   IBM - Bug 24465
13
 *   IBM - Bug 24465
14
 *   Zeligsoft - Bug 244654 (Update for J2SE 5.0)
14
 *   Zeligsoft - Bugs 244654 (Update for J2SE 5.0), 240775
15
 *
15
 *
16
 * </copyright>
16
 * </copyright>
17
 *
17
 *
Lines 50-55 Link Here
50
import org.eclipse.emf.transaction.impl.TriggerCommandTransaction;
50
import org.eclipse.emf.transaction.impl.TriggerCommandTransaction;
51
import org.eclipse.emf.transaction.util.TriggerCommand;
51
import org.eclipse.emf.transaction.util.TriggerCommand;
52
import org.eclipse.emf.workspace.EMFCommandOperation;
52
import org.eclipse.emf.workspace.EMFCommandOperation;
53
import org.eclipse.emf.workspace.IResourceUndoContextPolicy;
53
import org.eclipse.emf.workspace.IWorkspaceCommandStack;
54
import org.eclipse.emf.workspace.IWorkspaceCommandStack;
54
import org.eclipse.emf.workspace.ResourceUndoContext;
55
import org.eclipse.emf.workspace.ResourceUndoContext;
55
import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory;
56
import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory;
Lines 75-81 Link Here
75
	
76
	
76
	private final IOperationHistory history;
77
	private final IOperationHistory history;
77
	private DomainListener domainListener;
78
	private DomainListener domainListener;
78
	private Set<Resource> historyAffectedResources;
79
	
80
	private IResourceUndoContextPolicy undoContextPolicy = IResourceUndoContextPolicy.DEFAULT;
81
	private IUndoableOperation currentOperation;
82
	private Set<Resource> historyAffectedResources; 
79
	
83
	
80
	private final IUndoContext defaultContext = new UndoContext() {
84
	private final IUndoContext defaultContext = new UndoContext() {
81
	    @Override
85
	    @Override
Lines 435-440 Link Here
435
		historyAffectedResources = null;
439
		historyAffectedResources = null;
436
		mostRecentOperation = null;
440
		mostRecentOperation = null;
437
	}
441
	}
442
	
443
	/**
444
	 * Obtains my resource undo-context policy.
445
	 * 
446
	 * @return my resource undo-context policy
447
	 * 
448
	 * @since 1.3
449
	 */
450
	public IResourceUndoContextPolicy getResourceUndoContextPolicy() {
451
		return undoContextPolicy;
452
	}
453
	
454
	/**
455
	 * Sets my resource undo-context policy.
456
	 * 
457
	 * @param policy
458
	 *            my new policy, or <code>null</code> to restore the default
459
	 * 
460
	 * @since 1.3
461
	 */
462
	public void setResourceUndoContextPolicy(IResourceUndoContextPolicy policy) {
463
		this.undoContextPolicy = policy;
464
	}
438
465
439
	/**
466
	/**
440
	 * A listener on the editing domain and operation history that tracks
467
	 * A listener on the editing domain and operation history that tracks
Lines 454-459 Link Here
454
				case OperationHistoryEvent.ABOUT_TO_EXECUTE :
481
				case OperationHistoryEvent.ABOUT_TO_EXECUTE :
455
					// set up to remember affected resources in case we make EMF
482
					// set up to remember affected resources in case we make EMF
456
					// changes
483
					// changes
484
					currentOperation = operation;
457
					historyAffectedResources = new java.util.HashSet<Resource>();
485
					historyAffectedResources = new java.util.HashSet<Resource>();
458
					break;
486
					break;
459
				case OperationHistoryEvent.DONE :
487
				case OperationHistoryEvent.DONE :
Lines 469-474 Link Here
469
						}
497
						}
470
					}
498
					}
471
499
500
					currentOperation = null;
472
					historyAffectedResources = null;
501
					historyAffectedResources = null;
473
502
474
					if (operation.hasContext(getDefaultUndoContext())) {
503
					if (operation.hasContext(getDefaultUndoContext())) {
Lines 478-483 Link Here
478
				case OperationHistoryEvent.OPERATION_NOT_OK :
507
				case OperationHistoryEvent.OPERATION_NOT_OK :
479
					// just forget about the context because this operation
508
					// just forget about the context because this operation
480
					// failed
509
					// failed
510
					currentOperation = null;
481
					historyAffectedResources = null;
511
					historyAffectedResources = null;
482
					break;
512
					break;
483
				case OperationHistoryEvent.UNDONE :
513
				case OperationHistoryEvent.UNDONE :
Lines 498-517 Link Here
498
		public void resourceSetChanged(ResourceSetChangeEvent event) {
528
		public void resourceSetChanged(ResourceSetChangeEvent event) {
499
            IUndoableOperation operation = null;
529
            IUndoableOperation operation = null;
500
            
530
            
501
            Transaction tx = event.getTransaction();
502
            if (tx != null) {
503
                operation = (IUndoableOperation) tx.getOptions().get(
504
                    EMFWorkspacePlugin.OPTION_OWNING_OPERATION);
505
            }
506
            
507
            Set<Resource> affectedResources = ResourceUndoContext.getAffectedResources(
508
                event.getNotifications());
509
            
510
			Set<Resource> unloaded = getUnloadedResources(event.getNotifications());
531
			Set<Resource> unloaded = getUnloadedResources(event.getNotifications());
511
			if (unloaded != null) {
532
			if (unloaded != null) {
512
				// don't add these resources to the operation
513
				affectedResources.removeAll(unloaded);
514
				
515
                // dispose their undo contexts
533
                // dispose their undo contexts
516
				for (Resource next : unloaded) {
534
				for (Resource next : unloaded) {
517
					getOperationHistory().dispose(
535
					getOperationHistory().dispose(
Lines 519-543 Link Here
519
							true, true, true);
537
							true, true, true);
520
				}
538
				}
521
			}
539
			}
540
           
541
            Transaction tx = event.getTransaction();
542
            if (tx != null) {
543
                operation = (IUndoableOperation) tx.getOptions().get(
544
                    EMFWorkspacePlugin.OPTION_OWNING_OPERATION);
545
            }
522
            
546
            
523
            if ((operation != null) && !affectedResources.isEmpty()) {
547
            if (operation == null) {
524
                // add any resource undo contexts to this operation that are
548
            	operation = currentOperation;
525
                //   not already applied
526
                for (Resource next : affectedResources) {
527
                    ResourceUndoContext ctx = new ResourceUndoContext(
528
                        getDomain(), next);
529
                    
530
                    if (!operation.hasContext(ctx)) {
531
                        operation.addContext(ctx);
532
                    }
533
                }
534
            }
549
            }
535
            
550
            
536
            if (historyAffectedResources != null) {
551
            if (operation != null) {
537
				// there is an operation executing on our history that is
552
				Set<Resource> affectedResources = getResourceUndoContextPolicy()
538
				// affecting my editing domain. Remember the affected resources.
553
					.getContextResources(operation, event.getNotifications());
539
            	historyAffectedResources.addAll(affectedResources);
554
	            
540
			}
555
				if (unloaded != null) {
556
					// don't add these resources to the operation
557
					affectedResources.removeAll(unloaded);
558
				}
559
	            
560
	            if (!affectedResources.isEmpty()) {
561
	                // add any resource undo contexts to this operation that are
562
	                //   not already applied
563
	                for (Resource next : affectedResources) {
564
	                    ResourceUndoContext ctx = new ResourceUndoContext(
565
	                        getDomain(), next);
566
	                    
567
	                    if (!operation.hasContext(ctx)) {
568
	                        operation.addContext(ctx);
569
	                    }
570
	                }
571
	            }
572
	            
573
	            if (historyAffectedResources != null) {
574
					// there is an operation executing on our history that is
575
					// affecting my editing domain. Remember the affected
576
	            	// resources.
577
	            	historyAffectedResources.addAll(affectedResources);
578
				}
579
            }
541
		}
580
		}
542
		
581
		
543
		/**
582
		/**
(-)src/org/eclipse/emf/workspace/AbstractResourceUndoContextPolicy.java (+226 lines)
Added Link Here
1
/**
2
 * <copyright>
3
 * 
4
 * Copyright (c) 2008 Zeligsoft Inc. and others.
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
8
 * http://www.eclipse.org/legal/epl-v10.html
9
 * 
10
 * Contributors:
11
 *   Zeligsoft - Initial API and implementation
12
 * 
13
 * </copyright>
14
 *
15
 * $Id$
16
 */
17
18
package org.eclipse.emf.workspace;
19
20
import java.util.Collection;
21
import java.util.Collections;
22
import java.util.List;
23
import java.util.Set;
24
25
import org.eclipse.core.commands.operations.IUndoableOperation;
26
import org.eclipse.emf.common.notify.Notification;
27
import org.eclipse.emf.ecore.EObject;
28
import org.eclipse.emf.ecore.EReference;
29
import org.eclipse.emf.ecore.resource.Resource;
30
31
/**
32
 * <p>
33
 * The default implementation of the resource undo-context policy, suitable for
34
 * clients to extend/override as required. The default policy is to consider any
35
 * resource as affected by an operation if either
36
 * </p>
37
 * <ol>
38
 * <li>A non-touch {@link Notification} is received from a contained object or
39
 * from the resource, itself, or</li>
40
 * <li>A notification matching (1) is received from a uni-directional
41
 * {@link EReference} (i.e., one having no opposite) has an old value or a new
42
 * value in the resource
43
 * </ol>
44
 * <p>
45
 * In the first case, above, a subclass can choose to include only changes to a
46
 * resource's contents-list and URI as being significant (other resource
47
 * properties not affecting the serialization of the resource).
48
 * </p>
49
 * <p>
50
 * The second case, above, is intended for applications that use
51
 * {@link ResourceUndoContext}s to manage the Undo menus of their editors. It is
52
 * a pessimistic assumption that the referenced resource may either have derived
53
 * attributes whose values influenced precursor or successor operations, or that
54
 * such operations are influenced by the references incoming to the resource.
55
 * Thus, the concern is not so much with the dirty state of the resource as it
56
 * is with the integrity of the undo history for the associated editor and the
57
 * dependencies between successive operations. Subclasses can disable this case
58
 * by overriding the {@link #pessimisticCrossReferences()} method.
59
 * </p>
60
 * 
61
 * @author Christian W. Damus (cdamus)
62
 * @since 1.3
63
 * 
64
 * @see #pessimisticCrossReferences()
65
 * @see #considerAllResourceChanges()
66
 */
67
public abstract class AbstractResourceUndoContextPolicy
68
		implements IResourceUndoContextPolicy {
69
70
	/**
71
	 * Initializes me.
72
	 */
73
	protected AbstractResourceUndoContextPolicy() {
74
		super();
75
	}
76
77
	public Set<Resource> getContextResources(IUndoableOperation operation,
78
			List<? extends Notification> notifications) {
79
80
		Set<Resource> result;
81
82
		if (notifications.isEmpty()) {
83
			result = Collections.emptySet();
84
		} else {
85
			result = new java.util.HashSet<Resource>();
86
87
			for (Notification next : notifications) {
88
				if (next.isTouch()) {
89
					continue;
90
				}
91
				
92
				Object notifier = next.getNotifier();
93
94
				if (notifier instanceof Resource) {
95
					if (considerAllResourceChanges()
96
						|| (next.getFeatureID(Resource.class) == Resource.RESOURCE__CONTENTS)
97
						|| (next.getFeatureID(Resource.class) == Resource.RESOURCE__URI)) {
98
99
						result.add((Resource) notifier);
100
					}
101
				} else if (notifier instanceof EObject) {
102
					EObject eobj = (EObject) notifier;
103
					Resource resource = eobj.eResource();
104
105
					if (resource != null) {
106
						result.add(resource);
107
					}
108
109
					if (pessimisticCrossReferences()) {
110
						// if the reference has an opposite, then we will get
111
						// the
112
						// notification from the other end, anyway
113
						final Object feature = next.getFeature();
114
						if ((feature instanceof EReference)
115
							&& (((EReference) feature).getEOpposite() == null)) {
116
							handleCrossResourceReference(result, next);
117
						}
118
					}
119
				}
120
			}
121
		}
122
123
		return result;
124
	}
125
126
	/**
127
	 * May be overridden by subclasses to disable pessimistic handling of
128
	 * cross-resource references. The default implementation returns
129
	 * <code>true</code> always.
130
	 * 
131
	 * @return whether to consider changes to directed cross-resource references
132
	 *         as affecting the referenced resource
133
	 */
134
	protected boolean pessimisticCrossReferences() {
135
		return true;
136
	}
137
138
	/**
139
	 * May be overridden by subclasses to consider changes to any feature of a
140
	 * resource, not just its contents-list or URI, as affecting it.
141
	 * 
142
	 * @return <code>true</code> if all changes to a resource are considered as
143
	 *         affecting it for the purposes of undo context; <code>false</code>
144
	 *         if only the contents-list and URI are
145
	 */
146
	protected boolean considerAllResourceChanges() {
147
		return false;
148
	}
149
150
	/**
151
	 * Handles notifications that can potentially represent cross-resource
152
	 * references. Helper to the
153
	 * {@link #getContextResources(IUndoableOperation, List)} method.
154
	 * 
155
	 * @param resources
156
	 *            collects the affected resources
157
	 * @param notification
158
	 *            a potential cross-resource reference change notification
159
	 */
160
	protected void handleCrossResourceReference(Set<Resource> resources,
161
			Notification notification) {
162
163
		Object oldValue = notification.getOldValue();
164
		Object newValue = notification.getNewValue();
165
		Resource resource;
166
167
		switch (notification.getEventType()) {
168
			case Notification.SET :
169
			case Notification.UNSET :
170
				if (oldValue != null) {
171
					resource = ((EObject) oldValue).eResource();
172
173
					if (resource != null) {
174
						resources.add(resource);
175
					}
176
				}
177
				if (newValue != null) {
178
					resource = ((EObject) newValue).eResource();
179
180
					if (resource != null) {
181
						resources.add(resource);
182
					}
183
				}
184
				break;
185
			case Notification.ADD :
186
				resource = ((EObject) newValue).eResource();
187
188
				if (resource != null) {
189
					resources.add(resource);
190
				}
191
				break;
192
			case Notification.ADD_MANY : {
193
				@SuppressWarnings("unchecked")
194
				Collection<EObject> newReferences = (Collection<EObject>) newValue;
195
				for (EObject next : newReferences) {
196
					resource = next.eResource();
197
198
					if (resource != null) {
199
						resources.add(resource);
200
					}
201
				}
202
				break;
203
			}
204
			case Notification.REMOVE :
205
				resource = ((EObject) oldValue).eResource();
206
207
				if (resource != null) {
208
					resources.add(resource);
209
				}
210
				break;
211
			case Notification.REMOVE_MANY : {
212
				@SuppressWarnings("unchecked")
213
				Collection<EObject> oldReferences = (Collection<EObject>) oldValue;
214
				for (EObject next : oldReferences) {
215
					resource = next.eResource();
216
217
					if (resource != null) {
218
						resources.add(resource);
219
					}
220
				}
221
				break;
222
			}
223
		}
224
	}
225
226
}
(-)src/org/eclipse/emf/workspace/IResourceUndoContextPolicy.java (+76 lines)
Added Link Here
1
/**
2
 * <copyright>
3
 * 
4
 * Copyright (c) 2008 Zeligsoft Inc. and others.
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
8
 * http://www.eclipse.org/legal/epl-v10.html
9
 * 
10
 * Contributors:
11
 *   Zeligsoft - Initial API and implementation
12
 * 
13
 * </copyright>
14
 *
15
 * $Id$
16
 */
17
18
package org.eclipse.emf.workspace;
19
20
import java.util.List;
21
import java.util.Set;
22
23
import org.eclipse.core.commands.operations.IUndoableOperation;
24
import org.eclipse.emf.common.notify.Notification;
25
import org.eclipse.emf.ecore.resource.Resource;
26
27
/**
28
 * <p>
29
 * A rule determining the resources for which an {@link IUndoableOperation}
30
 * should be tagged with {@link ResourceUndoContext}s. In general, these are the
31
 * resources that
32
 * </p>
33
 * <ul>
34
 * <li>are modified by the operation, such that they are become dirty, and/or</li>
35
 * <li>whose editors should show the operation in their Undo menu</li>
36
 * </ul>
37
 * <p>
38
 * Clients may implement this interface, but it is recommended to extend the
39
 * {@link AbstractResourceUndoContextPolicy} class whenever possible.
40
 * </p>
41
 * 
42
 * @author Christian W. Damus (cdamus)
43
 * @since 1.3
44
 * 
45
 * @see AbstractResourceUndoContextPolicy
46
 */
47
public interface IResourceUndoContextPolicy {
48
49
	/**
50
	 * The default undo-context policy used by editing domains for which none is
51
	 * assigned by the client application.
52
	 */
53
	IResourceUndoContextPolicy DEFAULT = new AbstractResourceUndoContextPolicy() {
54
	};
55
56
	/**
57
	 * Determines the resources in the undo context of the specified
58
	 * <tt>operation</tt>, during which execution the changes indicated by the
59
	 * given <tt>notifications</tt> occurred. This operation may be called
60
	 * several times for the same operation, but always with different
61
	 * notifications.
62
	 * 
63
	 * @param operation
64
	 *            the operation. It may or may not have finished executing. Must
65
	 *            not be <code>null</code>
66
	 * @param notifications
67
	 *            a list of notifications of changes caused by the operation
68
	 *            during its execution, in the order in which they occurred.
69
	 *            This may be an empty list, but never <code>null</code>
70
	 * 
71
	 * @return the resources that are the undo context of this operation, or an
72
	 *         empty list if none. Never ruterns <code>null</code>
73
	 */
74
	Set<Resource> getContextResources(IUndoableOperation operation,
75
			List<? extends Notification> notifications);
76
}

Return to bug 240775