/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.support.actions; import com.eviware.soapui.support.UISupport; import com.eviware.soapui.support.xml.ProxyFindAndReplacable; import com.jgoodies.forms.builder.ButtonBarBuilder; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.SwingUtilities; import java.awt.BorderLayout; import java.awt.GridLayout; import java.awt.Window; import java.awt.event.ActionEvent; /** * Find-and-Replace dialog for a JXmlTextArea * * @author Ole.Matzura */ public class FindAndReplaceDialog extends AbstractAction { private final ProxyFindAndReplacable target; private JDialog dialog; private JCheckBox caseCheck; private JRadioButton allButton; private JRadioButton selectedLinesButton; private JRadioButton forwardButton; private JRadioButton backwardButton; private JCheckBox wholeWordCheck; private JButton findButton; private JButton replaceButton; private JButton replaceAllButton; private JComboBox findCombo; private JComboBox replaceCombo; private JCheckBox wrapCheck; public FindAndReplaceDialog(FindAndReplaceable target) { super("Find / Replace"); if (UISupport.isMac()) { putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke("meta F")); } else { putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke("control F")); } this.target = new ProxyFindAndReplacable(target); } public void actionPerformed(ActionEvent e) { show(); } public void show() { if (dialog == null) { buildDialog(); } target.getEditComponent().requestFocusInWindow(); replaceCombo.setEnabled(target.isEditable()); replaceAllButton.setEnabled(target.isEditable()); replaceButton.setEnabled(target.isEditable()); UISupport.showDialog(dialog); findCombo.getEditor().selectAll(); findCombo.requestFocus(); } private void buildDialog() { Window window = SwingUtilities.windowForComponent(target.getEditComponent()); dialog = new JDialog(window, "Find / Replace"); dialog.setModal(false); JPanel panel = new JPanel(new BorderLayout()); findCombo = new JComboBox(); findCombo.setEditable(true); replaceCombo = new JComboBox(); replaceCombo.setEditable(true); // create inputs GridLayout gridLayout = new GridLayout(2, 2); gridLayout.setVgap(5); JPanel inputPanel = new JPanel(gridLayout); inputPanel.add(new JLabel("Find:")); inputPanel.add(findCombo); inputPanel.add(new JLabel("Replace with:")); inputPanel.add(replaceCombo); inputPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); // create direction panel ButtonGroup directionGroup = new ButtonGroup(); forwardButton = new JRadioButton("Forward", true); forwardButton.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); directionGroup.add(forwardButton); backwardButton = new JRadioButton("Backward"); backwardButton.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); directionGroup.add(backwardButton); JPanel directionPanel = new JPanel(new GridLayout(2, 1)); directionPanel.add(forwardButton); directionPanel.add(backwardButton); directionPanel.setBorder(BorderFactory.createTitledBorder("Direction")); // create scope panel ButtonGroup scopeGroup = new ButtonGroup(); allButton = new JRadioButton("All", true); allButton.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); selectedLinesButton = new JRadioButton("Selected Lines"); selectedLinesButton.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); scopeGroup.add(allButton); scopeGroup.add(selectedLinesButton); JPanel scopePanel = new JPanel(new GridLayout(2, 1)); scopePanel.add(allButton); scopePanel.add(selectedLinesButton); scopePanel.setBorder(BorderFactory.createTitledBorder("Scope")); // create options caseCheck = new JCheckBox("Case Sensitive"); caseCheck.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); wholeWordCheck = new JCheckBox("Whole Word"); wholeWordCheck.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); wrapCheck = new JCheckBox("Wrap Search"); wrapCheck.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); JPanel optionsPanel = new JPanel(new GridLayout(3, 1)); optionsPanel.add(caseCheck); optionsPanel.add(wholeWordCheck); optionsPanel.add(wrapCheck); optionsPanel.setBorder(BorderFactory.createTitledBorder("Options")); // create panel with options JPanel options = new JPanel(new GridLayout(1, 2)); JPanel radios = new JPanel(new GridLayout(2, 1)); radios.add(directionPanel); radios.add(scopePanel); options.add(optionsPanel); options.add(radios); options.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8)); // create buttons ButtonBarBuilder builder = new ButtonBarBuilder(); findButton = new JButton(new FindAction()); builder.addFixed(findButton); builder.addRelatedGap(); replaceButton = new JButton(new ReplaceAction()); builder.addFixed(replaceButton); builder.addRelatedGap(); replaceAllButton = new JButton(new ReplaceAllAction()); builder.addFixed(replaceAllButton); builder.addUnrelatedGap(); builder.addFixed(new JButton(new CloseAction())); builder.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); // tie it up! panel.add(inputPanel, BorderLayout.NORTH); panel.add(options, BorderLayout.CENTER); panel.add(builder.getPanel(), BorderLayout.SOUTH); dialog.getContentPane().add(panel); dialog.pack(); UISupport.initDialogActions(dialog, null, findButton); } private int findNext(int pos, String txt, String value) { int ix = forwardButton.isSelected() ? txt.indexOf(value, pos) : txt.lastIndexOf(value, pos); if (selectedLinesButton.isSelected() && (ix < target.getSelectionStart() || ix > target.getSelectionEnd())) { ix = -1; } if (wholeWordCheck.isSelected()) { while (ix != -1 && ((ix > 0 && Character.isLetterOrDigit(txt.charAt(ix - 1))) || (ix < txt.length() - value.length() - 1 && Character.isLetterOrDigit(txt.charAt(ix + value.length()))))) { ix = forwardButton.isSelected() ? ++ix : --ix; ix = forwardButton.isSelected() ? txt.indexOf(value, ix) : txt.lastIndexOf(value, ix); } } if (ix == -1 && wrapCheck.isSelected()) { if (forwardButton.isSelected() && pos > 0) { return findNext(0, txt, value); } else if (backwardButton.isSelected() && pos < txt.length() - 1) { return findNext(txt.length() - 1, txt, value); } } return ix; } private class FindAction extends AbstractAction { String lastSearchedItem = ""; int lastPositionF = -1; public FindAction() { super("Find/Find Next"); } public void actionPerformed(ActionEvent e) { int pos = tweakPosition(); int lastpos = tweakLastPosition(); String txt = target.getText(); if (findCombo.getSelectedItem() == null) { return; } String value = findCombo.getSelectedItem().toString(); if (value.length() == 0 || (pos == txt.length() && !wrapCheck.isSelected())) { return; } if (!caseCheck.isSelected()) { value = value.toLowerCase(); txt = txt.toLowerCase(); } if (pos == lastPositionF && value.equals(lastSearchedItem)) { if (forwardButton.isSelected()) { pos += value.length() + 1; } else { pos -= value.length() - 1; } } int ix = findNext(pos, txt, value); lastSearchedItem = value; lastPositionF = ix; if (ix != -1) { if (selectedLinesButton.isSelected()) { target.select(ix, lastpos); } else { target.select(ix, ix + value.length()); } for (int c = 0; c < findCombo.getItemCount(); c++) { if (findCombo.getItemAt(c).equals(value)) { findCombo.removeItem(c); break; } } findCombo.insertItemAt(value, 0); } else { UISupport.showErrorMessage("String [" + value + "] not found"); } } } private class ReplaceAction extends AbstractAction { String lastSearchedItem = ""; int lastPositionF = -1; public ReplaceAction() { super("Replace/Replace Next"); } public void actionPerformed(ActionEvent e) { int pos = tweakPosition(); int lastpos = tweakLastPosition(); String txt = target.getText(); if (findCombo.getSelectedItem() == null) { return; } String value = findCombo.getSelectedItem().toString(); if (value.length() == 0 || txt.length() == 0) { return; } String newValue = replaceCombo.getSelectedItem() == null ? "" : replaceCombo.getSelectedItem().toString(); if (!caseCheck.isSelected()) { if (newValue.equalsIgnoreCase(value)) { return; } value = value.toLowerCase(); txt = txt.toLowerCase(); } else if (newValue.equals(value)) { return; } if (pos == lastPositionF && value.equals(lastSearchedItem)) { if (forwardButton.isSelected()) { pos += value.length() + 1; } else { pos -= value.length() - 1; } } int ix = findNext(pos, txt, value); lastSearchedItem = value; lastPositionF = ix; int firstIx = ix; if (ix != -1) { // System.out.println( "found match at " + ix + ", " + firstIx + // ", " + valueInNewValueIx ); target.select(ix, ix + value.length()); target.setSelectedText(newValue); if (selectedLinesButton.isSelected()) { target.select(ix, lastpos); } else { target.select(ix, ix + newValue.length()); } // adjust firstix if (ix < firstIx) { firstIx += newValue.length() - value.length(); } txt = target.getText(); if (!caseCheck.isSelected()) { txt = txt.toLowerCase(); } if (forwardButton.isSelected()) { ix = findNext(ix + newValue.length(), txt, value); } else { ix = findNext(ix - 1, txt, value); } } else { UISupport.showErrorMessage("String [" + value + "] not found"); } } } private class ReplaceAllAction extends AbstractAction { public ReplaceAllAction() { super("Replace All"); } public void actionPerformed(ActionEvent e) { int pos = tweakPosition(); String txt = target.getDialogText(); if (findCombo.getSelectedItem() == null) { return; } String value = findCombo.getSelectedItem().toString(); if (value.length() == 0 || txt.length() == 0) { return; } String newValue = replaceCombo.getSelectedItem() == null ? "" : replaceCombo.getSelectedItem().toString(); if (!caseCheck.isSelected()) { if (newValue.equalsIgnoreCase(value)) { return; } value = value.toLowerCase(); txt = txt.toLowerCase(); } else if (newValue.equals(value)) { return; } int ix = findNext(pos, txt, value); if (ix >= 0) { int firstIx = ix; int valueInNewValueIx = !caseCheck.isSelected() ? newValue.toLowerCase().indexOf(value) : newValue .indexOf(value); target.setReplaceAll(true); target.setSBTarget(); target.setNewValue(newValue); while (ix != -1) { target.select(ix, ix + value.length()); target.setSelectedText(newValue); target.select(ix, ix + newValue.length()); // adjust firstix if (ix < firstIx) { firstIx += newValue.length() - value.length(); } txt = target.getText(); if (!caseCheck.isSelected()) { txt = txt.toLowerCase(); } if (forwardButton.isSelected()) { ix = findNext(ix + newValue.length(), txt, value); } else { ix = findNext(ix - 1, txt, value); } if (wrapCheck.isSelected() && valueInNewValueIx != -1 && ix == firstIx + valueInNewValueIx) { break; } } target.flushSBText(); target.setReplaceAll(false); target.setCarretPosition(forwardButton.isSelected()); } else { UISupport.showErrorMessage("String [" + value + "] not found"); } } } private class CloseAction extends AbstractAction { public CloseAction() { super("Close"); } public void actionPerformed(ActionEvent e) { dialog.setVisible(false); } } private int tweakPosition() { int pos = target.getCaretPosition(); if (selectedLinesButton.isSelected()) { if (forwardButton.isSelected()) { int selstart = target.getSelectionStart(); if (selstart < pos && selstart != -1) { pos = selstart; } } else { int selend = target.getSelectionEnd(); if (selend > pos && selend != -1) { pos = selend; } } } else { int selstart = target.getSelectionStart(); if (selstart < pos && selstart != -1) { pos = selstart; } } return pos; } private int tweakLastPosition() { return forwardButton.isSelected() ? target.getSelectionEnd() : target.getSelectionStart(); } }