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.realizer;
15  
16  import demo.view.DemoBase;
17  import y.base.Node;
18  import y.geom.OrientedRectangle;
19  import y.view.Arrow;
20  import y.view.BridgeCalculator;
21  import y.view.DefaultGraph2DRenderer;
22  import y.view.Drawable;
23  import y.view.EdgeLabel;
24  import y.view.Graph2D;
25  import y.view.ImageNodeRealizer;
26  import y.view.InterfacePort;
27  import y.view.LineType;
28  import y.view.NodeLabel;
29  import y.view.PolyLineEdgeRealizer;
30  import y.view.ShapeNodeRealizer;
31  import y.view.SmartEdgeLabelModel;
32  import y.view.SmartNodeLabelModel;
33  import y.view.YLabel;
34  import y.view.QuadCurveEdgeRealizer;
35  import y.view.Bend;
36  import y.view.GenericNodeRealizer;
37  import y.view.ShinyPlateNodePainter;
38  import y.view.BevelNodePainter;
39  import y.view.ArcEdgeRealizer;
40  
41  import javax.swing.Icon;
42  import javax.swing.ImageIcon;
43  import java.awt.Color;
44  import java.awt.Graphics2D;
45  import java.awt.Rectangle;
46  import java.awt.EventQueue;
47  import java.awt.geom.Ellipse2D;
48  import java.util.Locale;
49  import java.util.Set;
50  import java.util.Map;
51  
52  /**
53   * Demonstrates visual features and editor behaviour <ol>
54   * <p/>
55   * <li>EdgeLabels that display icons and text
56   * <p/>
57   * <li>Rotated Labels
58   * <p/>
59   * <li>Auto rotating EdgeLabels
60   * <p/>
61   * <li>Transparent colors
62   * <p/>
63   * <li>Gradients
64   * <p/>
65   * <li>Bridges for crossing PolyLine Edges
66   * <p/>
67   * <li>InterfacePorts that display icons. (A port defines the logical and visual endpoint of and edge path)
68   * <p/>
69   * <li>In edit mode you can reposition an edge label by pressing on it with the left mouse button and then by dragging
70   * the label around. For better orientation some edges provide snap lines with suitable label positions. The snap lines
71   * disappear, if the shift key is pressed down. Then the placement of labels at arbitrary positions is possible.
72   * <p/>
73   * <li>In edit mode you can interactively change the offsets of edge ports. Select the edge that should have different
74   * ports. A little black dot will appear at the point where the port has it's logical location. You can drag the black
75   * dot around. If you release the mouse again the offset of the port will be changed.
76   * <p/>
77   * <li>In edit mode you can create an edge that has non-zero port offsets by starting edge creation with the shift key
78   * pressed down. The point where you press will become the source port location of the edge. If you have the shift key
79   * down when you finish edge creation (by releasing the mouse over a node) that the release point will become the offset
80   * of the target port of the edge.
81   * <p/>
82   * </ol>
83   */
84  
85  public class VisualFeatureDemo extends DemoBase {
86    private static final String SHINY_NODE_CONFIGURATION = "ShinyNodeConfig";
87    private static final String BEVEL_NODE_CONFIGURATION = "BevelNodeConfig";
88  
89    public VisualFeatureDemo() {
90  
91      final Graph2D graph = view.getGraph2D();
92  
93  
94      // show bridges
95      ((DefaultGraph2DRenderer) view.getGraph2DRenderer()).setBridgeCalculator(new BridgeCalculator());
96  
97      ShapeNodeRealizer defaultNodeRealizer = new ShapeNodeRealizer();
98      // configure a drop shadow
99      defaultNodeRealizer.setDropShadowColor(new Color(0, 0, 0, 64));
100     defaultNodeRealizer.setDropShadowOffsetX((byte) 5);
101     defaultNodeRealizer.setDropShadowOffsetY((byte) 5);
102     defaultNodeRealizer.setSize(50, 50);
103     configureNodeLabel(defaultNodeRealizer.getLabel(), SmartNodeLabelModel.POSITION_CENTER);
104     //set to graph as default
105     graph.setDefaultNodeRealizer(defaultNodeRealizer);
106 
107 
108 
109     //Node 1 to show the line type of the node
110     ShapeNodeRealizer node1Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
111     node1Realizer.setCenter(50, 50);
112     node1Realizer.setLineColor(Color.BLUE);
113     node1Realizer.setLineType(LineType.DASHED_1);
114     node1Realizer.setFillColor(Color.ORANGE);
115     node1Realizer.setShapeType(ShapeNodeRealizer.DIAMOND);
116     final Node node1 = graph.createNode(node1Realizer);
117 
118 
119     //Node 2
120     ShapeNodeRealizer node2Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
121     node2Realizer.setCenter(250, 50);
122     node2Realizer.setLineColor(Color.GRAY);
123     node2Realizer.setLineType(LineType.LINE_1);
124     node2Realizer.setFillColor2(Color.CYAN);
125     node2Realizer.setFillColor(Color.WHITE);
126     node2Realizer.setShapeType(ShapeNodeRealizer.DIAMOND);
127     final Node node2 = graph.createNode(node2Realizer);
128 
129 
130     //Node 3 to show the line type of the node
131     ShapeNodeRealizer node3Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
132     node3Realizer.setCenter(400, 50);
133     node3Realizer.setLineColor(Color.BLACK);
134     node3Realizer.setLineType(LineType.LINE_1);
135     node3Realizer.setFillColor(new Color(192, 192, 192, 255));
136     node3Realizer.setFillColor2(null);
137     node3Realizer.setShapeType(ShapeNodeRealizer.ROUND_RECT);
138     final Node node3 = graph.createNode(node3Realizer);
139 
140     //Node 4
141     ShapeNodeRealizer node4Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
142     node4Realizer.setCenter(600, 50);
143     node4Realizer.setLineColor(Color.GRAY);
144     node4Realizer.setLineType(LineType.LINE_1);
145     node4Realizer.setFillColor(new Color(255, 102, 0, 255));
146     node4Realizer.setFillColor2(Color.ORANGE);
147     node4Realizer.setShapeType(ShapeNodeRealizer.TRAPEZOID_2);
148     final Node node4 = graph.createNode(node4Realizer);
149 
150     //Instance of edge realizer that will be default
151     PolyLineEdgeRealizer defaultEdgeRealizer = new PolyLineEdgeRealizer();
152     graph.setDefaultEdgeRealizer(defaultEdgeRealizer);
153 
154     //add an edge between 1 und 2
155     PolyLineEdgeRealizer edge1_2Realizer = new PolyLineEdgeRealizer();
156     edge1_2Realizer.setLineType(LineType.DASHED_1);
157     edge1_2Realizer.setSourceArrow(Arrow.STANDARD);
158     edge1_2Realizer.setTargetArrow(Arrow.WHITE_DIAMOND);
159     graph.createEdge(node1, node2, edge1_2Realizer);
160 
161     //add an edge between 2 und 3
162     PolyLineEdgeRealizer edge2_3Realizer = new PolyLineEdgeRealizer();
163     edge2_3Realizer.setLineType(LineType.DASHED_DOTTED_2);
164     edge2_3Realizer.setSourceArrow(Arrow.NONE);
165     edge2_3Realizer.setTargetArrow(Arrow.NONE);
166     graph.createEdge(node2, node3,edge2_3Realizer);
167 
168     //add an edge between 3 und 4
169     PolyLineEdgeRealizer edge3_4Realizer = new PolyLineEdgeRealizer();
170     edge3_4Realizer.setLineType(LineType.LINE_1);
171     edge3_4Realizer.setSourceArrow(Arrow.STANDARD);
172     edge3_4Realizer.setTargetArrow(Arrow.DIAMOND);
173     Bend bend1 = edge3_4Realizer.createBend(470.0, 70.0, null, Graph2D.AFTER);
174     Bend bend2 = edge3_4Realizer.createBend(530.0, 30.0, bend1, Graph2D.AFTER);
175     graph.createEdge(node3, node4,edge3_4Realizer);
176 
177     //Node 5
178     ShapeNodeRealizer node5Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
179     node5Realizer.setCenter(50, 150);
180     node5Realizer.setLineColor(Color.BLACK);
181     node5Realizer.setLineType(LineType.LINE_1);
182     node5Realizer.setFillColor(Color.ORANGE);
183     node5Realizer.setFillColor2(null);
184     node5Realizer.setShapeType(ShapeNodeRealizer.TRIANGLE);
185     final Node node5 = graph.createNode(node5Realizer);
186 
187     //Node 6
188     ShapeNodeRealizer node6Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
189     node6Realizer.setCenter(250, 150);
190     node6Realizer.setLineColor(Color.BLACK);
191     node6Realizer.setLineType(LineType.LINE_1);
192     node6Realizer.setFillColor(new Color(255, 204, 0, 255));
193     node6Realizer.setShapeType(ShapeNodeRealizer.HEXAGON);
194     final Node node6 = graph.createNode(node6Realizer);
195 
196 
197     //Configure  new node realizers with specific painters
198     GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();
199     Map configurationMap = factory.createDefaultConfigurationMap();
200 
201     // ShinyPlateNodePainter has an option to draw a drop shadow that is more efficient
202     // than wrapping it in a ShadowNodePainter.
203     ShinyPlateNodePainter shinyPlateNodePainter = new ShinyPlateNodePainter();
204     shinyPlateNodePainter.setRadius(10);
205     shinyPlateNodePainter.setDrawShadow(true);
206     configurationMap.put(GenericNodeRealizer.Painter.class, shinyPlateNodePainter);
207     configurationMap.put(GenericNodeRealizer.ContainsTest.class, shinyPlateNodePainter);
208     factory.addConfiguration(SHINY_NODE_CONFIGURATION, configurationMap);
209 
210     BevelNodePainter bevelNodePainter = new BevelNodePainter();
211     bevelNodePainter.setDrawShadow(true);
212     configurationMap.put(GenericNodeRealizer.Painter.class, bevelNodePainter);
213     configurationMap.put(GenericNodeRealizer.ContainsTest.class, bevelNodePainter);
214     factory.addConfiguration(BEVEL_NODE_CONFIGURATION, configurationMap);
215 
216 
217     //Node 7
218     GenericNodeRealizer gnr_shiny = new GenericNodeRealizer(SHINY_NODE_CONFIGURATION);
219     gnr_shiny.setLineColor(new Color(255, 153, 0, 255));
220     gnr_shiny.setFillColor(new Color(255, 153, 0, 255));
221     gnr_shiny.setSize(50, 50);
222     gnr_shiny.setCenter(400, 150);
223     configureNodeLabel(gnr_shiny.getLabel(), SmartNodeLabelModel.POSITION_CENTER);
224     Node node7 = graph.createNode(gnr_shiny);
225 
226     //Node 8
227     GenericNodeRealizer gnr_bevel = new GenericNodeRealizer(BEVEL_NODE_CONFIGURATION);
228     gnr_bevel.setLineColor(new Color(255, 153, 0, 255));
229     gnr_bevel.setFillColor(new Color(255, 153, 0, 255));
230     gnr_bevel.setSize(50, 50);
231     gnr_bevel.setCenter(600, 150);
232     configureNodeLabel(gnr_bevel.getLabel(), SmartNodeLabelModel.POSITION_CENTER);
233     Node node8 = graph.createNode(gnr_bevel);
234 
235 
236     //add an edge between 1 und 5
237     PolyLineEdgeRealizer edge1_5Realizer = new PolyLineEdgeRealizer();
238     edge1_5Realizer.setSourceArrow(Arrow.NONE);
239     edge1_5Realizer.setTargetArrow(Arrow.SKEWED_DASH);
240     graph.createEdge(node1, node5, edge1_5Realizer);
241 
242     //add an edge between 5 und 6
243     PolyLineEdgeRealizer edge5_6Realizer = new PolyLineEdgeRealizer();
244     edge5_6Realizer.setSourceArrow(Arrow.WHITE_DELTA);
245     edge5_6Realizer.setTargetArrow(Arrow.STANDARD);
246     graph.createEdge(node5, node6, edge5_6Realizer);
247 
248     //add an edge between 6 und 6 (itself)
249     PolyLineEdgeRealizer edge6_6Realizer = new PolyLineEdgeRealizer();
250     edge6_6Realizer.setTargetArrow(Arrow.STANDARD);
251     graph.createEdge(node6, node6, edge6_6Realizer);
252 
253     //add an edge between 6 und 7
254     PolyLineEdgeRealizer edge6_7Realizer = new PolyLineEdgeRealizer();
255     edge6_7Realizer.setSourceArrow(Arrow.NONE);
256     edge6_7Realizer.setTargetArrow(Arrow.NONE);
257     graph.createEdge(node6, node7, edge6_7Realizer);
258 
259     //add an edge between 7 und 8
260     PolyLineEdgeRealizer edge7_8Realizer = new PolyLineEdgeRealizer();
261     edge7_8Realizer.setSourceArrow(Arrow.WHITE_DELTA);
262     edge7_8Realizer.setTargetArrow(Arrow.WHITE_DIAMOND);
263     EdgeLabel labelFor7_8_Edge = edge7_8Realizer.getLabel();
264     labelFor7_8_Edge.setText("EDGE LABEL");
265     configureEdgeLabel(labelFor7_8_Edge, SmartEdgeLabelModel.POSITION_RIGHT);
266     graph.createEdge(node7, node8,edge7_8Realizer);
267 
268     //Node 9
269     ShapeNodeRealizer node9Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
270     node9Realizer.setCenter(50, 250);
271     node9Realizer.setLineColor(Color.BLACK);
272     node9Realizer.setLineType(LineType.LINE_1);
273     node9Realizer.setFillColor(new Color(153, 204, 255, 255));
274     node9Realizer.setFillColor2(null);
275     node9Realizer.setShapeType(ShapeNodeRealizer.OCTAGON);
276     final Node node9 = graph.createNode(node9Realizer);
277 
278     //Node 10 (image node realizer)
279     // display an ImageNodeRealizer
280     ImageNodeRealizer imageNodeRealizer = new ImageNodeRealizer();
281     imageNodeRealizer.setImageURL(getClass().getResource("/demo/view/resource/yicon.png"));
282     imageNodeRealizer.setAlphaImageUsed(true);
283     imageNodeRealizer.setCenter(250, 250);
284     imageNodeRealizer.setToImageSize();
285     imageNodeRealizer.setSize(40,50);
286     configureNodeLabel(imageNodeRealizer.getLabel(), SmartNodeLabelModel.POSITION_CENTER);
287     final Node node10 = graph.createNode(imageNodeRealizer);
288 
289 
290     // Edge and arrows
291     //setup source arrow drawable
292     Drawable drawable = new Drawable() {
293       public void paint(Graphics2D g) {
294         Color color = g.getColor();
295         g.setColor(Color.yellow);
296         Ellipse2D.Double ellipse = new Ellipse2D.Double(-20, -10, 20, 20);
297         g.fill(ellipse);
298         g.setColor(Color.orange);
299         g.draw(ellipse);
300         g.setColor(Color.black);
301         g.drawString("A", -13, 5);
302         g.setColor(color);
303       }
304 
305       public Rectangle getBounds() {
306         return new Rectangle(-20, -20, 20, 20);
307       }
308     };
309 
310     PolyLineEdgeRealizer edge9_10Realizer = new PolyLineEdgeRealizer();
311     edge9_10Realizer.setSourceArrow(Arrow.addCustomArrow("coolArrow", drawable, 20, 3));
312     // choose smooth bends
313     edge9_10Realizer.setSmoothedBends(true);
314 
315     // choose a thicker line
316     edge9_10Realizer.setLineType(LineType.LINE_2);
317 
318     Icon icon;
319     //setup edge label
320     EdgeLabel labelForEdge9_10 = edge9_10Realizer.getLabel();
321     labelForEdge9_10.setText("rotated edge label");
322     configureEdgeLabel(labelForEdge9_10, SmartEdgeLabelModel.POSITION_RIGHT);
323     labelForEdge9_10.setRotationAngle(15);
324     icon = new ImageIcon(getClass().getResource("resource/about24.gif"));
325     labelForEdge9_10.setIcon(icon);
326 
327     //setup visual source port
328     icon = new ImageIcon(getClass().getResource("resource/info24.gif"));
329     InterfacePort p = new InterfacePort();
330     p.setIcon(icon);
331     edge9_10Realizer.setSourcePort(p);
332 
333     //setup visual target port
334     icon = new ImageIcon(getClass().getResource("resource/home16.gif"));
335     p = new InterfacePort();
336     p.setIcon(icon);
337     edge9_10Realizer.setTargetPort(p);
338 
339     //add an edge between 9 und 10
340     graph.createEdge(node9, node10, edge9_10Realizer);
341 
342 
343     //Node 11
344     GenericNodeRealizer gnr_shiny2 = new GenericNodeRealizer(SHINY_NODE_CONFIGURATION);
345     gnr_shiny2.setLineColor(new Color(255, 153, 0, 255));
346     gnr_shiny2.setFillColor(new Color(255, 153, 0, 255));
347     gnr_shiny2.setSize(15, 50);
348     gnr_shiny2.setCenter(400, 250);
349     configureNodeLabel(gnr_shiny2.getLabel(), SmartNodeLabelModel.POSITION_CENTER);
350     Node node11 = graph.createNode(gnr_shiny2);
351 
352     //Edge 10 11
353     PolyLineEdgeRealizer edge10_11Realizer = new PolyLineEdgeRealizer();
354     edge10_11Realizer.setTargetArrow(Arrow.CONVEX);
355     graph.createEdge(node10, node11, edge10_11Realizer);
356 
357     //Node 12
358     ShapeNodeRealizer node12Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
359     node12Realizer.setCenter(600, 250);
360     node12Realizer.setLineColor(Color.BLACK);
361     node12Realizer.setLineType(LineType.LINE_1);
362     node12Realizer.setFillColor(new Color(255, 102, 0, 255));
363     node12Realizer.setFillColor2(new Color(255, 153, 0, 255));
364     node12Realizer.setShapeType(ShapeNodeRealizer.PARALLELOGRAM);
365     final Node node12 = graph.createNode(600, 250);
366 
367     //Quadratic curve edge for nodes 11 und 12
368     QuadCurveEdgeRealizer quadCurveEdgeRealizer = new QuadCurveEdgeRealizer();
369     quadCurveEdgeRealizer.setTargetArrow(Arrow.STANDARD);
370     graph.createEdge(node11, node12, quadCurveEdgeRealizer);
371     //add symterical bedns on the edge
372     double bendStartX = quadCurveEdgeRealizer.getSourceIntersection().getX();
373     double bendEndX = quadCurveEdgeRealizer.getTargetIntersection().getX();
374     //calculate the y - middle between source and target to alternate the position of the bends
375     double bendStartEndY = (quadCurveEdgeRealizer.getSourceIntersection().getY() + quadCurveEdgeRealizer.getTargetIntersection().getY())/2;
376     Bend lastBend = null;
377     int numberOfBends = 10;
378     double deltaX = (bendEndX - bendStartX) / numberOfBends;
379     double x = bendStartX;
380     double y = 0;
381     for (int i = 0; i < numberOfBends; i++) {
382       x = x + deltaX;
383       if (i % 2 == 0) {
384         y = bendStartEndY - 25;
385       } else {
386         y = bendStartEndY + 25;
387       }
388       lastBend = quadCurveEdgeRealizer.createBend(x, y, lastBend, Graph2D.AFTER);
389     }
390 
391     //Node 13
392     // reconfigure the default NodeRealizer
393     ShapeNodeRealizer node13Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
394     node13Realizer.setShapeType(ShapeNodeRealizer.ELLIPSE);
395     node13Realizer.setCenter(50, 350);
396     node13Realizer.setFillColor(Color.YELLOW);
397     final NodeLabel nodeLabel = node13Realizer.getLabel();
398     nodeLabel.setText("<html><b><font color=\"red\">HTML</b><br/>labels!</html>");
399     configureNodeLabel(nodeLabel, SmartNodeLabelModel.POSITION_SOUTH);
400     Node node13 = graph.createNode(node13Realizer);
401 
402     //Node 14
403     ShapeNodeRealizer node14Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
404     node14Realizer.setShapeType(ShapeNodeRealizer.ELLIPSE);
405     node14Realizer.setSize(50, 50);
406     node14Realizer.setCenter(250,350);
407     node14Realizer.setFillColor(Color.red);
408     node14Realizer.setFillColor2(Color.yellow);
409     final NodeLabel node14Label = node14Realizer.getLabel();
410     node14Label.setFontSize(8);
411     node14Label.setText("Transparency! and automatically cropped text for custom label size!.");
412     Set configurations = NodeLabel.getFactory().getAvailableConfigurations();
413     // set a custom configuration for the label
414     if (configurations.contains("CroppingLabel")) {
415       node14Label.setConfiguration("CroppingLabel");
416       node14Label.setAutoSizePolicy(YLabel.AUTOSIZE_NONE);
417       node14Label.setContentSize(40, 40);
418     }
419     node14Label.setRotationAngle(45);
420     node14Label.setBackgroundColor(new Color(255, 255, 255, 128));
421     node14Label.setLineColor(Color.GRAY);
422     Node node14 = graph.createNode(node14Realizer);
423 
424     // add an edge from node 13 to 14
425     final ArcEdgeRealizer arcEdgeRealizer = new ArcEdgeRealizer();
426     arcEdgeRealizer.setTargetArrow(Arrow.STANDARD);
427     arcEdgeRealizer.setLineType(LineType.DOTTED_2);
428     EdgeLabel edge13_14Label = arcEdgeRealizer.getLabel();
429     edge13_14Label.setText("Arc edge");
430     edge13_14Label.setModel(EdgeLabel.FREE);
431     graph.createEdge(node14, node13, arcEdgeRealizer);
432     final OrientedRectangle labelBounds = edge13_14Label.getOrientedBox();
433     final Object newParam = edge13_14Label.getBestModelParameterForBounds(labelBounds.getMovedInstance(-80, 40));
434     edge13_14Label.setModelParameter(newParam);
435 
436 
437      //Node 15
438     ShapeNodeRealizer node15Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
439     node15Realizer.setShapeType(ShapeNodeRealizer.RECT_3D);
440     node15Realizer.setSize(50, 50);
441     node15Realizer.setCenter(400,350);
442     node15Realizer.setFillColor(Color.red);
443     node15Realizer.setFillColor2(Color.yellow);
444     final NodeLabel node15Label = node15Realizer.getLabel();
445     node15Label.setFontSize(8);
446     node15Label.setText("Transparency! and automatically cropped text for custom label size!.");
447     
448     // set a custom configuration for the label
449     if (configurations.contains("CroppingLabel")) {
450       node15Label.setConfiguration("CroppingLabel");
451       node15Label.setAutoSizePolicy(YLabel.AUTOSIZE_NONE);
452       node15Label.setContentSize(50, 50);
453     }
454     node15Label.setRotationAngle(45);
455     node15Label.setBackgroundColor(new Color(255, 255, 255, 128));
456     node15Label.setLineColor(Color.GRAY);
457     Node node15 = graph.createNode(node15Realizer);
458 
459     //Node 16
460     // reconfigure the default NodeRealizer
461     ShapeNodeRealizer node16Realizer = new ShapeNodeRealizer(graph.getDefaultNodeRealizer());
462     node16Realizer.setCenter(600, 350);
463     node16Realizer.setShapeType(ShapeNodeRealizer.ELLIPSE);
464     node16Realizer.setFillColor(Color.WHITE);
465     node16Realizer.setLineColor(new Color(255,80,0,255));
466     node16Realizer.setLineType(LineType.LINE_4);
467     final NodeLabel node16Label = node16Realizer.getLabel();
468     node16Label.setText("<html><b>1,2,3...</b></html>");
469     Node node16 = graph.createNode(node16Realizer);
470 
471     //Edge 14 15
472     PolyLineEdgeRealizer edge14_15Realizer = new PolyLineEdgeRealizer();
473     edge14_15Realizer.setTargetArrow(Arrow.addCustomArrow("offsetArrow", Arrow.T_SHAPE, 20));
474     graph.createEdge(node14, node15, edge14_15Realizer);
475 
476     //Edge 15 16
477     PolyLineEdgeRealizer edge15_16Realizer = new PolyLineEdgeRealizer();
478     edge15_16Realizer.setTargetArrow(Arrow.STANDARD);
479     graph.createEdge(node15, node16, edge15_16Realizer);
480 
481     //Edge 4 8
482     PolyLineEdgeRealizer edge4_8Realizer = new PolyLineEdgeRealizer();
483     edge4_8Realizer.setLineType(LineType.DOTTED_2);
484     EdgeLabel edge4_8Label = edge4_8Realizer.getLabel();
485     edge4_8Label.setText("Dotted");
486     configureEdgeLabel(edge4_8Label, SmartEdgeLabelModel.POSITION_LEFT);
487     graph.createEdge(node4, node8, edge4_8Realizer);
488 
489     // add an edge from node 16 to 12
490     final ArcEdgeRealizer arcEdge16_12Realizer = new ArcEdgeRealizer();
491     arcEdge16_12Realizer.setTargetArrow(Arrow.STANDARD);
492     arcEdge16_12Realizer.setLineType(LineType.DOTTED_1);
493     graph.createEdge(node16, node12, arcEdge16_12Realizer);
494 
495 
496 
497 
498   }
499 
500   private void configureEdgeLabel(EdgeLabel label, int position) {
501     final SmartEdgeLabelModel model = new SmartEdgeLabelModel();
502     label.setLabelModel(model);
503     label.setModelParameter(model.createDiscreteModelParameter(position));
504   }
505 
506   private void configureNodeLabel(NodeLabel label, int position) {
507     SmartNodeLabelModel model = new SmartNodeLabelModel();
508     label.setLabelModel(model);
509     label.setModelParameter(model.createDiscreteModelParameter(position));
510   }
511 
512   public static void main(String[] args) {
513     EventQueue.invokeLater(new Runnable() {
514       public void run() {
515         Locale.setDefault(Locale.ENGLISH);
516         initLnF();
517         (new VisualFeatureDemo()).start("Visual Feature Demo");
518       }
519     });
520   }
521 }
522 
523 
524