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