1
28 package demo.view.application;
29
30 import demo.view.DemoBase;
31
32 import y.base.Edge;
33 import y.base.EdgeCursor;
34 import y.base.EdgeList;
35 import y.base.Node;
36 import y.base.NodeCursor;
37 import y.base.NodeList;
38 import y.base.YCursor;
39 import y.geom.YPoint;
40 import y.layout.Layouter;
41 import y.layout.LayoutOrientation;
42 import y.layout.hierarchic.incremental.EdgeLayoutDescriptor;
43 import y.layout.hierarchic.IncrementalHierarchicLayouter;
44 import y.layout.hierarchic.incremental.RoutingStyle;
45 import y.util.GraphCopier;
46 import y.view.EditMode;
47 import y.view.Graph2D;
48 import y.view.Graph2DSelectionEvent;
49 import y.view.Graph2DSelectionListener;
50 import y.view.Graph2DView;
51 import y.view.HitInfo;
52 import y.view.LocalViewCreator.*;
53 import y.view.ViewMode;
54 import y.view.LocalViewCreator;
55 import y.view.ModelViewManager;
56 import y.view.NodeRealizer;
57 import y.view.hierarchy.GroupNodeRealizer;
58 import y.view.hierarchy.HierarchyManager;
59
60 import java.awt.BorderLayout;
61 import java.awt.CardLayout;
62 import java.awt.Dimension;
63 import java.awt.EventQueue;
64 import java.awt.FlowLayout;
65 import java.awt.GridBagConstraints;
66 import java.awt.GridBagLayout;
67 import java.awt.Insets;
68 import java.awt.geom.Point2D;
69 import java.awt.event.ActionEvent;
70 import java.awt.event.ActionListener;
71 import java.net.URL;
72 import java.util.HashSet;
73 import java.util.Iterator;
74 import java.util.Locale;
75
76 import javax.swing.AbstractAction;
77 import javax.swing.BorderFactory;
78 import javax.swing.Box;
79 import javax.swing.ButtonGroup;
80 import javax.swing.JPanel;
81 import javax.swing.JCheckBox;
82 import javax.swing.JComponent;
83 import javax.swing.JLabel;
84 import javax.swing.JRadioButton;
85 import javax.swing.JSpinner;
86 import javax.swing.JSplitPane;
87 import javax.swing.SpinnerNumberModel;
88 import javax.swing.Timer;
89 import javax.swing.Action;
90 import javax.swing.border.CompoundBorder;
91 import javax.swing.event.ChangeEvent;
92 import javax.swing.event.ChangeListener;
93
94
116 public class LocalViewDemo extends DemoBase {
117
121 private static final int TIMER_DELAY = 100;
122
123
127 private static final byte SELECTION_TRIGGER = 1;
128
132 private static final byte HOVER_TRIGGER = 2;
133
134
135 private final Graph2DView localView;
136
137 private final Neighborhood neighborhood;
139 private final CommonParentGroup commonParentGroup;
140 private final AncestorGroups ancestorGroups;
141 private final FolderContents folderContents;
142
143 private final SourceAndTarget sourceAndTarget;
145 private final EdgeGroup edgeGroup;
146
147 private final SelectedSubgraph selectedSubgraph;
149
150 private LocalViewCreator currentLocalViewCreator;
152 private AbstractLocalViewCreator nodeLocalViewCreator;
154 private AbstractLocalViewCreator edgeLocalViewCreator;
156
157
158 private final SelectionTrigger selectionTrigger;
161 private final HoverTrigger hoverTrigger;
164
165 private byte triggerType;
167
168
169 public LocalViewDemo() {
170 this(null);
171 }
172
173 public LocalViewDemo( final String helpFilePath ) {
174 final Graph2D graph = view.getGraph2D();
175 (new HierarchyManager(graph)).addHierarchyListener(
176 new GroupNodeRealizer.StateChangeListener());
177
178
179 final GraphCopier.CopyFactory factory = graph.getGraphCopyFactory();
184 final Graph2D localViewGraph = (Graph2D) factory.createGraph();
185
186 localView = new Graph2DView(localViewGraph);
187 localView.setPreferredSize(new Dimension(320, 240));
188
189 final Layouter layouter = createLayouter();
190 neighborhood = new Neighborhood(graph, factory, localViewGraph);
191 neighborhood.setLayouter(layouter);
192 commonParentGroup = new CommonParentGroup(graph, factory, localViewGraph);
193 ancestorGroups = new AncestorGroups(graph, factory, localViewGraph);
194 folderContents = new FolderContents(graph, factory, localViewGraph);
195
196 sourceAndTarget = new SourceAndTarget(graph, factory, localViewGraph);
197 sourceAndTarget.setLayouter(layouter);
198 edgeGroup = new EdgeGroup(graph, factory, localViewGraph);
199 edgeGroup.setLayouter(layouter);
200
201 selectedSubgraph = new SelectedSubgraph(graph, factory, localViewGraph);
202
203
204 setEdgeLocalViewCreator(sourceAndTarget);
205 setNodeLocalViewCreator(neighborhood);
206
207
208 loadGraph("resource/LocalViewDemo.graphml");
210
211
212 localView.addViewMode(new ViewMode() {
215 public void mouseClicked(double x, double y) {
216 if (lastClickEvent.getClickCount() == 2) {
218 final HitInfo hitInfo = getHitInfo(x, y);
219 final Graph2DView view = LocalViewDemo.this.view;
220 final Graph2D viewGraph = view.getGraph2D();
221 if (hitInfo.getHitNode() != null) {
223 final LocalViewCreator lvc = getCurrentLocalViewCreator();
225 final Node modelNode = lvc.getModelNode(hitInfo.getHitNode());
226 if (modelNode != null) {
227 if (modelNode.getGraph() == viewGraph) {
228 viewGraph.unselectAll();
230 final NodeRealizer nr = viewGraph.getRealizer(modelNode);
231 Point2D.Double center = new Point2D.Double(nr.getCenterX(), nr.getCenterY());
232 double minZoom = Math.min(view.getWidth() / (nr.getWidth() + 40),
233 view.getHeight() / (nr.getHeight() + 40));
234 view.focusView(Math.min(minZoom, view.getZoom()), center, true);
235 viewGraph.setSelected(modelNode, true);
236 viewGraph.updateViews();
237 }
238 }
239 } else if (hitInfo.getHitEdge() != null) { final LocalViewCreator lvc = getCurrentLocalViewCreator();
242 final Edge modelEdge = lvc.getModelEdge(hitInfo.getHitEdge());
243 if (modelEdge != null) {
244 if(modelEdge.getGraph() == viewGraph) {
245 final NodeRealizer snr = viewGraph.getRealizer(modelEdge.source());
247 final NodeRealizer tnr = viewGraph.getRealizer(modelEdge.target());
248 Point2D.Double sCenter = new Point2D.Double(snr.getCenterX(), snr.getCenterY());
249 Point2D.Double tCenter = new Point2D.Double(tnr.getCenterX(), tnr.getCenterY());
250 double minZoom =
251 Math.min(
252 view.getWidth()/(snr.getWidth() + tnr.getWidth() + Math.abs(sCenter.x - tCenter.x)),
253 view.getHeight() / (snr.getHeight() + tnr.getHeight() + Math.abs(sCenter.y - tCenter.y)));
254 view.focusView(Math.min(view.getZoom(), minZoom), new Point2D.Double((sCenter.x + tCenter.x) * 0.5d, (sCenter.y + tCenter.y) * 0.5d), true);
255 viewGraph.unselectAll();
256 viewGraph.setSelected(modelEdge, true);
257 viewGraph.updateViews();
258 }
259 }
260 }
261 }
262 }
263 });
264
265 localView.setFitContentOnResize(true);
266
267 selectionTrigger = new SelectionTrigger();
268 hoverTrigger = new HoverTrigger();
269
270 final JSplitPane localViewAndSettings = new JSplitPane(
271 JSplitPane.VERTICAL_SPLIT, localView, createSettingsComponent());
272 localViewAndSettings.setBorder(BorderFactory.createEmptyBorder());
273 localViewAndSettings.setResizeWeight(1);
274 final JSplitPane center = new JSplitPane(
275 JSplitPane.HORIZONTAL_SPLIT, localViewAndSettings, view);
276 center.setBorder(BorderFactory.createEmptyBorder());
277 center.setResizeWeight(0);
278
279 contentPane.add(center, BorderLayout.CENTER);
280 addHelpPane(helpFilePath);
281
282 setTrigger(SELECTION_TRIGGER);
284
285
286 if (!graph.isEmpty()) {
288 graph.unselectAll();
289 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
290 if (nc.node().inDegree() > 0 && nc.node().outDegree() > 0) {
291 graph.setSelected(nc.node(), true);
292 break;
293 }
294 }
295 if (graph.isSelectionEmpty()) {
296 graph.setSelected(graph.firstNode(), true);
297 }
298 graph.updateViews();
299 }
300 }
301
302
305 protected EditMode createEditMode() {
306 EditMode editMode = super.createEditMode();
307 editMode.allowEdgeCreation(false);
308 editMode.allowNodeCreation(false);
309 return editMode;
310 }
311
312
315 protected boolean isDeletionEnabled() {
316 return false;
317 }
318
319
322 protected boolean isUndoRedoEnabled() {
323 return false;
324 }
325
326
329 protected boolean isClipboardEnabled() {
330 return false;
331 }
332
333
336 protected Action createSaveAction() {
337 return null;
338 }
339
340
343 protected void loadGraph( final URL resource ) {
344 if (resource != null && localView != null) {
345 localView.getGraph2D().clear();
346 }
347
348 super.loadGraph(resource);
349
350 if (resource != null && localView != null) {
351 localView.updateView();
352 }
353 }
354
355
364 private void setTrigger( final byte triggerType ) {
365 switch (this.triggerType) {
367 case SELECTION_TRIGGER:
368 view.getGraph2D().removeGraph2DSelectionListener(selectionTrigger);
369 break;
370 case HOVER_TRIGGER:
371 view.removeViewMode(hoverTrigger);
372 break;
373 }
374
375 this.triggerType = triggerType;
376
377 switch (this.triggerType) {
379 case SELECTION_TRIGGER:
380 view.getGraph2D().addGraph2DSelectionListener(selectionTrigger);
381 break;
382 case HOVER_TRIGGER:
383 view.addViewMode(hoverTrigger);
384 break;
385 }
386 }
387
388
389
393 private void setEdgeLocalViewCreator( final AbstractLocalViewCreator elvc ) {
394 final boolean update = currentLocalViewCreator == edgeLocalViewCreator;
395
396 edgeLocalViewCreator = elvc;
397
398 updateEdgeViewImpl(update);
400 }
401
402
406 private void updateEdgeView() {
407 updateEdgeViewImpl(currentLocalViewCreator == edgeLocalViewCreator);
408 }
409
410 private void updateEdgeViewImpl( final boolean update ) {
411 if (update) {
412 if (SELECTION_TRIGGER == triggerType) {
413 createEdgeView(view.getGraph2D().selectedEdges());
414 } else {
415 createEdgeView(new EdgeList().edges());
416 }
417 }
418 }
419
420
424 private void setNodeLocalViewCreator( final AbstractLocalViewCreator nlvc ) {
425 final boolean update = currentLocalViewCreator == nodeLocalViewCreator;
426
427 nodeLocalViewCreator = nlvc;
428
429 updateNodeViewImpl(update);
431 }
432
433
437 private void updateNodeView() {
438 updateNodeViewImpl(currentLocalViewCreator == nodeLocalViewCreator);
439 }
440
441 private void updateNodeViewImpl( final boolean update ) {
442 if (update) {
443 if (SELECTION_TRIGGER == triggerType) {
444 createNodeView(view.getGraph2D().selectedNodes());
445 } else {
446 createNodeView((new NodeList().nodes()));
447 }
448 }
449 }
450
451
456 private void createEdgeView( final YCursor edges ) {
457 currentLocalViewCreator = edgeLocalViewCreator;
460
461 edgeLocalViewCreator.clearFocusEdges();
464 for (; edges.ok(); edges.next()) {
465 edgeLocalViewCreator.addFocusEdge((Edge) edges.current());
466 }
467
468 edgeLocalViewCreator.updateViewGraph();
477 }
478
479
484 private void createNodeView( final YCursor nodes ) {
485 currentLocalViewCreator = nodeLocalViewCreator;
488
489 nodeLocalViewCreator.clearFocusNodes();
492 for (; nodes.ok(); nodes.next()) {
493 nodeLocalViewCreator.addFocusNode((Node) nodes.current());
494 }
495
496 nodeLocalViewCreator.updateViewGraph();
505 }
506
507
511 private LocalViewCreator getCurrentLocalViewCreator() {
512 return currentLocalViewCreator;
513 }
514
515
521 private JComponent createSettingsComponent() {
522 final JPanel settingsPane = new JPanel(new CardLayout());
523
524 final Box nodeStrategyButtons = Box.createVerticalBox();
525 nodeStrategyButtons.setBorder(BorderFactory.createTitledBorder("Node Strategies"));
526
527 final ButtonGroup nodeStrategiesGroup = new ButtonGroup();
528
529 addStrategy(settingsPane, nodeStrategyButtons, nodeStrategiesGroup, "Neighborhood", createNeighborhoodSettings(), neighborhood, true);
531 addStrategy(settingsPane, nodeStrategyButtons, nodeStrategiesGroup, "Common Parent Group", createCommonParentGroupSettings(), commonParentGroup, true);
532 addStrategy(settingsPane, nodeStrategyButtons, nodeStrategiesGroup, "Ancestor Groups", createAncestorGroupsSettings(), ancestorGroups, true);
533 addStrategy(settingsPane, nodeStrategyButtons, nodeStrategiesGroup, "Folder Contents", createFolderContentsSettings(), folderContents, true);
534 addStrategy(settingsPane, nodeStrategyButtons, nodeStrategiesGroup, "Selected Subgraph", null, selectedSubgraph, true);
535
536
537 final ButtonGroup edgeStrategiesGroup = new ButtonGroup();
538 final Box edgeStrategyButtons = Box.createVerticalBox();
539 edgeStrategyButtons.setBorder(BorderFactory.createTitledBorder("Edge Strategies"));
540
541 addStrategy(settingsPane, edgeStrategyButtons, edgeStrategiesGroup, "Source and Target", createSourceAndTargetSettings(), sourceAndTarget, false);
543 addStrategy(settingsPane, edgeStrategyButtons, edgeStrategiesGroup, "Edge Group", createEdgeGroupSettings(), edgeGroup, false);
544
545
546 Box container = Box.createVerticalBox();
547 container.add(createTriggerPane());
548
549 final GridBagConstraints gbc = new GridBagConstraints();
551 final JPanel strategies = new JPanel(new GridBagLayout());
552 gbc.anchor = GridBagConstraints.NORTHWEST;
553 gbc.fill = GridBagConstraints.HORIZONTAL;
554 gbc.gridx = 0;
555 gbc.weightx = 1;
556 gbc.weighty = 0;
557 strategies.add(nodeStrategyButtons, gbc);
558 strategies.add(edgeStrategyButtons, gbc);
559 gbc.fill = GridBagConstraints.BOTH;
560 gbc.weighty = 1;
561 strategies.add(Box.createGlue(), gbc);
562
563 Box strategy = Box.createHorizontalBox();
564 strategy.add(strategies);
565 strategy.add(settingsPane);
566
567 container.add(strategy);
568 return container;
569 }
570
571
577 private JComponent createSourceAndTargetSettings() {
578 final JCheckBox hierarchyAware = new JCheckBox("Hierarchy aware");
579 hierarchyAware.addActionListener(new ActionListener() {
580 public void actionPerformed(ActionEvent e) {
581 sourceAndTarget.setHierarchyAware(hierarchyAware.isSelected());
582 updateEdgeView();
583 }
584 });
585
586 final Box settings = Box.createVerticalBox();
587 settings.add(hierarchyAware);
588 settings.add(Box.createGlue());
589 return settings;
590 }
591
592
598 private JComponent createEdgeGroupSettings() {
599 final JCheckBox src = new JCheckBox("Source");
600 src.setSelected(true);
601 final JCheckBox tgt = new JCheckBox("Target");
602 tgt.setSelected(true);
603 final AbstractAction groupTypes = new AbstractAction() {
604 public void actionPerformed( final ActionEvent e ) {
605 src.setEnabled(tgt.isSelected());
606 tgt.setEnabled(src.isSelected());
607 byte types = 0;
608 if (src.isSelected()) {
609 types |= EdgeGroup.GROUP_BY_SOURCE;
610 }
611 if (tgt.isSelected()) {
612 types |= EdgeGroup.GROUP_BY_TARGET;
613 }
614 edgeGroup.setGroupByPolicy(types);
615 updateEdgeView();
616 }
617 };
618 src.addActionListener(groupTypes);
619 tgt.addActionListener(groupTypes);
620
621 final Box settings = Box.createVerticalBox();
622 settings.add(new JLabel("Group by"));
623 settings.add(src);
624 settings.add(tgt);
625 settings.add(Box.createGlue());
626 return settings;
627 }
628
629
635 private JComponent createFolderContentsSettings() {
636 final ButtonGroup includeFoldersGroup = new ButtonGroup();
637 final JRadioButton always = new JRadioButton("Always Include Folders");
638 always.addActionListener(new ActionListener() {
639 public void actionPerformed( final ActionEvent e ) {
640 folderContents.setFolderPolicy(FolderContents.FOLDER_POLICY_ALWAYS);
641 updateNodeView();
642 }
643 });
644 includeFoldersGroup.add(always);
645 final JRadioButton asNeeeded = new JRadioButton("Include Folders As Needed");
646 asNeeeded.setSelected(true);
647 asNeeeded.addActionListener(new ActionListener() {
648 public void actionPerformed( final ActionEvent e ) {
649 folderContents.setFolderPolicy(FolderContents.FOLDER_POLICY_AS_NEEDED);
650 updateNodeView();
651 }
652 });
653 includeFoldersGroup.add(asNeeeded);
654 final JRadioButton never = new JRadioButton("Never Include Folders");
655 never.addActionListener(new ActionListener() {
656 public void actionPerformed( final ActionEvent e ) {
657 folderContents.setFolderPolicy(FolderContents.FOLDER_POLICY_NEVER);
658 updateNodeView();
659 }
660 });
661 includeFoldersGroup.add(never);
662
663 final Box settings = Box.createVerticalBox();
664 settings.add(always);
665 settings.add(asNeeeded);
666 settings.add(never);
667 settings.add(Box.createGlue());
668 return settings;
669 }
670
671
677 private JComponent createAncestorGroupsSettings() {
678 final JCheckBox includeFocusNodes = new JCheckBox("Include Focus Nodes");
679 includeFocusNodes.setSelected(ancestorGroups.isIncludeFocusNodes());
680 includeFocusNodes.addActionListener(new AbstractAction() {
681 public void actionPerformed( final ActionEvent e ) {
682 ancestorGroups.setIncludeFocusNodes(includeFocusNodes.isSelected());
683 updateNodeView();
684 }
685 });
686
687 final Box settings = Box.createVerticalBox();
688 settings.add(includeFocusNodes);
689 settings.add(Box.createGlue());
690 return settings;
691 }
692
693
699 private JComponent createCommonParentGroupSettings() {
700 final JCheckBox includeDescendants = new JCheckBox("Include Descendants");
701 includeDescendants.setSelected(commonParentGroup.isIncludeDescendants());
702 includeDescendants.addActionListener(new AbstractAction() {
703 public void actionPerformed( final ActionEvent e ) {
704 commonParentGroup.setIncludeDescendants(includeDescendants.isSelected());
705 updateNodeView();
706 }
707 });
708
709 final Box settings = Box.createVerticalBox();
710 settings.add(includeDescendants);
711 settings.add(Box.createGlue());
712 return settings;
713 }
714
715
721 private JComponent createNeighborhoodSettings() {
722 final ButtonGroup nodesGroup = new ButtonGroup();
723 final JRadioButton preds = new JRadioButton("Predecessors");
724 preds.addActionListener(new ActionListener() {
725 public void actionPerformed( final ActionEvent e ) {
726 neighborhood.setNeighborhoodType(Neighborhood.NEIGHBORHOOD_TYPE_PREDECESSORS);
727 updateNodeView();
728 }
729 });
730 nodesGroup.add(preds);
731 final JRadioButton succs = new JRadioButton("Successors");
732 succs.addActionListener(new ActionListener() {
733 public void actionPerformed( final ActionEvent e ) {
734 neighborhood.setNeighborhoodType(Neighborhood.NEIGHBORHOOD_TYPE_SUCCESSORS);
735 updateNodeView();
736 }
737 });
738 nodesGroup.add(succs);
739 final JRadioButton predsSuccs = new JRadioButton("Predecessors and Successors");
740 predsSuccs.setSelected(true);
741 predsSuccs.addActionListener(new ActionListener() {
742 public void actionPerformed( final ActionEvent e ) {
743 neighborhood.setNeighborhoodType(Neighborhood.NEIGHBORHOOD_TYPE_PREDECESSORS_AND_SUCCESSORS);
744 updateNodeView();
745 }
746 });
747 nodesGroup.add(predsSuccs);
748 final JRadioButton neighbors = new JRadioButton("All Neighbors");
749 neighbors.addActionListener(new ActionListener() {
750 public void actionPerformed( final ActionEvent e ) {
751 neighborhood.setNeighborhoodType(Neighborhood.NEIGHBORHOOD_TYPE_NEIGHBORS);
752 updateNodeView();
753 }
754 });
755 nodesGroup.add(neighbors);
756
757 final JSpinner neighborhoodMGD = new JSpinner();
758 neighborhoodMGD.getModel().setValue(new Integer(neighborhood.getMaximumGraphDistance()));
759 ((SpinnerNumberModel) neighborhoodMGD.getModel()).setMinimum(new Integer(0));
760 neighborhoodMGD.addChangeListener(new ChangeListener() {
761 public void stateChanged( final ChangeEvent e ) {
762 final Object value = neighborhoodMGD.getModel().getValue();
763 if (value instanceof Integer) {
764 final int mgd = ((Integer) value).intValue();
765 if (mgd > -1) {
766 neighborhood.setMaximumGraphDistance(mgd);
767 updateNodeView();
768 }
769 }
770 }
771 });
772
773 final JCheckBox hierarchyAware = new JCheckBox("Hierarchy aware");
774 hierarchyAware.addActionListener(new ActionListener() {
775 public void actionPerformed(ActionEvent e) {
776 neighborhood.setHierarchyAware(hierarchyAware.isSelected());
777 updateNodeView();
778 }
779 });
780
781 final ButtonGroup edgesGroup = new ButtonGroup();
782 final JRadioButton none = new JRadioButton("None");
783 none.addActionListener(new ActionListener() {
784 public void actionPerformed( final ActionEvent e ) {
785 neighborhood.setEdgePolicy(Neighborhood.EDGE_POLICY_NONE);
786 updateNodeView();
787 }
788 });
789 edgesGroup.add(none);
790 final JRadioButton subgraph = new JRadioButton("Subgraph Edges");
791 subgraph.addActionListener(new ActionListener() {
792 public void actionPerformed( final ActionEvent e ) {
793 neighborhood.setEdgePolicy(Neighborhood.EDGE_POLICY_INDUCED_SUBGRAPH);
794 updateNodeView();
795 }
796 });
797 edgesGroup.add(subgraph);
798 final JRadioButton shortestPaths = new JRadioButton("Shortest Paths");
799 shortestPaths.setSelected(true);
800 shortestPaths.addActionListener(new ActionListener() {
801 public void actionPerformed( final ActionEvent e ) {
802 neighborhood.setEdgePolicy(Neighborhood.EDGE_POLICY_SHORTEST_PATHS);
803 updateNodeView();
804 }
805 });
806 edgesGroup.add(shortestPaths);
807
808
809 final Box nodeTypes = Box.createVerticalBox();
810 nodeTypes.add(preds);
811 nodeTypes.add(succs);
812 nodeTypes.add(predsSuccs);
813 nodeTypes.add(neighbors);
814
815 final GridBagConstraints gbc = new GridBagConstraints();
816 final JPanel includedNodes = new JPanel(new GridBagLayout());
817 includedNodes.setBorder(BorderFactory.createTitledBorder("Included Nodes"));
818 gbc.anchor = GridBagConstraints.NORTHWEST;
819 gbc.fill = GridBagConstraints.HORIZONTAL;
820 gbc.gridx = 0;
821 gbc.gridy = 0;
822 gbc.gridwidth = 2;
823 gbc.gridheight = 1;
824 gbc.weightx = 1;
825 gbc.weighty = 0;
826 includedNodes.add(nodeTypes, gbc);
827 gbc.fill = GridBagConstraints.NONE;
828 gbc.gridy = 1;
829 gbc.gridwidth = 1;
830 gbc.insets = new Insets(5, 0, 0, 0);
831 gbc.weightx = 0;
832 includedNodes.add(new JLabel("Maximum Graph Distance"), gbc);
833 gbc.fill = GridBagConstraints.HORIZONTAL;
834 gbc.gridx = 1;
835 gbc.insets = new Insets(5, 5, 0, 0);
836 gbc.weightx = 1;
837 includedNodes.add(neighborhoodMGD, gbc);
838 gbc.gridwidth = 2;
839 gbc.gridx = 0;
840 gbc.gridy = 2;
841 gbc.insets = new Insets(0, 0, 5, 0);
842 includedNodes.add(hierarchyAware, gbc);
843
844 final Box includedEdges = Box.createVerticalBox();
845 includedEdges.setBorder(BorderFactory.createTitledBorder("Included Edges"));
846 includedEdges.add(none);
847 includedEdges.add(subgraph);
848 includedEdges.add(shortestPaths);
849
850 final JPanel controls = new JPanel(new GridBagLayout());
851 gbc.gridx = 0;
852 gbc.gridy = 0;
853 gbc.gridwidth = 1;
854 gbc.gridheight = 1;
855 gbc.weightx = 1;
856 gbc.weighty = 0;
857 controls.add(includedNodes, gbc);
858 gbc.gridy = 1;
859 controls.add(includedEdges, gbc);
860
861 final JPanel settings = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
862 settings.add(controls);
863 return settings;
864 }
865
866
872 private JComponent createTriggerPane() {
873 final ButtonGroup updateGroup = new ButtonGroup();
874 final JRadioButton updateHover = new JRadioButton(new AbstractAction("Mouse Hover") {
875 public void actionPerformed( final ActionEvent e ) {
876 setTrigger(HOVER_TRIGGER);
877 }
878 });
879 updateGroup.add(updateHover);
880 final JRadioButton updateSelection = new JRadioButton(new AbstractAction("Selection Change") {
881 public void actionPerformed( final ActionEvent e ) {
882 setTrigger(SELECTION_TRIGGER);
883 }
884 });
885 updateSelection.setSelected(true);
886 updateGroup.add(updateSelection);
887
888 final Box updatePane = Box.createHorizontalBox();
889 updatePane.add(Box.createHorizontalStrut(5));
890 updatePane.add(new JLabel("Update Trigger: "));
891 updatePane.add(updateHover);
892 updatePane.add(updateSelection);
893 updatePane.add(Box.createGlue());
894 return updatePane;
895 }
896
897
906 private void addStrategy(
907 final JPanel settingsPane,
908 final Box strategyButtons,
909 final ButtonGroup strategiesGroup,
910 final String title,
911 JComponent settings,
912 final AbstractLocalViewCreator lvc,
913 final boolean nodeBased
914 ) {
915 if (settings == null) {
916 settings = new JPanel();
917 settings.add(new JLabel("No Settings"));
918 }
919 final JRadioButton strategyButton = new JRadioButton(new AbstractAction(title) {
920 public void actionPerformed(ActionEvent e) {
921 ((CardLayout) settingsPane.getLayout()).show(settingsPane, title);
922 if (nodeBased) {
923 setNodeLocalViewCreator(lvc);
924 } else {
925 setEdgeLocalViewCreator(lvc);
926 }
927 }
928 });
929
930 final CompoundBorder border = BorderFactory.createCompoundBorder(
931 BorderFactory.createTitledBorder(title + " Settings"),
932 BorderFactory.createEmptyBorder(5, 5, 5, 5));
933 settings.setBorder(border);
934 settingsPane.add(settings, title);
935
936 strategiesGroup.add(strategyButton);
937 if (strategiesGroup.getButtonCount() == 1) {
938 strategiesGroup.setSelected(strategyButton.getModel(), true);
939 }
940 strategyButtons.add(strategyButton);
941 }
942
943
949 private Layouter createLayouter() {
950 final IncrementalHierarchicLayouter layouter = new IncrementalHierarchicLayouter();
954 layouter.setLayoutOrientation(LayoutOrientation.BOTTOM_TO_TOP);
955
956 final EdgeLayoutDescriptor eld = layouter.getEdgeLayoutDescriptor();
959 eld.setRoutingStyle(new RoutingStyle(RoutingStyle.EDGE_STYLE_ORTHOGONAL));
960 eld.setMinimumFirstSegmentLength(25);
961 eld.setMinimumLength(35);
962 return layouter;
963 }
964
965 public static void main( String[] args ) {
966 EventQueue.invokeLater(new Runnable() {
967 public void run() {
968 Locale.setDefault(Locale.ENGLISH);
969 initLnF();
970 (new LocalViewDemo("resource/localviewhelp.html")).start();
971 }
972 });
973 }
974
975
979 private final class SelectionTrigger implements Graph2DSelectionListener {
980 private final Timer timer;
981 private Graph2DSelectionEvent lastEvent;
982
983 SelectionTrigger() {
984 timer = new Timer(TIMER_DELAY, new ActionListener() {
985 public void actionPerformed( final ActionEvent e ) {
986 if (lastEvent != null) {
987 handleEvent(lastEvent);
988 }
989 }
990
991
994 private void handleEvent( final Graph2DSelectionEvent e ) {
995 if (e.isNodeSelection()) {
996 createNodeView(e.getGraph2D().selectedNodes());
997 } else if (e.isEdgeSelection()) {
998 createEdgeView(e.getGraph2D().selectedEdges());
999 }
1000 }
1001 });
1002 timer.setRepeats(false);
1003 }
1004
1005 public void onGraph2DSelectionEvent( final Graph2DSelectionEvent e ) {
1006 if (e.getGraph2D() == getCurrentLocalViewCreator().getModel()) {
1007 if (e.isNodeSelection() || e.isEdgeSelection()) {
1008 lastEvent = e;
1009 timer.restart();
1010 }
1011 }
1012 }
1013 }
1014
1015
1019 private final class HoverTrigger extends ViewMode {
1020 private final Timer timer;
1021 private YPoint lastPosition;
1022
1023 private HoverTrigger() {
1024 timer = new Timer(TIMER_DELAY, new ActionListener() {
1025 public void actionPerformed( ActionEvent e) {
1026 if (lastPosition != null) {
1027 handleHit(getHitInfo(lastPosition.x, lastPosition.y));
1028 }
1029 }
1030
1031
1034 private void handleHit( final HitInfo hitInfo ) {
1035 if (hitInfo.hasHitNodes()) {
1036 createNodeView(hitInfo.hitNodes());
1037 } else if (hitInfo.hasHitEdges()) {
1038 createEdgeView(hitInfo.hitEdges());
1039 }
1040 }
1041 });
1042 timer.setRepeats(false);
1043 }
1044
1045 public void mouseMoved(double x, double y) {
1046 super.mouseMoved(x, y);
1047 this.lastPosition = new YPoint(x, y);
1048 timer.restart();
1049 }
1050 }
1051
1052
1058 private static final class SelectedSubgraph extends AbstractLocalViewCreator {
1059 private final Graph2D model;
1060 private final GraphCopier.CopyFactory factory;
1061 private final Graph2D view;
1062
1063
1074 SelectedSubgraph(
1075 final Graph2D model,
1076 final GraphCopier.CopyFactory factory,
1077 final Graph2D view
1078 ) {
1079 super(AbstractLocalViewCreator.ELEMENT_TYPE_NODE);
1080 this.model = model;
1081 this.factory = factory;
1082 this.view = view;
1083
1084 final ModelViewManager mvm = ModelViewManager.getInstance(model);
1087 if (!mvm.isViewGraph(view)) {
1088 mvm.addViewGraph(view, null, false, false);
1089 mvm.setCopyFactory(view, factory);
1090 }
1091 }
1092
1093
1097 public Graph2D getModel() {
1098 return model;
1099 }
1100
1101
1105 public Graph2D getViewGraph() {
1106 return view;
1107 }
1108
1109
1116 public Node getModelNode( final Node view ) {
1117 return getManager().getModelNode(view);
1118 }
1119
1120
1129 public Node getViewNode( final Node model ) {
1130 return getManager().getViewNode(model, getViewGraph());
1131 }
1132
1133
1140 public Edge getModelEdge( final Edge view ) {
1141 return getManager().getModelEdge(view);
1142 }
1143
1144
1153 public Edge getViewEdge( final Edge model ) {
1154 return getManager().getViewEdge(model, getViewGraph());
1155 }
1156
1157
1163 protected Layouter createDefaultLayouter() {
1164 return null;
1165 }
1166
1167
1170 protected void buildViewGraph() {
1171 final Graph2D model = getModel();
1172 if (!model.isSelectionEmpty()) {
1173 final HashSet nodes = new HashSet();
1174 final HashSet edges = new HashSet();
1175
1176 for (Iterator it = focusNodes(); it.hasNext();) {
1178 final Node node = (Node) it.next();
1179 if (model.isSelected(node)) {
1180 nodes.add(node);
1181 }
1182 }
1183
1184 for (EdgeCursor ec = model.edges(); ec.ok(); ec.next()) {
1186 final Edge edge = ec.edge();
1187 if (nodes.contains(edge.source()) && nodes.contains(edge.target())) {
1188 edges.add(edge);
1189 }
1190 }
1191
1192 final Graph2D view = getViewGraph();
1194 final ModelViewManager mvm = getManager();
1195
1196 final GraphCopier.CopyFactory oldFactory = mvm.getCopyFactory(view);
1201 if (oldFactory != factory) {
1202 mvm.setCopyFactory(view, factory);
1203 }
1204 try {
1205 mvm.synchronizeModelToViewGraph(
1206 (new NodeList(nodes.iterator())).nodes(),
1207 (new EdgeList(edges.iterator())).edges(),
1208 view);
1209 } finally {
1210 if (oldFactory != factory) {
1212 mvm.setCopyFactory(view, oldFactory);
1213 }
1214 }
1215 }
1216 }
1217
1218 private ModelViewManager getManager() {
1219 return ModelViewManager.getInstance(getModel());
1220 }
1221 }
1222}
1223