/** * <copyright> * Copyright (c) 2010-2014 Henshin developers. 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 * </copyright> */ package org.eclipse.emf.henshin.model.actions; import java.util.List; import org.eclipse.emf.henshin.model.Edge; import org.eclipse.emf.henshin.model.Graph; import org.eclipse.emf.henshin.model.Mapping; import org.eclipse.emf.henshin.model.Node; import org.eclipse.emf.henshin.model.Rule; /** * A map editor for multi-rule elements. Used for multi-rules. * This does not implement {@link MapEditor}. * @author Christian Krause */ public class MultiRuleMapEditor { // Kernel and multi-rule. private final Rule kernel, multi; // Node map editors: private final NodeMapEditor lhsNodeMapEditor, rhsNodeMapEditor; // Edge map editors: private final EdgeMapEditor lhsEdgeMapEditor, rhsEdgeMapEditor; public MultiRuleMapEditor(Rule kernel, Rule multi) { // Source, target and the image graphs: this.kernel = kernel; this.multi = multi; // Node and edge map editors: lhsNodeMapEditor = new NodeMapEditor(kernel.getLhs(), multi.getLhs(), multi.getMultiMappings()); lhsEdgeMapEditor = new EdgeMapEditor(kernel.getLhs(), multi.getLhs(), multi.getMultiMappings()); rhsNodeMapEditor = new NodeMapEditor(kernel.getRhs(), multi.getRhs(), multi.getMultiMappings()); rhsEdgeMapEditor = new EdgeMapEditor(kernel.getRhs(), multi.getRhs(), multi.getMultiMappings()); } /** * Move a mapped node. * @param node Node to be moved. */ public void moveMappedNode(Node node) { // Get the opposite node and the mapping. Node opposite = getOppositeNode(node); Graph graph = node.getGraph(); if (opposite==null || graph==null) return; // Move the mapping: if (graph.getRule()==kernel) { multi.getMappings().add( getHorizontalMapping(node, opposite) ); } else if (graph.getRule()==multi) { kernel.getMappings().add( getHorizontalMapping(node, opposite) ); } // Move the node and the opposite node: if (graph==kernel.getLhs() || graph==multi.getLhs()) { rhsNodeMapEditor.move(opposite); lhsNodeMapEditor.move(node); } else if (graph==kernel.getRhs() || graph==multi.getRhs()) { rhsNodeMapEditor.move(node); lhsNodeMapEditor.move(opposite); } // It could be that we left an old mapping instance in the multi-rule. removeInvalidMappings(multi.getMappings(), multi.getLhs(), multi.getRhs()); } private static void removeInvalidMappings(List<Mapping> mappings, Graph source, Graph target) { for (int i=0; i<mappings.size(); i++) { Mapping mapping = mappings.get(i); if (mapping.getOrigin().getGraph()!=source || mapping.getImage().getGraph()!=target) { mappings.remove(i--); } } } /** * Copy a mapped node. * @param node Node to be copied. */ public void copyMappedNode(Node node) { // Get the opposite node and the mapping. Node opposite = getOppositeNode(node); Graph graph = node.getGraph(); if (opposite==null || graph==null) return; // Copy the node and the opposite node: Node copiedNode, copiedOpposite; if (graph==kernel.getLhs() || graph==multi.getLhs()) { copiedOpposite = rhsNodeMapEditor.copy(opposite); copiedNode = lhsNodeMapEditor.copy(node); } else if (graph==kernel.getRhs() || graph==multi.getRhs()) { copiedNode = rhsNodeMapEditor.copy(node); copiedOpposite = lhsNodeMapEditor.copy(opposite); } else { return; } // Create a copy of the mapping: Mapping mapping = getHorizontalMapping(node, opposite); if (graph.getRule()==kernel) { copyMapping(mapping, node, opposite, copiedNode, copiedOpposite, multi); } else if (graph.getRule()==multi) { copyMapping(mapping, node, opposite, copiedNode, copiedOpposite, kernel); } } /** * Move a mapped edge. * @param edge Edge to be moved. */ public void moveMappedEdge(Edge edge) { // Get the opposite edge first: Edge opposite = getOppositeEdge(edge); Graph graph = edge.getGraph(); if (opposite==null || graph==null) return; // Find out from where to where we move... Rule from; if (graph==kernel.getLhs() || graph==kernel.getRhs()) { from = kernel; } else if (graph==multi.getLhs() || graph==multi.getRhs()) { from = multi; } else { return; } // If the edge is mapped, then so is its source and target copyMappedNode(edge.getSource()); copyMappedNode(edge.getTarget()); // Now we move the edge to the new graph if (graph==from.getLhs()) { lhsEdgeMapEditor.move(edge); rhsEdgeMapEditor.move(opposite); } else if (graph==from.getRhs()) { lhsEdgeMapEditor.move(opposite); rhsEdgeMapEditor.move(edge); } } /** * Move a mapped element. This can be either a node or * an edge. If it is neither, nothing hapens. * @param element Element to be moved. */ public void moveMappedElement(Object element) { if (element instanceof Node) { moveMappedNode((Node) element); } else if (element instanceof Edge) { moveMappedEdge((Edge) element); } } public void ensureCompleteness() { for (Node node : kernel.getLhs().getNodes()) { copyNodeToTarget(node); } for (Edge edge : kernel.getLhs().getEdges()) { copyEdgeToTarget(edge); } } private void copyNodeToTarget(Node node) { if (getOppositeNode(node)!=null) { copyMappedNode(node); } else { if (node.getGraph()==kernel.getLhs()) { lhsNodeMapEditor.copy(node); } else if (node.getGraph()==kernel.getRhs()) { rhsNodeMapEditor.copy(node); } } } private void copyEdgeToTarget(Edge edge) { Edge opposite = getOppositeEdge(edge); if (edge.getGraph()==kernel.getLhs()) { lhsEdgeMapEditor.copy(edge); if (opposite!=null) { rhsEdgeMapEditor.copy(opposite); } } else if (edge.getGraph()==kernel.getRhs()) { rhsEdgeMapEditor.copy(edge); if (opposite!=null) { lhsEdgeMapEditor.copy(opposite); } } } /* * Get the opposite node. */ private Node getOppositeNode(Node node) { if (node.getGraph().getRule()==kernel) { return new NodeMapEditor(kernel.getRhs()).getOpposite(node); } else if (node.getGraph().getRule()==multi) { return new NodeMapEditor(multi.getRhs()).getOpposite(node); } else { return null; } } /* * Get the opposite edge. */ private Edge getOppositeEdge(Edge edge) { if (edge.getGraph().getRule()==kernel) { return new EdgeMapEditor(kernel.getRhs()).getOpposite(edge); } else if (edge.getGraph().getRule()==multi) { return new EdgeMapEditor(multi.getRhs()).getOpposite(edge); } else { return null; } } // Get the LHS-RHS mapping for two nodes. private Mapping getHorizontalMapping(Node n1, Node n2) { Mapping mapping = kernel.getMappings().get(n1, n2); if (mapping==null) { mapping = multi.getMappings().get(n1, n2); } return mapping; } private void copyMapping(Mapping mapping, Node old1, Node old2, Node new1, Node new2, Rule rule) { if (mapping.getOrigin()==old1 && mapping.getImage()==old2) { rule.getMappings().add(new1, new2); } else if (mapping.getOrigin()==old2 && mapping.getImage()==old1) { rule.getMappings().add(new2, new1); } } }