/* $Id: FileTree.java,v 1.11 2010/09/19 01:28:58 nhnb Exp $ */
/***************************************************************************
* (C) Copyright 2003-2010 - Stendhal *
***************************************************************************
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
package data.sprites.monsters;
/**
*
*/
import java.io.File;
import java.io.FileNotFoundException;
import javax.swing.JTree;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class FileTree extends JTree {
/**
*
*/
private static final long serialVersionUID = 1L;
public FileTree(final String path) throws FileNotFoundException {
// Create the JTree itself
super((TreeModel) null);
// Use horizontal and vertical lines
putClientProperty("JTree.lineStyle", "Angled");
// Create the first node
final FileTreeNode rootNode = new FileTreeNode(null, path);
// Populate the root node with its subdirectories
rootNode.populateDirectories(true);
setModel(new DefaultTreeModel(rootNode));
// Listen for Tree Selection Events
addTreeExpansionListener(new TreeExpansionHandler());
}
// Returns the full pathname for a path, or null
// if not a known path
public String getPathName(final TreePath path) {
final Object o = path.getLastPathComponent();
if (o instanceof FileTreeNode) {
return ((FileTreeNode) o).file.getAbsolutePath();
}
return null;
}
// Returns the File for a path, or null if not a known path
public File getFile(final TreePath path) {
final Object o = path.getLastPathComponent();
if (o instanceof FileTreeNode) {
return ((FileTreeNode) o).file;
}
return null;
}
// Inner class that represents a node in this
// file system tree
protected class FileTreeNode extends DefaultMutableTreeNode {
private static final long serialVersionUID = 3223106240309250204L;
/**
* File object for this node.
*/
protected File file;
/**
* Name of this node.
*/
protected String name;
/**
* true if we have been populated.
*/
protected boolean populated;
/**
* true if we are in interim state.
*/
protected boolean interim;
/**
* true if this is a directory.
*/
protected boolean isDir;
public FileTreeNode(final File parent, final String name) throws FileNotFoundException {
this.name = name;
// See if this node exists and whether it
// is a directory
file = new File(parent, name);
if (!file.exists()) {
throw new FileNotFoundException("File " + name + " does not exist");
}
isDir = file.isDirectory();
// Hold the File as the user object.
setUserObject(file);
}
// Override isLeaf to check whether this is a directory
@Override
public boolean isLeaf() {
return !isDir;
}
// Override getAllowsChildren to check whether
// this is a directory
@Override
public boolean getAllowsChildren() {
return isDir;
}
// For display purposes, we return our own name public String toString()
// { return name; }
// If we are a directory, scan our contents and populate
// with children. In addition, populate those children
// if the "descend" flag is true. We only descend once,
// to avoid recursing the whole subtree.
// Returns true if some nodes were added
boolean populateDirectories(final boolean descend) {
boolean addedNodes = false;
// Do this only once
if (!populated) {
if (interim) {
// We have had a quick look here before:
// remove the dummy node that we added last time
removeAllChildren();
interim = false;
}
// Get list of contents
final String[] names = file.list();
// Process the directories
for (int i = 0; i < names.length; i++) {
final String nameTemp = names[i];
try {
// if (d.isDirectory()) {
final FileTreeNode node = new FileTreeNode(file, nameTemp);
this.add(node);
if (descend) {
node.populateDirectories(false);
}
addedNodes = true;
if (!descend) {
// Only add one node if not descending
break;
}
// }
// else{
// }
} catch (final Throwable t) {
// Ignore phantoms or access problems
}
}
// If we were scanning to get all subdirectories,
// or if we found no subdirectories, there is no
// reason to look at this directory again, so
// set populated to true. Otherwise, we set interim
// so that we look again in the future if we need to
if (descend || !addedNodes) {
populated = true;
} else {
// Just set interim state
interim = true;
}
}
return addedNodes;
}
}
// Inner class that handles Tree Expansion Events
protected static class TreeExpansionHandler implements TreeExpansionListener {
public void treeExpanded(final TreeExpansionEvent evt) {
// The expanded path
final TreePath path = evt.getPath();
// The tree
final JTree tree = (JTree) evt.getSource();
// Get the last component of the path and
// arrange to have it fully populated.
final FileTreeNode node = (FileTreeNode) path.getLastPathComponent();
if (node.populateDirectories(true)) {
((DefaultTreeModel) tree.getModel()).nodeStructureChanged(node);
}
}
public void treeCollapsed(final TreeExpansionEvent evt) {
// Nothing to do
}
}
}