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