1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.6. 
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2000-2008 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.view.viewmode;
15  
16  
17  import demo.view.DemoBase;
18  import y.base.Edge;
19  import y.base.Node;
20  import y.base.YCursor;
21  import y.base.YList;
22  import y.view.CreateEdgeMode;
23  import y.view.EdgeRealizer;
24  import y.view.EditMode;
25  import y.view.Graph2D;
26  import y.view.NodeRealizer;
27  import y.view.Port;
28  
29  /**
30   * Demonstrates how CreateEdgeMode can be customized in order to
31   * control automatic assignments of ports for edges.
32   * Edges are created in such a way, that the source port is always on
33   * the top side of the source node and the target port is always on the bottom
34   * side of the target node.
35   */
36  public class PortCreateEdgeModeDemo extends DemoBase
37  {
38  
39    protected void registerViewModes() {
40      EditMode editMode = new EditMode();
41      view.addViewMode( editMode );
42      //set a custom CreateEdgeMode for the edge mode
43      editMode.setCreateEdgeMode( new PortCreateEdgeMode() );
44    }
45  
46    public static class PortCreateEdgeMode extends CreateEdgeMode
47    {
48      private Edge edge; // need this for the hook
49  
50      /**
51       * If a node was hit at the given coordinates, that node
52       * will be used as target node for the newly created edge.
53       *
54       */
55      public void mouseReleasedLeft(double x, double y)
56      {
57        // simulate a pressed shift...
58        // this will trigger CreateEdgeMode, to preassign offset
59        // to source and target ports
60        super.mouseShiftReleasedLeft(x, y);
61  
62        if (edge != null){ // the edge has just been created
63          Graph2D graph = (Graph2D) edge.getGraph();
64          EdgeRealizer er = graph.getRealizer(edge);
65  
66          // get a list of port candidates
67          YList ports = getPorts(edge.source(), edge);
68          Port p = er.getSourcePort();
69          // snap to one of them
70          snap(er, true, p.getOffsetX(), p.getOffsetY(), ports);
71  
72          // get a list of port candidates
73          ports = getPorts(edge.target(), edge);
74          p = er.getTargetPort();
75          // snap to one of them
76          snap(er, false, p.getOffsetX(), p.getOffsetY(), ports);
77  
78          // do some clean up
79          edge = null;
80          graph.updateViews();
81        }
82  
83      }
84  
85      /**
86       * Initiates the creation of an edge.
87       * 
88       */
89      public void mousePressedLeft(double x, double y)
90      {
91        // simulate a pressed shift...
92        // this will trigger CreateEdgeMode, to preassign offset
93        // to source and target ports
94        super.mouseShiftPressedLeft(x, y);
95      }
96  
97  
98      public void edgeCreated(Edge e){
99        //remember the edge...
100       this.edge = e;
101     }
102 
103     /**
104      * This method finds a list of Port objects for a specific edge/node pair
105      *
106      * @param onNode  the node
107      * @param forEdge the edge
108      * @return a list of Port objects
109      */
110     public YList getPorts(Node onNode, Edge forEdge) {
111       YList list = new YList();
112       Graph2D graph = (Graph2D) onNode.getGraph();
113       NodeRealizer nr = graph.getRealizer(onNode);
114       EdgeRealizer er = graph.getRealizer(forEdge);
115 
116       if (onNode == forEdge.source()) {
117         // source ports are centered on top of the node
118         list.add(new Port(0, -nr.getHeight() / 2));
119       } else {
120         // target ports are centered at the bottom of the node
121         list.add(new Port(0, nr.getHeight() / 2));
122       }
123       return list;
124     }
125 
126     /**
127      * This method calculates a metric for ports and points
128      *
129      * @param x    the initial x offset
130      * @param y    the initial y offset
131      * @param port the port
132      * @return the distance between the point (x,y) and the port
133      */
134     public static double getDistance(double x, double y, Port port) {
135       return Math.sqrt((x - port.getOffsetX()) * (x - port.getOffsetX())
136           + (y - port.getOffsetY()) * (y - port.getOffsetY()));
137     }
138 
139     /**
140      * This method chooses from a list of given ports for an edge
141      * a suitable port, given an initial placement.
142      *
143      * @param edge   the affected edge
144      * @param source whether we look at the source node
145      * @param x      the initial x offset
146      * @param y      the initial y offset
147      * @param ports  a list of Port objects (candidates)
148      */
149     public void snap(EdgeRealizer edge, boolean source, double x, double y, YList ports) {
150       if (ports == null || ports.size() < 1) return; // do nothing
151 
152       // find the closest port with regards to the getDistance function
153       Port closest = (Port) ports.first();
154       double dist = getDistance(x, y, closest);
155 
156       for (YCursor cursor = ports.cursor(); cursor.ok(); cursor.next()) {
157         Port p = (Port) cursor.current();
158         double d2 = getDistance(x, y, p);
159         if (d2 < dist) {
160           dist = d2;
161           closest = p;
162         }
163       }
164 
165       // assign the port
166       if (source) {
167         edge.setSourcePort(closest);
168       } else {
169         edge.setTargetPort(closest);
170       }
171     }
172 
173   }
174 
175   public static void main(String args[])
176   {
177     PortCreateEdgeModeDemo demo = new PortCreateEdgeModeDemo();
178     demo.start("Port Demo");
179   }
180 }
181 
182 
183       
184