/* * Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com * * 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.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.text.JTextComponent; import jsyntaxpane.SyntaxDocument; 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 dlg; /** * 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; } public void setPattern(Pattern pattern) { this.pattern = pattern; } 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) { SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(target); if (sDoc == null) { return; } if (getPattern() == null) { return; } Matcher matcher = sDoc.getMatcher(getPattern()); String newText = matcher.replaceAll(replacement); target.setText(newText); } /** * Perform a FindNext operation on the given text component. Position * the caret at the start of the next found pattern * @param target */ public void doFindNext(JTextComponent target) { if (getPattern() == null) { return; } SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(target); if (sDoc == null) { return; } int start = target.getCaretPosition() + 1; // we must advance the position by one, otherwise we will find // the same text again if (start >= sDoc.getLength()) { start = 0; } 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); } else { if (isWrap()) { matcher = sDoc.getMatcher(getPattern()); if (matcher != null && matcher.find()) { target.select(matcher.start(), matcher.end()); } else { msgNotFound(target); } } else { msgNotFound(target); } } } /** * Display an OptionPane dialog that the search string is not found * @param target */ public void msgNotFound(Component target) { JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(target), "Search String " + getPattern() + " not found", "Find", JOptionPane.INFORMATION_MESSAGE); } /** * Show the Find and Replace dialog for the given frame * @param target */ public void showDialog(JTextComponent target) { if (dlg == null) { dlg = new ReplaceDialog(target, this); } dlg.setVisible(true); } }