/*
* License: source-license.txt
* If this code is used independently, copy the license here.
*/
package wombat.gui.frames;
import java.awt.Frame;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.LayoutStyle;
import javax.swing.WindowConstants;
/**
* Dialog to find and replace text.
*/
public class FindReplaceDialog extends JDialog {
private static final long serialVersionUID = -4069253877583476204L;
// Text to find and replace.
private JTextPane text;
// Search position.
private int currentPos = -1;
private int pos = -1;
// Text to find / replace it with.
private JTextField findTextField;
private JTextField replaceTextField;
/**
* Create a new find/replace dialog.
* @param parent The parent frame of this dialog.
* @param text The text pane to replace text in.
*/
public FindReplaceDialog(final Frame parent, final JTextPane textPane) {
super(parent, false);
this.text = textPane;
this.currentPos = this.text.getCaretPosition();
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setTitle("Find/Replace");
replaceTextField = new JTextField();
findTextField = new JTextField();
// So we can access it in the nested event listener.
final FindReplaceDialog me = this;
// Button to find the next matching bit of text.
final JButton findButton = new JButton("Find Next");
findButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent event) {
System.err.println("Find starting at " + currentPos); // TODO: DEBUG
// Nothing to search for.
if (findTextField.getText().isEmpty()) return;
// Get the search term and sanity check.
String context = text.getText();
if (currentPos > context.length()) return;
String wordToFind = findTextField.getText();
pos = context.indexOf(wordToFind, currentPos);
int startPos = context.indexOf(wordToFind, 0);
// Fix to start at the beginning if we didn't find
if (pos == -1 && startPos != -1) pos = startPos;
// Find the word, highlight if so.
if (pos != -1) {
text.setSelectionStart(pos);
text.setSelectionEnd(pos + wordToFind.length());
text.requestFocusInWindow();
currentPos = pos + 1;
}
// Oops. Couldn't find it.
else {
JOptionPane.showMessageDialog(me, "Could not find '" + wordToFind + "'");
}
}
});
// Button to replace the current instance with the replacement text.
final JButton replaceButton = new JButton("Replace");
replaceButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent event) {
if (!findTextField.getText().isEmpty() && text.getSelectedText().equals(findTextField.getText()) && pos != -1) {
text.replaceSelection(replaceTextField.getText());
findButton.doClick();
}
}
});
// Replace all instances of the target text with the replacement.
final JButton replaceAllButton = new JButton("Replace All");
replaceAllButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent event) {
text.setText(text.getText().replace(findTextField.getText(), replaceTextField.getText()));
}
});
final JLabel replaceLabel = new JLabel("Replace with: ");
final JLabel findLabel = new JLabel("Find: ");
// Layout the group content.
GroupLayout layout = new GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(14, 14, 14)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(replaceLabel)
.addComponent(findLabel, GroupLayout.PREFERRED_SIZE, 42, GroupLayout.PREFERRED_SIZE))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
.addComponent(findTextField)
.addComponent(replaceTextField, GroupLayout.DEFAULT_SIZE, 196, Short.MAX_VALUE))
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(8, 8, 8)
.addComponent(findButton, GroupLayout.DEFAULT_SIZE, 96, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(replaceAllButton, GroupLayout.DEFAULT_SIZE, 98, Short.MAX_VALUE)
.addComponent(replaceButton, GroupLayout.PREFERRED_SIZE, 98, GroupLayout.PREFERRED_SIZE))))
.addContainerGap()));
layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(findTextField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(findButton)
.addComponent(findLabel))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(replaceLabel)
.addComponent(replaceTextField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(replaceButton))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(replaceAllButton)
.addContainerGap()));
pack();
}
}