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