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