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.view.flowchart;
15  
16  import y.geom.YPoint;
17  import y.option.RealizerCellRenderer;
18  import y.view.DropSupport;
19  import y.view.EdgeRealizer;
20  import y.view.Graph2DView;
21  import y.view.NodeRealizer;
22  import y.view.Graph2D;
23  import y.view.PolyLineEdgeRealizer;
24  import y.view.GenericNodeRealizer;
25  import y.view.Arrow;
26  
27  import javax.swing.DefaultListModel;
28  import javax.swing.Icon;
29  import javax.swing.JComponent;
30  import javax.swing.JList;
31  import javax.swing.JScrollPane;
32  import javax.swing.ListSelectionModel;
33  import javax.swing.event.ListSelectionListener;
34  import javax.swing.event.ListSelectionEvent;
35  import java.awt.Dimension;
36  import java.awt.BorderLayout;
37  import java.awt.dnd.DnDConstants;
38  import java.awt.dnd.DragGestureEvent;
39  import java.awt.dnd.DragGestureListener;
40  import java.awt.dnd.DragSource;
41  import java.util.ArrayList;
42  import java.util.Collection;
43  import java.util.HashMap;
44  import java.util.Iterator;
45  import java.util.List;
46  import java.util.Map;
47  
48  import demo.view.flowchart.painters.FlowchartAnnotationPainter;
49  import demo.view.flowchart.painters.FlowchartRealizerFactory;
50  
51  /**
52   * This is a component, which represents a palette of flowchart nodes and edges and allows to drag them into a Graph2DView.
53   */
54  public class FlowchartPalette extends JComponent {
55    private DragAndDropSupport dropSupport;
56    boolean snapMode;
57  
58    /**
59     * Creates a new FlowchartPalette with a pre-configured list of node and edge realizers.
60     */
61    public FlowchartPalette(final Graph2DView view) {
62      final BorderLayout borderLayout = new BorderLayout();
63      borderLayout.setVgap(10);
64      this.setLayout(borderLayout);
65      this.add(createDefaultPalette(view),BorderLayout.CENTER);
66      initializeDefaultRealizers(view);
67    }
68  
69    /**
70     * Returns whether or not snapping is enabled.
71     * @return true if snap mode enabled.
72     * @see #setSnapMode(boolean)
73     */
74    public boolean isSnapMode() {
75      return snapMode;
76    }
77  
78    /**
79     * Activates/deactivates snapping between graph elements, while dragging of a Flowchart-Node into the view.
80     * @param snapMode Whether to enable snapping.
81     */
82    public void setSnapMode(boolean snapMode) {
83      this.snapMode = snapMode;
84      dropSupport.configureSnapping(snapMode, 30, 15, true);
85    }
86  
87    /**
88     * Initializes default realizers
89     * @param view The respective Graph2DView.
90     */
91    protected void initializeDefaultRealizers(Graph2DView view) {
92      Graph2D graph = view.getGraph2D();
93      final EdgeRealizer der = graph.getDefaultEdgeRealizer();
94      if (der instanceof PolyLineEdgeRealizer){
95        ((PolyLineEdgeRealizer)der).setSmoothedBends(true);
96        der.setTargetArrow(Arrow.STANDARD);
97      }
98    }
99  
100   /**
101    * Creates a default flowchart realizers palette
102    * @param view The respective Graph2DView that is the target of the drag&drop action from the realizer palette.
103    */
104   private JComponent createDefaultPalette(final Graph2DView view) {
105 
106     final ArrayList realizers = new ArrayList();
107     addDefaultTemplates(realizers);
108 
109     //add the realizer list to the panel
110     //create the drag and drop list filled with the available realizer configurations
111     dropSupport = new DragAndDropSupport(realizers, view);
112     final JList realizerList = dropSupport.getList();
113     realizerList.setCellRenderer(new RealizerCellRenderer(60, 45) {
114       private Map nodeTips = new HashMap();
115       private Map edgeTips = new HashMap();
116 
117       protected Icon createEdgeRealizerIcon(EdgeRealizer realizer, int iconWidth, int iconHeight) {
118         final EdgeRealizerIcon icon = createIcon(realizer, iconWidth, iconHeight);
119         icon.setDrawingBends(false);
120         return icon;
121       }
122 
123       private EdgeRealizerIcon createIcon(EdgeRealizer realizer, int iconWidth, int iconHeight) {
124         if (realizer.labelCount() > 0) {
125           final String text = realizer.getLabelText();
126           if ("No".equalsIgnoreCase(text) || "Yes".equalsIgnoreCase(text)) {
127             return new EdgeRealizerIcon(realizer, iconWidth, iconHeight) {
128               protected YPoint calculateSourceBend(EdgeRealizer realizer, int iconWidth, int iconHeight) {
129                 return new YPoint(0.5 * iconWidth, iconHeight - realizer.getLabel().getHeight() - 2);
130               }
131             };
132           }
133         }
134         return new EdgeRealizerIcon(realizer, iconWidth, iconHeight);
135       }
136 
137       protected String createEdgeToolTipText(EdgeRealizer realizer) {
138         if(edgeTips.containsKey(realizer)){
139           return (String) edgeTips.get(realizer);
140         }else{
141           final String text = FlowchartPalette.this.createEdgeToolTipText(realizer);
142           edgeTips.put(realizer, text);
143           return text;
144         }
145       }
146 
147       protected String createNodeToolTipText( final NodeRealizer realizer ) {
148         if (nodeTips.containsKey(realizer)) {
149           return (String) nodeTips.get(realizer);
150         } else {
151           final String text = FlowchartPalette.this.createNodeToolTipText(realizer);
152           nodeTips.put(realizer, text);
153           return text;
154         }
155       }
156     });
157     realizerList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
158     realizerList.setVisibleRowCount(-1);
159     JScrollPane palette = new JScrollPane(realizerList);
160     palette.setPreferredSize(new Dimension(220, 300));
161     return palette;
162   }
163 
164   protected String createEdgeToolTipText( final EdgeRealizer realizer ) {
165     return null;
166   }
167 
168   protected String createNodeToolTipText( final NodeRealizer realizer ) {
169     if (realizer instanceof GenericNodeRealizer) {
170       String s = ((GenericNodeRealizer) realizer).getConfiguration();
171       if (s != null) {
172         s = s.trim();
173         final String prefix = "com.yworks.flowchart.";
174         if (s.startsWith(prefix)) {
175           s = s.substring(prefix.length());
176           final int l = s.length();
177           final char[] chars = s.toCharArray();
178           final StringBuffer sb = new StringBuffer(s.length() + 4);
179           int last = 0;
180           String del = "";
181           for (int i = 1; i < l; ++i) {
182             if (Character.isUpperCase(chars[i])) {
183               sb.append(del).append(Character.toUpperCase(chars[last]));
184               sb.append(chars, last + 1, i - last - 1);
185               last = i;
186               del = " ";
187             }
188           }
189           if (last < l) {
190             sb.append(del).append(Character.toUpperCase(chars[last]));
191             sb.append(chars, last + 1, l - last - 1);
192           }
193           return sb.toString();
194         }
195       }
196     }
197     return null;
198   }
199 
200   /**
201    * Adds default flowchart templates to the palette list.
202    *
203    * @param realizers The list of all template realizers
204    */
205   protected void addDefaultTemplates(final List realizers) {
206     realizers.add(FlowchartRealizerFactory.createData());
207     realizers.add(FlowchartRealizerFactory.createDirectData());
208     realizers.add(FlowchartRealizerFactory.createDataBase());
209     realizers.add(FlowchartRealizerFactory.createProcess());
210     realizers.add(FlowchartRealizerFactory.createDecision());
211     realizers.add(FlowchartRealizerFactory.createDocument());
212     realizers.add(FlowchartRealizerFactory.createStart1());
213     realizers.add(FlowchartRealizerFactory.createStart2());
214     realizers.add(FlowchartRealizerFactory.createPredefinedProcess());
215     realizers.add(FlowchartRealizerFactory.createStoredData());
216     realizers.add(FlowchartRealizerFactory.createInternalStorage());
217     realizers.add(FlowchartRealizerFactory.createSequentialData());
218     realizers.add(FlowchartRealizerFactory.createManualInput());
219     realizers.add(FlowchartRealizerFactory.createCard());
220     realizers.add(FlowchartRealizerFactory.createPaperTape());
221     realizers.add(FlowchartRealizerFactory.createCloud());
222     realizers.add(FlowchartRealizerFactory.createDelay());
223     realizers.add(FlowchartRealizerFactory.createDisplay());
224     realizers.add(FlowchartRealizerFactory.createManualOperation());
225     realizers.add(FlowchartRealizerFactory.createPreparation());
226     realizers.add(FlowchartRealizerFactory.createLoopLimit());
227     realizers.add(FlowchartRealizerFactory.createLoopLimitEnd());
228     realizers.add(FlowchartRealizerFactory.createTerminator());
229     realizers.add(FlowchartRealizerFactory.createOnPageReference());
230     realizers.add(FlowchartRealizerFactory.createOffPageReference());
231     realizers.add(FlowchartRealizerFactory.createAnnotation(FlowchartAnnotationPainter.PROPERTY_ORIENTATION_VALUE_AUTO));
232     realizers.add(FlowchartRealizerFactory.createUserMessage());
233     realizers.add(FlowchartRealizerFactory.createNetworkMessage());
234     realizers.add(FlowchartRealizerFactory.createDefaultConnection());
235     realizers.add(FlowchartRealizerFactory.createNoConnection());
236     realizers.add(FlowchartRealizerFactory.createYesConnection());
237   }
238 
239 
240   private static final class DragAndDropSupport {
241     private final JList realizerList;
242     private DropSupport dropSupport;
243 
244     public DragAndDropSupport(Collection realizers, final Graph2DView view) {
245       // create the drop support class that can be used for dropping realizers
246       // onto the Graph2DView
247       dropSupport = new DropSupport(view);
248 
249       dropSupport.setPreviewEnabled(true);
250 
251       // create a nice GUI for displaying NodeRealizers
252       DefaultListModel model = new DefaultListModel();
253       for (Iterator it = realizers.iterator(); it.hasNext();) {
254         model.addElement(it.next());
255       }
256       realizerList = new JList(model);
257       realizerList.setCellRenderer(new RealizerCellRenderer(120, 45));
258 
259       // set the currently selected NodeRealizer as default nodeRealizer
260       realizerList.addListSelectionListener(new ListSelectionListener() {
261         public void valueChanged(ListSelectionEvent e) {
262           if (realizerList.getSelectedValue() instanceof NodeRealizer) {
263             nodeRealizerSelected(view, (NodeRealizer) realizerList.getSelectedValue());
264           } else if (realizerList.getSelectedValue() instanceof EdgeRealizer) {
265             edgeRealizerSelected(view, (EdgeRealizer) realizerList.getSelectedValue());
266           }
267         }
268       });
269 
270       realizerList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
271       realizerList.setSelectedIndex(0);
272 
273       // define the realizer list to be the drag source
274       // use the string-valued name of the realizer as transferable
275       final DragSource dragSource = new DragSource();
276       dragSource.createDefaultDragGestureRecognizer(realizerList, DnDConstants.ACTION_MOVE,
277           new DragGestureListener() {
278             public void dragGestureRecognized(DragGestureEvent event) {
279               final Object value = realizerList.getSelectedValue();
280               if (value instanceof NodeRealizer) {
281                 NodeRealizer nr = (NodeRealizer) value;
282                 // use the drop support class to initialize the drag and drop operation.
283                 dropSupport.startDrag(dragSource, nr, event, DragSource.DefaultMoveDrop);
284               } else if (value instanceof EdgeRealizer) {
285                 EdgeRealizer nr = (EdgeRealizer) value;
286                 // use the drop support class to initialize the drag and drop operation.
287                 dropSupport.startDrag(dragSource, nr, event, DragSource.DefaultMoveDrop);
288               }
289             }
290           });
291     }
292 
293     public void configureSnapping(final boolean snapping, final int nodeToNodeDistance, final int nodeToEdgeDistance,
294                                   final boolean previewEnabled) {
295       configureDropSupport(dropSupport, snapping, previewEnabled, nodeToNodeDistance, nodeToEdgeDistance);
296     }
297 
298     protected static void configureDropSupport(final DropSupport dropSupport, final boolean snapping,
299                                                final boolean previewEnabled, final double nodeToNodeDistance,
300                                                final double nodeToEdgeDistance) {
301       dropSupport.setSnappingEnabled(snapping);
302       dropSupport.getSnapContext().setNodeToNodeDistance(nodeToNodeDistance);
303       dropSupport.getSnapContext().setNodeToEdgeDistance(nodeToEdgeDistance);
304       dropSupport.getSnapContext().setUsingSegmentSnapLines(snapping);
305       dropSupport.setPreviewEnabled(previewEnabled);
306     }
307 
308     /**
309      * Callback method that is triggered whenever the selection changes in the JList. This method sets the given
310      * NodeRealizer as the view's graph default node realizer.
311      */
312     protected void nodeRealizerSelected(Graph2DView view, NodeRealizer realizer) {
313       view.getGraph2D().setDefaultNodeRealizer(realizer);
314     }
315 
316     /**
317      * Callback method that is triggered whenever the selection changes in the JList. This method sets the given
318      * EdgeRealizer as the view's graph default node realizer.
319      */
320     protected void edgeRealizerSelected(Graph2DView view, EdgeRealizer realizer) {
321       view.getGraph2D().setDefaultEdgeRealizer(realizer);
322     }
323 
324     /** Return the JList that has been configured by this support class. */
325     public JList getList() {
326       return realizerList;
327     }
328   }
329 }