uml.diagrams/src/org/netbeans/modules/uml/diagrams/actions/sqd/MessagesConnectProvider.java
author Sergey B. Petrov <sj-nb@netbeans.org>
Sat, 05 Jan 2013 00:23:24 +0400
changeset 41 23c21d7d00d5
parent 0 054eeee980fe
permissions -rw-r--r--
classcast fix on sqd when draw new message
jglick@0
     1
/*
jglick@0
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jglick@0
     3
 *
jglick@0
     4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
jglick@0
     5
 *
jglick@0
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
jglick@0
     7
 * Other names may be trademarks of their respective owners.
jglick@0
     8
 *
jglick@0
     9
 * The contents of this file are subject to the terms of either the GNU
jglick@0
    10
 * General Public License Version 2 only ("GPL") or the Common
jglick@0
    11
 * Development and Distribution License("CDDL") (collectively, the
jglick@0
    12
 * "License"). You may not use this file except in compliance with the
jglick@0
    13
 * License. You can obtain a copy of the License at
jglick@0
    14
 * http://www.netbeans.org/cddl-gplv2.html
jglick@0
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jglick@0
    16
 * specific language governing permissions and limitations under the
jglick@0
    17
 * License.  When distributing the software, include this License Header
jglick@0
    18
 * Notice in each file and include the License file at
jglick@0
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
jglick@0
    20
 * particular file as subject to the "Classpath" exception as provided
jglick@0
    21
 * by Oracle in the GPL Version 2 section of the License file that
jglick@0
    22
 * accompanied this code. If applicable, add the following below the
jglick@0
    23
 * License Header, with the fields enclosed by brackets [] replaced by
jglick@0
    24
 * your own identifying information:
jglick@0
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
jglick@0
    26
 *
jglick@0
    27
 * Contributor(s):
jglick@0
    28
 *
jglick@0
    29
 * The Original Software is NetBeans. The Initial Developer of the Original
jglick@0
    30
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
jglick@0
    31
 * Microsystems, Inc. All Rights Reserved.
jglick@0
    32
 *
jglick@0
    33
 * If you wish your version of this file to be governed by only the CDDL
jglick@0
    34
 * or only the GPL Version 2, indicate your decision by adding
jglick@0
    35
 * "[Contributor] elects to include this software in this distribution
jglick@0
    36
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jglick@0
    37
 * single choice of license, a recipient has the option to distribute
jglick@0
    38
 * your version of this file under either the CDDL, the GPL Version 2 or
jglick@0
    39
 * to extend the choice of license to its licensees as provided above.
jglick@0
    40
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jglick@0
    41
 * Version 2 license, then the option applies only if the new code is
jglick@0
    42
 * made subject to such option by the copyright holder.
jglick@0
    43
 */
jglick@0
    44
jglick@0
    45
package org.netbeans.modules.uml.diagrams.actions.sqd;
jglick@0
    46
jglick@0
    47
import java.awt.Point;
jglick@0
    48
import java.awt.Rectangle;
jglick@0
    49
import java.util.ArrayList;
jglick@0
    50
import java.util.List;
jglick@0
    51
import java.util.ResourceBundle;
jglick@0
    52
import org.netbeans.api.visual.action.ActionFactory;
jglick@0
    53
import org.netbeans.api.visual.action.ConnectorState;
jglick@0
    54
import org.netbeans.api.visual.anchor.Anchor;
jglick@0
    55
import org.netbeans.api.visual.anchor.AnchorFactory;
jglick@0
    56
import org.netbeans.api.visual.graph.GraphScene;
jglick@0
    57
import org.netbeans.api.visual.model.ObjectScene;
jglick@0
    58
import org.netbeans.api.visual.router.Router;
jglick@0
    59
import org.netbeans.api.visual.widget.ConnectionWidget;
jglick@0
    60
import org.netbeans.api.visual.widget.Scene;
jglick@0
    61
import org.netbeans.api.visual.widget.Widget;
jglick@0
    62
import org.netbeans.modules.uml.core.metamodel.core.foundation.BaseElement;
jglick@0
    63
import org.netbeans.modules.uml.core.metamodel.core.foundation.FactoryRetriever;
jglick@0
    64
import org.netbeans.modules.uml.core.metamodel.core.foundation.ICreationFactory;
jglick@0
    65
import org.netbeans.modules.uml.core.metamodel.core.foundation.IElement;
jglick@0
    66
import org.netbeans.modules.uml.core.metamodel.core.foundation.INamedElement;
jglick@0
    67
import org.netbeans.modules.uml.core.metamodel.core.foundation.INamespace;
jglick@0
    68
import org.netbeans.modules.uml.core.metamodel.core.foundation.IPresentationElement;
jglick@0
    69
import org.netbeans.modules.uml.core.metamodel.core.foundation.IRelationship;
jglick@0
    70
import org.netbeans.modules.uml.core.metamodel.core.foundation.OwnerRetriever;
jglick@0
    71
import org.netbeans.modules.uml.core.metamodel.core.foundation.RelationProxy;
jglick@0
    72
import org.netbeans.modules.uml.core.metamodel.core.foundation.RelationValidator;
jglick@0
    73
import org.netbeans.modules.uml.core.metamodel.diagrams.IDiagram;
jglick@0
    74
import org.netbeans.modules.uml.core.metamodel.dynamics.ICombinedFragment;
jglick@0
    75
import org.netbeans.modules.uml.core.metamodel.dynamics.IInteraction;
jglick@0
    76
import org.netbeans.modules.uml.core.metamodel.dynamics.ILifeline;
jglick@0
    77
import org.netbeans.modules.uml.core.metamodel.dynamics.IMessage;
jglick@0
    78
import org.netbeans.modules.uml.core.metamodel.dynamics.IMessageConnector;
jglick@0
    79
import org.netbeans.modules.uml.core.metamodel.dynamics.Lifeline;
jglick@0
    80
import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IClassifier;
jglick@0
    81
import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IFeature;
jglick@0
    82
import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IOperation;
jglick@0
    83
import org.netbeans.modules.uml.core.support.umlutils.ETList;
jglick@0
    84
import org.netbeans.modules.uml.diagrams.anchors.CreateMessageTargetAnchor;
jglick@0
    85
import org.netbeans.modules.uml.diagrams.edges.factories.MessageFactory;
jglick@0
    86
import org.netbeans.modules.uml.diagrams.edges.sqd.MessageWidget;
jglick@0
    87
import org.netbeans.modules.uml.diagrams.engines.SequenceDiagramEngine;
jglick@0
    88
import org.netbeans.modules.uml.diagrams.nodes.sqd.CombinedFragmentWidget;
jglick@0
    89
import org.netbeans.modules.uml.diagrams.nodes.sqd.ExecutionSpecificationThinWidget;
jglick@0
    90
import org.netbeans.modules.uml.diagrams.nodes.sqd.InteractionOperandWidget;
jglick@0
    91
import org.netbeans.modules.uml.diagrams.nodes.sqd.LifelineBoxWidget;
jglick@0
    92
import org.netbeans.modules.uml.diagrams.nodes.sqd.LifelineLineWidget;
jglick@0
    93
import org.netbeans.modules.uml.diagrams.nodes.sqd.LifelineWidget;
jglick@0
    94
import org.netbeans.modules.uml.diagrams.nodes.sqd.MessagePinWidget;
jglick@0
    95
import org.netbeans.modules.uml.drawingarea.actions.ActionProvider;
jglick@0
    96
import org.netbeans.modules.uml.drawingarea.actions.AfterValidationExecutor;
jglick@0
    97
import org.netbeans.modules.uml.drawingarea.actions.SQDMessageConnectProvider;
jglick@0
    98
import org.netbeans.modules.uml.drawingarea.palette.RelationshipFactory;
jglick@0
    99
import org.netbeans.modules.uml.drawingarea.persistence.PersistenceUtil;
sj-nb@41
   100
import org.netbeans.modules.uml.drawingarea.support.ModelElementBridge;
jglick@0
   101
import org.netbeans.modules.uml.drawingarea.view.DesignerScene;
jglick@0
   102
import org.netbeans.modules.uml.drawingarea.view.DesignerTools;
jglick@0
   103
import org.netbeans.modules.uml.drawingarea.view.UMLEdgeWidget;
jglick@0
   104
import org.netbeans.modules.uml.drawingarea.view.UMLNodeWidget;
jglick@0
   105
import org.netbeans.modules.uml.ui.support.SimpleQuestionDialogKind;
jglick@0
   106
import org.netbeans.modules.uml.ui.support.SimpleQuestionDialogResultKind;
jglick@0
   107
import org.netbeans.modules.uml.ui.support.SwingPreferenceQuestionDialog;
jglick@0
   108
import org.netbeans.modules.uml.ui.support.commondialogs.IPreferenceQuestionDialog;
jglick@0
   109
import org.netbeans.modules.uml.ui.support.commondialogs.MessageIconKindEnum;
jglick@0
   110
jglick@0
   111
jglick@0
   112
/**
jglick@0
   113
 *
jglick@0
   114
 * @author psb
jglick@0
   115
 */
jglick@0
   116
