/* * RapidMiner * * Copyright (C) 2001-2008 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.gui.dialog; import java.awt.Component; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTextField; import com.rapidminer.gui.RapidMinerGUI; import com.rapidminer.tools.Tools; /** * The search dialog for searching strings in a {@link SearchableTextComponent}. * * @author Ingo Mierswa, Simon Fischer * @version $Id: SearchDialog.java,v 1.5 2008/05/09 19:23:20 ingomierswa Exp $ */ public class SearchDialog extends JDialog { private static final long serialVersionUID = -1019890951712706875L; private static class Result { private int start, end; private Result(int start, int end) { this.start = start; this.end = end; } public String toString() { return "start: " + start + ", end: " + end; } } private JTextField patternField = new JTextField(20); private JTextField replaceField = new JTextField(20); private JCheckBox caseSensitive = new JCheckBox("Case sensitive"); private JCheckBox regExp = new JCheckBox("Regular expression"); private JRadioButton up = new JRadioButton("Up"); private JRadioButton down = new JRadioButton("Down"); private transient SearchableTextComponent textComponent; public SearchDialog(Component owner, SearchableTextComponent textComponent) { this(owner, textComponent, false); } public SearchDialog(Component owner, SearchableTextComponent textComponent, boolean allowReplace) { super(RapidMinerGUI.getMainFrame()); this.textComponent = textComponent; this.textComponent.requestFocus(); this.textComponent.setCaretPosition(0); if (allowReplace) setTitle("Search and Replace"); else setTitle("Search"); setModal(false); GridBagLayout layout = new GridBagLayout(); getContentPane().setLayout(layout); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.insets = new Insets(5,5,5,5); c.ipadx = 10; c.weightx = 1.0d; c.gridwidth = 1; JLabel label = new JLabel("Search:"); layout.setConstraints(label, c); getContentPane().add(label); c.gridwidth = GridBagConstraints.RELATIVE; layout.setConstraints(patternField, c); getContentPane().add(patternField); final JButton search = new JButton("Search"); getRootPane().setDefaultButton(search); search.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { search(); getRootPane().setDefaultButton(search); } }); c.gridwidth = GridBagConstraints.REMAINDER; layout.setConstraints(search, c); getContentPane().add(search); if (allowReplace) { c.gridwidth = 1; label = new JLabel("Replace:"); layout.setConstraints(label, c); getContentPane().add(label); c.gridwidth = GridBagConstraints.RELATIVE; layout.setConstraints(replaceField, c); getContentPane().add(replaceField); final JButton replace = new JButton("Replace"); replace.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { replace(); search(); getRootPane().setDefaultButton(replace); } }); c.gridwidth = GridBagConstraints.REMAINDER; layout.setConstraints(replace, c); getContentPane().add(replace); } JPanel directionPanel = new JPanel(); directionPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(7, 0, 0, 7), BorderFactory.createTitledBorder("Direction"))); ButtonGroup directionGroup = new ButtonGroup(); up.setMnemonic(KeyEvent.VK_U); directionGroup.add(up); directionPanel.add(up); down.setMnemonic(KeyEvent.VK_D); directionGroup.add(down); down.setSelected(true); directionPanel.add(down); c.gridwidth = 1; layout.setConstraints(directionPanel, c); getContentPane().add(directionPanel); JPanel optionsPanel = new JPanel(); optionsPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(7, 0, 0, 7), BorderFactory.createTitledBorder("Options"))); optionsPanel.add(caseSensitive); optionsPanel.add(regExp); c.gridwidth = GridBagConstraints.RELATIVE; layout.setConstraints(optionsPanel, c); getContentPane().add(optionsPanel); c.gridwidth = GridBagConstraints.REMAINDER; JPanel dummyPanel = new JPanel(); layout.setConstraints(dummyPanel, c); getContentPane().add(dummyPanel); JPanel closeButtonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); JButton cancel = new JButton("Close"); cancel.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dispose(); } }); closeButtonPanel.add(cancel); c.gridwidth = GridBagConstraints.REMAINDER; layout.setConstraints(closeButtonPanel, c); getContentPane().add(closeButtonPanel); pack(); setLocationRelativeTo(owner); } private void search() { String pattern = patternField.getText().trim(); if (pattern.length() == 0) return; int startPos = textComponent.getCaretPosition(); String text = textComponent.getText(); if (startPos > text.length()) startPos = 0; if (down.isSelected()) { Result result = search(startPos, pattern, text, textComponent.canHandleCarriageReturn()); if (result == null) { noMoreHits(); return; } else { textComponent.select(result.start, result.end); } } else { Result lastResult = null; int pos = 0; while (true) { Result result = search(pos, pattern, text, textComponent.canHandleCarriageReturn()); if (result != null) { if (result.end < startPos) { pos = result.start + 1; lastResult = result; } else { break; } } else { break; } } if (lastResult == null) { noMoreHits(); } else { textComponent.select(lastResult.start, lastResult.end); } } } private void replace() { textComponent.replaceSelection(replaceField.getText()); } private Result search(int start, String pattern, String text, boolean canHandleCarriageReturn) { if (!canHandleCarriageReturn) { text = Tools.transformAllLineSeparators(text); } if (regExp.isSelected()) { Matcher matcher = Pattern.compile(pattern, caseSensitive.isSelected() ? 0 : Pattern.CASE_INSENSITIVE).matcher(text.subSequence(start, text.length())); if (matcher.find()) { return new Result(start + matcher.start(), start + matcher.end()); } else { return null; } } else { if (!caseSensitive.isSelected()) { text = text.toLowerCase(); pattern = pattern.toLowerCase(); } int result = text.indexOf(pattern, start); if (result == -1) { return null; } else { return new Result(result, result + pattern.length()); } } } private void noMoreHits() { String restartAt = up.isSelected() ? "end" : "beginning"; switch (JOptionPane.showConfirmDialog(this, "Search string not found. Search from " + restartAt + "?", "String not found", JOptionPane.YES_NO_OPTION)) { case JOptionPane.YES_OPTION: textComponent.setCaretPosition(up.isSelected() ? textComponent.getText().replaceAll("\r","").length() : 0); search(); break; case JOptionPane.NO_OPTION: default: return; } } }