1   /****************************************************************************
2    * This demo file is part of yFiles for Java 2.14.
3    * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4    * 72070 Tuebingen, Germany. All rights reserved.
5    * 
6    * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7    * of demo files in source code or binary form, with or without
8    * modification, is not permitted.
9    * 
10   * Owners of a valid software license for a yFiles for Java version that this
11   * demo is shipped with are allowed to use the demo source code as basis
12   * for their own yFiles for Java powered applications. Use of such programs is
13   * governed by the rights and conditions as set out in the yFiles for Java
14   * license agreement.
15   * 
16   * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19   * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   *
27   ***************************************************************************/
28  package demo.option;
29  
30  import demo.view.DemoBase;
31  import demo.view.DemoDefaults;
32  import y.base.Node;
33  import y.base.NodeCursor;
34  import y.option.DoubleOptionItem;
35  import y.option.OptionHandler;
36  import y.view.Graph2D;
37  import y.view.NodeRealizer;
38  import y.view.Selections;
39  import y.view.ViewMode;
40  
41  import javax.swing.AbstractAction;
42  import javax.swing.Action;
43  import javax.swing.JToolBar;
44  import java.awt.Color;
45  import java.awt.EventQueue;
46  import java.awt.event.ActionEvent;
47  import java.awt.event.ActionListener;
48  import java.awt.event.MouseEvent;
49  import java.util.Locale;
50  
51  /**
52   * <p>
53   * Demonstrates how to create a node property editor for nodes.
54   * This demo makes use of the "value-undefined" state of option items.
55   * <p>
56   * A node property editor can either be displayed for a single node
57   * by double-clicking on the node or for multiple nodes by first
58   * selecting the nodes and then clicking on the "Edit Node Properties" 
59   * toolbar button.
60   * <p>
61   * The property editor will be initialized by the current settings
62   * of the selected nodes. If the value of a specific property differs for two
63   * selected nodes the editor will display the value as undefined. 
64   * Upon closing the editor dialog, only well-defined values will be 
65   * committed to the selected nodes.
66   * </p>
67   *
68   * @see <a href="http://docs.yworks.com/yfiles/doc/api/index.html#/dguide/option_basic" target="_blank">Section Basic Functionality</a> in the yFiles for Java Developer's Guide
69   */
70  public class NodePropertyEditorDemo extends DemoBase
71  {
72    NodePropertyEditorAction nodePropertyEditorAction;
73    
74    public NodePropertyEditorDemo() {
75      
76      //open property editor upon double-clicking on a node
77      view.addViewMode(new ViewMode() {
78        public void mouseClicked(MouseEvent e) {
79          if(e.getClickCount() == 2) {
80            Node v = getHitInfo(e).getHitNode();
81            if(v != null) {
82              nodePropertyEditorAction.actionPerformed(null);
83            }
84          }
85        }
86      });
87    }
88    
89    protected JToolBar createToolBar() {
90      nodePropertyEditorAction = new NodePropertyEditorAction();
91  
92      JToolBar toolBar = super.createToolBar();
93      toolBar.addSeparator();
94      toolBar.add(createActionControl(nodePropertyEditorAction));
95      return toolBar;
96    }
97    
98    class NodePropertyEditorAction extends AbstractAction {
99  
100     NodePropertyHandler nodePropertyHandler;
101     
102     NodePropertyEditorAction() {
103       super("Node Properties", getIconResource("resource/properties.png"));
104       putValue(Action.SHORT_DESCRIPTION, "Edit the properties of selected nodes");
105    
106       Selections.SelectionStateObserver sso = new Selections.SelectionStateObserver() {
107         protected void updateSelectionState(Graph2D graph) 
108         {
109           setEnabled(view.getGraph2D().selectedNodes().ok());
110         } 
111       };
112       
113       view.getGraph2D().addGraph2DSelectionListener(sso);
114       view.getGraph2D().addGraphListener(sso);
115   
116       setEnabled(false);
117     
118       nodePropertyHandler = new NodePropertyHandler();
119     }
120 
121     public void actionPerformed(ActionEvent e) {
122       Graph2D graph = view.getGraph2D();
123       graph.firePreEvent();
124       graph.backupRealizers();
125       try {
126         if (!Selections.isNodeSelectionEmpty(graph)) {
127           nodePropertyHandler.updateValuesFromSelection(graph);
128 
129           final ActionListener nodePropertyListener = new ActionListener() {
130             public void actionPerformed(ActionEvent e) {
131               final Graph2D graph = view.getGraph2D();
132               nodePropertyHandler.commitNodeProperties(graph);
133               graph.updateViews();
134             }
135           };
136           OptionSupport.showDialog(nodePropertyHandler, nodePropertyListener, true, view.getFrame());
137         }
138       } finally {
139         graph.firePostEvent();
140       }
141     }
142   }
143   
144   public static class NodePropertyHandler extends OptionHandler 
145   {
146     static final String ITEM_LABEL_TEXT = "Label Text";
147     static final String ITEM_COLOR = "Color";
148     static final String ITEM_WIDTH = "Width";
149     static final String ITEM_HEIGHT = "Height";
150 
151     public NodePropertyHandler() {
152       super("Node Properties");
153       addString(ITEM_LABEL_TEXT, "").setValueUndefined(true);
154       addColor(ITEM_COLOR, DemoDefaults.DEFAULT_NODE_COLOR, false, true, true, true).setValueUndefined(true);
155       addDouble(ITEM_WIDTH, 1.0).setValueUndefined(true);
156       addDouble(ITEM_HEIGHT, 1.0).setValueUndefined(true);
157 
158       getItem(ITEM_WIDTH).setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(1.0));
159       getItem(ITEM_HEIGHT).setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(1.0));
160     }
161 
162     /**
163      * Retrieves the values from the set of selected nodes (actually node 
164      * realizers) and stores them in the respective option items. 
165      */
166     public void updateValuesFromSelection(Graph2D graph)
167     {
168       NodeCursor nc = graph.selectedNodes();
169       NodeRealizer nr = graph.getRealizer(nc.node());
170       
171       // Get the initial values from the first selected node. 
172       String label = nr.getLabelText();
173       boolean sameLabels = true;
174       Color color = nr.getFillColor();
175       boolean sameColor = true;
176       double width = nr.getWidth();
177       boolean sameWidth = true;
178       double height = nr.getHeight();
179       boolean sameHeight = true;
180       
181       // Get all further values from the remaining set of selected node 
182       // realizers. 
183       if (nc.size() > 1)
184       {
185         for (nc.next(); nc.ok(); nc.next())
186         {
187           nr = graph.getRealizer(nc.node());
188           
189           if (sameLabels && !label.equals(nr.getLabelText()))
190             sameLabels = false;
191           if (sameColor && color != nr.getFillColor())
192             sameColor = false;
193           if (sameWidth && width != nr.getWidth())
194             sameWidth = false;
195           if (sameHeight && height != nr.getHeight())
196             sameHeight = false;
197           
198           if (!(sameLabels | sameColor | sameWidth | sameHeight))
199             break;
200         }
201       }
202       
203       // If, for a single property, there are multiple values present in the set 
204       // of selected node realizers, then the respective option item is set to 
205       // indicate an "undefined value" state. 
206       // Note that property "valueUndefined" for an option item is set *after* 
207       // its value has actually been modified! 
208       set(ITEM_LABEL_TEXT, label);
209       getItem(ITEM_LABEL_TEXT).setValueUndefined(!sameLabels);
210       
211       set(ITEM_COLOR, color);
212       getItem(ITEM_COLOR).setValueUndefined(!sameColor);
213       
214       set(ITEM_WIDTH, new Double(width));
215       getItem(ITEM_WIDTH).setValueUndefined(!sameWidth);
216       
217       set(ITEM_HEIGHT, new Double(height));
218       getItem(ITEM_HEIGHT).setValueUndefined(!sameHeight);
219     }
220    
221     public void commitNodeProperties(Graph2D graph) 
222     {
223       for (NodeCursor nc = graph.selectedNodes(); nc.ok(); nc.next())
224       {
225         Node n = nc.node();
226         NodeRealizer nr = graph.getRealizer(n);
227         
228         if (!getItem(ITEM_LABEL_TEXT).isValueUndefined())
229           nr.setLabelText(getString(ITEM_LABEL_TEXT));
230         if (!getItem(ITEM_COLOR).isValueUndefined())
231           nr.setFillColor((Color)get(ITEM_COLOR));
232         if (!getItem(ITEM_WIDTH).isValueUndefined())
233           nr.setWidth(getDouble(ITEM_WIDTH));
234         if (!getItem(ITEM_HEIGHT).isValueUndefined())
235           nr.setHeight(getDouble(ITEM_HEIGHT));
236       }
237     }
238   }
239   
240   /** Launches this demo. */
241   public static void main(String[] args) {
242     EventQueue.invokeLater(new Runnable() {
243       public void run() {
244         Locale.setDefault(Locale.ENGLISH);
245         initLnF();
246         new NodePropertyEditorDemo().start("Node Property Editor Demo");
247       }
248     });
249   }
250 }
251