public class MessagesConnectProvider implements SQDMessageConnectProvider
jglick@0
   117
{
jglick@0
   118
jglick@0
   119
    private String edgeType;
jglick@0
   120
    private String defaultTargetType;
jglick@0
   121
    private int edgeKind;
jglick@0
   122
    private RelationValidator validator = new RelationValidator();
jglick@0
   123
    private RelationshipFactory factory = null;
jglick@0
   124
    private IMessage message;
jglick@0
   125
    private IMessage resultMessage;
jglick@0
   126
jglick@0
   127
jglick@0
   128
    /** 
jglick@0
   129
     * Creates a new instance of SceneConnectProvider.  The provider will create
jglick@0
   130
     * an edge of type edgeType.  If the user drops the edge on the diagram as
jglick@0
   131
     * opposed to a node, the targetType will be used to create a new node.  
jglick@0
   132
     * 
jglick@0
   133
     * @param edgeType the type of edge to create.
jglick@0
   134
     * @param targetType the type of node to create if the user releases over 
jglick@0
   135
     *                   the diagram.
jglick@0
   136
     */
jglick@0
   137
    public MessagesConnectProvider(String connectionType, int connectionKind, String defaultTargetType) {
jglick@0
   138
        this.edgeType = connectionType;
jglick@0
   139
        this.defaultTargetType = defaultTargetType;
jglick@0
   140
        this.edgeKind=connectionKind;
jglick@0
   141
        message=null;
jglick@0
   142
        resultMessage=null;
jglick@0
   143
    }
jglick@0
   144
jglick@0
   145
    /**
jglick@0
   146
     * constructor used to draw messages for existent model elemnts
jglick@0
   147
     * corrspodning conect method will not create new elements but will use specified in constructor elemnt
jglick@0
   148
     * presentation elements will be created
jglick@0
   149
     * @param message
jglick@0
   150
     */
jglick@0
   151
    public MessagesConnectProvider(IMessage message)
jglick@0
   152
    {
jglick@0
   153
        this(message,null);
jglick@0
   154
    }
jglick@0
   155
    
jglick@0
   156
    public MessagesConnectProvider(IMessage call, IMessage result) {
jglick@0
   157
        this.message=call;
jglick@0
   158
        resultMessage=result;
jglick@0
   159
        edgeKind=message.getKind();
jglick@0
   160
    }
jglick@0
   161
    
jglick@0
   162
    public boolean isSourceWidget(Widget sourceWidget)
jglick@0
   163
    {
jglick@0
   164
        return sourceWidget instanceof UMLNodeWidget;
jglick@0
   165
    }
jglick@0
   166
    
jglick@0
   167
    
jglick@0
   168
    public boolean isSourceWidget(Widget sourceWidget, Point sourcePoint) {
jglick@0
   169
        boolean ret=isSourceWidget(sourceWidget);
jglick@0
   170
        if(ret && sourceWidget instanceof LifelineWidget)
jglick@0
   171
        {
jglick@0
   172
                LifelineLineWidget sourceLine=((LifelineWidget)sourceWidget).getLine();
jglick@0
   173
                int y1=sourceLine.convertSceneToLocal(sourcePoint).y;//incoming corrdinates in LifelineWidget coordinates, we adds child to LifelineLineWidget
jglick@0
   174
                if(y1<0 || y1>sourceLine.getBounds().height)
jglick@0
   175
                {
jglick@0
   176
                    //outside of line
jglick@0
   177
                    ret=false;
jglick@0
   178
                }
jglick@0
   179
                else
jglick@0
   180
                {
jglick@0
   181
                    ExecutionSpecificationThinWidget sourcePreexistentSpec=getExSpecification(sourceLine, y1);
jglick@0
   182
                    ExSpecData sourcePair=null;
jglick@0
   183
jglick@0
   184
                    if(sourcePreexistentSpec!=null)
jglick@0
   185
                    {
jglick@0
   186
                        int ys=sourcePreexistentSpec.convertSceneToLocal(sourcePoint).y;
jglick@0
   187
                        sourcePair=getWidgetsAroundPoint(sourcePreexistentSpec, ys);
jglick@0
   188
                        //first can't draw any message within source of synch message (lifeline wait returns)
jglick@0
   189
                        //and also can't create/call multiple mthods at one atomic time
jglick@0
   190
                        //TBD add support for multiple calls from one ex specification 
jglick@0
   191
                        //TBD do not check in isTarget
jglick@0
   192
                        if(sourcePair.getFirstWidget() instanceof MessagePinWidget)
jglick@0
   193
                        {
jglick@0
   194
                            MessagePinWidget.PINKIND firstKind=((MessagePinWidget)sourcePair.getFirstWidget()).getKind();
jglick@0
   195
                            MessagePinWidget.PINKIND prevKind=firstKind;//by default if it above the very first pin, consider the same as first
jglick@0
   196
                            if(sourcePair.getPrevWidget()!=null && sourcePair.getPrevWidget() instanceof MessagePinWidget)prevKind=((MessagePinWidget)sourcePair.getPrevWidget()).getKind();
jglick@0
   197
                            if(firstKind==MessagePinWidget.PINKIND.SYNCHRONOUS_CALL_OUT || prevKind==MessagePinWidget.PINKIND.SYNCHRONOUS_CALL_OUT || firstKind==MessagePinWidget.PINKIND.ASYNCHRONOUS_CALL_OUT || firstKind==MessagePinWidget.PINKIND.CREATE_CALL_OUT)
jglick@0
   198
                            {
jglick@0
   199
                                //can't create from within of synchronous message source
jglick@0
   200
                                //prohobite also other creations from source for now
jglick@0
   201
                                ret= false;
jglick@0
   202
                            }
jglick@0
   203
                        }
jglick@0
   204
                    }
jglick@0
   205
                }
jglick@0
   206
        }
jglick@0
   207
        return ret;
jglick@0
   208
    }
jglick@0
   209
jglick@0
   210
    /**
jglick@0
   211
     * check target widget and consider target ppoint (checks if possible to draw message to this point)
jglick@0
   212
     * @param sourceWidget - message from this widget
jglick@0
   213
     * @param targetWidget - message to this widget
jglick@0
   214
     * @param sourcePoint - message from this point on source point in scene coordinates
jglick@0
   215
     * @param targetPoint - message to this point on target widget in scene coordinates, in general isn't used much and may be the same as source often
jglick@0
   216
     * @return accept if connection is possible
jglick@0
   217
     */
jglick@0
   218
    public ConnectorState isTargetWidget(Widget sourceWidget, Widget targetWidget,Point sourcePoint,Point targetPoint)
jglick@0
   219
    {   
jglick@0
   220
        ConnectorState retVal = ConnectorState.REJECT;
jglick@0
   221
        
jglick@0
   222
        if(targetWidget instanceof InteractionOperandWidget)return retVal;
jglick@0
   223
        
jglick@0
   224
        ObjectScene scene = (ObjectScene)sourceWidget.getScene();
jglick@0
   225
        // Verify that this relationship is ok
jglick@0
   226
        RelationProxy relationshipProxy = new RelationProxy();
jglick@0
   227
        IPresentationElement source = (IPresentationElement) scene.findObject(sourceWidget);
sj-nb@41
   228
        Object trg = scene.findObject(targetWidget);
sj-nb@41
   229
        IPresentationElement target = trg instanceof IPresentationElement ? (IPresentationElement) trg : null;;
jglick@0
   230
        if(target != null)
jglick@0
   231
        {
jglick@0
   232
            if(scene.findWidget(target) != targetWidget)
jglick@0
   233
            {
jglick@0
   234
                target = null;
jglick@0
   235
            }
jglick@0
   236
        }
jglick@0
   237
jglick@0
   238
jglick@0
   239
        //check if target is of valid type, it may be easier for now to check only comment element(invalid) but in case of more elements later 
jglick@0
   240
        //I use check for valid elements
jglick@0
   241
        if((source != null) && (target != null) && ((target.getFirstSubject() instanceof ILifeline) || (target.getFirstSubject() instanceof IInteraction) || (target.getFirstSubject() instanceof ICombinedFragment)))
jglick@0
   242
        {
jglick@0
   243
            relationshipProxy.setFrom(source.getFirstSubject());
jglick@0
   244
            relationshipProxy.setTo(target.getFirstSubject());
jglick@0
   245
            String connectorType="MessageConnector";//TBD, remove hardcoded type(if this provider will be used not for messages only)
jglick@0
   246
            relationshipProxy.setConnectionElementType(connectorType);
jglick@0
   247
jglick@0
   248
            // Verify the relation
jglick@0
   249
            validator.validateRelation(relationshipProxy);
jglick@0
   250
jglick@0
   251
            if(relationshipProxy.getRelationValidated() == true)
jglick@0
   252
            {
jglick@0
   253
                retVal = ConnectorState.ACCEPT;
jglick@0
   254
            }
jglick@0
   255
        }
jglick@0
   256
        
jglick@0
   257
        if(retVal==ConnectorState.ACCEPT)
jglick@0
   258
        {
jglick@0
   259
            if(targetWidget instanceof CombinedFragmentWidget)
jglick@0
   260
            {
jglick@0
   261
                Rectangle bnd=targetWidget.getBounds();
jglick@0
   262
                Point locPnt=targetWidget.convertSceneToLocal(targetPoint);
jglick@0
   263
                if(locPnt.x>(bnd.x+30) && locPnt.x<(bnd.x+bnd.width-30))retVal=ConnectorState.REJECT;
jglick@0
   264
                else if(target==source)retVal=ConnectorState.REJECT;//disable message to self on combined fragments
jglick@0
   265
            }
jglick@0
   266
            if(retVal==ConnectorState.ACCEPT)
jglick@0
   267
            {
jglick@0
   268
                //additional checks is required sometimes
jglick@0
   269
                if(edgeKind==BaseElement.MK_CREATE)
jglick@0
   270
                {
jglick@0
   271
                    targetWidget=scene.findWidget(target);
jglick@0
   272
                    if(targetWidget instanceof LifelineWidget)
jglick@0
   273
                    {
jglick@0
   274
                        LifelineWidget tmp=(LifelineWidget) targetWidget;
jglick@0
   275
                        if(tmp.isCreated() || targetWidget==sourceWidget)
jglick@0
   276
                        {
jglick@0
   277
                            //can't draw second create messsage or create message to self
jglick@0
   278
                            retVal=ConnectorState.REJECT;
jglick@0
   279
                        }
jglick@0
   280
                        else
jglick@0
   281
                        {
jglick@0
   282
                            //TODO how to check if there any messages which prevent creation, should it be as in previous release when any message block creation?
jglick@0
   283
                            Lifeline tmpE=(Lifeline) target.getFirstSubject();
jglick@0
   284
                            if(tmpE.getEvents().size()>1)retVal=ConnectorState.REJECT;//TBD, not perfect, need separate check if 1 event is destroy or receive of asycnh message
jglick@0
   285
                        }
jglick@0
   286
                    }
jglick@0
   287
                    else if(targetWidget instanceof Scene)
jglick@0
   288
                    {
jglick@0
   289
                        //all good
jglick@0
   290
                    }
jglick@0
   291
                    else
jglick@0
   292
                    {
jglick@0
   293
                        //default, for example can't create to combined fragment
jglick@0
   294
                        retVal=ConnectorState.REJECT;
jglick@0
   295
                    }
jglick@0
   296
                }
jglick@0
   297
                if(retVal==ConnectorState.ACCEPT)
jglick@0
   298
                {
jglick@0
   299
                    //checks existent position if still accept, case for lifeline-lifeline message
jglick@0
   300
                    if(source!=null)sourceWidget=scene.findWidget(source);
jglick@0
   301
                    if(target!=null)targetWidget=scene.findWidget(target);
jglick@0
   302
                    if(retVal==ConnectorState.ACCEPT && sourceWidget instanceof LifelineWidget && targetWidget instanceof LifelineWidget)
jglick@0
   303
                    {
jglick@0
   304
                        LifelineLineWidget sourceLine=((LifelineWidget)sourceWidget).getLine();
jglick@0
   305
                        LifelineLineWidget targetLine=((LifelineWidget)targetWidget).getLine();
jglick@0
   306
                        int y1=sourceLine.convertSceneToLocal(sourcePoint).y;//incoming corrdinates in LifelineWidget coordinates, we adds child to LifelineLineWidget
jglick@0
   307
                        int y2=targetLine.convertSceneToLocal(sourcePoint).y;//
jglick@0
   308
jglick@0
   309
                        ExecutionSpecificationThinWidget sourcePreexistentSpec=getExSpecification(sourceLine, y1);
jglick@0
   310
                        ExecutionSpecificationThinWidget targetPreexistentSpec=getExSpecification(targetLine, y2);
jglick@0
   311
                        ExSpecData sourcePair=null,targetPair=null;
jglick@0
   312
jglick@0
   313
                        if(sourcePreexistentSpec!=null)
jglick@0
   314
                        {
jglick@0
   315
                            int ys=sourcePreexistentSpec.convertSceneToLocal(sourcePoint).y;
jglick@0
   316
                            sourcePair=getWidgetsAroundPoint(sourcePreexistentSpec, ys);
jglick@0
   317
                        }
jglick@0
   318
                        if(targetPreexistentSpec!=null)
jglick@0
   319
                        {
jglick@0
   320
                            int yt=targetPreexistentSpec.convertSceneToLocal(sourcePoint).y;
jglick@0
   321
                            targetPair=getWidgetsAroundPoint(targetPreexistentSpec, yt);
jglick@0
   322
                        }
jglick@0
   323
                        //now filter out all unsupported cases (TBD do not check for them in creation later)
jglick@0
   324
jglick@0
   325
                    }
jglick@0
   326
                }
jglick@0
   327
            }
jglick@0
   328
        }
jglick@0
   329
       
jglick@0
   330
        return retVal;
jglick@0
   331
    }
jglick@0
   332
jglick@0
   333
    public boolean hasCustomTargetWidgetResolver(Scene scene)
jglick@0
   334
    {
jglick@0
   335
        return false;
jglick@0
   336
    }
jglick@0
   337
jglick@0
   338
    public Widget resolveTargetWidget(Scene scene, Point sceneLocation)
jglick@0
   339
    {
jglick@0
   340
        return null;
jglick@0
   341
    }
jglick@0
   342
    
jglick@0
   343
    
jglick@0
   344
    /**
jglick@0
   345
     * Method accept source/target widgets(Lifelines/Combined Fragments) and sraw message of kind specified during creation of connect provider
jglick@0
   346
     * If kind of message synchronous or result both links call and result are created
jglick@0
   347
     * if you need to adjust result message position after creation (point is used for call messages positioning) you have to adjust source and target related widgets positions for result
jglick@0
   348
     * @param sourceWidget from widget
jglick@0
   349
     * @param targetWidget to widget
jglick@0
   350
     * @param startingPoint starting point in scene coordinates
jglick@0
   351
     * @param finishPoint finish point in scene coordinated
jglick@0
   352
     * @return ArrayList with all created connectionwidgets
jglick@0
   353
     */
jglick@0
   354
    @SuppressWarnings(value = "unchecked")
jglick@0
   355
    public ArrayList<ConnectionWidget> createConnection(Widget sourceWidget, Widget targetWidget,Point startingPoint,Point finishPoint)
jglick@0
   356
    {
jglick@0
   357
        return handleCreateConnection(sourceWidget, targetWidget, startingPoint, finishPoint, null, null);
jglick@0
   358
    }
jglick@0
   359
    
jglick@0
   360
    public ArrayList<ConnectionWidget> createSynchConnection(Widget sourceWidget, Widget targetWidget, Point callStartingPoint, Point callFinishPoint, Point resultStartingPoint, Point resultFinishPoint) {
jglick@0
   361
        return handleCreateConnection(sourceWidget, targetWidget, callStartingPoint, callFinishPoint, resultStartingPoint, resultFinishPoint);
jglick@0
   362
    }
jglick@0
   363
    
jglick@0
   364
    private ArrayList<ConnectionWidget> handleCreateConnection(Widget sourceWidget, Widget targetWidget, Point callStartingPoint, Point callFinishPoint, Point resultStartingPoint, Point resultFinishPoint)
jglick@0
   365
    {
jglick@0
   366
         ArrayList ret=new ArrayList();
jglick@0
   367
        if((validator != null) && (sourceWidget.getScene() instanceof GraphScene))
jglick@0
   368
        {
jglick@0
   369
            GraphScene scene = (GraphScene)sourceWidget.getScene();
jglick@0
   370
            IPresentationElement sourceElement = getElement(sourceWidget);
jglick@0
   371
            IPresentationElement targetElement = getElement(targetWidget);
jglick@0
   372
            IElement sourceNE=sourceElement.getFirstSubject();
jglick@0
   373
            IElement targetNE=targetElement.getFirstSubject();
jglick@0
   374
jglick@0
   375
            IMessage call=null,result=null;
jglick@0
   376
            if(message!=null)//put existent model message to sqd
jglick@0
   377
            {
jglick@0
   378
                if(edgeKind==BaseElement.MK_RESULT)
jglick@0
   379
                {
jglick@0
   380
                    result=message;
jglick@0
   381
                    //find also call
jglick@0
   382
                    call=result.getSendingMessage();
jglick@0
   383
                    //TBD: verify if call was already created and throw smth?
jglick@0
   384
                }
jglick@0
   385
                else if (edgeKind==BaseElement.MK_SYNCHRONOUS)
jglick@0
   386
                {
jglick@0
   387
                    //throw new UnsupportedOperationException("draw of existent synch message is supported by use of result message only, do not use call message.");
jglick@0
   388
                    call=message;
jglick@0
   389
                    if(resultMessage!=null)
jglick@0
   390
                    {
jglick@0
   391
                        result=resultMessage;
jglick@0
   392
                    }
jglick@0
   393
                    else
jglick@0
   394
                    {
jglick@0
   395
                        IInteraction interaction=message.getInteraction();
jglick@0
   396
                        ETList<IMessage> messages=interaction.getMessages();
jglick@0
   397
                        //
jglick@0
   398
                        for(IMessage msg:messages)
jglick@0
   399
                        {
jglick@0
   400
                            if(msg==call)
jglick@0
   401
                            {
jglick@0
   402
                                //additional verification, find foirst call to be sure result goes after call
jglick@0
   403
                                result=call;
jglick@0
   404
                            }
jglick@0
   405
                            if(result==call)
jglick@0
   406
                            {
jglick@0
   407
                                //only if call found
jglick@0
   408
                                if(msg.getSendingMessage()==result)
jglick@0
   409
                                {
jglick@0
   410
                                    result=msg;
jglick@0
   411
                                    break;
jglick@0
   412
                                }
jglick@0
   413
                            }
jglick@0
   414
                        }
jglick@0
   415
                    }
jglick@0
   416
                    //verify result was found
jglick@0
   417
                    if(result==null || result==call)
jglick@0
   418
                    {
jglick@0
   419
                        throw new RuntimeException("Result message wasn't found within interaction after call message");
jglick@0
   420
                    }
jglick@0
   421
                }
jglick@0
   422
                else
jglick@0
   423
                {
jglick@0
   424
                    call=message;
jglick@0
   425
                }
jglick@0
   426
                //also if it's existent message it is expected to get starting and finishingPoint as message location, not starting/finishing osint for creation which need to take it may not be posible to bump all up and will create ex specification starting from posin
jglick@0
   427
                int fix=new MessagePinWidget(sourceWidget.getScene(), MessagePinWidget.PINKIND.ASYNCHRONOUS_CALL_OUT).getMarginBefore();
jglick@0
   428
                callStartingPoint.y-=fix;//all call messages starts with the same shift after "creation point"
jglick@0
   429
                callFinishPoint.y-=fix;
jglick@0
   430
            }
jglick@0
   431
            
jglick@0
   432
            if(getRelationshipFactory() != null || message!=null)
jglick@0
   433
            {
jglick@0
   434
                IElement rel = null;
jglick@0
   435
                if(message==null)rel=getRelationshipFactory().create(sourceElement.getFirstSubject(), 
jglick@0
   436
                                                                        targetElement.getFirstSubject());
jglick@0
   437
                if((getRelationshipFactory() instanceof MessageFactory) || message!=null)
jglick@0
   438
                {
jglick@0
   439
                    
jglick@0
   440
                    IPresentationElement msgPE1=null,msgPE2=null;
jglick@0
   441
                    MessageFactory mf=(MessageFactory) getRelationshipFactory();
jglick@0
   442
                    IMessage nextMessage=null;
jglick@0
   443
                    if(message==null)
jglick@0
   444
                    {
jglick@0
   445
                        //need to find next message if new one need to be created only
jglick@0
   446
                        IInteraction fromOwner=(IInteraction) OwnerRetriever.getOwnerByType(sourceNE,IInteraction.class);
jglick@0
   447
                        if(fromOwner==null && sourceNE instanceof IInteraction)fromOwner=(IInteraction) sourceNE;
jglick@0
   448
                        nextMessage=mf.getMessageNextToPoint(scene,fromOwner, callStartingPoint.y);
jglick@0
   449
                    }
jglick@0
   450
                    IMessage message1=call;
jglick@0
   451
                    if(mf!=null && message1==null)
jglick@0
   452
                    {
jglick@0
   453
                        message1=mf.createMessage(sourceNE,targetNE,edgeKind,nextMessage);
jglick@0
   454
                    }
jglick@0
   455
                    if(rel!=null)((IMessageConnector) rel).addMessage(message1);//TBD what for connector is created? if it possible to live without
jglick@0
   456
                    UMLEdgeWidget msgW1=null;
jglick@0
   457
                        msgPE1 = createPresentationElement(message1);
jglick@0
   458
                        msgW1=(UMLEdgeWidget) scene.addEdge(msgPE1);
jglick@0
   459
                        ret.add(msgW1);
jglick@0
   460
                        scene.setEdgeSource(msgPE1, sourceElement);
jglick@0
   461
                        scene.setEdgeTarget(msgPE1, targetElement);
jglick@0
   462
                    //
jglick@0
   463
                    if(edgeKind==BaseElement.MK_CREATE)
jglick@0
   464
                    {
jglick@0
   465
                        createCreateMessage(sourceWidget,(LifelineWidget)targetWidget,msgW1,callStartingPoint);
jglick@0
   466
                    }
jglick@0
   467
                    else
jglick@0
   468
                    {
jglick@0
   469
                        if(edgeKind==BaseElement.MK_SYNCHRONOUS)
jglick@0
   470
                        {
jglick@0
   471
                            //((IMessageConnector) rel)
jglick@0
   472
                            IMessage message2=null;
jglick@0
   473
                            UMLEdgeWidget msgW2=null;
jglick@0
   474
                            if(result==null)
jglick@0
   475
                            {
jglick@0
   476
                                //create only if new
jglick@0
   477
                                message2=mf.createMessage(targetNE,sourceNE,BaseElement.MK_RESULT,nextMessage);
jglick@0
   478
                                message2.setSendingMessage(message1);
jglick@0
   479
                                if(rel!=null)((IMessageConnector) rel).addMessage(message2);
jglick@0
   480
                            }
jglick@0
   481
                            else
jglick@0
   482
                            {
jglick@0
   483
                                message2=result;
jglick@0
   484
                            }
jglick@0
   485
                            msgPE2 = createPresentationElement(message2);
jglick@0
   486
                            //
jglick@0
   487
                            msgW2=(UMLEdgeWidget) scene.addEdge(msgPE2);
jglick@0
   488
                            ret.add(msgW2);
jglick@0
   489
                            scene.setEdgeSource(msgPE2, targetElement);
jglick@0
   490
                            scene.setEdgeTarget(msgPE2, sourceElement);
jglick@0
   491
                                     //
jglick@0
   492
                            createSynchMessage(sourceWidget,targetWidget,msgW1,msgW2,callStartingPoint,callFinishPoint,resultStartingPoint,resultFinishPoint);
jglick@0
   493
                        }
jglick@0
   494
                        else if(edgeKind==BaseElement.MK_RESULT && message!=null)
jglick@0
   495
                        {
jglick@0
   496
                            //separate creation of result link is supported for existent messages only
jglick@0
   497
                            IMessage message2=result;
jglick@0
   498
                            msgPE2 = createPresentationElement(message2);
jglick@0
   499
                            UMLEdgeWidget msgW2=(UMLEdgeWidget) scene.addEdge(msgPE2);
jglick@0
   500
                            ret.add(msgW2);
jglick@0
   501
                            scene.setEdgeSource(msgPE2, targetElement);
jglick@0
   502
                            scene.setEdgeTarget(msgPE2, sourceElement);
jglick@0
   503
                            createSynchMessage(targetWidget,sourceWidget,msgW1,msgW2,callStartingPoint,callFinishPoint,resultStartingPoint,resultFinishPoint);
jglick@0
   504
                       }
jglick@0
   505
                        else if(edgeKind==BaseElement.MK_ASYNCHRONOUS)
jglick@0
   506
                        {
jglick@0
   507
                             createASynchMessage(sourceWidget,targetWidget,msgW1,callStartingPoint,callFinishPoint);
jglick@0
   508
                        }
jglick@0
   509
                    }
jglick@0
   510
                }
jglick@0
   511
           }
jglick@0
   512
        }
jglick@0
   513
        return ret;       
jglick@0
   514
    }
jglick@0
   515
jglick@0
   516
    public boolean hasTargetWidgetCreator()
jglick@0
   517
    {
jglick@0
   518
        boolean retVal = false;
jglick@0
   519
        
jglick@0
   520
        if((defaultTargetType != null) && (defaultTargetType.length() > 0))
jglick@0
   521
        {
jglick@0
   522
            retVal = true;
jglick@0
   523
        }
jglick@0
   524
        return retVal;
jglick@0
   525
    }
jglick@0
   526
jglick@0
   527
    /**
jglick@0
   528
     * Create a new node widget to be used as the target widget for the connector.
jglick@0
   529
     * This provider expects the scene to be a graph scene.
jglick@0
   530
     * 
jglick@0
   531
     * @param targetScene The scene that will contain the node.  The scene must be a
jglick@0
   532
     *                    GraphScene.
jglick@0
   533
     * @return The new node that was created.
jglick@0
   534
     */
jglick@0
   535
    @SuppressWarnings("unchecked")
jglick@0
   536
    public Widget createTargetWidget(Scene targetScene, Point sourcePoint)
jglick@0
   537
    {
jglick@0
   538
        Widget retVal = null;
jglick@0
   539
        
jglick@0
   540
        if(targetScene instanceof DesignerScene)
jglick@0
   541
        {
jglick@0
   542
            DesignerScene scene = (DesignerScene)targetScene;
jglick@0
   543
            Object value = FactoryRetriever.instance().createType(defaultTargetType, 
jglick@0
   544
                                                                   null);
jglick@0
   545
jglick@0
   546
            if(value instanceof Lifeline)
jglick@0
   547
            {
jglick@0
   548
                Lifeline namedElement = (Lifeline)value;
jglick@0
   549
                IPresentationElement element = createPresentationElement(namedElement);
jglick@0
   550
                element.addSubject(namedElement);
jglick@0
   551
                //retVal = scene.addNode(element);
jglick@0
   552
                retVal = (scene).getEngine().addWidget(element, sourcePoint);
jglick@0
   553
                IDiagram diagram = scene.getDiagram();
jglick@0
   554
                if(diagram != null)
jglick@0
   555
                {
jglick@0
   556
                    INamespace space = diagram.getNamespaceForCreatedElements();
jglick@0
   557
                    space.addOwnedElement(namedElement);
jglick@0
   558
                }
jglick@0
   559
            }
jglick@0
   560
        }
jglick@0
   561
        
jglick@0
   562
        return retVal;
jglick@0
   563
    }
jglick@0
   564
jglick@0
   565
    public RelationshipFactory getRelationshipFactory()
jglick@0
   566
    {
jglick@0
   567
        return factory;
jglick@0
   568
    }
jglick@0
   569
jglick@0
   570
    public void setRelationshipFactory(RelationshipFactory factory)
jglick@0
   571
    {
jglick@0
   572
        this.factory = factory;
jglick@0
   573
    }
jglick@0
   574
jglick@0
   575
jglick@0
   576
    
jglick@0
   577
    private IPresentationElement createPresentationElement(INamedElement element)
jglick@0
   578
    {
jglick@0
   579
        IPresentationElement retVal = null;
jglick@0
   580
        
jglick@0
   581
        ICreationFactory creationFactory = FactoryRetriever.instance().getCreationFactory();
jglick@0
   582
        if(creationFactory != null)
jglick@0
   583
        {
jglick@0
   584
           Object presentationObj = creationFactory.retrieveMetaType("NodePresentation", null);
jglick@0
   585
           if (presentationObj instanceof IPresentationElement)
jglick@0
   586
           {
jglick@0
   587
                  retVal = (IPresentationElement)presentationObj;   
jglick@0
   588
                  element.addPresentationElement(retVal);
jglick@0
   589
           }
jglick@0
   590
        }
jglick@0
   591
        
jglick@0
   592
        return retVal;
jglick@0
   593
    }
jglick@0
   594
    
jglick@0
   595
    private IPresentationElement getElement(Widget widget)
jglick@0
   596
    {
jglick@0
   597
        IPresentationElement retVal = null;
jglick@0
   598
        
jglick@0
   599
        Scene widgetScene = widget.getScene();
jglick@0
   600
        if (widgetScene instanceof ObjectScene)
jglick@0
   601
        {
jglick@0
   602
            ObjectScene objScene = (ObjectScene)widgetScene;
jglick@0
   603
            Object value = objScene.findObject(widget);
jglick@0
   604
            if (value instanceof IPresentationElement)
jglick@0
   605
            {
jglick@0
   606
                retVal = (IPresentationElement)value;
jglick@0
   607
            }
jglick@0
   608
        }
jglick@0
   609
        
jglick@0
   610
        return retVal;
jglick@0
   611
    }
jglick@0
   612
    
jglick@0
   613
    private IPresentationElement createPresentationElement(IRelationship element)
jglick@0
   614
    {
jglick@0
   615
        IPresentationElement retVal = null;
jglick@0
   616
        
jglick@0
   617
        ICreationFactory creationFactory = FactoryRetriever.instance().getCreationFactory();
jglick@0
   618
        if(creationFactory != null)
jglick@0
   619
        {
jglick@0
   620
           Object presentationObj = creationFactory.retrieveMetaType("NodePresentation", null);
jglick@0
   621
           if (presentationObj instanceof IPresentationElement)
jglick@0
   622
           {
jglick@0
   623
                  retVal = (IPresentationElement)presentationObj;    
jglick@0
   624
                  element.addPresentationElement(retVal);
jglick@0
   625
           }
jglick@0
   626
        }
jglick@0
   627
        
jglick@0
   628
        return retVal;
jglick@0
   629
    }
jglick@0
   630
jglick@0
   631
    
jglick@0
   632
    /**
jglick@0
   633
     * TBD, should it be separated for different cases to simplify logic
jglick@0
   634
     * @param source
jglick@0
   635
     * @param target
jglick@0
   636
     * @param call
jglick@0
   637
     * @param result
jglick@0
   638
     * @param y
jglick@0
   639
     * @return success state
jglick@0
   640
     */
jglick@0
   641
    private boolean createSynchMessage(Widget source, Widget target,UMLEdgeWidget call,UMLEdgeWidget result,Point startingPoint,Point finishPoint,Point resultStartingPoint,Point resultFinishPoint) {
jglick@0
   642
            LifelineWidget sourceLifeline=null,targetLifeline=null;
jglick@0
   643
            CombinedFragmentWidget sourceCF=null,targetCF=null;
jglick@0
   644
            if(source instanceof LifelineWidget)sourceLifeline=(LifelineWidget) source;
jglick@0
   645
            else sourceCF=(CombinedFragmentWidget) source;//do not check type here because any other type is unexpected
jglick@0
   646
            if(target instanceof LifelineWidget)targetLifeline=(LifelineWidget) target;
jglick@0
   647
            else targetCF=(CombinedFragmentWidget) target;//do not check type here because any other type is unexpected
jglick@0
   648
        
jglick@0
   649
            LifelineLineWidget sourceLine=null;
jglick@0
   650
            if(sourceLifeline!=null)sourceLine=sourceLifeline.getLine();
jglick@0
   651
            LifelineLineWidget targetLine=null;
jglick@0
   652
            if(targetLifeline!=null)targetLine=targetLifeline.getLine();
jglick@0
   653
            //
jglick@0
   654
            Point scenePoint=startingPoint;
jglick@0
   655
            int y1=0;
jglick@0
   656
            if(sourceLine!=null)y1=convertSceneToLocal(sourceLine,scenePoint).y;//incoming corrdinates in LifelineWidget coordinates, we adds child to LifelineLineWidget
jglick@0
   657
            else y1=sourceCF.getMainWidget().convertSceneToLocal(scenePoint).y;
jglick@0
   658
            int y2=0;
jglick@0
   659
            if(targetLine!=null)y2=convertSceneToLocal(targetLine,scenePoint).y;//
jglick@0
   660
            else y2=targetCF.getMainWidget().convertSceneToLocal(scenePoint).y;
jglick@0
   661
            
jglick@0
   662
            GraphScene scene=(GraphScene) source.getScene();
jglick@0
   663
           
jglick@0
   664
            ExecutionSpecificationThinWidget sourcePreexistentSpec=getExSpecification(sourceLine, y1);
jglick@0
   665
            ExSpecData sourcePair=null,targetPair=null;
jglick@0
   666
            //
jglick@0
   667
               boolean sourceNested=sourcePreexistentSpec!=null;
jglick@0
   668
            if(sourceNested)
jglick@0
   669
            {
jglick@0
   670
                int ys=convertSceneToLocal(sourcePreexistentSpec,scenePoint).y;
jglick@0
   671
                sourcePair=getWidgetsAroundPoint(sourcePreexistentSpec, ys);
jglick@0
   672
                //correction if got position inside top margine
jglick@0
   673
                if(sourcePair.getPrevWidget()==null)
jglick@0
   674
                {
jglick@0
   675
                    scenePoint.y+=10;
jglick@0
   676
                    y2+=10;
jglick@0
   677
                    sourcePair=getWidgetsAroundPoint(sourcePreexistentSpec, ys+10);
jglick@0
   678
                }
jglick@0
   679
                //
jglick@0
   680
                y1=convertSceneToLocal(sourcePreexistentSpec,scenePoint).y;
jglick@0
   681
            }
jglick@0
   682
            ExecutionSpecificationThinWidget targetPreexistentSpec=getExSpecification(targetLine, y2+new MessagePinWidget(scene, MessagePinWidget.PINKIND.SYNCHRONOUS_CALL_OUT).getMarginBefore()-new MessagePinWidget(scene, MessagePinWidget.PINKIND.SYNCHRONOUS_CALL_IN).getMarginBefore());//usually it mean shift for 10 px because target do not have margin before);
jglick@0
   683
            boolean targetNested=targetPreexistentSpec!=null;
jglick@0
   684
            if(targetNested)
jglick@0
   685
            {
jglick@0
   686
                int yt=convertSceneToLocal(targetPreexistentSpec,scenePoint).y+new MessagePinWidget(scene, MessagePinWidget.PINKIND.SYNCHRONOUS_CALL_OUT).getMarginBefore()-new MessagePinWidget(scene, MessagePinWidget.PINKIND.SYNCHRONOUS_CALL_IN).getMarginBefore();//usually it mean shift for 10 px because target do not have margin before
jglick@0
   687
                targetPair=getWidgetsAroundPoint(targetPreexistentSpec, yt);
jglick@0
   688
                //correction if got position inside top margine
jglick@0
   689
                if(targetPair.getPrevWidget()==null)
jglick@0
   690
                {
jglick@0
   691
                    scenePoint.y+=10;
jglick@0
   692
                    y1+=10;
jglick@0
   693
                    targetPair=getWidgetsAroundPoint(targetPreexistentSpec, yt+10);
jglick@0
   694
                }
jglick@0
   695
                y2=convertSceneToLocal(targetPreexistentSpec,scenePoint).y;
jglick@0
   696
            }
jglick@0
   697
            
jglick@0
   698
            //
jglick@0
   699
            ExecutionSpecificationThinWidget sourceExWidget=null,targetExWidget=null;
jglick@0
   700
            MessagePinWidget sourceCallPin=null;
jglick@0
   701
            MessagePinWidget targetCallPin=null;
jglick@0
   702
                sourceCallPin=new MessagePinWidget(scene,MessagePinWidget.PINKIND.SYNCHRONOUS_CALL_OUT);
jglick@0
   703
                targetCallPin=new MessagePinWidget(scene,MessagePinWidget.PINKIND.SYNCHRONOUS_CALL_IN);
jglick@0
   704
            MessagePinWidget sourceReturnPin=null;new MessagePinWidget(scene,MessagePinWidget.PINKIND.SYNCHRONOUS_RETURN_OUT);
jglick@0
   705
            MessagePinWidget targetReturnPin=null;new MessagePinWidget(scene,MessagePinWidget.PINKIND.SYNCHRONOUS_RETURN_IN);
jglick@0
   706
                sourceReturnPin=new MessagePinWidget(scene,MessagePinWidget.PINKIND.SYNCHRONOUS_RETURN_OUT);
jglick@0
   707
                targetReturnPin=new MessagePinWidget(scene,MessagePinWidget.PINKIND.SYNCHRONOUS_RETURN_IN);
jglick@0
   708
                
jglick@0
   709
            
jglick@0
   710
                handleFreeSpaceExpantion(scenePoint,source,sourceCallPin.getKind(),targetLine==sourceLine && sourceLine!=null,sourcePreexistentSpec,sourcePair);
jglick@0
   711
                scene.validate();
jglick@0
   712
                handleFreeSpaceExpantion(scenePoint,target,targetCallPin.getKind(),targetLine==sourceLine && sourceLine!=null,targetPreexistentSpec,targetPair);
jglick@0
   713
                scene.validate();
jglick@0
   714
            
jglick@0
   715
            if(sourceLine==null)//combined fragment case
jglick@0
   716
            {
jglick@0
   717
                call.setSourceAnchor(AnchorFactory.createCenterAnchor(sourceCallPin));
jglick@0
   718
                result.setTargetAnchor(AnchorFactory.createCenterAnchor(targetReturnPin));
jglick@0
   719
            }
jglick@0
   720
            else if(!sourceNested)//from clear line
jglick@0
   721
            {
jglick@0
   722
                sourceExWidget=new ExecutionSpecificationThinWidget(scene);
jglick@0
   723
                sourceExWidget.setPreferredLocation(new Point(0,0));
jglick@0
   724
                sourceCallPin.setPreferredLocation(new Point(0,y1+sourceCallPin.getMarginBefore()));
jglick@0
   725
                targetReturnPin.setPreferredLocation(new Point(0,y1+sourceCallPin.getMarginBefore()+30));
jglick@0
   726
                call.setSourceAnchor(AnchorFactory.createCircularAnchor(sourceCallPin,sourceExWidget.width/2));
jglick@0
   727
                result.setTargetAnchor(AnchorFactory.createCircularAnchor(targetReturnPin,sourceExWidget.width/2));
jglick@0
   728
            }
jglick@0
   729
            else// from within existed spec
jglick@0
   730
            {
jglick@0
   731
                //from existent use existent execution specification
jglick@0
   732
                sourceCallPin.setPreferredLocation(new Point(0,y1+sourceCallPin.getMarginBefore()));
jglick@0
   733
                targetReturnPin.setPreferredLocation(new Point(0,y1+sourceCallPin.getMarginBefore()+30));
jglick@0
   734
                call.setSourceAnchor(AnchorFactory.createCircularAnchor(sourceCallPin,sourcePreexistentSpec.width/2));
jglick@0
   735
                result.setTargetAnchor(AnchorFactory.createCircularAnchor(targetReturnPin,sourcePreexistentSpec.width/2));
jglick@0
   736
            }
jglick@0
   737
            
jglick@0
   738
            if(targetLine==null)//combined fragment
jglick@0
   739
            {
jglick@0
   740
                result.setSourceAnchor(AnchorFactory.createCenterAnchor(sourceReturnPin));
jglick@0
   741
                call.setTargetAnchor(AnchorFactory.createCenterAnchor(targetCallPin));
jglick@0
   742
            }
jglick@0
   743
            else if(!targetNested)//to clear line
jglick@0
   744
            {
jglick@0
   745
                targetExWidget=new ExecutionSpecificationThinWidget(scene);
jglick@0
   746
                targetExWidget.setPreferredLocation(new Point(0,0));//y2+10));
jglick@0
   747
                targetCallPin.setPreferredLocation(new Point(0,y2+sourceCallPin.getMarginBefore()));
jglick@0
   748
                //return message/hardcoded position for now
jglick@0
   749
                sourceReturnPin.setPreferredLocation(new Point(0,y2+sourceCallPin.getMarginBefore()+30));
jglick@0
   750
                result.setSourceAnchor(AnchorFactory.createCircularAnchor(sourceReturnPin,targetExWidget.width/2));
jglick@0
   751
                call.setTargetAnchor(AnchorFactory.createCircularAnchor(targetCallPin,targetExWidget.width/2));
jglick@0
   752
            }
jglick@0
   753
            else//to existend specification
jglick@0
   754
            {
jglick@0
   755
                //to existent need to create target execution specification
jglick@0
   756
                targetExWidget=new ExecutionSpecificationThinWidget(scene);
jglick@0
   757
                targetExWidget.setPreferredLocation(new Point(0,0));//y2+10));
jglick@0
   758
                targetCallPin.setPreferredLocation(new Point(0,y2+sourceCallPin.getMarginBefore()));
jglick@0
   759
                //return message/hardcoded position for now
jglick@0
   760
                sourceReturnPin.setPreferredLocation(new Point(0,y2+sourceCallPin.getMarginBefore()+30));
jglick@0
   761
                result.setSourceAnchor(AnchorFactory.createCircularAnchor(sourceReturnPin,targetExWidget.width/2));
jglick@0
   762
                call.setTargetAnchor(AnchorFactory.createCircularAnchor(targetCallPin,targetExWidget.width/2));
jglick@0
   763
            }
jglick@0
   764
            
jglick@0
   765
            //actions
jglick@0
   766
            //seems reasonable to remove control button after drawing
jglick@0
   767
            //add actions to execution specifications
jglick@0
   768
            //if(sourceExWidget!=null)sourceExWidget.createActions(DesignerTools.SELECT).addAction(ActionFactory.createMoveAction(new ThinExecutionSpecificationMoveStrategy(),new ThinExecutionSpecificationMoveProvider()));
jglick@0
   769
            //if(targetExWidget!=null)targetExWidget.createActions(DesignerTools.SELECT).addAction(ActionFactory.createMoveAction(new ThinExecutionSpecificationMoveStrategy(),new ThinExecutionSpecificationMoveProvider()));
jglick@0
   770
            //--
jglick@0
   771
            //revalidate with
jglick@0
   772
            if(sourceNested)
jglick@0
   773
            {
jglick@0
   774
                Widget prevW=sourcePair.getPrevWidget();
jglick@0
   775
                int index=sourcePreexistentSpec.getChildren().indexOf(prevW);
jglick@0
   776
                sourcePreexistentSpec.addChild(index+1,sourceCallPin);
jglick@0
   777
                sourcePreexistentSpec.addChild(index+2,targetReturnPin);
jglick@0
   778
            }
jglick@0
   779
            else if(sourceLine!=null)
jglick@0
   780
            {
jglick@0
   781
                sourceExWidget.addChild(sourceCallPin);//this is new pins, so no need to find indexes
jglick@0
   782
                sourceExWidget.addChild(targetReturnPin);
jglick@0
   783
                //but need to find index for execution specifictions
jglick@0
   784
                //usual development from top to bottom, so start from bottom, later half way may b implemented for search
jglick@0
   785
                int index=findPrevPinOrESpecIndex(sourceLine, y1);
jglick@0
   786
                //if(index>=(sourceLine.getChildren().size()-1))sourceLine.addChild(sourceExWidget);
jglick@0
   787
                //else
jglick@0
   788
                {
jglick@0
   789
                    sourceLine.addChild(index+1,sourceExWidget);
jglick@0
   790
                }
jglick@0
   791
            }
jglick@0
   792
            else
jglick@0
   793
            {
jglick@0
   794
                //from combinedfragment, do not order for now (at least before implementation of separate containers for left and right messages)
jglick@0
   795
                Point start=sourceCF.getMainWidget().convertSceneToLocal(scenePoint);
jglick@0
   796
                start.x=(start.x<(sourceCF.getMainWidget().getBounds().x+sourceCF.getMainWidget().getBounds().width/2)) ? (0) : (sourceCF.getMainWidget().getBounds().width);
jglick@0
   797
                sourceCallPin.setPreferredLocation(new Point(start.x,start.y+10));
jglick@0
   798
                targetReturnPin.setPreferredLocation(new Point(start.x,start.y+40));//TBD, hardcoded
jglick@0
   799
                sourceCF.getMainWidget().addChild(sourceCallPin);
jglick@0
   800
                sourceCF.getMainWidget().addChild(targetReturnPin);
jglick@0
   801
            }
jglick@0
   802
            //
jglick@0
   803
            if(targetLine==sourceLine && sourceLine!=null)
jglick@0
   804
            {
jglick@0
   805
                //message to self
jglick@0
   806
                 if(sourceNested)
jglick@0
   807
                {
jglick@0
   808
                   //sourceCallPin is before target ex spec
jglick@0
   809
                    int index=sourcePreexistentSpec.getChildren().indexOf(sourceCallPin);
jglick@0
   810
                    sourcePreexistentSpec.addChild(index+1,targetExWidget);
jglick@0
   811
                }
jglick@0
   812
                else
jglick@0
   813
                {
jglick@0
   814
                    //source is new and before only call pin-> index=1
jglick@0
   815
                    sourceExWidget.addChild(1, targetExWidget);
jglick@0
   816
                }
jglick@0
   817
                targetExWidget.setPreferredLocation(new Point(7,0));
jglick@0
   818
                targetCallPin.setPreferredLocation(new Point(0,y2+20));
jglick@0
   819
                targetReturnPin.setPreferredLocation(new Point(0,y1+80));
jglick@0
   820
                sourceReturnPin.setPreferredLocation(new Point(0,y2+70));
jglick@0
   821
                //target spec for message to self isalways new, so no need to find index, but need to add in proper order
jglick@0
   822
                targetExWidget.addChild(targetCallPin);
jglick@0
   823
                targetExWidget.addChild(sourceReturnPin);
jglick@0
   824
                //
jglick@0
   825
                call.setRouter(new SelfMessageRouter());
jglick@0
   826
                result.setRouter(new SelfMessageRouter());
jglick@0
   827
            }
jglick@0
   828
            else if(targetNested)
jglick@0
   829
            {
jglick@0
   830
                //no need to find indexes for pins, becaise new ex spec is crea6ted, keep order
jglick@0
   831
                targetExWidget.addChild(targetCallPin);
jglick@0
   832
                targetExWidget.addChild(sourceReturnPin);
jglick@0
   833
                //for ex spec need to find index
jglick@0
   834
                int index=targetPreexistentSpec.getChildren().indexOf(targetPair.getPrevWidget());
jglick@0
   835
                targetPreexistentSpec.addChild(index+1, targetExWidget);
jglick@0
   836
            }
jglick@0
   837
            else if(targetLine!=null)
jglick@0
   838
            {
jglick@0
   839
                //no need to find indexes for pins, becaise new ex spec is crea6ted, keep order
jglick@0
   840
                targetExWidget.addChild(targetCallPin);
jglick@0
   841
                targetExWidget.addChild(sourceReturnPin);
jglick@0
   842
                //need to find prev on target line
jglick@0
   843
                int index=findPrevPinOrESpecIndex(targetLine, y2+sourceCallPin.getMarginBefore()-targetCallPin.getMarginBefore());
jglick@0
   844
                targetLine.addChild(index+1,targetExWidget);
jglick@0
   845
            }
jglick@0
   846
            else
jglick@0
   847
            {
jglick@0
   848
                //to combined fragment
jglick@0
   849
                targetCF.getMainWidget().addChild(targetCallPin);
jglick@0
   850
                targetCF.getMainWidget().addChild(sourceReturnPin);
jglick@0
   851
                Point finish=convertSceneToLocal(targetCF.getMainWidget(),finishPoint);
jglick@0
   852
                Point start=targetCF.getMainWidget().convertSceneToLocal(scenePoint);
jglick@0
   853
                finish.x=(finish.x<targetCF.getMainWidget().getBounds().width/2) ? (0) : (targetCF.getMainWidget().getBounds().width);
jglick@0
   854
                targetCallPin.setPreferredLocation(new Point(finish.x,start.y+sourceCallPin.getMarginBefore()));//margin shift is get from source pin, the same as y position from staring point
jglick@0
   855
                sourceReturnPin.setPreferredLocation(new Point(finish.x,start.y+sourceCallPin.getMarginBefore()+30));//TBD, hardcoded 40
jglick@0
   856
            }
jglick@0
   857
            //if result points are specified correct calculated points to specified
jglick@0
   858
            if(resultFinishPoint!=null)
jglick@0
   859
            {
jglick@0
   860
                Point toSet=convertSceneToLocal(targetReturnPin.getParentWidget(),resultFinishPoint);
jglick@0
   861
                //specified point shuld affect only y position, x should be the same as derived from call locations,
jglick@0
   862
                //so we don't use x
jglick@0
   863
                //from parameter.
jglick@0
   864
                toSet.x=targetReturnPin.getPreferredLocation().x;
jglick@0
   865
                targetReturnPin.setPreferredLocation(toSet);
jglick@0
   866
            }
jglick@0
   867
            if(resultStartingPoint!=null)
jglick@0
   868
            {
jglick@0
   869
                Point toSet=convertSceneToLocal(sourceReturnPin.getParentWidget(),resultStartingPoint);
jglick@0
   870
                //specified point shuld affect only y position, x should be the same as derived from call locations,
jglick@0
   871
                //so we don't use x
jglick@0
   872
                //from parameter.
jglick@0
   873
                toSet.x=sourceReturnPin.getPreferredLocation().x;
jglick@0
   874
                sourceReturnPin.setPreferredLocation(toSet);
jglick@0
   875
            }
jglick@0
   876
            return true;
jglick@0
   877
    }
jglick@0
   878
    //TBD check if all methods can be easily replaced with one
jglick@0
   879
    private void createASynchMessage(Widget source, Widget target, UMLEdgeWidget call,Point startingPoint,Point finishPoint) {
jglick@0
   880
            LifelineWidget sourceLifeline=null,targetLifeline=null;
jglick@0
   881
            CombinedFragmentWidget sourceCF=null,targetCF=null;
jglick@0
   882
            if(source instanceof LifelineWidget)sourceLifeline=(LifelineWidget) source;
jglick@0
   883
            else sourceCF=(CombinedFragmentWidget) source;//do not check type here because any other type is unexpected
jglick@0
   884
            if(target instanceof LifelineWidget)targetLifeline=(LifelineWidget) target;
jglick@0
   885
            else targetCF=(CombinedFragmentWidget) target;//do not check type here because any other type is unexpected
jglick@0
   886
        
jglick@0
   887
            LifelineLineWidget sourceLine=null;
jglick@0
   888
            if(sourceLifeline!=null)sourceLine=sourceLifeline.getLine();
jglick@0
   889
            LifelineLineWidget targetLine=null;
jglick@0
   890
            if(targetLifeline!=null)targetLine=targetLifeline.getLine();
jglick@0
   891
            Point scenePoint=startingPoint;
jglick@0
   892
            int y1=0;
jglick@0
   893
            if(sourceLine!=null)y1=convertSceneToLocal(sourceLine,scenePoint).y;//incoming corrdinates in LifelineWidget coordinates, we adds child to LifelineLineWidget
jglick@0
   894
            else y1=sourceCF.getMainWidget().convertSceneToLocal(scenePoint).y;
jglick@0
   895
            int y2=0;
jglick@0
   896
            if(targetLine!=null)y2=convertSceneToLocal(targetLine,scenePoint).y;
jglick@0
   897
            else y2=targetCF.getMainWidget().convertSceneToLocal(scenePoint).y;
jglick@0
   898
            
jglick@0
   899
            GraphScene scene=(GraphScene) source.getScene();
jglick@0
   900
            ExecutionSpecificationThinWidget sourcePreexistentSpec=getExSpecification(sourceLine, y1);
jglick@0
   901
            ExSpecData sourcePair=null,targetPair=null;
jglick@0
   902
            
jglick@0
   903
            
jglick@0
   904
            boolean sourceNested=sourcePreexistentSpec!=null;
jglick@0
   905
            if(sourceNested)
jglick@0
   906
            {
jglick@0
   907
                int ys=convertSceneToLocal(sourcePreexistentSpec,scenePoint).y;
jglick@0
   908
                sourcePair=getWidgetsAroundPoint(sourcePreexistentSpec, ys);
jglick@0
   909
                //correction if got position inside top margine
jglick@0
   910
                if(sourcePair.getPrevWidget()==null)
jglick@0
   911
                {
jglick@0
   912
                    scenePoint.y+=10;
jglick@0
   913
                    y2+=10;
jglick@0
   914
                    sourcePair=getWidgetsAroundPoint(sourcePreexistentSpec, ys+10);
jglick@0
   915
                }
jglick@0
   916
                //
jglick@0
   917
                y1=convertSceneToLocal(sourcePreexistentSpec,scenePoint).y;
jglick@0
   918
            }
jglick@0
   919
            ExecutionSpecificationThinWidget targetPreexistentSpec=getExSpecification(targetLine, y2+new MessagePinWidget(scene, MessagePinWidget.PINKIND.ASYNCHRONOUS_CALL_OUT).getMarginBefore()-new MessagePinWidget(scene, MessagePinWidget.PINKIND.ASYNCHRONOUS_CALL_IN).getMarginBefore());
jglick@0
   920
            boolean targetNested=targetPreexistentSpec!=null;
jglick@0
   921
            if(targetNested)
jglick@0
   922
            {
jglick@0
   923
                int yt=convertSceneToLocal(targetPreexistentSpec,scenePoint).y+new MessagePinWidget(scene, MessagePinWidget.PINKIND.ASYNCHRONOUS_CALL_OUT).getMarginBefore()-new MessagePinWidget(scene, MessagePinWidget.PINKIND.ASYNCHRONOUS_CALL_IN).getMarginBefore();
jglick@0
   924
                targetPair=getWidgetsAroundPoint(targetPreexistentSpec, yt);
jglick@0
   925
                //correction if got position inside top margine
jglick@0
   926
                if(targetPair.getPrevWidget()==null)
jglick@0
   927
                {
jglick@0
   928
                    scenePoint.y+=10;
jglick@0
   929
                    y1+=10;
jglick@0
   930
                    targetPair=getWidgetsAroundPoint(targetPreexistentSpec, yt+10);
jglick@0
   931
                }
jglick@0
   932
                y2=convertSceneToLocal(targetPreexistentSpec,scenePoint).y;
jglick@0
   933
            }
jglick@0
   934
jglick@0
   935
            
jglick@0
   936
            ExecutionSpecificationThinWidget sourceExWidget=null,targetExWidget=null;
jglick@0
   937
            MessagePinWidget sourceCallPin=new MessagePinWidget(scene,MessagePinWidget.PINKIND.ASYNCHRONOUS_CALL_OUT);
jglick@0
   938
            MessagePinWidget targetCallPin=new MessagePinWidget(scene,MessagePinWidget.PINKIND.ASYNCHRONOUS_CALL_IN);
jglick@0
   939
jglick@0
   940
            handleFreeSpaceExpantion(scenePoint,source,sourceCallPin.getKind(),targetLine==sourceLine && sourceLine!=null,sourcePreexistentSpec,sourcePair);
jglick@0
   941
            handleFreeSpaceExpantion(scenePoint,target,targetCallPin.getKind(),targetLine==sourceLine && sourceLine!=null,targetPreexistentSpec,targetPair);
jglick@0
   942
            //
jglick@0
   943
            if(sourceLine==null)//combined fragment
jglick@0
   944
            {
jglick@0
   945
                call.setSourceAnchor(AnchorFactory.createCenterAnchor(sourceCallPin));
jglick@0
   946
            }
jglick@0
   947
            else if(!sourceNested)//clear source
jglick@0
   948
            {
jglick@0
   949
                sourceExWidget=new ExecutionSpecificationThinWidget(scene);
jglick@0
   950
                sourceExWidget.setPreferredLocation(new Point(0,0));
jglick@0
   951
                sourceCallPin.setPreferredLocation(new Point(0,y1+sourceCallPin.getMarginBefore()));
jglick@0
   952
                call.setSourceAnchor(AnchorFactory.createCircularAnchor(sourceCallPin,sourceExWidget.width/2));
jglick@0
   953
            }
jglick@0
   954
            else//from existent ex specification
jglick@0
   955
            {
jglick@0
   956
                //from existent use existent execution specification
jglick@0
   957
                sourceCallPin.setPreferredLocation(new Point(0,y1+sourceCallPin.getMarginBefore()));
jglick@0
   958
                call.setSourceAnchor(AnchorFactory.createCircularAnchor(sourceCallPin,sourcePreexistentSpec.width/2));
jglick@0
   959
            }
jglick@0
   960
            
jglick@0
   961
            if(targetLine==null)
jglick@0
   962
            {
jglick@0
   963
                call.setTargetAnchor(AnchorFactory.createCenterAnchor(targetCallPin));
jglick@0
   964
            }
jglick@0
   965
            else if(!targetNested)
jglick@0
   966
            {
jglick@0
   967
                targetExWidget=new ExecutionSpecificationThinWidget(scene);
jglick@0
   968
                targetExWidget.setPreferredLocation(new Point(0,0));
jglick@0
   969
                targetCallPin.setPreferredLocation(new Point(0,y2+sourceCallPin.getMarginBefore()));
jglick@0
   970
                call.setTargetAnchor(AnchorFactory.createCircularAnchor(targetCallPin,targetExWidget.width/2));
jglick@0
   971
            }
jglick@0
   972
            else
jglick@0
   973
            {
jglick@0
   974
                //to existent need to create target execution specification
jglick@0
   975
                targetExWidget=new ExecutionSpecificationThinWidget(scene);
jglick@0
   976
                targetExWidget.setPreferredLocation(new Point(0,0));
jglick@0
   977
                targetCallPin.setPreferredLocation(new Point(0,y2+sourceCallPin.getMarginBefore()));
jglick@0
   978
                //return message/hardcoded position for now
jglick@0
   979
                call.setTargetAnchor(AnchorFactory.createCircularAnchor(targetCallPin,targetExWidget.width/2));
jglick@0
   980
            }
jglick@0
   981
jglick@0
   982
            //actions
jglick@0
   983
            //seems reasonable to remove control button after drawing
jglick@0
   984
            //add actions to execution specifications
jglick@0
   985
            //if(sourceExWidget!=null)sourceExWidget.createActions(DesignerTools.SELECT).addAction(ActionFactory.createMoveAction(new ThinExecutionSpecificationMoveStrategy(),new ThinExecutionSpecificationMoveProvider()));
jglick@0
   986
            //if(targetExWidget!=null)targetExWidget.createActions(DesignerTools.SELECT).addAction(ActionFactory.createMoveAction(new ThinExecutionSpecificationMoveStrategy(),new ThinExecutionSpecificationMoveProvider()));
jglick@0
   987
            //--
jglick@0
   988
            //revalidate with
jglick@0
   989
            if(sourceNested)
jglick@0
   990
            {
jglick@0
   991
                Widget prevW=sourcePair.getPrevWidget();
jglick@0
   992
                int index=sourcePreexistentSpec.getChildren().indexOf(prevW);
jglick@0
   993
                sourcePreexistentSpec.addChild(index+1,sourceCallPin);
jglick@0
   994
            }
jglick@0
   995
            else if(sourceLine!=null)
jglick@0
   996
            {
jglick@0
   997
                sourceExWidget.addChild(sourceCallPin);//this is new ex spec, so index always 0
jglick@0
   998
                //
jglick@0
   999
                 int index=findPrevPinOrESpecIndex(sourceLine, y1);
jglick@0
  1000
               //
jglick@0
  1001
                sourceLine.addChild(index+1,sourceExWidget);
jglick@0
  1002
            }
jglick@0
  1003
            else
jglick@0
  1004
            {
jglick@0
  1005
                sourceCF.getMainWidget().addChild(sourceCallPin);
jglick@0
  1006
                Point start=sourceCF.getMainWidget().convertSceneToLocal(scenePoint);
jglick@0
  1007
                start.x=(start.x<(sourceCF.getMainWidget().getBounds().x+sourceCF.getMainWidget().getBounds().width/2)) ? (0) : (sourceCF.getMainWidget().getBounds().width);
jglick@0
  1008
                sourceCallPin.setPreferredLocation(new Point(start.x,start.y+sourceCallPin.getMarginBefore()));
jglick@0
  1009
            }
jglick@0
  1010
            //-------
jglick@0
  1011
            if(targetLine==sourceLine && sourceLine!=null)
jglick@0
  1012
            {
jglick@0
  1013
                //message to self
jglick@0
  1014
                if(sourceNested)
jglick@0
  1015
                {
jglick@0
  1016
                   //sourceCallPin is before target ex spec
jglick@0
  1017
                    int index=sourcePreexistentSpec.getChildren().indexOf(sourceCallPin);
jglick@0
  1018
                    sourcePreexistentSpec.addChild(index+1,targetExWidget);
jglick@0
  1019
                }
jglick@0
  1020
                else
jglick@0
  1021
                {
jglick@0
  1022
                    sourceExWidget.addChild(1, targetExWidget);//this is new source, so have at 0 position only one call pin
jglick@0
  1023
                }
jglick@0
  1024
                targetExWidget.setPreferredLocation(new Point(7,0));
jglick@0
  1025
                targetCallPin.setPreferredLocation(new Point(0,y2+20));
jglick@0
  1026
                targetExWidget.addChild(targetCallPin);
jglick@0
  1027
                //TBD change router for messages
jglick@0
  1028
                call.setRouter(new SelfMessageRouter());
jglick@0
  1029
            }
jglick@0
  1030
            else if(targetNested)
jglick@0
  1031
            {
jglick@0
  1032
                targetExWidget.addChild(targetCallPin);
jglick@0
  1033
                int index=targetPreexistentSpec.getChildren().indexOf(targetPair.getPrevWidget());
jglick@0
  1034
                targetPreexistentSpec.addChild(index+1, targetExWidget);
jglick@0
  1035
            }
jglick@0
  1036
            else if(targetLine!=null)
jglick@0
  1037
            {
jglick@0
  1038
                targetExWidget.addChild(targetCallPin);
jglick@0
  1039
                int index=findPrevPinOrESpecIndex(targetLine, y2+sourceCallPin.getMarginBefore()-targetCallPin.getMarginBefore());
jglick@0
  1040
                targetLine.addChild(index+1,targetExWidget);
jglick@0
  1041
            }
jglick@0
  1042
            else
jglick@0
  1043
            {
jglick@0
  1044
                targetCF.getMainWidget().addChild(targetCallPin);
jglick@0
  1045
                Point finish=convertSceneToLocal(targetCF.getMainWidget(),finishPoint);
jglick@0
  1046
                Point start=targetCF.getMainWidget().convertSceneToLocal(scenePoint);
jglick@0
  1047
                finish.x=(finish.x<targetCF.getMainWidget().getBounds().width/2) ? (0) : (targetCF.getMainWidget().getBounds().width);
jglick@0
  1048
                targetCallPin.setPreferredLocation(new Point(finish.x,start.y+sourceCallPin.getMarginBefore()));
jglick@0
  1049
            }
jglick@0
  1050
    }
jglick@0
  1051
    
jglick@0
  1052
    /**
jglick@0
  1053
     * create message on a diagram, create message always to lifelines
jglick@0
  1054
     * @param source
jglick@0
  1055
     * @param target
jglick@0
  1056
     * @param call
jglick@0
  1057
     * @param y
jglick@0
  1058
     */
jglick@0
  1059
    private void createCreateMessage(Widget source, LifelineWidget target, UMLEdgeWidget call,Point startingPoint) {
jglick@0
  1060
            //int y=startingPoint.y;
jglick@0
  1061
            LifelineWidget sourceLifeline=null;
jglick@0
  1062
            CombinedFragmentWidget sourceCF=null;
jglick@0
  1063
            if(source instanceof LifelineWidget)sourceLifeline=(LifelineWidget) source;
jglick@0
  1064
            else sourceCF=(CombinedFragmentWidget) source;//do not check type here because any other type is unexpected
jglick@0
  1065
            LifelineLineWidget sourceLine=null;
jglick@0
  1066
            if(sourceLifeline!=null)sourceLine=sourceLifeline.getLine();
jglick@0
  1067
            LifelineLineWidget targetLine=null;
jglick@0
  1068
jglick@0
  1069
            LifelineBoxWidget targetBox=target.getBox();
jglick@0
  1070
            int y1=0;
jglick@0
  1071
            if(sourceLine!=null)y1=convertSceneToLocal(sourceLine,startingPoint).y;//incoming corrdinates in LifelineWidget coordinates, we adds child to LifelineLineWidget
jglick@0
  1072
            else y1=convertSceneToLocal(sourceCF.getMainWidget(),startingPoint).y;
jglick@0
  1073
            //set position of target lifeline
jglick@0
  1074
            Point boxCenter=new Point(targetBox.getPreferredBounds().x+targetBox.getPreferredBounds().width/2,targetBox.getPreferredBounds().y+targetBox.getPreferredBounds().height/2);//x doen't matter, in box coordinates
jglick@0
  1075
            boxCenter=targetBox.convertLocalToScene(boxCenter);//in scene coordinats
jglick@0
  1076
            boxCenter=convertSceneToLocal(target,boxCenter);//in lifeline coordinates
jglick@0
  1077
            Point targetCurSceneLocation=target.getParentWidget().convertLocalToScene(target.getPreferredLocation());
jglick@0
  1078
            Point targetNewSceneLocation=new Point(targetCurSceneLocation.x,startingPoint.y-boxCenter.y);
jglick@0
  1079
            Point targetLoc=convertSceneToLocal(target.getParentWidget(),targetNewSceneLocation);
jglick@0
  1080
            //
jglick@0
  1081
            ExecutionSpecificationThinWidget sourcePreexistentSpec=getExSpecification(sourceLine, y1);
jglick@0
  1082
            ExSpecData sourcePair=null;
jglick@0
  1083
            boolean sourceNested=sourcePreexistentSpec!=null;
jglick@0
  1084
             if(sourceNested)
jglick@0
  1085
            {
jglick@0
  1086
                int ys=convertSceneToLocal(sourcePreexistentSpec,startingPoint).y;
jglick@0
  1087
                sourcePair=getWidgetsAroundPoint(sourcePreexistentSpec, ys);
jglick@0
  1088
                //correction if got position inside top margine
jglick@0
  1089
                if(sourcePair.getPrevWidget()==null)
jglick@0
  1090
                {
jglick@0
  1091
                    startingPoint.y+=10;
jglick@0
  1092
                    targetLoc.y+=10;
jglick@0
  1093
                    sourcePair=getWidgetsAroundPoint(sourcePreexistentSpec, ys+10);
jglick@0
  1094
                }
jglick@0
  1095
                //
jglick@0
  1096
                y1=convertSceneToLocal(sourcePreexistentSpec,startingPoint).y;
jglick@0
  1097
            }
jglick@0
  1098
            //
jglick@0
  1099
            final DesignerScene scene=(DesignerScene) source.getScene();
jglick@0
  1100
            //
jglick@0
  1101
            MessagePinWidget sourceCallPin=new MessagePinWidget(scene,MessagePinWidget.PINKIND.CREATE_CALL_OUT);
jglick@0
  1102
            MessagePinWidget targetCallPin=new MessagePinWidget(scene,MessagePinWidget.PINKIND.CREATE_CALL_IN);
jglick@0
  1103
            handleFreeSpaceExpantion(startingPoint,source,sourceCallPin.getKind(),targetLine==sourceLine && sourceLine!=null,sourcePreexistentSpec,sourcePair);
jglick@0
  1104
            //
jglick@0
  1105
            targetLoc.y+=sourceCallPin.getMarginBefore();//pin shift in source
jglick@0
  1106
            ExecutionSpecificationThinWidget sourceExWidget=null;
jglick@0
  1107
            if(sourceLine==null)//combined fragment
jglick@0
  1108
            {
jglick@0
  1109
                call.setSourceAnchor(AnchorFactory.createCenterAnchor(sourceCallPin));
jglick@0
  1110
            }
jglick@0
  1111
            else if(!sourceNested)//free line
jglick@0
  1112
            {
jglick@0
  1113
                sourceExWidget=new ExecutionSpecificationThinWidget(scene);
jglick@0
  1114
                sourceExWidget.setPreferredLocation(new Point(0,0));
jglick@0
  1115
                sourceCallPin.setPreferredLocation(new Point(0,y1+sourceCallPin.getMarginBefore()));
jglick@0
  1116
jglick@0
  1117
                call.setSourceAnchor(AnchorFactory.createCircularAnchor(sourceCallPin,sourceExWidget.width/2));
jglick@0
  1118
            }
jglick@0
  1119
            else
jglick@0
  1120
            {
jglick@0
  1121
                //from existent use existent execution specification
jglick@0
  1122
                sourceCallPin.setPreferredLocation(new Point(0,y1+sourceCallPin.getMarginBefore()));
jglick@0
  1123
                call.setSourceAnchor(AnchorFactory.createCircularAnchor(sourceCallPin,sourcePreexistentSpec.width/2));
jglick@0
  1124
            }
jglick@0
  1125
            //
jglick@0
  1126
            targetBox.addChild(targetCallPin);
jglick@0
  1127
            //
jglick@0
  1128
            call.setTargetAnchor(new CreateMessageTargetAnchor(targetCallPin));
jglick@0
  1129
            //actions
jglick@0
  1130
            //seems reasonable to remove control button after drawing
jglick@0
  1131
            //add actions to execution specifications
jglick@0
  1132
            //if(sourceExWidget!=null)sourceExWidget.createActions(DesignerTools.SELECT).addAction(ActionFactory.createMoveAction(new ThinExecutionSpecificationMoveStrategy(),new ThinExecutionSpecificationMoveProvider()));
jglick@0
  1133
            //--
jglick@0
  1134
            //revalidate with
jglick@0
  1135
            if(sourceNested)
jglick@0
  1136
            {
jglick@0
  1137
                Widget prevW=sourcePair.getPrevWidget();
jglick@0
  1138
                int index=sourcePreexistentSpec.getChildren().indexOf(prevW);
jglick@0
  1139
                sourcePreexistentSpec.addChild(index+1,sourceCallPin);
jglick@0
  1140
            }
jglick@0
  1141
            else if(sourceLine!=null)
jglick@0
  1142
            {
jglick@0
  1143
                sourceExWidget.addChild(sourceCallPin);
jglick@0
  1144
                //
jglick@0
  1145
                 int index=findPrevPinOrESpecIndex(sourceLine, y1);
jglick@0
  1146
                 sourceLine.addChild(index+1,sourceExWidget);
jglick@0
  1147
            }
jglick@0
  1148
            else
jglick@0
  1149
            {
jglick@0
  1150
                sourceCF.getMainWidget().addChild(sourceCallPin);
jglick@0
  1151
                Point start=convertSceneToLocal(sourceCF.getMainWidget(),startingPoint);
jglick@0
  1152
                start.x=(start.x<(sourceCF.getMainWidget().getBounds().x+sourceCF.getMainWidget().getBounds().width/2)) ? (0) : (sourceCF.getMainWidget().getBounds().width);
jglick@0
  1153
                sourceCallPin.setPreferredLocation(new Point(start.x,start.y+sourceCallPin.getMarginBefore()));
jglick@0
  1154
            }
jglick@0
  1155
            target.setPreferredLocation(targetLoc);
jglick@0
  1156
            
jglick@0
  1157
            if(!PersistenceUtil.isDiagramLoading())
jglick@0
  1158
                new AfterValidationExecutor(new ActionProvider() {
jglick@0
  1159
                public void perfomeAction() {
jglick@0
  1160
                    SequenceDiagramEngine  engine=(SequenceDiagramEngine) scene.getEngine();
jglick@0
  1161
                    engine.normalizeLifelines(false, false, null);//align to minimum after create message
jglick@0
  1162
                }
jglick@0
  1163
                },scene);
jglick@0
  1164
    }
jglick@0
  1165
    
jglick@0
  1166
        
jglick@0
  1167
    /**
jglick@0
  1168
     * 
jglick@0
  1169
     * @param level
jglick@0
  1170
     * @param y
jglick@0
  1171
     * @return
jglick@0
  1172
     */
jglick@0
  1173
    private ExecutionSpecificationThinWidget getExSpecification(Widget level,int y)
jglick@0
  1174
    {
jglick@0
  1175
        Widget deep=null;
jglick@0
  1176
        if(level!=null)
jglick@0
  1177
        {
jglick@0
  1178
            List<Widget> children=level.getChildren();//don't need sorted here because n*log(n) is more then just n iteration here
jglick@0
  1179
            for(int i=0;i<children.size();i++)
jglick@0
  1180
            {
jglick@0
  1181
                Widget ch=children.get(i);
jglick@0
  1182
                if(ch instanceof ExecutionSpecificationThinWidget)
jglick@0
  1183
                {
jglick@0
  1184
                    if((ch.getLocation().y+ch.getBounds().y)<=y && (ch.getLocation().y+ch.getBounds().y+ch.getBounds().height)>=y)
jglick@0
  1185
                    {
jglick@0
  1186
                        deep=ch;
jglick@0
  1187
                        //try deeper
jglick@0
  1188
                        Widget deeper=getExSpecification(deep, y-deep.getLocation().y);
jglick@0
  1189
                        if(deeper!=null)deep=deeper;
jglick@0
  1190
                        break;
jglick@0
  1191
                    }
jglick@0
  1192
                }
jglick@0
  1193
            }
jglick@0
  1194
        }
jglick@0
  1195
        return (ExecutionSpecificationThinWidget) deep;
jglick@0
  1196
    }
jglick@0
  1197
    
jglick@0
  1198
    /**
jglick@0
  1199
     * 
jglick@0
  1200
     * 
jglick@0
  1201
     * @param exspec
jglick@0
  1202
     * @param y
jglick@0
  1203
     * @return pair of widgets enclosing point on execution specification and also first and last in the specification, usually pin widgets, but may be null and other execution specification
jglick@0
  1204
     */
jglick@0
  1205
    private ExSpecData getWidgetsAroundPoint(ExecutionSpecificationThinWidget exspec,int y)
jglick@0
  1206
    {
jglick@0
  1207
        Widget pre=null;
jglick@0
  1208
        Widget nxt=null;
jglick@0
  1209
        Widget first=null;
jglick@0
  1210
        Widget last=null;
jglick@0
  1211
        int maxYPre=Integer.MIN_VALUE;
jglick@0
  1212
        int minYnxt=Integer.MAX_VALUE;
jglick@0
  1213
        int minYFirst=Integer.MAX_VALUE;
jglick@0
  1214
        int maxYLast=Integer.MIN_VALUE;
jglick@0
  1215
        for(Widget w:exspec.getChildren())
jglick@0
  1216
        {
jglick@0
  1217
            int y0=w.getLocation().y+w.getBounds().y;
jglick@0
  1218
            int y1=y0+w.getBounds().height;
jglick@0
  1219
            //
jglick@0
  1220
            if(y1<=y)
jglick@0
  1221
            {
jglick@0
  1222
                //pre
jglick@0
  1223
                if(y1>maxYPre)
jglick@0
  1224
                {
jglick@0
  1225
                    maxYPre=y1;
jglick@0
  1226
                    pre=w;
jglick@0
  1227
                }
jglick@0
  1228
            }
jglick@0
  1229
            else if(y0>=y)
jglick@0
  1230
            {
jglick@0
  1231
                //after
jglick@0
  1232
                if(y0<minYnxt)
jglick@0
  1233
                {
jglick@0
  1234
                    minYnxt=y0;
jglick@0
  1235
                    nxt=w;
jglick@0
  1236
                }
jglick@0
  1237
            }
jglick@0
  1238
            else
jglick@0
  1239
            {
jglick@0
  1240
                //unexpected, for test purpose throw exception
jglick@0
  1241
                throw new RuntimeException("Unexpected Exception");
jglick@0
  1242
            }
jglick@0
  1243
            
jglick@0
  1244
            if(y0>maxYLast)
jglick@0
  1245
            {
jglick@0
  1246
                maxYLast=y0;
jglick@0
  1247
                last=w;
jglick@0
  1248
            }
jglick@0
  1249
            if(y0<minYFirst)
jglick@0
  1250
            {
jglick@0
  1251
              minYFirst=y0;
jglick@0
  1252
              first=w;
jglick@0
  1253
            }
jglick@0
  1254
        }
jglick@0
  1255
        return new ExSpecData(first,last,pre,nxt);
jglick@0
  1256
    }
jglick@0
  1257
            
jglick@0
  1258
    private class ExSpecData
jglick@0
  1259
    {
jglick@0
  1260
        Widget prev,next,first,last;
jglick@0
  1261
        public ExSpecData(Widget first,Widget last,Widget prev,Widget next)
jglick@0
  1262
        {
jglick@0
  1263
            this.prev=prev;
jglick@0
  1264
            this.next=next;
jglick@0
  1265
            this.first=first;
jglick@0
  1266
            this.last=last;
jglick@0
  1267
        }
jglick@0
  1268
        public Widget getPrevWidget()
jglick@0
  1269
        {
jglick@0
  1270
            return prev;
jglick@0
  1271
        }
jglick@0
  1272
        public Widget getNextWidget()
jglick@0
  1273
        {
jglick@0
  1274
            return next;
jglick@0
  1275
        }
jglick@0
  1276
        public Widget getFirstWidget()
jglick@0
  1277
        {
jglick@0
  1278
            return first;
jglick@0
  1279
        }
jglick@0
  1280
        public Widget getLastWidget()
jglick@0
  1281
        {
jglick@0
  1282
            return last;
jglick@0
  1283
        }
jglick@0
  1284
    }
jglick@0
  1285
    
jglick@0
  1286
    private class SelfMessageRouter implements Router
jglick@0
  1287
    {
jglick@0
  1288
jglick@0
  1289
        public List<Point> routeConnection(ConnectionWidget widget) {
jglick@0
  1290
            ArrayList<Point> ret=new ArrayList<Point>();
jglick@0
  1291
            MessagePinWidget source=(MessagePinWidget) widget.getSourceAnchor().getRelatedWidget();
jglick@0
  1292
            MessagePinWidget target=(MessagePinWidget) widget.getTargetAnchor().getRelatedWidget();
jglick@0
  1293
            //find line
jglick@0
  1294
            Widget line=source.getParentWidget();
jglick@0
  1295
            for(;line!=null;line=line.getParentWidget())
jglick@0
  1296
            {
jglick@0
  1297
                if(line instanceof LifelineLineWidget)break;
jglick@0
  1298
            }
jglick@0
  1299
            Point lineLocation=line.getPreferredLocation();
jglick@0
  1300
            if(lineLocation==null)lineLocation=line.getLocation();
jglick@0
  1301
            lineLocation=line.getParentWidget().convertLocalToScene(lineLocation);
jglick@0
  1302
            //
jglick@0
  1303
            Point start=widget.getSourceAnchor().getRelatedSceneLocation();
jglick@0
  1304
            Point finish=widget.getTargetAnchor().getRelatedSceneLocation();
jglick@0
  1305
            //
jglick@0
  1306
            boolean right=start.x>=lineLocation.x;
jglick@0
  1307
            //
jglick@0
  1308
            int semi_w=5;//consider all same, TBD get 10 somewhere
jglick@0
  1309
            //
jglick@0
  1310
            int max=Math.max(start.x,finish.x);
jglick@0
  1311
            int min=Math.min(start.x,finish.x);
jglick@0
  1312
            //
jglick@0
  1313
            if(right)
jglick@0
  1314
            {
jglick@0
  1315
                start.x+=semi_w;
jglick@0
  1316
                finish.x+=semi_w;
jglick@0
  1317
            }
jglick@0
  1318
            else
jglick@0
  1319
            {
jglick@0
  1320
                start.x-=semi_w;
jglick@0
  1321
                finish.x-=semi_w;
jglick@0
  1322
            }
jglick@0
  1323
            //
jglick@0
  1324
            ret.add(start);
jglick@0
  1325
            if(right)
jglick@0
  1326
            {
jglick@0
  1327
                ret.add(new Point(max+20,start.y));
jglick@0
  1328
                ret.add(new Point(max+25,(start.y+finish.y)/2));
jglick@0
  1329
                ret.add(new Point(max+20,finish.y));
jglick@0
  1330
            }
jglick@0
  1331
            else
jglick@0
  1332
            {
jglick@0
  1333
                ret.add(new Point(min-20,start.y));
jglick@0
  1334
                ret.add(new Point(min-25,(start.y+finish.y)/2));
jglick@0
  1335
                ret.add(new Point(min-20,finish.y));
jglick@0
  1336
            }
jglick@0
  1337
            ret.add(finish);
jglick@0
  1338
            //
jglick@0
  1339
            return ret;
jglick@0
  1340
        }
jglick@0
  1341
        
jglick@0
  1342
    }
jglick@0
  1343
    
jglick@0
  1344
    /**
jglick@0
  1345
     * Calculation consider widgets orderes, higher indexed widgets have higher y corrdinate
jglick@0
  1346
     * @param lineWidget - LifelineLineWidget or ExecutionSpec widget or any widget which may contain pins and ex specifications
jglick@0
  1347
     * @param y - ppint before which we are looking other widgets in lineWidget coordinate system
jglick@0
  1348
     * @return index of previous widget
jglick@0
  1349
     */
jglick@0
  1350
    private int findPrevPinOrESpecIndex(Widget lineWidget,int y)
jglick@0
  1351
    {
jglick@0
  1352
                        int index=-1;
jglick@0
  1353
                for(int i=lineWidget.getChildren().size()-1;i>=0;i--)
jglick@0
  1354
                {
jglick@0
  1355
                    Widget w=lineWidget.getChildren().get(i);
jglick@0
  1356
                    if(w instanceof ExecutionSpecificationThinWidget || w instanceof MessagePinWidget)
jglick@0
  1357
                    {
jglick@0
  1358
                        if((w.getPreferredLocation().y+w.getPreferredBounds().y+w.getPreferredBounds().height)<y)
jglick@0
  1359
                        {
jglick@0
  1360
                            index=i;
jglick@0
  1361
                            break;
jglick@0
  1362
                        }
jglick@0
  1363
                    }
jglick@0
  1364
                    //else we do not support direct connection without spec from line now
jglick@0
  1365
                }
jglick@0
  1366
          return index;      
jglick@0
  1367
    }
jglick@0
  1368
    
jglick@0
  1369
    /**
jglick@0
  1370
     * this method handle new message cases, i.e. dependent on new message ex spec sizes and isn't very good to reconnect action
jglick@0
  1371
     * TBD need to be updated later
jglick@0
  1372
     * @param y position in scene? coordinated
jglick@0
  1373
     * @param widget Lifeline/CF widget
jglick@0
  1374
     * @param kind create/asych,synch messages
jglick@0
  1375
     * @param preExistent if there preexistent spec in place
jglick@0
  1376
     */
jglick@0
  1377
    private void handleFreeSpaceExpantion(Point scenePoint,Widget widget,MessagePinWidget.PINKIND pinkind,boolean toself,ExecutionSpecificationThinWidget preExistent,ExSpecData pair)
jglick@0
  1378
    {
jglick@0
  1379
        if(widget instanceof LifelineWidget)
jglick@0
  1380
        {
jglick@0
  1381
            LifelineWidget lifeline=(LifelineWidget) widget;
jglick@0
  1382
            int yfree_req=20;//minimum free space?, for rcreate message, call out of asynch
jglick@0
  1383
            if(toself)
jglick@0
  1384
            {
jglick@0
  1385
                if(pinkind==MessagePinWidget.PINKIND.SYNCHRONOUS_CALL_OUT)
jglick@0
  1386
                {
jglick@0
  1387
                    yfree_req=90;
jglick@0
  1388
                }
jglick@0
  1389
                else
jglick@0
  1390
                {
jglick@0
  1391
                    yfree_req=80;
jglick@0
  1392
                }
jglick@0
  1393
            }
jglick@0
  1394
            else
jglick@0
  1395
            {
jglick@0
  1396
                if(pinkind==MessagePinWidget.PINKIND.SYNCHRONOUS_CALL_OUT || pinkind==MessagePinWidget.PINKIND.SYNCHRONOUS_CALL_IN)
jglick@0
  1397
                {
jglick@0
  1398
                    yfree_req=50;
jglick@0
  1399
                }
jglick@0
  1400
                else if(pinkind==MessagePinWidget.PINKIND.ASYNCHRONOUS_CALL_IN)
jglick@0
  1401
                {
jglick@0
  1402
                    yfree_req=40;
jglick@0
  1403
                }
jglick@0
  1404
            }
jglick@0
  1405
            yfree_req+=10;
jglick@0
  1406
            ////////////
jglick@0
  1407
            if(preExistent!=null)
jglick@0
  1408
            {
jglick@0
  1409
                Widget nxt=pair.getNextWidget();
jglick@0
  1410
                if(nxt instanceof MessagePinWidget)
jglick@0
  1411
                {
jglick@0
  1412
                    MessagePinWidget pin=(MessagePinWidget) nxt;
jglick@0
  1413
                    int dy=yfree_req-(pin.getParentWidget().convertLocalToScene(pin.getPreferredLocation()).y-scenePoint.y);
jglick@0
  1414
                    new ArrangeMoveWithBumping(null, null, null).moveDown(pin, dy);
jglick@0
  1415
                    widget.getScene().validate();
jglick@0
  1416
                }
jglick@0
  1417
                else if(nxt!=null)
jglick@0
  1418
                {
jglick@0
  1419
                    ExecutionSpecificationThinWidget exSpec=(ExecutionSpecificationThinWidget) nxt;
jglick@0
  1420
                    MessagePinWidget pin=(MessagePinWidget) exSpec.getChildren().get(0);
jglick@0
  1421
                    int dy=yfree_req-(pin.getParentWidget().convertLocalToScene(pin.getPreferredLocation()).y-scenePoint.y);
jglick@0
  1422
                    new ArrangeMoveWithBumping(null, null, null).moveDown(pin, dy);
jglick@0
  1423
                    widget.getScene().validate();
jglick@0
  1424
                }
jglick@0
  1425
                else
jglick@0
  1426
                {
jglick@0
  1427
                    
jglick@0
  1428
                }
jglick@0
  1429
            }
jglick@0
  1430
            else
jglick@0
  1431
            {
jglick@0
  1432
                LifelineLineWidget line=lifeline.getLine();
jglick@0
  1433
                ExecutionSpecificationThinWidget nxt=null;
jglick@0
  1434
                Point linePoint=convertSceneToLocal(line,scenePoint);
jglick@0
  1435
                for(Widget w:line.getChildren())
jglick@0
  1436
                {
jglick@0
  1437
                    if((w.getPreferredLocation().y+w.getPreferredBounds().y)>linePoint.y)
jglick@0
  1438
                    {
jglick@0
  1439
                        //if(nxt==null || ((nxt.getPreferredLocation().y+nxt.getPreferredBounds().y)>(w.getPreferredLocation().y+w.getPreferredBounds().y)))
jglick@0
  1440
                        {
jglick@0
  1441
                            nxt=(ExecutionSpecificationThinWidget) w;
jglick@0
  1442
                            break;//it's ordered
jglick@0
  1443
                        }
jglick@0
  1444
                    }
jglick@0
  1445
                }
jglick@0
  1446
                if(nxt!=null)
jglick@0
  1447
                {
jglick@0
  1448
                    Point nxtPoint=new Point(0,nxt.getPreferredLocation().y+nxt.getPreferredBounds().y);
jglick@0
  1449
                    int dy=yfree_req-(nxt.getParentWidget().convertLocalToScene(nxtPoint).y-scenePoint.y);
jglick@0
  1450
                    new ArrangeMoveWithBumping(null, null, null).moveDown((MessagePinWidget) nxt.getChildren().get(0), dy);
jglick@0
  1451
                    widget.getScene().validate();
jglick@0
  1452
                }
jglick@0
  1453
            }
jglick@0
  1454
        }
jglick@0
  1455
        else if(widget instanceof CombinedFragmentWidget)
jglick@0
  1456
        {
jglick@0
  1457
            
jglick@0
  1458
        }
jglick@0
  1459
    }
jglick@0
  1460
    
jglick@0
  1461
    /**
jglick@0
  1462
     * support reconnection of target of synch or asynch messages from to lifelines only
jglick@0
  1463
     */
jglick@0
  1464
    public void reconnectMessage(GraphScene scene,MessageFactory factory,IPresentationElement messagePE,IPresentationElement targetLifelinePE)
jglick@0
  1465
    {
jglick@0
  1466
        if(!processInvokedOperation(messagePE.getFirstSubject(),targetLifelinePE.getFirstSubject()))return;
jglick@0
  1467
        factory.reconnectTarget(messagePE.getFirstSubject(), targetLifelinePE.getFirstSubject());
jglick@0
  1468
        IMessage message=(IMessage) messagePE.getFirstSubject();
jglick@0
  1469
        IMessage resultMessage=null;
jglick@0
  1470
        ILifeline targetLifeline=(ILifeline) targetLifelinePE.getFirstSubject();
jglick@0
  1471
        IPresentationElement resultPE=null;
jglick@0
  1472
        LifelineWidget target=(LifelineWidget) scene.findWidget(targetLifelinePE);
jglick@0
  1473
        if(message.getKind()==BaseElement.MK_SYNCHRONOUS || message.getKind()==BaseElement.MK_ASYNCHRONOUS)
jglick@0
  1474
        {
jglick@0
  1475
            MessageWidget call=(MessageWidget) scene.findWidget(messagePE);
jglick@0
  1476
            
jglick@0
  1477
            MessageWidget result=null;
jglick@0
  1478
            //call section
jglick@0
  1479
            MessagePinWidget targetPin1=(MessagePinWidget) call.getTargetAnchor().getRelatedWidget();
jglick@0
  1480
            ExecutionSpecificationThinWidget targetSpec=(ExecutionSpecificationThinWidget) targetPin1.getParentWidget();
jglick@0
  1481
            //need to move return message also, and may be need to move all child messages
jglick@0
  1482
            MessagePinWidget returnPin=null;
jglick@0
  1483
            for(Widget w:targetSpec.getChildren())
jglick@0
  1484
            {
jglick@0
  1485
                if(w instanceof MessagePinWidget)
jglick@0
  1486
                {
jglick@0
  1487
                    MessagePinWidget pin=(MessagePinWidget) w;
jglick@0
  1488
                    if(pin.getKind()==MessagePinWidget.PINKIND.SYNCHRONOUS_RETURN_OUT)returnPin=pin;
jglick@0
  1489
                }
jglick@0
  1490
            }
jglick@0
  1491
            //
jglick@0
  1492
            if(returnPin!=null)
jglick@0
  1493
            {
jglick@0
  1494
                result=(MessageWidget) returnPin.getConnection(0);
jglick@0
  1495
                resultPE=(IPresentationElement) scene.findObject(result);
jglick@0
  1496
                resultMessage=(IMessage) resultPE.getFirstSubject();
jglick@0
  1497
                factory.reconnectSource(resultMessage, targetLifelinePE.getFirstSubject());
jglick@0
  1498
            }
jglick@0
  1499
            //position where it was
jglick@0
  1500
            Point localPoint=targetPin1.getPreferredLocation();//consider all specs are at zero position and only pins move
jglick@0
  1501
            Point scenePoint1=targetSpec.convertLocalToScene(localPoint);
jglick@0
  1502
            Point scenePoint2=null;
jglick@0
  1503
            if(returnPin!=null)
jglick@0
  1504
            {
jglick@0
  1505
                scenePoint2=targetSpec.convertLocalToScene(returnPin.getPreferredLocation());
jglick@0
  1506
            }
jglick@0
  1507
            targetSpec.getParentWidget().removeChild(targetSpec);
jglick@0
  1508
            //
jglick@0
  1509
            //+++++++++++++++++++++++++++++++++
jglick@0
  1510
            LifelineWidget targetLifeLine=(LifelineWidget) scene.findWidget(targetLifelinePE);
jglick@0
  1511
            LifelineLineWidget targetLine=targetLifeLine.getLine();
jglick@0
  1512
            int y2=targetLine.convertSceneToLocal(scenePoint1).y;//
jglick@0
  1513
            int yret=0;if(scenePoint2!=null)yret=targetLine.convertSceneToLocal(scenePoint2).y;
jglick@0
  1514
            ExecutionSpecificationThinWidget targetPreexistentSpec=getExSpecification(targetLine, y2);
jglick@0
  1515
            ExSpecData targetPair=null;
jglick@0
  1516
            
jglick@0
  1517
            
jglick@0
  1518
            boolean targetNested=targetPreexistentSpec!=null;
jglick@0
  1519
            if(targetNested)
jglick@0
  1520
            {
jglick@0
  1521
                y2=targetPreexistentSpec.convertSceneToLocal(scenePoint1).y;
jglick@0
  1522
                targetPair=getWidgetsAroundPoint(targetPreexistentSpec, y2);
jglick@0
  1523
                if(scenePoint2!=null)yret=targetPreexistentSpec.convertSceneToLocal(scenePoint2).y;
jglick@0
  1524
                //correction if got position inside top margine
jglick@0
  1525
                if(targetPair.getPrevWidget()==null)
jglick@0
  1526
                {
jglick@0
  1527
                    throw new UnsupportedOperationException("Can't reconnect, need code improvement");
jglick@0
  1528
                }
jglick@0
  1529
            }
jglick@0
  1530
            
jglick@0
  1531
            handleFreeSpaceExpantion(scenePoint1,target,targetPin1.getKind(),false,targetPreexistentSpec,targetPair);//do not support messages to self for now (as in 6.0, TBD disable start of reconnection)
jglick@0
  1532
            //--
jglick@0
  1533
            if(targetNested)
jglick@0
  1534
            {
jglick@0
  1535
                int index=targetPreexistentSpec.getChildren().indexOf(targetPair.getPrevWidget());
jglick@0
  1536
                targetPreexistentSpec.addChild(index+1, targetSpec);
jglick@0
  1537
                targetPin1.setPreferredLocation(new Point(0,y2));
jglick@0
  1538
                if(returnPin!=null)returnPin.setPreferredLocation(new Point(0,yret));
jglick@0
  1539
            }
jglick@0
  1540
            else if(targetLine!=null)
jglick@0
  1541
            {
jglick@0
  1542
                int index=findPrevPinOrESpecIndex(targetLine, y2);
jglick@0
  1543
                targetLine.addChild(index+1,targetSpec);
jglick@0
  1544
                targetPin1.setPreferredLocation(new Point(0,y2));
jglick@0
  1545
                if(returnPin!=null)returnPin.setPreferredLocation(new Point(0,yret));
jglick@0
  1546
             }
jglick@0
  1547
            //+++++++++++++++++++++++++++++++++
jglick@0
  1548
            Anchor tmp=call.getTargetAnchor();
jglick@0
  1549
            scene.setEdgeTarget(messagePE, targetLifelinePE);
jglick@0
  1550
            call.setTargetAnchor(tmp);//edge update change anchor also
jglick@0
  1551
            if(resultPE!=null)
jglick@0
  1552
            {
jglick@0
  1553
                tmp=result.getSourceAnchor();
jglick@0
  1554
                scene.setEdgeSource(resultPE, targetLifelinePE);
jglick@0
  1555
                result.setSourceAnchor(tmp);
jglick@0
  1556
            }
jglick@0
  1557
        }
jglick@0
  1558
    }
jglick@0
  1559
    /**
jglick@0
  1560
     * When a message has been moved from one lifeline to another, process its invoked operation
jglick@0
  1561
     *
jglick@0
  1562
     * @param edge    The TS edge containing the a message, which may have an invoked operation
jglick@0
  1563
     * @param endNode The node the edge is moving to
jglick@0
  1564
     */
jglick@0
  1565
    protected boolean processInvokedOperation( IElement edgeElement, IElement nodeElement )
jglick@0
  1566
    {       
jglick@0
  1567
        boolean bProcessInvokedOperation = true;
jglick@0
  1568
        
jglick@0
  1569
        if (edgeElement instanceof IMessage)
jglick@0
  1570
        {
jglick@0
  1571
            IMessage message = (IMessage)edgeElement;
jglick@0
  1572
            
jglick@0
  1573
            IOperation operation = message.getOperationInvoked();
jglick@0
  1574
            if( operation != null )
jglick@0
  1575
            {
jglick@0
  1576
                // Determine the new invoked operation, the default is null
jglick@0
  1577
                IOperation operationInvoked = null;
jglick@0
  1578
                
jglick@0
  1579
                if (nodeElement instanceof ILifeline)
jglick@0
  1580
                {
jglick@0
  1581
                    ILifeline lifeline = (ILifeline)nodeElement;
jglick@0
  1582
                    
jglick@0
  1583
                    IClassifier classifier = lifeline.getRepresentingClassifier();
jglick@0
  1584
                    if( classifier != null )
jglick@0
  1585
                    {
jglick@0
  1586
                        operationInvoked = classifier.findMatchingOperation( operation );
jglick@0
  1587
                        
jglick@0
  1588
                        if( null == operationInvoked )
jglick@0
  1589
                        {
jglick@0
  1590
                            // Determine if the user wants to copy, move or cancel
jglick@0
  1591
                            //kris richards - PROBLEM - need to remove this pref.
jglick@0
  1592
                            IPreferenceQuestionDialog questionDialog = new SwingPreferenceQuestionDialog();
jglick@0
  1593
                            if( questionDialog != null )
jglick@0
  1594
                            {
jglick@0
  1595
                                String strQuestion = RESOURCE_BUNDLE.getString( "IDS_Q_INVOKED_OPERATION" );
jglick@0
  1596
                                String strQuestionTitle = RESOURCE_BUNDLE.getString( "IDS_Q_INVOKED_OPERATION_TITLE" );
jglick@0
  1597
                                
jglick@0
  1598
                                int nResult =
jglick@0
  1599
                                        questionDialog.displayFromStrings( "Default",
jglick@0
  1600
                                        "Diagrams|SequenceDiagram",
jglick@0
  1601
                                        "UML_ShowMe_Move_Invoked_Operation",
jglick@0
  1602
                                        "PSK_ALWAYS",
jglick@0
  1603
                                        "PSK_NEVER",
jglick@0
  1604
                                        "PSK_ASK",
jglick@0
  1605
                                        strQuestion,
jglick@0
  1606
                                        SimpleQuestionDialogResultKind.SQDRK_RESULT_YES,
jglick@0
  1607
                                        strQuestionTitle,
jglick@0
  1608
                                        SimpleQuestionDialogKind.SQDK_YESNOCANCEL,
jglick@0
  1609
                                        MessageIconKindEnum.EDIK_ICONQUESTION,
jglick@0
  1610
                                        null );
jglick@0
  1611
                                
jglick@0
  1612
                                switch( nResult )
jglick@0
  1613
                                {
jglick@0
  1614
                                    case SimpleQuestionDialogResultKind.SQDRK_RESULT_YES:
jglick@0
  1615
                                        operation.moveToClassifier( classifier );
jglick@0
  1616
                                        operationInvoked = operation;
jglick@0
  1617
                                        break;
jglick@0
  1618
                                        
jglick@0
  1619
                                    case SimpleQuestionDialogResultKind.SQDRK_RESULT_NO:
jglick@0
  1620
                                    {
jglick@0
  1621
                                        IFeature feature = operation.duplicateToClassifier( classifier );
jglick@0
  1622
                                        if (feature instanceof IOperation)
jglick@0
  1623
                                        {
jglick@0
  1624
                                            operationInvoked = (IOperation)feature;
jglick@0
  1625
                                        }
jglick@0
  1626
                                    }
jglick@0
  1627
                                    break;
jglick@0
  1628
                                    
jglick@0
  1629
                                    default:
jglick@0
  1630
                                        assert ( false );
jglick@0
  1631
                                    case SimpleQuestionDialogResultKind.SQDRK_RESULT_CANCEL:
jglick@0
  1632
                                        bProcessInvokedOperation = false;
jglick@0
  1633
                                        break;
jglick@0
  1634
                                }
jglick@0
  1635
                            }
jglick@0
  1636
                        }
jglick@0
  1637
                    }
jglick@0
  1638
                }
jglick@0
  1639
                
jglick@0
  1640
                if( bProcessInvokedOperation )
jglick@0
  1641
                {
jglick@0
  1642
                    message.setOperationInvoked( operationInvoked );
jglick@0
  1643
                }
jglick@0
  1644
            }
jglick@0
  1645
        }
jglick@0
  1646
        
jglick@0
  1647
        return bProcessInvokedOperation;
jglick@0
  1648
    }
jglick@0
  1649
    
jglick@0
  1650
    public ConnectorState isTargetWidget(Widget sourceWidget, Widget targetWidget) {
jglick@0
  1651
        throw new UnsupportedOperationException("Messages can't be created without points specification.");
jglick@0
  1652
    }
jglick@0
  1653
    public void createConnection(Widget sourceWidget, Widget targetWidget) {
jglick@0
  1654
        throw new UnsupportedOperationException("Messages can't be created without points specification.");
jglick@0
  1655
    }
jglick@0
  1656
jglick@0
  1657
    private static final String BUNDLE_NAME = "org.netbeans.modules.uml.diagrams.engines.Bundle"; //$NON-NLS-1$
jglick@0
  1658
    private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
jglick@0
  1659
jglick@0
  1660
    public Widget createTargetWidget(Scene scene, Widget soruceWidget, Point location) {
jglick@0
  1661
        throw new UnsupportedOperationException("Not supported yet.");
jglick@0
  1662
    }
jglick@0
  1663
    
jglick@0
  1664
    /**
jglick@0
  1665
     * Converts a location in the scene coordination system to the local coordination system.
jglick@0
  1666
     * coerting based on preferred widgets locations
jglick@0
  1667
     * @param sceneLocation the scene location
jglick@0
  1668
     * @return the local location
jglick@0
  1669
     */
jglick@0
  1670
    public Point convertSceneToLocal (Widget widget,Point sceneLocation) {
jglick@0
  1671
        Point localLocation = new Point (sceneLocation);
jglick@0
  1672
        while (widget != null) {
jglick@0
  1673
            if (widget == widget.getScene())
jglick@0
  1674
                break;
jglick@0
  1675
            Point location = widget.getPreferredLocation();
jglick@0
  1676
            if(location==null)location=widget.getLocation();
jglick@0
  1677
            localLocation.x -= location.x;
jglick@0
  1678
            localLocation.y -= location.y;
jglick@0
  1679
            widget = widget.getParentWidget ();
jglick@0
  1680
        }
jglick@0
  1681
        return localLocation;
jglick@0
  1682
    }
jglick@0
  1683
jglick@0
  1684
}