📄 abstractsearchdialog.java
字号:
/*
* 04/08/2004
*
* AbstractSearchDialog.java - Base class for all search dialogs
* (find, replace, etc.).
* 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.search;
import java.awt.Frame;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.ResourceBundle;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;
import javax.swing.border.Border;
import org.fife.RUtilities;
import org.fife.ui.MaxWidthComboBox;
import org.fife.ui.RButton;
import org.fife.ui.RComboBoxModel;
/**
* Base class for all search dialogs (find, replace, find in files, etc.).
* This class is not useful on its own; you should use either FindDialog
* or ReplaceDialog, or extend this class to create your own search
* dialog.
*
* @author Robert Futrell
* @version 0.1
*/
public class AbstractSearchDialog extends JDialog implements ActionListener {
/**
*
*/
private static final long serialVersionUID = -1628956085490808507L;
public static final String MATCH_CASE_PROPERTY = "SearchDialog.MatchCase";
public static final String MATCH_WHOLE_WORD_PROPERTY = "SearchDialog.MatchWholeWord";
public static final String USE_REG_EX_PROPERTY = "SearchDialog.UseRegularExpressions";
// Conditions check boxes and the panel they go in.
// This should be added in the actual layout of the search dialog.
protected JCheckBox caseCheckBox;
protected JCheckBox wholeWordCheckBox;
protected JCheckBox regExpCheckBox;
protected JPanel searchConditionsPanel;
/**
* The combo box where the user enters the text for which to search.
*/
protected MaxWidthComboBox findTextComboBox;
// Miscellaneous other stuff.
protected JButton cancelButton;
/*****************************************************************************/
/**
* Constructor. Does initializing for parts common to all search
* dialogs.
*
* @param owner The window that owns this search dialog.
* @param resources The resource bundle from which to get strings, etc.
* @param useRButtons If <code>true</code>, then
* <code>org.fife.ui.RButton</code>s will be used for all buttons
* defined here (currently just the Cancel button). Otherwise,
* regular <code>JButton</code>s are used.
*/
public AbstractSearchDialog(Frame owner, ResourceBundle resources,
boolean useRButtons) {
super(owner);
// Make a panel containing the option checkboxes.
searchConditionsPanel = new JPanel();
searchConditionsPanel.setLayout(new BoxLayout(searchConditionsPanel, BoxLayout.Y_AXIS));
caseCheckBox = RUtilities.createCheckBox(resources, "MatchCase", "MatchCaseMnemonic");
caseCheckBox.setActionCommand("FlipMatchCaseValue");
caseCheckBox.addActionListener(this);
searchConditionsPanel.add(caseCheckBox);
wholeWordCheckBox = RUtilities.createCheckBox(resources,
"WholeWord", "WholeWordMnemonic");
wholeWordCheckBox.setActionCommand("FlipWholeWordValue");
wholeWordCheckBox.addActionListener(this);
searchConditionsPanel.add(wholeWordCheckBox);
regExpCheckBox = RUtilities.createCheckBox(resources, "RegEx", "RegExMnemonic");
regExpCheckBox.setActionCommand("FlipRegularExpressionValue");
regExpCheckBox.addActionListener(this);
searchConditionsPanel.add(regExpCheckBox);
// Initialize any text fields.
findTextComboBox = new MaxWidthComboBox(new RComboBoxModel(), 200);
findTextComboBox.setEditable(true);
// Initialize other stuff.
if (useRButtons==true) {
cancelButton = new RButton(resources.getString("Cancel"));
}
else {
cancelButton = new JButton(resources.getString("Cancel"));
}
cancelButton.setMnemonic((int)resources.getString("CancelMnemonic").charAt(0));
cancelButton.setActionCommand("Cancel");
cancelButton.addActionListener(this);
}
/*****************************************************************************/
/**
* Listens for actions in this search dialog.
*/
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
// They check/uncheck the "Match Case" checkbox on the Find dialog.
if (actionCommand.equals("FlipMatchCaseValue")) {
boolean matchCase = caseCheckBox.isSelected();
firePropertyChange(MATCH_CASE_PROPERTY, !matchCase, matchCase);
}
// They check/uncheck the "Whole word" checkbox on the Find dialog.
else if (actionCommand.equals("FlipWholeWordValue")) {
boolean wholeWord = wholeWordCheckBox.isSelected();
firePropertyChange(MATCH_WHOLE_WORD_PROPERTY, !wholeWord, wholeWord);
}
// They check/uncheck the "Regular expression" checkbox.
else if (actionCommand.equals("FlipRegularExpressionValue")) {
boolean useRegEx = regExpCheckBox.isSelected();
firePropertyChange(USE_REG_EX_PROPERTY, !useRegEx, useRegEx);
}
// If they press the "Cancel" button.
else if (actionCommand.equals("Cancel")) {
setVisible(false);
}
}
/*****************************************************************************/
/**
* Returns a titled border for panels on search dialogs.
*
* @param title The title for the border.
* @return The border.
*/
protected Border createTitledBorder(String title) {
if (title!=null && title.charAt(title.length()-1)!=':')
title += ":";
return BorderFactory.createTitledBorder(title);
}
/*****************************************************************************/
/**
* Returns the text on the Cancel button.
*
* @return The text on the Cancel button.
* @see #setCancelButtonText
*/
public final String getCancelButtonText() {
return cancelButton.getText();
}
/*****************************************************************************/
/**
* Returns the text for the "Match Case" check box.
*
* @return The text for the "Match Case" check box.
* @see #setMatchCaseCheckboxText
*/
public final String getMatchCaseCheckboxText() {
return caseCheckBox.getText();
}
/*****************************************************************************/
/**
* Returns the text for the "Regular Expression" check box.
*
* @return The text for the "Regular Expression" check box.
* @see #setRegularExpressionCheckboxText
*/
public final String getRegularExpressionCheckboxText() {
return regExpCheckBox.getText();
}
/*****************************************************************************/
/**
* Returns the text for the "Whole Word" check box.
*
* @return The text for the "Whole Word" check box.
* @see #setWholeWordCheckboxText
*/
public final String getWholeWordCheckboxText() {
return wholeWordCheckBox.getText();
}
/*****************************************************************************/
/**
* Searches <code>searchIn</code> for an occurance of
* <code>searchFor</code> either forwards or backwards, matching case or
* not.
*
* @param searchFor The string to look for.
* @param searchIn The string to search in.
* @param startPos The position in <code>searchIn</code> at which to begin
* searching.
* @param goForward Whether to search forward or backward in
* <code>searchIn</code>.
* @param matchCase If <code>true</code>, do a case-sensitive search for
* <code>searchFor</code>.
* @param lookForWholeWord If <code>true</code>, <code>searchFor</code>
* occurances embedded in longer words in <code>searchIn</code>
* don't count as matches.
* @return The starting position of a match, or <code>-1</code> if no match
* was found.
* @see #getNextMatchPosImpl
* @see #getNextMatchPosRegEx
*/
public static final int getNextMatchPos(String searchFor, String searchIn,
int startPos, boolean goForward, boolean matchCase,
boolean lookForWholeWord) {
// To speed up things a tad below if looking for a "whole word".
int tempChange = 0;
if (lookForWholeWord) {
// If going FORWARD and we found a match that isn't a whole word,
// we continue searching 2 characters AFTER the end of the
// non-whole-word match, as that's the first position where a
// whole-word match could possibly be.
// If going BACKWARD and we found a match that isn't a whole
// word, we continue searching (searchFor.length()+1) characters
// before the beginning of the non-whole word match. This is
// because String.lastIndexOf() will return a match BEGINNING at
// the specified location (e.g., "fatty".lastIndexOf("at", 1)
// returns 1).
tempChange = goForward ? searchFor.length() + 1 :
-(searchFor.length() + 1);
}
// Make our variables lower case if we're ignoring case.
if (!matchCase) {
return getNextMatchPosImpl(searchFor.toLowerCase(),
searchIn.toLowerCase(), startPos, goForward, matchCase,
lookForWholeWord, tempChange);
}
return getNextMatchPosImpl(searchFor, searchIn, startPos, goForward,
matchCase, lookForWholeWord, tempChange);
}
/*****************************************************************************/
/**
* Actually does the work of matching; assumes searchFor and searchIn are
* already upper/lower-cased appropriately.<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -