| /******************************************************************************* |
| * Copyright (c) 2005, 2012 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.bpel.ui.commands.util; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.bpel.common.ui.editmodel.AbstractEditModelCommand; |
| import org.eclipse.bpel.model.Process; |
| import org.eclipse.bpel.model.resource.BPELResource; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.wst.sse.core.internal.format.IStructuredFormatProcessor; |
| import org.eclipse.wst.wsdl.WSDLElement; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; |
| import org.eclipse.wst.xml.core.internal.provisional.format.FormatProcessorXML; |
| import org.w3c.dom.Element; |
| |
| /** |
| * A base class for BPEL editor commands. Since the BPEL editor will have |
| * automatic EMF-based Undo/Redo support, editor commands should not implement |
| * the undo() or redo() methods (and the framework should not call them!). |
| */ |
| public abstract class AutoUndoCommand extends AbstractEditModelCommand { |
| private Set<Object> fModelRoots; |
| |
| public AutoUndoCommand(String label, EObject modelRoot) { |
| super(label); |
| if (modelRoot == null) { |
| throw new IllegalStateException("modelRoot cannot be null here"); |
| } |
| fModelRoots = Collections.singleton((Object) modelRoot); |
| } |
| |
| public AutoUndoCommand(EObject modelRoot) { |
| if (modelRoot == null) { |
| throw new IllegalStateException("modelRoot cannot be null here"); |
| } |
| fModelRoots = Collections.singleton((Object) modelRoot); |
| } |
| |
| public AutoUndoCommand(String label, ArrayList<Object> modelRoots) { |
| super(label); |
| fModelRoots = new HashSet<Object>(); |
| fModelRoots.addAll(modelRoots); |
| } |
| |
| public AutoUndoCommand(ArrayList<Object> modelRoots) { |
| fModelRoots = new HashSet<Object>(); |
| fModelRoots.addAll(modelRoots); |
| } |
| |
| private void beginRecording(Object element) { |
| if (element instanceof IDOMNode) { |
| IDOMModel model = ((IDOMNode) element).getModel(); |
| model.aboutToChangeModel(); |
| model.beginRecording(this, |
| getUndoDescription()); |
| } |
| } |
| |
| private void endRecording(Object element) { |
| if (element instanceof IDOMNode) { |
| IDOMModel model = ((IDOMNode) element).getModel(); |
| model.changedModel(); |
| model.endRecording(this); |
| } |
| } |
| |
| protected String getUndoDescription() { |
| return getLabel(); |
| } |
| |
| protected void formatChild(Element child) { |
| if (child instanceof IDOMNode) { |
| IDOMModel model = ((IDOMNode) child).getModel(); |
| try { |
| // tell the model that we are about to make a big model change |
| model.aboutToChangeModel(); |
| |
| IStructuredFormatProcessor formatProcessor = new FormatProcessorXML(); |
| formatProcessor.formatNode(child); |
| } finally { |
| // tell the model that we are done with the big model change |
| model.changedModel(); |
| } |
| } |
| } |
| |
| public void execute() { |
| if (canDoExecute()) { |
| Object element = calculateLeastCommonAncestor(); |
| try { |
| beginRecording(element); |
| doExecute(); |
| } finally { |
| endRecording(element); |
| } |
| } |
| } |
| |
| private Object calculateLeastCommonAncestor() { |
| Object[] roots = getModelRoots().toArray(); |
| if (roots.length == 0) { |
| return null; |
| } |
| if (roots.length == 1) { |
| return ((WSDLElement)roots[0]).getElement(); |
| } |
| Integer worms = roots.length; |
| HashMap<Object, Integer> wormed = new HashMap<Object, Integer>(); |
| Set<WSDLElement> old = new HashSet<WSDLElement>(); |
| Set<WSDLElement> current = new HashSet<WSDLElement>(); |
| for (Object node : roots) { |
| wormed.put(node, 1); |
| current.add((WSDLElement)node); |
| } |
| while (true) { |
| Set<WSDLElement> temp = old; |
| old = current; |
| current = temp; |
| current.clear(); |
| for (WSDLElement node : old) { |
| if (node.getContainer() == null) { |
| if (node instanceof Process) { |
| return node.getElement(); |
| } else { |
| continue; |
| } |
| } |
| Integer count = wormed.get(node); |
| if (count == null) { |
| wormed.put(node, 1); |
| } else if (worms.equals(count + 1)) { |
| return node.getElement(); |
| } else if (count != null) { |
| wormed.put(node, count + 1); |
| } |
| current.add(node.getContainer()); |
| } |
| if (current.isEmpty()) { |
| return ((BPELResource)((WSDLElement)roots[0]).eResource()).getProcess().getElement(); |
| } |
| } |
| } |
| |
| /** |
| * @return true if we can execute this, false otherwise. |
| */ |
| |
| public boolean canDoExecute() { |
| return true; |
| } |
| |
| public void doExecute() { |
| |
| } |
| |
| @SuppressWarnings("nls") |
| protected void addModelRoot(Object modelRoot) { |
| if (modelRoot == null) { |
| throw new IllegalStateException("modelRoot cannot be null here"); |
| } |
| getModelRoots().add(modelRoot); |
| } |
| |
| protected void addModelRoots(List<Object> modelRoot) { |
| getModelRoots().addAll(modelRoot); |
| } |
| |
| protected void addModelRoots(Set<Object> modelRoot) { |
| getModelRoots().addAll(modelRoot); |
| } |
| |
| public Set<Object> getModelRoots() { |
| return fModelRoots; |
| } |
| |
| protected Resource getResource (Object modelRoot) { |
| if (modelRoot instanceof EObject) return ((EObject)modelRoot).eResource(); |
| if (modelRoot instanceof Resource) return (Resource)modelRoot; |
| throw new IllegalArgumentException(); |
| } |
| |
| /** |
| * Default implementation. Assume that any resource containing a modelRoot |
| * will be modified by the command. |
| */ |
| @Override |
| public Resource[] getResources() { |
| if (getModelRoots().size() < 2) { |
| if (getModelRoots().isEmpty()) { |
| // This should never happen. ? |
| throw new IllegalStateException(); |
| // return new Resource[0] |
| } |
| Resource resource = getResource(getModelRoots().toArray()[0]); |
| if (resource != null) { |
| return new Resource[] { resource }; |
| } |
| return EMPTY_RESOURCE_ARRAY; |
| } |
| Set<Resource> resultSet = new HashSet<Resource>(getModelRoots().size()); |
| for (Object next : getModelRoots()) { |
| Resource resource = getResource(next); |
| if (resource != null) { |
| resultSet.add(resource); |
| } |
| } |
| return resultSet.toArray( EMPTY_RESOURCE_ARRAY ); |
| } |
| |
| /** |
| * Default implementation: assume that all modelRoots resources were modified. |
| * |
| * TODO: comment out this method and check each place where a red X appears, to |
| * see if it should implement the method. |
| * |
| * TODO: maybe a better way is to just query the recorder for affected resources...! |
| */ |
| |
| @Override |
| public final Resource[] getModifiedResources() { |
| return getResources(); |
| } |
| } |