jsyntaxpane.actions.DocumentSearchData Maven / Gradle / Ivy
/*
* Copyright 2008 Ayman Al-Sairafi [email protected]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License
* at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jsyntaxpane.actions;
import java.awt.Component;
import java.text.MessageFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.actions.gui.QuickFindDialog;
import jsyntaxpane.actions.gui.ReplaceDialog;
/**
* Data that is shared by Find / Replace and Find Next actions for a Document
* The data here will be added as a property of the Document using the key
* PROPERTY_KEY. Only through the getFtmEditor can you crate a new instance.
*
* The class is responsible for handling the doFind and doReplace all actions.
*
* The class is also responsible for displaying the Find / Replace dialog
*
* @author Ayman Al-Sairafi
*/
public class DocumentSearchData {
private static final String PROPERTY_KEY = "SearchData";
private Pattern pattern = null;
private boolean wrap = true;
private ReplaceDialog replaceDlg;
private QuickFindDialog quickFindDlg;
/**
* This prevent creating a new instance. You must call the getFromEditor
* to crate a new instance attached to a Document
*
*/
private DocumentSearchData() {
}
public Pattern getPattern() {
return pattern;
}
/**
* Set the pattern to the given compiled pattern.
* @see this#setPattern(String, boolean, boolean)
* @param pattern
*/
public void setPattern(Pattern pattern) {
this.pattern = pattern;
}
/**
* Sets the pattern from a string and flags
* @param pat String of pattern
* @param regex true if the pattern should be a regexp
* @param ignoreCase true to ignore case
* @throws java.util.regex.PatternSyntaxException
*/
public void setPattern(String pat, boolean regex, boolean ignoreCase)
throws PatternSyntaxException {
if (pat != null && pat.length() > 0) {
int flag = (regex) ? 0 : Pattern.LITERAL;
flag |= (ignoreCase) ? Pattern.CASE_INSENSITIVE : 0;
setPattern(Pattern.compile(pat, flag));
} else {
setPattern(null);
}
}
public boolean isWrap() {
return wrap;
}
public void setWrap(boolean wrap) {
this.wrap = wrap;
}
/**
* Get the Search data from a Document. If document does not have any
* search data, then a new instance is added, put and reurned.
* @param target JTextCOmponent we are attaching to
* @return
*/
public static DocumentSearchData getFromEditor(JTextComponent target) {
if (target == null) {
return null;
}
Object o = target.getDocument().getProperty(PROPERTY_KEY);
if (o instanceof DocumentSearchData) {
DocumentSearchData documentSearchData = (DocumentSearchData) o;
return documentSearchData;
} else {
DocumentSearchData newDSD = new DocumentSearchData();
target.getDocument().putProperty(PROPERTY_KEY, newDSD);
return newDSD;
}
}
/**
* Perform a replace all operation on the given component.
* Note that this create a new duplicate String big as the entire
* document and then assign it to the target text component
* @param target
* @param replacement
*/
public void doReplaceAll(JTextComponent target, String replacement) {
if (replacement == null) {
replacement = "";
}
SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(target);
if (sDoc == null) {
return;
}
if (getPattern() == null) {
return;
}
Matcher matcher = sDoc.getMatcher(getPattern());
String newText = matcher.replaceAll(replacement);
try {
sDoc.replace(0, sDoc.getLength(), newText, null);
} catch (BadLocationException ex) {
Logger.getLogger(DocumentSearchData.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Replace single occurrence of match with the replacement.
* @param target
* @param replacement
*/
public void doReplace(JTextComponent target, String replacement) {
if (target.getSelectedText() != null) {
target.replaceSelection(replacement == null ? "" : replacement);
doFindNext(target);
}
}
/**
* FInd the previous match
* @param target
* @return
*/
public boolean doFindPrev(JTextComponent target) {
if (getPattern() == null) {
return false;
}
SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(target);
if (sDoc == null) {
return false;
}
int dot = target.getSelectionStart();
Matcher matcher = sDoc.getMatcher(getPattern());
if (matcher == null) {
return false;
}
// we have no way of jumping to last match, so we need to
// go throw all matches, and stop when we reach current pos
int start = -1;
int end = -1;
while (matcher.find()) {
if (matcher.end() >= dot) {
break;
}
start = matcher.start();
end = matcher.end();
}
if (end > 0) {
target.select(start, end);
return true;
} else {
return false;
}
}
/**
* Perform a FindNext operation on the given text component. Position
* the caret at the start of the next found pattern.
* @param target
* @return true if pattern is found, false otherwise
*/
public boolean doFindNext(JTextComponent target) {
if (getPattern() == null) {
return false;
}
SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(target);
if (sDoc == null) {
return false;
}
int start = target.getSelectionEnd();
if (target.getSelectionEnd() == target.getSelectionStart()) {
// we must advance the position by one, otherwise we will find
// the same text again
start++;
}
if (start >= sDoc.getLength()) {
start = sDoc.getLength();
}
Matcher matcher = sDoc.getMatcher(getPattern(), start);
if (matcher != null && matcher.find()) {
// since we used an offset in the matcher, the matcher location
// MUST be offset by that location
target.select(matcher.start() + start, matcher.end() + start);
return true;
} else {
if (isWrap()) {
matcher = sDoc.getMatcher(getPattern());
if (matcher != null && matcher.find()) {
target.select(matcher.start(), matcher.end());
return true;
} else {
return false;
}
} else {
return false;
}
}
}
/**
* Display an OptionPane dialog that the search string is not found
* @param target
*/
public void msgNotFound(Component target) {
JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(target),
MessageFormat.format(java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("DocumentSearchData.SearchStringNotFound"), getPattern()),
java.util.ResourceBundle.getBundle("jsyntaxpane/Bundle").getString("DocumentSearchData.Find"), JOptionPane.INFORMATION_MESSAGE);
}
/**
* Show the Find and Replace dialog for the given frame
* @param target
*/
public void showReplaceDialog(JTextComponent target) {
if (replaceDlg == null) {
replaceDlg = new ReplaceDialog(target, this);
}
replaceDlg.setVisible(true);
}
public void showQuickFindDialog(JTextComponent target) {
if (quickFindDlg == null) {
quickFindDlg = new QuickFindDialog(target, this);
}
quickFindDlg.showFor(target);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy