/* * Copyright (c) 2014, IETR/INSA of Rennes * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the IETR/INSA of Rennes nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package net.sf.orcc.xdf.ui.features; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import net.sf.orcc.df.Argument; import net.sf.orcc.df.Connection; import net.sf.orcc.df.DfFactory; import net.sf.orcc.df.Entity; import net.sf.orcc.df.Instance; import net.sf.orcc.df.Network; import net.sf.orcc.df.Port; import net.sf.orcc.graph.Edge; import net.sf.orcc.graph.Vertex; import net.sf.orcc.ir.ExprVar; import net.sf.orcc.ir.Var; import net.sf.orcc.ir.util.IrUtil; import net.sf.orcc.util.OrccLogger; import net.sf.orcc.xdf.ui.diagram.XdfDiagramFeatureProvider; import net.sf.orcc.xdf.ui.patterns.InstancePattern; import net.sf.orcc.xdf.ui.util.PropsUtil; import net.sf.orcc.xdf.ui.util.XdfUtil; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.graphiti.features.IFeatureProvider; import org.eclipse.graphiti.features.context.IAddConnectionContext; import org.eclipse.graphiti.features.context.IContext; import org.eclipse.graphiti.features.context.ICustomContext; import org.eclipse.graphiti.features.context.impl.AddContext; import org.eclipse.graphiti.features.context.impl.CustomContext; import org.eclipse.graphiti.features.context.impl.DeleteContext; import org.eclipse.graphiti.features.context.impl.MultiDeleteInfo; import org.eclipse.graphiti.features.custom.ICustomFeature; import org.eclipse.graphiti.mm.pictograms.Anchor; import org.eclipse.graphiti.mm.pictograms.PictogramElement; import org.eclipse.graphiti.pattern.IFeatureProviderWithPatterns; import org.eclipse.graphiti.pattern.IPattern; import org.eclipse.graphiti.services.Graphiti; /** * Replace the selected instance by the content of the network it refined on. * * @author Antoine Lorence * */ public class UngroupNetworkFeature extends AbstractTimeConsumingCustomFeature { public UngroupNetworkFeature(IFeatureProvider fp) { super(fp); } @Override public String getName() { return "Separate the network into new instances"; } @Override public String getDescription() { return "Replace this instance by the network content it is refined on."; } @Override public boolean isAvailable(IContext context) { return super.isAvailable(context); } /* * This feature can be executed if user selected only 1 instance, and if * this instance is refined on a Network * * (non-Javadoc) * * @see * org.eclipse.graphiti.features.custom.AbstractCustomFeature#canExecute * (org.eclipse.graphiti.features.context.ICustomContext) */ @Override public boolean canExecute(ICustomContext context) { if (context.getPictogramElements().length != 1) { return false; } final PictogramElement pe = context.getPictogramElements()[0]; if (PropsUtil.isInstance(pe)) { final Object obj = getBusinessObjectForPictogramElement(pe); if (obj instanceof Instance && ((Instance) obj).isNetwork()) { return true; } } return false; } @Override public void execute(ICustomContext context, IProgressMonitor parentMonitor) { final PictogramElement instancePe = context.getPictogramElements()[0]; final Instance instance = (Instance) getBusinessObjectForPictogramElement(instancePe); final Network subNetwork = instance.getNetwork(); final Network thisNetwork = (Network) getBusinessObjectForPictogramElement(getDiagram()); final IFeatureProviderWithPatterns fp = (IFeatureProviderWithPatterns) getFeatureProvider(); final Map<Instance, Instance> copies = new HashMap<Instance, Instance>(); final Map<Instance, PictogramElement> peMap = new HashMap<Instance, PictogramElement>(); final SubMonitor monitor = SubMonitor.convert(parentMonitor, 100); monitor.newChild(5); monitor.setTaskName("Initialization"); // Copy subNetwork variables into the current network for (Var variable : subNetwork.getVariables()) { thisNetwork.getVariables().add(IrUtil.copy(variable)); } // Copy content of sub network in this network for (final Vertex vertex : subNetwork.getChildren()) { if (vertex instanceof Instance) { final Instance subInstance = IrUtil.copy((Instance) vertex); subInstance.setName(XdfUtil.uniqueVertexName(thisNetwork, subInstance.getName())); copies.put((Instance) vertex, subInstance); final AddContext addCtxt = new AddContext(); addCtxt.setLocation(10, 10); addCtxt.setNewObject(subInstance); addCtxt.setTargetContainer(getDiagram()); final PictogramElement pe = getFeatureProvider().addIfPossible(addCtxt); if (pe != null) { peMap.put(subInstance, pe); } // Update subInstance argument variable uses for (Argument arg : subInstance.getArguments()) { for (Iterator<EObject> it = arg.eAllContents(); it .hasNext();) { final EObject childEObject = it.next(); if (childEObject instanceof ExprVar) { final ExprVar exprVar = (ExprVar) childEObject; final String varName = exprVar.getUse() .getVariable().getName(); Var theVar = subNetwork.getVariable(varName); if (theVar != null) { theVar = EcoreUtil.copy(theVar); thisNetwork.getVariables().add(theVar); } else { theVar = subNetwork.getParameter(varName); if (theVar != null) { theVar = EcoreUtil.copy(theVar); thisNetwork.getVariables().add(theVar); final Argument argument = instance .getArgument(varName); if (argument.getValue() != null) { theVar.setInitialValue(argument .getValue()); } } } if (theVar != null) { exprVar.getUse().setVariable(theVar); } else { final StringBuilder msg = new StringBuilder() .append("Unable to retrieve the variable ") .append(varName) .append(" in the current network. It is used in a ") .append(instance.getName()) .append("'s argument"); OrccLogger.severeln(msg.toString()); } } } } } } SubMonitor loopProgress = monitor.newChild(20).setWorkRemaining( subNetwork.getConnections().size()); monitor.setTaskName("Update connections"); // Re-generate connections between subNetwork instances for(final Connection connection : subNetwork.getConnections()) { loopProgress.newChild(1); // The connection is between 2 instances // Connections from/to a network port are analyzed later if(connection.getSourcePort() != null && connection.getTargetPort() != null) { final Instance source = copies.get(connection.getSource()); final Port sourcePort = source.getAdapter(Entity.class).getOutput(connection.getSourcePort().getName()); final Instance target = copies.get(connection.getTarget()); final Port targetPort = target.getAdapter(Entity.class).getInput(connection.getTargetPort().getName()); final Connection newConnection = DfFactory.eINSTANCE .createConnection(source, sourcePort, target, targetPort, connection.getSize()); // We will 'add' a new Connection to a diagram (not create it, // in Graphiti context). It must exists in the current network thisNetwork.add(newConnection); // Really add the connection final IAddConnectionContext addConContext = XdfUtil .getAddConnectionContext(fp, getDiagram(), newConnection); getFeatureProvider().addIfPossible(addConContext); } } loopProgress.setWorkRemaining(subNetwork.getInputs().size() + subNetwork.getOutputs().size()); // Merge connections: // outerCon = connected from something in the current graph to an input of the instance // innerCon = connected from a subNetwork input to something else (in // subNetwork too) for (final Port inPort : subNetwork.getInputs()) { loopProgress.newChild(1); final Connection outerCon = instance.getIncomingPortMap().get(inPort); if (outerCon == null) { continue; } for (final Edge innerEdge : inPort.getOutgoing()) { final Connection innnerCon = (Connection) innerEdge; final Instance target = copies.get(innnerCon.getTarget()); final Port targetPort = target.getAdapter(Entity.class).getInput(innnerCon.getTargetPort().getName()); final Connection c = DfFactory.eINSTANCE.createConnection( outerCon.getSource(), outerCon.getSourcePort(), target, targetPort); // We will 'add' a new Connection to a diagram (not create it, // in Graphiti context). It must exists in the current network thisNetwork.add(c); // Really add the connection final IAddConnectionContext addConContext = XdfUtil .getAddConnectionContext(fp, getDiagram(), c); getFeatureProvider().addIfPossible(addConContext); } } final InstancePattern instancePattern = (InstancePattern) ((IFeatureProviderWithPatterns) getFeatureProvider()) .getPatternForPictogramElement(instancePe); // Merge connections: // outerCons = connected from an output of the instance to something in the current graph // innerCon = connected from something to an output in the subNetwork for (final Port outPort : subNetwork.getOutputs()) { loopProgress.newChild(1); final List<Connection> outerCons = instance.getOutgoingPortMap() .get(outPort); if (outerCons == null || outerCons.isEmpty()) { continue; } for (final Edge innerEdge : outPort.getIncoming()) { final Connection innerCon = (Connection) innerEdge; for (final Connection outerCon : outerCons) { final Instance source = copies.get(innerCon.getSource()); final Port sourcePort = source.getAdapter(Entity.class).getOutput(innerCon.getSourcePort().getName()); // Update this network connection with the new source // instance outerCon.setSource(source); outerCon.setSourcePort(sourcePort); // Update this diagram connection with the new start anchor final List<PictogramElement> linkedPes = Graphiti .getLinkService().getPictogramElements( getDiagram(), outerCon); for (final PictogramElement pe : linkedPes) { if (pe instanceof org.eclipse.graphiti.mm.pictograms.Connection) { final Anchor anchor = instancePattern .getAnchorForPort(peMap.get(source), sourcePort); ((org.eclipse.graphiti.mm.pictograms.Connection) pe) .setStart(anchor); } } } } } monitor.newChild(70); monitor.setTaskName("Delete useless network instance"); // Delete the selected instance PictogramElement from the current // diagram. This will also delete: // - The linked Instance from the Network // - The FreeFormConnections from/to this instance // - The corresponding net.sf.orcc.df.Connection instances from the // network final IPattern pattern = fp.getPatternForPictogramElement(instancePe); final DeleteContext delContext = new DeleteContext(instancePe); delContext.setMultiDeleteInfo(new MultiDeleteInfo(false, false, 0)); pattern.delete(delContext); monitor.newChild(5); monitor.setTaskName("Lay out the diagram"); // And layout the resulting diagram final IContext layoutContext = new CustomContext(); final ICustomFeature layoutFeature = ((XdfDiagramFeatureProvider) getFeatureProvider()) .getDefaultLayoutFeature(); if (layoutFeature.canExecute(layoutContext)) { layoutFeature.execute(layoutContext); } monitor.done(); } }