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.advanced.ports;
15  
16  import y.base.Node;
17  import y.geom.YPoint;
18  import y.option.RealizerCellRenderer;
19  import y.view.DropSupport;
20  import y.view.Graph2D;
21  import y.view.Graph2DView;
22  import y.view.NodePort;
23  import y.view.NodeRealizer;
24  import y.view.NodeScaledPortLocationModel;
25  
26  import java.awt.Color;
27  import java.awt.GridLayout;
28  import java.awt.dnd.DnDConstants;
29  import java.awt.dnd.DragGestureEvent;
30  import java.awt.dnd.DragGestureListener;
31  import java.awt.dnd.DragSource;
32  import java.awt.geom.Rectangle2D;
33  import java.util.Enumeration;
34  import javax.swing.DefaultListModel;
35  import javax.swing.JList;
36  import javax.swing.JPanel;
37  import javax.swing.JScrollPane;
38  import javax.swing.ListSelectionModel;
39  import javax.swing.event.ListSelectionEvent;
40  import javax.swing.event.ListSelectionListener;
41  
42  /**
43   * A palette that provides templates for nodes with node ports.
44   *
45   */
46  class Palette extends JPanel {
47    /**
48     * Initializes a new <code>Palette</code> instance for the specified graph
49     * view.
50     * @param view the {@link y.view.Graph2DView} holding the graph in which
51     * nodes can be created using this palette's templates.
52     */
53    Palette( final Graph2DView view ) {
54      super(new GridLayout(1, 1));
55  
56      // begin create templates
57      final NodeRealizer nr = view.getGraph2D().getDefaultNodeRealizer();
58      final NodeRealizer prototype = nr.createCopy();
59      prototype.setSize(90, 60);
60      prototype.setFillColor(Color.LIGHT_GRAY);
61  
62      final DefaultListModel model = new DefaultListModel();
63      model.addElement(addDynamicPorts(prototype.createCopy()));
64      model.addElement(addEllipsePorts(prototype.createCopy()));
65      model.addElement(addRectanglePort(prototype.createCopy()));
66      // end create templates
67  
68      // begin create control to choose between templates
69      final Rectangle2D.Double r = new Rectangle2D.Double(0, 0, -1, -1);
70      for (Enumeration en = model.elements(); en.hasMoreElements();) {
71        ((NodeRealizer) en.nextElement()).calcUnionRect(r);
72      }
73  
74      final JList jl = new JList(model);
75      jl.setCellRenderer(new RealizerCellRenderer(
76              (int) Math.ceil(r.getWidth()) + 10,
77              (int) Math.ceil(r.getHeight()) + 10));
78      jl.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
79        public void valueChanged( final ListSelectionEvent e ) {
80          final Object value = jl.getSelectedValue();
81          if (value instanceof NodeRealizer) {
82            view.getGraph2D().setDefaultNodeRealizer((NodeRealizer) value);
83          }
84        }
85      });
86      jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
87      jl.setSelectedIndex(0);
88  
89      add(new JScrollPane(jl));
90      // end create control to choose between templates
91  
92      // begin setup drag and drop support
93      //   nodes can be created by dragging this palette's templates to the
94      //   associated graph view
95      final DropSupport dropSupport = new DropSupport(view) {
96        protected Node createNode(
97                final Graph2DView view,
98                final NodeRealizer nr,
99                final double x,
100               final double y
101       ) {
102         final Graph2D graph = view.getGraph2D();
103         final Node node = super.createNode(view, nr, x, y);
104         graph.getRealizer(node).setLabelText(Integer.toString(graph.nodeCount()));
105         return node;
106       }
107     };
108     dropSupport.setPreviewEnabled(true);
109 
110     final DragSource dragSource = new DragSource();
111     dragSource.createDefaultDragGestureRecognizer(jl, DnDConstants.ACTION_MOVE,
112         new DragGestureListener() {
113           public void dragGestureRecognized( final DragGestureEvent e ) {
114             final Object value = jl.getSelectedValue();
115             if (value instanceof NodeRealizer) {
116               dropSupport.startDrag(dragSource, (NodeRealizer) value, e, DragSource.DefaultMoveDrop);
117             }
118           }
119         });
120     // end setup drag and drop support
121   }
122 
123   /**
124    * Adds dynamic, rectangular node ports to the specified realizer.
125    * @param nr the {@link y.view.NodeRealizer} to which node ports are added.
126    * @return the specified realizer instance.
127    */
128   private NodeRealizer addDynamicPorts( final NodeRealizer nr ) {
129     return addPorts(
130             nr,
131             PortConfigurations.INSTANCE.portConfigDynamic,
132             NodeScaledPortLocationModel.POLICY_BOUNDARY,
133             new YPoint[]{
134                     new YPoint(nr.getCenterX(), nr.getY()),
135                     new YPoint(nr.getX(), nr.getCenterY()),
136                     new YPoint(nr.getCenterX(), nr.getY() + nr.getHeight()),
137                     new YPoint(nr.getX() + nr.getWidth(), nr.getCenterY()),
138             }
139     );
140   }
141 
142   /**
143    * Adds rectangular node ports to the specified realizer.
144    * @param nr the {@link y.view.NodeRealizer} to which node ports are added.
145    * @return the specified realizer instance.
146    */
147   private NodeRealizer addRectanglePort( final NodeRealizer nr ) {
148     final double x = nr.getX();
149     final double y = nr.getY();
150     final double w = nr.getWidth();
151     final double h = nr.getHeight();
152     return addPorts(
153             nr,
154             PortConfigurations.INSTANCE.portConfigRectangle,
155             NodeScaledPortLocationModel.POLICY_BOUNDARY,
156             new YPoint[] {
157                     new YPoint(x, y + h * 0.25),
158                     new YPoint(x, y + h * 0.75),
159                     new YPoint(x + w, y + h * 0.25),
160                     new YPoint(x + w, y + h * 0.75),
161             }
162     );
163   }
164 
165   /**
166    * Adds elliptical node ports to the specified realizer.
167    * @param nr the {@link y.view.NodeRealizer} to which node ports are added.
168    * @return the specified realizer instance.
169    */
170   private NodeRealizer addEllipsePorts( final NodeRealizer nr ) {
171     final double x = nr.getX();
172     final double y = nr.getY();
173     final double w = nr.getWidth();
174     final double h = nr.getHeight();
175     return addPorts(
176             nr,
177             PortConfigurations.INSTANCE.portConfigEllipse,
178             NodeScaledPortLocationModel.POLICY_BOUNDARY_CENTER,
179             new YPoint[]{
180                     new YPoint(x, y + h * 0.25),
181                     new YPoint(x, y + h * 0.75),
182                     new YPoint(x + w * 0.25, y + h),
183                     new YPoint(x + w * 0.5, y + h),
184                     new YPoint(x + w * 0.75, y + h),
185                     new YPoint(x + w, y + h * 0.75),
186                     new YPoint(x + w, y + h * 0.25),
187                     new YPoint(x + w * 0.75, y),
188                     new YPoint(x + w * 0.5, y),
189                     new YPoint(x + w * 0.25, y),
190             }
191     );
192   }
193 
194   /**
195    * Adds a node port to the specified realizer for each of the specified
196    * port positions.
197    * @param nr the {@link y.view.NodeRealizer} to which node ports are added.
198    * @param configuration the name of the node port configuration for the
199    * added node ports.
200    * @param policy the location policy of the {@link y.view.PortLocationModel}
201    * used for the added node ports.
202    * @param positions the positions of the added node ports.
203    * @return the specified realizer instance.
204    */
205   private NodeRealizer addPorts(
206           final NodeRealizer nr,
207           final String configuration,
208           final byte policy,
209           final YPoint[] positions
210   ) {
211     for (int i = 0; i < positions.length; ++i) {
212       final NodePort port = new NodePort();
213       port.setConfiguration(configuration);
214       nr.addPort(port);
215       final NodeScaledPortLocationModel model = new NodeScaledPortLocationModel();
216       model.setPortLocationPolicy(policy);
217       port.setModelParameter(model.createParameter(nr, positions[i]));
218     }
219 
220     return nr;
221   }
222 }
223