/** * This file is protected by Copyright. * Please refer to the COPYRIGHT file distributed with this source distribution. * * This file is part of REDHAWK IDE. * * 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 gov.redhawk.ide.graphiti.ui.diagram.util; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.graphiti.datatypes.ILocation; import org.eclipse.graphiti.features.IFeatureProvider; import org.eclipse.graphiti.features.IUpdateFeature; import org.eclipse.graphiti.features.context.IResizeShapeContext; import org.eclipse.graphiti.features.context.impl.UpdateContext; import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; import org.eclipse.graphiti.mm.pictograms.Anchor; import org.eclipse.graphiti.mm.pictograms.ContainerShape; import org.eclipse.graphiti.mm.pictograms.Diagram; import org.eclipse.graphiti.mm.pictograms.PictogramElement; import org.eclipse.graphiti.mm.pictograms.PictogramLink; import org.eclipse.graphiti.mm.pictograms.Shape; import org.eclipse.graphiti.services.Graphiti; import org.eclipse.graphiti.ui.services.GraphitiUi; import gov.redhawk.core.graphiti.ui.ext.RHContainerShape; import gov.redhawk.ide.graphiti.ui.diagram.patterns.AbstractFindByPattern; import mil.jpeojtrs.sca.partitioning.FindBy; import mil.jpeojtrs.sca.partitioning.FindByStub; import mil.jpeojtrs.sca.partitioning.ProvidesPortStub; import mil.jpeojtrs.sca.partitioning.UsesPortStub; import mil.jpeojtrs.sca.sad.HostCollocation; public class DUtil extends gov.redhawk.core.graphiti.ui.util.DUtil { /** * Returns all of the shape children recursively * @param diagramElement * @return */ public static List<Shape> collectShapeChildren(Shape diagramElement) { List<Shape> children = new ArrayList<Shape>(); children.add(diagramElement); // if containershape, collect children recursively if (diagramElement instanceof ContainerShape) { ContainerShape cs = (ContainerShape) diagramElement; for (Shape c : cs.getChildren()) { children.addAll(collectShapeChildren(c)); } } return children; } /** * Remove Business object from all linked PictogramElement * @param diagram * @param eObject */ public static void removeBusinessObjectFromAllPictogramElements(Diagram diagram, EObject eObject) { // get pe with link to bo List<PictogramElement> pictogramElements = Graphiti.getLinkService().getPictogramElements(diagram, eObject); // remove link for (PictogramElement pe : pictogramElements) { pe.getLink().getBusinessObjects().remove(eObject); } } public static void addLink(IFeatureProvider featureProvider, PictogramElement pe, EObject eObject) { if (eObject == null) { return; } if (pe.getLink() == null) { featureProvider.link(pe, eObject); } else { pe.getLink().getBusinessObjects().add(eObject); } } public static void addLinks(IFeatureProvider featureProvider, PictogramElement pe, Collection< ? extends EObject> eObjects) { if (eObjects == null || eObjects.size() < 1) { return; } if (pe.getLink() == null) { featureProvider.link(pe, eObjects.toArray()); } else { pe.getLink().getBusinessObjects().addAll(eObjects); } } /** * Returns the ancestor (parent chain) of the provided diagramElement with the provided PropertyContainer * @param diagramElement * @return */ public static ContainerShape findContainerShapeParentWithProperty(Shape shape, String propertyValue) { if (shape instanceof Diagram) { return null; } if (shape instanceof ContainerShape && DUtil.isPropertyElementType(shape, propertyValue)) { return (ContainerShape) shape; } if (DUtil.isPropertyElementType(shape.getContainer(), propertyValue)) { return shape.getContainer(); } return findContainerShapeParentWithProperty(shape.getContainer(), propertyValue); } /** * Returns the ancestor (parent chain) of the provided diagramElement with the provided PropertyContainer * First checks self to see if it is a container with matching property * @param diagramElement * @return */ public static ContainerShape findContainerShapeParentWithProperty(PictogramElement pe, String propertyValue) { if (pe instanceof ContainerShape && DUtil.isPropertyElementType(pe, propertyValue)) { return (ContainerShape) pe; } PictogramElement peContainer = Graphiti.getPeService().getActiveContainerPe(pe); if (peContainer instanceof ContainerShape) { ContainerShape outerContainerShape = DUtil.findContainerShapeParentWithProperty((ContainerShape) peContainer, propertyValue); return outerContainerShape; } return null; } /** * Checks the container shape and all its children and returns any which overlap any of the specified area. * @param containerShape Usually this should be the {@link Diagram} * @param width * @param height * @param x Absolute x * @param y Absolute y * @return */ public static List<Shape> getShapesInArea(final ContainerShape containerShape, int width, int height, int x, int y) { List<Shape> retList = new ArrayList<Shape>(); EList<Shape> shapes = containerShape.getChildren(); for (Shape s : shapes) { if (shapeExistsPartiallyInArea(s, width, height, x, y)) { retList.add(s); } } return retList; } /** * Returns true if the specified area overlaps any part of a host collocation. * @param diagram * @param width * @param height * @param x Absolute x * @param y Absolute y * @return */ public static boolean overlapsHostCollocation(Diagram diagram, int width, int height, int x, int y) { for (Shape shape : diagram.getChildren()) { PictogramElement pe = shape.getLink().getPictogramElement(); if (!(DUtil.getBusinessObject(pe) instanceof HostCollocation)) { continue; } if (shapeExistsPartiallyInArea(shape, width, height, x, y)) { return true; } } return false; } /** * Adjust children x/y so they remain in the same relative position after resize * @param containerShape * @param context */ public static void shiftChildrenRelativeToParentResize(ContainerShape containerShape, IResizeShapeContext context) { int widthDiff = containerShape.getGraphicsAlgorithm().getWidth() - context.getWidth(); int heightDiff = containerShape.getGraphicsAlgorithm().getHeight() - context.getHeight(); switch (context.getDirection()) { case (IResizeShapeContext.DIRECTION_NORTH_EAST): shiftChildrenYPositionUp(containerShape, heightDiff); break; case (IResizeShapeContext.DIRECTION_WEST): case (IResizeShapeContext.DIRECTION_SOUTH_WEST): shiftChildrenXPositionLeft(containerShape, widthDiff); break; case (IResizeShapeContext.DIRECTION_NORTH_WEST): shiftChildrenXPositionLeft(containerShape, widthDiff); shiftChildrenYPositionUp(containerShape, heightDiff); break; case (IResizeShapeContext.DIRECTION_NORTH): // handle top of box getting smaller shiftChildrenYPositionUp(containerShape, heightDiff); break; default: break; } } /** * Shifts children of container x value to the left by specified amount * Can be negative * @param ga * @param shiftLeftAmount */ private static void shiftChildrenXPositionLeft(ContainerShape containerShape, int shiftLeftAmount) { for (Shape s : containerShape.getChildren()) { GraphicsAlgorithm ga = s.getGraphicsAlgorithm(); Graphiti.getGaService().setLocation(ga, ga.getX() - shiftLeftAmount, ga.getY()); } } /** * Shifts children of container Y value up by specified amount * Can be negative * @param ga * @param shiftUpAmount */ private static void shiftChildrenYPositionUp(ContainerShape containerShape, int shiftUpAmount) { for (Shape s : containerShape.getChildren()) { GraphicsAlgorithm ga = s.getGraphicsAlgorithm(); Graphiti.getGaService().setLocation(ga, ga.getX(), ga.getY() - shiftUpAmount); } } /** * Checks the container shape and all its children and returns any which do not overlap any of the specified area. * @param containerShape Usually this should be the {@link Diagram} * @param width * @param height * @param x Absolute x * @param y Absolute y * @return */ public static List<Shape> getShapesOutsideArea(final ContainerShape containerShape, int width, int height, int x, int y) { List<Shape> retList = new ArrayList<Shape>(); EList<Shape> shapes = containerShape.getChildren(); for (Shape s : shapes) { if (!shapeExistsPartiallyInArea(s, width, height, x, y)) { retList.add(s); } } return retList; } /** * Determine if a shape overlaps an area. Coordinates should be absolute. * @param s * @param width * @param height * @param x * @param y * @return */ public static boolean shapeExistsPartiallyInArea(final Shape s, int width, int height, int x, int y) { GraphicsAlgorithm ga = s.getGraphicsAlgorithm(); ILocation shapeLoc = GraphitiUi.getUiLayoutService().getLocationRelativeToDiagram(s); return ((x + width) > ga.getX() && x < (shapeLoc.getX() + ga.getWidth()) && (y + height) > ga.getY() && y < (shapeLoc.getY() + ga.getHeight())); } /** * Returns all ContainerShapes with the provided property value * @param containerShape * @param propertyValue * @return */ public static List<ContainerShape> getAllContainerShapes(ContainerShape containerShape, String propertyValue) { List<ContainerShape> children = new ArrayList<ContainerShape>(); if (containerShape instanceof ContainerShape && isPropertyElementType(containerShape, propertyValue)) { children.add(containerShape); } else { for (Shape s : containerShape.getChildren()) { if (s instanceof ContainerShape) { children.addAll(getAllContainerShapes((ContainerShape) s, propertyValue)); } } } return children; } /** * Returns true if Pictogram Link contains an object of the provided Class * @param <T> * @param link * @param cls * @return */ public static < T > boolean doesLinkContainObjectTypeInstance(PictogramLink link, Class<T> cls) { if (link != null) { for (EObject eObj : link.getBusinessObjects()) { if (cls.isInstance(eObj)) { return true; } } } return false; } /** * Update PictogramElement via feature * Relies on the framework determining which feature should be used and whether it can be added to diagram * @param featureProvider * @param pe * @return */ public static boolean updateShapeViaFeature(IFeatureProvider featureProvider, Diagram diagram, PictogramElement pe) { UpdateContext updateContext = new UpdateContext(pe); IUpdateFeature updateFeature = featureProvider.getUpdateFeature(updateContext); if (updateFeature.canUpdate(updateContext)) { return updateFeature.update(updateContext); } return false; } /** * Search for the FindByStub in the diagram given the findBy object * @param findBy * @param diagram * @return */ public static FindByStub findFindByStub(FindBy findBy, Diagram diagram) { for (RHContainerShape findByShape : AbstractFindByPattern.getAllFindByShapes(diagram)) { FindByStub findByStub = (FindByStub) DUtil.getBusinessObject(findByShape); // determine findBy match if (findByStub != null && AbstractFindByPattern.doFindByObjectsMatch(findBy, findByStub)) { // it matches return findByStub; } } return null; } /** * Return true if target is HostCollocation ContainerShape * @param context */ public static HostCollocation getHostCollocation(final ContainerShape targetContainerShape) { if (targetContainerShape instanceof ContainerShape) { if (targetContainerShape.getLink() != null && targetContainerShape.getLink().getBusinessObjects() != null) { for (EObject obj : targetContainerShape.getLink().getBusinessObjects()) { if (obj instanceof HostCollocation) { return (HostCollocation) obj; } } } } return null; } // convenient method for getting diagram for a ContainerShape public static Diagram findDiagram(ContainerShape containerShape) { return Graphiti.getPeService().getDiagramForShape(containerShape); } /** * If a provides port with the port name still exists, return the new anchor so the connection can be redrawn * @param providesPortStubs * @param oldPortName * @return Anchor object that is associated with the port */ public static Anchor getProvidesAnchor(Diagram diagram, EList<ProvidesPortStub> providesPortStubs, String oldPortName) { for (ProvidesPortStub port : providesPortStubs) { if (port.getName().equals(oldPortName)) { Anchor anchor = (Anchor) DUtil.getPictogramElementForBusinessObject(diagram, (EObject) port, Anchor.class); return anchor; } } return null; } /** * If a uses port with the port name still exists, return the new anchor so the connection can be redrawn * @param usesPortStubs * @param oldPortName * @return Anchor object that is associated with the port */ public static Anchor getUsesAnchor(Diagram diagram, EList<UsesPortStub> usesPortStubs, String oldPortName) { for (UsesPortStub port : usesPortStubs) { if (port.getName().equals(oldPortName)) { Anchor anchor = (Anchor) DUtil.getPictogramElementForBusinessObject(diagram, (EObject) port, Anchor.class); return anchor; } } return null; } }