View Javadoc

    1   /*
    2    *  soapUI, copyright (C) 2004-2007 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  {
    43  	private final FindAndReplaceable target;
    44  	private JDialog dialog;
    45  	private JCheckBox caseCheck;
    46  	private JRadioButton allButton;
    47  	private JRadioButton selectedLinesButton;
    48  	private JRadioButton forwardButton;
    49  	private JRadioButton backwardButton;
    50  	private JCheckBox wholeWordCheck;
    51  	private JButton findButton;
    52  	private JButton replaceButton;
    53  	private JButton replaceAllButton;
    54  	private JComboBox findCombo;
    55  	private JComboBox replaceCombo;
    56  	private JCheckBox wrapCheck;
    57
    58  	public FindAndReplaceDialog(FindAndReplaceable target)
    59  	{
    60  		super( "Find / Replace" );
    61  		putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "F3" ));
    62  		this.target = target;
    63  	}
    64
    65  	public void actionPerformed(ActionEvent e)
    66  	{
    67  		show();
    68  	}
    69
    70  	public void show()
    71  	{
    72  		if( dialog == null )
    73  			buildDialog();
    74
    75  		replaceCombo.setEnabled( target.isEditable() );
    76  		replaceAllButton.setEnabled( target.isEditable() );
    77  		replaceButton.setEnabled( target.isEditable() );
    78
    79  		UISupport.showDialog( dialog );
    80  		findCombo.getEditor().selectAll();
    81  		findCombo.requestFocus();
    82  	}
    83
    84  	private void buildDialog()
    85  	{
    86  		dialog = new JDialog( UISupport.getMainFrame(), "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  		// create inputs
    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 		// create direction panel
    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 		// create scope panel
    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 		// create options
    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 		// create panel with options
    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 		// create buttons
    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 		// tie it up!
    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 < target.getSelectionStart() || ix > target.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 = target.getCaretPosition();
    220 			int selstart = target.getSelectionStart();
    221 			if( selstart < pos && selstart != -1 )
    222 				pos = selstart;
    223
    224 			String txt = target.getText();
    225
    226 			String value = findCombo.getSelectedItem().toString();
    227 			if( value.length() == 0 || pos == txt.length() ) return;
    228
    229 			if( !caseCheck.isSelected())
    230 			{
    231 				value = value.toUpperCase();
    232 				txt = txt.toUpperCase();
    233 			}
    234
    235 			int ix = findNext(pos, txt, value);
    236
    237 			if( ix != -1 )
    238 			{
    239 				target.select( ix, ix + value.length());
    240
    241 				for( int c = 0; c < findCombo.getItemCount(); c++ )
    242 				{
    243 					if( findCombo.getItemAt( c ).equals( value ))
    244 					{
    245 						findCombo.removeItem( c );
    246 						break;
    247 					}
    248 				}
    249
    250 				findCombo.insertItemAt( value, 0 );
    251 			}
    252 			else Toolkit.getDefaultToolkit().beep();
    253 		}
    254 	}
    255
    256 	private class ReplaceAction extends AbstractAction
    257 	{
    258 		public ReplaceAction()
    259 		{
    260 			super( "Replace" );
    261 		}
    262
    263 		public void actionPerformed(ActionEvent e)
    264 		{
    265 			if( target.getSelectedText() == null )
    266 				return;
    267
    268 			String value = replaceCombo.getSelectedItem().toString();
    269 			int ix = target.getSelectionStart();
    270 			target.setSelectedText( value );
    271 			target.select( ix+value.length(), ix );
    272
    273 			for( int c = 0; c < replaceCombo.getItemCount(); c++ )
    274 			{
    275 				if( replaceCombo.getItemAt( c ).equals( value ))
    276 				{
    277 					replaceCombo.removeItem( c );
    278 					break;
    279 				}
    280 			}
    281
    282 			replaceCombo.insertItemAt( value, 0 );
    283 		}
    284 	}
    285
    286 	private class ReplaceAllAction extends AbstractAction
    287 	{
    288 		public ReplaceAllAction()
    289 		{
    290 			super( "Replace All" );
    291 		}
    292
    293 		public void actionPerformed(ActionEvent e)
    294 		{
    295 			int pos = target.getCaretPosition();
    296 			String txt = target.getText();
    297
    298 			String value = findCombo.getSelectedItem().toString();
    299 			if( value.length() == 0 || txt.length() == 0 ) return;
    300 			String newValue = replaceCombo.getSelectedItem().toString();
    301
    302 			if( !caseCheck.isSelected() )
    303 			{
    304 				if( newValue.equalsIgnoreCase( value )) return;
    305 				value = value.toUpperCase();
    306 				txt = txt.toUpperCase();
    307 			}
    308 			else if( newValue.equals( value )) return;
    309
    310 			int ix = findNext(pos, txt, value);
    311 			int firstIx = ix;
    312 			int valueInNewValueIx = !caseCheck.isSelected() ? newValue.toUpperCase().indexOf( value ) : newValue.indexOf( value );
    313
    314 			while( ix != -1 )
    315 			{
    316 				System.out.println( "found match at " + ix+ ", " + firstIx + ", " + valueInNewValueIx);
    317 				target.select( ix + value.length(), ix );
    318
    319 				target.setSelectedText( newValue );
    320 				target.select( ix+newValue.length(), ix );
    321
    322 				// adjust firstix
    323 				if( ix < firstIx )
    324 					firstIx += newValue.length()-value.length();
    325
    326 				txt = target.getText();
    327 				if( !caseCheck.isSelected())
    328 				{
    329 					txt = txt.toUpperCase();
    330 				}
    331
    332 				ix = findNext(ix+newValue.length(), txt, value);
    333 				if( wrapCheck.isSelected() && valueInNewValueIx != -1 && ix == firstIx+valueInNewValueIx )
    334 				{
    335 					break;
    336 				}
    337 			}
    338 		}
    339 	}
    340
    341 	private class CloseAction extends AbstractAction
    342 	{
    343 		public CloseAction()
    344 		{
    345 			super( "Close" );
    346 		}
    347
    348 		public void actionPerformed(ActionEvent e)
    349 		{
    350 			dialog.setVisible( false );
    351 		}
    352 	}
    353
    354 }