1 /*
GNU General Public License
TreeSpider - Directory & File Traversal Utility Class
Copyright (C) 2000 Howard A Kistler
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.
This program 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 for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package com
.hexidec
.util
;
import java
.io
.File
;
import java
.util
.Arrays
;
import java
.util
.Collections
;
import java
.util
.Comparator
;
import java
.util
.Enumeration
;
import java
.util
.Hashtable
;
import java
.util
.Vector
;
import javax
.swing
.tree
.DefaultMutableTreeNode
;
import javax
.swing
.tree
.DefaultTreeModel
;
/** TreeSpider
* Utility class for traversing, scanning & describing directory/file structures
*
* @author Howard Kistler
* @version 0.2
*
* VERSION HISTORY
* 0.1 (09/14/2000) - initial creation (started on 08/09/2000)
* 0.2 (09/22/2001) - numerous enhancements
*/
public class TreeSpider
{
private File rootFile
;
private Vector vcFiles
;
private Vector vcExtensions
;
private int maxDepth
;
private boolean bScreenExtensions
;
private boolean bFileNamesOnly
;
private boolean bDisplayMode
;
private FileTreeComparator localComparison
;
// Constructors ---------------------------------------------------------------------------->
/* Main Constructor */
public TreeSpider(String origin, Vector exts, boolean caseSensitive, int mDepth) {
rootFile = new File(origin);
vcFiles = new Vector();
vcExtensions = exts;
maxDepth = mDepth;
bScreenExtensions = false;
bFileNamesOnly = false;
bDisplayMode = false;
if(vcExtensions.size() > 0) {
bScreenExtensions = true;
}
localComparison = new FileTreeComparator(caseSensitive);
}
/* Alternate Constructor */
public TreeSpider(String origin, Vector exts, boolean caseSensitive) {
this(origin, new Vector(), caseSensitive, 0);
}
/* Alternate Constructor */
public TreeSpider(String origin, boolean caseSensitive, int mDepth) {
this(origin, new Vector(), caseSensitive, mDepth);
}
/* Alternate Constructor */
public TreeSpider(String origin, boolean caseSensitive) {
this(origin, new Vector(), caseSensitive, 0);
}
/* Alternate Constructor */
public TreeSpider(String origin, int mDepth) {
this(origin, new Vector(), false, mDepth);
}
/* Alternate Constructor */
public TreeSpider(String origin) {
this(origin, new Vector(), false, 0);
}
/* Alternate Constructor */
public TreeSpider() {
this(".", new Vector(), false, 0);
}
// Public Class Methods -------------------------------------------------------------------->
/** Returns a DefaultTreeModel built from the specified root file */
public DefaultTreeModel fetchTree(File newRootFile) {
return describeTree(newRootFile);
}
/** Returns a DefaultTreeModel built from the preset root file */
public DefaultTreeModel fetchTree() {
return describeTree(rootFile);
}
/** Returns an unsorted listing of the file tree */
public Vector fetchMassListing() {
return fetchListing();
}
/** Returns an index-style listing of the file tree of complete file names and paths */
public Vector sortMassListing() {
Vector vcListing = fetchListing();
Collections.sort(vcListing, localComparison);
return vcListing;
}
/** Returns an index-style listing of the file tree of file names only */
public Vector sortFileListing() {
Vector vcListing = trimToName(fetchListing());
Collections.sort(vcListing, localComparison);
return vcListing;
}
/** Returns a directory-style listing of the file tree */
public Hashtable collectListing() {
Vector vcListing = fetchListing();
Hashtable htCollected = new Hashtable();
for(int i = 0; i < vcListing.size(); i++) {
String fullname = (String)(vcListing.elementAt(i));
String filepath = fullname.substring(0, fullname.lastIndexOf(File.separator));
String filename = fullname.substring(fullname.lastIndexOf(File.separator) + 1, fullname.length());
if(htCollected.containsKey(filepath)) {
((Vector)(htCollected.get(filepath))).add(filename);
}
else {
htCollected.put(filepath, new Vector());
((Vector)(htCollected.get(filepath))).add(filename);
}
}
return htCollected;
}
// Internal Class Methods ------------------------------------------------------------------>
private DefaultTreeModel describeTree(File rootFile) {
DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode(rootFile.getName());
DefaultTreeModel treeModel = new DefaultTreeModel(treeRoot);
if(!(rootFile.isDirectory())) {
return treeModel;
}
String rootStr = rootFile.getAbsolutePath().trim() + File.separator;
Vector vcContents = fetchListing();
while(vcContents.size() > 0) {
String nodeName = (String)(vcContents.elementAt(0));
if(nodeName.startsWith(rootStr)) {
nodeName = nodeName.substring(rootStr.length());
if(nodeName.indexOf(File.separator) > -1) {
String baseNode = nodeName.substring(0, nodeName.indexOf(File.separator));
describeTreeSubNodes(vcContents, treeModel, treeRoot, rootStr, baseNode);
}
else {
treeModel.insertNodeInto(new DefaultMutableTreeNode(nodeName), treeRoot, treeModel.getChildCount(treeRoot));
vcContents.removeElementAt(0);
}
}
else {
vcContents.removeElementAt(0);
}
}
return treeModel;
}
private void describeTreeSubNodes(Vector vcNodes, DefaultTreeModel treeModel, DefaultMutableTreeNode nodeParent, String basePath, String baseNodeName) {
DefaultMutableTreeNode thisNode = new DefaultMutableTreeNode(baseNodeName);
treeModel.insertNodeInto(thisNode, nodeParent, treeModel.getChildCount(nodeParent));
boolean inSubNode = true;
String fullNodePath = basePath + baseNodeName + File.separator;
while(inSubNode && vcNodes.size() > 0) {
String nodeName = (String)(vcNodes.elementAt(0));
if(nodeName.startsWith(fullNodePath)) {
nodeName = nodeName.substring(fullNodePath.length());
if(nodeName.indexOf(File.separator) > -1) {
String baseNode = nodeName.substring(0, nodeName.indexOf(File.separator));
describeTreeSubNodes(vcNodes, treeModel, thisNode, fullNodePath, baseNode);
}
else {
treeModel.insertNodeInto(new DefaultMutableTreeNode(nodeName), thisNode, treeModel.getChildCount(thisNode));
vcNodes.removeElementAt(0);
}
}
else {
inSubNode = false;
}
}
}
private Vector fetchListing() {
Vector vcFetch = new Vector();
if(rootFile.isDirectory()) {
vcFetch.add(exploreFolder("", rootFile, new Vector(), 1));
}
else {
String fullFile = rootFile.getAbsolutePath().trim();
if(!bScreenExtensions || (bScreenExtensions && screensOkay(fullFile))) {
vcFetch.add(fullFile);
}
}
return describeListing(vcFetch);
}
private Vector trimToName(Vector fullFiles) {
Vector vcReturn = new Vector(fullFiles.size());
for(int i = 0; i < fullFiles.size(); i++) {
String trimName = (String)(fullFiles.elementAt(i));
if(trimName.indexOf(File.separator) > -1) {
vcReturn.add(trimName.substring(trimName.lastIndexOf(File.separator) + 1, trimName.length()));
}
else {
vcReturn.add(trimName);
}
}
return vcReturn;
}
/* Recursively explores file folders and subfolders, adding all files which match the filtered type
to the returning Vector.
*/
private Vector exploreFolder(String currentLocal, File folder, Vector vcWorking, int currDepth) {
if((maxDepth != 0) && currDepth > maxDepth) {
return vcWorking;
}
String fullDescriptor = currentLocal + File.separator + folder.getName();
File[] contents = folder.listFiles();
for(int i = 0; i < contents.length; i++) {
if(contents[i].isDirectory()) {
vcWorking.add(exploreFolder(fullDescriptor, contents[i], new Vector(), currDepth + 1));
}
else {
String completeName = contents[i].getAbsolutePath();
if(bFileNamesOnly) { completeName = contents[i].getName(); }
if(!bScreenExtensions || (bScreenExtensions && screensOkay(completeName))) {
vcWorking.add(completeName.trim());
}
}
}
Collections.sort(vcWorking, localComparison);
return vcWorking;
}
/* Explores only current file folder, adding all files which match the filtered type
to the returning Vector.
*/
private Vector exploreFolderOnly(String currentLocal, File folder, Vector vcWorking) {
String fullDescriptor = currentLocal + File.separator + folder.getName();
File[] contents = folder.listFiles();
for(int i = 0; i < contents.length; i++) {
if(contents[i].isDirectory()) {
/* ignore */
}
else {
String completeName = contents[i].getAbsolutePath();
if(bFileNamesOnly) { completeName = contents[i].getName(); }
if(!bScreenExtensions || (bScreenExtensions && screensOkay(completeName))) {
vcWorking.add(completeName.trim());
}
}
}
Collections.sort(vcWorking, localComparison);
return vcWorking;
}
private Vector describeListing(Vector vcTree) {
Collections.sort(vcTree, localComparison);
Vector vcDescription = new Vector();
for(int i = 0; i < vcTree.size(); i++) {
if(vcTree.elementAt(i) instanceof Vector) {
describeNode((Vector)(vcTree.elementAt(i)), vcDescription);
}
else {
vcDescription.add(vcTree.elementAt(i));
}
}
return vcDescription;
}
private void describeNode(Vector vcNode, Vector vcStore) {
for(int i = 0; i < vcNode.size(); i++) {
if(vcNode.elementAt(i) instanceof Vector) {
describeNode((Vector)(vcNode.elementAt(i)), vcStore);
}
else {
vcStore.add(vcNode.elementAt(i));
}
}
}
private boolean screensOkay(String filename) {
for(int i = 0; i < vcExtensions.size(); i++) {
String extension = ((String)(vcExtensions.elementAt(i))).toLowerCase();
if(filename.toLowerCase().endsWith(extension)) {
return true;
}
}
return false;
}
// Accessor Methods ------------------------------------------------------------------------>
public File getRootFile() { return rootFile; }
public Vector getFiles() { return vcFiles; }
public Vector getExtensions() { return vcExtensions; }
public int getMaxDepth() { return maxDepth; }
public boolean doScreenExtensions() { return bScreenExtensions; }
public boolean showFileNamesOnly() { return bFileNamesOnly; }
public boolean getDisplayMode() { return bDisplayMode; }
public void setRootFile(File f) { rootFile = f; }
public void setFiles(Vector vc) { vcFiles = vc; }
public void setExtensions(Vector vc) {
vcExtensions = vc;
if(vcExtensions.size() > 0) {
setScreenExtensions(true);
}
else {
setScreenExtensions(false);
}
}
public void setMaxDepth(int i) { maxDepth = i; }
public void setScreenExtensions(boolean b) { bScreenExtensions = b; }
public void setFileNamesOnly(boolean b) { bFileNamesOnly = b; }
public void setDisplayMode(boolean b) { bDisplayMode = b; }
// Unit Test Method ------------------------------------------------------------------------>
/** Unit test method for testing the code with example settings */
public static void unitTest(String dir) {
Vector vcCommonExts = new Vector();
vcCommonExts.add(".java");
vcCommonExts.add(".class");
vcCommonExts.add(".txt");
vcCommonExts.add(".html");
vcCommonExts.add(".htm");
vcCommonExts.add(".gif");
vcCommonExts.add(".jpeg");
vcCommonExts.add(".jpg");
TreeSpider testSpider = new TreeSpider(dir, vcCommonExts, false, 0);
System.out.println("UNIT TEST SCAN");
Hashtable htColl = testSpider.collectListing();
Enumeration enumKeys = htColl.keys();
while(enumKeys.hasMoreElements()) {
String key = (String)(enumKeys.nextElement());
System.out.println(key);
Vector vcValues = (Vector)(htColl.get(key));
for(int i = 0; i < vcValues.size(); i++) {
System.out.println(" " + vcValues.elementAt(i));
}
}
}
// Main Method ----------------------------------------------------------------------------->
public static void main(String[] args) {
if(args.length < 1) {
try {
TreeSpider.unitTest((new File(".")).getCanonicalPath());
}
catch(java.io.IOException ioe) {
System.out.println("Unable to resolve current directory. Please specify a directory explicitly.");
System.exit(1);
}
}
else {
TreeSpider.unitTest(args[0]);
}
}
// Inner Classes --------------------------------------------------------------------------->
/* Class for sorting file listings by directory then name */
class FileTreeComparator implements Comparator
{
private boolean isCaseSensitive;
public FileTreeComparator(boolean caseCheck) {
isCaseSensitive = caseCheck;
}
public FileTreeComparator() {
isCaseSensitive = true;
}
public int compare(Object objA, Object objB) {
if(objA instanceof Vector) {
if(objB instanceof Vector) {
if(((Vector)(objA)).size() < 1)
{
return -1;
}
else if(((Vector)(objB)).size() < 1)
{
return 1;
}
else
{
return compare(((Vector)(objA)).elementAt(0), ((Vector)(objB)).elementAt(0));
}
}
else {
return 1;
}
}
else if(objB instanceof Vector) {
return -1;
}
else {
String strA = (String)objA;
String strB = (String)objB;
return (isCaseSensitive ? strA.compareTo(strB) : strA.compareToIgnoreCase(strB));
}
}
}
}