001/* 002 * $Id: FileSystemModel.java 3927 2011-02-22 16:34:11Z 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 022package org.jdesktop.swingx.treetable; 023 024import java.io.File; 025import java.util.Arrays; 026import 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 */ 048public 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 @Override 090 public File getChild(Object parent, int index) { 091 if (!isValidFileNode(parent)) { 092 throw new IllegalArgumentException("parent is not a file governed by this model"); 093 } 094 095 File parentFile = (File) parent; 096 String[] children = parentFile.list(); 097 098 if (children != null) { 099 return new File(parentFile, children[index]); 100 } 101 102 return null; 103 } 104 105 /** 106 * {@inheritDoc} 107 */ 108 @Override 109 public int getChildCount(Object parent) { 110 if (parent instanceof File) { 111 String[] children = ((File) parent).list(); 112 113 if (children != null) { 114 return children.length; 115 } 116 } 117 118 return 0; 119 } 120 121 /** 122 * {@inheritDoc} 123 */ 124 @Override 125 public Class<?> getColumnClass(int column) { 126 switch (column) { 127 case 0: 128 return String.class; 129 case 1: 130 return Long.class; 131 case 2: 132 return Boolean.class; 133 case 3: 134 return Date.class; 135 default: 136 return super.getColumnClass(column); 137 } 138 } 139 140 @Override 141 public int getColumnCount() { 142 return 4; 143 } 144 145 @Override 146 public String getColumnName(int column) { 147 switch (column) { 148 case 0: 149 return "Name"; 150 case 1: 151 return "Size"; 152 case 2: 153 return "Directory"; 154 case 3: 155 return "Modification Date"; 156 default: 157 return super.getColumnName(column); 158 } 159 } 160 161 @Override 162 public Object getValueAt(Object node, int column) { 163 if (node instanceof File) { 164 File file = (File) node; 165 switch (column) { 166 case 0: 167 return file.getName(); 168 case 1: 169 return isLeaf(node) ? file.length() : DIRECTORY; 170 case 2: 171 return file.isDirectory(); 172 case 3: 173 return new Date(file.lastModified()); 174 } 175 } 176 177 return null; 178 } 179 180 /** 181 * {@inheritDoc} 182 */ 183 @Override 184 public int getIndexOfChild(Object parent, Object child) { 185 if (parent instanceof File && child instanceof File) { 186 File parentFile = (File) parent; 187 File[] files = parentFile.listFiles(); 188 189 Arrays.sort(files); 190 191 for (int i = 0, len = files.length; i < len; i++) { 192 if (files[i].equals(child)) { 193 return i; 194 } 195 } 196 } 197 198 return -1; 199 } 200 201 /** 202 * {@inheritDoc} 203 */ 204 @Override 205 public File getRoot() { 206 return (File) root; 207 } 208 209 /** 210 * Sets the root for this tree table model. This method will notify 211 * listeners that a change has taken place. 212 * 213 * @param root 214 * the new root node to set 215 */ 216 public void setRoot(File root) { 217 this.root = root; 218 219 modelSupport.fireNewRoot(); 220 } 221 222 /** 223 * {@inheritDoc} 224 */ 225 @Override 226 public boolean isLeaf(Object node) { 227 if (node instanceof File) { 228 //do not use isFile(); some system files return false 229 return ((File) node).list() == null; 230 } 231 232 return true; 233 } 234}