📄 fsacombobox.java
字号:
/*
* 05/12/2004
*
* FSAComboBox.java - A "File System-Aware" combo box that keeps its drop-down
* list popuplated with files matching the text typed in by
* the user.
* Copyright (C) 2004 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;
import java.io.File;
import java.io.FilenameFilter;
import javax.swing.*;
import javax.swing.event.*;
/**
* A "File System-Aware" combo box. When the user is typing into this
* combo box, it automagically locates all files that begin with the
* text typed in, and populates the combo box with file choices. This
* is similar to the combo box found in the "Run" dialog in Microsoft
* Windows.<p>
*
* You should no longer use this class; use {@link FSATextField} instead. It
* has the same functionality but fewer problems.
*
* @author Robert Futrell
* @version 0.1
* @deprecated
*/
public class FSAComboBox extends JComboBox implements DocumentListener {
/**
*
*/
private static final long serialVersionUID = -5747590228545687478L;
/**
* <code>true</code> iff the OS is a Windows variant. This tells us
* whether or not filename comparisons should be done case-sensitively
* or not.
*/
private static final boolean osIsWindows = System.getProperty("os.name").toLowerCase().indexOf("windows")>-1;
/**
* The file separator for this OS.
*/
private static final String separator = System.getProperty("file.separator");
/**
* File filter used if directories-only mode is set.
*/
private FilenameFilter directoriesOnlyFilenameFilter;
/**
* These are an attempt to speed things up in the "common" case. If the
* user types a letter into the combo box but the last position of a
* file separator is the same as it was last time, then the "current
* directory" hasn't changed, so we can just keep the File instance for
* the directory we already have. We do this because doing a regex match
* loop through possibly hundreds of file names can be slow on some systems.
*/
private int lastLastSeparator = -1;
private File directory;
private String dirName;
/**
* Real variables used by the combo box.
*/
private JTextField textComponent;
private boolean repopulatePopupList = true;
private boolean directoriesOnly;
private long lastCount = -1;
/**
* Cached values of the files in the current directory and the number
* of files in the current directory.
*/
private String[] containedFiles;
private int num;
/**
* The "current directory;" if the user is typing a relative pathname
* (i.e., not absolute), then assume this is the root directory.
*/
private String currentDirectory;
/**
* Whether or not the combo box pops up a list of matching files.
*/
private boolean fileSystemAware;
/*****************************************************************************/
/**
* Creates a new FSAComboBox that previews both files and directories,
* and whose current directory is the program's current directory.
*/
public FSAComboBox() {
this(false, System.getProperty("user.dir"));
}
/*****************************************************************************/
/**
* Creates a new FSAComboBox.
*
* @param directoriesOnly Whether this combo box should preview only
* directories (or both files and directories).
* @param currentDirectory The directory for which the combo box should
* assume relative filenames are in.
*/
public FSAComboBox(boolean directoriesOnly, File currentDirectory) {
this(directoriesOnly, currentDirectory.getAbsolutePath());
}
/*****************************************************************************/
/**
* Creates a new FSAComboBox.
*
* @param directoriesOnly Whether this combo box should preview only
* directories (or both files and directories).
* @param currentDirectory The directory for which the combo box should
* assume relative filenames are in.
*/
public FSAComboBox(boolean directoriesOnly, String currentDirectory) {
super();
setEditable(true);
setDirectoriesOnly(directoriesOnly);
setCurrentDirectory(currentDirectory);
fileSystemAware = true;
}
/*****************************************************************************/
/**
* Called when the text component's document receives a style change.
* Since it is a plain document, this is never called.
*/
public void changedUpdate(DocumentEvent e) {
}
/*****************************************************************************/
/**
* Returns the current directory for this combo box.
*
* @return The current directory.
* @see #setCurrentDirectory
*/
public String getCurrentDirectory() {
return currentDirectory;
}
/*****************************************************************************/
/**
* Called when text is inserted into the text component's document.
*/
public void insertUpdate(DocumentEvent e) {
if (repopulatePopupList && isShowing() && fileSystemAware)
SwingUtilities.invokeLater(new Runnable() {
public void run() {
updateComboBoxContents();
}
});
}
/*****************************************************************************/
/**
* Returns whether or not this combo box previews both files and
* directories or just directories.
*
* @return Whether or not this combo box shows only directories.
* @see #setDirectoriesOnly
*/
public boolean isDirectoriesOnly() {
return directoriesOnly;
}
/*****************************************************************************/
/**
* Returns whether or not this combo box is file-system-aware. If it is,
* then the combo box expands to display all matching files/directories
* as the user types.
*
* @return Whether or not this combo box is file-system aware.
* @see #setFileSystemAware
*/
public boolean isFileSystemAware() {
return fileSystemAware;
}
/*****************************************************************************/
/**
* Called when text is removed from the text component's document.
*/
public void removeUpdate(DocumentEvent e) {
if (repopulatePopupList && isShowing() && fileSystemAware)
SwingUtilities.invokeLater(new Runnable() {
public void run() {
updateComboBoxContents();
}
});
}
/*****************************************************************************/
/**
* Sets the current directory for this combo box. The current directory
* is the directory in which the combo box assumes typed relative
* files reside in.
*
* @param currentDirectory The new "current directory" for this combo
* box. This value should be an absolute
* pathname.
* @see #getCurrentDirectory
*/
public void setCurrentDirectory(File currentDirectory) {
this.currentDirectory = currentDirectory.getAbsolutePath();
}
/*****************************************************************************/
/**
* Sets the current directory for this combo box. The current directory
* is the directory in which the combo box assumes typed relative
* files reside in.
*
* @param currentDirectory The new "current directory" for this combo
* box. This value should be an absolute
* pathname.
* @see #getCurrentDirectory
*/
public void setCurrentDirectory(String currentDirectory) {
this.currentDirectory = currentDirectory;
}
/*****************************************************************************/
/**
* Sets whether or not this combo box previews both files and
* directories or just directories.
*
* @param directoriesOnly Whether or not to preview only directories.
* @see #isDirectoriesOnly
*/
public void setDirectoriesOnly(boolean directoriesOnly) {
// Lazily create the file filter used.
if (directoriesOnly) {
directoriesOnlyFilenameFilter = new FilenameFilter() {
public boolean accept(File parentDir, String fileName) {
return new File(parentDir.getAbsolutePath() + separator + fileName).isDirectory();
}
};
}
this.directoriesOnly = directoriesOnly;
}
/*****************************************************************************/
/**
* Toggles whether or not this dialog is file-system-aware. This
* property should be set to <code>false</code> when programmatically
* inserting text into the combo box; otherwise, it has a bad habit of
* stealing the focus from the currently focused component, etc.
*
* @param aware Whether or not this combo box should be file-system
* aware.
* @see #isFileSystemAware
*/
public void setFileSystemAware(boolean aware) {
fileSystemAware = aware;
}
/*****************************************************************************/
public void setSelectedIndex(int index) {
repopulatePopupList = false;
super.setSelectedIndex(index);
repopulatePopupList = true;
}
/*****************************************************************************/
/**
* Updates the combo box's dropdown list to contain files matching
* the characters typed by the user into the combo box's text field.
*/
public void updateComboBoxContents() {
String text = textComponent.getText();
// We're nice and allow the user to type either '/' or '\\' as the separator on any OS.
int lastSeparator = Math.max(text.lastIndexOf('/'), text.lastIndexOf('\\')) + 1;//text.lastIndexOf(separator);
// Get the path for the file they're typing. If they haven't typed a
// separator char yet, assume it's a relative path from the current
// directory (and they're typing the name of a file in that directory).
// If they have typed a separator char, check to see if it's a relative
// directory path or an absolute one.
File t2 = null;
if (lastSeparator!=0) {
String pathPart = text.substring(0, lastSeparator);
t2 = new File(pathPart);
if (!t2.isAbsolute())
t2 = new File(currentDirectory + separator + pathPart);
}
else {
if (text.length()==0) {
setPopupVisible(false);
lastCount = 0;
return;
}
t2 = new File(currentDirectory);
}
// An attempt to speed things up in the common case. If the
// directory they're working in hasn't changed, we don't
// have to get the list of files in the directory (as it is cached).
if (!t2.equals(directory)) {
directory = t2;
if (!directory.isDirectory()) {
lastCount = -1;
lastLastSeparator = 0;
setPopupVisible(false);
num = 0;
containedFiles = null;
return;
}
lastLastSeparator = lastSeparator;
dirName = directory.getAbsolutePath();
if (dirName.charAt(dirName.length()-1)!=separator.charAt(0))
dirName += separator; // Only need to add slash if not == "C:\" on Windows.
// If they only want to see directories, we have to take a little
// more care.
if (directoriesOnly) {
containedFiles = directory.list(directoriesOnlyFilenameFilter);
}
else {
containedFiles = directory.list();
}
// We must check for null here in case an IO error occurs.
num = containedFiles!=null ? containedFiles.length : 0;
} // End of if (lastSeparator!=lastLastSeparator).
if (num > 0) {
repopulatePopupList = false;
removeAllItems();
// We only match on the file name since the canonical-file path is
// cached in dirName.
String fpFileName = text.substring(lastSeparator);
int fpFileNameLength = fpFileName.length();
long count = 0;
for (int i=0; i<num; i++) {
// If fileName starts with fpFileName, matching case only in Windows...
if (containedFiles[i].regionMatches(osIsWindows, 0, fpFileName, 0,fpFileNameLength)) {
count++;
addItem(dirName + containedFiles[i]);
}
}
if (count!=lastCount && count>0) {
setPopupVisible(false);
setPopupVisible(true); // This tricks the popup menu's list to "resize" properly.
}
else if (count==0)
setPopupVisible(false);
lastCount = count;
textComponent.setText(text); // The text in the component gets goobered.
repopulatePopupList = true;
}
else {
lastCount = -1;
lastSeparator = 0;
setPopupVisible(false);
}
}
/*****************************************************************************/
/**
* Overridden so that we always have a document listener on the text field
* contained by this combo box.
*/
public void setUI(javax.swing.plaf.ComboBoxUI ui) {
if (textComponent!=null)
textComponent.getDocument().removeDocumentListener(this);
super.setUI(ui);
textComponent = (JTextField)getEditor().getEditorComponent();
textComponent.getDocument().addDocumentListener(this);
}
/*****************************************************************************/
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -