/******************************************************************************* * Copyright (c) 2006-2012 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026 * * 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: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Berlin, Germany * - initial API and implementation ******************************************************************************/ package org.reuseware.lacome.layoutlanguage.topcased; import java.util.Iterator; import java.util.List; import org.eclipse.draw2d.geometry.Point; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.EcoreUtil; import org.reuseware.lacome.CompositionDiagramUtil; import org.reuseware.lacome.DiagramDescription; import org.reuseware.lacome.strategy.DiagramMerger; import org.topcased.modeler.di.model.DiagramElement; import org.topcased.modeler.di.model.DiagramInterchangePackage; import org.topcased.modeler.di.model.EMFSemanticModelBridge; import org.topcased.modeler.di.model.GraphConnector; import org.topcased.modeler.di.model.GraphEdge; import org.topcased.modeler.di.model.GraphElement; import org.topcased.modeler.di.model.GraphNode; import org.topcased.modeler.di.model.SemanticModelBridge; import org.topcased.modeler.diagrams.model.Diagrams; /** * Diagram merger that can handle Topcased diagrams. */ public class TopcasedMerger implements DiagramMerger { /** * @param receivingDiagram the diagram to be extended * @return true if the first element in the receiving diagram is an instance of * <code>org.topcased.modeler.diagrams.model.Diagrams</code>. */ public boolean canMerge(DiagramDescription receivingDiagram) { if (!receivingDiagram.getDiagramRoots().isEmpty()) { return receivingDiagram.getDiagramRoots().get(0) instanceof Diagrams; } return false; } /** * Universal implementation of merge for all Topcased diagrams. * * @param contributingDiagrams the Topcased diagrams of the contributing fragments * @param receivingDiagram the Topcased diagram of the receiving fragment * @param additionalDiagrams other Topcased diagrams that are processed in another composition * step of the same composition program execution */ public void merge(List<DiagramDescription> contributingDiagrams, DiagramDescription receivingDiagram, List<DiagramDescription> additionalDiagrams) { for (DiagramDescription contributingDiagram : contributingDiagrams) { int offsetx = contributingDiagram.getSourceBounds().getX(); int offsety = contributingDiagram.getSourceBounds().getY(); moveElements(contributingDiagram.getDiagramRoots(), receivingDiagram.getContents(), contributingDiagram.getTargetBounds().getX() - offsetx, contributingDiagram.getTargetBounds().getY() - offsety); } EList<EObject> contributingLayout = new BasicEList<EObject>(); EList<EObject> contributingContents = new BasicEList<EObject>(); EList<EObject> additionalLayout = new BasicEList<EObject>(); for (DiagramDescription contributingDiagram : contributingDiagrams) { contributingLayout.addAll(contributingDiagram.getDiagramRoots()); contributingContents.addAll(contributingDiagram.getContents()); } for (DiagramDescription additionalDiagram : additionalDiagrams) { additionalLayout.addAll(additionalDiagram.getDiagramRoots()); } EList<EObject> receivingContents = receivingDiagram.getContents(); rerouteDiagram(receivingDiagram.getDiagramRoots(), contributingLayout, additionalLayout); mergeDiagrams(contributingLayout, receivingDiagram.getDiagramRoots(), receivingContents); } /** * Removes a view (node or edge) if its semantic element was removed or if another * graphical element to which it connected was removed. * * @param element the element that was target of a cleanup * @param feature the feature modified during cleanup * @param removedValue the old value of the feature before cleanup * @return true if element was removed from diagram */ public boolean cleanup(EObject element, EStructuralFeature feature, EObject removedValue) { if (element instanceof SemanticModelBridge) { //dead nodes SemanticModelBridge bridge = (SemanticModelBridge) element; EcoreUtil.remove(bridge.getGraphElement()); return true; } if (element instanceof GraphEdge && DiagramInterchangePackage.Literals.GRAPH_EDGE__ANCHOR.equals(feature)) { //edges pointing into nowhere EcoreUtil.remove(element); return true; } return false; } private void moveElements(EList<EObject> contributingDiagrams, EList<EObject> receivingContents, int boundingBoxX, int boundingBoxY) { TreeIterator<EObject> treeIterator = EcoreUtil.getAllContents(contributingDiagrams); while (treeIterator.hasNext()) { EObject node = treeIterator.next(); if (node instanceof GraphNode) { EObject element = findSematicModelElement(node); for (EObject receivingRootElement : receivingContents) { //skip all outer elements which are the old parents if (EcoreUtil.isAncestor(receivingRootElement, element)) { Point pos = ((GraphNode) node).getPosition(); if (pos != null) { int x = pos.x + boundingBoxX; int y = pos.y + boundingBoxY; pos = new Point(x, y); ((GraphNode) node).setPosition(pos); //children nodes have relative positions and do not need to be moved treeIterator.prune(); break; } } } } } } private boolean mergeDiagrams(EList<EObject> contributingDiagramRoot, EList<EObject> receivingDiagramRoot, EList<EObject> receivingContentRoot) { boolean result = false; boolean change = true; while (change) { change = false; TreeIterator<EObject> diagramElIt = EcoreUtil.getAllContents(contributingDiagramRoot); while (diagramElIt.hasNext()) { EObject next = diagramElIt.next(); if (next instanceof DiagramElement) { DiagramElement diagramEl = (DiagramElement) next; EObject element = findSematicModelElement(diagramEl); if (element == null) { continue; } EObject container = element.eContainer(); if (!(diagramEl.eContainer() instanceof Diagrams)) { while (container != null && !container.eClass().equals(findSematicModelElement(diagramEl.eContainer()).eClass())) { //maybe the diagram element is contained in the diagram element for a container further up container = container.eContainer(); } } if (receivingContentRoot.contains(EcoreUtil.getRootContainer(element))) { for (Iterator<EObject> tDiagramElIt = EcoreUtil.getAllContents(receivingDiagramRoot); tDiagramElIt.hasNext();) { EObject tNext = tDiagramElIt.next(); if (tNext instanceof GraphElement) { GraphElement tDiagramEl = (GraphElement) tNext; EObject tElement = findSematicModelElement(tDiagramEl); if (container != null && container.equals(tElement) //some elements have several representations: do not add to node, what was in diagram before && diagramEl.eContainer().eClass().equals(tDiagramEl.eClass())) { addToSuitableReference(tDiagramEl, diagramEl); change = true; result = true; break; } } } } } if (change) { break; } } } return result; } private void rerouteDiagram(EList<EObject> diagramWithOldElements, EList<EObject> diagramWithNewElements, EList<EObject> additionalDiagrams) { EList<EObject> allDiagrams = new BasicEList<EObject>(diagramWithNewElements); allDiagrams.addAll(diagramWithOldElements); allDiagrams.addAll(additionalDiagrams); for (TreeIterator<EObject> diagramElIt = EcoreUtil.getAllContents(allDiagrams); diagramElIt.hasNext();) { EObject next = diagramElIt.next(); if (next instanceof GraphElement) { GraphElement diagramEl = (GraphElement) next; EObject element = findSematicModelElement(diagramEl); if (element == null) { continue; } //look for anchored replacements List<EObject> replacedValues = CompositionDiagramUtil.getReplacedValues(element); for (EObject replacedValue : replacedValues) { //find diagram element of reference for (Iterator<EObject> replacedDiagramElIt = EcoreUtil.getAllContents(allDiagrams); replacedDiagramElIt.hasNext();) { EObject replacedNext = replacedDiagramElIt.next(); if (replacedNext instanceof GraphElement) { GraphElement replacedDiagramEl = (GraphElement) replacedNext; if (diagramEl.eClass().equals(replacedDiagramEl.eClass())) { EObject replacedElementCand = findSematicModelElement(replacedDiagramEl); //EObject originalReplacedElementCand = CompositionDiagramUtil.getOriginal(replacedElementCand); //EObject originalReplacedValue = CompositionDiagramUtil.getOriginal(replacedValue); if (replacedValue.equals(replacedElementCand)) { diagramEl.getAnchorage().addAll(replacedDiagramEl.getAnchorage()); break; } } } } } //look for anchored containers GraphElement container = null; for (Iterator<EObject> replacedDiagramElIt = EcoreUtil.getAllContents(diagramWithNewElements); replacedDiagramElIt.hasNext();) { EObject otherNext = replacedDiagramElIt.next(); if (otherNext instanceof GraphElement) { GraphElement otherDiagramEl = (GraphElement) otherNext; if (element.eContainer() != null && element.eContainer().equals(findSematicModelElement(otherDiagramEl))) { container = otherDiagramEl; } } } if (container != null) { for (Iterator<EObject> replacedDiagramElIt = EcoreUtil.getAllContents(diagramWithOldElements); replacedDiagramElIt.hasNext();) { EObject otherNext = replacedDiagramElIt.next(); if (otherNext instanceof GraphElement) { GraphElement otherDiagramEl = (GraphElement) otherNext; if (otherDiagramEl.eClass().equals(container.eClass())) { EObject otherSematicModelElement = findSematicModelElement(otherDiagramEl); EObject sematicModelElement = findSematicModelElement(container); if (sematicModelElement != null && otherSematicModelElement != null && otherSematicModelElement.eClass().equals(sematicModelElement.eClass())) { for (GraphConnector connector : new BasicEList<GraphConnector>(otherDiagramEl.getAnchorage())) { if (connector.getGraphEdge().contains(diagramEl)) { container.getAnchorage().add(connector); } } } } } } } } } } private void addToSuitableReference(GraphElement container, DiagramElement value) { container.getContained().add(value); } private EObject findSematicModelElement(EObject diagramElement) { EObject element = null; if (diagramElement instanceof GraphElement) { GraphElement ge = (GraphElement) diagramElement; SemanticModelBridge bridge = ge.getSemanticModel(); if (bridge instanceof EMFSemanticModelBridge) { element = ((EMFSemanticModelBridge) bridge).getElement(); } } return element; } }