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  
15  package demo.io;
16  
17  import y.base.Node;
18  import y.base.NodeMap;
19  import y.io.GMLIOHandler;
20  import y.io.gml.EncoderFactory;
21  import y.io.gml.ParserFactory;
22  import y.option.OptionHandler;
23  import y.view.EditMode;
24  import y.view.Graph2D;
25  import y.view.PopupMode;
26  
27  import javax.swing.AbstractAction;
28  import javax.swing.JFileChooser;
29  import javax.swing.JPopupMenu;
30  import java.awt.event.ActionEvent;
31  import java.util.ArrayList;
32  import java.util.Iterator;
33  import java.util.List;
34  
35  /**
36   * This class demonstrates how to create a customized GML
37   * format. It is capable of associating attributes to nodes
38   * dynamically, encode them in gml and parse them back in.
39   * {@link #createNodeDataList } is a factory method, that
40   * creates a list of the possible node attributes.
41   * The view component is configured to present a popup menu
42   * on all visible nodes, which can be used to access the
43   * properties from the list. When the graph is saved using the
44   * GML format, these properties are encoded in the .graph.node.
45   * section as additional attributes. When this file is opened
46   * using this demo, the attributes will be parsed back in
47   * and associated with the nodes.
48   * <br>
49   * Additionally, the use
50   * of customized PopupModes and OptionHandlers is demonstrated briefly.
51   * <br>
52   * Note that this demo makes use of the following classes:
53   * {@link demo.io.CustomGMLFactory},
54   * {@link demo.io.CustomNodeObjectEncoder}, and
55   * {@link demo.io.CustomNodeParser}. 
56   */
57  public class CustomGMLDemo extends demo.view.DemoBase
58  {
59    private EncoderFactory backupEncoderFactory;
60    private ParserFactory backupParserFactory;
61  
62    protected void registerViewModes() {
63      Graph2D g = view.getGraph2D();
64      List list = createNodeDataList(g);
65  
66      backupEncoderFactory = GMLIOHandler.getEncoderFactory();
67      backupParserFactory = GMLIOHandler.getParserFactory();
68      CustomGMLFactory factory = new CustomGMLFactory(list);
69      GMLIOHandler.setEncoderFactory(factory);
70      GMLIOHandler.setParserFactory(factory);
71  
72      EditMode editMode = new EditMode();
73      view.addViewMode( editMode );
74      editMode.setPopupMode( new DemoPopupMode( list ) );
75    }
76  
77  
78    class DemoPopupMode extends PopupMode
79    {
80      private List nodeDataList;
81      
82      DemoPopupMode(List nodeDataList)
83      {
84        this.nodeDataList = nodeDataList;
85      }
86      
87      /** Popup menu for a hit node, this will trigger the display
88       * of the OptionHandler for each node
89       */
90      public JPopupMenu getNodePopup(Node v)
91      {
92        JPopupMenu pm = new JPopupMenu();
93        pm.add(new ShowNodeProperties(v, nodeDataList));
94        return pm;
95      }
96    }
97    
98    class ShowNodeProperties extends AbstractAction
99    {
100     private Node n;
101     private List nodeDataList;
102     private OptionHandler op;
103     
104     ShowNodeProperties(Node n, List nodeDataList)
105     {
106       super("Edit Properties...");
107       this.n = n;
108       this.nodeDataList = nodeDataList;
109     }
110     
111     public void actionPerformed(java.awt.event.ActionEvent actionEvent)
112     {
113       if(op == null)
114       {
115         op = new OptionHandler("Node Properties");
116         for (Iterator it = nodeDataList.iterator(); it.hasNext();)
117         {
118           NodeData data = (NodeData) it.next();
119           if (data.getClassType().equals(String.class)){
120             Object value = data.getNodeMap().get(n);
121             op.addString(data.getPropertyName(), (String) value, 1);
122           } else if (data.getClassType().equals(Double.class)){
123             double value = data.getNodeMap().getDouble(n);
124             op.addDouble(data.getPropertyName(), value);
125           } else if (data.getClassType().equals(Float.class)){
126             double value = data.getNodeMap().getDouble(n);
127             op.addDouble(data.getPropertyName(), value);
128           } else if (data.getClassType().equals(Boolean.class)){
129             boolean value = data.getNodeMap().getBool(n);
130             op.addBool(data.getPropertyName(), value);
131           } else if (data.getClassType().equals(Integer.class)){
132             int value = data.getNodeMap().getInt(n);
133             op.addInt(data.getPropertyName(), value);
134           }
135         }
136       }
137       if(op.showEditor())
138       {
139         for (Iterator it = nodeDataList.iterator(); it.hasNext();)
140         {
141           NodeData data = (NodeData) it.next();
142           if (data.getClassType().equals(String.class)){
143             Object value = op.getString(data.getPropertyName());
144             data.getNodeMap().set(n, value);
145           } else if (data.getClassType().equals(Double.class)){
146             Object value = new Double(op.getDouble(data.getPropertyName()));
147             data.getNodeMap().set(n, value);
148           } else if (data.getClassType().equals(Float.class)){
149             Object value = new Double(op.getDouble(data.getPropertyName()));
150             data.getNodeMap().set(n, value);
151           } else if (data.getClassType().equals(Boolean.class)){
152             Object value = new Boolean(op.getBool(data.getPropertyName()));
153             data.getNodeMap().set(n, value);
154           } else if (data.getClassType().equals(Integer.class)){
155             Object value = new Integer(op.getInt(data.getPropertyName()));
156             data.getNodeMap().set(n, value);
157           }
158         }
159       }
160     }
161   }
162   
163   /** This factory method is used to determine the additional
164    * attributes a node can have. The list must consists of
165    * {@link NodeData} objects. This is list is used for
166    * encoding, parsing and creating an appropriate
167    * {@link y.option.OptionHandler}
168    * @param forGraph the graph which should be used to create
169    * {@link y.base.NodeMap}s, which will store the
170    * attributes.
171    * @return a list of {@link NodeData} objects
172    */  
173   protected List createNodeDataList(Graph2D forGraph)
174   {
175     List list = new ArrayList(5);
176     NodeMap nodeMap;
177     nodeMap = forGraph.createNodeMap();
178     list.add(new CustomGMLDemo.NodeData("stringValue", String.class, nodeMap));
179     nodeMap = forGraph.createNodeMap();
180     list.add(new CustomGMLDemo.NodeData("doubleValue", Double.class, nodeMap));
181     nodeMap = forGraph.createNodeMap();
182     list.add(new CustomGMLDemo.NodeData("booleanValue", Boolean.class, nodeMap));
183     nodeMap = forGraph.createNodeMap();
184     list.add(new CustomGMLDemo.NodeData("intValue", Integer.class, nodeMap));
185     nodeMap = forGraph.createNodeMap();
186     list.add(new CustomGMLDemo.NodeData("floatValue", Float.class, nodeMap));
187     return list;
188   }
189 
190   public void dispose()
191   {
192     GMLIOHandler.setEncoderFactory(backupEncoderFactory );
193     GMLIOHandler.setParserFactory(backupParserFactory);
194   }
195 
196   /**
197    * Launches this demo.
198    */
199   public static void main(String args[])
200   {
201     CustomGMLDemo demo = new CustomGMLDemo();
202     demo.start("Custom GML Demo");
203   }
204   
205   /** overwritten to provide this demo with the GMLIOHandler
206    */  
207   protected javax.swing.Action createLoadAction()
208   {
209     return new demo.io.CustomGMLDemo.LoadAction();
210   }
211   
212   /** overwritten to provide this demo with the GMLIOHandler
213    */  
214   protected javax.swing.Action createSaveAction()
215   {
216     return new demo.io.CustomGMLDemo.SaveAction();
217   }
218   
219   /**
220    * Action that saves the current graph to a file in GML format.
221    */
222   class SaveAction extends javax.swing.AbstractAction
223   {
224     SaveAction()
225     {
226       super("Save...");
227     }
228     
229     public void actionPerformed(ActionEvent e)
230     {
231       JFileChooser chooser = new JFileChooser();
232       if(chooser.showSaveDialog(contentPane) == JFileChooser.APPROVE_OPTION)
233       {
234         String name = chooser.getSelectedFile().toString();
235         if(!name.endsWith(".gml")) name = name + ".gml";
236         y.io.IOHandler ioh = new GMLIOHandler();
237         try
238         {
239           ioh.write(view.getGraph2D(),name);
240         } catch (java.io.IOException ioe)
241         {
242           y.util.D.show(ioe);
243         }
244       }
245     }
246   }
247   
248   
249   /**
250    * Action that loads the current graph from a file in GML format.
251    */
252   class LoadAction extends javax.swing.AbstractAction
253   {
254     LoadAction()
255     {
256       super("Load...");
257     }
258     
259     public void actionPerformed(ActionEvent e)
260     {
261       JFileChooser chooser = new JFileChooser();
262       if(chooser.showOpenDialog(contentPane) == JFileChooser.APPROVE_OPTION)
263       {
264         String name = chooser.getSelectedFile().toString();
265         if(!name.endsWith(".gml")) name = name + ".gml";
266         y.io.IOHandler ioh = new GMLIOHandler();
267         try
268         {
269           Graph2D graph = view.getGraph2D();
270           graph.clear();
271           ioh.read(graph,name);
272         } catch (java.io.IOException ioe)
273         {
274           y.util.D.show(ioe);
275         }
276         //force redisplay of view contents
277         view.updateView();
278       }
279     }
280   }
281   
282   /** This class is used to store the meta-data for the additional
283    * node attributes.
284    */  
285   public static class NodeData
286   {
287     
288     /** Holds value of property propertyName. */
289     private String propertyName;
290     
291     /** Holds value of property classType. */
292     private Class classType;
293     
294     /** Holds value of property nodeMap. */
295     private NodeMap nodeMap;
296     
297     /** creates a generic node meta data object
298      * @param propertyName the name of the property, which will be used for
299      * display in the optionhandler, and in the gml file
300      * @param classtype the type of the attributes, either
301      * <CODE>String.class</CODE>, <CODE>Float.class</CODE>,
302      * <CODE>Double.class</CODE>, <CODE>Integer.class</CODE>
303      * or <CODE>Boolean.class</CODE>
304      * @param nodeMap the nodemap used for the mapping between the nodes
305      * and the values
306      */    
307     public NodeData(String propertyName, Class classtype, NodeMap nodeMap)
308     {
309       this.propertyName = propertyName;
310       this.classType = classtype;
311       this.nodeMap = nodeMap;
312     }
313     
314     /** Getter for property propertyName.
315      * @return Value of property propertyName.
316      */
317     public String getPropertyName()
318     {
319       return this.propertyName;
320     }
321     
322     /** Getter for property classType.
323      * @return Value of property classType.
324      */
325     public Class getClassType()
326     {
327       return this.classType;
328     }
329     
330     /** Getter for property nodeMap.
331      * @return Value of property nodeMap.
332      */
333     public NodeMap getNodeMap()
334     {
335       return this.nodeMap;
336     }
337   }
338 }
339