package iiuf.swing;
/**
JTree based tree view implementation.
(c) 2000, 2001, IIUF, DIUF<p>
@author $Author: ohitz $
@version $Name: $ $Revision: 1.1 $
*/
import java.util.Enumeration;
import java.util.ArrayList;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Component;
import java.awt.dnd.DragGestureRecognizer;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetListener;
import java.awt.dnd.DragSource;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import javax.swing.JTree;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.tree.TreeModel;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeNode;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import iiuf.util.ProgressListener;
import iiuf.util.ProgressWatcher;
import iiuf.util.EventListenerList;
import iiuf.log.Log;
import iiuf.awt.Awt;
public class JTreeView
extends
JScrollPane
implements
TreeView,
ProgressListener,
TreeModelListener
{
private final static Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
private Cursor saveCursor;
private TreeModel model;
private JTree trcmp = new JTree();
private EventListenerList listeners = new EventListenerList();
public JTreeView() {
this(null);
}
public JTreeView(TreeModel tree) {
this(tree, tree == null ? null : new TreePath(tree.getRoot()));
}
private TreeWillExpandListener treeWillExpandListener = new TreeWillExpandListener() {
public void treeWillCollapse(TreeExpansionEvent e) {}
public void treeWillExpand(TreeExpansionEvent e) {
synchronized(JTreeView.this) {
if(saveCursor == null) {
saveCursor = trcmp.getCursor();
ProgressWatcher.watch(JTreeView.this);
}
}
// force loading of tree
for(Enumeration en = ((TreeNode)e.getPath().getLastPathComponent()).children();
en.hasMoreElements();
en.nextElement());
}
};
public JTreeView(TreeModel model, TreePath rootPath) {
setModel(model, rootPath);
expanded = false;
trcmp.addTreeWillExpandListener(Swing.asyncWrapper(treeWillExpandListener));
trcmp.setRootVisible(false);
trcmp.setShowsRootHandles(true);
trcmp.putClientProperty("JTree.lineStyle", "Angled");
setViewportView(trcmp);
}
public void addRootNodeChangeListener(ChangeListener l) {
listeners.add(ChangeListener.class, l);
}
public void addRootNodeChangeListener(ChangeListener l, boolean weak) {
listeners.add(ChangeListener.class, l, weak);
}
public void removeRootNodeChangeListener(ChangeListener l) {
listeners.remove(ChangeListener.class, l);
}
public void treeNodesChanged(TreeModelEvent e) {
System.out.println(e);
Object[] childs = e.getChildren();
for(int i = 0; i < childs.length; i++)
if(childs[i] == trcmp.getModel().getRoot()) {
fireRootNodeChanged();
break;
}
}
public void treeStructureChanged(TreeModelEvent e) {
System.out.println(e);
if(e.getTreePath().getPathCount() == 1 &&
e.getTreePath().getPathComponent(0) != trcmp.getModel().getRoot())
fireRootNodeChanged();
}
public void treeNodesInserted(TreeModelEvent e) {}
public void treeNodesRemoved(TreeModelEvent e) {}
private void fireRootNodeChanged() {
ChangeListener[] listeners = (ChangeListener[])listenerList.getListeners(ChangeListener.class);
ChangeEvent ev = listeners.length == 0 ?
null :
new ChangeEvent(this);
for(int i = 0; i < listeners.length; i++)
listeners[i].stateChanged(ev);
}
private TreePath shortestCommonPath(TreePath p1, TreePath p2) {
TreePath result = new TreePath(p1.getPathComponent(0));
for(int i = 0; i < Math.min(p1.getPathCount(), p2.getPathCount()); i++)
if(!p1.getPathComponent(i).equals(p2.getPathComponent(i)))
break;
else
result = result.pathByAddingChild(p1.getPathComponent(i));
return result;
}
boolean expanded;
private void expandRoot() {
if(expanded) return;
trcmp.expandPath(new TreePath(trcmp.getModel().getRoot()));
expanded = true;
}
public Object locationToObject(Component component, Point location) {
TreePath path = trcmp.getPathForLocation(location.x, location.y);
return path == null ? null : path.getLastPathComponent();
}
public Component getComponent() {
return trcmp;
}
public void setContextMenuManager(ContextMenuManager manager) {}
public TreePath getSelectionPath() {
if(trcmp.getModel() instanceof SubTreeModel)
return ((SubTreeModel)trcmp.getModel()).absolute(trcmp.getSelectionPath());
else
return trcmp.getSelectionPath();
}
public TreePath[] getSelectionPaths() {
TreePath[] result = trcmp.getSelectionPaths();
if(result == null) return new TreePath[0];
if(trcmp.getModel() instanceof SubTreeModel)
for(int i = 0; i < result.length; i++)
result[i] = ((SubTreeModel)trcmp.getModel()).absolute(result[i]);
return result;
}
private TreePath relative(TreePath path) {
if(trcmp.getModel() instanceof SubTreeModel)
return ((SubTreeModel)trcmp.getModel()).relative(path);
else
return path;
}
public void makeVisible(TreePath path) {
if(path == null) return;
path = relative(path);
if(path == null) return;
trcmp.expandPath(path);
trcmp.scrollPathToVisible(path);
}
public void setModel(TreeModel model) {
setModel(model, null);
}
public void setModel(TreeModel model_, TreePath rootPath) {
trcmp.getModel().removeTreeModelListener(this);
model = model_;
if(rootPath == null)
trcmp.setModel(model);
else
trcmp.setModel(new SubTreeModel(model, (TreeNode)rootPath.getLastPathComponent()));
trcmp.getModel().addTreeModelListener(this);
}
public void setSelectionPath(TreePath path) {
path = relative(path);
if(path == null) return;
makeVisible(path);
trcmp.setSelectionPath(path);
}
public void setSelectionPaths(TreePath[] path) {
for(int i = 0; i < path.length; i++)
path[i] = relative(path[i]);
if(path == null || path.length == 0) return;
makeVisible(path[0]);
trcmp.setSelectionPaths(path);
}
public void clearSelection() {
trcmp.clearSelection();
}
public TreeModel getModel() {
return model;
}
public Object getViewRoot() {
return trcmp.getModel().getRoot();
}
public boolean isVisible(TreePath path) {
path = relative(path);
return trcmp.isVisible(path);
}
public TreePath getMostVisiblePath() {
TreePath result = new TreePath(trcmp.getModel().getRoot());
Enumeration e = trcmp.getExpandedDescendants(result);
if(e == null) return result;
while(e.hasMoreElements()) {
TreePath p = (TreePath)e.nextElement();
if(p.getPathCount() >= result.getPathCount())
result = p;
}
if(trcmp.getModel() instanceof SubTreeModel)
return ((SubTreeModel)trcmp.getModel()).absolute(result);
else
return result;
}
public void operationStart(String desc) {}
public void operationProgress(int amount, int of) {
if(amount == 0) trcmp.setCursor(WAIT_CURSOR);
}
public void operationStop() {
synchronized(JTreeView.this) {
trcmp.setCursor(saveCursor);
saveCursor = null;
}
}
DragGestureRecognizer sourceRecognizer;
DragGestureListener srcListener;
public void enableDrag(int sourceActions, DragGestureListener sourceListener) {
disableDrag();
sourceRecognizer = DragSource.getDefaultDragSource().
createDefaultDragGestureRecognizer(trcmp, sourceActions, sourceListener);
srcListener = sourceListener;
System.out.println(sourceRecognizer);
}
DropTarget dropTarget;
DropTargetListener trgtListener;
public void enableDrop(int targetActions, DropTargetListener targetListener) {
disableDrop();
dropTarget = new DropTarget(trcmp, targetActions, targetListener);
trgtListener = targetListener;
}
public void disableDrag() {
if(sourceRecognizer != null)
sourceRecognizer.removeDragGestureListener(srcListener);
sourceRecognizer = null;
srcListener = null;
System.gc();
}
public void disableDrop() {
if(dropTarget != null)
dropTarget.removeDropTargetListener(trgtListener);
dropTarget = null;
trgtListener = null;
System.gc();
}
}
/*
$Log: JTreeView.java,v $
Revision 1.1 2002/07/11 12:09:52 ohitz
Initial checkin
Revision 1.9 2001/01/14 13:21:13 schubige
Win NT update
Revision 1.8 2001/01/12 08:26:20 schubige
TJGUI update and some TreeView bug fixes
Revision 1.7 2001/01/04 16:28:38 schubige
Header update for 2001 and DIUF
Revision 1.6 2001/01/03 08:30:39 schubige
graph stuff beta
Revision 1.5 2000/12/01 14:41:36 schubige
SourceWatch beta 1
Revision 1.4 2000/11/09 07:48:44 schubige
early checkin for DCJava
Revision 1.3 2000/10/10 16:32:12 schubige
Added subtree display to TreeView, fixed some bugs
Revision 1.2 2000/10/03 08:39:39 schubige
Added tree view and contect menu stuff
Revision 1.1 2000/08/17 16:22:14 schubige
Swing cleanup & TreeView added
*/