001/* Manhattan Geometry Link
002
003 Copyright (c) 2006-2016 The Regents of the University of California.
004 All rights reserved.
005
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024 */
025
026package ptolemy.vergil.actor;
027
028import java.util.ArrayList;
029
030import diva.canvas.Site;
031import diva.canvas.connector.BasicManhattanRouter;
032import diva.canvas.connector.ManhattanConnector;
033import ptolemy.actor.IOPort;
034import ptolemy.kernel.util.Location;
035import ptolemy.kernel.util.NamedObj;
036import ptolemy.vergil.kernel.Link;
037
038///////////////////////////////////////////////////////////////////
039//// LinkManhattanConnector
040
041/**
042 An extension to BasicManhattanRouter supporting links to multiports.
043
044 @author Edward A. Lee
045 @version $Id$
046 @since Ptolemy II 5.2
047 @Pt.ProposedRating Yellow (eal)
048 @Pt.AcceptedRating Red (eal)
049 */
050public class LinkManhattanConnector extends ManhattanConnector {
051    /** Construct a new connector with the given tail and head
052     *  for the specified link. The head and tail sites may be
053     *  representative sites for multiport, in which case they are
054     *  not necessarily the ones returned by getHeadSite() or
055     *  getTailSite().  Those methods will return new sites
056     *  as needed to ensure that each each connection is to its
057     *  own site.
058     *  @param tail The tail site.
059     *  @param head The head site.
060     *  @param link The link.
061     */
062    public LinkManhattanConnector(Site tail, Site head, Link link) {
063        super(tail, head, _router);
064
065        Object headObject = link.getHead();
066
067        if (headObject instanceof IOPort) {
068            _headPort = (IOPort) headObject;
069        } else if (headObject instanceof Location) {
070            // If this is an external port, the object might be an
071            // instance of Location contained by the port.
072            NamedObj container = ((Location) headObject).getContainer();
073
074            if (container instanceof IOPort) {
075                _headPort = (IOPort) container;
076            }
077        }
078
079        Object tailObject = link.getTail();
080
081        if (tailObject instanceof IOPort) {
082            _tailPort = (IOPort) tailObject;
083        } else if (tailObject instanceof Location) {
084            // If this is an external port, the object might be an
085            // instance of Location contained by the port.
086            NamedObj container = ((Location) tailObject).getContainer();
087
088            if (container instanceof IOPort) {
089                _tailPort = (IOPort) container;
090            }
091        }
092
093        _link = link;
094    }
095
096    ///////////////////////////////////////////////////////////////////
097    ////                         public methods                    ////
098
099    /** Override the base class to return a different site for each
100     *  connection to a multiport.
101     *  @return The connection site.
102     */
103    @Override
104    public Site getHeadSite() {
105        Site result = super.getHeadSite();
106        if (_headPort == null || !_headPort.isMultiport()) {
107            return result;
108        }
109        if (result instanceof PortConnectSite) {
110            PortTerminal terminal = ((PortConnectSite) result).getTerminal();
111            int orderIndex = terminal.getOrderIndex(this);
112
113            if (orderIndex >= 0) {
114                // This should not create a new site if it has already
115                // created one!  Record the ones created and return them.
116                if (_headSites == null) {
117                    _headSites = new ArrayList();
118                }
119                if (_headSites.size() > orderIndex) {
120                    if (_headSites.get(orderIndex) == null) {
121                        result = new PortConnectSite(result.getFigure(),
122                                terminal, orderIndex + 1, result.getNormal());
123                    } else {
124                        result = (Site) _headSites.get(orderIndex);
125                    }
126                    _headSites.set(orderIndex, result);
127                } else {
128                    result = new PortConnectSite(result.getFigure(), terminal,
129                            orderIndex + 1, result.getNormal());
130                    while (_headSites.size() < orderIndex) {
131                        _headSites.add(null);
132                    }
133                    _headSites.add(result);
134                }
135            }
136        }
137        return result;
138    }
139
140    /** Return the associated link.
141     *  @return The associated link.
142     */
143    public Link getLink() {
144        return _link;
145    }
146
147    /** Override the base class to return a different site for each
148     *  connection to a multiport.
149     *  @return The connection site.
150     */
151    @Override
152    public Site getTailSite() {
153        Site result = super.getTailSite();
154        if (_tailPort == null || !_tailPort.isMultiport()) {
155            return result;
156        }
157        if (result instanceof PortConnectSite) {
158            PortTerminal terminal = ((PortConnectSite) result).getTerminal();
159            int orderIndex = terminal.getOrderIndex(this);
160
161            if (orderIndex >= 0) {
162                // This should not create a new site if it has already
163                // created one!  Record the ones created and return them.
164                if (_tailSites == null) {
165                    _tailSites = new ArrayList();
166                }
167                if (_tailSites.size() > orderIndex) {
168                    if (_tailSites.get(orderIndex) == null) {
169                        result = new PortConnectSite(result.getFigure(),
170                                terminal, orderIndex + 1, result.getNormal());
171                    } else {
172                        result = (Site) _tailSites.get(orderIndex);
173                    }
174                    _tailSites.set(orderIndex, result);
175                } else {
176                    result = new PortConnectSite(result.getFigure(), terminal,
177                            orderIndex + 1, result.getNormal());
178                    while (_tailSites.size() < orderIndex) {
179                        _tailSites.add(null);
180                    }
181                    _tailSites.add(result);
182                }
183            }
184        }
185        return result;
186    }
187
188    ///////////////////////////////////////////////////////////////////
189    ////                     private members                       ////
190
191    /** The port at the head, if there is one and it's an IOPort. */
192    private IOPort _headPort = null;
193
194    /** Head sites, in case this is a multiport. */
195    private ArrayList _headSites = null;
196
197    /** The link. */
198    private Link _link;
199
200    /** Specialized router. */
201    private static BasicManhattanRouter _router = new BasicManhattanRouter();
202
203    /** The port at the tail, if there is one and it's an IOPort. */
204    private IOPort _tailPort = null;
205
206    /** Tail sites, in case this is a multiport. */
207    private ArrayList _tailSites = null;
208}