1   /****************************************************************************
2    **
3    ** This file is part of the yFiles extension package ySVG-2.3.
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) 2002-2010 by yWorks GmbH, Vor dem Kreuzberg 28,
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.yext.svg;
15  
16  import yext.svg.io.SVGDOMEnhancer;
17  import yext.svg.io.SVGIOHandler;
18  
19  import y.base.Edge;
20  import y.base.Node;
21  import y.option.OptionHandler;
22  import y.view.EdgeLabel;
23  import y.view.EdgeRealizer;
24  import y.view.EditMode;
25  import y.view.HitInfo;
26  import y.view.NodeLabel;
27  import y.view.NodeRealizer;
28  import y.view.ViewMode;
29  
30  import java.awt.EventQueue;
31  import java.util.HashMap;
32  import java.util.Map;
33  
34  /** 
35   * Demonstrates how to write SVG that hyperlinks nodes, edges and labels of a graph. 
36   * <p>
37   * Basic Usage: After nodes, edges and labels have been created in the editor it is 
38   * possible to associate an URL with these objects by right clicking on them.  
39   */
40  public class HyperlinkDemo extends SVGExportDemo
41  {
42    //Map used to store URLs for nodes, edges and labels.
43    Map linkMap;
44    
45    /**
46     * Instantiates HyperlinkDemo
47     */
48    public HyperlinkDemo()
49    {
50      //add right click handler
51      view.addViewMode(new RightClickMode());
52      
53      //configure default edge
54      EdgeRealizer er = view.getGraph2D().getDefaultEdgeRealizer();
55      EdgeLabel el = er.getLabel();
56      el.setText("EDGE LABEL");
57  
58      //configure default node
59      NodeRealizer nr = view.getGraph2D().getDefaultNodeRealizer();
60      nr.setSize(120, 40);
61      NodeLabel nl = nr.getLabel();
62      nl.setText("LABEL");
63      linkMap = new HashMap();
64    }
65    
66    /**
67     * Create an edit mode that displays the URL
68     * of a node as tooltip.
69     */
70    protected EditMode createEditMode()
71    {
72      EditMode editMode = new EditMode() {
73        public String getNodeTip(Node v) {
74          String url = (String)linkMap.get(v);
75          if(url != null)
76          {
77            return "<html>URL: <b>" + url + "</b></html>";
78          }
79          else
80          {
81            return "<html>No URL assigned to node. <br><b>Right click on node</b></html>";
82          }
83        }
84      };
85      editMode.showNodeTips(true);
86      return editMode;
87    }
88    
89    /**
90     * Creates and configures the SVGIOHandlers to be used.
91     * This method will add a specialized SVGDOMEnhancer to
92     * the IOHandler.
93     */
94    protected SVGIOHandler createSVGIOHandler(boolean svgz)
95    {
96      SVGIOHandler ioh = super.createSVGIOHandler(svgz);
97      SVGDOMEnhancer enhancer = new HttpLinksEnhancer();
98      ioh.setSVGGraph2DRenderer(enhancer);
99      return ioh;
100   }
101   
102   /**
103    * A custom SVGDOMEnhancer. This class will add hyperlink statements 
104    * around each node, node label, edge and
105    * edge label for which the user has given a URL.
106    */
107   class HttpLinksEnhancer extends SVGDOMEnhancer
108   {
109     protected void initializeDOM() {
110       final String function =
111               "function yhref(evt) {\n" +
112               "  if (evt.charAt(0) != '#') {\n" +
113               "    window.parent.location.href = evt;\n" +
114               "  } else {\n" +
115               "    window.parent.location.hash = evt;\n" +
116               "  }\n" +
117               "}";
118       org.w3c.dom.Element script = createElement("script");
119       script.setAttribute("type", "text/ecmascript");
120       script.appendChild(createCDATASection(function));
121       addToSVGDefinition(script);
122     }
123 
124     /**
125      * Override a callback method. Hyperlink the given node.
126      */
127     protected void nodeAddedToDOM(Node yNode, org.w3c.dom.Element element)
128     {
129       insertLink(yNode, element, true);
130     }
131     
132     /**
133      * Override a callback method. Hyperlink the given edge.
134      */
135     protected void edgeAddedToDOM(Edge yEdge, org.w3c.dom.Element element)
136     {
137       insertLink(yEdge, element, true);
138     }
139     
140     
141     /**
142      * Override a callback method. Hyperlink the given node label.
143      */
144     protected void nodeLabelAddedToDOM(NodeLabel yNodeLabel, org.w3c.dom.Element element)
145     {
146       insertLink(yNodeLabel, element, false);
147     }
148 
149     /**
150      * Override a callback method. Hyperlink the given edge label.
151      */
152     protected void edgeLabelAddedToDOM(EdgeLabel yEdgeLabel, org.w3c.dom.Element element)
153     {
154       insertLink(yEdgeLabel, element, false);
155     }
156     
157     /**
158      * Inserts a new hyperlink element in the dom tree. The URL of the hyperlink
159      * will be looked up in <code>linkMap</code>.
160      * @param item the graph item (node, node label, edge, or edge label) for
161      * which a hyperlink is created.
162      * @param element the DOM element representing the specified graph item in
163      * the generated SVG document.
164      * @param notALabel <code>true</code> if the specified graph element is
165      * neither a node label nor an edge label; <code>false</code> otherwise.
166      */   
167     private void insertLink(Object item, org.w3c.dom.Element element, boolean notALabel)
168     {
169       String url = (String)linkMap.get(item);
170       if(url != null) {
171         if (notALabel) {
172           org.w3c.dom.Element a = createElement("a");
173           element.setAttribute("onclick", "yhref('" + url + "')");
174           insertNodeBelow(a, element);
175         } else {
176           if (!"text".equals(element.getLocalName())) {
177             org.w3c.dom.NodeList text = element.getElementsByTagName("text");
178             element = text.getLength() > 0 ? (org.w3c.dom.Element)text.item(0) : null;
179           }
180           if (element != null) {
181             element.setAttribute("onclick", "yhref('" + url + "')");
182           }
183         }
184       }
185     }
186   }
187   
188   /**
189    * ViewMode reponsible for processing a right mouse click.
190    * Right clicking on nodes, edges and labels will bring up
191    * an option handler that allows to enter a URL for each item.
192    * Hyperlinks to these URLs will be integrated in the SVG output.
193    */   
194   class RightClickMode extends ViewMode
195   {
196     public void mouseReleasedRight(double x, double y)
197     {
198       HitInfo hitInfo = new HitInfo(view, x, y, true);
199 
200       if(hitInfo.getHitNodeLabel() != null)
201       {
202         editLinkInfo(hitInfo.getHitNodeLabel(), "node label");
203       }
204       else if(hitInfo.getHitEdgeLabel() != null)
205       {
206         editLinkInfo(hitInfo.getHitEdgeLabel(), "edge label");
207       }
208       else if(hitInfo.getHitNode() != null)
209       {
210         editLinkInfo(hitInfo.getHitNode(), "node");
211       }
212       else if(hitInfo.getHitEdge() != null)
213       {
214         editLinkInfo(hitInfo.getHitEdge(), "edge");
215       }
216     }
217     
218     void editLinkInfo(Object key, String type)
219     {
220       OptionHandler op = new OptionHandler("Hyperlink for " + type);
221       String url = (String)linkMap.get(key);
222       if(url != null)
223       {
224         op.addString("Hyperlink URL",url);
225       }
226       else
227       {
228         op.addString("Hyperlink URL","");
229       }
230       if(op.showEditor())
231       {
232         url = op.getString("Hyperlink URL");
233         if(url.length() > 0)
234         {
235           linkMap.put(key, url);
236         }
237         else
238         {
239           linkMap.remove(key);
240         }
241       } 
242     }
243   }
244   
245   /**
246    * Launches this demo.
247    * @param args ignored.
248    */
249   public static void main(String[] args) {
250     EventQueue.invokeLater(new Runnable() {
251       public void run() {
252         initLnF();
253         (new HyperlinkDemo()).start();
254       }
255     });
256   }
257 }