/*
* @(#)GraphSelectionDemo.java 3.3 23-APR-04
*
* Copyright (c) 2001-2004, Gaudenz Alder All rights reserved.
*
* See LICENSE file in distribution for licensing details of this source file
*/
package com.jgraph.example;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import org.jgraph.JGraph;
import org.jgraph.event.GraphModelEvent;
import org.jgraph.event.GraphModelListener;
import org.jgraph.event.GraphSelectionEvent;
import org.jgraph.event.GraphSelectionListener;
import org.jgraph.graph.GraphModel;
/**
* With this example you'll learn how to listen to graph selection event,
* program graph selections and navigate accross the graph groups.
*
* This demo is is a bit like the GraphTreeModel demo. But this time, we
* synchronize the graph and the tree selection with two listeners.
*
* There are two issues actually. The first is that we should disable one
* listener when we programatically change its selection after the other
* listener receives a selection event (else we would fail in infinite loops).
* The other issue is navigating the graph and especially its group in order to
* get the equivalent tree selection. Also notice that ports should be handled
* like a special kind of group children.
*
* @author rvalyi
*/
public class GraphSelectionDemo extends DefaultTreeModel implements
GraphModelListener {
private static JTree tree;
private static JGraph graph;
private static GraphSelectionDemo gtModel;
private static GraphModelTreeNode gtModelTreeNode;
private static SyncGraphSelectionListener mySyncTreeSelectionListener = new SyncGraphSelectionListener();
public static void main(String[] args) {
JFrame frame = new JFrame("GraphSelectionDemo");
graph = new JGraph();
gtModel = new GraphSelectionDemo(graph.getModel());
gtModelTreeNode = new GraphModelTreeNode(graph.getModel());
graph.getModel().addGraphModelListener(gtModel);
tree = new JTree(gtModel);
tree.setRootVisible(false);
JScrollPane sGraph = new JScrollPane(graph);
JScrollPane sTree = new JScrollPane(tree);
tree.addTreeSelectionListener(new SyncTreeSelectionListener());
graph.addGraphSelectionListener(mySyncTreeSelectionListener);
graph.addMouseListener(new MyMouseListener());
JSplitPane pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sTree,
sGraph);
frame.getContentPane().add(pane);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public GraphSelectionDemo(GraphModel model) {
super(new GraphModelTreeNode(model));
}
public void graphChanged(GraphModelEvent e) {
reload();
}
public static class SyncTreeSelectionListener implements
TreeSelectionListener {
public void valueChanged(TreeSelectionEvent e) {
if (tree.isSelectionEmpty())//a selection in the graph can trigger that event while no tree selection exists yet
return;
TreePath[] treeSelection = tree.getSelectionModel()
.getSelectionPaths();
Object[] graphSelection = new Object[treeSelection.length];
for (int i = 0; i < treeSelection.length; i++) {
graphSelection[i] = treeSelection[i].getLastPathComponent();
}
// now we set the corresponding graph selection
graph.setSelectionCells(graphSelection);
/*
* System.out .print(tree.getSelectionModel().getSelectionPath() +
* "\n");
*/
}
}
/**
* Prevent from loosing the synchronisation after a graph element is dragged
*/
public static class MyMouseListener extends MouseInputAdapter {
public void mouseReleased(MouseEvent e) {
if (e.getSource() instanceof JGraph) {
mySyncTreeSelectionListener.valueChanged(null);
}
}
}
public static class SyncGraphSelectionListener implements
GraphSelectionListener {
public void valueChanged(GraphSelectionEvent e) {
Object selectedPort = null;
Object[] selection = graph.getSelectionModel().getSelectionCells();
if (selection == null)
return;
TreePath[] paths = new TreePath[selection.length];
for (int i = 0; i < selection.length; i++) {
ArrayList list = new ArrayList();
Object selected = selection[i];
if (selected == null)
return;
list.add(tree.getModel().getRoot());
if (graph.getModel().isPort(selected)) {// shift if a port
// is
// selected
selectedPort = selected;
selected = graph.getModel().getParent(selected);
}
list = computeTreePathSelection(list, graph.getModel()
.getParent(selected), selected);
if (selectedPort != null)
list.add(selectedPort);
TreePath treePath = new TreePath(list.toArray());
if (treePath != null) {
paths[i] = treePath;
// System.out.print( treePath.toString() + "\n");
}
}
// to emphasis the change, we collapse the whole tree before
// assigning a new selection
int treeSize = tree.getRowCount();
int row = 0;
while (row < treeSize) {
tree.collapseRow(row);
row++;
}
// now we set the corresponding tree selection
tree.setSelectionPaths(paths);
}
/**
* Recursively adds the selected graph cells to the array list, starting
* from the current child and going until the graph root.
*
* @param currentList
* @param parent
* @param child
* @return collection of selected graph cells
*/
public ArrayList computeTreePathSelection(ArrayList currentList,
Object parent, Object child) {
if (parent == null) {
currentList.add(child);
return currentList;
}
int parentIndex = graph.getModel().getIndexOfRoot(parent);
if (parentIndex < 0) {// then parent is in a group or is a port
computeTreePathSelection(currentList, graph.getModel()
.getParent(parent), parent);
}
// parentIndex refer to a valid selected node in the tree
currentList.add(gtModelTreeNode.getChildAt(parentIndex));
// index of the child in the graph
int childIndex = graph.getModel().getIndexOfChild(parent, child);
// corresponding node in the tree
Object node = tree.getModel().getChild(parent, childIndex);
currentList.add(node);
return currentList;
}
}
/**
* See the GraphModelTree demo
*/
public static class GraphModelTreeNode implements TreeNode {
protected GraphModel model;
public GraphModelTreeNode(GraphModel model) {
this.model = model;
}
public Enumeration children() {
Vector v = new Vector();
for (int i = 0; i < model.getRootCount(); i++)
v.add(model.getRootAt(i));
return v.elements();
}
public boolean getAllowsChildren() {
return true;
}
public TreeNode getChildAt(int childIndex) {
return (TreeNode) model.getRootAt(childIndex);
}
public int getChildCount() {
return model.getRootCount();
}
public int getIndex(TreeNode node) {
return model.getIndexOfRoot(node);
}
public TreeNode getParent() {
return null;
}
public boolean isLeaf() {
return false;
}
public String toString() {
return model.toString();
}
}
}