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  
29  package demo.view.application;
30  
31  import demo.view.DemoBase;
32  import y.base.Node;
33  import y.option.RealizerCellRenderer;
34  import y.view.Arrow;
35  import y.view.BezierEdgeRealizer;
36  import y.view.Drawable;
37  import y.view.DropSupport;
38  import y.view.EdgeRealizer;
39  import y.view.Graph2DView;
40  import y.view.NodeLabel;
41  import y.view.NodeRealizer;
42  import y.view.PolyLineEdgeRealizer;
43  import y.view.QuadCurveEdgeRealizer;
44  import y.view.ShapeNodeRealizer;
45  import y.view.SmartNodeLabelModel;
46  import y.view.SplineEdgeRealizer;
47  
48  import javax.swing.AbstractAction;
49  import javax.swing.AbstractButton;
50  import javax.swing.JList;
51  import javax.swing.JScrollPane;
52  import javax.swing.JToggleButton;
53  import javax.swing.JToolBar;
54  import javax.swing.ListSelectionModel;
55  import javax.swing.event.ListSelectionEvent;
56  import javax.swing.event.ListSelectionListener;
57  import java.awt.BorderLayout;
58  import java.awt.Color;
59  import java.awt.EventQueue;
60  import java.awt.dnd.DnDConstants;
61  import java.awt.dnd.DragGestureEvent;
62  import java.awt.dnd.DragGestureListener;
63  import java.awt.dnd.DragSource;
64  import java.awt.event.ActionEvent;
65  import java.util.ArrayList;
66  import java.util.Collection;
67  import java.util.Iterator;
68  import java.util.List;
69  import java.util.Locale;
70  import java.util.Map;
71  
72  /**
73   * Demo that shows how to display and drag different {@link NodeRealizer} and
74   * {@link EdgeRealizer} instances from a list and how to drop them onto a
75   * {@link Graph2DView} using a {@link Drawable} that indicates the drop
76   * operation. Additionally, {@link DropSupport} is configured to split an edge
77   * when a node is dropped on it.
78   * Moreover, using snap lines for node drag and drop is demonstrated.
79   * This demo makes use of the {@link java.awt.dnd.DnDConstants java.awt.dnd} package.
80   *
81   * @see <a href="http://docs.yworks.com/yfiles/doc/api/index.html#/dguide/mvc_view#dragdrop" target="_blank">Section Drag and Drop Support</a> in the yFiles for Java Developer's Guide
82   */
83  public class DragAndDropDemo extends DemoBase {
84    private final DragAndDropSupport dndSupport;
85  
86    /** Creates a new instance of DragAndDropDemo */
87    public DragAndDropDemo() {
88      // create the customized DnD support instance
89      dndSupport = createDragAndDropSupport();
90  
91      // get the List UI
92      final JList realizerList = dndSupport.getList();
93  
94      //add the realizer list to the panel
95      contentPane.add(new JScrollPane(realizerList), BorderLayout.WEST);
96    }
97  
98    /**
99     * Creates the demo's Drag and Drop support class.
100    * @return a <code>DragAndDropSupport</code> instance.
101    */
102   protected DragAndDropSupport createDragAndDropSupport() {
103     return new DragAndDropSupport(createRealizers(), view);
104   }
105 
106   /**
107    * Creates a toolbar for this demo.
108    */
109   protected JToolBar createToolBar() {
110     final JToggleButton snapLineButton = new JToggleButton(new AbstractAction("Snapping") {
111       public void actionPerformed(ActionEvent e) {
112         dndSupport.configureSnapping(((AbstractButton) e.getSource()).isSelected(), 30.0, 15.0, true);
113       }
114     });
115     snapLineButton.setIcon(getIconResource("resource/mode_snapping.png"));
116 
117     final JToolBar toolbar = super.createToolBar();
118     toolbar.addSeparator();
119     toolbar.add(snapLineButton);
120     return toolbar;
121   }
122 
123   /**
124    * Creates a collection of realizer
125    * instance. The realizer instances have different shapes
126    * and colors.
127    */
128   protected Collection createRealizers()
129   {
130     List result = new ArrayList();
131 
132     Map shapeTypeToStringMap = ShapeNodeRealizer.shapeTypeToStringMap();
133     float hueIncrease = 1.0f / (float) shapeTypeToStringMap.size();
134     float hue = 0.0f;
135     for (Iterator iter = shapeTypeToStringMap.keySet().iterator(); iter.hasNext(); hue += hueIncrease) {
136       Byte shapeType = (Byte) iter.next();
137       ShapeNodeRealizer r = new ShapeNodeRealizer(shapeType.byteValue());
138       r.setWidth(100.0);
139       r.setLabelText((String) shapeTypeToStringMap.get(shapeType));
140       r.setFillColor(new Color(Color.HSBtoRGB(hue, 0.5f, 1.0f)));
141       NodeLabel label = r.getLabel();
142       SmartNodeLabelModel model = new SmartNodeLabelModel();
143       label.setLabelModel(model, model.getDefaultParameter());
144       result.add(r);
145     }
146 
147     final PolyLineEdgeRealizer smoothedPolyLine = new PolyLineEdgeRealizer();
148     smoothedPolyLine.setSmoothedBends(true);
149 
150     List edgeRealizers = new ArrayList();
151     edgeRealizers.add(new PolyLineEdgeRealizer());
152     edgeRealizers.add(smoothedPolyLine);
153     edgeRealizers.add(new QuadCurveEdgeRealizer());
154     edgeRealizers.add(new BezierEdgeRealizer());
155     edgeRealizers.add(new SplineEdgeRealizer());
156 
157     // Set the target arrow for the edge realizers.
158     for (Iterator iterator = edgeRealizers.iterator(); iterator.hasNext();) {
159       EdgeRealizer edgeRealizer = (EdgeRealizer) iterator.next();
160       edgeRealizer.setTargetArrow(Arrow.STANDARD);
161     }
162 
163     result.addAll(edgeRealizers);
164 
165     return result;
166   }
167 
168   /**
169    * Support class that be used to create a JList that contains NodeRealizers that can be dragged
170    * and dropped onto the given Graph2DView object.
171    */
172   public static class DragAndDropSupport {
173     protected JList realizerList;
174     protected DropSupport dropSupport;
175 
176 
177     public DragAndDropSupport(Collection realizerList, final Graph2DView view) {
178       this(realizerList.toArray(), view);
179     }
180 
181     public DragAndDropSupport(Object[] realizers, final Graph2DView view) {
182       this(realizers, view, 120, 45);
183     }
184 
185     public DragAndDropSupport(Object[] realizers, final Graph2DView view, int itemWidth, int itemHeight) {
186       initializeDropSupport(view);
187       initializeRealizerList(realizers, view, itemWidth, itemHeight);
188       initializeDragSource();
189     }
190 
191     /**
192      * Creates the drop support class that can be used for dropping realizers onto the Graph2DView.
193      */
194     protected void initializeDropSupport(final Graph2DView view) {
195       dropSupport = new DropSupport(view) {
196         protected Node createNode(Graph2DView view, NodeRealizer r, double worldCoordX, double worldCoordY) {
197           final Node node = super.createNode(view, r, worldCoordX, worldCoordY);
198           nodeCreated(node, worldCoordX, worldCoordY);
199           return node;
200         }
201       };
202 
203       dropSupport.setPreviewEnabled(true);
204       dropSupport.setIndicatingSourceNode(true);
205 
206       // when a node is dropped on an edge, split the edge
207       dropSupport.setEdgeSplittingEnabled(true);
208       // when an edge is split, remove bends that lie inside the dropped node
209       dropSupport.getEdgeSplitSupport().setRemovingInnerBends(true);
210     }
211 
212     /**
213      * Creates a nice GUI for displaying NodeRealizers.
214      */
215     protected void initializeRealizerList(Object[] realizers, final Graph2DView view, int itemWidth, int itemHeight) {
216       realizerList = new JList(realizers);
217       realizerList.setCellRenderer(createCellRenderer(itemWidth, itemHeight));
218 
219       // set the currently selected NodeRealizer as default nodeRealizer
220       realizerList.addListSelectionListener(new ListSelectionListener() {
221         public void valueChanged(ListSelectionEvent e) {
222           if (realizerList.getSelectedValue() instanceof NodeRealizer) {
223             nodeRealizerSelected(view, (NodeRealizer) realizerList.getSelectedValue());
224           } else if (realizerList.getSelectedValue() instanceof EdgeRealizer) {
225             edgeRealizerSelected(view, (EdgeRealizer) realizerList.getSelectedValue());
226           }
227         }
228       });
229 
230       realizerList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
231       realizerList.setSelectedIndex(0);
232     }
233 
234     /**
235      * Defines the realizer list to be the drag source use the string-valued name of the realizer as transferable.
236      */
237     protected void initializeDragSource() {
238       final DragSource dragSource = new DragSource();
239       dragSource.createDefaultDragGestureRecognizer(realizerList, DnDConstants.ACTION_MOVE,
240           new DragGestureListener() {
241             public void dragGestureRecognized(DragGestureEvent event) {
242               final Object value = realizerList.getSelectedValue();
243               if (value instanceof NodeRealizer) {
244                 NodeRealizer nr = (NodeRealizer) value;
245                 // use the drop support class to initialize the drag and drop operation.
246                 dropSupport.startDrag(dragSource, nr, event, DragSource.DefaultMoveDrop);
247               } else if (value instanceof EdgeRealizer) {
248                 EdgeRealizer nr = (EdgeRealizer) value;
249                 // use the drop support class to initialize the drag and drop operation.
250                 dropSupport.startDrag(dragSource, nr, event, DragSource.DefaultMoveDrop);
251               }
252             }
253           });
254     }
255 
256     /**
257      * Configures the {@link DropSupport}of this class according to the specified snapping configuration.
258      */
259     public void configureSnapping(final SnappingConfiguration config, final boolean previewEnabled) {
260       dropSupport.setSnappingEnabled(config.isSnappingEnabled() || config.isGridSnappingEnabled());
261       config.configureSnapContext(dropSupport.getSnapContext());
262       dropSupport.setPreviewEnabled(previewEnabled);
263     }
264 
265     /**
266      * Configures the {@link DropSupport}of this class according to the specified parameters.
267      */
268     public void configureSnapping(final boolean snapping, final double nodeToNodeDistance,
269                                   final double nodeToEdgeDistance, final boolean previewEnabled) {
270       dropSupport.setSnappingEnabled(snapping);
271       dropSupport.getSnapContext().setNodeToNodeDistance(nodeToNodeDistance);
272       dropSupport.getSnapContext().setNodeToEdgeDistance(nodeToEdgeDistance);
273       dropSupport.getSnapContext().setUsingSegmentSnapLines(snapping);
274       dropSupport.setPreviewEnabled(previewEnabled);
275     }
276 
277     /**
278      * Creates the realizer cell renderer used by this class.
279      */
280     protected RealizerCellRenderer createCellRenderer(int itemWidth, int itemHeight) {
281       return new RealizerCellRenderer(itemWidth, itemHeight);
282     }
283 
284     protected void nodeCreated(Node node, double worldCoordX, double worldCoordY) {
285     }
286 
287     /**
288      * Callback method that is triggered whenever the selection changes in the JList.
289      * This method sets the given NodeRealizer as the view's graph default node realizer.
290      */
291     protected void nodeRealizerSelected(Graph2DView view, NodeRealizer realizer) {
292       view.getGraph2D().setDefaultNodeRealizer(realizer);
293     }
294 
295     /**
296      * Callback method that is triggered whenever the selection changes in the JList.
297      * This method sets the given EdgeRealizer as the view's graph default node realizer.
298      */
299     protected void edgeRealizerSelected(Graph2DView view, EdgeRealizer realizer) {
300       view.getGraph2D().setDefaultEdgeRealizer(realizer);
301     }
302 
303     /**
304      * Return the JList that has been configured by this support class.
305      */
306     public JList getList() {
307       return realizerList;
308     }
309   }
310 
311   /**
312    * Instantiates and starts this demo.
313    */
314   public static void main(String[] args) {
315     EventQueue.invokeLater(new Runnable() {
316       public void run() {
317         Locale.setDefault(Locale.ENGLISH);
318         initLnF();
319         (new DragAndDropDemo()).start("Drag and Drop Demo");
320       }
321     });
322   }
323 }
324