0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram;
0043:
0044: import java.awt.Color;
0045: import java.awt.Dimension;
0046: import java.awt.Font;
0047: import java.awt.Point;
0048: import java.awt.event.MouseEvent;
0049: import java.util.Iterator;
0050: import java.util.List;
0051:
0052: import javax.swing.SwingUtilities;
0053:
0054: import org.netbeans.modules.uml.common.ETException;
0055: import org.netbeans.modules.uml.common.generics.ETPairT;
0056: import org.netbeans.modules.uml.core.metamodel.core.foundation.IElement;
0057: import org.netbeans.modules.uml.core.metamodel.core.foundation.IPresentationElement;
0058: import org.netbeans.modules.uml.core.metamodel.core.primitivetypes.IMessageKind;
0059: import org.netbeans.modules.uml.core.metamodel.diagrams.IDiagram;
0060: import org.netbeans.modules.uml.core.metamodel.diagrams.IGraphEventKind;
0061: import org.netbeans.modules.uml.core.metamodel.dynamics.IInteractionOperand;
0062: import org.netbeans.modules.uml.core.metamodel.dynamics.ILifeline;
0063: import org.netbeans.modules.uml.core.metamodel.dynamics.IMessage;
0064: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IClassifier;
0065: import org.netbeans.modules.uml.core.support.umlsupport.ETPoint;
0066: import org.netbeans.modules.uml.core.support.umlsupport.ETRect;
0067: import org.netbeans.modules.uml.core.support.umlsupport.ETSize;
0068: import org.netbeans.modules.uml.core.support.umlsupport.IETPoint;
0069: import org.netbeans.modules.uml.core.support.umlsupport.IETRect;
0070: import org.netbeans.modules.uml.core.support.umlsupport.IETSize;
0071: import org.netbeans.modules.uml.core.support.umlutils.ETArrayList;
0072: import org.netbeans.modules.uml.core.support.umlutils.ETList;
0073: import org.netbeans.modules.uml.ui.products.ad.ADDrawEngines.ADNodeDrawEngine;
0074: import org.netbeans.modules.uml.ui.products.ad.compartments.sequencediagram.IADLifelineCompartment;
0075: import org.netbeans.modules.uml.ui.products.ad.compartments.IADNameCompartment;
0076: import org.netbeans.modules.uml.ui.products.ad.compartments.IADStereotypeCompartment;
0077: import org.netbeans.modules.uml.ui.products.ad.compartments.sequencediagram.IConnectorsCompartment;
0078: import org.netbeans.modules.uml.ui.products.ad.compartments.sequencediagram.ILifelineNameCompartment;
0079: import org.netbeans.modules.uml.ui.products.ad.compartments.sequencediagram.LifelineConnectorLocation;
0080: import org.netbeans.modules.uml.ui.products.ad.compartments.sequencediagram.lifelinepieces.ConnectorPiece;
0081: import org.netbeans.modules.uml.ui.products.ad.compartments.sequencediagram.lifelinepieces.LifelinePiecesKind;
0082: import org.netbeans.modules.uml.ui.products.ad.compartments.sequencediagram.lifelinepieces.LifelineCompartmentPiece;
0083: import org.netbeans.modules.uml.ui.products.ad.compartments.sequencediagram.lifelinepieces.LifelinePiece;
0084: import org.netbeans.modules.uml.ui.products.ad.diagramengines.IADSequenceDiagEngine;
0085: import org.netbeans.modules.uml.ui.products.ad.drawengines.ETDrawEngine;
0086: import org.netbeans.modules.uml.ui.products.ad.drawengines.MouseQuadrantEnum;
0087: import org.netbeans.modules.uml.ui.products.ad.graphobjects.ETNode;
0088: import org.netbeans.modules.uml.ui.products.ad.viewfactory.IETGraphObjectUI;
0089: import org.netbeans.modules.uml.ui.support.applicationmanager.IEdgePresentation;
0090: import org.netbeans.modules.uml.ui.support.applicationmanager.INodePresentation;
0091: import org.netbeans.modules.uml.ui.support.applicationmanager.MoveToFlags;
0092: import org.netbeans.modules.uml.ui.support.archivesupport.IProductArchive;
0093: import org.netbeans.modules.uml.ui.support.archivesupport.IProductArchiveDefinitions;
0094: import org.netbeans.modules.uml.ui.support.archivesupport.IProductArchiveElement;
0095: import org.netbeans.modules.uml.ui.support.viewfactorysupport.GDISupport;
0096: import org.netbeans.modules.uml.ui.support.viewfactorysupport.ICompartment;
0097: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine;
0098: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawInfo;
0099: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IETGraphObject;
0100: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IETNodeUI;
0101: import org.netbeans.modules.uml.ui.support.viewfactorysupport.ILabelManager;
0102: import org.netbeans.modules.uml.ui.support.viewfactorysupport.INotificationTargets;
0103: import org.netbeans.modules.uml.ui.support.viewfactorysupport.IStickFigureCompartment;
0104: import org.netbeans.modules.uml.ui.support.viewfactorysupport.ITSGraphObject;
0105: import org.netbeans.modules.uml.ui.support.viewfactorysupport.ModelElementChangedKind;
0106: import org.netbeans.modules.uml.ui.support.viewfactorysupport.PresentationHelper;
0107: import org.netbeans.modules.uml.ui.support.viewfactorysupport.TypeConversions;
0108: import org.netbeans.modules.uml.ui.swing.drawingarea.ADGraphWindow;
0109: import org.netbeans.modules.uml.ui.swing.drawingarea.IDiagramEngine;
0110: import org.netbeans.modules.uml.ui.swing.drawingarea.IDrawingAreaControl;
0111: import org.netbeans.modules.uml.ui.swing.drawingarea.diagramtools.SmartDragTool;
0112: import com.tomsawyer.drawing.TSConnector;
0113: import com.tomsawyer.drawing.TSDEdge;
0114: import com.tomsawyer.drawing.TSDNode;
0115: import com.tomsawyer.editor.TSEEdge;
0116: import com.tomsawyer.editor.TSENode;
0117: import com.tomsawyer.editor.tool.TSEReconnectEdgeTool;
0118: import com.tomsawyer.graph.TSEdge;
0119: import com.tomsawyer.graph.TSGraphObject;
0120: import com.tomsawyer.graph.TSNode;
0121: import com.tomsawyer.drawing.geometry.TSConstPoint;
0122: import com.tomsawyer.editor.TSTransform;
0123: import java.awt.GradientPaint;
0124: import org.netbeans.modules.uml.core.support.Debug;
0125: import org.openide.ErrorManager;
0126:
0127: /**
0128: *
0129: * @author Trey Spiva
0130: */
0131: public class LifelineDrawEngine extends ADNodeDrawEngine implements
0132: ILifelineDrawEngine {
0133: public final static int PIECES_BUFFER = 20;
0134: public final static int LIFELINE_MIN_WIDTH = 40;
0135:
0136: private IStickFigureCompartment m_StickFigureCompartment = null;
0137: private ILifelineNameCompartment m_NameCompartment = null;
0138: private IADLifelineCompartment m_LifelineCompartment = null;
0139: private IADStereotypeCompartment m_StereotypeCompartment = null;
0140: private TSConnector m_ConnectorCreate = null;
0141:
0142: /// xml id for the create message that was read from the archive
0143: private String m_strCreateMessageXML_ID;
0144:
0145: /// Mouse quadrant is the quadrant of the node the user is resizing
0146: int m_mqResize = MouseQuadrantEnum.MQ_UNKNOWN;
0147:
0148: /// the minimum allowable rectangle for this container
0149: IETRect m_rectMinimumResize = null;
0150: private boolean adjustCreateConnnector = false;
0151:
0152: public void init() throws ETException {
0153: if (TypeConversions.getElement(this ) != null) {
0154: IPresentationElement pPE = getPresentationElement();
0155: if (pPE != null) {
0156: clearCompartments();
0157: createCompartments();
0158: initCompartments(pPE);
0159: }
0160:
0161: initResources();
0162: handleSizeToContents(-1);
0163: }
0164: }
0165:
0166: public String getElementType() {
0167: String type = super .getElementType();
0168: if (type == null) {
0169: type = new String("Lifeline");
0170: }
0171: return type;
0172: }
0173:
0174: public String getDrawEngineID() {
0175: return "LifelineDrawEngine";
0176: }
0177:
0178: public String getManagerMetaType(int nManagerKind) {
0179: return nManagerKind == ETDrawEngine.MK_EVENTMANAGER
0180: && getFirstModelElement() instanceof ILifeline ? "ADLifelineEventManager"
0181: : "";
0182: }
0183:
0184: /**
0185: * Place a specific type of decoration on the node at the specified location.
0186: *
0187: * @param type The type of decoration to add.
0188: * @param ptLocation The location of the decoration.
0189: */
0190: public void addDecoration(String type, IETPoint location) {
0191: IADLifelineCompartment compartment = getLifelineCompartment();
0192: if (compartment != null) {
0193: compartment.addDecoration(type, location);
0194: invalidate();
0195: }
0196: }
0197:
0198: private boolean updateConnectors = false;
0199:
0200: public void setFontResource(int resourceKind, Font font) {
0201: super .setFontResource(resourceKind, font);
0202: updateConnectors = true;
0203:
0204: }
0205:
0206: int previousTopHeight = -1;
0207:
0208: /**
0209: * Draws the contents of the node. The contents of the node is decided by
0210: * each draw engine.
0211: *
0212: * @param pDrawInfo The information needed to draw.
0213: */
0214: protected void drawContents(IDrawInfo pDrawInfo) {
0215: IETRect rectBounding = pDrawInfo.getDeviceBounds();
0216:
0217: // Since all the compartments are stacked from top to bottom, keep track
0218: // of where the next top will be in device units
0219: int topOfNextCompartment = pDrawInfo.getDeviceBounds().getTop();
0220:
0221: IStickFigureCompartment stickFigure = getStickFigureCompartment();
0222: if (stickFigure != null) {
0223: IETSize size = stickFigure.calculateOptimumSize(pDrawInfo,
0224: false);
0225: IETRect stickBounds = pDrawInfo.getDeviceBounds();
0226: stickBounds.setBottom(stickBounds.getTop()
0227: + size.getHeight());
0228: // Device
0229: topOfNextCompartment = stickBounds.getBottom();
0230:
0231: stickFigure.draw(pDrawInfo, stickBounds);
0232: }
0233:
0234: // First calculate the size of our stereotype and name compartments, then
0235: // draw the box around both compartments and allow them to draw their text
0236: IETRect nameBoxRect = (IETRect) pDrawInfo.getDeviceBounds()
0237: .clone();
0238: nameBoxRect.setTop(topOfNextCompartment);
0239:
0240: IETRect rectStereotype;
0241: IADStereotypeCompartment stereoType = getStereotypeCompartment();
0242: if (stereoType != null) {
0243: rectStereotype = (IETRect) nameBoxRect.clone();
0244: rectStereotype.setTop((int) topOfNextCompartment);
0245:
0246: IETSize stereoTypeSize = stereoType.calculateOptimumSize(
0247: pDrawInfo, false);
0248:
0249: // Size the actor compartment to its minimum size, centered on the
0250: // life line
0251: topOfNextCompartment = rectStereotype.getTop()
0252: + stereoTypeSize.getHeight();
0253: rectStereotype.setBottom((int) topOfNextCompartment);
0254: } else
0255: rectStereotype = null;
0256:
0257: // Now calculate the size of the name compartment
0258: ILifelineNameCompartment nameCompartment = getNameCompartment();
0259: IETRect rectNameCompartment = null;
0260: if (nameCompartment != null) {
0261: rectNameCompartment = (IETRect) rectBounding.clone();
0262: rectNameCompartment.setTop((int) topOfNextCompartment);
0263:
0264: IETSize nameSize = nameCompartment.calculateOptimumSize(
0265: pDrawInfo, false);
0266: topOfNextCompartment = rectNameCompartment.getTop()
0267: + nameSize.getHeight();
0268: rectNameCompartment.setBottom((int) topOfNextCompartment);
0269: }
0270:
0271: // Now draw the name around the stereotype and the name compartments
0272: nameBoxRect.setBottom(topOfNextCompartment);
0273:
0274: float centerX = (float) nameBoxRect.getCenterX();
0275: GradientPaint paint = new GradientPaint(centerX, nameBoxRect
0276: .getBottom(), getBkColor(), centerX, nameBoxRect
0277: .getTop(), getLightGradientFillColor());
0278: GDISupport.drawRectangle(pDrawInfo.getTSEGraphics(),
0279: nameBoxRect.getRectangle(), getBorderBoundsColor(),
0280: paint);
0281:
0282: // For the stereotype and name compartments tell them to draw so their
0283: // text is placed on top of the rectangle we drew above.
0284:
0285: if (stereoType != null && rectStereotype != null) {
0286: stereoType.draw(pDrawInfo, rectStereotype);
0287: }
0288:
0289: if (nameCompartment != null && rectNameCompartment != null) {
0290: nameCompartment.draw(pDrawInfo, rectNameCompartment);
0291: }
0292:
0293: IADLifelineCompartment lifeline = getLifelineCompartment();
0294: if (lifeline != null) {
0295: IETRect rectLifeline = (IETRect) rectBounding.clone();
0296: if (rectBounding.getWidth() >= 4) {
0297: rectLifeline.setTop((int) topOfNextCompartment);
0298: if (topOfNextCompartment == 0) {
0299: IETPoint worldOffset = lifeline
0300: .getLogicalOffsetInDrawEngineRect();
0301:
0302: if (worldOffset != null) {
0303: rectLifeline.setTop(pDrawInfo.getTSTransform()
0304: .yToDevice(worldOffset.getY()));
0305: }
0306: }
0307:
0308: if (rectLifeline.getHeight() != 0) {
0309: lifeline.draw(pDrawInfo, rectLifeline);
0310: }
0311: }
0312: }
0313:
0314: if (updateConnectors == true) {
0315: // If the size of the head changes, we need to make sure that we
0316: // update the messages, because everything will push down.
0317: // This is not perfect, we rely on layout being executed after
0318: // drawing
0319: updateConnectors = false;
0320:
0321: int curHeight = (int) nameBoxRect.getHeight();
0322: if ((previousTopHeight > 0)
0323: && (previousTopHeight != curHeight)) {
0324: getLifelineCompartment().lifelineTopHeightChanged(
0325: curHeight - previousTopHeight);
0326: }
0327: }
0328:
0329: previousTopHeight = (int) nameBoxRect.getHeight();
0330: }
0331:
0332: /**
0333: * Tells the draw engine to write its data to the IProductArchive.
0334: *
0335: * @param productArchive [in] The archive we're saving to
0336: * @param parentElement [in] The current element, or parent for any new attributes or elements.
0337: */
0338: public long writeToArchive(IProductArchive productArchive,
0339: IProductArchiveElement parentElement) {
0340: if (null == productArchive)
0341: throw new IllegalArgumentException();
0342: if (null == parentElement)
0343: throw new IllegalArgumentException();
0344:
0345: super .writeToArchive(productArchive, parentElement);
0346:
0347: // Write the create connector's ID to the archive
0348: if (m_ConnectorCreate != null) {
0349: IETGraphObject etGraphObject = (IETGraphObject) getParentETElement();
0350: if (etGraphObject != null) {
0351: TSDEdge edge = PresentationHelper.getConnectedEdge(
0352: m_ConnectorCreate, false);
0353: if (edge != null) {
0354: IPresentationElement pe = TypeConversions
0355: .getPresentationElement(edge);
0356: if (pe != null) {
0357: String strXMIID = pe.getXMIID();
0358: if (strXMIID.length() > 0) {
0359: IProductArchiveElement engineElement = parentElement
0360: .getElement(IProductArchiveDefinitions.ENGINENAMEELEMENT_STRING);
0361: if (engineElement != null) {
0362: engineElement
0363: .addAttributeString(
0364: IProductArchiveDefinitions.LIFELINEENGINE_CREATEMESSAGE_STRING,
0365: strXMIID);
0366: }
0367: }
0368: }
0369: }
0370: }
0371: }
0372:
0373: return 0;
0374: }
0375:
0376: /**
0377: * Tells the draw engine to read its data to the IProductArchive
0378: *
0379: * @param productArchive [in] The archive we're reading from
0380: * @param pEngineElement [in] The element where this draw engine's information should exist.
0381: */
0382: public long readFromArchive(IProductArchive productArchive,
0383: IProductArchiveElement parentElement) {
0384: if (null == productArchive)
0385: throw new IllegalArgumentException();
0386: if (null == parentElement)
0387: throw new IllegalArgumentException();
0388:
0389: super .readFromArchive(productArchive, parentElement);
0390:
0391: m_strCreateMessageXML_ID = parentElement
0392: .getAttributeString(IProductArchiveDefinitions.LIFELINEENGINE_CREATEMESSAGE_STRING);
0393:
0394: // The message is attached during attachCreateMessageConnector()
0395:
0396: updateNameCompartmentRepresentsMetaType();
0397:
0398: return 0;
0399: }
0400:
0401: /**
0402: * Notification of a post load event.
0403: */
0404: public long postLoad() {
0405: // Fix W3561: Hook up the create message after all the presentaion elements are hooked up
0406: attachCreateMessageConnector();
0407:
0408: super .postLoad();
0409:
0410: layout();
0411:
0412: return 0;
0413: }
0414:
0415: /**
0416: * Initializes our compartments.
0417: *
0418: * @param pElement [in] The presentation element we are representing
0419: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#initCompartments(org.netbeans.modules.uml.core.metamodel.core.foundation.IPresentationElement)
0420: */
0421: public void initCompartments(IPresentationElement pElement) {
0422: try {
0423: // We may get here with no compartments. This happens if we've been
0424: // created by the user. If we read from a file then the compartments
0425: // have been pre-created and we just need to initialize them.
0426: if (getNumCompartments() == 0) {
0427: createCompartments();
0428: } else {
0429: // Fix W2736: Need to add the stick figure for the actor
0430: String currentModelElementType = getRepresentsMetaType();
0431: if (currentModelElementType != null
0432: && currentModelElementType.equals("Actor") == true) {
0433: if (getStickFigureCompartment() == null) {
0434: ICompartment stickFigure = createAndAddCompartment(
0435: "StickFigureCompartment", 0);
0436: setStickFigureCompartment(stickFigure);
0437: }
0438: }
0439: }
0440:
0441: // Enhancement W6120: Process the stereotype compartment
0442: IADStereotypeCompartment stereotypeCompartment = getStereotypeCompartment();
0443: if (stereotypeCompartment != null) {
0444: stereotypeCompartment.setEngine(this );
0445: }
0446: updateStereotypeCompartment(pElement);
0447:
0448: IElement modelElement = TypeConversions
0449: .getElement(pElement);
0450: if (modelElement != null) {
0451: ILifelineNameCompartment nameCompartment = getNameCompartment();
0452: if (nameCompartment != null) {
0453: nameCompartment.addModelElement(modelElement, -1);
0454: setDefaultCompartment(nameCompartment);
0455: }
0456:
0457: IADLifelineCompartment lifeLineCompartment = getLifelineCompartment();
0458: if (lifeLineCompartment != null) {
0459: lifeLineCompartment.addModelElement(modelElement,
0460: -1);
0461: }
0462: }
0463:
0464: // Fix W2987: Make sure the representing metatype is updated properly
0465: updateNameCompartmentRepresentsMetaType();
0466: } catch (ETException e) {
0467: // TODO Auto-generated catch block
0468: e.printStackTrace();
0469: }
0470: }
0471:
0472: /**
0473: * Initializes our compartments.
0474: *
0475: * @param pElement [in] The presentation element we are representing
0476: */
0477: public void initCompartments() {
0478: initCompartments(getPresentation());
0479: }
0480:
0481: /**
0482: * Create the compartments for this node.
0483: */
0484: public void createCompartments() throws ETException {
0485: // Fixed issue 82208, 82207
0486: // get the flag which indicates if this lifeline is a actor lifeline.
0487: // If the lifeline is an actor lifeline or representes an actor classifier,
0488: // then add a stickFigureCompartment
0489: boolean isActorLifeline = false;
0490: ILifeline lifeline = getLifeline();
0491: if (lifeline != null) {
0492: isActorLifeline = lifeline.getIsActorLifeline();
0493: }
0494: String currentModelElementType = getRepresentsMetaType();
0495:
0496: // Process the stick figure compartment, if necessary
0497: if (currentModelElementType.equals("Actor") || isActorLifeline) {
0498: ICompartment compartment = createAndAddCompartment(
0499: "StickFigureCompartment", 0);
0500: if (compartment instanceof IStickFigureCompartment) {
0501: setStickFigureCompartment((IStickFigureCompartment) compartment);
0502: }
0503: } else {
0504: ICompartment stereotype = createAndAddCompartment("StereotypeCompartment");
0505: if (stereotype instanceof IADStereotypeCompartment) {
0506: IADStereotypeCompartment stereotypeCompartment = (IADStereotypeCompartment) stereotype;
0507: setStereotypeCompartment(stereotypeCompartment);
0508: }
0509: }
0510:
0511: ICompartment nameCompart = createAndAddCompartment("LifelineNameCompartment");
0512: if (nameCompart instanceof ILifelineNameCompartment) {
0513: ILifelineNameCompartment lifeName = (ILifelineNameCompartment) nameCompart;
0514: lifeName
0515: .setNameCompartmentBorderKind(IADNameCompartment.NCBK_DRAW_JUST_NAME);
0516: setNameCompartment(lifeName);
0517: }
0518:
0519: ICompartment lifeCompart = createAndAddCompartment("ADLifelineCompartment");
0520: if (lifeCompart instanceof IADLifelineCompartment) {
0521: setLifelineCompartment((IADLifelineCompartment) lifeCompart);
0522: }
0523: }
0524:
0525: //**************************************************
0526: // helper methods
0527: //**************************************************
0528:
0529: /**
0530: * Update the location for the create message connector.
0531: */
0532: protected void updateConnector() {
0533: if (m_ConnectorCreate != null) {
0534: ILifelineNameCompartment compartment = getNameCompartment();
0535: if (compartment != null) {
0536: IETRect rectEngineBounding = getLogicalBoundingRect();
0537: IETRect rectNameBounding = TypeConversions
0538: .getLogicalBoundingRect(compartment);
0539:
0540: // Here we make sure the connector is on the left side of the name
0541: // compartment
0542: // UPDATE: This is because we can not get the clipping to work
0543: // properly.
0544: double yDelta = rectEngineBounding.getTop()
0545: - rectNameBounding.getTop();
0546: double yOffset = yDelta
0547: + (rectNameBounding.getHeight() / 2);
0548: double origYOffset = m_ConnectorCreate
0549: .getConstantYOffset();
0550:
0551: if ((origYOffset != yOffset)
0552: && (origYOffset != (yOffset - 1))) // solves "dancing" problem
0553: {
0554: m_ConnectorCreate.setConstantYOffset(-yOffset);
0555: m_ConnectorCreate.setProportionalYOffset(0.5);
0556: m_ConnectorCreate.setProportionalXOffset(-0.5);
0557:
0558: // Fix J2573: We need to ensure that the connector will always
0559: // be found inside the lifeline name compartment,
0560: // because that compartment knows how to make sure
0561: // the create edge stays horizontal, in
0562: // ETLifelineNameCompartment.updateConnectors()
0563: m_ConnectorCreate.setConstantXOffset(2);
0564:
0565: // if(isResizing() == false)
0566: // {
0567: // makeCreateMessageHorizontal();
0568: // }
0569: }
0570: }
0571: }
0572: }
0573:
0574: /**
0575: * Uses the current representing classifier to update the stereotype
0576: * compartment information
0577: */
0578: protected void updateStereotypeCompartment(
0579: IPresentationElement element) {
0580: IADStereotypeCompartment compartment = getStereotypeCompartment();
0581: if (compartment != null) {
0582: IClassifier classifier = getRepresentingClassifier(element);
0583: if (classifier != null) {
0584: compartment.addModelElement(classifier, -1);
0585: }
0586: }
0587: }
0588:
0589: /**
0590: * Handle the pre resize graph event
0591: */
0592: void handlePreResize() {
0593: boolean bProcessMinRect = false;
0594: Point ptLeftTop = new Point(Integer.MAX_VALUE,
0595: Integer.MIN_VALUE);
0596: Point ptRightBottom = new Point(Integer.MIN_VALUE,
0597: Integer.MAX_VALUE);
0598:
0599: // Determine the minimum resize rectangle from the contained connectors
0600: TSENode tsNode = getNode();
0601: if (tsNode != null) {
0602: List connectors = tsNode.connectors();
0603: for (Iterator iter = connectors.iterator(); iter.hasNext();) {
0604: TSConnector connector = (TSConnector) iter.next();
0605:
0606: if (!TypeConversions.areSameTSObjects(
0607: m_ConnectorCreate, connector)) {
0608: TSConstPoint ptCenter = connector.getCenter();
0609:
0610: ptLeftTop.x = Math.min(ptLeftTop.x, (int) ptCenter
0611: .getX());
0612: ptLeftTop.y = Math.max(ptLeftTop.y, (int) ptCenter
0613: .getY());
0614:
0615: ptRightBottom.x = Math.max(ptRightBottom.x,
0616: (int) ptCenter.getX());
0617: ptRightBottom.y = Math.min(ptRightBottom.y,
0618: (int) ptCenter.getY());
0619:
0620: bProcessMinRect = true;
0621: }
0622: }
0623: }
0624:
0625: m_mqResize = MouseQuadrantEnum.MQ_UNKNOWN;
0626:
0627: if (bProcessMinRect) {
0628: m_rectMinimumResize = new ETRect();
0629: m_rectMinimumResize.setSides((int) ptLeftTop.getX(),
0630: (int) ptLeftTop.getY(), (int) ptRightBottom.getX(),
0631: (int) ptRightBottom.getY());
0632:
0633: m_rectMinimumResize.inflate(
0634: LifelineCompartmentPiece.PIECE_WIDTH,
0635: 2 * LifelineCompartmentPiece.MIN_SIBLING_SPACE);
0636:
0637: // Also account for the area above the lifeline compartment
0638: {
0639: IADLifelineCompartment lifelineCompartment = getCompartmentByKind(IADLifelineCompartment.class);
0640: if (lifelineCompartment != null) {
0641: IETPoint ptOffset = lifelineCompartment
0642: .getLogicalOffsetInDrawEngineRect();
0643: if (ptOffset != null) {
0644: int iOffsetY = ptOffset.getY();
0645:
0646: final int iOldBottom = m_rectMinimumResize
0647: .getBottom();
0648: m_rectMinimumResize.setTop(m_rectMinimumResize
0649: .getTop()
0650: + iOffsetY);
0651: m_rectMinimumResize.setBottom(iOldBottom);
0652: }
0653: }
0654: }
0655:
0656: // Determine which quadrant is being resized
0657: m_mqResize = MouseQuadrantEnum.getQuadrant(getGraphWindow()
0658: .getCurrentTool());
0659: } else {
0660: m_rectMinimumResize = null;
0661: }
0662: }
0663:
0664: /**
0665: * Handle the post resize graph event
0666: */
0667: void handlePostResize() {
0668: m_rectMinimumResize = null;
0669:
0670: // Since we are using the resize mechanisim from the 6.2 code we need this code from 6.2
0671: if (m_ConnectorCreate != null) {
0672: ConnectorPiece otherPiece = ConnectorPiece
0673: .getAssociatedPiece(m_ConnectorCreate, false);
0674: if (otherPiece != null) {
0675: otherPiece.setLogicalTop((int) m_ConnectorCreate
0676: .getCenterY());
0677: }
0678: }
0679: }
0680:
0681: /**
0682: * Returns the metatype for the represents object on the lifeline.
0683: */
0684: protected String getRepresentsMetaType() {
0685: String retVal = "";
0686:
0687: IClassifier classifier = getRepresentingClassifier();
0688: if (classifier != null) {
0689: retVal = classifier.getElementType();
0690: }
0691:
0692: if ((retVal == null) || (retVal.length() <= 0)) {
0693: retVal = "Class";
0694:
0695: String initStr = getInitializationString();
0696: if ((initStr != null) && (initStr.length() > 0)) {
0697: int pos = initStr.lastIndexOf(' ');
0698:
0699: String shortName = initStr;
0700: if (pos >= 0) {
0701: shortName = initStr.substring(pos + 1);
0702: }
0703: if ((shortName != null)
0704: && (shortName.equals("Actor") == true)) {
0705: retVal = shortName;
0706: }
0707: }
0708: }
0709:
0710: return retVal;
0711: }
0712:
0713: /**
0714: * Returns the metatype for the represents object on the lifeline.
0715: * @return The representing classifier.
0716: */
0717: protected IClassifier getRepresentingClassifier() {
0718: IClassifier retVal = null;
0719:
0720: ILifeline lifeline = getLifeline();
0721: if (lifeline != null) {
0722: retVal = lifeline.getRepresentingClassifier();
0723: }
0724:
0725: return retVal;
0726: }
0727:
0728: /**
0729: * Returns the metatype for the represents object on the lifeline.
0730: * @return The representing classifier.
0731: */
0732: protected IClassifier getRepresentingClassifier(
0733: IPresentationElement element) {
0734: IClassifier retVal = null;
0735:
0736: ILifeline lifeline = getLifeline(element);
0737: if (lifeline != null) {
0738: retVal = lifeline.getRepresentingClassifier();
0739: }
0740:
0741: return retVal;
0742: }
0743:
0744: /**
0745: * Determine the ILifeline from the draw engine's model element.
0746: *
0747: * @return The lifeline that the draw engine represents.
0748: */
0749: protected ILifeline getLifeline() {
0750: ILifeline retVal = null;
0751:
0752: retVal = getLifeline(getPresentationElement());
0753:
0754: return retVal;
0755: }
0756:
0757: /**
0758: * Determine the ILifeline from the draw engine's model element.
0759: *
0760: * @return The lifeline that the draw engine represents.
0761: */
0762: protected ILifeline getLifeline(IPresentationElement pElement) {
0763: ILifeline retVal = null;
0764:
0765: if (pElement != null) {
0766: IElement element = TypeConversions.getElement(pElement);
0767: if (element instanceof ILifeline) {
0768: retVal = (ILifeline) element;
0769: }
0770: }
0771:
0772: return retVal;
0773: }
0774:
0775: /**
0776: * Determine the ILifeline given the TSDConnector.
0777: *
0778: * @param pConnector Connector to determine the lifeline from
0779: * @return The lifeline associated with the connector
0780: */
0781: protected ILifeline getLifeline(TSConnector connector) {
0782: ILifeline retVal = null;
0783:
0784: if (connector != null) {
0785: TSGraphObject tsObject = connector.getOwner();
0786: IElement element = TypeConversions.getElement(tsObject);
0787:
0788: if (element instanceof ILifeline) {
0789: retVal = (ILifeline) element;
0790: }
0791: }
0792:
0793: return retVal;
0794: }
0795:
0796: /**
0797: * Retrieves the stick figure compartment (if one exist). The stick figure
0798: * compartment will only be present if the lifeline is an actor lifeline.
0799: */
0800: protected IStickFigureCompartment getStickFigureCompartment() {
0801: IStickFigureCompartment retVal = m_StickFigureCompartment;
0802:
0803: if (retVal == null) {
0804: retVal = getCompartmentByKind(IStickFigureCompartment.class);
0805: setStickFigureCompartment(retVal);
0806: }
0807:
0808: return retVal;
0809: }
0810:
0811: /**
0812: * Sets the stick figure compartment.
0813: *
0814: * @param value The stick figure compartment.
0815: */
0816: protected void setStickFigureCompartment(ICompartment value) {
0817: if (value instanceof IStickFigureCompartment) {
0818: setStickFigureCompartment((IStickFigureCompartment) value);
0819: }
0820: }
0821:
0822: /**
0823: * Sets the stick figure compartment.
0824: *
0825: * @param value The stick figure compartment.
0826: */
0827: protected void setStickFigureCompartment(
0828: IStickFigureCompartment value) {
0829: m_StickFigureCompartment = value;
0830: }
0831:
0832: /**
0833: * @return
0834: */
0835: public IADLifelineCompartment getLifelineCompartment() {
0836: IADLifelineCompartment retVal = m_LifelineCompartment;
0837:
0838: if (retVal == null) {
0839: retVal = getCompartmentByKind(IADLifelineCompartment.class);
0840: setLifelineCompartment(retVal);
0841: }
0842:
0843: return retVal;
0844: }
0845:
0846: /**
0847: * @param compartment
0848: */
0849: public void setLifelineCompartment(
0850: IADLifelineCompartment compartment) {
0851: m_LifelineCompartment = compartment;
0852: }
0853:
0854: /**
0855: * @return
0856: */
0857: public ILifelineNameCompartment getNameCompartment() {
0858: //return m_NameCompartment;
0859: ILifelineNameCompartment retVal = m_NameCompartment;
0860:
0861: if (retVal == null) {
0862: retVal = getCompartmentByKind(ILifelineNameCompartment.class);
0863: setNameCompartment(retVal);
0864: }
0865:
0866: return retVal;
0867: }
0868:
0869: /**
0870: * @param compartment
0871: */
0872: public void setNameCompartment(ILifelineNameCompartment compartment) {
0873: m_NameCompartment = compartment;
0874: }
0875:
0876: /**
0877: * @return
0878: */
0879: public IADStereotypeCompartment getStereotypeCompartment() {
0880: IADStereotypeCompartment retVal = m_StereotypeCompartment;
0881:
0882: if (retVal == null) {
0883: retVal = getCompartmentByKind(IADStereotypeCompartment.class);
0884: setStereotypeCompartment(retVal);
0885: }
0886:
0887: return retVal;
0888: }
0889:
0890: /**
0891: * @param compartment
0892: */
0893: public void setStereotypeCompartment(
0894: IADStereotypeCompartment compartment) {
0895: m_StereotypeCompartment = compartment;
0896: }
0897:
0898: /**
0899: * Creates a connector for the target end of create message.
0900: *
0901: * @see org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram.ILifelineDrawEngine#getConnectorForCreateMessage()
0902: */
0903: public TSConnector getConnectorForCreateMessage() {
0904: // Fix W5739: The member create connector can become invalid
0905: // when the user deletes the create message.
0906: if (m_ConnectorCreate != null) {
0907: TSENode ownerNode = getOwnerNode();
0908: if (ownerNode != null) {
0909: List connectors = ownerNode.connectors();
0910: if (connectors.contains(m_ConnectorCreate) == false) {
0911: m_ConnectorCreate = null;
0912: }
0913: }
0914: }
0915:
0916: if (m_ConnectorCreate == null) {
0917: m_ConnectorCreate = addConnector();
0918: }
0919: return m_ConnectorCreate;
0920: }
0921:
0922: /**
0923: * Validates the model data against the displayed data.
0924: *
0925: * @return <code>true</code> if the node is valid.
0926: */
0927: public boolean validateNode() {
0928: // We migbt have been deleted and this gets called by invokeLater , so make sure we have an owner.
0929: boolean retVal = this .getOwnerNode() != null;
0930:
0931: // J2101-Deleting fragment and diagram results in exception (regression)
0932: // Also watch for deleted/closed diagram
0933: if (retVal && getDrawingArea() == null) {
0934: retVal = false;
0935: }
0936:
0937: if (retVal) {
0938: IDrawingAreaControl daCtrl = getDrawingArea();
0939: ADGraphWindow graphWindow = daCtrl != null ? daCtrl
0940: .getGraphWindow() : null;
0941: // Don't remove the connectors if we are in the Reconnect Edge mode,
0942: // boolean reconnecting = graphWindow != null && graphWindow.getCurrentTool() instanceof TSEReconnectEdgeState;
0943: boolean reconnecting = graphWindow != null
0944: && graphWindow.getCurrentTool() instanceof TSEReconnectEdgeTool;
0945: if (!reconnecting) {
0946: removeUnusedConnectors();
0947:
0948: IADLifelineCompartment compartment = getLifelineCompartment();
0949: if (compartment != null) {
0950: compartment.validatePieces();
0951: }
0952:
0953: layout();
0954:
0955: // Fix J2701: Ensure that the lifeline is invalidated so the pieces get cleaned up.
0956: invalidate();
0957: } else if (graphWindow != null && reconnecting) {
0958: SwingUtilities.invokeLater(new Runnable() {
0959: public void run() {
0960: validateNode();
0961: }
0962: });
0963: }
0964: }
0965:
0966: return retVal;
0967:
0968: }
0969:
0970: /**
0971: * Removes any connectors that don't have any messages attached
0972: */
0973: protected void removeUnusedConnectors() {
0974: TSENode node = getNode();
0975: if (node != null) {
0976: List connectors = node.connectors();
0977: ETList<ITSGraphObject> unusedConnector = new ETArrayList<ITSGraphObject>();
0978: for (Iterator iter = connectors.iterator(); iter.hasNext();) {
0979: TSConnector curConnector = (TSConnector) iter.next();
0980: if (curConnector != null && curConnector.degree() == 0
0981: && curConnector.getOwner() == node
0982: && curConnector instanceof ITSGraphObject) {
0983: unusedConnector.add((ITSGraphObject) curConnector);
0984: }
0985: }
0986:
0987: // We don't want to delete from TomSawyers list, build a copy.
0988: Iterator<ITSGraphObject> deleteIter = unusedConnector
0989: .iterator();
0990: while (deleteIter.hasNext()) {
0991: ITSGraphObject connector = deleteIter.next();
0992: try {
0993: connector.delete();
0994: } catch (Exception e) {
0995: }
0996: deleteIter.remove();
0997: }
0998: }
0999: }
1000:
1001: /**
1002: * Attaches the create message from the archive.
1003: */
1004: protected void attachCreateMessageConnector() {
1005: if (m_strCreateMessageXML_ID.length() > 0) {
1006: m_ConnectorCreate = null;
1007:
1008: IDiagram diagram = getDiagram();
1009: if (diagram != null) {
1010: IPresentationElement presentationElement = diagram
1011: .findPresentationElement(m_strCreateMessageXML_ID);
1012: if (presentationElement instanceof IEdgePresentation) {
1013: IEdgePresentation edgePresentation = (IEdgePresentation) presentationElement;
1014:
1015: TSEEdge edge = edgePresentation.getTSEdge();
1016: if (edge != null) {
1017: TSConnector connector = edge
1018: .getTargetConnector();
1019: if (connector == null) {
1020: // Hook up the create message connector for this draw engine
1021: // to the edge whose xml id is contained in the archive
1022: connector = getConnectorForCreateMessage();
1023: if (connector != null) {
1024: edge.setTargetConnector(connector);
1025:
1026: invalidate();
1027: }
1028: } else {
1029: m_ConnectorCreate = connector;
1030: }
1031: }
1032: }
1033: }
1034:
1035: // Clear the String so we only perform this action once
1036: assert m_ConnectorCreate != null;
1037: m_strCreateMessageXML_ID = "";
1038: }
1039: }
1040:
1041: /**
1042: * Informs the name compartment of the metatype the lifeline is representing.
1043: */
1044: protected void updateNameCompartmentRepresentsMetaType() {
1045: // Make sure the represents metatype is updated
1046: ILifelineNameCompartment cpNameCompartment = getNameCompartment();
1047: if (cpNameCompartment != null) {
1048: cpNameCompartment
1049: .setRepresentsMetaType(getRepresentsMetaType());
1050: }
1051: }
1052:
1053: /**
1054: * Calculates the <i>best</i> size for this draw engine, allowing for border thickness
1055: *
1056: * @param pCDC This is the CDC* represented as an OLE_HANDLE
1057: * @param bAt100Pct nX,nY is either in current zoom or 100% based on
1058: * this flag. If bAt100Pct then it's at 100%.
1059: * @return The <i>best</i>width and height of the draw engine
1060: */
1061: public IETSize calculateOptimumSize(IDrawInfo pDrawInfo,
1062: boolean bAt100Pct) {
1063: IETSize retVal = super .calculateOptimumSize(pDrawInfo, true);
1064:
1065: if (retVal != null) {
1066: // Fix J1794: Because we handle sizing differently in Java, we need to
1067: // ensure the minimum width of the lifeline is maintained here.
1068: final int width = Math.max(LIFELINE_MIN_WIDTH, retVal
1069: .getWidth());
1070: retVal.setWidth(width + (2 * getBorderThickness()));
1071:
1072: if (!bAt100Pct) {
1073: TSTransform transform = pDrawInfo != null ? pDrawInfo
1074: .getTSTransform() : getTransform();
1075: if (transform != null) {
1076: retVal = scaleSize(retVal, transform);
1077: }
1078: }
1079: }
1080:
1081: return retVal;
1082: }
1083:
1084: /**
1085: * Resizes the node to fit the incoming compartment.
1086: *
1087: * @param pCompartment The compartment to use in the calculations.
1088: * @param bKeepUpperLeftPoint Not used.
1089: * @param bIgnorePreferences Not Used.
1090: *
1091: * @see org.netbeans.modules.uml.ui.products.ad.drawengines.INodeDrawEngine#resizeToFitCompartment(org.netbeans.modules.uml.ui.support.viewfactorysupport.ICompartment, boolean, boolean)
1092: */
1093: public void resizeToFitCompartment(ICompartment pCompartment,
1094: boolean bKeepUpperLeftPoint, boolean bIgnorePreferences) {
1095: if (pCompartment instanceof IADLifelineCompartment) {
1096: handleSizeToContents((long) getLogicalBoundingRect()
1097: .getWidth());
1098: }
1099: }
1100:
1101: /**
1102: * Returns the optimum size for an item. This is used when an item is
1103: * created from the toolbar.
1104: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#sizeToContents()
1105: */
1106: public void sizeToContents() {
1107: handleSizeToContents(-1);
1108: }
1109:
1110: /**
1111: * Moves this draw engine so the create message, if it exists, is horizontal.
1112: */
1113: public void makeCreateMessageHorizontal() {
1114: if (m_ConnectorCreate != null) {
1115: updateConnector();
1116:
1117: TSConnector otherConnector = PresentationHelper
1118: .getConnectorOnOtherEndOfEdge(m_ConnectorCreate,
1119: false);
1120: if (otherConnector != null) {
1121: moveConnectorYTo(m_ConnectorCreate, otherConnector
1122: .getCenterY());
1123: }
1124:
1125: updateConnectors();
1126: }
1127: }
1128:
1129: /**
1130: *
1131: */
1132: public void updateConnectors() {
1133: updateConnectors(getLifelineCompartment());
1134: }
1135:
1136: /**
1137: *
1138: */
1139: public void updateConnectors(IADLifelineCompartment compartment) {
1140: if (compartment instanceof IConnectorsCompartment) {
1141: IConnectorsCompartment connectCompartment = (IConnectorsCompartment) compartment;
1142: connectCompartment.updateConnectors(null);
1143: }
1144: }
1145:
1146: /**
1147: * Moves this draw engine so the create message connector is at the specified
1148: * vertical location.
1149: *
1150: * @param m_ConnectorCreate The connector to update.
1151: * @param y The new vertical location for the create message connector
1152: */
1153: protected void moveConnectorYTo(TSConnector connector, double y) {
1154: double delta = y - connector.getCenterY();
1155:
1156: // The C++ version is concerned with zoom here. I am going to try to not
1157: // not be concerned with zoom.
1158:
1159: INodePresentation nodeP = TypeConversions
1160: .getNodePresentation(this );
1161: if (nodeP != null) {
1162: IETRect bounding = TypeConversions
1163: .getLogicalBoundingRect(nodeP);
1164: // Fix J2573: CLEAN bounding.normalizeRect();
1165:
1166: // assert bounding.getTop() <= bounding.getBottom() : "The normalizeRect method failed";
1167: // Fix J2314: For some reason the draw engine was not getting redrawn during
1168: // SQD CDFS. So, we just invalidate the node to make sure it gets drawn.
1169: nodeP
1170: .moveTo(
1171: 0,
1172: (int) (bounding.getCenterY() + delta),
1173: (MoveToFlags.MTF_MOVEY
1174: | MoveToFlags.MTF_LOGICALCOORD | MoveToFlags.MTF_INVALIDATE));
1175: }
1176: }
1177:
1178: /**
1179: * Find 1st message below the edge's location on the diagram.
1180: * @see org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram.ILifelineDrawEngine#findFirstMessageBelow(int)
1181: */
1182: public IMessage findFirstMessageBelow(int lY) {
1183: IMessage retVal = null;
1184:
1185: IADSequenceDiagEngine sqdEngine = getDiagramEngine();
1186: if (sqdEngine != null) {
1187: IElement element = sqdEngine.findFirstElementBelow(
1188: "Message", lY);
1189: if (element instanceof IMessage) {
1190: retVal = (IMessage) element;
1191: }
1192: }
1193:
1194: return retVal;
1195: }
1196:
1197: /**
1198: * Find 1st message Above the edge's location on the diagram.
1199: * @see org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram.ILifelineDrawEngine#findFirstMessageAbove(int)
1200: */
1201: public IMessage findFirstMessageAbove(int lY) {
1202: IMessage retVal = null;
1203:
1204: IADSequenceDiagEngine sqdEngine = getDiagramEngine();
1205: if (sqdEngine != null) {
1206: IElement element = sqdEngine.findFirstElementAbove(
1207: "Message", lY);
1208: if (element instanceof IMessage) {
1209: retVal = (IMessage) element;
1210: }
1211: }
1212:
1213: return retVal;
1214: }
1215:
1216: /**
1217: * Creates a return message on the bottom of the pieces connected to the
1218: * input connectors. The input pieces are used to determine the lifeline
1219: * pieces to start/end the newly created return message.
1220: *
1221: * @param pFromConnector The piece attached to this connector will be
1222: * the starting piece for the return message.
1223: * @param pToConnector The piece attached to this connector will be the
1224: * ending piece for the return message.
1225: * @param pInteractionOperand The interaction operand that contains the
1226: * return message
1227: * @see org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram.ILifelineDrawEngine#createReturnMessage(com.tomsawyer.graph.TSEdge, org.netbeans.modules.uml.core.metamodel.dynamics.IMessage, org.netbeans.modules.uml.core.metamodel.dynamics.IInteractionOperand, org.netbeans.modules.uml.core.metamodel.dynamics.IMessage)
1228: */
1229: public void createReturnMessage(TSEEdge synchronousEdge,
1230: IMessage synchronousMessage,
1231: IInteractionOperand interactionOperand,
1232: IMessage beforeMessage) {
1233: if ((synchronousEdge != null) && (synchronousMessage != null)) {
1234: TSConnector toConnector = synchronousEdge
1235: .getSourceConnector();
1236: TSConnector fromConnector = synchronousEdge
1237: .getTargetConnector();
1238: IDrawingAreaControl ctrl = getDrawingArea();
1239:
1240: if ((toConnector != null) && (fromConnector != null)
1241: && (ctrl != null)) {
1242: ILifeline fromLifeline = getLifeline(fromConnector);
1243: ILifeline toLifeline = getLifeline(toConnector);
1244:
1245: if ((fromLifeline != null) && (toLifeline != null)) {
1246: // Create the result message
1247: IMessage returnMsg = fromLifeline.insertMessage(
1248: beforeMessage, interactionOperand,
1249: toLifeline, interactionOperand, null,
1250: IMessageKind.MK_RESULT);
1251:
1252: TSGraphObject fromObject = fromConnector.getOwner();
1253: TSGraphObject toObject = toConnector.getOwner();
1254:
1255: TSEEdge newEdge = createEdge(returnMsg,
1256: (TSENode) fromObject, (TSENode) toObject);
1257:
1258: // Update the edge's connectors with the new locations
1259: IADLifelineCompartment lifelineCompartment = getLifelineCompartment();
1260: if (lifelineCompartment != null) {
1261: lifelineCompartment.connectReturnEdge(
1262: fromConnector, toConnector, newEdge);
1263: }
1264:
1265: returnMsg.setSendingMessage(synchronousMessage);
1266:
1267: if (newEdge != null) {
1268: // Hide the return edge if that is the user's setting
1269: IADSequenceDiagEngine sqdEngine = getDiagramEngine();
1270: if (sqdEngine != null) {
1271: if (sqdEngine.isShowAllReturnMessages() == false) {
1272: IDrawEngine engine = TypeConversions
1273: .getDrawEngine(newEdge);
1274: if (engine instanceof IMessageEdgeDrawEngine) {
1275: ((IMessageEdgeDrawEngine) engine)
1276: .setShow(false);
1277: }
1278: }
1279: }
1280: }
1281: }
1282: }
1283: }
1284: }
1285:
1286: /**
1287: * Creates a message, type determined by the input message, to the other draw engine.
1288: *
1289: * @param message [in] Meta data message to attach to the presentation element
1290: * @param toEngine [in] The recieving lifeline draw engine
1291: * @param verticalLocatoin The vertical location of the message.
1292: * @return The message draw engine that renders the message.
1293: * @see org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram.ILifelineDrawEngine#createMessage(org.netbeans.modules.uml.core.metamodel.dynamics.IMessage, org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram.ILifelineDrawEngine, int)
1294: */
1295: public ETPairT<IMessageEdgeDrawEngine, Integer> createMessage(
1296: IMessage message, ILifelineDrawEngine toEngine,
1297: int verticalLocation) {
1298: IMessageEdgeDrawEngine retEngine = null;
1299: Integer retLocation = new Integer(verticalLocation);
1300:
1301: if ((message != null) && (toEngine != null)) {
1302: TSENode fromNode = getNode();
1303: TSENode toNode = toEngine.getNode();
1304:
1305: boolean isMessageToSelf = (fromNode == toNode);
1306:
1307: if ((fromNode != null) && (toNode != null)) {
1308: TSEEdge newEdge = createEdge(message, fromNode, toNode);
1309: int newLocation = updatePiecesAndAttachMessage(message,
1310: toEngine, newEdge, verticalLocation);
1311: retLocation = new Integer(newLocation);
1312:
1313: IDrawEngine engine = TypeConversions
1314: .getDrawEngine(newEdge);
1315: if (engine instanceof IMessageEdgeDrawEngine) {
1316: retEngine = (IMessageEdgeDrawEngine) engine;
1317: retEngine.setIsMessageToSelf(isMessageToSelf);
1318:
1319: // Make sure the operation is shown
1320: ILabelManager labelManager = retEngine
1321: .getLabelManager();
1322: if (labelManager != null) {
1323: labelManager.createInitialLabels();
1324: }
1325: }
1326:
1327: // Must invalidate the nodes so the pieces get drawn properly during
1328: // sequence diagram generation.
1329: invalidate();
1330: if (isMessageToSelf == false) {
1331: toEngine.invalidate();
1332: }
1333: }
1334: }
1335:
1336: return new ETPairT<IMessageEdgeDrawEngine, Integer>(retEngine,
1337: retLocation);
1338: }
1339:
1340: /* (non-Javadoc)
1341: * @see org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram.ILifelineDrawEngine#hasMessagesAttached()
1342: */
1343: public boolean hasMessagesAttached() {
1344: TSENode node = getOwnerNode();
1345: if (node != null) {
1346: return node.connectors().size() > 1;
1347: }
1348:
1349: return false;
1350: }
1351:
1352: /* (non-Javadoc)
1353: * @see org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram.ILifelineDrawEngine#isDestroyed()
1354: */
1355: public boolean isDestroyed() {
1356: boolean bIsDestroyed = false;
1357:
1358: IADLifelineCompartment compartment = getLifelineCompartment();
1359: if (compartment != null) {
1360: bIsDestroyed = compartment.getIsDestroyed();
1361: }
1362:
1363: return bIsDestroyed;
1364: }
1365:
1366: /* (non-Javadoc)
1367: * @see org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram.ILifelineDrawEngine#removeIncomingOperations(boolean)
1368: */
1369: public void removeIncomingOperations(
1370: boolean bRemoveAssociatedMessages) {
1371: // TODO Auto-generated method stub
1372:
1373: }
1374:
1375: /* (non-Javadoc)
1376: * @see org.netbeans.modules.uml.ui.products.ad.diagramengines.sequencediagram.ILifelineDrawEngine#getAllMessageToSelfs()
1377: */
1378: public ETList<IPresentationElement> getAllMessageToSelfs() {
1379: return null;
1380: }
1381:
1382: /* (non-Javadoc)
1383: * @see org.netbeans.modules.uml.ui.products.ad.ADDrawEngines.IADNodeDrawEngine#launchNodeTool(org.netbeans.modules.uml.core.support.umlsupport.IETPoint, org.netbeans.modules.uml.ui.support.viewfactorysupport.ICompartment, org.netbeans.modules.uml.core.support.umlsupport.IETRect)
1384: */
1385: public void launchNodeTool(IETPoint pStartPos,
1386: ICompartment pCompartment, IETRect pBounds) {
1387: // TODO Auto-generated method stub
1388:
1389: }
1390:
1391: //**************************************************
1392: // Helper Methods
1393: //**************************************************
1394:
1395: /**
1396: * Size the node to the contained element with a minimum width.
1397: *
1398: * @param lMinWidth [in] The minumum width of the node in device scale,
1399: * -1 indicates use the calculated width.
1400: */
1401: protected void handleSizeToContents(long minWidth) {
1402: IETGraphObjectUI ui = getUI();
1403: if (ui instanceof IETNodeUI) {
1404: IETNodeUI nodeUI = (IETNodeUI) ui;
1405: IDrawInfo info = nodeUI.getDrawInfo();
1406:
1407: IETSize optimumSize = calculateOptimumSize(info, false);
1408:
1409: // disable automatic down-sizing #90587, but stretch lifeline when necessary
1410: double minHeight = -1;
1411: TSTransform transform = (info != null ? info
1412: .getTSTransform() : getTransform());
1413: if (transform != null) {
1414: minHeight = transform
1415: .heightToDevice(nodeUI.getHeight());
1416: }
1417: resize(new ETSize((int) Math.max(optimumSize.getWidth(),
1418: minWidth), (int) Math.max(optimumSize.getHeight(),
1419: minHeight)), true);
1420:
1421: }
1422: }
1423:
1424: /* (non-Javadoc)
1425: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#onGraphEvent(int)
1426: */
1427: public void onGraphEvent(int nKind) {
1428: super .onGraphEvent(nKind);
1429:
1430: switch (nKind) {
1431: case IGraphEventKind.GEK_PRE_MOVE:
1432: // This mechanism should not be necessary
1433: // This flag was used in C++ to capture the fact that TS passes a bogus resize event
1434: // during a moveto command from the node presentation element.
1435: // CLEAN m_bIsMoving = true;
1436: break;
1437:
1438: case IGraphEventKind.GEK_POST_MOVE: {
1439: // CLEAN m_bIsMoving = false;
1440:
1441: IADLifelineCompartment lifelineCompartment = getCompartmentByKind(IADLifelineCompartment.class);
1442: if (lifelineCompartment != null) {
1443: layout();
1444:
1445: updateConnectors(lifelineCompartment);
1446:
1447: // Fix W4687: The wiggle from CSequenceDiagramAddEdgeListener.postIncrementalMoveMessages()
1448: // sends a this event, so here is a good place to update the reflexive bends.
1449: lifelineCompartment.updateReflexiveBends();
1450: }
1451: }
1452: break;
1453:
1454: case IGraphEventKind.GEK_POST_PASTE_VIEW: {
1455: validateNode();
1456: }
1457: break;
1458:
1459: case IGraphEventKind.GEK_PRE_RESIZE:
1460: handlePreResize();
1461: break;
1462:
1463: case IGraphEventKind.GEK_POST_RESIZE:
1464: handlePostResize();
1465: break;
1466:
1467: case IGraphEventKind.GEK_SQD_DIAGRAM_POST_SCROLLZOOM: {
1468: // Notification that the sequence diagram has been zoomed
1469: layout();
1470: }
1471: break;
1472:
1473: case IGraphEventKind.GEK_PRE_DELETEGATHERSELECTED:
1474: onPreDeleteGatherSelected();
1475: break;
1476:
1477: default:
1478: // do nothing
1479: break;
1480: }
1481: }
1482:
1483: /**
1484: * alled when a node is resized. nodeResizeOriginator is a TSENodeResizeOriginator.
1485: */
1486: public void onResized() {
1487: super .onResized();
1488:
1489: if (adjustCreateConnnector == true) {
1490: makeCreateMessageHorizontal();
1491: adjustCreateConnnector = false;
1492: }
1493: }
1494:
1495: /**
1496: * Called before the owner node is resized so that this view can restrict the way in which a resize can occur.
1497: *
1498: * @param plWidth
1499: * @param plHeight
1500: */
1501: public Dimension validateResize(int x, int y) {
1502: if (m_mqResize != MouseQuadrantEnum.MQ_UNKNOWN) {
1503: // The m_rectMinimumResize is the minimum allowable rectangle,
1504: // so don't allow any of the sides to end up inside this rectangle
1505:
1506: final IETRect rectCurrent = getLogicalBoundingRect(false);
1507:
1508: if ((x > 0)
1509: && ((m_rectMinimumResize.getLeft() != 0) || (m_rectMinimumResize
1510: .getRight() != 0))) {
1511: if (MouseQuadrantEnum.MQ_LEFT == (m_mqResize & MouseQuadrantEnum.MQ_LEFT)) {
1512: final int iLeft = m_rectMinimumResize.getLeft();
1513: final int iRight = rectCurrent.getRight();
1514: x = Math.max(iRight - iLeft, x);
1515: } else if (MouseQuadrantEnum.MQ_RIGHT == (m_mqResize & MouseQuadrantEnum.MQ_RIGHT)) {
1516: final int iLeft = rectCurrent.getLeft();
1517: final int iRight = m_rectMinimumResize.getRight();
1518: x = Math.max(iRight - iLeft, x);
1519: }
1520:
1521: assert (x > 0);
1522: }
1523:
1524: if ((y > 0)
1525: && ((m_rectMinimumResize.getTop() != 0) || (m_rectMinimumResize
1526: .getBottom() != 0))) {
1527: // Since these rectangle are not upside-down in Java,
1528: // I (BDB) had to switch the top & bottom calculations for the Java code.
1529:
1530: if (MouseQuadrantEnum.MQ_TOP == (m_mqResize & MouseQuadrantEnum.MQ_TOP)) {
1531: final int iTop = m_rectMinimumResize.getTop();
1532: final int iBottom = rectCurrent.getBottom();
1533: y = Math.max(iTop - iBottom, y);
1534: } else if (MouseQuadrantEnum.MQ_BOTTOM == (m_mqResize & MouseQuadrantEnum.MQ_BOTTOM)) {
1535: final int iTop = rectCurrent.getTop();
1536: final int iBottom = m_rectMinimumResize.getBottom();
1537: y = Math.max(iTop - iBottom, y);
1538: }
1539:
1540: assert (y > 0);
1541: }
1542: }
1543:
1544: /// Ensure that the lifeline has minimim size
1545: IADLifelineCompartment fromCompartment = getCompartmentByKind(IADLifelineCompartment.class);
1546: if (fromCompartment != null) {
1547: int iMinHeight = fromCompartment.getMinimumHeight();
1548: if (iMinHeight < Integer.MAX_VALUE) {
1549: IETPoint point = fromCompartment
1550: .getLogicalOffsetInDrawEngineRect();
1551:
1552: iMinHeight += point.getY();
1553: y = Math.max(y, iMinHeight);
1554: }
1555: }
1556:
1557: // Fix W3290: Have to make sure the width does not get too small.
1558: // Hopefully this avoids the problem where the connectors get deleted.
1559: x = Math.max(x, LIFELINE_MIN_WIDTH);
1560:
1561: return new Dimension(x, y);
1562: }
1563:
1564: /**
1565: * Notifier that the model element has changed, if available the changed
1566: * IFeature is passed along.
1567: *
1568: * @param pTargets Information about what has changed
1569: */
1570: public long modelElementHasChanged(INotificationTargets targets) {
1571: if (targets != null) {
1572: int kind = targets.getKind();
1573: switch (kind) {
1574: case ModelElementChangedKind.MECK_REPRESENTINGCLASSIFIERCHANGED:
1575: // Enhancement W6120: Process the stereotype compartment
1576: updateStereotypeCompartment();
1577: // fall through
1578:
1579: case ModelElementChangedKind.MECK_STEREOTYPEAPPLIED:
1580: case ModelElementChangedKind.MECK_STEREOTYPEDELETED:
1581: delayedSizeToContents();
1582: adjustCreateConnnector = true;
1583: break;
1584:
1585: default:
1586: // do nothing
1587: break;
1588: }
1589: }
1590:
1591: return super .modelElementHasChanged(targets);
1592: }
1593:
1594: /**
1595: * Uses the current representing classifier to update the stereotype
1596: * compartment information.
1597: */
1598: protected void updateStereotypeCompartment() {
1599: IADStereotypeCompartment stereotypeCompartment = getStereotypeCompartment();
1600: if (stereotypeCompartment != null) {
1601: IClassifier classifier = getRepresentingClassifier();
1602: if (classifier != null) {
1603: stereotypeCompartment.addModelElement(classifier, -1);
1604: }
1605: }
1606: }
1607:
1608: //**************************************************
1609: // Helper Methods
1610: //**************************************************
1611:
1612: /**
1613: * Creates a TS edge between the two nodes.
1614: *
1615: * @param message The message to associated with the TS edge, also determines
1616: * edge type
1617: * @param fromNode The node where the edge starts from
1618: * @param toNode The node where the edge finishes
1619: * @return The created edge
1620: */
1621: protected TSEEdge createEdge(IMessage message, TSENode fromNode,
1622: TSENode toNode) {
1623: TSEEdge retVal = null;
1624:
1625: if ((message != null) && (fromNode != null) && (toNode != null)) {
1626: String initStr = "";
1627: switch (message.getKind()) {
1628: case IMessageKind.MK_CREATE:
1629: initStr = "org.netbeans.modules.uml.ui.products.ad.viewfactory.RelationEdge Message create";
1630: break;
1631:
1632: default:
1633: assert false : "did we add another message kind?";
1634:
1635: case IMessageKind.MK_SYNCHRONOUS:
1636: initStr = "org.netbeans.modules.uml.ui.products.ad.viewfactory.RelationEdge Message";
1637: break;
1638:
1639: case IMessageKind.MK_ASYNCHRONOUS:
1640: initStr = "org.netbeans.modules.uml.ui.products.ad.viewfactory.RelationEdge Message asynchronous";
1641: break;
1642:
1643: case IMessageKind.MK_RESULT:
1644: initStr = "org.netbeans.modules.uml.ui.products.ad.viewfactory.RelationEdge Message result";
1645: break;
1646: }
1647:
1648: try {
1649: IDrawingAreaControl ctrl = getDrawingArea();
1650: if ((initStr.length() > 0) && (ctrl != null)) {
1651: ctrl.setModelElement(message);
1652: TSEdge edge = ctrl.addEdge(initStr, fromNode,
1653: toNode, false, false);
1654: ctrl.setModelElement(null);
1655:
1656: if (edge instanceof TSEEdge) {
1657: retVal = (TSEEdge) edge;
1658: }
1659:
1660: }
1661: } catch (ETException e) {
1662: retVal = null;
1663: }
1664: }
1665:
1666: return retVal;
1667: }
1668:
1669: /**
1670: * Update any necessary pieces on the lifelines, and attach the TS edge to
1671: * them.
1672: *
1673: * @param pMessage The message to associated with the TS edge, also determines edge type
1674: * @param pFromNode The node where the edge starts from
1675: * @param pToNode The node where the edge finishes
1676: * @param pEdge The TS edge to be connected to the lifelines
1677: * @return The drawing area vertical location for the TS edge
1678: */
1679: protected int updatePiecesAndAttachMessage(IMessage message,
1680: ILifelineDrawEngine toEngine, TSEEdge edge,
1681: int verticalLocation) {
1682: int retVal = verticalLocation;
1683: if ((message != null) && (toEngine != null) && (edge != null)) {
1684: int kind = message.getKind();
1685: switch (kind) {
1686: case IMessageKind.MK_CREATE:
1687: retVal = attachCreateEdge(toEngine, edge,
1688: verticalLocation);
1689: break;
1690:
1691: default:
1692: assert false : "did we add another message kind?";
1693:
1694: case IMessageKind.MK_SYNCHRONOUS:
1695: retVal = createPiecesAndAttachEdge(toEngine, edge,
1696: kind, verticalLocation);
1697: break;
1698:
1699: case IMessageKind.MK_ASYNCHRONOUS:
1700: retVal = createPiecesAndAttachEdge(toEngine, edge,
1701: kind, verticalLocation);
1702: break;
1703:
1704: case IMessageKind.MK_RESULT:
1705: attachResultEdge(toEngine, edge, verticalLocation);
1706: break;
1707: }
1708: }
1709:
1710: return retVal;
1711: }
1712:
1713: /**
1714: * Update any necessary pieces on the lifelines, and attach the TS edge to them.
1715: *
1716: * @param toNode The node where the edge finishes
1717: * @param edge The TS edge to be connected to the lifelines
1718: * @param plVerticalLocation The drawing area vertical location for the TS edge
1719: */
1720: protected void attachResultEdge(ILifelineDrawEngine toEngine,
1721: TSEEdge edge, int verticalLocation) {
1722: if ((toEngine != null) && (edge != null)) {
1723: boolean isMessageToSelf = (this == toEngine);
1724:
1725: IElement element = TypeConversions.getElement(edge);
1726: if (element instanceof IMessage) {
1727: IMessage returnMsg = (IMessage) element;
1728: IMessage sendingMessage = returnMsg.getSendingMessage();
1729: if (sendingMessage == null) {
1730: sendingMessage = discoverSendingMessage(returnMsg);
1731: }
1732:
1733: IADLifelineCompartment fromCompartment = getLifelineCompartment();
1734:
1735: if (sendingMessage != null) {
1736: IDiagram diagram = getDiagram();
1737: ETList<IPresentationElement> presElements = diagram
1738: .getAllItems2(sendingMessage);
1739:
1740: assert presElements.size() == 1 : "There should only be one presentation element per message";
1741: if ((presElements != null)
1742: && (presElements.size() > 0)) {
1743: IPresentationElement curPresElement = presElements
1744: .get(0);
1745: if (curPresElement instanceof IEdgePresentation) {
1746: // Update the edge's connectors with the new locations
1747: IEdgePresentation edgeP = (IEdgePresentation) curPresElement;
1748:
1749: TSEEdge tsEdge = edgeP.getTSEdge();
1750: TSConnector toConnector = tsEdge
1751: .getSourceConnector();
1752: TSConnector fromConnector = tsEdge
1753: .getTargetConnector();
1754: if ((toConnector != null)
1755: && (fromConnector != null)) {
1756: fromCompartment.connectReturnEdge(
1757: fromConnector, toConnector,
1758: edge);
1759: }
1760: }
1761: }
1762: } else {
1763: IADLifelineCompartment toComparment = toEngine
1764: .getLifelineCompartment();
1765: long deltaClosestAbove = 0;
1766:
1767: int lclFrom = LifelineConnectorLocation.LCL_UNKNOWN;
1768: int lclTo = LifelineConnectorLocation.LCL_UNKNOWN;
1769: if (fromCompartment == toComparment) {
1770: lclFrom = lclTo = LifelineConnectorLocation.LCL_BOTTOMRIGHT;
1771: deltaClosestAbove = PIECES_BUFFER;
1772: } else {
1773: lclFrom = determineBottomPieceFromCorner(toEngine);
1774: lclTo = determineBottomPieceToCorner(toEngine);
1775: }
1776:
1777: // Find the closest piece on the "from" lifeline
1778: IETPoint point = createNewPiecePoint(
1779: fromCompartment,
1780: (int) (verticalLocation + deltaClosestAbove));
1781:
1782: // IETPoint point = new ETPoint((int)rectBounding.getCenterX(),
1783: // (int)(verticalLocation + deltaClosestAbove));
1784:
1785: LifelinePiece fromPiece = fromCompartment
1786: .getClosestLifelinePiece(point);
1787: if ((fromPiece != null)
1788: && (fromPiece.isValid() == true)) {
1789: // Create the from connector
1790: TSConnector fromConnect = fromPiece
1791: .createConnector(lclFrom);
1792:
1793: // and attach the message
1794: edge.setSourceConnector(fromConnect);
1795:
1796: // here we are trying to find the to piece by tracing back
1797: // along our from piece's first connnector. Attach the
1798: // message to the suspension bar on the "to" lifeline
1799: LifelinePiece toPiece = null;
1800: if (isMessageToSelf == true) {
1801: // "Message to self" needs to be handled the "old" way
1802: toPiece = fromPiece.getParentPiece();
1803: } else {
1804: toPiece = fromPiece.getAssociatedPiece();
1805: }
1806:
1807: if ((toPiece != null)
1808: && (toPiece.isValid() == true)) {
1809: // Create the from connector
1810: TSConnector toConnector = toPiece
1811: .createConnector(lclTo);
1812:
1813: // and attach the message
1814: edge.setTargetConnector(toConnector);
1815:
1816: // Update the vertical location
1817: toPiece.setIsPartOfMessageToSelf(true);
1818: }
1819: }
1820: }
1821: }
1822: }
1823: }
1824:
1825: /**
1826: * Select all the messages attached to the lifeline
1827: */
1828: protected void onPreDeleteGatherSelected() {
1829: // Remove any connectors that don't have an edge
1830: TSENode node = getNode();
1831: if (node != null) {
1832: List list = node.connectors();
1833: if (list != null) {
1834: for (Iterator iter = list.iterator(); iter.hasNext();) {
1835: TSConnector connector = (TSConnector) iter.next();
1836:
1837: // Determine if there is an edge connected to this connector
1838: TSEEdge edge = (TSEEdge) PresentationHelper
1839: .getConnectedEdge(connector, true);
1840: if (edge != null) {
1841: if (TypeConversions.areSameTSObjects(connector,
1842: m_ConnectorCreate)) {
1843: // select the edge, to be deleted later
1844: edge.setSelected(true);
1845:
1846: // invalidate the edge so that the user can see what is to be deleted
1847: IETGraphObject etGraphObject = TypeConversions
1848: .getETGraphObject(edge);
1849: if (etGraphObject != null) {
1850: etGraphObject.invalidate();
1851: }
1852: } else {
1853: IElement element = TypeConversions
1854: .getElement(edge);
1855: if (element instanceof IMessage) {
1856: IMessage message = (IMessage) element;
1857:
1858: IETGraphObject etGraphObject = TypeConversions
1859: .getETGraphObject(edge);
1860: if (etGraphObject != null) {
1861: ConnectorPiece
1862: .selectAssociatedEdges(etGraphObject);
1863: }
1864: }
1865: }
1866: }
1867: }
1868: }
1869: }
1870: }
1871:
1872: /**
1873: * Create the pieces necessary to attach the message.
1874: *
1875: * @param pMessage The message to associated with the TS edge, also
1876: * determines edge type
1877: * @param toEngine The draw engine the where the edge finishes
1878: * @param edge The TS edge to be connected to the lifelines
1879: * @param kind Used to determine the type of pieces to create
1880: * @param verticalLocation The vertical location for the TS edge. The
1881: * return value is an updated version of the
1882: * verticdal location.
1883: * @return The drawing area vertical location for the TS edge.
1884: *
1885: * @return HRESULT
1886: */
1887: protected int createPiecesAndAttachEdge(
1888: ILifelineDrawEngine toEngine, TSEEdge edge, int kind,
1889: int verticalLocation) {
1890: int retVal = verticalLocation;
1891:
1892: if ((toEngine != null) && (edge != null)) {
1893: IADLifelineCompartment fromCompartment = getLifelineCompartment();
1894: IADLifelineCompartment toCompartment = toEngine
1895: .getLifelineCompartment();
1896: if ((fromCompartment != null) && (toCompartment != null)) {
1897: int lclFrom = LifelineConnectorLocation.LCL_UNKNOWN;
1898: int lclTo = LifelineConnectorLocation.LCL_UNKNOWN;
1899: boolean isMessageToSelf = false;
1900: if (fromCompartment == toCompartment) {
1901: lclFrom = LifelineConnectorLocation.LCL_TOPRIGHT;
1902: lclTo = LifelineConnectorLocation.LCL_TOPRIGHT;
1903: isMessageToSelf = true;
1904: } else {
1905: lclFrom = determinePieceFromCorner(toEngine);
1906: lclTo = determinePieceToCorner(toEngine);
1907: }
1908:
1909: // Create the required piece on the from lifeline
1910: // CComPtr< ILifelinePiece > cpFromPiece;
1911: int kindPiece = LifelinePiecesKind.LPK_SUSPENSION;
1912: if (IMessageKind.MK_ASYNCHRONOUS == kind) {
1913: kindPiece = LifelinePiecesKind.LPK_ATOMIC_FRAGMENT;
1914: }
1915:
1916: IETPoint point = createNewPiecePoint(fromCompartment,
1917: retVal);
1918: LifelinePiece fromPiece = fromCompartment
1919: .createLifelinePiece(kindPiece, point);
1920: if (fromPiece != null) {
1921: // Create the from connector
1922: TSConnector fromConnector = fromPiece
1923: .createConnector(lclFrom);
1924:
1925: // and attach the message
1926: edge.setSourceConnector(fromConnector);
1927:
1928: // Determine the "to" vertical location
1929: if (fromConnector != null) {
1930: retVal = fromPiece.getLogicalTop();
1931:
1932: // Fix W2355 & W2761: When the user tries to add the message
1933: // to self decoration on an activation bar the creation was
1934: // getting messed up.
1935: if (isMessageToSelf == true) {
1936: retVal -= PIECES_BUFFER / 2;
1937: }
1938: }
1939: }
1940:
1941: // Clean up the activation bars so that the new activation bar will hook
1942: // hook to the one above, if possible.
1943: // This inturn also updates the associated suspension area, which is
1944: // really what we need.
1945: // TESTING fromCompartment.cleanUpActivationBars();
1946:
1947: // Create an activation bar on the to lifeline, and attach the message
1948: point = createNewPiecePoint(toCompartment, retVal);
1949: LifelinePiece toPiece = toCompartment
1950: .createLifelinePiece(
1951: LifelinePiecesKind.LPK_ACTIVATION,
1952: point);
1953: if (toPiece.isValid() == true) {
1954: // Create the from connector
1955: TSConnector toConnector = toPiece
1956: .createConnector(lclTo);
1957:
1958: // and attach the message
1959: edge.setTargetConnector(toConnector);
1960:
1961: if (fromCompartment == toCompartment) {
1962: // For reflexive messages,
1963: // the next point must be just beyond the bottom of the activation bar.
1964: int bottom = toPiece.getLogicalBottom();
1965: retVal = bottom - (PIECES_BUFFER / 2);
1966: } else if ((LifelinePiecesKind.LPK_ATOMIC_FRAGMENT == kind)
1967: && (toPiece != null)) {
1968: retVal = toPiece.getLogicalBottom();
1969: retVal -= PIECES_BUFFER / 2;
1970: } else {
1971: // For non-reflexive messages,
1972: // the next point must not be further down then the end of the parent piece
1973: retVal -= PIECES_BUFFER;
1974: }
1975: }
1976: }
1977:
1978: }
1979:
1980: return retVal;
1981: }
1982:
1983: /**
1984: * Determine the sending message for the input result message
1985: * This is done by searching for the preceeding synchronous message that
1986: * points the opposite direction to the result message.
1987: *
1988: * @warning For now the code fails if there is a synchronous/result pair between the result and its sender
1989: */
1990: protected IMessage discoverSendingMessage(IMessage messageResult) {
1991: // The C++ version always returns NULL from some reason. So, we are
1992: // doing the same thing here.
1993: return null;
1994: }
1995:
1996: /**
1997: * @param toEngine
1998: * @param edge
1999: * @return
2000: */
2001: protected int attachCreateEdge(ILifelineDrawEngine toEngine,
2002: TSEEdge edge, int verticalLocation) {
2003: int retVal = verticalLocation;
2004:
2005: if ((toEngine != null) && (edge != null)) {
2006: IADLifelineCompartment fromCompartment = getLifelineCompartment();
2007: if (fromCompartment != null) {
2008: TSConnector fromConnector = addConnector();
2009:
2010: // Create a suspension area on the from lifeline, and attach the
2011: // message
2012: IETPoint pt = createNewPiecePoint(fromCompartment,
2013: verticalLocation);
2014: fromConnector.setCenterY(pt.getY());
2015: //fromConnector.setCenterY(0);
2016: fromCompartment.createElement(
2017: LifelinePiecesKind.LPK_ATOMIC_FRAGMENT,
2018: fromConnector,
2019: determinePieceFromCorner(toEngine));
2020:
2021: edge.setSourceConnector(fromConnector);
2022:
2023: // Attach the end of the edge to the create connector for the to DE
2024: TSConnector toConnector = toEngine
2025: .getConnectorForCreateMessage();
2026: edge.setTargetConnector(toConnector);
2027: toEngine.makeCreateMessageHorizontal();
2028:
2029: retVal -= PIECES_BUFFER / 2;
2030: }
2031: }
2032:
2033: Debug.out.println("Number of Connectors "
2034: + getNode().numberOfConnectors());
2035: return retVal;
2036: }
2037:
2038: /**
2039: * Determine which from corner is the inside corners between this DE and the to
2040: * DE.
2041: *
2042: * @param toEngine The other engine
2043: * @return The connector location for this engine. Will be one of the
2044: * LifelineConnectorLocation values.
2045: *
2046: * @see LifelineConnectorLocation
2047: */
2048: protected int determinePieceFromCorner(ILifelineDrawEngine toEngine) {
2049: int retVal = LifelineConnectorLocation.LCL_UNKNOWN;
2050:
2051: if (toEngine != null) {
2052: IETRect rectFromBounding = getLogicalBoundingRect();
2053: IETRect rectToBounding = TypeConversions
2054: .getLogicalBoundingRect(toEngine);
2055:
2056: if (rectFromBounding.getCenterX() < rectToBounding
2057: .getCenterX()) {
2058: retVal = LifelineConnectorLocation.LCL_TOPRIGHT;
2059: } else {
2060: retVal = LifelineConnectorLocation.LCL_TOPLEFT;
2061: }
2062: }
2063:
2064: return retVal;
2065: }
2066:
2067: /**
2068: * Determine which from corner is the inside corners between this DE and the to
2069: * DE.
2070: *
2071: * @param toEngine The other engine
2072: * @return The connector location for this engine. Will be one of the
2073: * LifelineConnectorLocation values.
2074: *
2075: * @see LifelineConnectorLocation
2076: */
2077: protected int determineBottomPieceFromCorner(
2078: ILifelineDrawEngine toEngine) {
2079: int retVal = LifelineConnectorLocation.LCL_UNKNOWN;
2080:
2081: if (toEngine != null) {
2082: IETRect rectFromBounding = getLogicalBoundingRect();
2083: IETRect rectToBounding = TypeConversions
2084: .getLogicalBoundingRect(toEngine);
2085:
2086: if (rectFromBounding.getCenterX() < rectToBounding
2087: .getCenterX()) {
2088: retVal = LifelineConnectorLocation.LCL_BOTTOMRIGHT;
2089: } else {
2090: retVal = LifelineConnectorLocation.LCL_BOTTOMLEFT;
2091: }
2092: }
2093:
2094: return retVal;
2095: }
2096:
2097: /**
2098: * Determine which from corner is the inside corners between this DE and the to
2099: * DE.
2100: *
2101: * @param toEngine The other engine
2102: * @return The connector location for this engine. Will be one of the
2103: * LifelineConnectorLocation values.
2104: *
2105: * @see LifelineConnectorLocation
2106: */
2107: protected int determineBottomPieceToCorner(
2108: ILifelineDrawEngine toEngine) {
2109: int retVal = LifelineConnectorLocation.LCL_UNKNOWN;
2110:
2111: if (toEngine != null) {
2112: IETRect rectFromBounding = getLogicalBoundingRect();
2113: IETRect rectToBounding = TypeConversions
2114: .getLogicalBoundingRect(toEngine);
2115:
2116: if (rectFromBounding.getCenterX() < rectToBounding
2117: .getCenterX()) {
2118: retVal = LifelineConnectorLocation.LCL_BOTTOMLEFT;
2119: } else {
2120: retVal = LifelineConnectorLocation.LCL_BOTTOMRIGHT;
2121: }
2122: }
2123:
2124: return retVal;
2125: }
2126:
2127: /**
2128: * Determine which from corner is the inside corners between this DE and the to
2129: * DE.
2130: *
2131: * @param toEngine The other engine
2132: * @return The connector location for this engine. Will be one of the
2133: * LifelineConnectorLocation values.
2134: *
2135: * @see LifelineConnectorLocation
2136: */
2137: protected int determinePieceToCorner(ILifelineDrawEngine toEngine) {
2138: int retVal = LifelineConnectorLocation.LCL_UNKNOWN;
2139:
2140: if (toEngine != null) {
2141: IETRect rectFromBounding = getLogicalBoundingRect();
2142: IETRect rectToBounding = TypeConversions
2143: .getLogicalBoundingRect(toEngine);
2144:
2145: if (rectFromBounding.getCenterX() < rectToBounding
2146: .getCenterX()) {
2147: retVal = LifelineConnectorLocation.LCL_TOPLEFT;
2148: } else {
2149: retVal = LifelineConnectorLocation.LCL_TOPRIGHT;
2150: }
2151: }
2152:
2153: return retVal;
2154: }
2155:
2156: /**
2157: * Creates an ET point that is the logical drawing area coordinate for a new
2158: * piece this is done by using the center location of the draw engine for the
2159: * horizontal location
2160: *
2161: * @param comparment The reference compartment.
2162: * @param verticalLocation The logical drawing area vertical location for
2163: * the new piece
2164: * @return The point
2165: */
2166: protected IETPoint createNewPiecePoint(
2167: IADLifelineCompartment compartment, int verticalLocation) {
2168: IETPoint retVal = null;
2169:
2170: IETRect rectBounding = TypeConversions
2171: .getLogicalBoundingRect(compartment);
2172: retVal = new ETPoint((int) rectBounding.getCenterX(),
2173: verticalLocation);
2174:
2175: return retVal;
2176: }
2177:
2178: /**
2179: * Retreives the diagram engine for the diagram that contains the draw engine.
2180: * @return The sequence diagram engine contains the lifeline.
2181: */
2182: protected IADSequenceDiagEngine getDiagramEngine() {
2183: IADSequenceDiagEngine retVal = null;
2184:
2185: IDiagramEngine engine = TypeConversions
2186: .getDiagramEngine(getDiagram());
2187: if (engine instanceof IADSequenceDiagEngine) {
2188: retVal = (IADSequenceDiagEngine) engine;
2189: }
2190:
2191: return retVal;
2192: }
2193:
2194: /* (non-Javadoc)
2195: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#handleLeftMouseButtonPressed(java.awt.event.MouseEvent)
2196: */
2197: public boolean handleLeftMouseButtonPressed(MouseEvent pEvent) {
2198: if (hasMessagesAttached()) {
2199: IDrawingAreaControl daCtrl = getDrawingArea();
2200: ADGraphWindow graphWindow = daCtrl != null ? daCtrl
2201: .getGraphWindow() : null;
2202:
2203: SmartDragTool dragTool = createSmartDragTool(pEvent);
2204:
2205: if (dragTool == null)
2206: return false;
2207:
2208: dragTool
2209: .setDragRestrictionType(SmartDragTool.DR.HORIZONTAL_MOVE_ONLY);
2210:
2211: //graphWindow.getCurrentState().setState(dragTool);
2212: graphWindow.getCurrentTool().setTool(dragTool);
2213: dragTool.onMousePressed(pEvent);
2214:
2215: return true;
2216: } else
2217: return super .handleLeftMouseButtonPressed(pEvent);
2218: }
2219:
2220: public boolean isCreated() {
2221: validateCreateMessageConnector();
2222:
2223: return m_ConnectorCreate != null;
2224: }
2225:
2226: /**
2227: * Inserts a new message between a this lifeline and another lifeline.
2228: * If a relative message is also specified, the new message will be added
2229: * before the specified message. Otherwise the new message will be added
2230: * after all other message.
2231: *
2232: * @param to The reciever of the message.
2233: * @param msgType The type of message.
2234: * @param relativeMessage The message that will be after the new message.
2235: * May be null.
2236: */
2237: public void insertMessageBefore(ILifelineDrawEngine to,
2238: int msgType, IMessageEdgeDrawEngine relativeMessage) {
2239: IADLifelineCompartment compartment = getLifelineCompartment();
2240: compartment.addMessageBefore(to, relativeMessage, msgType);
2241: }
2242:
2243: /**
2244: * Inserts a new message between a this lifeline and another lifeline.
2245: * If a relative message is also specified, the new message will be added
2246: * after the specified message. Otherwise the new message will be added
2247: * after all other message.
2248: *
2249: * @param to The reciever of the message.
2250: * @param msgType The type of message.
2251: * @param relativeMessage The message that will be before the new message.
2252: * May be null.
2253: */
2254: public void insertMessageAfter(ILifelineDrawEngine to, int msgType,
2255: IMessageEdgeDrawEngine relativeMessage) {
2256: IADLifelineCompartment compartment = getLifelineCompartment();
2257: compartment.addMessageAfter(to, relativeMessage, msgType);
2258: }
2259:
2260: /**
2261: * Adds a destroy decorator to the end of a the lifeline.
2262: */
2263: public void addDestroyMessage() {
2264: getLifelineCompartment().addDecoration("destroy", null);
2265: }
2266:
2267: /**
2268: * Inserts a new message to self. The location of the new messages is
2269: * based on target messages. The new message to self will be either
2270: * before or after the target message.
2271: *
2272: * If the target message is null, the new message will be at the end of the
2273: * lifeline.
2274: *
2275: * @param targetMsg The message that the new message will be relative to.
2276: * Can be null.
2277: * @param before if true, the new message will be before the target message.
2278: * if false, the new message will be after the target message.
2279: */
2280: public void addMessageToSelf(IMessageEdgeDrawEngine targetMsg,
2281: boolean before) {
2282: IADLifelineCompartment compartment = getLifelineCompartment();
2283: if (before == true) {
2284: compartment.addMessageBefore(this , targetMsg,
2285: IMessageKind.MK_SYNCHRONOUS);
2286: } else {
2287: compartment.addMessageAfter(this , targetMsg,
2288: IMessageKind.MK_SYNCHRONOUS);
2289: }
2290: }
2291:
2292: /**
2293: * Inserts a new create message. The location of the new messages is
2294: * based on target messages. The new create message will be either
2295: * before or after the target message.
2296: *
2297: * If the target message is null, the new message will be at the end of the
2298: * lifeline.
2299: *
2300: * @param targetMsg The message that the new message will be relative to.
2301: * Can be null.
2302: * @param before if true, the new message will be before the target message.
2303: * if false, the new message will be after the target message.
2304: */
2305: public void addCreateMessage(IMessageEdgeDrawEngine targetMsg,
2306: boolean before) {
2307: try {
2308: ETNode node = (ETNode) TypeConversions.getTSObject(this );
2309: double newNodeX = node.getLocalRight() + 20;
2310:
2311: ETPoint pt = new ETPoint((int) newNodeX, (int) node
2312: .getLocalTop());
2313: ETNode newNode = getDrawingArea().addNodeForType(
2314: "Lifeline", pt, false, true);
2315:
2316: IDrawEngine targetEngine = TypeConversions
2317: .getDrawEngine((TSNode) newNode);
2318: if (targetEngine instanceof ILifelineDrawEngine) {
2319: ILifelineDrawEngine targetLifeline = (ILifelineDrawEngine) targetEngine;
2320: IADLifelineCompartment compartment = getLifelineCompartment();
2321: if (before == true) {
2322: compartment.addMessageBefore(targetLifeline,
2323: targetMsg, IMessageKind.MK_CREATE);
2324: } else {
2325: compartment.addMessageAfter(targetLifeline,
2326: targetMsg, IMessageKind.MK_CREATE);
2327: }
2328: }
2329: } catch (ETException ex) {
2330: ErrorManager.getDefault().notify(ex);
2331: }
2332: }
2333:
2334: protected void validateCreateMessageConnector() {
2335: if (m_ConnectorCreate != null) {
2336: TSDNode node = getOwnerNode();
2337:
2338: if (node != null) {
2339: List connectorList = node.connectors();
2340: if (!connectorList.contains(m_ConnectorCreate))
2341: m_ConnectorCreate = null;
2342: }
2343: }
2344: }
2345:
2346: public void initResources() {
2347: setFillColor("lifelinefill", 211, 227, 244);
2348: setLightGradientFillColor("lifelinelightgradientfill", 255,
2349: 255, 255);
2350: setBorderColor("lifelineborder", Color.BLACK);
2351:
2352: super .initResources();
2353: }
2354:
2355: /* (non-Javadoc)
2356: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#performDeepSynch()
2357: */
2358: public long performDeepSynch() {
2359: // this should be in ETDrawEngine.performDeepSynch, but the engines aren't implemented correctly
2360: IPresentationElement presentationElement = TypeConversions
2361: .getPresentationElement(this );
2362: if (presentationElement != null)
2363: initCompartments(presentationElement);
2364:
2365: validateNode();
2366:
2367: return 0;
2368: }
2369:
2370: /* (non-Javadoc)
2371: * @see org.netbeans.modules.uml.ui.support.viewfactorysupport.IDrawEngine#onDiscardParentETElement()
2372: */
2373: public void onDiscardParentETElement() {
2374: super .onDiscardParentETElement();
2375: // Stops the connectors from updating if our parent node is deleted from the graph.
2376: m_StickFigureCompartment = null;
2377:
2378: m_NameCompartment = null;
2379: m_LifelineCompartment = null;
2380: m_StereotypeCompartment = null;
2381: m_ConnectorCreate = null;
2382:
2383: /// the minimum allowable rectangle for this container
2384: m_rectMinimumResize = null;
2385: }
2386:
2387: }
|