1   /****************************************************************************
2    * This demo file is part of yFiles for Java 2.14.
3    * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4    * 72070 Tuebingen, Germany. All rights reserved.
5    * 
6    * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7    * of demo files in source code or binary form, with or without
8    * modification, is not permitted.
9    * 
10   * Owners of a valid software license for a yFiles for Java version that this
11   * demo is shipped with are allowed to use the demo source code as basis
12   * for their own yFiles for Java powered applications. Use of such programs is
13   * governed by the rights and conditions as set out in the yFiles for Java
14   * license agreement.
15   * 
16   * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19   * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   *
27   ***************************************************************************/
28  package demo.view.viewmode;
29  
30  
31  import demo.view.DemoBase;
32  import demo.view.DemoDefaults;
33  import y.base.Edge;
34  import y.base.Node;
35  import y.base.YCursor;
36  import y.base.YList;
37  import y.view.CreateEdgeMode;
38  import y.view.EdgeRealizer;
39  import y.view.EditMode;
40  import y.view.Graph2D;
41  import y.view.NodeRealizer;
42  import y.view.Port;
43  
44  import java.awt.EventQueue;
45  import java.util.Locale;
46  
47  /**
48   * Demonstrates how {@link CreateEdgeMode} can be customized in order to
49   * control automatic assignments of ports for edges.
50   * Edges are created in such a way, that the source port is always on
51   * the top side of the source node and the target port is always on the bottom
52   * side of the target node.
53   * <p>
54   * Usage: Create some nodes and edges. Select an edge to check its source
55   * and target ports.
56   * </p>
57   * @see <a href="http://docs.yworks.com/yfiles/doc/api/index.html#/dguide/mvc_controller#custom_edit_mode" target="_blank">Section User Interaction</a> in the yFiles for Java Developer's Guide
58   */
59  public class PortCreateEdgeModeDemo extends DemoBase
60  {
61    protected void initialize() {
62      super.initialize();
63      loadGraph("resource/PortCreateEdgeModeDemo.graphml");
64      DemoDefaults.applyRealizerDefaults(view.getGraph2D());
65    }
66  
67    protected void registerViewModes() {
68      EditMode editMode = new EditMode();
69      view.addViewMode( editMode );
70      //set a custom CreateEdgeMode for the edge mode
71      editMode.setCreateEdgeMode( new PortCreateEdgeMode() );
72    }
73  
74    public static class PortCreateEdgeMode extends CreateEdgeMode
75    {
76      private Edge edge; // need this for the hook
77  
78      /**
79       * If a node was hit at the given coordinates, that node
80       * will be used as target node for the newly created edge.
81       *
82       */
83      public void mouseReleasedLeft(double x, double y)
84      {
85        // simulate a pressed shift...
86        // this will trigger CreateEdgeMode, to preassign offset
87        // to source and target ports
88        super.mouseShiftReleasedLeft(x, y);
89  
90        if (edge != null){ // the edge has just been created
91          Graph2D graph = (Graph2D) edge.getGraph();
92          EdgeRealizer er = graph.getRealizer(edge);
93  
94          // get a list of port candidates
95          YList ports = getPorts(edge.source(), edge);
96          Port p = er.getSourcePort();
97          // snap to one of them
98          snap(er, true, p.getOffsetX(), p.getOffsetY(), ports);
99  
100         // get a list of port candidates
101         ports = getPorts(edge.target(), edge);
102         p = er.getTargetPort();
103         // snap to one of them
104         snap(er, false, p.getOffsetX(), p.getOffsetY(), ports);
105 
106         // do some clean up
107         edge = null;
108         graph.updateViews();
109       }
110 
111     }
112 
113     /**
114      * Initiates the creation of an edge.
115      * 
116      */
117     public void mousePressedLeft(double x, double y)
118     {
119       // simulate a pressed shift...
120       // this will trigger CreateEdgeMode, to preassign offset
121       // to source and target ports
122       super.mouseShiftPressedLeft(x, y);
123     }
124 
125 
126     public void edgeCreated(Edge e){
127       //remember the edge...
128       this.edge = e;
129     }
130 
131     /**
132      * This method finds a list of Port objects for a specific edge/node pair
133      *
134      * @param onNode  the node
135      * @param forEdge the edge
136      * @return a list of Port objects
137      */
138     public YList getPorts(Node onNode, Edge forEdge) {
139       YList list = new YList();
140       Graph2D graph = (Graph2D) onNode.getGraph();
141       NodeRealizer nr = graph.getRealizer(onNode);
142       EdgeRealizer er = graph.getRealizer(forEdge);
143 
144       if (onNode == forEdge.source()) {
145         // source ports are centered on bottom of the node
146         list.add(new Port(0, nr.getHeight() / 2));
147       } else {
148         // target ports are centered at the top of the node
149         list.add(new Port(0, -nr.getHeight() / 2));
150       }
151       return list;
152     }
153 
154     /**
155      * This method calculates a metric for ports and points
156      *
157      * @param x    the initial x offset
158      * @param y    the initial y offset
159      * @param port the port
160      * @return the distance between the point (x,y) and the port
161      */
162     public static double getDistance(double x, double y, Port port) {
163       return Math.sqrt((x - port.getOffsetX()) * (x - port.getOffsetX())
164           + (y - port.getOffsetY()) * (y - port.getOffsetY()));
165     }
166 
167     /**
168      * This method chooses from a list of given ports for an edge
169      * a suitable port, given an initial placement.
170      *
171      * @param edge   the affected edge
172      * @param source whether we look at the source node
173      * @param x      the initial x offset
174      * @param y      the initial y offset
175      * @param ports  a list of Port objects (candidates)
176      */
177     public void snap(EdgeRealizer edge, boolean source, double x, double y, YList ports) {
178       if (ports == null || ports.size() < 1) {
179         return; // do nothing
180       }
181 
182       // find the closest port with regards to the getDistance function
183       Port closest = (Port) ports.first();
184       double dist = getDistance(x, y, closest);
185 
186       for (YCursor cursor = ports.cursor(); cursor.ok(); cursor.next()) {
187         Port p = (Port) cursor.current();
188         double d2 = getDistance(x, y, p);
189         if (d2 < dist) {
190           dist = d2;
191           closest = p;
192         }
193       }
194 
195       // assign the port
196       if (source) {
197         edge.setSourcePort(closest);
198       } else {
199         edge.setTargetPort(closest);
200       }
201     }
202 
203   }
204 
205   public static void main(String[] args) {
206     EventQueue.invokeLater(new Runnable() {
207       public void run() {
208         Locale.setDefault(Locale.ENGLISH);
209         initLnF();
210         (new PortCreateEdgeModeDemo()).start();
211       }
212     });
213   }
214 }
215 
216 
217       
218