📄 findinfilesthread.java
字号:
/*
* 10/03/2005
*
* FindInFilesThread.java - Thread that does the searching for a
* Find in Files dialog.
* 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.search;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.awt.Point;
import javax.swing.JTextArea;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import org.fife.io.UnicodeReader;
import org.fife.ui.GUIWorkerThread;
/**
* A thread created by a <code>FindInFilesDialog</code> to do the searching.
*
* @author Robert Futrell
* @version 1.0
* @see FindInFilesDialog
*/
class FindInFilesThread extends GUIWorkerThread {
private FindInFilesDialog dialog;
private File directory;
private String verboseLabelString;
private String verboseNoFiltMatchString;
private String dontSearchSubfoldersString;
private String newFilesToExamineString;
private String occurrencesString;
/*****************************************************************************/
/**
* Constructor.
*
* @param dialog The "find in files" dialog.
* @param directory The directory in which to search.
*/
public FindInFilesThread(FindInFilesDialog dialog, File directory) {
this.dialog = dialog;
this.directory = directory;
ResourceBundle msg = dialog.getBundle();
verboseLabelString = "<html><em>" + msg.getString("VerboseLabel") +
"</em>";
verboseNoFiltMatchString = msg.getString("VerboseNoFiltMatch");
dontSearchSubfoldersString = msg.getString("SearchSubFoldUnchecked");
newFilesToExamineString = msg.getString("NewFilesToExamine");
occurrencesString = " " + msg.getString("Occurrences");
}
/*****************************************************************************/
protected MatchData createErrorMatchData(String filePath, String msg) {
return new MatchData(filePath, "--", msg,
MatchData.TYPE_ERROR);
}
/*****************************************************************************/
protected MatchData createVerboseMatchData(String filePath, String msg) {
return new MatchData(filePath, "--", verboseLabelString + msg,
MatchData.TYPE_VERBOSE);
}
/*****************************************************************************/
/**
* Converts a <code>String</code> representing a wildcard file filter into
* another <code>String</code> containing a regular expression good for
* finding files that match the wildcard expressions.<br><br>
* Example: For<br><br>
* <code>String regEx = getRegularExpressionForFileFilter("*.c");</code>
* <br><br>
* <code>regEx</code> will contain <code>^.*\.c$</code>.
*
* @param fileFilter The file filter for which to create equivalent
* regular expressions. This filter can currently only contain
* the wildcards '*' and '?'.
* @param showErrorDialog If <code>true</code>, an error dialog is
* displayed if an error occurs.
* @return A <code>String</code> representing an equivalent regular
* expression for the string passed in. If an error occurs,
* <code>null</code> is returned.
*/
private String getRegularExpressionForFileFilter(String fileFilter,
boolean showErrorDialog) {
// Create a regex for the file filter.
String pattern = "^" + fileFilter;
pattern = pattern.replaceAll("\\.", "\\\\."); // '.' => '\.'
pattern = pattern.replaceAll("\\*", ".*"); // '*' => '.*'
pattern = pattern.replaceAll("\\?", "."); // '?' => '.'
pattern = pattern.replaceAll("\\$", "\\\\\\$"); // '$' => '\$'
pattern += "$";
try {
Pattern.compile(pattern);
} catch (PatternSyntaxException pse) {
// Do nothing; should never fail.
}
return pattern;
}
/*****************************************************************************/
/**
* Runs the search.
*/
public Object construct() {
String searchString = dialog.getSearchString();
// Next, get the list of regular expressions to apply when deciding
// whether or not to look in a file. If we're on Windows, do case-
// insensitive regexes.
StringTokenizer st = new StringTokenizer(
dialog.getInFilesComboBoxContents());
Pattern[] filterStrings = new Pattern[st.countTokens()];
int numFilterStrings = 0;
boolean osIsWindows = System.getProperty("os.name").toLowerCase().
indexOf("windows")>-1;
int flags = osIsWindows ? Pattern.CASE_INSENSITIVE : 0;
try {
while (st.hasMoreTokens()) {
String pattern = getRegularExpressionForFileFilter(
st.nextToken(), true);
if (pattern!=null)
filterStrings[numFilterStrings++] =
Pattern.compile(pattern, flags);
}
} catch (PatternSyntaxException e) {
e.printStackTrace(); // Never happens.
}
if (numFilterStrings==0) {
dialog.searchCompleted("");
return null;
}
// Then, do the search.
// The next two lines have the effect of "clearing" the results.
dialog.clearSearchResults();
File[] files = directory.listFiles();
List fileList = new ArrayList();
fileList.addAll(Arrays.asList(files));
boolean checkSubfolders = dialog.getCheckSubfolders();
boolean matchingLines = dialog.getShowMatchingLines();
boolean matchCase = dialog.getMatchCase();
boolean wholeWord = dialog.getMatchWholeWord();
boolean useRegExpressions = dialog.getUseRegEx();
boolean doVerboseOutput = dialog.getDoVerboseOutput();
// Since we're using getNextMatchPosImpl, we do this to keep from
// having to lower-case it every iteration of the loop in each file.
// If we're using regular expressions however, we just let the regex
// engine do it.
if (!useRegExpressions && !matchCase)
searchString = searchString.toLowerCase();
long startMillis = System.currentTimeMillis();
// Use JTextArea as it figures out line numbers for us.
JTextArea textArea = new JTextArea();
int numFiles = fileList.size();
for (int i=0; i<numFiles; i++) {
// If the user cancelled the search...
if (Thread.currentThread().isInterrupted()) {
dialog.searchCompleted(
dialog.getBundle().getString("SearchTerminated"));
return null;
}
File temp = (File)fileList.get(i);
String fileFullPath = temp.getAbsolutePath();
// If temp is a regular file (i.e., non-directory) AND exists...
if (temp.isFile()) {
// If the file doesn't match one of the filters from
// "In files:", skip it.
boolean filteredOut = true;
for (int j=0; j<numFilterStrings; j++) {
Matcher m = filterStrings[j].matcher(temp.getName());
if (m.matches()) {
filteredOut = false;
break;
}
}
if (filteredOut==true) {
if (doVerboseOutput) {
MatchData data = createVerboseMatchData(
fileFullPath, verboseNoFiltMatchString);
dialog.addMatchData(data);
}
continue;
}
// Display the file we're searching in the status bar.
// Note that this method postpones the update to the EDT.
dialog.setStatusText(
dialog.getBundle().getString("SearchingFile")
+ i + "/" + numFiles + ": " + fileFullPath);
// NOTE: WHAT IS THE BEST WAY TO READ IN A FILE? WE DO IT
// THIS WAY BECAUSE WE USE TEXTAREA LATER.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -