/******************************************************************************* * Copyright (c) 2009 itemis AG (http://www.itemis.eu) 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 *******************************************************************************/ package org.eclipse.xtext.gmf.glue.editingdomain; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EContentAdapter; import org.eclipse.xtext.resource.XtextResource; import com.google.common.collect.Lists; /** * @author Knut Wannheden - Initial contribution and API * @author Jan Koehnlein */ public class ChangeAggregatorAdapter extends EContentAdapter { private Collection<EObject> modifiedObjects = new LinkedHashSet<EObject>(); private boolean isRecording = false; private boolean isSuspended = false; @Override public void notifyChanged(Notification notification) { super.notifyChanged(notification); if (!doRecord(notification)) return; if (notification.getNotifier() instanceof EObject) { recordObjectModification((EObject) notification.getNotifier()); } } protected void recordObjectModification(EObject obj) { if (obj.eResource() == null || false == obj.eResource() instanceof XtextResource) modifiedObjects.remove(obj); else modifiedObjects.add(obj); } protected boolean doRecord(Notification notification) { if (!isRecording || isSuspended || notification.isTouch()) return false; switch (notification.getEventType()) { case Notification.ADD: case Notification.ADD_MANY: case Notification.MOVE: case Notification.REMOVE: case Notification.REMOVE_MANY: case Notification.SET: case Notification.UNSET: return true; default: return false; } } private void reset() { modifiedObjects.clear(); } /** * This element comes from the XText/GMF integration example, and was not originally documented. */ public void beginRecording() { reset(); isRecording = true; } /** * This element comes from the XText/GMF integration example, and was not originally documented. */ public void endRecording() { isRecording = false; } /** * This element comes from the XText/GMF integration example, and was not originally documented. * @param isSuspended */ public void setSuspended(boolean isSuspended) { this.isSuspended = isSuspended; } /** * This element comes from the XText/GMF integration example, and was not originally documented. * @return List<EOject> */ public List<EObject> getModificationRoots() { Map<Resource, List<EObject>> resource2ChangePathMap = new HashMap<Resource, List<EObject>>(); for (EObject eObject : modifiedObjects) { if (!eObject.eIsProxy()) { Resource resource = eObject.eResource(); List<EObject> resourceChangePath = resource2ChangePathMap.get(resource); if (resourceChangePath == null) { resourceChangePath = allContainers(eObject); resource2ChangePathMap.put(resource, resourceChangePath); } else { resourceChangePath.retainAll(allContainers(eObject)); } } } List<EObject> modificationRoots = new ArrayList<EObject>(resource2ChangePathMap.size()); for (List<EObject> changePath : resource2ChangePathMap.values()) { if (!changePath.isEmpty()) { modificationRoots.add(changePath.get(changePath.size() - 1)); } } return modificationRoots; } private LinkedList<EObject> allContainers(EObject eObject) { final LinkedList<EObject> allContainers = Lists.newLinkedList(); allContainers.add(eObject); EObject currentContainer = eObject.eContainer(); final Resource resource = eObject.eResource(); while (currentContainer != null && resource == currentContainer.eResource()) { allContainers.addFirst(currentContainer); currentContainer = currentContainer.eContainer(); } return allContainers; } /** * Only attach to XtextResources */ @Override protected void setTarget(Resource target) { if (target instanceof XtextResource) { super.setTarget(target); } } @Override protected void setTarget(EObject target) { if (target.eResource() instanceof XtextResource) { super.setTarget(target); } } @Override public boolean isAdapterForType(Object type) { return type == ChangeAggregatorAdapter.class; } }