⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 filesystemtree.java

📁 具有不同语法高亮的编辑器实例
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * 02/11/2005
 *
 * FileSystemTree.java - A JTree containing all files in the local host's
 *                      file system.
 * Copyright (C) 2005 Robert Futrell
 * email@address.com
 * www.website.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.fife.ui.rtextfilechooser;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ResourceBundle;
import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.*;

import org.fife.ui.ToolTipTree;


/**
 * A tree containing all files in the local host's file system.  So that you
 * can create components that contain a <code>FileSystemTree</code>, the
 * following property change events are fired when the tree is manipulated:
 *
 * <ul>
 *   <li><code>WILL_EXPAND_PROPERTY</code> - When the tree is about to
 *       expand one of its nodes.  Upon receiving this property change event,
 *       you could set the cursor to the system wait cursor, for example (as
 *       the expansion could take some time; Java seems to have some trouble
 *       calling <code>File.isDirectory()</code> on network files...).</li>
 *   <li><code>EXPANDED_PROPERTY</code> - When the tree has completed
 *       expanding the node.  Upon receiving this property change event, you
 *       could set the cursor back to the default.</li>
 * </ul>
 *
 * @author Robert Futrell
 * @version 0.8
 */
public class FileSystemTree extends ToolTipTree {

	/**
	 * 
	 */
	private static final long serialVersionUID = -7841970085397169435L;

	public static final String EXPANDED_PROPERTY		= "FileSystemTree.treeExpanded";
	public static final String WILL_EXPAND_PROPERTY	= "FileSystemTree.treeWillExpand";

	private static final String DUMMY_FILE_NAME		= "dummy";
	private static final File   DUMMY_FILE			= new File(DUMMY_FILE_NAME);
	private static final String EMPTY				= "";

	private DefaultTreeModel treeModel;
	private FileSystemTreeNode root;
	private HashMap rootNameCache;				// Cache of root names.
	private FileSystemView fileSystemView;
	protected FileChooserIconManager iconManager;
	private JPopupMenu popup;
	private FileSystemTreeRenderer cellRenderer;

	private static final String BUNDLE_NAME =
						"org.fife.ui.rtextfilechooser.FileSystemTree";


/*****************************************************************************/


	/**
	 * Constructor.
	 */
	public FileSystemTree() {

		super();

		// Initialize variables.
		fileSystemView = FileSystemView.getFileSystemView();
		iconManager = new FileChooserIconManager();
		rootNameCache = new HashMap();

		// Add all of our "root" nodes.
		root = new FileSystemTreeNode();
		for (Iterator i=RootManager.getInstance().iterator(); i.hasNext(); ) {
			File aRoot = (File)i.next();
			// Hack - We "know" all roots are directories, so why query
			// via isDirectory()?  This is a nice performance boost.
			root.add(createTreeNodeForImpl(aRoot, true));
			addCachedRootName(aRoot);
		}

		// Make it so they can only select one node at a time.
		getSelectionModel().setSelectionMode(
							TreeSelectionModel.SINGLE_TREE_SELECTION);

		// Set the root.  Note that this must come BEFORE we
		// set the cell renderer (below), otherwise, each tree node's
		// width will initially be incorrect (fixed when the node is
		// expanded/collapsed).
		treeModel = new DefaultTreeModel(root);
		setModel(treeModel);

		cellRenderer = new FileSystemTreeRenderer();
		setCellRenderer(cellRenderer);

		// Make everything look nice.
		enableEvents(AWTEvent.MOUSE_EVENT_MASK);
		setShowsRootHandles(true);
		setRootVisible(false);

	}


/*****************************************************************************/


	/**
	 * Adds a file name to the cached names (for roots).  We cache root
	 * directories' names because FileSystemView.getSystemDisplayName() can
	 * be costly, especially for disk drives on Windows (like A:\).
	 */
	private void addCachedRootName(File aRoot) {
		// Check separator character as a quick "hack" to check for Windows.
		// We don't call getName() for drives because for some reason it can
		// take a long time to get the name if it has one (such as A:\ and
		// C:\).
		if (File.separatorChar=='\\') {
			String absolutePath = aRoot.getAbsolutePath();
			if (absolutePath.length()==3 &&
					absolutePath.endsWith(":\\")) {
				rootNameCache.put(aRoot, absolutePath);
				return;
			}
		}
		rootNameCache.put(aRoot, getName(aRoot));
	}


/*****************************************************************************/


	/**
	 * Creates the popup menu for this file system tree.  Subclasses can
	 * override this method if they wish to add more menu items to the
	 * popup menu.
	 *
	 * @return The popup menu for this file system tree.
	 * @see #displayPopupMenu
	 */
	protected JPopupMenu createPopupMenu() {
		JPopupMenu popup = new JPopupMenu();
		ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME);
		Action a = new RefreshAction(bundle);
		JMenuItem item = new JMenuItem(a);
		popup.add(item);
		return popup;
	}


/*****************************************************************************/


	/**
	 * Creates a tree node for the specified file.
	 *
	 * @param file The file for which to create a tree node.
	 * @return The tree node for the file.
	 */
	private FileSystemTreeNode createTreeNodeFor(File file) {
		return createTreeNodeForImpl(file, file.isDirectory());
	}


