/******************************************************************************* * Copyright (c) 2014, 2015 Cisco Systems, Inc. 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 * *******************************************************************************/ package com.cisco.yangide.ext.model.editor.util; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.emf.common.util.ECollections; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.graphiti.datatypes.IDimension; import org.eclipse.graphiti.features.IFeatureProvider; import org.eclipse.graphiti.features.IRemoveFeature; import org.eclipse.graphiti.features.context.IAddConnectionContext; import org.eclipse.graphiti.features.context.IAddContext; import org.eclipse.graphiti.features.context.impl.AddConnectionContext; import org.eclipse.graphiti.features.context.impl.AddContext; import org.eclipse.graphiti.features.context.impl.LayoutContext; import org.eclipse.graphiti.features.context.impl.RemoveContext; import org.eclipse.graphiti.features.context.impl.UpdateContext; import org.eclipse.graphiti.mm.algorithms.Ellipse; import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; import org.eclipse.graphiti.mm.algorithms.Image; import org.eclipse.graphiti.mm.algorithms.Polyline; import org.eclipse.graphiti.mm.algorithms.RoundedRectangle; import org.eclipse.graphiti.mm.algorithms.Text; import org.eclipse.graphiti.mm.pictograms.Anchor; import org.eclipse.graphiti.mm.pictograms.AnchorContainer; import org.eclipse.graphiti.mm.pictograms.BoxRelativeAnchor; import org.eclipse.graphiti.mm.pictograms.ChopboxAnchor; import org.eclipse.graphiti.mm.pictograms.Connection; import org.eclipse.graphiti.mm.pictograms.ConnectionDecorator; 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.Shape; import org.eclipse.graphiti.services.Graphiti; import org.eclipse.graphiti.services.IGaService; import org.eclipse.graphiti.services.IPeCreateService; import org.eclipse.graphiti.ui.services.GraphitiUi; import com.cisco.yangide.ext.model.ContainingNode; import com.cisco.yangide.ext.model.NamedNode; import com.cisco.yangide.ext.model.TypedNode; import com.cisco.yangide.ext.model.Typeref; public class YangModelUIUtil { private YangModelUIUtil() { super(); } public static final int DEFAULT_WIDTH = 225; public static final int DEFAULT_TEXT_HEIGHT = 18; public static final int DEFAULT_V_ALIGN = 5; public static final int DEFAULT_H_ALIGN = 2; public static final int DEFAULT_OBJECT_NUMBER_IND = 2; public static final int DEFAULT_BOX_ANCHOR_RADIUS = 2; public static final int DEFAULT_COMPOSITE_HEIGHT = 30; private static final ShapeVerticalComparator COMPARATOR = new ShapeVerticalComparator(); private static Map<EAttribute, String> attributeShapes = new HashMap<EAttribute, String>(); static { attributeShapes.put(YangModelUtil.MODEL_PACKAGE.getNamedNode_Name(), PropertyUtil.OBJECT_HEADER_TEXT_SHAPE_KEY); attributeShapes.put(YangModelUtil.MODEL_PACKAGE.getUses_QName(), PropertyUtil.OBJECT_HEADER_TEXT_SHAPE_KEY); } private static class ShapeVerticalComparator implements Comparator<Shape> { @Override public int compare(Shape o1, Shape o2) { if (null == o1 && null == o2) { return 0; } if (null != o1 && null == o2) { return 1; } if (null == o1 && null != o2) { return -1; } if (PropertyUtil.isBusinessObjectShape(o1) && PropertyUtil.isBusinessObjectShape(o2)) { return o1.getGraphicsAlgorithm().getY() > o2.getGraphicsAlgorithm().getY() ? 1 : o1.getGraphicsAlgorithm().getY() == o2.getGraphicsAlgorithm().getY() ? 0 : -1; } return o1.getGraphicsAlgorithm().getY() + o1.getGraphicsAlgorithm().getHeight() > o2.getGraphicsAlgorithm().getY() + o2.getGraphicsAlgorithm().getHeight() ? 1 : o1.getGraphicsAlgorithm().getY() + o1.getGraphicsAlgorithm().getHeight() == o2.getGraphicsAlgorithm().getY() + o2.getGraphicsAlgorithm().getHeight() ? 0 : -1; } } public static void sortPictogramElements(EList<Shape> elements) { ECollections.sort(elements, COMPARATOR); } public static void sortPictogramElements(List<Shape> elements) { Collections.sort(elements, COMPARATOR); } public static int getPositionInParent(ContainerShape parent, Shape child, IFeatureProvider fp) { EList<Shape> elements = parent.getChildren(); sortPictogramElements(elements); int pos = 0; for (Shape shape : elements) { if (child == shape) { return pos; } if (null != fp.getBusinessObjectForPictogramElement(shape) && YangModelUtil.checkType(YangModelUtil.MODEL_PACKAGE.getContainingNode(), fp.getBusinessObjectForPictogramElement(parent)) && ((ContainingNode) fp.getBusinessObjectForPictogramElement(parent)).getChildren() .contains(fp.getBusinessObjectForPictogramElement(shape))) { pos++; } } return pos; } public static int getPositionInParent(ContainerShape parent, int y, IFeatureProvider fp) { List<Shape> elements = filterBusinessObjectShapes(parent.getChildren()); sortPictogramElements(elements); int pos = 0; for (Shape shape : elements) { if (null != fp.getBusinessObjectForPictogramElement(shape) && YangModelUtil.checkType(YangModelUtil.MODEL_PACKAGE.getContainingNode(), fp.getBusinessObjectForPictogramElement(parent)) && ((ContainingNode) fp.getBusinessObjectForPictogramElement(parent)).getChildren() .contains(fp.getBusinessObjectForPictogramElement(shape))) { if (y < shape.getGraphicsAlgorithm().getY()) { return pos; } pos++; } } return pos; } public static void layoutPictogramElement(PictogramElement diagram, IFeatureProvider fp) { LayoutContext lc = new LayoutContext(diagram); fp.layoutIfPossible(lc); } public static Anchor getChopboxAnchor(AnchorContainer ac) { if (null != ac) { return Graphiti.getPeService().getChopboxAnchor(ac); } return null; } public static Anchor getBoxRelativeAnchor(AnchorContainer ac) { if (null != ac) { for (Anchor a : ac.getAnchors()) { if (a instanceof BoxRelativeAnchor) { return a; } } } return null; } public static List<Shape> filterBusinessObjectShapes(List<Shape> shapes) { List<Shape> result = new ArrayList<Shape>(); for (Shape shape : shapes) { if (PropertyUtil.isBusinessObjectShape(shape)) { result.add(shape); } } return result; } public static Shape getBusinessObjectPropShape(ContainerShape parent, String prop) { for (Shape shape : parent.getChildren()) { if (PropertyUtil.isObjectShapeProp(shape, prop)) { return shape; } } return null; } public static PictogramElement getBusinessObjectShape(IFeatureProvider fp, EObject obj) { PictogramElement[] pe = fp.getAllPictogramElementsForBusinessObject(obj); for (PictogramElement shape : pe) { if (shape instanceof Diagram || PropertyUtil.isBusinessObjectShape(shape)) { return shape; } } return null; } public static PictogramElement getBusinessObjectPropShape(IFeatureProvider fp, EObject obj, String prop) { PictogramElement[] pe = fp.getAllPictogramElementsForBusinessObject(obj); for (PictogramElement shape : pe) { if (PropertyUtil.isObjectShapeProp(shape, prop)) { return shape; } } return null; } public static PictogramElement getBusinessObjectPropShape(IFeatureProvider fp, EObject obj, EAttribute attr) { if (attributeShapes.containsKey(attr)) { return getBusinessObjectPropShape(fp, obj, attributeShapes.get(attr)); } return null; } public static Polyline getPolyline(ContainerShape cs) { for (Shape shape : cs.getChildren()) { if (shape.getGraphicsAlgorithm() instanceof Polyline) { return (Polyline) shape.getGraphicsAlgorithm(); } } return null; } public static GraphicsAlgorithm getObjectPropGA(ContainerShape cs, String prop) { Shape shape = getBusinessObjectPropShape(cs, prop); if (null != shape) { return shape.getGraphicsAlgorithm(); } return null; } public static void deletePictogramElement(IFeatureProvider fp, PictogramElement pe) { RemoveContext removeContext = new RemoveContext(pe); IRemoveFeature f = fp.getRemoveFeature(removeContext); f.remove(removeContext); } public static void updatePictogramElement(IFeatureProvider fp, PictogramElement pe) { UpdateContext context = new UpdateContext(pe); fp.updateIfPossible(context); } public static boolean updateConnections(EObject obj, IFeatureProvider fp) { if (YangModelUtil.hasReference(obj)) { EObject ref = YangModelUtil.getReferencedObject(fp, obj); PictogramElement startPE = YangModelUIUtil.getBusinessObjectShape(fp, obj); Anchor start = YangModelUIUtil.getBoxRelativeAnchor((AnchorContainer) startPE); Connection con = null; if (null != start && null != start.getOutgoingConnections() && !start.getOutgoingConnections().isEmpty()) { con = start.getOutgoingConnections().get(0); } if (null == ref) { if (null != con) { deletePictogramElement(fp, con); // RemoveContext removeContext = new RemoveContext(con); // fp.getRemoveFeature(removeContext).remove(removeContext); return true; } } else { PictogramElement finishPE = YangModelUIUtil.getBusinessObjectShape(fp, ref); if (null != finishPE) { Anchor finish = YangModelUIUtil.getChopboxAnchor((AnchorContainer) finishPE); if (null != con && con.getEnd().equals(finish)) { return false; } if (null != con) { con.setEnd(finish); } else { YangModelUIUtil.drawConnection(obj, start, finish, fp); } LayoutUtil.layoutDiagramConnections(fp); return true; } } } return false; } public static boolean updateConnections(EClass type, IFeatureProvider fp) { Object module = fp.getBusinessObjectForPictogramElement(fp.getDiagramTypeProvider().getDiagram()); if (null != module && module instanceof EObject) { List<EObject> objects = YangModelUtil.filter(YangModelUtil.getAllBusinessObjects((EObject) module, null), type); for (EObject obj : objects) { updateConnections(obj, fp); } } return false; } public static PictogramElement drawObject(EObject obj, ContainerShape cs, IFeatureProvider fp, int x, int y) { AddContext ac = new AddContext(); ac.setTargetContainer(cs); ac.setLocation(x, y); ac.setNewObject(obj); return fp.addIfPossible(ac); } public static Connection drawConnection(EObject obj, Anchor start, Anchor finish, IFeatureProvider fp) { AddConnectionContext ac = new AddConnectionContext(start, finish); ac.setNewObject(obj); return (Connection) fp.addIfPossible(ac); } public static Connection drawPictogramConnectionElement(IAddConnectionContext context, IFeatureProvider fp) { return drawPictogramConnectionElement(context, fp, Strings.EMPTY_STRING); } public static Connection drawPictogramConnectionElement(IAddConnectionContext context, IFeatureProvider fp, String title) { EObject addedEReference = (EObject) context.getNewObject(); IPeCreateService peCreateService = Graphiti.getPeCreateService(); Connection connection = peCreateService.createFreeFormConnection(fp.getDiagramTypeProvider().getDiagram()); connection.setStart(context.getSourceAnchor()); connection.setEnd(context.getTargetAnchor()); IGaService gaService = Graphiti.getGaService(); Polyline polyline = gaService.createPlainPolyline(connection); polyline.setStyle(StyleUtil.getStyleForDomainObject(fp.getDiagramTypeProvider().getDiagram())); // add dynamic text decorator for the reference name ConnectionDecorator textDecorator = peCreateService.createConnectionDecorator(connection, false, 0.5, true); Text text = gaService.createPlainText(textDecorator); text.setStyle(StyleUtil.getStyleForTextDecorator(fp.getDiagramTypeProvider().getDiagram())); gaService.setLocation(text, 10, 0); // set reference name in the text decorator text.setValue(title); // add static graphical decorators (composition and inheritance) if (YangModelUtil.checkType(YangModelUtil.MODEL_PACKAGE.getIdentity(), addedEReference)) { createInheritanceConnectionArrow(connection, fp); } else { createConnectionArrow(connection, fp); } return connection; } public static Polyline createConnectionArrow(Connection connection, IFeatureProvider fp) { ConnectionDecorator cd = Graphiti.getPeCreateService().createConnectionDecorator(connection, false, 1.0, true); Polyline polyline = Graphiti.getGaCreateService().createPlainPolyline(cd, new int[] { -10, 5, 0, 0, -10, -5 }); polyline.setStyle(StyleUtil.getStyleForDomainObject(fp.getDiagramTypeProvider().getDiagram())); return polyline; } public static Polyline createInheritanceConnectionArrow(Connection connection, IFeatureProvider fp) { ConnectionDecorator cd = Graphiti.getPeCreateService().createConnectionDecorator(connection, false, 1.0, true); Polyline polyline = Graphiti.getGaCreateService().createPlainPolygon(cd, new int[] { -10, 5, 0, 0, -10, -5 }); polyline.setStyle(StyleUtil.getStyleForDomainObject(fp.getDiagramTypeProvider().getDiagram())); return polyline; } public static void drawBoxRelativeAnchor(ContainerShape containerShape, IAddContext context, IFeatureProvider fp) { final BoxRelativeAnchor boxAnchor = Graphiti.getPeCreateService().createBoxRelativeAnchor(containerShape); boxAnchor.setRelativeWidth(1.0); boxAnchor.setRelativeHeight(0.5); boxAnchor.setReferencedGraphicsAlgorithm(containerShape.getGraphicsAlgorithm()); final Ellipse ellipse = Graphiti.getGaService().createPlainEllipse(boxAnchor); Graphiti.getGaService().setLocationAndSize(ellipse, -2 * DEFAULT_BOX_ANCHOR_RADIUS, -2 * DEFAULT_BOX_ANCHOR_RADIUS, 2 * DEFAULT_BOX_ANCHOR_RADIUS, 2 * DEFAULT_BOX_ANCHOR_RADIUS); ellipse.setStyle(StyleUtil.getStyleForDomainObject(fp.getDiagramTypeProvider().getDiagram())); } public static String getTypeText(TypedNode node) { if (null != node) { return getTypeText(node.getType()); } return null; } public static String getTypeText(Typeref ref) { if (null != ref) { return " : " + ref.getName(); } return null; } public static void drawPictogramElementHeader(ContainerShape containerShape, IAddContext context, IFeatureProvider fp, String imageId, String title, int width, int height) { final Shape imageShape = Graphiti.getPeCreateService().createShape(containerShape, false); // create and set text graphics algorithm final Image image = Graphiti.getGaService().createImage(imageShape, imageId); image.setHeight(height); image.setWidth(height); image.setStretchH(true); image.setStretchH(true); image.setProportional(true); Graphiti.getGaService().setLocationAndSize(image, DEFAULT_V_ALIGN, 0, height, height); PropertyUtil.setObjectShapeProp(imageShape, PropertyUtil.OBJECT_IMAGE_SHAPE_KEY, true); final Shape textShape = Graphiti.getPeCreateService().createShape(containerShape, false); Text text; if (YangModelUtil.checkType(YangModelUtil.MODEL_PACKAGE.getNamedNode(), context.getNewObject())) { if (null == ((NamedNode) context.getNewObject()).getName()) { ((NamedNode) context.getNewObject()).setName("name"); } text = Graphiti.getGaService().createPlainText(textShape, ((NamedNode) context.getNewObject()).getName()); fp.link(textShape, new Object[] { context.getNewObject(), YangModelUtil.MODEL_PACKAGE.getNamedNode_Name() }); PropertyUtil.setObjectShapeProp(textShape, PropertyUtil.EDITABLE_SHAPE, true); } else { String qName = YangModelUtil.getQNamePresentation((EObject) context.getNewObject()); if (null == qName) { text = Graphiti.getGaService().createPlainText(textShape, title); } else { text = Graphiti.getGaService().createPlainText(textShape, qName); fp.link(textShape, context.getNewObject()); } } text.setStyle(StyleUtil.getStyleForDomainObjectText(fp.getDiagramTypeProvider().getDiagram())); PropertyUtil.setObjectShapeProp(textShape, PropertyUtil.OBJECT_HEADER_TEXT_SHAPE_KEY, true); Graphiti.getGaService().setLocationAndSize(text, height + DEFAULT_V_ALIGN, 0, width, height); if (YangModelUtil.checkType(YangModelUtil.MODEL_PACKAGE.getTypedNode(), context.getNewObject())) { Shape typeShape = Graphiti.getPeCreateService().createShape(containerShape, false); Text type = Graphiti.getGaService().createPlainText(typeShape, getTypeText((TypedNode) context.getNewObject())); fp.link(typeShape, context.getNewObject()); type.setStyle(StyleUtil.getStyleForDomainObjectTypeText(fp.getDiagramTypeProvider().getDiagram())); PropertyUtil.setObjectShapeProp(typeShape, PropertyUtil.BUSINESS_OBJECT_TYPE_SHAPE_KEY, true); Graphiti.getGaService().setLocationAndSize(type, height + DEFAULT_V_ALIGN, 0, Math.max(0, width), height); } } public static void drawPictogramElementPositionInParent(ContainerShape shape, IFeatureProvider fp) { Integer pos = YangModelUtil.getPositionInParent(fp.getBusinessObjectForPictogramElement(shape.getContainer()), fp.getBusinessObjectForPictogramElement(shape)); if (0 <= pos) { pos++; final Shape textShape = Graphiti.getPeCreateService().createShape(shape, false); Text text = Graphiti.getGaService().createPlainText(textShape, pos.toString()); text.setStyle(StyleUtil.getStyleForDomainObjectNumberText(fp.getDiagramTypeProvider().getDiagram())); IDimension dim = GraphitiUi.getUiLayoutService().calculateTextSize(text.getValue(), text.getStyle().getFont()); Graphiti.getGaService().setLocationAndSize(text, shape.getGraphicsAlgorithm().getWidth() - DEFAULT_OBJECT_NUMBER_IND, DEFAULT_OBJECT_NUMBER_IND, dim.getWidth(), dim.getHeight()); PropertyUtil.setObjectShapeProp(textShape, PropertyUtil.OBJECT_NUMBER_SHAPE_KEY, true); } } public static ContainerShape drawPictogramElement(IAddContext context, IFeatureProvider fp, String imageId, String title) { ContainerShape result = null; if (YangModelUtil.checkType(YangModelUtil.MODEL_PACKAGE.getContainingNode(), context.getNewObject())) { result = drawCompositePictogramElement(context, fp, imageId, title); } else { result = drawAttributePictogramElement(context, fp, imageId, title); } fp.link(result, context.getNewObject()); ChopboxAnchor anchor = Graphiti.getPeCreateService().createChopboxAnchor(result); anchor.setReferencedGraphicsAlgorithm(result.getGraphicsAlgorithm()); // create BoxRelativeAnchor for references if (context.getNewObject() instanceof EObject && YangModelUtil.hasReference((EObject) context.getNewObject())) { drawBoxRelativeAnchor(result, context, fp); } PropertyUtil.setObjectShapeProp(result, PropertyUtil.BUSINESS_OBJECT_SHAPE_KEY, true); // call the layout feature if (context.getTargetContainer() instanceof Diagram) { drawPictogramElementPositionInParent(result, fp); } // add feedback element final Shape feedbackShape = Graphiti.getPeCreateService().createShape(result, false); Graphiti.getGaService().createPlatformGraphicsAlgorithm(feedbackShape, "feedback"); ContainerShape layoutShape = result; while (!(layoutShape.getContainer() instanceof Diagram)) { layoutShape = layoutShape.getContainer(); } layoutPictogramElement(layoutShape, fp); return result; } public static ContainerShape drawCompositePictogramElement(IAddContext context, IFeatureProvider fp, String imageId, String title) { ContainerShape targetShape = context.getTargetContainer(); IPeCreateService peCreateService = Graphiti.getPeCreateService(); IGaService gaService = Graphiti.getGaService(); ContainerShape containerShape = peCreateService.createContainerShape(targetShape, true); final int width = context.getWidth() <= 0 ? DEFAULT_WIDTH : context.getWidth(); final int height = context.getHeight() <= 0 ? DEFAULT_COMPOSITE_HEIGHT : context.getHeight(); RoundedRectangle roundedRectangle = gaService.createPlainRoundedRectangle(containerShape, 5, 5); roundedRectangle.setStyle(StyleUtil.getStyleForDomainObject(fp.getDiagramTypeProvider().getDiagram())); gaService.setLocationAndSize(roundedRectangle, context.getX(), context.getY(), width, height); // create shape for line final Shape shape = peCreateService.createShape(containerShape, false); // create and set graphics algorithm final Polyline polyline = gaService.createPlainPolyline(shape, new int[] { 0, DEFAULT_TEXT_HEIGHT, width, DEFAULT_TEXT_HEIGHT }); polyline.setStyle(StyleUtil.getStyleForDomainObject(fp.getDiagramTypeProvider().getDiagram())); drawPictogramElementHeader(containerShape, context, fp, imageId, title, width, DEFAULT_TEXT_HEIGHT); return containerShape; } public static ContainerShape drawAttributePictogramElement(IAddContext context, IFeatureProvider fp, String imageId, String title) { ContainerShape targetShape = context.getTargetContainer(); IPeCreateService peCreateService = Graphiti.getPeCreateService(); IGaService gaService = Graphiti.getGaService(); ContainerShape containerShape = peCreateService.createContainerShape(targetShape, true); final int width = context.getWidth() <= 0 ? DEFAULT_WIDTH : context.getWidth(); final int height = context.getHeight() <= 0 ? DEFAULT_TEXT_HEIGHT : context.getHeight(); GraphicsAlgorithm rectangle; if (context.getTargetContainer() instanceof Diagram) { rectangle = gaService.createPlainRoundedRectangle(containerShape, 5, 5); } else { rectangle = gaService.createInvisibleRectangle(containerShape); } rectangle.setStyle(StyleUtil.getStyleForDomainObject(fp.getDiagramTypeProvider().getDiagram())); gaService.setLocationAndSize(rectangle, context.getX(), context.getY(), width, height); drawPictogramElementHeader(containerShape, context, fp, imageId, title, width, DEFAULT_TEXT_HEIGHT); return containerShape; } }