1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.9. 
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-2011 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 demo.view.DemoDefaults;
19  import y.base.Edge;
20  import y.base.Node;
21  import y.base.YCursor;
22  import y.base.YList;
23  import y.view.CreateEdgeMode;
24  import y.view.EdgeRealizer;
25  import y.view.EditMode;
26  import y.view.Graph2D;
27  import y.view.NodeRealizer;
28  import y.view.Port;
29  
30  import java.awt.EventQueue;
31  import java.util.Locale;
32  
33  /**
34   * Demonstrates how {@link CreateEdgeMode} can be customized in order to
35   * control automatic assignments of ports for edges.
36   * Edges are created in such a way, that the source port is always on
37   * the top side of the source node and the target port is always on the bottom
38   * side of the target node.
39   * <p>
40   * Usage: Create some nodes and edges. Select an edge to check its source
41   * and target ports.
42   * </p>
43   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/mvc_controller.html#custom_edit_mode">Section User Interaction</a> in the yFiles for Java Developer's Guide
44   */
45  public class PortCreateEdgeModeDemo extends DemoBase
46  {
47    protected void initialize() {
48      super.initialize();
49      loadGraph("resource/PortCreateEdgeModeDemo.graphml");
50      DemoDefaults.applyRealizerDefaults(view.getGraph2D());
51    }
52  
53    protected void registerViewModes() {
54      EditMode editMode = new EditMode();
55      view.addViewMode( editMode );
56      //set a custom CreateEdgeMode for the edge mode
57      editMode.setCreateEdgeMode( new PortCreateEdgeMode() );
58    }
59  
60    public static class PortCreateEdgeMode extends CreateEdgeMode
61    {
62      private Edge edge; // need this for the hook
63  
64      /**
65       * If a node was hit at the given coordinates, that node
66       * will be used as target node for the newly created edge.
67       *
68       */
69      public void mouseReleasedLeft(double x, double y)
70      {
71        // simulate a pressed shift...
72        // this will trigger CreateEdgeMode, to preassign offset
73        // to source and target ports
74        super.mouseShiftReleasedLeft(x, y);
75  
76        if (edge != null){ // the edge has just been created
77          Graph2D graph = (Graph2D) edge.getGraph();
78          EdgeRealizer er = graph.getRealizer(edge);
79  
80          // get a list of port candidates
81          YList ports = getPorts(edge.source(), edge);
82          Port p = er.getSourcePort();
83          // snap to one of them
84          snap(er, true, p.getOffsetX(), p.getOffsetY(), ports);
85  
86          // get a list of port candidates
87          ports = getPorts(edge.target(), edge);
88          p = er.getTargetPort();
89          // snap to one of them
90          snap(er, false, p.getOffsetX(), p.getOffsetY(), ports);
91  
92          // do some clean up
93          edge = null;
94          graph.updateViews();
95        }
96  
97      }
98  
99      /**
100      * Initiates the creation of an edge.
101      * 
102      */
103     public void mousePressedLeft(double x, double y)
104     {
105       // simulate a pressed shift...
106       // this will trigger CreateEdgeMode, to preassign offset
107       // to source and target ports
108       super.mouseShiftPressedLeft(x, y);
109     }
110 
111 
112     public void edgeCreated(Edge e){
113       //remember the edge...
114       this.edge = e;
115     }
116 
117     /**
118      * This method finds a list of Port objects for a specific edge/node pair
119      *
120      * @param onNode  the node
121      * @param forEdge the edge
122      * @return a list of Port objects
123      */
124     public YList getPorts(Node onNode, Edge forEdge) {
125       YList list = new YList();
126       Graph2D graph = (Graph2D) onNode.getGraph();
127       NodeRealizer nr = graph.getRealizer(onNode);
128       EdgeRealizer er = graph.getRealizer(forEdge);
129 
130       if (onNode == forEdge.source()) {
131         // source ports are centered on bottom of the node
132         list.add(new Port(0, nr.getHeight() / 2));
133       } else {
134         // target ports are centered at the top of the node
135         list.add(new Port(0, -nr.getHeight() / 2));
136       }
137       return list;
138     }
139 
140     /**
141      * This method calculates a metric for ports and points
142      *
143      * @param x    the initial x offset
144      * @param y    the initial y offset
145      * @param port the port
146      * @return the distance between the point (x,y) and the port
147      */
148     public static double getDistance(double x, double y, Port port) {
149       return Math.sqrt((x - port.getOffsetX()) * (x - port.getOffsetX())
150           + (y - port.getOffsetY()) * (y - port.getOffsetY()));
151     }
152 
153     /**
154      * This method chooses from a list of given ports for an edge
155      * a suitable port, given an initial placement.
156      *
157      * @param edge   the affected edge
158      * @param source whether we look at the source node
159      * @param x      the initial x offset
160      * @param y      the initial y offset
161      * @param ports  a list of Port objects (candidates)
162      */
163     public void snap(EdgeRealizer edge, boolean source, double x, double y, YList ports) {
164       if (ports == null || ports.size() < 1) {
165         return; // do nothing
166       }
167 
168       // find the closest port with regards to the getDistance function
169       Port closest = (Port) ports.first();
170       double dist = getDistance(x, y, closest);
171 
172       for (YCursor cursor = ports.cursor(); cursor.ok(); cursor.next()) {
173         Port p = (Port) cursor.current();
174         double d2 = getDistance(x, y, p);
175         if (d2 < dist) {
176           dist = d2;
177           closest = p;
178         }
179       }
180 
181       // assign the port
182       if (source) {
183         edge.setSourcePort(closest);
184       } else {
185         edge.setTargetPort(closest);
186       }
187     }
188 
189   }
190 
191   public static void main(String[] args) {
192     EventQueue.invokeLater(new Runnable() {
193       public void run() {
194         Locale.setDefault(Locale.ENGLISH);
195         initLnF();
196         (new PortCreateEdgeModeDemo()).start();
197       }
198     });
199   }
200 }
201 
202 
203       
204