package org.eclipse.uml2.diagram.timing.edit.policies; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gef.Request; import org.eclipse.gef.commands.Command; import org.eclipse.gef.editpolicies.AbstractEditPolicy; import org.eclipse.gef.requests.ChangeBoundsRequest; import org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand; import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand; import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; import org.eclipse.gmf.runtime.notation.Bounds; import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.gmf.runtime.notation.Edge; import org.eclipse.gmf.runtime.notation.LayoutConstraint; import org.eclipse.gmf.runtime.notation.Node; import org.eclipse.gmf.runtime.notation.Size; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.uml2.diagram.timing.edit.parts.DSegmentEditPart; import org.eclipse.uml2.diagram.timing.edit.parts.DTickEditPart; import org.eclipse.uml2.diagram.timing.model.timingd.DSegment; import org.eclipse.uml2.diagram.timing.model.timingd.DSegmentElement; import org.eclipse.uml2.diagram.timing.model.timingd.DSegmentEnd; import org.eclipse.uml2.diagram.timing.model.timingd.DSegmentMiddlePoint; import org.eclipse.uml2.diagram.timing.model.timingd.DSegmentStart; import org.eclipse.uml2.diagram.timing.model.timingd.DStateSwitch; import org.eclipse.uml2.diagram.timing.model.timingd.DTick; public class MoveSegmentEditPolicy extends AbstractEditPolicy { public static final String ROLE = MoveSegmentEditPolicy.class.getName() + ":ROLE"; @Override public Command getCommand(Request request) { if (request instanceof ChangeBoundsRequest){ return getAdjustRelatedSegmentsCommand((ChangeBoundsRequest)request); } return super.getCommand(request); } private TransactionalEditingDomain getDomain(){ return getHostImpl().getEditingDomain(); } private IGraphicalEditPart getHostImpl(){ return ((IGraphicalEditPart)getHost()); } private Command getAdjustRelatedSegmentsCommand(ChangeBoundsRequest req){ Point moveDelta = req.getMoveDelta(); if (moveDelta == null){ return null; } CompositeTransactionalCommand cc = new CompositeTransactionalCommand(getDomain(), "Adjust related segments"); Map<EObject, View> domain2Notation = new Domain2NotationCollector().collectAll(getHostImpl().getNotationView().getDiagram()); AffectedTicksCollector ticksCollector = new AffectedTicksCollector(); for (Object next : req.getEditParts()){ if (next instanceof DSegmentEditPart){ DSegmentEditPart nextEP = (DSegmentEditPart)next; DSegment nextSegment = (DSegment) nextEP.resolveSemanticElement(); DSegmentStart start = nextSegment.getStart(); DSegmentEnd end = nextSegment.getEnd(); ticksCollector.addAffectedSegment(nextSegment); if (start != null){ DStateSwitch incomingSwitch = start.getIncomingSwitch(); if (incomingSwitch != null){ DSegment fromSegment = incomingSwitch.getFromSegment(); if (fromSegment != null){ ticksCollector.addSegmentElement(fromSegment.getEnd()); View fromSegmentView = domain2Notation.get(fromSegment); if (fromSegmentView instanceof Node){ LayoutConstraint constr = ((Node)fromSegmentView).getLayoutConstraint(); if (constr instanceof Size){ Size size = (Size)constr; int width = size.getWidth(); if (width > 0){ if (width > -moveDelta.x){ cc.compose(new SetBoundsCommand(getDomain(), "", new EObjectAdapter(fromSegmentView), new Dimension(width + moveDelta.x, size.getHeight()))); } else { cc.compose(UnexecutableCommand.INSTANCE); } } } } } } } if (end != null){ DStateSwitch outgoingSwitch = end.getSwitch(); if (outgoingSwitch != null){ DSegment toSegment = outgoingSwitch.getToSegment(); if (toSegment != null){ ticksCollector.addSegmentElement(toSegment.getStart()); View toSegmentView = domain2Notation.get(toSegment); if (toSegmentView instanceof Node){ LayoutConstraint constr = ((Node)toSegmentView).getLayoutConstraint(); if (constr instanceof Bounds){ Bounds bounds = (Bounds)constr; int width = bounds.getWidth(); if (width > moveDelta.x){ Rectangle newBounds = new Rectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()); newBounds.x += moveDelta.x; newBounds.width -= moveDelta.x; cc.compose(new SetBoundsCommand(getDomain(), "", new EObjectAdapter(toSegmentView), newBounds)); } else { cc.compose(UnexecutableCommand.INSTANCE); } } } } } } } } Command result = null; if (!ticksCollector.isEmpty()){ for (DTick nextAffectedTick : ticksCollector.getTicks()){ View tickView = domain2Notation.get(nextAffectedTick); if (tickView == null){ continue; } DTickEditPart tickEP = (DTickEditPart) getHost().getViewer().getEditPartRegistry().get(tickView); if (tickEP != null){ ChangeBoundsRequest moveTickRequest = new ChangeBoundsRequest(REQ_MOVE); moveTickRequest.setMoveDelta(req.getMoveDelta()); moveTickRequest.setSizeDelta(new Dimension(0, 0)); moveTickRequest.setLocation(req.getLocation()); moveTickRequest.setExtendedData(req.getExtendedData()); moveTickRequest.getExtendedData().put(MoveTickEditPolicy.KEY_INITIATED_FROM_CIRCLE, getHostImpl()); Command moveTickCommand = tickEP.getCommand(moveTickRequest); moveTickRequest.getExtendedData().put(MoveTickEditPolicy.KEY_INITIATED_FROM_CIRCLE, null); result = chain(result, moveTickCommand); } } } if (cc.size() == 0){ return result; } return chain(result, new ICommandProxy(cc.reduce())); } private static class Domain2NotationCollector { private Map<EObject, View> myResult; public Map<EObject, View> collectAll(View view){ myResult = new HashMap<EObject, View>(); visit(view); if (false == view instanceof Diagram){ visitDiagramLinks(view.getDiagram()); } Map<EObject, View> result = myResult; myResult = null; return result; } private void visit(View root){ register(root); for (Object next : root.getChildren()){ if (next instanceof Edge && false == root instanceof Diagram){ continue; } visit((View)next); } } private void register(View view){ if (view.getElement() != null){ myResult.put(view.getElement(), view); } } private void visitDiagramLinks(Diagram diagram){ for (Object next : diagram.getChildren()){ if (next instanceof Edge){ register((Edge)next); } } } } private static class AffectedTicksCollector { private final List<DTick> myTicks; public AffectedTicksCollector(){ myTicks = new LinkedList<DTick>(); } public Iterable<DTick> getTicks(){ return myTicks; } public boolean isEmpty(){ return myTicks.isEmpty(); } public void addSegmentElement(DSegmentElement circle){ if (circle != null && circle.getTick() != null){ myTicks.add(circle.getTick()); } } public void addAffectedSegment(DSegment segment){ if (segment == null){ return; } addSegmentElement(segment.getStart()); addSegmentElement(segment.getEnd()); for (DSegmentMiddlePoint nextMiddle : segment.getMiddlePoints()){ addSegmentElement(nextMiddle); } } } private static Command chain(Command first, Command second){ return first == null ? second : first.chain(second); } }