/*****************************************************************************/


	/**
	 * Creates a tree node for the specified file.  This version of the method
	 * is for when you know ahead of time whether the file is a directory
	 * such as when the file is a "root").  This greatly speeds things up,
	 * as isDirectory() is notoriously slow.
	 *
	 * @param file The file for which to create a tree node.
	 * @param directory Whether the specified file is a directory.
	 * @return The tree node for the file.
	 */
	private FileSystemTreeNode createTreeNodeForImpl(File file,
											boolean directory) {

		// The node for the file.
		FileSystemTreeNode dmtn = new FileSystemTreeNode(file);

		// Make it have a "+/-" icon beside it if this node represents a
		// directory containing files.
		if (directory) {
			// NOTE:  We're just putting in a dummy file no matter what
			// for performance, as any kind of File querying methods in
			// Java degrade performance.
			//File[] files = fileSystemView.getFiles(file, false);
			//if (files!=null && files.length>0)
				dmtn.add(new FileSystemTreeNode(DUMMY_FILE));
		}

		return dmtn;

	}


/*****************************************************************************/


	/**
	 * Displays the popup menu at the specified location.
	 *
	 * @param p The location at which to display the popup.
	 * @see #createPopupMenu
	 */
	protected synchronized void displayPopupMenu(Point p) {

		// Create the popup menu if necessary.
		if (popup==null)
			popup = createPopupMenu();

		// Only have the "Refresh" menu item enabled if a directory
		// item is selected.
		boolean enableRefreshItem = false;
		TreePath path = getSelectionPath();
		if (path!=null) {
			FileSystemTreeNode node = (FileSystemTreeNode)path.
									getLastPathComponent();
			if (node!=null) {
				File file = node.getFile();
				if (file.isDirectory())
					enableRefreshItem = true;
			}
		}
		// NOTE:  We assume refresh item is first in menu...
		popup.getComponent(0).setEnabled(enableRefreshItem);

		// And display it!
		popup.show(this, p.x, p.y);

	}


/*****************************************************************************/


	/**
	 * Does any filtering and sorting of an array of files so that they will
	 * be displayed properly.  For example this method sorts the array so
	 * that directories are all listed before regular files.  Subclasses can
	 * override this method to do other things, such as only display
	 * directories.
	 *
	 * @param files The array of files to filter and sort.
	 * @return The filtered and sorted array of files.
	 */
	protected File[] filterAndSort(File[] files) {

		int num = files.length;
		ArrayList dirList = new ArrayList();
		ArrayList fileList = new ArrayList();

		// First, separate the directories from regular files so we can
		// sort them individually.  This part could be made more compact,
		// but it isn't just for a tad more speed.
		for (int i=0; i<num; i++) {
			if (files[i].isDirectory())
				dirList.add(files[i]);
			else
				fileList.add(files[i]);
		}

		Collections.sort(fileList);
		Collections.sort(dirList);
		dirList.addAll(fileList);

		File[] fileArray = new File[dirList.size()];
		return (File[])dirList.toArray(fileArray);

	}


/*****************************************************************************/


	/**
	 * Called when a node has expanded.
	 */
	public void fireTreeExpanded(TreePath e) {

		super.fireTreeExpanded(e);

		// We fire a property change at the beginning and end of a node
		// expanding so that anyone interested only has to register a
		// PropertyChangeLister to know when nodes are expanding (so they can
		// display a wait cursor, for example).  Otherwise, they'd have to add
		// both a TreeExpansionListener and a TreeWillExpandListener.  Cheap,
		// I know, but oh well.
		firePropertyChange(EXPANDED_PROPERTY, null, null);

	}


/*****************************************************************************/


	/**
	 * Called when a node is about to be expanded.  This method is overridden
	 * so that the node that is being expanded will be populated with its
	 * subdirectories, if necessary.
	 */
	public void fireTreeWillExpand(TreePath e) throws ExpandVetoException {

		// We fire a property change at the beginning and end of a node
		// expanding so that anyone interested only has to register a
		// PropertyChangeLister to know when nodes are expanding (so they can
		// display a wait cursor, for example).  Otherwise, they'd have to add
		// both a TreeExpansionListener and a TreeWillExpandListener.  Cheap,
		// I know, but oh well.
		firePropertyChange(WILL_EXPAND_PROPERTY, null, null);

		super.fireTreeWillExpand(e);

		FileSystemTreeNode dmtn =
					(FileSystemTreeNode)e.getLastPathComponent();

		// If the only child is the dummy one, we know we haven't populated
		// this node with true children yet.
		int childCount = dmtn.getChildCount();
		if (childCount==1 && ((FileSystemTreeNode)dmtn.getChildAt(0)).
				containsFile(DUMMY_FILE)) {
			refreshChildren(dmtn);
		}

	}


/*****************************************************************************/


	/**
	 * Returns the child of the specified node containing the specified file.
	 *
	 * @param node The node whose children you want to search.
	 * @param file The file for which to search.
	 * @return The child node representing the specified file, or
	 *         <code>null</code> if none of the children specified the file.
	 */
	private FileSystemTreeNode getChildRepresentingFile(
								FileSystemTreeNode node, Object file) {
		if (file==null)
			return null;
		int childCount = node.getChildCount();
		for (int i=0; i<childCount; i++) {
			FileSystemTreeNode child =
						(FileSystemTreeNode)node.getChildAt(i);
			if (file.equals(child.getUserObject()))
				return child;
		}
		return null;
	}


/*****************************************************************************/


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -