View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package org.xnap.gui.tree;
21  
22  import java.io.File;
23  import java.util.Arrays;
24  import java.util.Comparator;
25  import java.util.Hashtable;
26  import java.util.Vector;
27  
28  import javax.swing.event.TreeModelEvent;
29  
30  public class FileTreeModel extends AbstractTreeModel implements Comparator
31  {
32  
33      // --- Data Field(s)
34  
35      private Vector subRoots;
36      private Hashtable subChildren = new Hashtable();
37      private File cachedDir;
38      private boolean cacheSorted;
39      private File[] cache;
40      private boolean filterDotFiles = true;
41  
42      // --- Constructor(s) ---
43  
44      public FileTreeModel(String root, File[] roots)
45      {
46  		super(root);
47  
48  		if (roots != null) {
49  			subRoots = new Vector(roots.length);
50  			for (int i = 0; i < roots.length; i++) {
51  				addSubRoot(roots[i]);
52  			}
53  		}
54  		else {
55  			subRoots = new Vector();
56  		}
57      }
58  
59      public FileTreeModel(String root)
60      {
61          this(root, null);
62      }
63  
64      // --- Method(s)
65  
66      public int compare(Object o1, Object o2)
67      {
68  		return 
69  			o1.toString().toLowerCase().compareTo(o2.toString().toLowerCase());
70      }
71  
72      public boolean isLeaf(Object node)
73      {
74          return false;
75      }
76  
77      public int getChildCount(Object node)
78      {
79  		if (node instanceof File && ((File)node).canRead()) {
80  			return getSubDirs((File)node, false).length;
81  		} 
82  		else if (node instanceof String) {
83  			if (node.equals(root)) {
84  				return subRoots.size();
85  			}
86  			return ((Vector)subChildren.get(node)).size();
87  		}
88  		else {
89  			return 0;
90  		}
91      }
92      
93      public Object getChild(Object parent, int index)
94      {
95  		if (parent instanceof File) {
96  			File[] children = getSubDirs((File)parent, true);
97  
98  			if ((children == null) || (index >= children.length)) 
99  				return null;
100 			return new FileNode(children[index]);
101 		} 
102 		else if (parent instanceof String) {
103 			if (parent.equals(root) && index < subRoots.size())
104 				return subRoots.get(index);
105 	    
106 			Vector v = (Vector)subChildren.get(parent);
107 			if (index < v.size())
108 				return v.elementAt(index);
109 	    
110 			return null;
111 		}
112 		else {
113 			return null;
114 		}
115     }
116     
117     public int getIndexOfChild(Object parent, Object child)
118     {
119 		if (parent instanceof File) {
120 			File[] children = getSubDirs((File)parent, true);
121 
122 			if (children == null) 
123 				return -1;
124 
125 			for (int i = 0; i < children.length; i++) {
126 				if (children[i] == child)
127 					return i;
128 			}
129 		}
130 		else if (parent instanceof String) {
131 			if (parent.equals(root)) {
132 				return subRoots.indexOf(child);
133 			}
134 			return ((Vector)subChildren.get(parent)).indexOf(child);
135 		}
136 
137 		return -1; 
138     }
139 
140     private File[] getSubDirs(File f, boolean doSort)
141     {
142 		if (f == cachedDir && cacheSorted == doSort)
143 			return cache;
144 
145 		File[] children = f.listFiles(); 
146 		int count = 0;
147 		if (children != null) {
148 			for (int i = 0; i < children.length; i++) {
149 				if (children[i].isDirectory()) {
150 					if (filterDotFiles 
151 						&& children[i].getName().startsWith("."))
152 						continue;
153 
154 					children[count] = children[i];
155 					count++;
156 				}
157 			}
158 		}
159 
160 		cache = new File[count];
161 		if (count > 0) {
162 			System.arraycopy(children, 0, cache, 0, count);
163 
164 			if (doSort) {
165 				Arrays.sort(cache, this);
166 			}
167 		}
168 
169 		cachedDir = f;
170 		cacheSorted = doSort;
171 
172 		return cache;
173     }
174 
175     public void addSubRoot(String s)
176     {
177 		if (subRoots.contains(s))
178 			return;
179 	
180 		subRoots.add(s);
181 	
182 		/* add vector for children of this node */
183 		subChildren.put(s, new Vector());
184 
185 		Object[] path = { root };
186 		int[] indices = { subRoots.size() - 1 };
187 		Object[] children = { s };
188 		fireTreeNodesInserted(new TreeModelEvent(this, path, indices,
189 												 children));
190 	
191     }
192 
193     public void addSubRoot(File f)
194     {
195 		if (subRoots.contains(f))
196 			return;
197 	
198 		subRoots.add(f);
199 	
200 		Object[] path = { root };
201 		int[] indices = { subRoots.size() - 1 };
202 		Object[] children = { f };
203 		fireTreeNodesInserted(new TreeModelEvent(this, path, indices, 
204 												 children));
205     }
206 
207     public void removeSubRoots()
208     {
209 		/* remove respective vectors in hash tree */
210 		for (int i = 0; i < subRoots.size(); i++)
211 			subChildren.remove(subRoots.get(i));
212 	
213 		subRoots.clear();
214 	
215 		Object[] path = { root };
216 		fireTreeStructureChanged(new TreeModelEvent(this, path));
217     }
218     
219     public void removeChildrenOfSubRoot(String s)
220     {
221 		if (!subRoots.contains(s))
222 			return;
223 
224 		Vector v = (Vector)subChildren.get(s);
225 
226 		v.removeAllElements();
227 		
228 		Object[] path = { root, s };
229 		fireTreeStructureChanged(new TreeModelEvent(this, path));
230     }
231 
232     public void addChildOfSubRoot(File f, String s)
233     {
234 		addChildOfSubRoot(f, s, null);
235     }
236 
237     public void addChildOfSubRoot(File f, String s, String label)
238     {
239 		addSubRoot(s);
240 	
241 		Vector kids = (Vector) subChildren.get(s);
242 	
243 		FileNode node = new FileNode(f, true, label);
244 	
245 		if (kids.contains(node))
246 			return;
247 	
248 		kids.add(node);
249 		Object[] path = { root, s };
250 		int[] indices = { kids.size() - 1 };
251 		Object[] children = { f };
252 		fireTreeNodesInserted(new TreeModelEvent(this, path, indices,
253 												 children ));
254     }
255 
256     public void removeChildOfSubRoot(File f, String s)
257     {
258 		if (!subRoots.contains(s))
259 			return;
260 	    
261 		Vector kids = (Vector) subChildren.get(s);
262 	
263 		FileNode node = new FileNode(f, true);
264 
265 		int index = kids.indexOf(node);
266 
267 		if (index == -1)
268 			return;
269 	
270 		kids.remove(index);
271 
272 		Object[] path = { root, s };
273 		int[] indices = { index };
274 		Object[] children = { node };
275 		fireTreeNodesRemoved(new TreeModelEvent(this, path, indices,
276 												children));
277     }
278 }