1 package wjhk.jupload2.gui.filepanel.treeview; 2 3 import java.io.File; 4 import java.util.Date; 5 6 import javax.swing.table.TableModel; 7 import javax.swing.tree.TreePath; 8 9 import wjhk.jupload2.exception.JUploadExceptionStopAddingFiles; 10 import wjhk.jupload2.gui.filepanel.FilePanel; 11 import wjhk.jupload2.gui.filepanel.FilePanelFlatDataModel2; 12 import wjhk.jupload2.policies.UploadPolicy; 13 14 /** 15 * This code is taken from the tutorial written by Jörn Hameister, <A 16 * HREF="http://www.hameister.org/JavaSwingTreeTable.html">available here</A>.<BR/> 17 * <BR/> 18 * In the class MyDataModel the concrete data model view is defined. Ie, the columns are defined including data type. 19 * The class also contains the unimplemented methods of the interface TreeModel . It should be noted the method 20 * isCellEditable . This has the value true return so that the Listener on a treeExpanded or treeCollapsed can respond. 21 * One could in this method only for the first column ( column ) the value true and otherwise return the value false . 22 * 23 * @author Jörn Hameister 24 */ 25 public class FileDataTreeViewModel extends MyAbstractTreeTableModel<TreeFileDataNode> { 26 27 /** 28 * The uploadPolicy contains all current parameter, including the FileDataParam 29 */ 30 UploadPolicy uploadPolicy = null; 31 32 /** 33 * The column names, as displayed on the applet. They are not real final values, as they are translated: we need to 34 * have an uploadPolicy for this translation, and the uploadPolicy is 'given' to the constructor. 35 */ 36 final static String COL_NAME = "colName"; 37 38 final static String COL_SIZE = "colSize"; 39 40 final static String COL_DIRECTORY = "colDirectory"; 41 42 final static String COL_MODIFIED = "colModified"; 43 44 /** The localized column name, for the file name */ 45 String colName = null; 46 47 /** The localized column name, for the file size */ 48 String colSize = null; 49 50 /** The localized column name, for the file directory */ 51 String colDirectory = null; 52 53 /** The localized column name, for the file last modification date */ 54 String colModified = null; 55 56 String[] columnNames = null; 57 58 /** 59 * This array indicates, for each column, the percentage of the available width it should use. It's initialized in 60 * the constructor of this class. 61 * 62 * @see #getColumnSize(int) 63 */ 64 int[] columnSizePercentage = null; 65 66 /** 67 * Indicates whether each column is editable or not. Only the check box should be editable. 68 */ 69 boolean[] columnEditable = null; 70 71 Class<?> columnClasses[] = null; 72 73 public FileDataTreeViewModel(UploadPolicy uploadPolicy, FilePanelFlatDataModel2 flatModel) { 74 // The models are unknown now. They will be set later. 75 super(uploadPolicy, new RootNode(uploadPolicy, null, flatModel)); 76 77 this.uploadPolicy = uploadPolicy; 78 79 // Initialization for column name 80 colName = this.uploadPolicy.getLocalizedString(COL_NAME); 81 colSize = this.uploadPolicy.getLocalizedString(COL_SIZE); 82 colDirectory = this.uploadPolicy.getLocalizedString(COL_DIRECTORY); 83 colModified = this.uploadPolicy.getLocalizedString(COL_MODIFIED); 84 this.columnNames = new String[] { 85 colName, colSize, colDirectory, colModified, "" 86 }; 87 88 // Initial size (before percentage) was: 150, 75, 199, 130, 75 89 this.columnSizePercentage = new int[] { 90 50, 17, 15, 15, 3 91 }; 92 93 this.columnClasses = new Class[] { 94 MyTreeTableModel.class, Long.class, String.class, Date.class, Boolean.class 95 }; 96 97 // Initial size (before percentage) was: 150, 75, 199, 130, 75 98 this.columnEditable = new boolean[] { 99 true, false, false, false, true 100 }; 101 } 102 103 /** {@inheritDoc} */ 104 public int getColumnCount() { 105 return columnNames.length; 106 } 107 108 /** {@inheritDoc} */ 109 public String getColumnName(int column) { 110 return columnNames[column]; 111 } 112 113 /** {@inheritDoc} */ 114 public int getColumnSizePercentage(int col) { 115 return this.columnSizePercentage[col]; 116 } 117 118 /** {@inheritDoc} */ 119 public Class<?> getColumnClass(int column) { 120 return columnClasses[column]; 121 } 122 123 /** {@inheritDoc} */ 124 public Object getValueAt(TreeFileDataNode node, int column) { 125 if (node != null) { 126 String columnName = getColumnName(column); 127 // Don't know if it will be useful, but the switch below allows the 128 // column to be in any order. 129 if (columnName.equals(colName)) { 130 return node.getFileName(); 131 } else if (columnName.equals(colSize)) { 132 return Long.valueOf(node.getFileLength()); 133 } else if (columnName.equals(colDirectory)) { 134 return node.getDirectory(); 135 } else if (columnName.equals(colModified)) { 136 return node.getLastModified(); 137 } else if (columnName.equals("")) { 138 return node.getUploadFlag(); 139 } else { 140 this.uploadPolicy.displayErr("Unknown column in " + this.getClass().getName() + ": " + columnName); 141 return null; 142 } 143 } else { 144 return null; 145 } 146 } 147 148 /** @see TableModel#isCellEditable(int, int) */ 149 public boolean isCellEditable(TreeFileDataNode node, int column) { 150 return columnEditable[column]; 151 } 152 153 /** @see TableModel#setValueAt(Object, int, int) */ 154 public void setValueAt(Object aValue, TreeFileDataNode node, int col) { 155 if (!columnEditable[col]) { 156 this.uploadPolicy.displayWarn(this.getClass().getName() + ".setValueAt: no action"); 157 } else { 158 if (!(aValue instanceof Boolean)) { 159 this.uploadPolicy.displayErr("Internal error in " + this.getClass().getName() 160 + ": aValue should be a Boolean but is a " + aValue.getClass().getName()); 161 } else { 162 node.setUploadFlag((Boolean) aValue); 163 } 164 } 165 } 166 167 /** 168 * Returns the {@link TreePath} for the given {@link File}. This TreePath is basically the array of 169 * {@link TreeFileDataNode}, representing the given file. the root path if the filename for the {@link RootNode}, 170 * that is: the empty String: "" 171 * 172 * @param fileRoot The File we want the path for. It may be the root, a folder, leaf... 173 * @return The TreePath for this file, or null if this file doesn't exist in the existing hierarchy. public TreePath 174 * getTreePath(TreeFileDataNode fileData) { TreeFileDataNode parent = (TreeFileDataNode) 175 * fileData.getParent(); if (parent == null) { TreeFileDataNode[] path = (TreeFileDataNode[]) 176 * (Array.newInstance(TreeFileDataNode.class, 2)); path[0] = absoluteRoot; path[1] = ((FolderNode) 177 * absoluteRoot).getChild(fileData.getFileName()); return new TreePath(path); } else { TreePath 178 * treePathParent = getTreePath(parent); if (treePathParent == null) { // The parent is not in the file 179 * hierarchy, so this file is not either. return null; } else { FolderNode folderNodeParent = (FolderNode) 180 * treePathParent.getLastPathComponent(); TreeFileDataNode tfdn = 181 * folderNodeParent.getChild(fileData.getFileName()); if (tfdn == null) { // This file doesn't exist in the 182 * hierarchy. return null; } else { return treePathParent.pathByAddingChild(tfdn); } } } } 183 */ 184 185 /** 186 * Returns the {@link TreePath} for the given {@link File}. This TreePath is basically the array of 187 * {@link TreeFileDataNode}, representing the given file. the root path if the filename for the {@link RootNode}, 188 * that is: the empty String: "" 189 * 190 * @param fileRoot The File we want the path for. It may be the root, a folder, leaf... If the given file is null, 191 * the returned {@link TreePath} is a one level {@link TreePath}, containing only the absolute root of 192 * the tree view. 193 * @param createIntermediateNode If true, all missing intermediate nodes are created. If false, no node are created. 194 * In this last case, the returned {@link TreePath} is null, if one or mode nodes are missing. 195 * @return The TreePath for this file, or null if this file doesn't exist in the existing hierarchy. 196 * @throws JUploadExceptionStopAddingFiles 197 */ 198 public TreePath getTreePathFromFile(File file, boolean createIntermediateNode) 199 throws JUploadExceptionStopAddingFiles { 200 if (this.uploadPolicy.getFileListViewMode() != FilePanel.FileListViewMode.FLAT 201 && this.uploadPolicy.getFileListViewMode() != FilePanel.FileListViewMode.TREE_VIEW) { 202 throw new IllegalStateException(this.getClass().getName() 203 + ".getTreePathFromFile(File) may not be called when the ListViewMode is in " 204 + this.uploadPolicy.getFileListViewMode() + " mode"); 205 } 206 if (file == null) { 207 return new TreePath(absoluteRoot); 208 } else { 209 TreePath parentTreePath = getTreePathFromFile(file.getParentFile(), createIntermediateNode); 210 if (parentTreePath == null) { 211 // At least one node is missing. We can't build the TreePath 212 return null; 213 } else { 214 // The parent TreePath should finish by a folder ... as it's our parent ! 215 FolderNode parentNode = (FolderNode) parentTreePath.getLastPathComponent(); 216 TreeFileDataNode node = parentNode.getChild(file); 217 218 // If file is not a child of the node for the parent file, we may have to create a new Node. 219 if (node == null && createIntermediateNode) { 220 node = parentNode.addChild(file); 221 } 222 223 // If there is no node for our file ... there is no valid TreePath 224 if (node == null) { 225 return null; 226 } else { 227 return parentTreePath.pathByAddingChild(node); 228 } 229 }/* 230 * File parent = file.getParentFile(); if (parent == null) { TreeFileDataNode[] path = (TreeFileDataNode[]) 231 * (Array.newInstance(TreeFileDataNode.class, 2)); path[0] = absoluteRoot; path[1] = ((FolderNode) 232 * absoluteRoot).getChild(file); // if the root doesn't return new TreePath(path); } else { TreePath 233 * treePathParent = getTreePathFromFile(parent, createIntermediateNode); if (treePathParent == null) { // 234 * The parent is not in the file hierarchy, so this file is not either. return null; } else { FolderNode 235 * folderNodeParent = (FolderNode) treePathParent.getLastPathComponent(); TreeFileDataNode tfdn = 236 * folderNodeParent.getChild(file); if (tfdn == null) { // This file doesn't exist in the hierarchy. return 237 * null; } else { return treePathParent.pathByAddingChild(tfdn); } } } 238 */ 239 }// if (file == null) 240 } 241 242 /** 243 * Returns the node corresponding to the given treePath, or null if this node is'nt found, when crawling the 244 * hierarchy behind {@link #absoluteRoot}. 245 * 246 * @param treePath A {@link TreePath} made of String. If it's made of String, each represents a filename. If it's a 247 * {@link TreePath} made of TreeFileDataNode, this method works, but it's much quicker to just use 248 * {@link TreePath#getLastPathComponent()} instead of this method. 249 * @return TreeFileDataNode getNode(TreePath treePath) { TreePath parent = treePath.getParentPath(); if (parent == 250 * null) { return absoluteRoot; } else { TreeFileDataNode parentNode = getNode(parent); return 251 * (TreeFileDataNode) parentNode.getChild((String) treePath.getLastPathComponent()); } } 252 */ 253 254 /** 255 * This method returns 256 * 257 * @param file 258 * @return 259 * @throws JUploadExceptionStopAddingFiles public FolderNode getFolderNodeForNewFile(File file) throws 260 * JUploadExceptionStopAddingFiles { return getFolderNodeForNewFile(file.getParentFile(), null); } 261 */ 262 263 /** 264 * This method searches in the hierarchy of files and folder to upload, the node which contains this file. If this 265 * node doesn't exist, it is first created and attached into the hierarchy. 266 * 267 * @param o A File or Folder. If o is a file, it will just be added. If o is a folder, it will be added, including 268 * all its content (child, grand-child...) 269 * @return The number of files added to the hierarchy. Folders are not counted. 270 * @throws JUploadExceptionStopAddingFiles When an exception occurs 271 * @throws NullPointerException When o is null 272 * @throws IllegalArgumentException When o is not a {@link File} 273 * @see MyAbstractTreeTableModel 274 */ 275 public int attachObject(Object o) throws NullPointerException, IllegalArgumentException, 276 JUploadExceptionStopAddingFiles { 277 if (o == null) { 278 throw new NullPointerException(this.getClass().getName() + " has been called with a null parameter"); 279 } else if (!(o instanceof File)) { 280 throw new IllegalArgumentException(this.getClass().getName() + " has been called with a " 281 + o.getClass().getName() + ". It must be a File"); 282 } 283 File file = (File) o; 284 285 FolderNode parentNode = null; 286 switch (uploadPolicy.getFileListViewMode()) { 287 case FLAT: 288 case TREE_VIEW: 289 // We're mapped to the file system, we need to find the parent for this file. 290 if (file.getParentFile() != null) { 291 parentNode = (FolderNode) getTreePathFromFile(file.getParentFile(), true).getLastPathComponent(); 292 } else { 293 parentNode = (FolderNode) absoluteRoot; 294 } 295 break; 296 case INDEPENDENT_TREE_VIEW: 297 // Otherwise, it's just a new child of the root. 298 parentNode = (FolderNode) absoluteRoot; 299 } 300 301 if (parentNode == null) { 302 throw new IllegalArgumentException("Root not found for file " + file.getAbsolutePath()); 303 } 304 305 return parentNode.addChildAndDescendants(file); 306 } 307 308 /** {@inheritDoc} */ 309 public TreePath getTreePathForObject(Object o) { 310 if (o != null && !(o instanceof File)) { 311 throw new IllegalArgumentException(this.getClass().getName() + " has been called with a " 312 + o.getClass().getName() + ". It must be a File"); 313 } 314 try { 315 return getTreePathFromFile((File) o, false); 316 } catch (JUploadExceptionStopAddingFiles e) { 317 throw new IllegalStateException(e.getMessage(), e); 318 } 319 } 320 321 }