View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.support.actions;
14  
15  import java.awt.BorderLayout;
16  import java.awt.GridLayout;
17  import java.awt.Toolkit;
18  import java.awt.event.ActionEvent;
19  
20  import javax.swing.AbstractAction;
21  import javax.swing.Action;
22  import javax.swing.BorderFactory;
23  import javax.swing.ButtonGroup;
24  import javax.swing.JButton;
25  import javax.swing.JCheckBox;
26  import javax.swing.JComboBox;
27  import javax.swing.JDialog;
28  import javax.swing.JLabel;
29  import javax.swing.JPanel;
30  import javax.swing.JRadioButton;
31  
32  import com.eviware.soapui.support.UISupport;
33  import com.jgoodies.forms.builder.ButtonBarBuilder;
34  
35  /***
36   * Find-and-Replace dialog for a JXmlTextArea
37   * 
38   * @author Ole.Matzura
39   */
40  
41  public class FindAndReplaceDialog extends AbstractAction {
42  	private final FindAndReplaceable target;
43  	private JDialog dialog;
44  	private JCheckBox caseCheck;
45  	private JRadioButton allButton;
46  	private JRadioButton selectedLinesButton;
47  	private JRadioButton forwardButton;
48  	private JRadioButton backwardButton;
49  	private JCheckBox wholeWordCheck;
50  	private JButton findButton;
51  	private JButton replaceButton;
52  	private JButton replaceAllButton;
53  	private JComboBox findCombo;
54  	private JComboBox replaceCombo;
55  	private JCheckBox wrapCheck;
56  
57  	public FindAndReplaceDialog(FindAndReplaceable target) {
58  		super("Find / Replace");
59  		putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke("F3"));
60  		this.target = target;
61  	}
62  
63  	public void actionPerformed(ActionEvent e) {
64  		show();
65  	}
66  
67  	public void show() {
68  		if (dialog == null)
69  			buildDialog();
70  
71  		replaceCombo.setEnabled(target.isEditable());
72  		replaceAllButton.setEnabled(target.isEditable());
73  		replaceButton.setEnabled(target.isEditable());
74  
75  		UISupport.showDialog(dialog);
76  		findCombo.getEditor().selectAll();
77  		findCombo.requestFocus();
78  	}
79  
80  	private void buildDialog() {
81  		dialog = new JDialog(UISupport.getMainFrame(), "Find / Replace", false);
82  
83  		JPanel panel = new JPanel(new BorderLayout());
84  		findCombo = new JComboBox();
85  		findCombo.setEditable(true);
86  		replaceCombo = new JComboBox();
87  		replaceCombo.setEditable(true);
88  
89  		// create inputs
90  		GridLayout gridLayout = new GridLayout(2, 2);
91  		gridLayout.setVgap(5);
92  		JPanel inputPanel = new JPanel(gridLayout);
93  		inputPanel.add(new JLabel("Find:"));
94  		inputPanel.add(findCombo);
95  		inputPanel.add(new JLabel("Replace with:"));
96  		inputPanel.add(replaceCombo);
97  		inputPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
98  
99  		// create direction panel
100 		ButtonGroup directionGroup = new ButtonGroup();
101 		forwardButton = new JRadioButton("Forward", true);
102 		forwardButton.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
103 		directionGroup.add(forwardButton);
104 		backwardButton = new JRadioButton("Backward");
105 		backwardButton.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
106 		directionGroup.add(backwardButton);
107 
108 		JPanel directionPanel = new JPanel(new GridLayout(2, 1));
109 		directionPanel.add(forwardButton);
110 		directionPanel.add(backwardButton);
111 		directionPanel.setBorder(BorderFactory.createTitledBorder("Direction"));
112 
113 		// create scope panel
114 		ButtonGroup scopeGroup = new ButtonGroup();
115 		allButton = new JRadioButton("All", true);
116 		allButton.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
117 		selectedLinesButton = new JRadioButton("Selected Lines");
118 		selectedLinesButton.setBorder(BorderFactory.createEmptyBorder(3, 3, 3,
119 				3));
120 		scopeGroup.add(allButton);
121 		scopeGroup.add(selectedLinesButton);
122 
123 		JPanel scopePanel = new JPanel(new GridLayout(2, 1));
124 		scopePanel.add(allButton);
125 		scopePanel.add(selectedLinesButton);
126 		scopePanel.setBorder(BorderFactory.createTitledBorder("Scope"));
127 
128 		// create options
129 		caseCheck = new JCheckBox("Case Sensitive");
130 		caseCheck.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
131 		wholeWordCheck = new JCheckBox("Whole Word");
132 		wholeWordCheck.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
133 		wrapCheck = new JCheckBox("Wrap Search");
134 		wrapCheck.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
135 		JPanel optionsPanel = new JPanel(new GridLayout(3, 1));
136 		optionsPanel.add(caseCheck);
137 		optionsPanel.add(wholeWordCheck);
138 		optionsPanel.add(wrapCheck);
139 		optionsPanel.setBorder(BorderFactory.createTitledBorder("Options"));
140 
141 		// create panel with options
142 		JPanel options = new JPanel(new GridLayout(1, 2));
143 
144 		JPanel radios = new JPanel(new GridLayout(2, 1));
145 		radios.add(directionPanel);
146 		radios.add(scopePanel);
147 
148 		options.add(optionsPanel);
149 		options.add(radios);
150 		options.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8));
151 
152 		// create buttons
153 		ButtonBarBuilder builder = new ButtonBarBuilder();
154 		findButton = new JButton(new FindAction());
155 		builder.addFixed(findButton);
156 		builder.addRelatedGap();
157 		replaceButton = new JButton(new ReplaceAction());
158 		builder.addFixed(replaceButton);
159 		builder.addRelatedGap();
160 		replaceAllButton = new JButton(new ReplaceAllAction());
161 		builder.addFixed(replaceAllButton);
162 		builder.addUnrelatedGap();
163 		builder.addFixed(new JButton(new CloseAction()));
164 		builder.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
165 
166 		// tie it up!
167 		panel.add(inputPanel, BorderLayout.NORTH);
168 		panel.add(options, BorderLayout.CENTER);
169 		panel.add(builder.getPanel(), BorderLayout.SOUTH);
170 
171 		dialog.getContentPane().add(panel);
172 		dialog.pack();
173 		UISupport.initDialogActions(dialog, null, findButton);
174 	}
175 
176 	private int findNext(int pos, String txt, String value) {
177 		int ix = forwardButton.isSelected() ? txt.indexOf(value, pos) : txt
178 				.lastIndexOf(value, pos);
179 
180 		if (wholeWordCheck.isSelected()) {
181 			while (ix != -1
182 					&& (ix > 0 && Character.isLetterOrDigit(txt.charAt(ix - 1)))
183 					|| (ix < txt.length() - value.length() - 1 && Character
184 							.isLetterOrDigit(txt.charAt(ix + value.length())))) {
185 				ix = findNext(ix, txt, value);
186 			}
187 		}
188 
189 		if (ix == -1 && wrapCheck.isSelected()) {
190 			if (forwardButton.isSelected() && pos > 0)
191 				return findNext(0, txt, value);
192 			else if (backwardButton.isSelected() && pos < txt.length() - 1)
193 				return findNext(txt.length() - 1, txt, value);
194 		}
195 
196 		if (selectedLinesButton.isSelected()
197 				&& (ix < target.getSelectionStart() || ix > target
198 						.getSelectionEnd()))
199 			ix = -1;
200 
201 		return ix;
202 	}
203 
204 	private class FindAction extends AbstractAction {
205 		public FindAction() {
206 			super("Find");
207 		}
208 
209 		public void actionPerformed(ActionEvent e) {
210 			int pos = target.getCaretPosition();
211 			int selstart = target.getSelectionStart();
212 			if (selstart < pos && selstart != -1)
213 				pos = selstart;
214 
215 			String txt = target.getText();
216 
217 			if( findCombo.getSelectedItem() == null ) {
218 				return;
219 			}
220 			String value = findCombo.getSelectedItem().toString();
221 			if (value.length() == 0 || pos == txt.length())
222 				return;
223 
224 			if (!caseCheck.isSelected()) {
225 				value = value.toUpperCase();
226 				txt = txt.toUpperCase();
227 			}
228 
229 			int ix = findNext(pos, txt, value);
230 
231 			if (ix != -1) {
232 				target.select(ix, ix + value.length());
233 
234 				for (int c = 0; c < findCombo.getItemCount(); c++) {
235 					if (findCombo.getItemAt(c).equals(value)) {
236 						findCombo.removeItem(c);
237 						break;
238 					}
239 				}
240 
241 				findCombo.insertItemAt(value, 0);
242 			} else
243 				Toolkit.getDefaultToolkit().beep();
244 		}
245 	}
246 
247 	private class ReplaceAction extends AbstractAction {
248 		public ReplaceAction() {
249 			super("Replace");
250 		}
251 
252 		public void actionPerformed(ActionEvent e) {
253 			if (target.getSelectedText() == null)
254 				return;
255 
256 			String value = replaceCombo.getSelectedItem().toString();
257 			int ix = target.getSelectionStart();
258 			target.setSelectedText(value);
259 			target.select(ix + value.length(), ix);
260 
261 			for (int c = 0; c < replaceCombo.getItemCount(); c++) {
262 				if (replaceCombo.getItemAt(c).equals(value)) {
263 					replaceCombo.removeItem(c);
264 					break;
265 				}
266 			}
267 
268 			replaceCombo.insertItemAt(value, 0);
269 		}
270 	}
271 
272 	private class ReplaceAllAction extends AbstractAction {
273 		public ReplaceAllAction() {
274 			super("Replace All");
275 		}
276 
277 		public void actionPerformed(ActionEvent e) {
278 			int pos = target.getCaretPosition();
279 			String txt = target.getText();
280 
281 			if( findCombo.getSelectedItem() == null ) {
282 				return;
283 			}
284 			String value = findCombo.getSelectedItem().toString();
285 			if (value.length() == 0 || txt.length() == 0)
286 				return;
287 			String newValue = replaceCombo.getSelectedItem().toString();
288 
289 			if (!caseCheck.isSelected()) {
290 				if (newValue.equalsIgnoreCase(value))
291 					return;
292 				value = value.toUpperCase();
293 				txt = txt.toUpperCase();
294 			} else if (newValue.equals(value))
295 				return;
296 
297 			int ix = findNext(pos, txt, value);
298 			int firstIx = ix;
299 			int valueInNewValueIx = !caseCheck.isSelected() ? newValue
300 					.toUpperCase().indexOf(value) : newValue.indexOf(value);
301 
302 			while (ix != -1) {
303 				System.out.println("found match at " + ix + ", " + firstIx
304 						+ ", " + valueInNewValueIx);
305 				target.select(ix + value.length(), ix);
306 
307 				target.setSelectedText(newValue);
308 				target.select(ix + newValue.length(), ix);
309 
310 				// adjust firstix
311 				if (ix < firstIx)
312 					firstIx += newValue.length() - value.length();
313 
314 				txt = target.getText();
315 				if (!caseCheck.isSelected()) {
316 					txt = txt.toUpperCase();
317 				}
318 
319 				if (forwardButton.isSelected()) {
320 					ix = findNext(ix + newValue.length(), txt, value);
321 				} else {
322 					ix = findNext(ix -1, txt, value);
323 				}
324 				if (wrapCheck.isSelected() && valueInNewValueIx != -1
325 						&& ix == firstIx + valueInNewValueIx) {
326 					break;
327 				}
328 			}
329 		}
330 	}
331 
332 	private class CloseAction extends AbstractAction {
333 		public CloseAction() {
334 			super("Close");
335 		}
336 
337 		public void actionPerformed(ActionEvent e) {
338 			dialog.setVisible(false);
339 		}
340 	}
341 
342 }