📄 filesystemmodel2.java
字号:
import java.io.IOException;import java.io.File;import java.util.Date;import java.util.Stack;import javax.swing.SwingUtilities;import javax.swing.tree.TreePath;public class FileSystemModel2 extends AbstractTreeTableModel { // Names of the columns. static protected String[] cNames = { "Name", "Size", "Type", "Modified" }; // Types of the columns. static protected Class[] cTypes = { TreeTableModel.class, Integer.class, String.class, Date.class }; // The the returned file length for directories. public static final Integer ZERO = new Integer(0); /** An array of MergeSorter sorters, that will sort based on size. */ static Stack sorters = new Stack(); /** * True if the receiver is valid, once set to false all Threads loading * files will stop. */ protected boolean isValid; /** * Node currently being reloaded, this becomes somewhat muddy if reloading * is happening in multiple threads. */ protected FileNode reloadNode; /** > 0 indicates reloading some nodes. */ int reloadCount; /** Returns true if links are to be descended. */ protected boolean descendLinks; /** * Returns a MergeSort that can sort on the totalSize of a FileNode. */ protected static MergeSort getSizeSorter() { synchronized (sorters) { if (sorters.size() == 0) { return new SizeSorter(); } return (MergeSort) sorters.pop(); } } /** * Should be invoked when a MergeSort is no longer needed. */ protected static void recycleSorter(MergeSort sorter) { synchronized (sorters) { sorters.push(sorter); } } public FileSystemModel2() { this(File.separator); } public FileSystemModel2(String rootPath) { super(null); isValid = true; root = new FileNode(new File(rootPath)); } public int getChildCount(Object node) { Object[] children = getChildren(node); return (children == null) ? 0 : children.length; } public Object getChild(Object node, int i) { return getChildren(node)[i]; } public boolean isLeaf(Object node) { return ((FileNode) node).isLeaf(); } public int getColumnCount() { return cNames.length; } public String getColumnName(int column) { return cNames[column]; } public Class getColumnClass(int column) { return cTypes[column]; } public Object getValueAt(Object node, int column) { FileNode fn = (FileNode) node; try { switch (column) { case 0: return fn.getFile().getName(); case 1: if (fn.isTotalSizeValid()) { return new Integer((int) ((FileNode) node).totalSize()); } return null; case 2: return fn.isLeaf() ? "File" : "Directory"; case 3: return fn.lastModified(); } } catch (SecurityException se) { } return null; } public void reloadChildren(Object node) { FileNode fn = (FileNode) node; synchronized (this) { reloadCount++; } fn.resetSize(); new Thread(new FileNodeLoader((FileNode) node)).start(); } public void stopLoading() { isValid = false; synchronized (this) { while (reloadCount > 0) { try { wait(); } catch (InterruptedException ie) { } } } isValid = true; } public void setDescendsLinks(boolean newValue) { descendLinks = newValue; } public boolean getDescendsLinks() { return descendLinks; } public String getPath(Object node) { return ((FileNode) node).getFile().getPath(); } public long getTotalSize(Object node) { return ((FileNode) node).totalSize(); } public boolean isReloading() { return (reloadCount > 0); } public TreePath getPathLoading() { FileNode rn = reloadNode; if (rn != null) { return new TreePath(rn.getPath()); } return null; } public Object getNodeLoading() { return reloadNode; } protected File getFile(Object node) { FileNode fileNode = ((FileNode) node); return fileNode.getFile(); } protected Object[] getChildren(Object node) { FileNode fileNode = ((FileNode) node); return fileNode.getChildren(); } protected static FileNode[] EMPTY_CHILDREN = new FileNode[0]; static private MergeSort fileMS = new MergeSort() { public int compareElementsAt(int beginLoc, int endLoc) { return ((String) toSort[beginLoc]) .compareTo((String) toSort[endLoc]); } }; class FileNode { /** java.io.File the receiver represents. */ protected File file; /** Parent FileNode of the receiver. */ private FileNode parent; /** Children of the receiver. */ protected FileNode[] children; /** Size of the receiver and all its children. */ protected long totalSize; /** Valid if the totalSize has finished being calced. */ protected boolean totalSizeValid; /** Path of the receiver. */ protected String canonicalPath; /** * True if the canonicalPath of this instance does not start with the * canonical path of the parent. */ protected boolean isLink; /** Date last modified. */ protected Date lastModified; protected FileNode(File file) { this(null, file); } protected FileNode(FileNode parent, File file) { this.parent = parent; this.file = file; try { canonicalPath = file.getCanonicalPath(); } catch (IOException ioe) { canonicalPath = ""; } if (parent != null) { isLink = !canonicalPath.startsWith(parent.getCanonicalPath()); } else { isLink = false; } if (isLeaf()) { totalSize = file.length(); totalSizeValid = true; } } /** * Returns the date the receiver was last modified. */ public Date lastModified() { if (lastModified == null && file != null) { lastModified = new Date(file.lastModified()); } return lastModified; } /** * Returns the the string to be used to display this leaf in the JTree. */ public String toString() { return file.getName(); } /** * Returns the java.io.File the receiver represents. */ public File getFile() { return file; } /** * Returns size of the receiver and all its children. */ public long totalSize() { return totalSize; } /** * Returns the parent of the receiver. */ public FileNode getParent() { return parent; } /** * Returns true if the receiver represents a leaf, that is it is isn't a * directory. */ public boolean isLeaf() { return file.isFile(); } /** * Returns true if the total size is valid. */ public boolean isTotalSizeValid() { return totalSizeValid; } /** * Clears the date. */ protected void resetLastModified() { lastModified = null; } /** * Sets the size of the receiver to be 0. */ protected void resetSize() { alterTotalSize(-totalSize); } /** * Loads the children, caching the results in the children instance * variable. */ protected FileNode[] getChildren() { return children; } /** * Recursively loads all the children of the receiver. */ protected void loadChildren(MergeSort sorter) { totalSize = file.length(); children = createChildren(null); for (int counter = children.length - 1; counter >= 0; counter--) { Thread.yield(); // Give the GUI CPU time to draw itself. if (!children[counter].isLeaf() && (descendLinks || !children[counter].isLink())) { children[counter].loadChildren(sorter); } totalSize += children[counter].totalSize(); if (!isValid) { counter = 0; } } if (isValid) { if (sorter != null) { sorter.sort(children); } totalSizeValid = true; } } /** * Loads the children of of the receiver. */ protected FileNode[] createChildren(MergeSort sorter) { FileNode[] retArray = null; try { String[] files = file.list(); if (files != null) { if (sorter != null) { sorter.sort(files); } retArray = new FileNode[files.length]; String path = file.getPath(); for (int i = 0; i < files.length; i++) { File childFile = new File(path, files[i]); retArray[i] = new FileNode(this, childFile); } } } catch (SecurityException se) { } if (retArray == null) { retArray = EMPTY_CHILDREN; } return retArray; } /** * Returns true if the children have been loaded. */ protected boolean loadedChildren() { return (file.isFile() || (children != null)); } /** * Gets the path from the root to the receiver. */ public FileNode[] getPath() { return getPathToRoot(this, 0); } /** * Returns the canonical path for the receiver. */ public String getCanonicalPath() { return canonicalPath; } /** * Returns true if the receiver's path does not begin with the parent's * canonical path. */ public boolean isLink() { return isLink; } protected FileNode[] getPathToRoot(FileNode aNode, int depth) { FileNode[] retNodes; if (aNode == null) { if (depth == 0) return null; else retNodes = new FileNode[depth]; } else { depth++; retNodes = getPathToRoot(aNode.getParent(), depth); retNodes[retNodes.length - depth] = aNode; } return retNodes; } /** * Sets the children of the receiver, updates the total size, and if * generateEvent is true a tree structure changed event is created. */ protected void setChildren(FileNode[] newChildren, boolean generateEvent) { long oldSize = totalSize; totalSize = file.length(); children = newChildren; for (int counter = children.length - 1; counter >= 0; counter--) { totalSize += children[counter].totalSize(); } if (generateEvent) { FileNode[] path = getPath(); fireTreeStructureChanged(FileSystemModel2.this, path, null, null); FileNode parent = getParent(); if (parent != null) { parent.alterTotalSize(totalSize - oldSize); } } } protected synchronized void alterTotalSize(long sizeDelta) { if (sizeDelta != 0 && (parent = getParent()) != null) { totalSize += sizeDelta; nodeChanged(); parent.alterTotalSize(sizeDelta); } else { // Need a way to specify the root. totalSize += sizeDelta; } } /** * This should only be invoked on the event dispatching thread. */ protected synchronized void setTotalSizeValid(boolean newValue) { if (totalSizeValid != newValue) { nodeChanged(); totalSizeValid = newValue; FileNode parent = getParent(); if (parent != null) { parent.childTotalSizeChanged(this); } } } /** * Marks the receivers total size as valid, but does not invoke node * changed, nor message the parent. */ protected synchronized void forceTotalSizeValid() { totalSizeValid = true; } /** * Invoked when a childs total size has changed. */ protected synchronized void childTotalSizeChanged(FileNode child) { if (totalSizeValid != child.isTotalSizeValid()) { if (totalSizeValid) { setTotalSizeValid(false); } else { FileNode[] children = getChildren(); for (int counter = children.length - 1; counter >= 0; counter--) { if (!children[counter].isTotalSizeValid()) { return; } } setTotalSizeValid(true); } } } /** * Can be invoked when a node has changed, will create the appropriate * event. */ protected void nodeChanged() { FileNode parent = getParent(); if (parent != null) { FileNode[] path = parent.getPath(); int[] index = { getIndexOfChild(parent, this) }; Object[] children = { this }; fireTreeNodesChanged(FileSystemModel2.this, path, index, children); } } } class FileNodeLoader implements Runnable { /** Node creating children for. */ FileNode node; /** Sorter. */ MergeSort sizeMS; FileNodeLoader(FileNode node) { this.node = node; node.resetLastModified(); node.setChildren(node.createChildren(fileMS), true); node.setTotalSizeValid(false); } public void run() { FileNode[] children = node.getChildren(); sizeMS = getSizeSorter(); for (int counter = children.length - 1; counter >= 0; counter--) { if (!children[counter].isLeaf()) { reloadNode = children[counter]; loadChildren(children[counter]); reloadNode = null; } if (!isValid) { counter = 0; } } recycleSorter(sizeMS); if (isValid) { SwingUtilities.invokeLater(new Runnable() { public void run() { MergeSort sorter = getSizeSorter(); sorter.sort(node.getChildren()); recycleSorter(sorter); node.setChildren(node.getChildren(), true); synchronized (FileSystemModel2.this) { reloadCount--; FileSystemModel2.this.notifyAll(); } } }); } else { synchronized (FileSystemModel2.this) { reloadCount--; FileSystemModel2.this.notifyAll(); } } } protected void loadChildren(FileNode node) { if (!node.isLeaf() && (descendLinks || !node.isLink())) { final FileNode[] children = node.createChildren(null); for (int counter = children.length - 1; counter >= 0; counter--) { if (!children[counter].isLeaf()) { if (descendLinks || !children[counter].isLink()) { children[counter].loadChildren(sizeMS); } else { children[counter].forceTotalSizeValid(); } } if (!isValid) { counter = 0; } } if (isValid) { final FileNode fn = node; // Reset the children SwingUtilities.invokeLater(new Runnable() { public void run() { MergeSort sorter = getSizeSorter(); sorter.sort(children); recycleSorter(sorter); fn.setChildren(children, true); fn.setTotalSizeValid(true); fn.nodeChanged(); } }); } } else { node.forceTotalSizeValid(); } } } static class SizeSorter extends MergeSort { public int compareElementsAt(int beginLoc, int endLoc) { long firstSize = ((FileNode) toSort[beginLoc]).totalSize(); long secondSize = ((FileNode) toSort[endLoc]).totalSize(); if (firstSize != secondSize) { return (int) (secondSize - firstSize); } return ((FileNode) toSort[beginLoc]).toString().compareTo( ((FileNode) toSort[endLoc]).toString()); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -