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  package demo.option;
15  
16  import demo.view.DemoBase;
17  import y.base.Node;
18  import y.base.NodeCursor;
19  import y.option.OptionHandler;
20  import y.view.Graph2D;
21  import y.view.NodeRealizer;
22  import y.view.Selections;
23  import y.view.ShapeNodeRealizer;
24  import y.view.ViewMode;
25  
26  import javax.swing.AbstractAction;
27  import javax.swing.Action;
28  import javax.swing.ImageIcon;
29  import javax.swing.JToolBar;
30  import java.awt.Color;
31  import java.awt.event.ActionEvent;
32  import java.awt.event.MouseEvent;
33  
34  /**
35   * <p>
36   * Demonstrates how to create a node property editor for nodes.
37   * This demo makes use of the "value-undefined" state of option items.
38   * <p>
39   * A node property editor can either be diplayed for a single node
40   * by double-clicking on the node or for multiple nodes by first
41   * selecting the nodes and then clicking on the "Edit Node Properties" 
42   * toolbar button.
43   * <p>
44   * The property editor will be initialized by the current settings
45   * of the selected nodes. If the value of a specific property differs for two
46   * selected nodes the editor will display the value as undefined. 
47   * Upon closing the editor dialog, only well-defined values will be 
48   * commited to the selected nodes.
49   * </p>
50   */
51  public class NodePropertyEditorDemo extends DemoBase
52  {
53    NodePropertyEditorAction nodePropertyEditorAction;
54    
55    public NodePropertyEditorDemo() {
56      
57      //open property editor upon double-clicking on a node
58      view.addViewMode(new ViewMode() {
59        public void mouseClicked(MouseEvent ev) {
60          if(ev.getClickCount() == 2) {
61            Node v = getHitInfo(ev).getHitNode();
62            if(v != null) {
63              nodePropertyEditorAction.actionPerformed(null);
64            }
65          }
66        }
67      });
68    }
69    
70    protected JToolBar createToolBar() {
71      JToolBar bar = super.createToolBar();
72      bar.addSeparator();
73      //add node property action to toolbar
74      bar.add(nodePropertyEditorAction = new NodePropertyEditorAction());
75      return bar;
76    }
77    
78    class NodePropertyEditorAction extends AbstractAction {
79  
80      NodePropertyHandler nodePropertyHandler;
81      
82      NodePropertyEditorAction() {
83        super("Node Properties");
84        putValue(Action.SMALL_ICON,
85            new ImageIcon( DemoBase.class.getResource("resource/Preferences16.gif")));
86        putValue(Action.SHORT_DESCRIPTION, "Edit Node Properties");
87     
88        Selections.SelectionStateObserver sso = new Selections.SelectionStateObserver() {
89          protected void updateSelectionState(Graph2D graph) 
90          {
91            setEnabled(view.getGraph2D().selectedNodes().ok());
92          } 
93        };
94        
95        view.getGraph2D().addGraph2DSelectionListener(sso);
96        view.getGraph2D().addGraphListener(sso);
97    
98        setEnabled(false);
99      
100       nodePropertyHandler = new NodePropertyHandler();
101     }
102     
103     public void actionPerformed(ActionEvent ev) {
104       Graph2D graph = view.getGraph2D();
105       if(!Selections.isNodeSelectionEmpty(graph)) {
106         nodePropertyHandler.updateValuesFromSelection(graph);
107         if(nodePropertyHandler.showEditor(view.getFrame())) {
108           nodePropertyHandler.commitNodeProperties(graph);
109           graph.updateViews();
110         }
111       }
112     }
113   }
114   
115   public static class NodePropertyHandler extends OptionHandler 
116   {
117     static final String[] shapeTypes = { "Rectangle", "Rounded Rectangle", "Ellipse" };
118     public NodePropertyHandler() {
119       super("Node Properties");
120       addString("Label", "").setValueUndefined(true);
121       addEnum("Shape Type", shapeTypes, 0).setValueUndefined(true);
122       addColor("Color", null, true).setValueUndefined(true);
123       addDouble("Width", 0.0).setValueUndefined(true);
124       addDouble("Height", 0.0).setValueUndefined(true);
125     }
126   
127     /**
128      * Retrieves the values from the set of selected nodes (actually node 
129      * realizers) and stores them in the respective option items. 
130      */
131     public void updateValuesFromSelection(Graph2D graph)
132     {
133       NodeCursor nc = graph.selectedNodes();
134       NodeRealizer nr = graph.getRealizer(nc.node());
135       
136       // Get the initial values from the first selected node. 
137       String label = nr.getLabelText();
138       boolean sameLabels = true;
139       byte shapeType = 0;
140       boolean onlyShapeNR = true;
141       boolean sameShapeType = true;
142       if (nr instanceof ShapeNodeRealizer)
143         shapeType = ((ShapeNodeRealizer)nr).getShapeType();
144       else
145       {
146         onlyShapeNR = false;
147         sameShapeType = false;
148       }
149       Color color = nr.getFillColor();
150       boolean sameColor = true;
151       double width = nr.getWidth();
152       boolean sameWidth = true;
153       double height = nr.getHeight();
154       boolean sameHeight = true;
155       
156       // Get all further values from the remaining set of selected node 
157       // realizers. 
158       if (nc.size() > 1)
159       {
160         for (nc.next(); nc.ok(); nc.next())
161         {
162           nr = graph.getRealizer(nc.node());
163           
164           if (sameLabels && !label.equals(nr.getLabelText()))
165             sameLabels = false;
166           if (sameShapeType && onlyShapeNR)
167           {
168             if (nr instanceof ShapeNodeRealizer)
169             {
170               if (shapeType != ((ShapeNodeRealizer)nr).getShapeType())
171                 sameShapeType = false;
172             }
173             else
174             {
175               onlyShapeNR = false;
176               sameShapeType = false;
177             }
178           }
179           if (sameColor && color != nr.getFillColor())
180             sameColor = false;
181           if (sameWidth && width != nr.getWidth())
182             sameWidth = false;
183           if (sameHeight && height != nr.getHeight())
184             sameHeight = false;
185           
186           if (!(sameLabels | sameShapeType | sameColor | sameWidth | sameHeight))
187             break;
188         }
189       }
190       
191       // If, for a single property, there are multiple values present in the set 
192       // of selected node realizers, then the respective option item is set to 
193       // indicate an "undefined value" state. 
194       // Note that property "valueUndefined" for an option item is set *after* 
195       // its value has actually been modified! 
196       set("Label", label);
197       getItem("Label").setValueUndefined(!sameLabels);
198       
199       set("Shape Type", shapeTypes[shapeType]);
200       getItem("Shape Type").setValueUndefined(!sameShapeType);
201       getItem("Shape Type").setEnabled(onlyShapeNR);
202 
203       set("Color", color);
204       getItem("Color").setValueUndefined(!sameColor);
205       
206       set("Width", new Double(width));
207       getItem("Width").setValueUndefined(!sameWidth);
208       
209       set("Height", new Double(height));
210       getItem("Height").setValueUndefined(!sameHeight);
211     }
212    
213     public void commitNodeProperties(Graph2D graph) 
214     {
215       for (NodeCursor nc = graph.selectedNodes(); nc.ok(); nc.next())
216       {
217         Node n = nc.node();
218         NodeRealizer nr = graph.getRealizer(n);
219         
220         if (!getItem("Label").isValueUndefined())
221           nr.setLabelText(getString("Label"));
222         if (!getItem("Shape Type").isValueUndefined() && nr instanceof ShapeNodeRealizer)
223           ((ShapeNodeRealizer)nr).setShapeType((byte)getEnum("Shape Type"));
224         if (!getItem("Color").isValueUndefined())
225           nr.setFillColor((Color)get("Color"));
226         if (!getItem("Width").isValueUndefined())
227           nr.setWidth(getDouble("Width"));
228         if (!getItem("Height").isValueUndefined())
229           nr.setHeight(getDouble("Height"));
230       }
231     }
232   }
233   
234   /** Launches this demo. */
235   public static void main(String args[])
236   {
237     initLnF();
238     NodePropertyEditorDemo demo = new NodePropertyEditorDemo();
239     demo.start(demo.getClass().getName());
240   }
241 }
242