/*
* Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
package com.sun.tools.example.debug.gui;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.*;
import com.sun.tools.example.debug.bdi.*;
public class SourceTreeTool extends JPanel {
private static final long serialVersionUID = 3336680912107956419L;
private Environment env;
private ExecutionManager runtime;
private SourceManager sourceManager;
private ClassManager classManager;
private JTree tree;
private SourceTreeNode root;
private SearchPath sourcePath;
private CommandInterpreter interpreter;
private static String HEADING = "SOURCES";
public SourceTreeTool(Environment env) {
super(new BorderLayout());
this.env = env;
this.runtime = env.getExecutionManager();
this.sourceManager = env.getSourceManager();
this.interpreter = new CommandInterpreter(env);
sourcePath = sourceManager.getSourcePath();
root = createDirectoryTree(HEADING);
// Create a tree that allows one selection at a time.
tree = new JTree(new DefaultTreeModel(root));
tree.setSelectionModel(new SingleLeafTreeSelectionModel());
/******
// Listen for when the selection changes.
tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
SourceTreeNode node = (SourceTreeNode)
(e.getPath().getLastPathComponent());
interpreter.executeCommand("view " + node.getRelativePath());
}
});
******/
MouseListener ml = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int selRow = tree.getRowForLocation(e.getX(), e.getY());
TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
if(selRow != -1) {
if(e.getClickCount() == 1) {
SourceTreeNode node =
(SourceTreeNode)selPath.getLastPathComponent();
// If user clicks on leaf, select it, and issue 'view' command.
if (node.isLeaf()) {
tree.setSelectionPath(selPath);
interpreter.executeCommand("view " + node.getRelativePath());
}
}
}
}
};
tree.addMouseListener(ml);
JScrollPane treeView = new JScrollPane(tree);
add(treeView);
// Create listener for source path changes.
SourceTreeToolListener listener = new SourceTreeToolListener();
sourceManager.addSourceListener(listener);
//### remove listeners on exit!
}
private class SourceTreeToolListener implements SourceListener {
@Override
public void sourcepathChanged(SourcepathChangedEvent e) {
sourcePath = sourceManager.getSourcePath();
root = createDirectoryTree(HEADING);
tree.setModel(new DefaultTreeModel(root));
}
}
private static class SourceOrDirectoryFilter implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
return (name.endsWith(".java") ||
new File(dir, name).isDirectory());
}
}
private static FilenameFilter filter = new SourceOrDirectoryFilter();
SourceTreeNode createDirectoryTree(String label) {
try {
return new SourceTreeNode(label, null, "", true);
} catch (SecurityException e) {
env.failure("Cannot access source file or directory");
return null;
}
}
class SourceTreeNode implements TreeNode {
private String name;
private boolean isDirectory;
private SourceTreeNode parent;
private SourceTreeNode[] children;
private String relativePath;
private boolean isExpanded;
private SourceTreeNode(String label,
SourceTreeNode parent,
String relativePath,
boolean isDirectory) {
this.name = label;
this.relativePath = relativePath;
this.parent = parent;
this.isDirectory = isDirectory;
}
@Override
public String toString() {
return name;
}
public String getRelativePath() {
return relativePath;
}
private void expandIfNeeded() {
try {
if (!isExpanded && isDirectory) {
String[] files = sourcePath.children(relativePath, filter);
children = new SourceTreeNode[files.length];
for (int i = 0; i < files.length; i++) {
String childName =
(relativePath.equals(""))
? files[i]
: relativePath + File.separator + files[i];
File file = sourcePath.resolve(childName);
boolean isDir = (file != null && file.isDirectory());
children[i] =
new SourceTreeNode(files[i], this, childName, isDir);
}
}
isExpanded = true;
} catch (SecurityException e) {
children = null;
env.failure("Cannot access source file or directory");
}
}
// -- interface TreeNode --
/*
* Returns the child <code>TreeNode</code> at index
* <code>childIndex</code>.
*/
@Override
public TreeNode getChildAt(int childIndex) {
expandIfNeeded();
return children[childIndex];
}
Returns the number of children TreeNode
s the receiver
contains.
/**
* Returns the number of children <code>TreeNode</code>s the receiver
* contains.
*/
@Override
public int getChildCount() {
expandIfNeeded();
return children.length;
}
Returns the parent TreeNode
of the receiver.
/**
* Returns the parent <code>TreeNode</code> of the receiver.
*/
@Override
public TreeNode getParent() {
return parent;
}
Returns the index of node
in the receivers children.
If the receiver does not contain node
, -1 will be
returned.
/**
* Returns the index of <code>node</code> in the receivers children.
* If the receiver does not contain <code>node</code>, -1 will be
* returned.
*/
@Override
public int getIndex(TreeNode node) {
expandIfNeeded();
for (int i = 0; i < children.length; i++) {
if (children[i] == node) {
return i;
}
}
return -1;
}
Returns true if the receiver allows children.
/**
* Returns true if the receiver allows children.
*/
@Override
public boolean getAllowsChildren() {
return isDirectory;
}
Returns true if the receiver is a leaf.
/**
* Returns true if the receiver is a leaf.
*/
@Override
public boolean isLeaf() {
expandIfNeeded();
return !isDirectory;
}
Returns the children of the receiver as an Enumeration.
/**
* Returns the children of the receiver as an Enumeration.
*/
@Override
public Enumeration children() {
expandIfNeeded();
return new Enumeration() {
int i = 0;
@Override
public boolean hasMoreElements() {
return (i < children.length);
}
@Override
public Object nextElement() throws NoSuchElementException {
if (i >= children.length) {
throw new NoSuchElementException();
}
return children[i++];
}
};
}
}
}