/* $Id: UMLSequenceDiagram.java 18355 2010-04-29 08:18:48Z bobtarling $ ***************************************************************************** * Copyright (c) 2009 Contributors - see below * 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: * bobtarling ***************************************************************************** * * Some portions of this file was previously release using the BSD License: */ // Copyright (c) 2007-2009 The Regents of the University of California. All // Rights Reserved. Permission to use, copy, modify, and distribute this // software and its documentation without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph appear in all copies. This software program and // documentation are copyrighted by The Regents of the University of // California. The software program and documentation are supplied "AS // IS", without any accompanying services from The Regents. The Regents // does not warrant that the operation of the program will be // uninterrupted or error-free. The end-user understands that the program // was developed for research purposes and is advised not to rely // exclusively on the program for any reason. IN NO EVENT SHALL THE // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. package org.argouml.sequence2.diagram; import java.awt.Point; import java.awt.Rectangle; import java.beans.PropertyVetoException; import java.util.Collection; import java.util.List; import org.apache.log4j.Logger; import org.argouml.i18n.Translator; import org.argouml.model.CollaborationsHelper; import org.argouml.model.Facade; import org.argouml.model.Model; import org.argouml.uml.diagram.DiagramElement; import org.argouml.uml.diagram.DiagramSettings; import org.argouml.uml.diagram.SequenceDiagram; import org.argouml.uml.diagram.static_structure.ui.FigComment; import org.argouml.uml.diagram.ui.ActionSetMode; import org.argouml.uml.diagram.ui.FigNodeModelElement; import org.argouml.uml.diagram.ui.RadioAction; import org.argouml.uml.diagram.ui.UMLDiagram; import org.tigris.gef.base.Editor; import org.tigris.gef.base.Globals; import org.tigris.gef.base.LayerPerspective; import org.tigris.gef.base.LayerPerspectiveMutable; import org.tigris.gef.base.ModePlace; import org.tigris.gef.graph.GraphFactory; import org.tigris.gef.graph.GraphModel; import org.tigris.gef.graph.MutableGraphModel; import org.tigris.gef.presentation.Fig; import org.tigris.gef.presentation.FigNode; /** * The diagram for sequence diagrams. * * @author penyaskito */ public class UMLSequenceDiagram extends UMLDiagram implements SequenceDiagram { private Object[] actions; private static final Logger LOG = Logger .getLogger(UMLSequenceDiagram.class); /** * TODO: Document! * * @deprecated for 0.28 by tfmorris. Use * {@link #UMLActivityDiagram(String, Object, GraphModel)}. */ @Deprecated public UMLSequenceDiagram() { super(); // Create the graph model MutableGraphModel gm = new SequenceDiagramGraphModel(); setGraphModel(gm); // Create the layer LayerPerspective lay = new LayerPerspectiveMutable(this.getName(), gm); setLayer(lay); // Create the renderer SequenceDiagramRenderer renderer = new SequenceDiagramRenderer(); lay.setGraphNodeRenderer(renderer); lay.setGraphEdgeRenderer(renderer); LOG.debug("Created sequence diagram"); } /** * Creates a new UmlSequenceDiagram with a collaboration. * @param collaboration The collaboration * */ public UMLSequenceDiagram(Object collaboration) { this(); if (LOG.isDebugEnabled()) { LOG.debug("Constructing Sequence Diagram for collaboration " + collaboration); } try { this.setName(getNewDiagramName()); } catch (PropertyVetoException e) { LOG.error("Exception", e); } ((SequenceDiagramGraphModel) getGraphModel()). setCollaboration(collaboration); setNamespace(collaboration); } /** * Method called by PGML parser during diagram load to initialize a diagram. * We are passed the owner of that diagram which is the collaboration. * @param owner UML model element representing the collaboration * @see org.tigris.gef.base.Diagram#initialize(java.lang.Object) */ @Override public void initialize(Object owner) { super.initialize(owner); SequenceDiagramGraphModel gm = (SequenceDiagramGraphModel) getGraphModel(); gm.setCollaboration(owner); } /** * Get the Uml actions that can be performed in the diagram * @return An array with the Uml actions * @see org.argouml.uml.diagram.ui.UMLDiagram#getUmlActions() */ @Override protected Object[] getUmlActions() { if (actions == null) { actions = new Object[8]; int i = 0; actions[i++] = new RadioAction(new ActionAddClassifierRole()); actions[i++] = new RadioAction(new ActionSetAddMessageMode( Model.getMetaTypes().getCallAction(), "button.new-callaction")); actions[i++] = new RadioAction(new ActionSetAddMessageMode( Model.getMetaTypes().getSendAction(), "button.new-sendaction")); actions[i++] = new RadioAction(new ActionSetAddMessageMode( Model.getMetaTypes().getReturnAction(), "button.new-returnaction")); actions[i++] = new RadioAction(new ActionSetAddMessageMode( Model.getMetaTypes().getCreateAction(), "button.new-createaction")); actions[i++] = new RadioAction(new ActionSetAddMessageMode( Model.getMetaTypes().getDestroyAction(), "button.new-destroyaction")); actions[i++] = new RadioAction(new ActionSetMode( ModeBroomMessages.class, "button.broom-messages")); } return actions; } /** * Get the localized label name for the diagram * @return The localized label name for the diagram * @see org.argouml.uml.diagram.ui.UMLDiagram#getLabelName() */ @Override public String getLabelName() { return Translator.localize("label.sequence-diagram"); } @Override public void encloserChanged(FigNode enclosed, FigNode oldEncloser, FigNode newEncloser) { // Do nothing. } @Override public boolean isRelocationAllowed(Object base) { return Model.getFacade().isACollaboration(base); } @SuppressWarnings("unchecked") public Collection getRelocationCandidates(Object root) { return Model.getModelManagementHelper().getAllModelElementsOfKindWithModel( root, Model.getMetaTypes().getCollaboration()); } @Override public boolean relocate(Object base) { ((SequenceDiagramGraphModel) getGraphModel()) .setCollaboration(base); setNamespace(base); damage(); return true; } /** * A sequence diagram can accept all classifiers. It will add them as a new * Classifier Role with that classifier as a base. * @param objectToAccept element to test for acceptability * @return true if the element is acceptable * @see org.argouml.uml.diagram.ui.UMLDiagram#doesAccept(java.lang.Object) */ @Override public boolean doesAccept(Object objectToAccept) { if (Model.getFacade().isAClassifier(objectToAccept)) { return true; } else if (Model.getFacade().isAComment(objectToAccept)) { return true; } return false; } /** * Creates a new Classifier Role with a specified base. * @param base * @return The new CR */ private Object makeNewCR(Object base) { Object node = null; Editor ce = Globals.curEditor(); GraphModel gm = ce.getGraphModel(); if (gm instanceof SequenceDiagramGraphModel) { Object collaboration = ((SequenceDiagramGraphModel) gm).getCollaboration(); node = Model.getCollaborationsFactory().buildClassifierRole( collaboration); } Model.getCollaborationsHelper().addBase(node, base); return node; } /** * Creates the Fig for the CR. Y position will be adjusted to match other * the other CRs. * @param classifierRole * @param location The position where to put the new fig. * @return */ private FigClassifierRole makeNewFigCR(Object classifierRole, Point location) { if (classifierRole != null) { Rectangle bounds = new Rectangle(); // Y position of the new CR should match existing CRs Y position for (Fig fig : (List<Fig>) getLayer().getContentsNoEdges()) { if (fig instanceof FigClassifierRole) { bounds.y = fig.getY(); bounds.height = fig.getHeight(); break; } } if (location != null) { if (bounds.y == 0) { bounds.y = location.y; } bounds.x = location.x; } FigClassifierRole newCR = new FigClassifierRole(classifierRole, bounds, getDiagramSettings()); getGraphModel().getNodes().add(newCR.getOwner()); return newCR; } return null; } public DiagramElement createDiagramElement( final Object modelElement, final Rectangle bounds) { FigNodeModelElement figNode = null; DiagramSettings settings = getDiagramSettings(); if (Model.getFacade().isAComment(modelElement)) { figNode = new FigComment(modelElement, bounds, settings); } else if (Model.getFacade().isAClassifierRole(modelElement)) { if (!getGraphModel().getNodes().contains(modelElement)) { figNode = makeNewFigCR(modelElement, null); } } else if (Model.getFacade().isAClassifier(modelElement)) { figNode = makeNewFigCR( makeNewCR(modelElement), bounds.getLocation()); } if (figNode != null) { LOG.debug("Model element " + modelElement + " converted to " + figNode); } else { LOG.debug("Dropped object NOT added " + figNode); } return figNode; } @Override public String getInstructions(Object droppedObject) { if (Model.getFacade().isAClassifierRole(droppedObject)) { return super.getInstructions(droppedObject); } else if (Model.getFacade().isAClassifier(droppedObject)) { return Translator.localize( "misc.message.click-on-diagram-to-add-as-cr", new Object[] {Model.getFacade().toString(droppedObject)}); } return super.getInstructions(droppedObject); } @Override public ModePlace getModePlace(GraphFactory gf, String instructions) { return new ModePlaceClassifierRole(gf, instructions); } public Object getCollaboration() { return ((SequenceDiagramGraphModel) getGraphModel()).getCollaboration(); } /** * Ensure that all elements represented in this diagram are part of this * diagrams collaboration */ public void postLoad() { super.postLoad(); final Facade facade = Model.getFacade(); LOG.info("doing postLoad on " + getName()); // See issue 5811. We have collaborationroles, associationroles // and messages and actions saved to the incorrect interaction and // and collaboration. If we detect this circumstance at load then // move the model elements and delete the empty collaborations // and interactions. final Object collaboration = getCollaboration(); Object correctInteraction = null; for (final Fig f : getLayer().getContents()) { final Object modelElement = f.getOwner(); if (f instanceof FigMessage) { final Object interaction = facade.getInteraction(modelElement); final Object context = facade.getContext(interaction); if (context == collaboration) { correctInteraction = interaction; } } } if (correctInteraction != null) { final CollaborationsHelper collabHelper = Model.getCollaborationsHelper(); for (final Fig f : getLayer().getContents()) { if (f instanceof FigMessage) { final Object message = f.getOwner(); LOG.info("Checking message " + f.getOwner()); final Object interaction = facade.getInteraction(message); final Object context = facade.getContext(interaction); final Object action = facade.getAction(message); if (context != collaboration) { LOG.warn("namespace of interaction does not match " + "collaboration - moving " + message + " to " + correctInteraction); collabHelper.addMessage(correctInteraction, message); Model.getCoreHelper().setNamespace( action, collaboration); } } else if (f instanceof FigClassifierRole) { final Object cr = f.getOwner(); final Object namespace = facade.getNamespace(cr); if (namespace != collaboration) { LOG.warn("namespace of classifierrole does not match " + "collaboration - moving " + cr + " to " + collaboration); Model.getCoreHelper().setNamespace( cr, collaboration); Collection associationEndRoles = facade.getAssociationEnds(cr); for (Object assEndRole : associationEndRoles) { Object assRole = facade.getAssociation(assEndRole); if (facade.getNamespace(assRole) != collaboration) { Model.getCoreHelper().setNamespace( assRole, collaboration); } } } } } } } }