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