1
14 package demo.view.advanced.ports;
15
16 import demo.view.DemoBase;
17 import demo.view.DemoDefaults;
18 import demo.view.application.DragAndDropDemo;
19 import y.base.Edge;
20 import y.base.Node;
21 import y.base.YList;
22 import y.geom.YPoint;
23 import y.geom.YRectangle;
24 import y.layout.LayoutOrientation;
25 import y.layout.hierarchic.IncrementalHierarchicLayouter;
26 import y.view.Arrow;
27 import y.view.CreateEdgeMode;
28 import y.view.EdgeRealizer;
29 import y.view.EditMode;
30 import y.view.GenericNodeRealizer;
31 import y.view.Graph2D;
32 import y.view.HotSpotMode;
33 import y.view.LineType;
34 import y.view.MovePortMode;
35 import y.view.NodeLabel;
36 import y.view.NodePort;
37 import y.view.NodeScaledPortLocationModel;
38 import y.view.NodeRealizer;
39 import y.view.HitInfo;
40 import y.view.Drawable;
41 import y.view.AbstractCustomNodePainter;
42 import y.view.SmartNodeLabelModel;
43 import y.view.YRenderingHints;
44 import y.view.Graph2DTraversal;
45 import y.view.Graph2DLayoutExecutor;
46
47 import javax.swing.AbstractAction;
48 import javax.swing.Action;
49 import javax.swing.JList;
50 import javax.swing.JScrollPane;
51 import javax.swing.JToolBar;
52 import javax.swing.event.ListSelectionEvent;
53 import javax.swing.event.ListSelectionListener;
54 import java.awt.BorderLayout;
55 import java.awt.Color;
56 import java.awt.EventQueue;
57 import java.awt.Insets;
58 import java.awt.Graphics2D;
59 import java.awt.Rectangle;
60 import java.awt.GradientPaint;
61 import java.awt.Shape;
62 import java.awt.geom.Ellipse2D;
63 import java.awt.geom.Rectangle2D;
64 import java.awt.geom.GeneralPath;
65 import java.awt.geom.Arc2D;
66 import java.awt.geom.AffineTransform;
67 import java.awt.geom.Line2D;
68 import java.awt.event.ActionEvent;
69 import java.awt.event.MouseEvent;
70 import java.util.ArrayList;
71 import java.util.List;
72 import java.util.Locale;
73 import java.util.Map;
74 import java.util.HashMap;
75 import java.util.Iterator;
76
77
88 public class LogicGatesDemo extends DemoBase {
89 private static final String AND_GATE_NODE_CONFIGURATION = "AndGateNodeConfiguration";
90 private static final String NAND_GATE_NODE_CONFIGURATION = "NandGateNodeConfiguration";
91 private static final String NOT_GATE_NODE_CONFIGURATION = "NotGateNodeConfiguration";
92 private static final String PORT_CONFIG_INPUT = "INPUT_PORT";
93 private static final String PORT_CONFIG_OUTPUT = "OUTPUT_PORT";
94 private static final Color PORT_HIGHLIGHT_COLOR = Color.GREEN;
95 private static final Color LINE_COLOR = Color.BLACK;
96 private static final LineType LINE_TYPE = LineType.LINE_2;
97
98 public LogicGatesDemo() {
99 this(null);
100 }
101
102 public LogicGatesDemo( final String helpFilePath ) {
103 loadGraph("resource/LogicGatesDemo.graphml");
105 addHelpPane(helpFilePath);
106 }
107
108 protected JToolBar createToolBar() {
113 final IncrementalHierarchicLayouter ihl = new IncrementalHierarchicLayouter();
114 ihl.setLayoutOrientation(LayoutOrientation.LEFT_TO_RIGHT);
115 ihl.setOrthogonallyRouted(true);
116 final Graph2DLayoutExecutor executor = new Graph2DLayoutExecutor();
117 executor.getNodePortConfigurator().setAutomaticPortConstraintsEnabled(true);
119
120 final Action layoutAction = new AbstractAction(
121 "Layout", SHARED_LAYOUT_ICON) {
122 public void actionPerformed(ActionEvent e) {
123 executor.doLayout(view, ihl);
124 }
125 };
126
127 final JToolBar jtb = super.createToolBar();
128 jtb.addSeparator();
129 jtb.add(createActionControl(layoutAction));
130 return jtb;
131 }
132
133 protected void initialize() {
134 initializePortConfiguration();
135
136 List gatesNRList = new ArrayList();
138 GenericNodeRealizer.Factory gnrFactory = GenericNodeRealizer.getFactory();
139
140 Map andSymbolConfMap = gnrFactory.createDefaultConfigurationMap();
142 AndGateConfiguration andGateHandler = new AndGateConfiguration(true);
143 andSymbolConfMap.put(GenericNodeRealizer.Painter.class, andGateHandler);
144 andSymbolConfMap.put(GenericNodeRealizer.ContainsTest.class, andGateHandler);
145 gnrFactory.addConfiguration(AND_GATE_NODE_CONFIGURATION, andSymbolConfMap);
146 GenericNodeRealizer andRealizer = new GenericNodeRealizer(AND_GATE_NODE_CONFIGURATION);
147 andRealizer.setSize(100, 50);
148 andRealizer.setLineColor(Color.BLACK);
149 andRealizer.setLineType(LINE_TYPE);
150 andRealizer.setFillColor2(Color.WHITE);
151 andRealizer.setFillColor(DemoDefaults.DEFAULT_CONTRAST_COLOR);
152 configureLabelModel(andRealizer.getLabel());
153 addPort(andRealizer, new YPoint(-0.5, -0.25), PORT_CONFIG_INPUT);
154 addPort(andRealizer, new YPoint(-0.5, 0.25), PORT_CONFIG_INPUT);
155 addPort(andRealizer, new YPoint( 0.5, 0.0), PORT_CONFIG_OUTPUT);
156 gatesNRList.add(andRealizer);
157
158 Map nandSymbolConfMap = gnrFactory.createDefaultConfigurationMap();
160 AndGateConfiguration nandGateHandler = new AndGateConfiguration(false);
161 nandSymbolConfMap.put(GenericNodeRealizer.Painter.class, nandGateHandler);
162 nandSymbolConfMap.put(GenericNodeRealizer.ContainsTest.class, nandGateHandler);
163 gnrFactory.addConfiguration(NAND_GATE_NODE_CONFIGURATION, nandSymbolConfMap);
164 GenericNodeRealizer nandRealizer = new GenericNodeRealizer(NAND_GATE_NODE_CONFIGURATION);
165 nandRealizer.setSize(100, 50);
166 nandRealizer.setLineColor(Color.BLACK);
167 nandRealizer.setLineType(LINE_TYPE);
168 nandRealizer.setFillColor2(Color.WHITE);
169 nandRealizer.setFillColor(DemoDefaults.DEFAULT_CONTRAST_COLOR);
170 configureLabelModel(nandRealizer.getLabel());
171 addPort(nandRealizer, new YPoint(-0.5, -0.25), PORT_CONFIG_INPUT);
172 addPort(nandRealizer, new YPoint(-0.5, 0.25), PORT_CONFIG_INPUT);
173 addPort(nandRealizer, new YPoint( 0.5, 0.0), PORT_CONFIG_OUTPUT);
174 gatesNRList.add(nandRealizer);
175
176 Map notSymbolConfMap = gnrFactory.createDefaultConfigurationMap();
178 NotGateConfiguration notGateHandler = new NotGateConfiguration();
179 notSymbolConfMap.put(GenericNodeRealizer.Painter.class, notGateHandler);
180 notSymbolConfMap.put(GenericNodeRealizer.ContainsTest.class, notGateHandler);
181 gnrFactory.addConfiguration(NOT_GATE_NODE_CONFIGURATION, notSymbolConfMap);
182 GenericNodeRealizer notRealizer = new GenericNodeRealizer(NOT_GATE_NODE_CONFIGURATION);
183 notRealizer.getLabel().setInsets(new Insets(0, 0, 0, 15));
184 notRealizer.setSize(100, 50);
185 notRealizer.setLineColor(Color.BLACK);
186 notRealizer.setLineType(LINE_TYPE);
187 notRealizer.setFillColor2(Color.WHITE);
188 notRealizer.setFillColor(DemoDefaults.DEFAULT_CONTRAST_COLOR);
189 configureLabelModel(notRealizer.getLabel());
190 addPort(notRealizer, new YPoint(-0.5, 0.0), PORT_CONFIG_INPUT);
191 addPort(notRealizer, new YPoint( 0.5, 0.0), PORT_CONFIG_OUTPUT);
192 gatesNRList.add(notRealizer);
193
194 final Graph2D graph = this.view.getGraph2D();
195
196 final GenericNodeRealizer[] logicSymbols = new GenericNodeRealizer[gatesNRList.size()];
197 gatesNRList.toArray(logicSymbols);
198
199 EdgeRealizer er = graph.getDefaultEdgeRealizer();
201 er.setLineType(LINE_TYPE);
202 er.setLineColor(LINE_COLOR);
203 er.setArrow(Arrow.NONE);
204
205 DragAndDropDemo.DragAndDropSupport dragAndDropSupport = new DragAndDropDemo.DragAndDropSupport(logicSymbols, view);
207 dragAndDropSupport.configureSnapping(true, 30, 20, true);
208
209 final JList list = dragAndDropSupport.getList();
211 list.addListSelectionListener(new ListSelectionListener() {
212 public void valueChanged(ListSelectionEvent e) {
213 graph.setDefaultNodeRealizer(logicSymbols[list.getSelectedIndex()]);
214 }
215 });
216
217 list.setSelectedIndex(0);
219 JScrollPane scrollPane = new JScrollPane(list);
220
221 contentPane.add(scrollPane, BorderLayout.WEST);
222 }
223
224 private static void configureLabelModel(NodeLabel label) {
225 SmartNodeLabelModel model = new SmartNodeLabelModel();
226 label.setLabelModel(model);
227 label.setModelParameter(model.getDefaultParameter());
228 }
229
230 private static void addPort(GenericNodeRealizer owner, YPoint relativeOffsets, String portConfiguration) {
231 NodePort port = new NodePort();
232 owner.addPort(port);
233 port.setConfiguration(portConfiguration);
234 port.setModelParameter(new NodeScaledPortLocationModel().createScaledParameter(relativeOffsets));
235 }
236
237 private void initializePortConfiguration() {
238 final HashMap portImpls = new HashMap();
239
240 portImpls.put(NodePort.BoundsProvider.class, new NodePort.BoundsProvider() {
243 public YRectangle getBounds(NodePort port) {
244 return getLogicGateHandler(port).getBounds(port);
245 }
246
247 private LogicGateConfiguration getLogicGateHandler(NodePort port) {
248 String configuration = ((GenericNodeRealizer) port.getRealizer()).getConfiguration();
249 GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();
250 return (LogicGateConfiguration) factory.getImplementation(configuration, GenericNodeRealizer.ContainsTest.class);
251 }
252 });
253 portImpls.put(NodePort.Painter.class, new NodePort.Painter() {
255 public void paint(NodePort port, Graphics2D gfx) {
256 YRectangle bounds = port.getBounds();
257 gfx.setStroke(LINE_TYPE);
259 gfx.setColor(LINE_COLOR);
260 gfx.draw(new Line2D.Double(bounds.getX(), bounds.getY(), bounds.getX() + bounds.getWidth(), bounds.getY()));
261 }
262 });
263 NodePort.getFactory().addConfiguration(PORT_CONFIG_INPUT, portImpls);
264 NodePort.getFactory().addConfiguration(PORT_CONFIG_OUTPUT, portImpls);
265 }
266
267 protected EditMode createEditMode() {
268 EditMode editMode = new HighlightOutputPortsEditMode();
269 editMode.setMoveNodePortMode(null);
270 editMode.allowMovePorts(true);
271 editMode.setOrthogonalEdgeRouting(true);
272 editMode.assignNodeLabel(false);
273
274 CreateEdgeMode createEdgeMode = new CreateEdgeMode() {
276 protected boolean acceptSourceNodePort(Node node, NodePort port, double x, double y) {
277 return isOutput(port);
279 }
280 protected boolean acceptTargetNodePort(Node node, NodePort port, double x, double y) {
281 return isInput(port);
283 }
284 protected void drawTargetPortIndicator(Graphics2D gfx, final NodePort port) {
285 if (isInput(port)) {
288 highlightPort(gfx, port);
289 }
290 }
291 };
292 createEdgeMode.setIndicatingTargetNode(true);
293 createEdgeMode.setOrthogonalEdgeCreation(true);
294 editMode.setCreateEdgeMode(createEdgeMode);
295
296 HotSpotMode hotSpotMode = new HotSpotMode() {
298 protected boolean isModifierPressed(MouseEvent me) {
299 return true;
300 }
301 };
302 editMode.setHotSpotMode(hotSpotMode);
303
304 final MovePortMode mpm = new MovePortMode() {
306 protected YList getPortCandidates(Node v, Edge e, double gridSpacing) {
307 YList result = new YList();
308 NodeRealizer nr = getGraph2D().getRealizer(v);
309 boolean newTarget = port == port.getOwner().getTargetPort();
311 for (int i = 0; i < nr.portCount(); i++) {
312 final NodePort nodePort = nr.getPort(i);
313 if ((newTarget && isInput(nodePort)) || (!newTarget && isOutput(nodePort))) {
314 result.add(nodePort.getLocation());
315 }
316 }
317 return result;
318 }
319
320 protected void drawPortCandidate(Graphics2D gfx, YPoint p, Node v, Edge e, boolean isSnapActive,
321 boolean isSnapCandidate) {
322 if (isSnapCandidate) {
324 HitInfo info = view.getHitInfoFactory().createHitInfo(p.x, p.y, Graph2DTraversal.NODE_PORTS, true);
325 NodePort hitNodePort = info.getHitNodePort();
326 if (hitNodePort != null && isInput(hitNodePort)) {
327 highlightPort(gfx, hitNodePort);
328 }
329 }
330 }
331 };
332 mpm.setChangeEdgeEnabled(true);
333 mpm.setUsingRealizerPortCandidates(true);
334 mpm.setUsingNodePortCandidates(true);
335 mpm.setSegmentSnappingEnabled(true);
336 editMode.setMovePortMode(mpm);
337
338 return editMode;
339 }
340
341 private boolean isInput(NodePort port) {
342 return port.getConfiguration().equals(PORT_CONFIG_INPUT);
343 }
344
345 private boolean isOutput(NodePort port) {
346 return port.getConfiguration().equals(PORT_CONFIG_OUTPUT);
347 }
348
349 public static void highlightPort(Graphics2D gfx, NodePort port1) {
351 final YRectangle bounds = port1.getBounds();
352 Rectangle2D.Double box = new Rectangle2D.Double(
353 bounds.getX(), bounds.getY() - 2, bounds.getWidth(), bounds.getHeight() + 4);
354 Color oldColor = gfx.getColor();
355 gfx.setColor(PORT_HIGHLIGHT_COLOR);
356 gfx.fill(box);
357 gfx.setColor(oldColor);
358 }
359
360 public static void main(String[] args) {
361 EventQueue.invokeLater(new Runnable() {
362 public void run() {
363 Locale.setDefault(Locale.ENGLISH);
364 initLnF();
365 (new LogicGatesDemo("resource/logicgateshelp.html")).start();
366 }
367 });
368 }
369
370
371 private class HighlightOutputPortsEditMode extends EditMode {
372 private Node previousNode;
373 private ArrayList portHighlightDrawables;
374
375 public HighlightOutputPortsEditMode() {
376 super();
377 portHighlightDrawables = new ArrayList();
378 }
379
380 public void mousePressed(MouseEvent e) {
381 unhighlightPorts();
382 super.mousePressed(e);
383 }
384
385 public void mouseMoved(double x, double y) {
386 super.mouseMoved(x, y);
387 final HitInfo hi = getHitInfo(x, y);
388 if (hi.hasHitNodes()) {
389 final Node node = hi.getHitNode();
391 final Graph2D graph = view.getGraph2D();
392 final NodeRealizer nr = graph.getRealizer(node);
393 if ((node != previousNode) && !nr.isSelected()) {
394 unhighlightPorts();
396 for (int i = 0; i < nr.portCount(); i++) {
397 final NodePort port = nr.getPort(i);
398 if (isOutput(port)) {
399 highlight(port);
400 }
401 }
402 view.updateView();
403 previousNode = node;
404 }
405 } else {
406 previousNode = null;
407 unhighlightPorts();
408 }
409 }
410
411 private void highlight(NodePort port) {
412 PortHighlightDrawable portHighlightDrawable = new PortHighlightDrawable(port);
413 portHighlightDrawables.add(portHighlightDrawable);
414 view.addDrawable(portHighlightDrawable);
415 }
416
417 private void unhighlightPorts() {
418 if (!portHighlightDrawables.isEmpty()) {
419 for (Iterator ports = portHighlightDrawables.iterator(); ports.hasNext();) {
420 PortHighlightDrawable currPortHighlightDrawable = (PortHighlightDrawable) ports.next();
421 view.removeDrawable(currPortHighlightDrawable);
422 }
423 portHighlightDrawables.clear();
424 view.updateView();
425 }
426 }
427 }
428
429
430 private static final class PortHighlightDrawable implements Drawable {
431 private NodePort port;
432
433 public PortHighlightDrawable(NodePort port) {
434 this.port = port;
435 }
436
437 public void paint(Graphics2D gfx) {
438 highlightPort(gfx, port);
439 }
440
441 public Rectangle getBounds() {
442 YRectangle rect = port.getBounds();
443 return new Rectangle((int) rect.getX(), (int) rect.getY(), (int) rect.getWidth(), (int) rect.getHeight());
444 }
445 }
446
447
453 private abstract static class LogicGateConfiguration
454 extends AbstractCustomNodePainter implements GenericNodeRealizer.ContainsTest {
455
456 private static final double REALLY_SMALL_HEIGHT = 0.001;
459
460 private static final Rectangle2D.Double rawBounds = new Rectangle2D.Double(0, 0, 120, 60);
462
463 protected GeneralPath symbol;
465
466 private boolean inverted;
468
469 protected LogicGateConfiguration(boolean inverted) {
470 super();
471 this.inverted = inverted;
472 }
473
474 public boolean isInverted() {
475 return inverted;
476 }
477
478 protected GeneralPath getSymbol() {
479 return symbol;
480 }
481
482 protected Rectangle2D.Double getRawBounds() {
483 return rawBounds;
484 }
485
486 protected void paintNode(NodeRealizer context, Graphics2D graphics, boolean sloppy) {
488 Shape shape = getTransformedSymbol(context);
489 final boolean useSelectionStyle = useSelectionStyle(context, graphics);
490 Color fillColor1 = getFillColor(context, useSelectionStyle);
491 Color fillColor2 = getFillColor2(context, useSelectionStyle);
492 if (fillColor2 != null && useGradientStyle(graphics)) {
493 double x = context.getX();
494 double y = context.getY();
495 double width = context.getWidth();
496 double height = context.getHeight();
497 GradientPaint gp = new GradientPaint(
498 (float) x, (float) y, fillColor2,
499 (float) (x + width * 0.5), (float) (y + height * 0.5), fillColor1);
500 graphics.setPaint(gp);
501 } else {
502 graphics.setColor(fillColor1);
503 }
504 graphics.fill(shape);
505 graphics.setStroke(getLineStroke(context, useSelectionStyle));
506 graphics.setColor(getLineColor(context, useSelectionStyle));
507 graphics.draw(shape);
508 }
509
510 public boolean contains(NodeRealizer context, double x, double y) {
513 if (!context.getBoundingBox().contains(x, y)) {
514 return false;
517 }
518 if (getTransformedSymbol(context).contains(x, y)) {
519 return true;
520 }
521 for (int i = 0; i < context.portCount(); i++) {
523 NodePort port = context.getPort(i);
524 YRectangle bounds = port.getBounds();
525 double tolerance = 4;
526 if (bounds.x - tolerance <= x && x <= bounds.x + bounds.width + tolerance &&
527 bounds.y - tolerance <= y && y <= bounds.y + bounds.height + tolerance) {
528 return true;
529 }
530 }
531 return false;
532 }
533
534 public YRectangle getBounds(NodePort port) {
538 YPoint location = port.getLocation();
539 if (port.getConfiguration().equals(PORT_CONFIG_INPUT)) {
540 double width = getXScale(port.getRealizer()) * getLeftOffset();
541 return new YRectangle(location.getX(), location.getY(), width, REALLY_SMALL_HEIGHT);
542 } else {
543 double width = getXScale(port.getRealizer()) * getRightOffset();
544 return new YRectangle(location.getX() - width, location.getY(), width, REALLY_SMALL_HEIGHT);
545 }
546 }
547
548 static boolean useGradientStyle( final Graphics2D graphics ) {
549 return YRenderingHints.isGradientPaintingEnabled(graphics);
550 }
551
552 static boolean useSelectionStyle(
553 final NodeRealizer context,
554 final Graphics2D gfx
555 ) {
556 return context.isSelected() &&
557 YRenderingHints.isSelectionPaintingEnabled(gfx);
558 }
559
560 private Shape getTransformedSymbol(NodeRealizer context) {
563 AffineTransform transform = new AffineTransform();
564 Rectangle2D.Double bounds = getRawBounds();
565 transform.translate(context.getX() - bounds.getX(), context.getY() - bounds.getY());
566 transform.scale(getXScale(context), getYScale(context));
567 return getSymbol().createTransformedShape(transform);
568 }
569
570 protected double getYScale(NodeRealizer context) {
571 return context.getHeight() / getRawBounds().getHeight();
572 }
573
574 protected double getXScale(NodeRealizer context) {
575 return context.getWidth() / getRawBounds().getWidth();
576 }
577
578 private double getLeftOffset() {
579 return getSymbol().getBounds2D().getX() - getRawBounds().getX();
580 }
581
582 private double getRightOffset() {
583 return getRawBounds().getMaxX() - getSymbol().getBounds2D().getMaxX();
584 }
585 }
586
587 private static class AndGateConfiguration extends LogicGateConfiguration {
588 public AndGateConfiguration(boolean inverted) {
589 super(inverted);
590
591 symbol = new GeneralPath();
592 symbol.moveTo(70f, 0f);
593 symbol.lineTo(20f, 0f);
594 symbol.lineTo(20f, 60f);
595 symbol.lineTo(70f, 60f);
596 symbol.append(new Arc2D.Double(40, 0, 60, 60, 270, 180, Arc2D.OPEN), true);
597
598 if (isInverted()) {
600 Ellipse2D negationSymbol = new Ellipse2D.Double();
601 negationSymbol.setFrame(100, 26, 8, 8);
602 symbol.append(negationSymbol, false);
603 }
604 }
605 }
606
607 private static class NotGateConfiguration extends LogicGateConfiguration {
608 public NotGateConfiguration() {
609 super(true);
610
611 symbol = new GeneralPath();
612 symbol.moveTo(30f, 0f);
613 symbol.lineTo(90f, 30f);
614 symbol.lineTo(30f, 60f);
615 symbol.closePath();
616
617 Ellipse2D negationSymbol = new Ellipse2D.Double();
618 negationSymbol.setFrame(90, 26, 8, 8);
619 symbol.append(negationSymbol, false);
620 }
621 }
622 }