001 /*
002 * $Id: FileSystemModel.java 2713 2008-02-15 15:08:23Z kleopatra $
003 *
004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020 */
021
022 package org.jdesktop.swingx.treetable;
023
024 import java.io.File;
025 import java.util.Arrays;
026 import java.util.Date;
027
028 /**
029 * A tree table model to simulate a file system.
030 * <p>
031 * This tree table model implementation extends {@code AbstractTreeTableModel}.
032 * The file system metaphor demonstrates that it is often easier to directly
033 * implement tree structures directly instead of using intermediaries, such as
034 * {@code TreeTableNode}.
035 * <p>
036 * A comparison of this class with {@code SimpleFileSystemModel}, shows that
037 * extending {@code AbstractTreeTableModel} is often easier than creating a model
038 * from scratch.
039 * <p>
040 * A "full" version of this model might allow editing of file names, the
041 * deletion of files, and the movement of files. This simple implementation does
042 * not intend to tackle such problems, but this implementation may be extended
043 * to handle such details.
044 *
045 * @author Ramesh Gupta
046 * @author Karl Schaefer
047 */
048 public class FileSystemModel extends AbstractTreeTableModel {
049 // The the returned file length for directories.
050 private static final Long DIRECTORY = 0L;
051
052 /**
053 * Creates a file system model using the root directory as the model root.
054 */
055 public FileSystemModel() {
056 this(new File(File.separator));
057 }
058
059 /**
060 * Creates a file system model using the specified {@code root}.
061 *
062 * @param root
063 * the root for this model; this may be different than the root
064 * directory for a file system.
065 */
066 public FileSystemModel(File root) {
067 super(root);
068 }
069
070 private boolean isValidFileNode(Object file) {
071 boolean result = false;
072
073 if (file instanceof File) {
074 File f = (File) file;
075
076 while (!result && f != null) {
077 result = f.equals(root);
078
079 f = f.getParentFile();
080 }
081 }
082
083 return result;
084 }
085
086 /**
087 * {@inheritDoc}
088 */
089 public File getChild(Object parent, int index) {
090 if (!isValidFileNode(parent)) {
091 throw new IllegalArgumentException("parent is not a file governed by this model");
092 }
093
094 File parentFile = (File) parent;
095 String[] children = parentFile.list();
096
097 if (children != null) {
098 return new File(parentFile, children[index]);
099 }
100
101 return null;
102 }
103
104 /**
105 * {@inheritDoc}
106 */
107 public int getChildCount(Object parent) {
108 if (parent instanceof File) {
109 String[] children = ((File) parent).list();
110
111 if (children != null) {
112 return children.length;
113 }
114 }
115
116 return 0;
117 }
118
119 /**
120 * {@inheritDoc}
121 */
122 @Override
123 public Class<?> getColumnClass(int column) {
124 switch (column) {
125 case 0:
126 return String.class;
127 case 1:
128 return Long.class;
129 case 2:
130 return Boolean.class;
131 case 3:
132 return Date.class;
133 default:
134 return super.getColumnClass(column);
135 }
136 }
137
138 public int getColumnCount() {
139 return 4;
140 }
141
142 @Override
143 public String getColumnName(int column) {
144 switch (column) {
145 case 0:
146 return "Name";
147 case 1:
148 return "Size";
149 case 2:
150 return "Directory";
151 case 3:
152 return "Modification Date";
153 default:
154 return super.getColumnName(column);
155 }
156 }
157
158 public Object getValueAt(Object node, int column) {
159 if (node instanceof File) {
160 File file = (File) node;
161 switch (column) {
162 case 0:
163 return file.getName();
164 case 1:
165 return isLeaf(node) ? file.length() : DIRECTORY;
166 case 2:
167 return file.isDirectory();
168 case 3:
169 return new Date(file.lastModified());
170 }
171 }
172
173 return null;
174 }
175
176 /**
177 * {@inheritDoc}
178 */
179 public int getIndexOfChild(Object parent, Object child) {
180 if (parent instanceof File && child instanceof File) {
181 File parentFile = (File) parent;
182 File[] files = parentFile.listFiles();
183
184 Arrays.sort(files);
185
186 for (int i = 0, len = files.length; i < len; i++) {
187 if (files[i].equals(child)) {
188 return i;
189 }
190 }
191 }
192
193 return -1;
194 }
195
196 /**
197 * {@inheritDoc}
198 */
199 @Override
200 public File getRoot() {
201 return (File) root;
202 }
203
204 /**
205 * Sets the root for this tree table model. This method will notify
206 * listeners that a change has taken place.
207 *
208 * @param root
209 * the new root node to set
210 */
211 public void setRoot(File root) {
212 this.root = root;
213
214 modelSupport.fireNewRoot();
215 }
216
217 /**
218 * {@inheritDoc}
219 */
220 @Override
221 public boolean isLeaf(Object node) {
222 if (node instanceof File) {
223 //do not use isFile(); some system files return false
224 return ((File) node).list() == null;
225 }
226
227 return true;
228 }
229 }