1 /* $Id$ */ 2 /*************************************************************************** 3 * (C) Copyright 2003-2010 - Stendhal * 4 *************************************************************************** 5 *************************************************************************** 6 * * 7 * This program is free software; you can redistribute it and/or modify * 8 * it under the terms of the GNU General Public License as published by * 9 * the Free Software Foundation; either version 2 of the License, or * 10 * (at your option) any later version. * 11 * * 12 ***************************************************************************/ 13 package data.sprites.monsters; 14 15 /** 16 * 17 */ 18 19 import java.io.File; 20 import java.io.FileNotFoundException; 21 import java.util.Arrays; 22 23 import javax.swing.JTree; 24 import javax.swing.event.TreeExpansionEvent; 25 import javax.swing.event.TreeExpansionListener; 26 import javax.swing.tree.DefaultMutableTreeNode; 27 import javax.swing.tree.DefaultTreeModel; 28 import javax.swing.tree.TreeModel; 29 import javax.swing.tree.TreePath; 30 31 public class FileTree extends JTree { 32 /** 33 * 34 */ 35 private static final long serialVersionUID = 1L; 36 FileTree(final String path)37 public FileTree(final String path) throws FileNotFoundException { 38 // Create the JTree itself 39 super((TreeModel) null); 40 41 // Use horizontal and vertical lines 42 putClientProperty("JTree.lineStyle", "Angled"); 43 44 // Create the first node 45 final FileTreeNode rootNode = new FileTreeNode(null, path); 46 47 // Populate the root node with its subdirectories 48 rootNode.populateDirectories(true); 49 setModel(new DefaultTreeModel(rootNode)); 50 51 // Listen for Tree Selection Events 52 addTreeExpansionListener(new TreeExpansionHandler()); 53 } 54 55 // Returns the full pathname for a path, or null 56 // if not a known path getPathName(final TreePath path)57 public String getPathName(final TreePath path) { 58 final Object o = path.getLastPathComponent(); 59 if (o instanceof FileTreeNode) { 60 return ((FileTreeNode) o).file.getAbsolutePath(); 61 } 62 return null; 63 } 64 65 // Returns the File for a path, or null if not a known path getFile(final TreePath path)66 public File getFile(final TreePath path) { 67 final Object o = path.getLastPathComponent(); 68 if (o instanceof FileTreeNode) { 69 return ((FileTreeNode) o).file; 70 } 71 return null; 72 } 73 74 // Inner class that represents a node in this 75 // file system tree 76 protected class FileTreeNode extends DefaultMutableTreeNode { 77 78 private static final long serialVersionUID = 3223106240309250204L; 79 80 /** 81 * File object for this node. 82 */ 83 protected File file; 84 85 /** 86 * Name of this node. 87 */ 88 protected String name; 89 /** 90 * true if we have been populated. 91 */ 92 protected boolean populated; 93 /** 94 * true if we are in interim state. 95 */ 96 97 protected boolean interim; 98 /** 99 * true if this is a directory. 100 */ 101 102 protected boolean isDir; 103 104 105 106 FileTreeNode(final File parent, final String name)107 public FileTreeNode(final File parent, final String name) throws FileNotFoundException { 108 this.name = name; 109 110 // See if this node exists and whether it 111 // is a directory 112 file = new File(parent, name); 113 if (!file.exists()) { 114 throw new FileNotFoundException("File " + name + " does not exist"); 115 } 116 117 isDir = file.isDirectory(); 118 119 // Hold the File as the user object. 120 setUserObject(file); 121 122 } 123 124 // Override isLeaf to check whether this is a directory 125 @Override isLeaf()126 public boolean isLeaf() { 127 return !isDir; 128 } 129 130 // Override getAllowsChildren to check whether 131 // this is a directory 132 @Override getAllowsChildren()133 public boolean getAllowsChildren() { 134 return isDir; 135 } 136 137 // For display purposes, we return our own name public String toString() 138 // { return name; } 139 // If we are a directory, scan our contents and populate 140 // with children. In addition, populate those children 141 // if the "descend" flag is true. We only descend once, 142 // to avoid recursing the whole subtree. 143 // Returns true if some nodes were added populateDirectories(final boolean descend)144 boolean populateDirectories(final boolean descend) { 145 boolean addedNodes = false; 146 // Do this only once 147 if (!populated) { 148 if (interim) { 149 // We have had a quick look here before: 150 // remove the dummy node that we added last time 151 removeAllChildren(); 152 interim = false; 153 } 154 // Get list of contents 155 final String[] names = file.list(); 156 Arrays.sort(names); 157 158 // Process the directories 159 for (int i = 0; i < names.length; i++) { 160 final String nameTemp = names[i]; 161 try { 162 // if (d.isDirectory()) { 163 final FileTreeNode node = new FileTreeNode(file, nameTemp); 164 this.add(node); 165 if (descend) { 166 node.populateDirectories(false); 167 } 168 addedNodes = true; 169 if (!descend) { 170 // Only add one node if not descending 171 break; 172 } 173 // } 174 // else{ 175 176 // } 177 } catch (final Throwable t) { 178 // Ignore phantoms or access problems 179 } 180 } 181 182 // If we were scanning to get all subdirectories, 183 // or if we found no subdirectories, there is no 184 // reason to look at this directory again, so 185 // set populated to true. Otherwise, we set interim 186 // so that we look again in the future if we need to 187 if (descend || !addedNodes) { 188 populated = true; 189 } else { 190 // Just set interim state 191 interim = true; 192 } 193 } 194 return addedNodes; 195 } 196 197 198 } 199 200 // Inner class that handles Tree Expansion Events 201 protected static class TreeExpansionHandler implements TreeExpansionListener { 202 @Override treeExpanded(final TreeExpansionEvent evt)203 public void treeExpanded(final TreeExpansionEvent evt) { 204 // The expanded path 205 final TreePath path = evt.getPath(); 206 // The tree 207 final JTree tree = (JTree) evt.getSource(); 208 209 // Get the last component of the path and 210 // arrange to have it fully populated. 211 final FileTreeNode node = (FileTreeNode) path.getLastPathComponent(); 212 if (node.populateDirectories(true)) { 213 ((DefaultTreeModel) tree.getModel()).nodeStructureChanged(node); 214 } 215 } 216 217 @Override treeCollapsed(final TreeExpansionEvent evt)218 public void treeCollapsed(final TreeExpansionEvent evt) { 219 // Nothing to do 220 } 221 } 222 } 223