/***************************************************************************** * Copyright (c) 2009 CEA * * * 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: * Atos Origin - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.sequence.edit.policies; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.emf.ecore.EObject; import org.eclipse.gef.EditPart; import org.eclipse.gef.commands.Command; import org.eclipse.gef.commands.UnexecutableCommand; import org.eclipse.gmf.runtime.common.core.command.CompositeCommand; import org.eclipse.gmf.runtime.diagram.core.edithelpers.CreateElementRequestAdapter; import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; import org.eclipse.gmf.runtime.diagram.ui.commands.CommandProxy; import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; import org.eclipse.gmf.runtime.diagram.ui.commands.SemanticCreateCommand; import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand; import org.eclipse.gmf.runtime.diagram.ui.editpolicies.CreationEditPolicy; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest; import org.eclipse.gmf.runtime.diagram.ui.requests.EditCommandRequestWrapper; import org.eclipse.gmf.runtime.diagram.ui.requests.RefreshConnectionsRequest; import org.eclipse.gmf.runtime.emf.type.core.IHintedType; import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.LifelineEditPart; import org.eclipse.papyrus.uml.diagram.sequence.figures.LifelineDotLineCustomFigure; import org.eclipse.papyrus.uml.diagram.sequence.providers.UMLElementTypes; import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceRequestConstant; import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceUtil; import org.eclipse.uml2.uml.InteractionFragment; import org.eclipse.uml2.uml.OccurrenceSpecification; /** * A specific creation edit policy for the Lifeline. * Execution Specification is created graphically on the lifeline, but depending on its graphical position determines also its model container. * * Occurrence Specification is located on the lifeline, but not visible. Though, elements must be created on it. */ public class LifelineCreationEditPolicy extends CreationEditPolicy { @Override protected Command getCreateElementAndViewCommand(CreateViewAndElementRequest request) { // get the element descriptor CreateElementRequestAdapter requestAdapter = request.getViewAndElementDescriptor().getCreateElementRequestAdapter(); // get the semantic request CreateElementRequest createElementRequest = (CreateElementRequest)requestAdapter.getAdapter(CreateElementRequest.class); if(createElementRequest.getContainer() == null) { // complete the semantic request by filling in the host's semantic // element as the context View view = (View)getHost().getModel(); EObject hostElement = ViewUtil.resolveSemanticElement(view); if(hostElement == null && view.getElement() == null) { hostElement = view; } // Returns null if host is unresolvable so that trying to create a // new element in an unresolved shape will not be allowed. if(hostElement == null) { return null; } createElementRequest.setContainer(hostElement); } InteractionFragment ift = SequenceUtil.findInteractionFragmentContainerAt(request.getLocation(), getHost()); Map<String, Object> extendedData = request.getExtendedData(); extendedData.put(SequenceRequestConstant.INTERACTIONFRAGMENT_CONTAINER, ift); // record the nearest event if necessary String requestHint = request.getViewAndElementDescriptor().getSemanticHint(); if(isCreatedOnOccurrenceSpecification(requestHint)) { EditPart hostPart = getHost(); if(hostPart instanceof LifelineEditPart) { Entry<Point, List<OccurrenceSpecification>> eventAndLocation = SequenceUtil.findNearestEvent(request.getLocation(), (LifelineEditPart)hostPart); // find an event near enough to create the constraint or observation List<OccurrenceSpecification> events = Collections.emptyList(); Point location = null; if(eventAndLocation != null) { location = eventAndLocation.getKey(); events = eventAndLocation.getValue(); } if(extendedData.containsKey(SequenceRequestConstant.NEAREST_OCCURRENCE_SPECIFICATION_2)) { extendedData.put(SequenceRequestConstant.NEAREST_OCCURRENCE_SPECIFICATION_2, events); } else { extendedData.put(SequenceRequestConstant.NEAREST_OCCURRENCE_SPECIFICATION, events); } if(extendedData.containsKey(SequenceRequestConstant.OCCURRENCE_SPECIFICATION_LOCATION_2)) { extendedData.put(SequenceRequestConstant.OCCURRENCE_SPECIFICATION_LOCATION_2, location); } else { extendedData.put(SequenceRequestConstant.OCCURRENCE_SPECIFICATION_LOCATION, location); } } } // get the create element command based on the elementdescriptor's // request Command createElementCommand = getHost().getCommand(new EditCommandRequestWrapper((CreateElementRequest)requestAdapter.getAdapter(CreateElementRequest.class), request.getExtendedData())); if(createElementCommand == null) { return UnexecutableCommand.INSTANCE; } if(!createElementCommand.canExecute()) { return createElementCommand; } // create the semantic create wrapper command SemanticCreateCommand semanticCommand = new SemanticCreateCommand(requestAdapter, createElementCommand); Command viewCommand = getCreateCommand(request); Command refreshConnectionCommand = getHost().getCommand(new RefreshConnectionsRequest(((List)request.getNewObject()))); // form the compound command and return CompositeCommand cc = new CompositeCommand(semanticCommand.getLabel()); cc.compose(semanticCommand); cc.compose(new CommandProxy(viewCommand)); if(refreshConnectionCommand != null) { cc.compose(new CommandProxy(refreshConnectionCommand)); } LifelineEditPart parentPart = (LifelineEditPart)getHost(); IHintedType type = (IHintedType)UMLElementTypes.Lifeline_3001; if(type.getSemanticHint().equals(request.getViewAndElementDescriptor().getSemanticHint())) { setChildLifelineBounds(cc, request, parentPart); } return new ICommandProxy(cc); } private void setChildLifelineBounds(CompositeCommand cc, CreateViewAndElementRequest request, LifelineEditPart parentPart) { Point location = request.getLocation().getCopy(); LifelineDotLineCustomFigure parentFigure = (LifelineDotLineCustomFigure) parentPart.getContentPane(); Rectangle parentBounds = parentFigure.getBounds().getCopy(); parentFigure.translateToAbsolute(parentBounds ); Rectangle childBounds = parentBounds.getCopy(); childBounds.height = parentBounds.height; childBounds.width = -1; // default size childBounds.y = 0; // y offset from parent childBounds.x = location.x - parentBounds.x; // x offset from parent SetBoundsCommand cmd = new SetBoundsCommand(parentPart.getEditingDomain(), "set size", request.getViewAndElementDescriptor(), childBounds); cc.compose(cmd); } /** * Return true if creation must be performed on an occurrence specification * * @param requestHint * the hint of object to create * @return true if creation on an occurrence specification */ private boolean isCreatedOnOccurrenceSpecification(String requestHint) { return isTimeHint(requestHint) || isDurationHint(requestHint); } /** * Return true if hint is for creating a duration observation/constraint * * @param requestHint * the hint of object to create * @return true if correct hint */ private boolean isDurationHint(String requestHint) { String durCstOnLifelineHint = ((IHintedType)UMLElementTypes.DurationConstraint_3021).getSemanticHint(); String durCstOnMessage = ((IHintedType)UMLElementTypes.DurationConstraint_3023).getSemanticHint(); String durObsOnMessage = ((IHintedType)UMLElementTypes.DurationObservation_3024).getSemanticHint(); return durCstOnLifelineHint.equals(requestHint) || durCstOnMessage.equals(requestHint) || durObsOnMessage.equals(requestHint); } /** * Return true if hint is for creating a time observation/constraint * * @param requestHint * the hint of object to create * @return true if correct hint */ private boolean isTimeHint(String requestHint) { String timeConstraintHint = ((IHintedType)UMLElementTypes.TimeConstraint_3019).getSemanticHint(); String timeObservationHint = ((IHintedType)UMLElementTypes.TimeObservation_3020).getSemanticHint(); return timeConstraintHint.equals(requestHint) || timeObservationHint.equals(requestHint); } }