1   
28  package demo.view.advanced.ports;
29  
30  import y.base.Node;
31  import y.base.NodeList;
32  import y.geom.YPoint;
33  import y.geom.YRectangle;
34  import y.view.Graph2D;
35  import y.view.HitInfo;
36  import y.view.NodeLabel;
37  import y.view.NodePort;
38  import y.view.NodeRealizer;
39  import y.view.NodeScaledPortLocationModel;
40  import y.view.PopupMode;
41  import y.view.PortLabelModel;
42  import y.view.PortLocationModel;
43  import y.view.ShapeNodeRealizer;
44  
45  import java.awt.Component;
46  import java.awt.Graphics;
47  import java.awt.Graphics2D;
48  import java.awt.event.ActionEvent;
49  import javax.swing.AbstractAction;
50  import javax.swing.Icon;
51  import javax.swing.JMenu;
52  import javax.swing.JPopupMenu;
53  
54  
58  final class NodePortPopupMode extends PopupMode {
59    private YPoint point;
60  
61  
62    
67    public JPopupMenu getNodeLabelPopup( final NodeLabel label ) {
68      final JPopupMenu jpm = new JPopupMenu("NodeLabel");
69      jpm.add(new AbstractAction("Edit Label") {
70        public void actionPerformed( final ActionEvent e ) {
71          editLabel(label);
72        }
73      });
74      jpm.add(new AbstractAction("Delete Label") {
75        public void actionPerformed( final ActionEvent e ) {
76          final NodeRealizer nr = label.getRealizer();
77          nr.removeLabel(label);
78          getGraph2D().updateViews();
79        }
80      });
81      return jpm;
82    }
83  
84    
89    public JPopupMenu getNodePopup( final Node v ) {
90      final JPopupMenu jpm = new JPopupMenu("Node");
91      jpm.add(new AbstractAction("Add NodePort") {
92        {
93          setEnabled(false);
94        }
95        public void actionPerformed( final ActionEvent e ) {
96        }
97      });
98      jpm.add(new AddPortAction(PortConfigurations.INSTANCE.portConfigRectangle, v));
99      jpm.add(new AddPortAction(PortConfigurations.INSTANCE.portConfigDynamic, v));
100     jpm.add(new AddPortAction(PortConfigurations.INSTANCE.portConfigEllipse, v));
101     return jpm;
102   }
103 
104   
112   public JPopupMenu getNodePortPopup( final NodePort port ) {
113     final JPopupMenu jpm = new JPopupMenu("NodePort");
114 
115     jpm.add(new AbstractAction("Add Label") {
116       public void actionPerformed( final ActionEvent e ) {
117         editLabel(addPortLabel(port.getRealizer(), port, "Port"));
118       }
119     });
120 
121     final JMenu policies = new JMenu("Change Location Policy");
122     policies.add(new ChangeLocationPolicyAction(
123             port, NodeScaledPortLocationModel.POLICY_DISCRETE));
124     policies.add(new ChangeLocationPolicyAction(
125             port, NodeScaledPortLocationModel.POLICY_BOUNDARY));
126     policies.add(new ChangeLocationPolicyAction(
127             port, NodeScaledPortLocationModel.POLICY_BOUNDARY_CENTER));
128     policies.add(new ChangeLocationPolicyAction(
129             port, NodeScaledPortLocationModel.POLICY_BOUNDARY_INSIDE));
130     policies.add(new ChangeLocationPolicyAction(
131             port, NodeScaledPortLocationModel.POLICY_FREE));
132     policies.addSeparator();
133     policies.add(new ChangeSideLocationAction(
134             port, SidePortLocationModel.SIDE_TOP));
135     policies.add(new ChangeSideLocationAction(
136             port, SidePortLocationModel.SIDE_LEFT));
137     policies.add(new ChangeSideLocationAction(
138             port, SidePortLocationModel.SIDE_BOTTOM));
139     policies.add(new ChangeSideLocationAction(
140             port, SidePortLocationModel.SIDE_RIGHT));
141     jpm.add(policies);
142 
143     jpm.add(new AbstractAction("Remove Port") {
144       public void actionPerformed( final ActionEvent e ) {
145         final Graph2D graph = getGraph2D();
146         graph.firePreEvent();
147         try {
148           removePortImpl(graph, port);
149         } finally {
150           graph.firePostEvent();
151         }
152 
153         graph.updateViews();
154       }
155 
156       private void removePortImpl( final Graph2D graph, final NodePort port ) {
157         final NodeRealizer nr = port.getRealizer();
158         final Node node = nr.getNode();
159         graph.backupRealizers((new NodeList(node)).nodes());
160 
161         NodePort.remove(port);
162       }
163     });
164     return jpm;
165   }
166 
167   
176   protected JPopupMenu getPopup(
177           final HitInfo hitInfo,
178           final double x,
179           final double y,
180           final int popupType
181   ) {
182     point = new YPoint(x ,y);
183     return super.getPopup(hitInfo, x, y, popupType);
184   }
185 
186 
187 
188   private NodeLabel addPortLabel(
189           final NodeRealizer nr,
190           final NodePort port,
191           final String text
192   ) {
193     final NodeLabel nl = nr.createNodeLabel();
194     nl.setText(text);
195     nl.setLabelModel(new PortLabelModel(3),
196         PortLabelModel.createParameter(port, PortLabelModel.NORTH));
197     nr.addLabel(nl);
198     return nl;
199   }
200 
201   private void editLabel( final NodeLabel label ) {
202     final YRectangle bnds = label.getBox();
203     view.openLabelEditor(
204             label,
205             bnds.getX(),
206             bnds.getY(),
207             null,
208             true
209             );
210   }
211 
212 
213   
218   private final class ChangeLocationPolicyAction extends AbstractAction {
219     private final byte policy;
220     private final NodePort port;
221 
222     
228     ChangeLocationPolicyAction( final NodePort port, final byte policy ) {
229       super(createActionName(policy));
230       this.policy = policy;
231       this.port = port;
232 
233       final PortLocationModel model = port.getModelParameter().getModel();
234       if (model instanceof NodeScaledPortLocationModel &&
235           ((NodeScaledPortLocationModel) model).getPortLocationPolicy() == policy) {
236         setEnabled(false);
237       }
238     }
239 
240     public void actionPerformed( final ActionEvent e ) {
241       final Graph2D graph = getGraph2D();
242       graph.firePreEvent();
243       try {
244         changeLocationPolicyImpl(port, policy);
245       } finally {
246         graph.firePostEvent();
247       }
248 
249       graph.updateViews();
250     }
251 
252     
259     private void changeLocationPolicyImpl(
260             final NodePort port, final byte policy
261     ) {
262       final YPoint location = port.getLocation();
263       final PortLocationModel model = port.getModelParameter().getModel();
264       if (model instanceof NodeScaledPortLocationModel) {
265         ((NodeScaledPortLocationModel) model).setPortLocationPolicy(policy);
266         port.setModelParameter(model.createParameter(port.getRealizer(), location));
267       } else {
268         final NodeScaledPortLocationModel nsplm = new NodeScaledPortLocationModel();
269         nsplm.setPortLocationPolicy(policy);
270         port.setModelParameter(nsplm.createParameter(port.getRealizer(), location));
271       }
272     }
273   }
274 
275   
281   private static String createActionName( final byte policy ) {
282     switch (policy) {
283       case NodeScaledPortLocationModel.POLICY_DISCRETE:
284         return "Discrete";
285       case NodeScaledPortLocationModel.POLICY_BOUNDARY:
286         return "Boundary";
287       case NodeScaledPortLocationModel.POLICY_BOUNDARY_CENTER:
288         return "Boundary or Center";
289       case NodeScaledPortLocationModel.POLICY_BOUNDARY_INSIDE:
290         return "Inside";
291       case NodeScaledPortLocationModel.POLICY_FREE:
292         return "Free";
293       default:
294         return "Unknown";
295     }
296   }
297 
298   
303   private final class ChangeSideLocationAction extends AbstractAction {
304     private final int side;
305     private final NodePort port;
306 
307     
313     ChangeSideLocationAction( final NodePort port, final int side ) {
314       super(createActionName(side));
315       this.side = side;
316       this.port = port;
317 
318       final PortLocationModel model = port.getModelParameter().getModel();
319       if (model instanceof SidePortLocationModel &&
320           ((SidePortLocationModel) model).getSides() == side) {
321         setEnabled(false);
322       }
323     }
324 
325     public void actionPerformed( final ActionEvent e ) {
326       final Graph2D graph = getGraph2D();
327       graph.firePreEvent();
328       try {
329         changeSideLocationImpl(port, side);
330       } finally {
331         graph.firePostEvent();
332       }
333 
334       graph.updateViews();
335     }
336 
337     
344     private void changeSideLocationImpl( final NodePort port, final int side ) {
345       final YPoint location = port.getLocation();
346       final SidePortLocationModel splm = SidePortLocationModel.newInstance(side);
347       port.setModelParameter(splm.createParameter(port.getRealizer(), location));
348     }
349   }
350 
351   
358   private static String createActionName( final int side ) {
359     switch (side) {
360       case SidePortLocationModel.SIDE_TOP:
361         return "Top only";
362       case SidePortLocationModel.SIDE_LEFT:
363         return "Left only";
364       case SidePortLocationModel.SIDE_BOTTOM:
365         return "Bottom only";
366       case SidePortLocationModel.SIDE_RIGHT:
367         return "Right only";
368       default:
369         return "Unknown";
370     }
371   }
372 
373   
377   private final class AddPortAction extends AbstractAction {
378     private final Node node;
379     private final String configuration;
380 
381     
388     AddPortAction( final String configurationName, final Node node ) {
389       super(createActionName(configurationName));
390       this.configuration = configurationName;
391       this.node = node;
392       putValue(SMALL_ICON, new PortIcon(configurationName));
393     }
394 
395     public void actionPerformed( final ActionEvent e ) {
396       final Graph2D graph = getGraph2D();
397       graph.firePreEvent();
398       try {
399         addPortImpl(graph, node, configuration);
400       } finally {
401         graph.firePostEvent();
402       }
403 
404       graph.updateViews();
405     }
406 
407     
414     private void addPortImpl(
415             final Graph2D graph,
416             final Node node,
417             final String portConfigId
418     ) {
419       graph.backupRealizers((new NodeList(node)).nodes());
420 
421       final NodeRealizer nr = graph.getRealizer(node);
422       final YPoint location =
423               point == null
424               ? new YPoint(nr.getCenterX(), nr.getCenterY())
425               : point;
426 
427       final NodeScaledPortLocationModel model = new NodeScaledPortLocationModel();
428       model.setPortLocationPolicy(NodeScaledPortLocationModel.POLICY_BOUNDARY);
429       final NodePort port = new NodePort();
430       port.setModelParameter(model.createParameter(nr, location));
431       port.setConfiguration(portConfigId);
432       nr.addPort(port);
433 
434       addPortLabel(nr, port, "Port " + nr.portCount());
435     }
436   }
437 
438   
444   private static String createActionName( final String portConfigId ) {
445     String s = portConfigId;
446     if (s != null) {
447       s = s.trim();
448       if (s.length() > 0) {
449         s = s.toUpperCase();
450         if (s.startsWith("PORT_")) {
451           s = s.substring(5);
452         }
453         if (s.length() > 1) {
454           s = s.charAt(0) + s.substring(1).toLowerCase();
455         }
456 
457         return s;
458       }
459     }
460     return null;
461   }
462 
463   
466   private static final class PortIcon implements Icon {
467     private static final int MARGIN = 2;
468 
469     private final NodePort port;
470     private final double x;
471     private final double y;
472     private final int w;
473     private final int h;
474 
475     PortIcon( final String configuration ) {
476       final NodeRealizer dummy = new ShapeNodeRealizer();
477       dummy.setFrame(0, 0, 10, 10);
478       port = new NodePort();
479       dummy.addPort(port);
480       port.setConfiguration(configuration);
481       final YRectangle bnds = port.getBounds();
482       w = (int) Math.ceil(bnds.getWidth()) + 2*MARGIN;
483       h = (int) Math.ceil(bnds.getHeight())  + 2*MARGIN;
484       x = bnds.getX() - MARGIN;
485       y = bnds.getY() - MARGIN;
486     }
487 
488     public int getIconHeight() {
489       return h;
490     }
491 
492     public int getIconWidth() {
493       return w;
494     }
495 
496     public void paintIcon( final Component c, final Graphics g, final int x, final int y ) {
497       final Graphics2D gfx = (Graphics2D) g.create();
498       gfx.translate(x - this.x, y - this.y);
499       port.paint(gfx);
500       gfx.dispose();
501     }
502   }
503 }
504