/******************************************************************************* * Copyright (c) 2010 protos software gmbh (http://www.protos.de). * 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: * Thomas Schuetz and Henrik Rentz-Reichert (initial contribution) * *******************************************************************************/ package org.eclipse.etrice.ui.behavior.support; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.etrice.core.naming.RoomNameProvider; import org.eclipse.etrice.core.room.ChoicePoint; import org.eclipse.etrice.core.room.RoomFactory; import org.eclipse.etrice.core.room.State; import org.eclipse.etrice.core.room.StateGraph; import org.eclipse.etrice.ui.behavior.ImageProvider; import org.eclipse.etrice.ui.common.support.NoResizeFeature; import org.eclipse.graphiti.dt.IDiagramTypeProvider; import org.eclipse.graphiti.features.IAddFeature; import org.eclipse.graphiti.features.ICreateConnectionFeature; import org.eclipse.graphiti.features.ICreateFeature; import org.eclipse.graphiti.features.IDeleteFeature; import org.eclipse.graphiti.features.IFeatureProvider; import org.eclipse.graphiti.features.IMoveShapeFeature; import org.eclipse.graphiti.features.IReason; import org.eclipse.graphiti.features.IRemoveFeature; import org.eclipse.graphiti.features.IResizeShapeFeature; import org.eclipse.graphiti.features.IUpdateFeature; import org.eclipse.graphiti.features.context.IAddContext; import org.eclipse.graphiti.features.context.ICreateContext; import org.eclipse.graphiti.features.context.IDeleteContext; import org.eclipse.graphiti.features.context.IMoveShapeContext; import org.eclipse.graphiti.features.context.IPictogramElementContext; import org.eclipse.graphiti.features.context.IRemoveContext; import org.eclipse.graphiti.features.context.IResizeShapeContext; import org.eclipse.graphiti.features.context.IUpdateContext; import org.eclipse.graphiti.features.context.impl.CreateConnectionContext; import org.eclipse.graphiti.features.context.impl.RemoveContext; import org.eclipse.graphiti.features.impl.AbstractAddFeature; import org.eclipse.graphiti.features.impl.AbstractCreateFeature; import org.eclipse.graphiti.features.impl.AbstractUpdateFeature; import org.eclipse.graphiti.features.impl.DefaultMoveShapeFeature; import org.eclipse.graphiti.features.impl.DefaultRemoveFeature; import org.eclipse.graphiti.features.impl.Reason; import org.eclipse.graphiti.mm.algorithms.Ellipse; import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; import org.eclipse.graphiti.mm.algorithms.Rectangle; import org.eclipse.graphiti.mm.algorithms.Text; import org.eclipse.graphiti.mm.algorithms.styles.Color; import org.eclipse.graphiti.mm.algorithms.styles.Orientation; import org.eclipse.graphiti.mm.pictograms.Anchor; import org.eclipse.graphiti.mm.pictograms.AnchorContainer; import org.eclipse.graphiti.mm.pictograms.ChopboxAnchor; import org.eclipse.graphiti.mm.pictograms.ContainerShape; 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.tb.ContextButtonEntry; import org.eclipse.graphiti.tb.DefaultToolBehaviorProvider; import org.eclipse.graphiti.tb.IContextButtonPadData; import org.eclipse.graphiti.tb.IToolBehaviorProvider; import org.eclipse.graphiti.ui.features.DefaultDeleteFeature; import org.eclipse.graphiti.ui.features.DefaultFeatureProvider; import org.eclipse.graphiti.util.ColorConstant; import org.eclipse.graphiti.util.IColorConstant; public class ChoicePointSupport { public static final int ITEM_SIZE = StateGraphSupport.MARGIN; protected static final int LINE_WIDTH = 2; protected static final IColorConstant DARK_COLOR = new ColorConstant(0, 0, 0); protected static final IColorConstant INHERITED_COLOR = new ColorConstant(100, 100, 100); protected static final IColorConstant BRIGHT_COLOR = new ColorConstant(255, 255, 255); protected static final String PROP_KIND = "item-kind"; private static class FeatureProvider extends DefaultFeatureProvider { private static class CreateFeature extends AbstractCreateFeature { public CreateFeature(IFeatureProvider fp, String name, String description) { super(fp, name, description); } @Override public String getCreateImageId() { return ImageProvider.IMG_CP; } @Override public Object[] create(ICreateContext context) { StateGraph sg = (StateGraph) context.getTargetContainer().getLink().getBusinessObjects().get(0); // create choice point ChoicePoint cp = RoomFactory.eINSTANCE.createChoicePoint(); String name = RoomNameProvider.getUniqueChoicePointName(sg); cp.setName(name); sg.getChPoints().add(cp); // do the add addGraphicalRepresentation(context, cp); // return newly created business object(s) return new Object[] { cp }; } @Override public boolean canCreate(ICreateContext context) { if (context.getTargetContainer().getLink()!=null) if (context.getTargetContainer().getLink().getBusinessObjects().size()==1) { EObject obj = context.getTargetContainer().getLink().getBusinessObjects().get(0); if (obj instanceof StateGraph) { return true; } } return false; } } private class AddFeature extends AbstractAddFeature { public AddFeature(IFeatureProvider fp) { super(fp); } @Override public boolean canAdd(IAddContext context) { if (context.getNewObject() instanceof ChoicePoint) { if (context.getTargetContainer().getLink().getBusinessObjects().size()==1) { EObject obj = context.getTargetContainer().getLink().getBusinessObjects().get(0); if (obj instanceof StateGraph) { return true; } } } return false; } @Override public PictogramElement add(IAddContext context) { ChoicePoint cp = (ChoicePoint) context.getNewObject(); ContainerShape sgShape = context.getTargetContainer(); Object bo = getBusinessObjectForPictogramElement(sgShape); boolean inherited = isInherited(cp, bo, sgShape); // CONTAINER SHAPE WITH RECTANGLE IPeCreateService peCreateService = Graphiti.getPeCreateService(); ContainerShape containerShape = peCreateService.createContainerShape(sgShape, true); Graphiti.getPeService().setPropertyValue(containerShape, Constants.TYPE_KEY, Constants.TRP_TYPE); int x = context.getX()-ITEM_SIZE; int y = context.getY()-ITEM_SIZE; Color dark = manageColor(inherited? INHERITED_COLOR:DARK_COLOR); IGaService gaService = Graphiti.getGaService(); { final Rectangle invisibleRectangle = gaService.createInvisibleRectangle(containerShape); gaService.setLocationAndSize(invisibleRectangle, x, y, 2*ITEM_SIZE, 2*ITEM_SIZE); createFigure(cp, containerShape, invisibleRectangle, dark, manageColor(BRIGHT_COLOR)); // create link and wire it link(containerShape, cp); } { Shape labelShape = peCreateService.createShape(containerShape, false); Text label = gaService.createDefaultText(labelShape, "C"); label.setForeground(dark); label.setBackground(dark); label.setHorizontalAlignment(Orientation.ALIGNMENT_CENTER); label.setVerticalAlignment(Orientation.ALIGNMENT_CENTER); gaService.setLocationAndSize(label, 0, ITEM_SIZE/2, 2*ITEM_SIZE, ITEM_SIZE); } // call the layout feature layoutPictogramElement(containerShape); return containerShape; } } protected class MoveShapeFeature extends DefaultMoveShapeFeature { public MoveShapeFeature(IFeatureProvider fp) { super(fp); } @Override public boolean canMoveShape(IMoveShapeContext context) { boolean canMove = super.canMoveShape(context); if (canMove) { Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement()); if (bo instanceof ChoicePoint) { ChoicePoint cp = (ChoicePoint) bo; ContainerShape acShape = context.getTargetContainer(); Object parentBO = getBusinessObjectForPictogramElement(acShape); if (isInherited(cp, parentBO, acShape)) return false; return true; } return false; } return canMove; } } private class UpdateFeature extends AbstractUpdateFeature { public UpdateFeature(IFeatureProvider fp) { super(fp); } @Override public boolean canUpdate(IUpdateContext context) { Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement()); if (bo instanceof EObject && ((EObject)bo).eIsProxy()) return true; return bo instanceof ChoicePoint; } @Override public IReason updateNeeded(IUpdateContext context) { Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement()); if (bo instanceof EObject && ((EObject)bo).eIsProxy()) { return Reason.createTrueReason("ChoicePoint deleted from model"); } // check if cp still owned/inherited // TODOHRR-B check inheritance // ChoicePoint cp = (ChoicePoint) bo; // ContainerShape containerShape = (ContainerShape)context.getPictogramElement(); // bo = getBusinessObjectForPictogramElement(containerShape); // if (bo instanceof StateGraph) { // StateGraph sg = (StateGraph) bo; // boolean found = false; // do { // if (sg==cp.eContainer()) // found = true; // sg = sg.getBase(); // } // while (!found && sg!=null); // // if (!found) // return Reason.createTrueReason("TransitionPoint not inherited anymore"); // } return Reason.createFalseReason(); } @Override public boolean update(IUpdateContext context) { ContainerShape containerShape = (ContainerShape)context.getPictogramElement(); Object bo = getBusinessObjectForPictogramElement(containerShape); if (bo instanceof EObject && ((EObject)bo).eIsProxy()) { IRemoveContext rc = new RemoveContext(containerShape); IFeatureProvider featureProvider = getFeatureProvider(); IRemoveFeature removeFeature = featureProvider.getRemoveFeature(rc); if (removeFeature != null) { removeFeature.remove(rc); } EcoreUtil.delete((EObject) bo); return true; } ChoicePoint cp = (ChoicePoint) bo; boolean inherited = isInherited(cp, bo, containerShape); Color dark = manageColor(inherited? INHERITED_COLOR:DARK_COLOR); updateFigure(cp, containerShape, dark, manageColor(BRIGHT_COLOR)); return true; } } protected static class RemoveFeature extends DefaultRemoveFeature { public RemoveFeature(IFeatureProvider fp) { super(fp); } public boolean canRemove(IRemoveContext context) { Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement()); if (bo instanceof ChoicePoint) { ChoicePoint cp = (ChoicePoint) bo; ContainerShape containerShape = (ContainerShape) context.getPictogramElement().eContainer(); Object parentBO = getBusinessObjectForPictogramElement(containerShape); return !isInherited(cp, parentBO, containerShape); } return false; } } protected static class DeleteFeature extends DefaultDeleteFeature { public DeleteFeature(IFeatureProvider fp) { super(fp); } @Override public boolean canDelete(IDeleteContext context) { Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement()); if (bo instanceof ChoicePoint) { ChoicePoint cp = (ChoicePoint) bo; ContainerShape containerShape = (ContainerShape) context.getPictogramElement().eContainer(); Object parentBO = getBusinessObjectForPictogramElement(containerShape); return !isInherited(cp, parentBO, containerShape); } return false; } } protected IFeatureProvider fp; protected FeatureProvider(IDiagramTypeProvider dtp, IFeatureProvider fp) { super(dtp); this.fp = fp; } @Override public ICreateFeature[] getCreateFeatures() { return new ICreateFeature[] { new CreateFeature(fp, "Choice Point", "Create Choice Point") }; } @Override public IAddFeature getAddFeature(IAddContext context) { return new AddFeature(fp); } @Override public IMoveShapeFeature getMoveShapeFeature(IMoveShapeContext context) { return new MoveShapeFeature(fp); } @Override public IResizeShapeFeature getResizeShapeFeature(IResizeShapeContext context) { return new NoResizeFeature(fp); } @Override public IUpdateFeature getUpdateFeature(IUpdateContext context) { return new UpdateFeature(fp); } @Override public IRemoveFeature getRemoveFeature(IRemoveContext context) { return new RemoveFeature(fp); } @Override public IDeleteFeature getDeleteFeature(IDeleteContext context) { return new DeleteFeature(fp); } protected static void createFigure(ChoicePoint cp, ContainerShape containerShape, GraphicsAlgorithm invisibleRectangle, Color darkColor, Color brightColor) { IGaService gaService = Graphiti.getGaService(); Ellipse circle = gaService.createEllipse(invisibleRectangle); circle.setForeground(darkColor); circle.setBackground(brightColor); circle.setLineWidth(LINE_WIDTH); int s2 = ITEM_SIZE/2; gaService.setLocationAndSize(circle, s2, s2, ITEM_SIZE, ITEM_SIZE); if (containerShape.getAnchors().isEmpty()) { // here we place our anchor IPeCreateService peCreateService = Graphiti.getPeCreateService(); // TODOHRR: EllipseAnchor would be nice ChopboxAnchor anchor = peCreateService.createChopboxAnchor(containerShape); anchor.setReferencedGraphicsAlgorithm(circle); } else { // we just set the referenced GA //containerShape.getAnchors().get(0).setReferencedGraphicsAlgorithm(rect); } } private static void updateFigure(ChoicePoint cp, PictogramElement pe, Color dark, Color bright) { ContainerShape container = (ContainerShape)pe; // we clear the figure and rebuild it GraphicsAlgorithm invisibleRect = pe.getGraphicsAlgorithm(); invisibleRect.getGraphicsAlgorithmChildren().clear(); createFigure(cp, container, invisibleRect, dark, bright); } protected static boolean isInherited(ChoicePoint cp, Object container, ContainerShape cs) { if (container instanceof StateGraph) { StateGraph sg = (StateGraph) container; return cp.eContainer()!=sg; } else if (container instanceof State) { // have to check whether the State is inherited State s = (State) container; ContainerShape sCont = cs.getContainer(); EObject cls = sCont.getLink().getBusinessObjects().get(0); return s.eContainer()!=cls; } return false; } } private class BehaviorProvider extends DefaultToolBehaviorProvider { public BehaviorProvider(IDiagramTypeProvider dtp) { super(dtp); } @Override public GraphicsAlgorithm[] getClickArea(PictogramElement pe) { GraphicsAlgorithm invisible = pe.getGraphicsAlgorithm(); GraphicsAlgorithm rectangle = invisible.getGraphicsAlgorithmChildren().get(0); return new GraphicsAlgorithm[] { rectangle }; } @Override public GraphicsAlgorithm getSelectionBorder(PictogramElement pe) { GraphicsAlgorithm invisible = pe.getGraphicsAlgorithm(); GraphicsAlgorithm rectangle = invisible.getGraphicsAlgorithmChildren().get(0); return rectangle; } @Override public IContextButtonPadData getContextButtonPad( IPictogramElementContext context) { IContextButtonPadData data = super.getContextButtonPad(context); PictogramElement pe = context.getPictogramElement(); CreateConnectionContext ccc = new CreateConnectionContext(); ccc.setSourcePictogramElement(pe); Anchor anchor = null; if (pe instanceof AnchorContainer) { // our transition point has four fixed point anchor - we choose the first one anchor = ((ContainerShape)pe).getAnchors().get(0); } ccc.setSourceAnchor(anchor); ContextButtonEntry button = new ContextButtonEntry(null, context); button.setText("Create Transition"); button.setIconId(ImageProvider.IMG_TRANSITION); ICreateConnectionFeature[] features = getFeatureProvider().getCreateConnectionFeatures(); for (ICreateConnectionFeature feature : features) { if (feature.isAvailable(ccc) && feature.canStartConnection(ccc)) button.addDragAndDropFeature(feature); } if (button.getDragAndDropFeatures().size() > 0) { data.getDomainSpecificContextButtons().add(button); } return data; } } private FeatureProvider pfp; private BehaviorProvider tbp; public ChoicePointSupport(IDiagramTypeProvider dtp, IFeatureProvider fp) { pfp = new FeatureProvider(dtp,fp); tbp = new BehaviorProvider(dtp); } public IFeatureProvider getFeatureProvider() { return pfp; } public IToolBehaviorProvider getToolBehaviorProvider() { return tbp; } }