1
28 package demo.view;
29
30 import y.io.GraphMLIOHandler;
31 import y.io.IOHandler;
32 import y.module.YModule;
33 import y.option.DefaultEditorFactory;
34 import y.option.Editor;
35 import y.option.EditorFactory;
36 import y.option.GuiFactory;
37 import y.option.OptionHandler;
38 import y.util.D;
39 import y.view.AutoDragViewMode;
40 import y.view.CreateEdgeMode;
41 import y.view.EditMode;
42 import y.view.Graph2D;
43 import y.view.Graph2DClipboard;
44 import y.view.Graph2DPrinter;
45 import y.view.Graph2DTraversal;
46 import y.view.Graph2DUndoManager;
47 import y.view.Graph2DView;
48 import y.view.Graph2DViewActions;
49 import y.view.Graph2DViewMouseWheelZoomListener;
50 import y.view.HitInfo;
51 import y.view.MoveLabelMode;
52 import y.view.MovePortMode;
53 import y.view.MoveSelectionMode;
54 import y.view.MoveSnapContext;
55 import y.view.OrthogonalMoveBendsMode;
56 import y.view.HotSpotMode;
57 import y.view.TooltipMode;
58 import y.view.View2DConstants;
59 import y.view.DropSupport;
60
61 import javax.swing.AbstractAction;
62 import javax.swing.Action;
63 import javax.swing.ActionMap;
64 import javax.swing.BorderFactory;
65 import javax.swing.Icon;
66 import javax.swing.ImageIcon;
67 import javax.swing.InputMap;
68 import javax.swing.JButton;
69 import javax.swing.JComponent;
70 import javax.swing.JDialog;
71 import javax.swing.JEditorPane;
72 import javax.swing.JFileChooser;
73 import javax.swing.JFrame;
74 import javax.swing.JMenu;
75 import javax.swing.JMenuBar;
76 import javax.swing.JPanel;
77 import javax.swing.JRootPane;
78 import javax.swing.JScrollPane;
79 import javax.swing.JToolBar;
80 import javax.swing.JOptionPane;
81 import javax.swing.KeyStroke;
82 import javax.swing.filechooser.FileFilter;
83 import java.awt.BorderLayout;
84 import java.awt.Dimension;
85 import java.awt.EventQueue;
86 import java.awt.FlowLayout;
87 import java.awt.Frame;
88 import java.awt.Image;
89 import java.awt.Rectangle;
90 import java.awt.Color;
91 import java.awt.Toolkit;
92 import java.awt.event.ActionEvent;
93 import java.awt.event.ActionListener;
94 import java.awt.event.InputEvent;
95 import java.awt.event.KeyEvent;
96 import java.awt.print.PageFormat;
97 import java.awt.print.PrinterJob;
98 import java.io.File;
99 import java.io.IOException;
100 import java.net.MalformedURLException;
101 import java.net.URI;
102 import java.net.URISyntaxException;
103 import java.net.URL;
104 import java.util.regex.Pattern;
105
106
113 public abstract class DemoBase {
114
118 public static final Dimension TOOLBAR_SMALL_SEPARATOR = new Dimension(3, 3);
119
120 public static final Icon SHARED_LAYOUT_ICON = getIconResource("resource/layout.png");
121
122 private static final Pattern PATH_SEPARATOR_PATTERN = Pattern.compile("/");
123
124
127 public static void initLnF() {
128 DemoDefaults.initLnF();
129 }
130
131
134 protected Graph2DView view;
135
136 protected final JPanel contentPane;
137
138
141 private Graph2DUndoManager undoManager;
142
143
146 private Graph2DClipboard clipboard;
147
148
153 protected DemoBase() {
154 view = createGraphView();
155 configureDefaultRealizers();
156
157 contentPane = new JPanel();
158 contentPane.setLayout(new BorderLayout());
159
160 initialize();
161
162 registerViewModes();
163 registerViewActions();
164
165 contentPane.add(view, BorderLayout.CENTER);
166 final JToolBar jtb = createToolBar();
167 if (jtb != null) {
168 contentPane.add(jtb, BorderLayout.NORTH);
169 }
170
171 registerViewListeners();
172 }
173
174
178 protected Graph2DView createGraphView() {
179 Graph2DView view = new Graph2DView();
180 view.setFitContentOnResize(true);
181 return view;
182 }
183
184
188 protected void configureDefaultRealizers() {
189 DemoDefaults.configureDefaultRealizers(view);
190 }
191
192
196 protected void initialize() {
197 }
198
199 public void dispose() {
200 }
201
202 protected void loadGraph(URL resource) {
203
204 if (resource == null) {
205 String message = "Resource \"" + resource + "\" not found in classpath";
206 D.showError(message);
207 throw new RuntimeException(message);
208 }
209
210 try {
211 IOHandler ioh = createGraphMLIOHandler();
212 view.getGraph2D().clear();
213 ioh.read(view.getGraph2D(), resource);
214 } catch (IOException e) {
215 String message = "Unexpected error while loading resource \"" + resource + "\" due to " + e.getMessage();
216 D.bug(message);
217 throw new RuntimeException(message, e);
218 }
219 view.getGraph2D().setURL(resource);
220 view.fitContent();
221 view.updateView();
222
223 getUndoManager().resetQueue();
224 }
225
226 protected GraphMLIOHandler createGraphMLIOHandler() {
227 return new GraphMLIOHandler();
228 }
229
230 protected void loadGraph(Class aClass, String resourceString) {
231 final URL resource = getResource(aClass, resourceString);
232 if (resource == null) {
233 throw new RuntimeException("Resource \"" + resourceString +
234 "\" not found in classpath of " + aClass);
235 }
236 loadGraph(resource);
237 }
238
239 protected void loadGraph(String resourceString) {
240 loadGraph(getClass(), resourceString);
241 }
242
243
247 public final void start() {
248 start(getSimpleClassName());
249 }
250
251
254 private String getSimpleClassName() {
255 final String className = getClass().getName();
256 return className.substring(className.lastIndexOf('.') + 1);
257 }
258
259
263 public final void start(String title) {
264 JFrame frame = new JFrame(title);
265 JOptionPane.setRootFrame(frame);
266 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
267 frame.setIconImage(getFrameIcon());
268 this.addContentTo(frame.getRootPane());
269 frame.pack();
270 frame.setLocationRelativeTo(null);
271 frame.setVisible(true);
272 }
273
274 public void addContentTo(final JRootPane rootPane) {
275 final JMenuBar jmb = createMenuBar();
276 if (jmb != null) {
277 rootPane.setJMenuBar(jmb);
278 }
279 rootPane.setContentPane(contentPane);
280 }
281
282 protected void addHelpPane( final String helpFilePath ) {
283 if (helpFilePath != null) {
284 final URL url = getResource(helpFilePath);
285 if (url == null) {
286 System.err.println("Could not locate help file: " + helpFilePath);
287 } else {
288 final JComponent helpPane = createHelpPane(url);
289 if (helpPane != null) {
290 contentPane.add(helpPane, BorderLayout.EAST);
291 }
292 }
293 }
294 }
295
296
300 protected JComponent createHelpPane( final URL helpURL ) {
301 try {
302 JEditorPane editorPane = new JEditorPane(helpURL);
303 editorPane.setEditable(false);
304 editorPane.setPreferredSize(new Dimension(250, 250));
305 return new JScrollPane(editorPane);
306 } catch (IOException e) {
307 e.printStackTrace();
308 }
309 return null;
310 }
311
312
315 protected void registerViewActions() {
316 Graph2DViewActions actions = new Graph2DViewActions(view);
317 ActionMap amap = view.getCanvasComponent().getActionMap();
318 if (amap != null) {
319 InputMap imap = actions.createDefaultInputMap(amap);
320 if (!isDeletionEnabled()) {
321 amap.remove(Graph2DViewActions.DELETE_SELECTION);
322 } else {
323 amap.put(Graph2DViewActions.DELETE_SELECTION, createDeleteSelectionAction());
324 }
325 if (isUndoRedoEnabled()) {
326 amap.put("UNDO", getUndoManager().getUndoAction());
327 imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_MASK), "UNDO");
328
329 amap.put("REDO", getUndoManager().getRedoAction());
330 imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_MASK), "REDO");
331 }
332 if (isClipboardEnabled()) {
333 amap.put("CUT", getClipboard().getCutAction());
334 imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK), "CUT");
335
336 amap.put("COPY", getClipboard().getCopyAction());
337 imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK), "COPY");
338
339 amap.put("PASTE", getClipboard().getPasteAction());
340 imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK), "PASTE");
341 }
342 view.getCanvasComponent().setInputMap(JComponent.WHEN_FOCUSED, imap);
343 }
344 }
345
346
351 protected void registerViewModes() {
352 EditMode editMode = createEditMode();
353 if (editMode != null) {
354 view.addViewMode(editMode);
355 }
356
357 TooltipMode tooltipMode = createTooltipMode();
358 if(tooltipMode != null) {
359 view.addViewMode(tooltipMode);
360 }
361
362 view.addViewMode(new AutoDragViewMode());
363 }
364
365
371 protected EditMode createEditMode() {
372 return configureEditMode(new EditMode());
373 }
374
375
380 protected EditMode configureEditMode( final EditMode editMode ) {
381 if (editMode.getCreateEdgeMode() instanceof CreateEdgeMode) {
383 ((CreateEdgeMode) editMode.getCreateEdgeMode()).setIndicatingTargetNode(true);
384 }
385 if (editMode.getMovePortMode() instanceof MovePortMode) {
386 ((MovePortMode) editMode.getMovePortMode()).setIndicatingTargetNode(true);
387 }
388
389 editMode.allowMovingWithPopup(true);
391
392 return editMode;
393 }
394
395
401 protected TooltipMode createTooltipMode() {
402 TooltipMode tooltipMode = new TooltipMode();
403 tooltipMode.setEdgeTipEnabled(false);
404 return tooltipMode;
405 }
406
407
411 protected void registerViewListeners() {
412 Graph2DViewMouseWheelZoomListener wheelZoomListener = new Graph2DViewMouseWheelZoomListener();
413 wheelZoomListener.setCenterZooming(false);
415 wheelZoomListener.addToCanvas(view);
416 }
417
418
422 protected boolean isDeletionEnabled() {
423 return true;
424 }
425
426
429 protected boolean isUndoRedoEnabled() {
430 return true;
431 }
432
433
436 protected boolean isClipboardEnabled() {
437 return true;
438 }
439
440
443 protected JToolBar createToolBar() {
444 JToolBar toolBar = new JToolBar();
445 toolBar.setFloatable(false);
446 toolBar.add(new Zoom(view, 1.25));
447 toolBar.add(new Zoom(view, 0.8));
448 toolBar.add(new ResetZoom(view));
449 toolBar.add(new FitContent(view));
450 if (isDeletionEnabled()) {
451 toolBar.add(createDeleteSelectionAction());
452 }
453 if (isUndoRedoEnabled()) {
454 toolBar.addSeparator();
455 toolBar.add(createUndoAction());
456 toolBar.add(createRedoAction());
457 }
458 if (isClipboardEnabled()) {
459 toolBar.addSeparator();
460 toolBar.add(createCutAction());
461 toolBar.add(createCopyAction());
462 toolBar.add(createPasteAction());
463 }
464 return toolBar;
465 }
466
467
470 protected JMenuBar createMenuBar() {
471 JMenuBar menuBar = new JMenuBar();
472 JMenu menu = new JMenu("File");
473 Action action;
474 action = createLoadAction();
475 if (action != null) {
476 menu.add(action);
477 }
478 action = createSaveAction();
479 if (action != null) {
480 menu.add(action);
481 }
482 menu.addSeparator();
483 menu.add(new PrintAction());
484 menu.addSeparator();
485 menu.add(new ExitAction());
486 menuBar.add(menu);
487
488 if (getExampleResources() != null && getExampleResources().length != 0) {
489 createExamplesMenu(menuBar);
490 }
491
492 return menuBar;
493 }
494
495
499 protected Graph2DUndoManager getUndoManager() {
500 if (undoManager == null) {
501 undoManager = createUndoManager(view);
502 }
503 return undoManager;
504 }
505
506
509 protected Graph2DUndoManager createUndoManager(final Graph2DView view) {
510 Graph2DUndoManager undoManager = new Graph2DUndoManager(view.getGraph2D());
512
513 undoManager.setViewContainer(view);
516 return undoManager;
517 }
518
519
523 protected Graph2DClipboard getClipboard() {
524 if (clipboard == null) {
525 clipboard = createClipboard(view);
526 }
527 return clipboard;
528 }
529
530
533 protected Graph2DClipboard createClipboard(final Graph2DView view) {
534 Graph2DClipboard clipboard = new Graph2DClipboard(view);
535 clipboard.setCopyFactory(view.getGraph2D().getGraphCopyFactory());
536 return clipboard;
537 }
538
539 protected Action createLoadAction() {
540 return new LoadAction();
541 }
542
543 protected Action createSaveAction() {
544 return new SaveAction();
545 }
546
547 protected Action createDeleteSelectionAction() {
548 return new DeleteSelection(view);
549 }
550
551 protected Action createUndoAction() {
552 final Action action = getUndoManager().getUndoAction();
553 action.putValue(Action.SMALL_ICON, getIconResource("resource/undo.png"));
554 action.putValue(Action.SHORT_DESCRIPTION, "Undo");
555 return action;
556 }
557
558 protected Action createRedoAction() {
559 final Action action = getUndoManager().getRedoAction();
560 action.putValue(Action.SMALL_ICON, getIconResource("resource/redo.png"));
561 action.putValue(Action.SHORT_DESCRIPTION, "Redo");
562 return action;
563 }
564
565 protected Action createCutAction() {
566 final Action action = getClipboard().getCutAction();
567 action.putValue(Action.SMALL_ICON, getIconResource("resource/cut.png"));
568 action.putValue(Action.SHORT_DESCRIPTION, "Cut");
569 return action;
570 }
571
572 protected Action createCopyAction() {
573 final Action action = getClipboard().getCopyAction();
574 action.putValue(Action.SMALL_ICON, getIconResource("resource/copy.png"));
575 action.putValue(Action.SHORT_DESCRIPTION, "Copy");
576 return action;
577 }
578
579 protected Action createPasteAction() {
580 final Action action = getClipboard().getPasteAction();
581 action.putValue(Action.SMALL_ICON, getIconResource("resource/paste.png"));
582 action.putValue(Action.SHORT_DESCRIPTION, "Paste");
583 return action;
584 }
585
586
591 protected void createExamplesMenu(JMenuBar menuBar) {
592 final String[] fileNames = getExampleResources();
593 if (fileNames == null) {
594 return;
595 }
596
597 final JMenu menu = new JMenu("Example Graphs");
598 menuBar.add(menu);
599
600 for (int i = 0; i < fileNames.length; i++) {
601 final String filename = fileNames[i];
602 final String[] path = PATH_SEPARATOR_PATTERN.split(filename);
603 menu.add(new AbstractAction(path[path.length - 1]) {
604 public void actionPerformed(ActionEvent e) {
605 loadGraph(filename);
606 }
607 });
608 }
609 }
610
611 public JPanel getContentPane() {
612 return contentPane;
613 }
614
615
618 protected String[] getExampleResources() {
619 return null;
620 }
621
622
625 public class PrintAction extends AbstractAction {
626 PageFormat pageFormat;
627
628 OptionHandler printOptions;
629
630 public PrintAction() {
631 super("Print");
632
633 printOptions = new OptionHandler("Print Options");
635 printOptions.addInt("Poster Rows", 1);
636 printOptions.addInt("Poster Columns", 1);
637 printOptions.addBool("Add Poster Coords", false);
638 final String[] area = {"View", "Graph"};
639 printOptions.addEnum("Clip Area", area, 1);
640 }
641
642 public void actionPerformed(ActionEvent e) {
643 Graph2DPrinter gprinter = new Graph2DPrinter(view);
644
645 if (!printOptions.showEditor(view.getFrame())) {
647 return;
648 }
649 gprinter.setPosterRows(printOptions.getInt("Poster Rows"));
650 gprinter.setPosterColumns(printOptions.getInt("Poster Columns"));
651 gprinter.setPrintPosterCoords(printOptions.getBool("Add Poster Coords"));
652 if ("Graph".equals(printOptions.get("Clip Area"))) {
653 gprinter.setClipType(Graph2DPrinter.CLIP_GRAPH);
654 } else {
655 gprinter.setClipType(Graph2DPrinter.CLIP_VIEW);
656 }
657
658 PrinterJob printJob = PrinterJob.getPrinterJob();
660 if (pageFormat == null) {
661 pageFormat = printJob.defaultPage();
662 }
663 PageFormat pf = printJob.pageDialog(pageFormat);
664 if (pf == pageFormat) {
665 return;
666 } else {
667 pageFormat = pf;
668 }
669
670 printJob.setPrintable(gprinter, pageFormat);
673
674 if (printJob.printDialog()) {
675 try {
676 printJob.print();
677 } catch (Exception ex) {
678 ex.printStackTrace();
679 }
680 }
681 }
682 }
683
684
687 public static class ExitAction extends AbstractAction {
688 public ExitAction() {
689 super("Exit");
690 }
691
692 public void actionPerformed(ActionEvent e) {
693 System.exit(0);
694 }
695 }
696
697
700 public class SaveAction extends AbstractAction {
701 JFileChooser chooser;
702
703 public SaveAction() {
704 super("Save...");
705 chooser = null;
706 }
707
708 public void actionPerformed(ActionEvent e) {
709 if (chooser == null) {
710 chooser = new JFileChooser();
711 chooser.setAcceptAllFileFilterUsed(false);
712 chooser.addChoosableFileFilter(new FileFilter() {
713 public boolean accept(File f) {
714 return f.isDirectory() || f.getName().endsWith(".graphml");
715 }
716
717 public String getDescription() {
718 return "GraphML Format (.graphml)";
719 }
720 });
721 }
722
723 URL url = view.getGraph2D().getURL();
724 if (url != null && "file".equals(url.getProtocol())) {
725 try {
726 chooser.setSelectedFile(new File(new URI(url.toString())));
727 } catch (URISyntaxException e1) {
728 }
730 }
731
732 if (chooser.showSaveDialog(contentPane) == JFileChooser.APPROVE_OPTION) {
733 String name = chooser.getSelectedFile().toString();
734 if(!name.endsWith(".graphml")) {
735 name += ".graphml";
736 }
737 IOHandler ioh = createGraphMLIOHandler();
738
739 try {
740 ioh.write(view.getGraph2D(), name);
741 } catch (IOException ioe) {
742 D.show(ioe);
743 }
744 }
745 }
746 }
747
748
751 public class LoadAction extends AbstractAction {
752 JFileChooser chooser;
753
754 public LoadAction() {
755 super("Load...");
756 chooser = null;
757 }
758
759 public void actionPerformed(ActionEvent e) {
760 if (chooser == null) {
761 chooser = new JFileChooser();
762 chooser.setAcceptAllFileFilterUsed(false);
763 chooser.addChoosableFileFilter(new FileFilter() {
764 public boolean accept(File f) {
765 return f.isDirectory() || f.getName().endsWith(".graphml");
766 }
767
768 public String getDescription() {
769 return "GraphML Format (.graphml)";
770 }
771 });
772 }
773 if (chooser.showOpenDialog(contentPane) == JFileChooser.APPROVE_OPTION) {
774 URL resource = null;
775 try {
776 resource = chooser.getSelectedFile().toURI().toURL();
777 } catch (MalformedURLException urlex) {
778 urlex.printStackTrace();
779 }
780 loadGraph(resource);
781 }
782 }
783 }
784
785
788 public static class DeleteSelection extends Graph2DViewActions.DeleteSelectionAction {
789 public DeleteSelection(final Graph2DView view) {
790 super(view);
791 putValue(Action.NAME, "Delete Selection");
792 this.putValue(Action.SMALL_ICON, getIconResource("resource/delete.png"));
793 this.putValue(Action.SHORT_DESCRIPTION, "Delete Selection");
794 }
795 }
796
797
800 public static class ResetZoom extends AbstractAction {
801 private final Graph2DView view;
802
803 public ResetZoom(final Graph2DView view) {
804 super("Reset Zoom");
805 this.view = view;
806 this.putValue(Action.SMALL_ICON, getIconResource("resource/zoomOriginal.png"));
807 this.putValue(Action.SHORT_DESCRIPTION, "Reset Zoom");
808 }
809
810 public void actionPerformed( final ActionEvent e ) {
811 view.setZoom(1.0);
812 Rectangle box = view.getGraph2D().getBoundingBox();
817 view.setWorldRect(box.x - 20, box.y - 20, box.width + 40, box.height + 40);
818
819 view.updateView();
820 }
821 }
822
823
826 public static class Zoom extends AbstractAction {
827 private final Graph2DView view;
828 double factor;
829
830 public Zoom(final Graph2DView view, double factor) {
831 super("Zoom " + (factor > 1.0 ? "In" : "Out"));
832 this.view = view;
833 String resource = factor > 1.0d ? "resource/zoomIn.png" : "resource/zoomOut.png";
834 this.putValue(Action.SMALL_ICON, getIconResource(resource));
835 this.putValue(Action.SHORT_DESCRIPTION, "Zoom " + (factor > 1.0 ? "In" : "Out"));
836 this.factor = factor;
837 }
838
839 public void actionPerformed(ActionEvent e) {
840 view.setZoom(view.getZoom() * factor);
841 Rectangle box = view.getGraph2D().getBoundingBox();
846 view.setWorldRect(box.x - 20, box.y - 20, box.width + 40, box.height + 40);
847
848 view.updateView();
849 }
850 }
851
852
855 public static class FitContent extends AbstractAction {
856 private final Graph2DView view;
857
858 public FitContent(final Graph2DView view) {
859 super("Fit Content");
860 this.view = view;
861 this.putValue(Action.SMALL_ICON, getIconResource("resource/zoomFit.png"));
862 this.putValue(Action.SHORT_DESCRIPTION, "Fit Content");
863 }
864
865 public void actionPerformed(ActionEvent e) {
866 view.fitContent();
867 view.updateView();
868 }
869 }
870
871
879 public static class SnappingConfiguration {
880 private boolean snappingEnabled;
881 private double snapDistance;
882 private double snapLineExtension;
883 private Color snapLineColor;
884 private boolean removingInnerBends;
885
886 private double nodeToNodeDistance;
887 private double nodeToEdgeDistance;
888 private double edgeToEdgeDistance;
889
890 private boolean gridSnappingEnabled;
891 private double gridSnapDistance;
892 private double gridDistance;
893 private int gridType;
894
895
896 public double getEdgeToEdgeDistance() {
897 return edgeToEdgeDistance;
898 }
899
900 public void setEdgeToEdgeDistance(double edgeToEdgeDistance) {
901 this.edgeToEdgeDistance = edgeToEdgeDistance;
902 }
903
904 public double getGridSnapDistance() {
905 return gridSnapDistance;
906 }
907
908 public void setGridSnapDistance(double gridSnapDistance) {
909 this.gridSnapDistance = gridSnapDistance;
910 }
911
912 public boolean isGridSnappingEnabled() {
913 return gridSnappingEnabled;
914 }
915
916 public void setGridSnappingEnabled(boolean gridSnappingEnabled) {
917 this.gridSnappingEnabled = gridSnappingEnabled;
918 }
919
920 public double getNodeToEdgeDistance() {
921 return nodeToEdgeDistance;
922 }
923
924 public void setNodeToEdgeDistance(double nodeToEdgeDistance) {
925 this.nodeToEdgeDistance = nodeToEdgeDistance;
926 }
927
928 public double getNodeToNodeDistance() {
929 return nodeToNodeDistance;
930 }
931
932 public void setNodeToNodeDistance(double nodeToNodeDistance) {
933 this.nodeToNodeDistance = nodeToNodeDistance;
934 }
935
936 public boolean isRemovingInnerBends() {
937 return removingInnerBends;
938 }
939
940 public void setRemovingInnerBends(boolean removingInnerBends) {
941 this.removingInnerBends = removingInnerBends;
942 }
943
944 public double getSnapDistance() {
945 return snapDistance;
946 }
947
948 public void setSnapDistance(double snapDistance) {
949 this.snapDistance = snapDistance;
950 }
951
952 public Color getSnapLineColor() {
953 return snapLineColor;
954 }
955
956 public void setSnapLineColor(Color snapLineColor) {
957 this.snapLineColor = snapLineColor;
958 }
959
960 public double getSnapLineExtension() {
961 return snapLineExtension;
962 }
963
964 public void setSnapLineExtension(double snapLineExtension) {
965 this.snapLineExtension = snapLineExtension;
966 }
967
968 public boolean isSnappingEnabled() {
969 return snappingEnabled;
970 }
971
972 public void setSnappingEnabled(boolean snappingEnabled) {
973 this.snappingEnabled = snappingEnabled;
974 }
975
976 public double getGridDistance() {
977 return gridDistance;
978 }
979
980 public void setGridDistance(double gridDistance) {
981 this.gridDistance = gridDistance;
982 }
983
984 public int getGridType() {
985 return gridType;
986 }
987
988 public void setGridType(int gridType) {
989 this.gridType = gridType;
990 }
991
992 public void configureView(final Graph2DView view) {
993 view.setGridMode(false);
995
996 if (isGridSnappingEnabled()) {
997 view.setGridVisible(true);
999 view.setGridResolution(getGridDistance());
1000 view.setGridType(getGridType());
1001 view.setGridColor(getSnapLineColor());
1002 } else {
1003 view.setGridVisible(false);
1004 }
1005
1006 view.updateView();
1007 }
1008
1009 public void configureDropSupport(final DropSupport dropSupport) {
1010 dropSupport.setSnappingEnabled(isSnappingEnabled());
1011 configureSnapContext(dropSupport.getSnapContext());
1012 }
1013
1014
1020 public void configureEditMode(final EditMode editMode) {
1021 if (editMode.getHotSpotMode() instanceof HotSpotMode) {
1022 HotSpotMode hotSpotMode = (HotSpotMode) editMode.getHotSpotMode();
1023 hotSpotMode.setSnappingEnabled(isSnappingEnabled());
1024 hotSpotMode.getSnapContext().setSnapLineColor(getSnapLineColor());
1025 }
1026 {
1027 MoveSelectionMode moveSelectionMode = (MoveSelectionMode) editMode.getMoveSelectionMode();
1028 MoveSnapContext snapContext = moveSelectionMode.getSnapContext();
1029 moveSelectionMode.setSnappingEnabled(isGridSnappingEnabled() || isSnappingEnabled());
1030
1031 configureSnapContext(snapContext);
1032 moveSelectionMode.setRemovingInnerBends(isRemovingInnerBends());
1033 }
1034 {
1035 OrthogonalMoveBendsMode moveBendsMode = (OrthogonalMoveBendsMode) editMode.getOrthogonalMoveBendsMode();
1036 MoveSnapContext snapContext = moveBendsMode.getSnapContext();
1037 moveBendsMode.setSnappingEnabled(isGridSnappingEnabled() || isSnappingEnabled());
1038
1039 configureSnapContext(snapContext);
1040 moveBendsMode.setRemovingInnerBends(isRemovingInnerBends());
1041 }
1042 {
1043 CreateEdgeMode createEdgeMode = (CreateEdgeMode) editMode.getCreateEdgeMode();
1044 MoveSnapContext snapContext = createEdgeMode.getSnapContext();
1045 if (isSnappingEnabled()) {
1046 createEdgeMode.setSnapToOrthogonalSegmentsDistance(5.0);
1047 createEdgeMode.setUsingNodeCenterSnapping(true);
1048 createEdgeMode.setSnappingOrthogonalSegments(true);
1049 } else {
1050 createEdgeMode.setSnapToOrthogonalSegmentsDistance(0.0);
1051 createEdgeMode.setUsingNodeCenterSnapping(false);
1052 createEdgeMode.setSnappingOrthogonalSegments(false);
1053 }
1054
1055 configureSnapContext(snapContext);
1056 }
1057 if (editMode.getMovePortMode() instanceof MovePortMode) {
1058 MovePortMode movePortMode = (MovePortMode) editMode.getMovePortMode();
1059 movePortMode.setUsingRealizerPortCandidates(!isSnappingEnabled());
1060 movePortMode.setSegmentSnappingEnabled(isSnappingEnabled());
1061 MoveSnapContext snapContext = movePortMode.getSnapContext();
1062 configureSnapContext(snapContext);
1063 }
1064 if(editMode.getMoveLabelMode() instanceof MoveLabelMode) {
1065 final MoveLabelMode moveLabelMode = (MoveLabelMode) editMode.getMoveLabelMode();
1066 moveLabelMode.setSnappingEnabled(isSnappingEnabled());
1067 }
1068 }
1069
1070
1075 public void configureSnapContext(final MoveSnapContext snapContext) {
1076
1077 snapContext.setSnapLineColor(getSnapLineColor());
1078 snapContext.setSnapDistance(getSnapDistance());
1079 snapContext.setGridSnapDistance(getGridSnapDistance());
1080 snapContext.setSnapLineExtension(getSnapLineExtension());
1081
1082 snapContext.setUsingGridSnapping(isGridSnappingEnabled());
1083 snapContext.setRenderingSnapLines(isGridSnappingEnabled() || isSnappingEnabled());
1084
1085 if (isGridSnappingEnabled() && !isSnappingEnabled()) {
1086 snapContext.setSnappingBendsToSnapLines(false);
1087 snapContext.setSnappingSegmentsToSnapLines(false);
1088 snapContext.setUsingCenterSnapLines(false);
1089 snapContext.setUsingEquidistantSnapLines(false);
1090 snapContext.setUsingFixedNodeSnapLines(false);
1091 snapContext.setUsingOrthogonalBendSnapping(false);
1092 snapContext.setUsingOrthogonalMovementConstraints(false);
1093 snapContext.setUsingOrthogonalPortSnapping(false);
1094 snapContext.setUsingSegmentSnapLines(false);
1095
1096 snapContext.setEdgeToEdgeDistance(0.0);
1098 snapContext.setNodeToEdgeDistance(-1.0);
1099 snapContext.setNodeToNodeDistance(0.0);
1100 } else {
1101 snapContext.setSnappingBendsToSnapLines(false);
1102 snapContext.setSnappingSegmentsToSnapLines(true);
1103 snapContext.setUsingCenterSnapLines(false);
1104 snapContext.setUsingEquidistantSnapLines(true);
1105 snapContext.setUsingFixedNodeSnapLines(true);
1106 snapContext.setUsingOrthogonalBendSnapping(true);
1107 snapContext.setUsingOrthogonalMovementConstraints(true);
1108 snapContext.setUsingOrthogonalPortSnapping(true);
1109 snapContext.setUsingSegmentSnapLines(true);
1110
1111 snapContext.setEdgeToEdgeDistance(getEdgeToEdgeDistance());
1112 snapContext.setNodeToEdgeDistance(getNodeToEdgeDistance());
1113 snapContext.setNodeToNodeDistance(getNodeToNodeDistance());
1114 }
1115 }
1116 }
1117
1118
1121 public static SnappingConfiguration createDefaultSnappingConfiguration() {
1122 SnappingConfiguration result = new SnappingConfiguration();
1123 result.setSnappingEnabled(true);
1124 result.setGridSnappingEnabled(false);
1125 result.setSnapLineColor(Color.LIGHT_GRAY);
1126 result.setRemovingInnerBends(true);
1127 result.setNodeToNodeDistance(30.0);
1128 result.setNodeToEdgeDistance(20.0);
1129 result.setEdgeToEdgeDistance(20.0);
1130 result.setSnapDistance(5.0);
1131 result.setGridSnapDistance(10.0);
1132 result.setSnapLineExtension(40.0);
1133 result.setGridDistance(50.0);
1134 result.setGridType(View2DConstants.GRID_CROSS);
1135 return result;
1136 }
1137
1138
1145 public static JComponent createActionControl(final Action action) {
1146 return createActionControl(action, true);
1147 }
1148
1149
1157 public static JComponent createActionControl(final Action action, final boolean showActionText) {
1158 final JButton jb = new JButton();
1159 if (action.getValue(Action.SMALL_ICON) != null) {
1160 jb.putClientProperty("hideActionText", Boolean.valueOf(!showActionText));
1161 }
1162 jb.setAction(action);
1163 return jb;
1164 }
1165
1166
1177 public static Icon getIconResource( final String resource ) {
1178 try {
1179 final URL icon = getSharedResource(resource);
1180 if (icon == null) {
1181 return null;
1182 } else {
1183 return new ImageIcon(icon);
1184 }
1185 } catch (Exception e) {
1186 return null;
1187 }
1188 }
1189
1190
1201 protected URL getResource( final String name ) {
1202 return getResource(getClass(), name);
1203 }
1204
1205
1216 public static URL getSharedResource( final String name ) {
1217 return getResource(DemoBase.class, name);
1218 }
1219
1220
1229 public static URL getResource(
1230 final Class resolver, final String name
1231 ) {
1232 final URL resource = resolver.getResource(name);
1233 if (resource == null) {
1234 final int idx = name.indexOf('.');
1235 if (idx > -1) {
1236 final String ext = name.substring(idx + 1);
1237 D.showError(
1238 "Resource \"" + name + "\" not found in classpath of " +
1239 resolver + ".\nPlease ensure that your IDE recognizes \"*." +
1240 ext + "\" files as resource files.\n" +
1241 "If you are using Intellij IDEA, open the \"Settings\" " +
1242 "dialog (\"File\" -> \"Settings\"), select \"Compiler\" from " +
1243 "the list of \"Project Settings\", and add \"?*." + ext + "\" " +
1244 "to \"Resource Patterns\".");
1245 } else {
1246 D.showError(
1247 "Resource \"" + name + "\" not found in classpath of " +
1248 resolver + ".");
1249 }
1250 }
1251 return resource;
1252 }
1253
1254
1260 public static Image getFrameIcon() {
1261 try {
1262 final Class resolver = DemoBase.class;
1263 final URL resource = resolver.getResource("resource/yicon32.png");
1264 if (resource != null) {
1265 final Toolkit toolkit = Toolkit.getDefaultToolkit();
1266 return toolkit.getImage(resource);
1267 }
1268 } catch (Exception e) {
1269 }
1272
1273 return null;
1274 }
1275
1276
1285 public static HitInfo checkNodeHit(
1286 final Graph2DView view,
1287 final double x, final double y
1288 ) {
1289 return view.getHitInfoFactory().createHitInfo(x, y, Graph2DTraversal.NODES, true);
1290 }
1291
1292
1295 public static class OptionSupport {
1296 private final EditorFactory editorFactory;
1297
1298
1307 public static void showDialog(final YModule module, final Graph2D graph, final boolean runOnOk, Frame owner) {
1308 if (module.getOptionHandler() == null) {
1309 module.start(graph);
1310 } else {
1311 final ActionListener listener = new ActionListener() {
1312 public void actionPerformed(ActionEvent e) {
1313 module.start(graph);
1314 }
1315 };
1316
1317 showDialog(module.getOptionHandler(), listener, runOnOk, owner);
1318 }
1319 }
1320
1321
1331 public static void showDialog(final OptionHandler oh, final ActionListener listener,
1332 final boolean runOnOk, Frame owner) {
1333 final ActionListener delegatingListener = new ActionListener() {
1334 public void actionPerformed(final ActionEvent e) {
1335 final String actionCommand = e.getActionCommand();
1336 if ("Apply".equals(actionCommand) || (runOnOk && "Ok".equals(actionCommand))) {
1337 EventQueue.invokeLater(new Runnable() {
1338 public void run() {
1339 listener.actionPerformed(e);
1340 }
1341 });
1342 }
1343 }
1344 };
1345
1346 final JDialog dialog = new OptionSupport().createDialog(oh, delegatingListener, owner);
1347 dialog.setVisible(true);
1348 }
1349
1350 public OptionSupport() {
1351 editorFactory = new DefaultEditorFactory();
1352 }
1353
1354
1362 public JDialog createDialog(final OptionHandler oh, ActionListener listener, Frame owner) {
1363 final JDialog dialog = new JDialog(owner, getTitle(oh), true);
1364
1365 final AbstractAction applyAction = new AbstractAction("Apply") {
1366 public void actionPerformed(ActionEvent e) {
1367 if (oh.checkValues()) {
1368 oh.commitValues();
1369 }
1370 }
1371 };
1372 final JButton applyButton = createButton(applyAction, listener);
1373 applyButton.setDefaultCapable(true);
1374 applyButton.requestFocus();
1375
1376 final AbstractAction closeAction = new AbstractAction("Cancel") {
1377 public void actionPerformed(ActionEvent e) {
1378 dialog.dispose();
1379 }
1380 };
1381
1382 final AbstractAction okAction = new AbstractAction("Ok") {
1383 public void actionPerformed(ActionEvent e) {
1384 if (oh.checkValues()) {
1385 oh.commitValues();
1386 dialog.dispose();
1387 }
1388 }
1389 };
1390
1391 final AbstractAction resetAction = new AbstractAction("Reset") {
1392 public void actionPerformed(ActionEvent e) {
1393 oh.resetValues();
1394 }
1395 };
1396
1397 final JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
1398 buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 11, 5));
1399 buttonPanel.add(createButton(okAction, listener));
1400 buttonPanel.add(createButton(closeAction, listener));
1401 buttonPanel.add(applyButton);
1402 buttonPanel.add(createButton(resetAction, listener));
1403
1404 final Editor editor = getEditorFactory().createEditor(oh);
1405 final JComponent editorComponent = editor.getComponent();
1406 if (editorComponent instanceof JPanel) {
1407 editorComponent.setBorder(BorderFactory.createEmptyBorder(11, 5, 5, 5));
1408 } else {
1409 editorComponent.setBorder(BorderFactory.createEmptyBorder(9, 9, 15, 9));
1410 }
1411
1412 final JPanel contentPanel = new JPanel(new BorderLayout(0, 0));
1413 contentPanel.add(editorComponent, BorderLayout.CENTER);
1414 contentPanel.add(buttonPanel, BorderLayout.SOUTH);
1415
1416 dialog.setContentPane(contentPanel);
1417 dialog.getRootPane().getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "APPLY_ACTION");
1418 dialog.getRootPane().getActionMap().put("APPLY_ACTION", applyAction);
1419 dialog.getRootPane().getInputMap().put(KeyStroke.getKeyStroke("ESCAPE"), "CANCEL_ACTION");
1420 dialog.getRootPane().getActionMap().put("CANCEL_ACTION", closeAction);
1421 dialog.getRootPane().setDefaultButton(applyButton);
1422 dialog.pack();
1423 dialog.setSize(dialog.getPreferredSize());
1424 dialog.setResizable(false);
1425 dialog.setLocationRelativeTo(owner);
1426
1427 return dialog;
1428 }
1429
1430 protected EditorFactory getEditorFactory() {
1431 return editorFactory;
1432 }
1433
1434 String getTitle(OptionHandler oh) {
1435 final Object title = oh.getAttribute(OptionHandler.ATTRIBUTE_TITLE);
1436 if (title instanceof String) {
1437 return (String) title;
1438 }
1439
1440 final Object titleKey = oh.getAttribute(OptionHandler.ATTRIBUTE_TITLE_KEY);
1441 if (titleKey instanceof String) {
1442 return getTitle(oh, (String) titleKey);
1443 } else {
1444 return getTitle(oh, oh.getName());
1445 }
1446 }
1447
1448 static String getTitle(OptionHandler oh, String title) {
1449 final GuiFactory guiFactory = oh.getGuiFactory();
1450 return guiFactory == null ? title : guiFactory.getString(title);
1451 }
1452
1453 static JButton createButton(AbstractAction action, ActionListener listener) {
1454 final JButton button = new JButton(action);
1455 button.addActionListener(listener);
1456 return button;
1457
1458 }
1459 }
1460}
1461