001: /*
002: * soapUI, copyright (C) 2004-2007 eviware.com
003: *
004: * soapUI is free software; you can redistribute it and/or modify it under the
005: * terms of version 2.1 of the GNU Lesser General Public License as published by
006: * the Free Software Foundation.
007: *
008: * soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009: * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: * See the GNU Lesser General Public License for more details at gnu.org.
011: */
012:
013: package com.eviware.soapui.support.actions;
014:
015: import java.awt.BorderLayout;
016: import java.awt.GridLayout;
017: import java.awt.Toolkit;
018: import java.awt.event.ActionEvent;
019:
020: import javax.swing.AbstractAction;
021: import javax.swing.Action;
022: import javax.swing.BorderFactory;
023: import javax.swing.ButtonGroup;
024: import javax.swing.JButton;
025: import javax.swing.JCheckBox;
026: import javax.swing.JComboBox;
027: import javax.swing.JDialog;
028: import javax.swing.JLabel;
029: import javax.swing.JPanel;
030: import javax.swing.JRadioButton;
031:
032: import com.eviware.soapui.support.UISupport;
033: import com.jgoodies.forms.builder.ButtonBarBuilder;
034:
035: /**
036: * Find-and-Replace dialog for a JXmlTextArea
037: *
038: * @author Ole.Matzura
039: */
040:
041: public class FindAndReplaceDialog extends AbstractAction {
042: private final FindAndReplaceable target;
043: private JDialog dialog;
044: private JCheckBox caseCheck;
045: private JRadioButton allButton;
046: private JRadioButton selectedLinesButton;
047: private JRadioButton forwardButton;
048: private JRadioButton backwardButton;
049: private JCheckBox wholeWordCheck;
050: private JButton findButton;
051: private JButton replaceButton;
052: private JButton replaceAllButton;
053: private JComboBox findCombo;
054: private JComboBox replaceCombo;
055: private JCheckBox wrapCheck;
056:
057: public FindAndReplaceDialog(FindAndReplaceable target) {
058: super ("Find / Replace");
059: putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke("F3"));
060: this .target = target;
061: }
062:
063: public void actionPerformed(ActionEvent e) {
064: show();
065: }
066:
067: public void show() {
068: if (dialog == null)
069: buildDialog();
070:
071: replaceCombo.setEnabled(target.isEditable());
072: replaceAllButton.setEnabled(target.isEditable());
073: replaceButton.setEnabled(target.isEditable());
074:
075: UISupport.showDialog(dialog);
076: findCombo.getEditor().selectAll();
077: findCombo.requestFocus();
078: }
079:
080: private void buildDialog() {
081: dialog = new JDialog(UISupport.getMainFrame(),
082: "Find / Replace", false);
083:
084: JPanel panel = new JPanel(new BorderLayout());
085: findCombo = new JComboBox();
086: findCombo.setEditable(true);
087: replaceCombo = new JComboBox();
088: replaceCombo.setEditable(true);
089:
090: // create inputs
091: GridLayout gridLayout = new GridLayout(2, 2);
092: gridLayout.setVgap(5);
093: JPanel inputPanel = new JPanel(gridLayout);
094: inputPanel.add(new JLabel("Find:"));
095: inputPanel.add(findCombo);
096: inputPanel.add(new JLabel("Replace with:"));
097: inputPanel.add(replaceCombo);
098: inputPanel.setBorder(BorderFactory
099: .createEmptyBorder(8, 8, 8, 8));
100:
101: // create direction panel
102: ButtonGroup directionGroup = new ButtonGroup();
103: forwardButton = new JRadioButton("Forward", true);
104: forwardButton.setBorder(BorderFactory.createEmptyBorder(3, 3,
105: 3, 3));
106: directionGroup.add(forwardButton);
107: backwardButton = new JRadioButton("Backward");
108: backwardButton.setBorder(BorderFactory.createEmptyBorder(3, 3,
109: 3, 3));
110: directionGroup.add(backwardButton);
111:
112: JPanel directionPanel = new JPanel(new GridLayout(2, 1));
113: directionPanel.add(forwardButton);
114: directionPanel.add(backwardButton);
115: directionPanel.setBorder(BorderFactory
116: .createTitledBorder("Direction"));
117:
118: // create scope panel
119: ButtonGroup scopeGroup = new ButtonGroup();
120: allButton = new JRadioButton("All", true);
121: allButton
122: .setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
123: selectedLinesButton = new JRadioButton("Selected Lines");
124: selectedLinesButton.setBorder(BorderFactory.createEmptyBorder(
125: 3, 3, 3, 3));
126: scopeGroup.add(allButton);
127: scopeGroup.add(selectedLinesButton);
128:
129: JPanel scopePanel = new JPanel(new GridLayout(2, 1));
130: scopePanel.add(allButton);
131: scopePanel.add(selectedLinesButton);
132: scopePanel.setBorder(BorderFactory.createTitledBorder("Scope"));
133:
134: // create options
135: caseCheck = new JCheckBox("Case Sensitive");
136: caseCheck
137: .setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
138: wholeWordCheck = new JCheckBox("Whole Word");
139: wholeWordCheck.setBorder(BorderFactory.createEmptyBorder(3, 3,
140: 3, 3));
141: wrapCheck = new JCheckBox("Wrap Search");
142: wrapCheck
143: .setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
144: JPanel optionsPanel = new JPanel(new GridLayout(3, 1));
145: optionsPanel.add(caseCheck);
146: optionsPanel.add(wholeWordCheck);
147: optionsPanel.add(wrapCheck);
148: optionsPanel.setBorder(BorderFactory
149: .createTitledBorder("Options"));
150:
151: // create panel with options
152: JPanel options = new JPanel(new GridLayout(1, 2));
153:
154: JPanel radios = new JPanel(new GridLayout(2, 1));
155: radios.add(directionPanel);
156: radios.add(scopePanel);
157:
158: options.add(optionsPanel);
159: options.add(radios);
160: options.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8));
161:
162: // create buttons
163: ButtonBarBuilder builder = new ButtonBarBuilder();
164: findButton = new JButton(new FindAction());
165: builder.addFixed(findButton);
166: builder.addRelatedGap();
167: replaceButton = new JButton(new ReplaceAction());
168: builder.addFixed(replaceButton);
169: builder.addRelatedGap();
170: replaceAllButton = new JButton(new ReplaceAllAction());
171: builder.addFixed(replaceAllButton);
172: builder.addUnrelatedGap();
173: builder.addFixed(new JButton(new CloseAction()));
174: builder.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
175:
176: // tie it up!
177: panel.add(inputPanel, BorderLayout.NORTH);
178: panel.add(options, BorderLayout.CENTER);
179: panel.add(builder.getPanel(), BorderLayout.SOUTH);
180:
181: dialog.getContentPane().add(panel);
182: dialog.pack();
183: dialog.getRootPane().setDefaultButton(findButton);
184: }
185:
186: private int findNext(int pos, String txt, String value) {
187: int ix = forwardButton.isSelected() ? txt.indexOf(value,
188: pos + 1) : txt.lastIndexOf(value, pos - 1);
189:
190: if (wholeWordCheck.isSelected()) {
191: while (ix != -1
192: && (ix > 0 && Character.isLetterOrDigit(txt
193: .charAt(ix - 1)))
194: || (ix < txt.length() - value.length() - 1 && Character
195: .isLetterOrDigit(txt.charAt(ix
196: + value.length())))) {
197: ix = findNext(ix, txt, value);
198: }
199: }
200:
201: if (ix == -1 && wrapCheck.isSelected()) {
202: if (forwardButton.isSelected() && pos > 0)
203: return findNext(0, txt, value);
204: else if (backwardButton.isSelected()
205: && pos < txt.length() - 1)
206: return findNext(txt.length() - 1, txt, value);
207: }
208:
209: if (selectedLinesButton.isSelected()
210: && (ix < target.getSelectionStart() || ix > target
211: .getSelectionEnd()))
212: ix = -1;
213:
214: return ix;
215: }
216:
217: private class FindAction extends AbstractAction {
218: public FindAction() {
219: super ("Find");
220: }
221:
222: public void actionPerformed(ActionEvent e) {
223: int pos = target.getCaretPosition();
224: int selstart = target.getSelectionStart();
225: if (selstart < pos && selstart != -1)
226: pos = selstart;
227:
228: String txt = target.getText();
229:
230: String value = findCombo.getSelectedItem().toString();
231: if (value.length() == 0 || pos == txt.length())
232: return;
233:
234: if (!caseCheck.isSelected()) {
235: value = value.toUpperCase();
236: txt = txt.toUpperCase();
237: }
238:
239: int ix = findNext(pos, txt, value);
240:
241: if (ix != -1) {
242: target.select(ix, ix + value.length());
243:
244: for (int c = 0; c < findCombo.getItemCount(); c++) {
245: if (findCombo.getItemAt(c).equals(value)) {
246: findCombo.removeItem(c);
247: break;
248: }
249: }
250:
251: findCombo.insertItemAt(value, 0);
252: } else
253: Toolkit.getDefaultToolkit().beep();
254: }
255: }
256:
257: private class ReplaceAction extends AbstractAction {
258: public ReplaceAction() {
259: super ("Replace");
260: }
261:
262: public void actionPerformed(ActionEvent e) {
263: if (target.getSelectedText() == null)
264: return;
265:
266: String value = replaceCombo.getSelectedItem().toString();
267: int ix = target.getSelectionStart();
268: target.setSelectedText(value);
269: target.select(ix + value.length(), ix);
270:
271: for (int c = 0; c < replaceCombo.getItemCount(); c++) {
272: if (replaceCombo.getItemAt(c).equals(value)) {
273: replaceCombo.removeItem(c);
274: break;
275: }
276: }
277:
278: replaceCombo.insertItemAt(value, 0);
279: }
280: }
281:
282: private class ReplaceAllAction extends AbstractAction {
283: public ReplaceAllAction() {
284: super ("Replace All");
285: }
286:
287: public void actionPerformed(ActionEvent e) {
288: int pos = target.getCaretPosition();
289: String txt = target.getText();
290:
291: String value = findCombo.getSelectedItem().toString();
292: if (value.length() == 0 || txt.length() == 0)
293: return;
294: String newValue = replaceCombo.getSelectedItem().toString();
295:
296: if (!caseCheck.isSelected()) {
297: if (newValue.equalsIgnoreCase(value))
298: return;
299: value = value.toUpperCase();
300: txt = txt.toUpperCase();
301: } else if (newValue.equals(value))
302: return;
303:
304: int ix = findNext(pos, txt, value);
305: int firstIx = ix;
306: int valueInNewValueIx = !caseCheck.isSelected() ? newValue
307: .toUpperCase().indexOf(value) : newValue
308: .indexOf(value);
309:
310: while (ix != -1) {
311: System.out.println("found match at " + ix + ", "
312: + firstIx + ", " + valueInNewValueIx);
313: target.select(ix + value.length(), ix);
314:
315: target.setSelectedText(newValue);
316: target.select(ix + newValue.length(), ix);
317:
318: // adjust firstix
319: if (ix < firstIx)
320: firstIx += newValue.length() - value.length();
321:
322: txt = target.getText();
323: if (!caseCheck.isSelected()) {
324: txt = txt.toUpperCase();
325: }
326:
327: ix = findNext(ix + newValue.length(), txt, value);
328: if (wrapCheck.isSelected() && valueInNewValueIx != -1
329: && ix == firstIx + valueInNewValueIx) {
330: break;
331: }
332: }
333: }
334: }
335:
336: private class CloseAction extends AbstractAction {
337: public CloseAction() {
338: super ("Close");
339: }
340:
341: public void actionPerformed(ActionEvent e) {
342: dialog.setVisible(false);
343: }
344: }
345:
346: }
|