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.impl.wsdl.panels.teststeps;
    14
    15  import java.awt.BorderLayout;
    16  import java.awt.Dimension;
    17  import java.awt.GridLayout;
    18  import java.awt.event.ActionEvent;
    19  import java.awt.event.ItemEvent;
    20  import java.awt.event.ItemListener;
    21  import java.beans.PropertyChangeEvent;
    22  import java.beans.PropertyChangeListener;
    23  import java.util.ArrayList;
    24  import java.util.Arrays;
    25  import java.util.Date;
    26  import java.util.List;
    27
    28  import javax.swing.AbstractAction;
    29  import javax.swing.Action;
    30  import javax.swing.BorderFactory;
    31  import javax.swing.DefaultComboBoxModel;
    32  import javax.swing.DefaultListModel;
    33  import javax.swing.JButton;
    34  import javax.swing.JCheckBox;
    35  import javax.swing.JComboBox;
    36  import javax.swing.JComponent;
    37  import javax.swing.JLabel;
    38  import javax.swing.JList;
    39  import javax.swing.JPanel;
    40  import javax.swing.JScrollPane;
    41  import javax.swing.JSplitPane;
    42  import javax.swing.JTextArea;
    43  import javax.swing.ListSelectionModel;
    44  import javax.swing.event.ChangeEvent;
    45  import javax.swing.event.ChangeListener;
    46  import javax.swing.event.ListSelectionEvent;
    47  import javax.swing.event.ListSelectionListener;
    48  import javax.swing.table.AbstractTableModel;
    49  import javax.swing.text.Document;
    50
    51  import org.jdesktop.swingx.JXTable;
    52
    53  import com.eviware.soapui.SoapUI;
    54  import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
    55  import com.eviware.soapui.impl.wsdl.panels.support.TestRunComponentEnabler;
    56  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
    57  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
    58  import com.eviware.soapui.impl.wsdl.teststeps.PropertyTransfer;
    59  import com.eviware.soapui.impl.wsdl.teststeps.TransferResponseValuesTestStep;
    60  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequest;
    61  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep;
    62  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStep;
    63  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStepListener;
    64  import com.eviware.soapui.impl.wsdl.teststeps.TransferResponseValuesTestStep.ValueTransferResult;
    65  import com.eviware.soapui.model.ModelItem;
    66  import com.eviware.soapui.model.support.TestRunListenerAdapter;
    67  import com.eviware.soapui.model.support.TestSuiteListenerAdapter;
    68  import com.eviware.soapui.model.testsuite.TestRunContext;
    69  import com.eviware.soapui.model.testsuite.TestRunner;
    70  import com.eviware.soapui.model.testsuite.TestStep;
    71  import com.eviware.soapui.model.testsuite.TestStepProperty;
    72  import com.eviware.soapui.model.testsuite.TestStepResult;
    73  import com.eviware.soapui.support.DocumentListenerAdapter;
    74  import com.eviware.soapui.support.UISupport;
    75  import com.eviware.soapui.support.components.JComponentInspector;
    76  import com.eviware.soapui.support.components.JInspectorPanel;
    77  import com.eviware.soapui.support.components.JUndoableTextArea;
    78  import com.eviware.soapui.support.components.JXToolBar;
    79  import com.eviware.soapui.support.xml.XmlUtils;
    80  import com.eviware.soapui.ui.desktop.DesktopPanel;
    81  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
    82
    83  /***
    84   * DesktopPanel for TransferResponseValuesTestStep
    85   *
    86   * @author Ole.Matzura
    87   */
    88
    89  public class TransferResponseValuesDesktopPanel extends ModelItemDesktopPanel<TransferResponseValuesTestStep>
    90  {
    91  	private final TransferResponseValuesTestStep transferStep;
    92  	private DefaultListModel listModel;
    93  	private JList transferList;
    94  	private JTextArea sourceArea;
    95  	private JTextArea targetArea;
    96  	private JButton copyButton;
    97  	private JButton deleteButton;
    98  	private JButton declareButton;
    99  	private JComboBox sourcePropertyCombo;
    100 	private JComboBox targetPropertyCombo;
    101 	private JComboBox sourceStepCombo;
    102 	private JComboBox targetStepCombo;
    103 	private DefaultComboBoxModel sourceStepModel;
    104 	private DefaultComboBoxModel targetStepModel;
    105 	private TestStepNameListener sourceTestStepNameListener;
    106 	private TestStepNameListener targetStepNameListener;
    107 	private TestStepPropertiesListener sourceStepPropertiesListener;
    108 	private TestStepPropertiesListener targetStepPropertiesListener;
    109 	private TransferPropertyChangeListener transferPropertyChangeListener = new TransferPropertyChangeListener();
    110 	private boolean selecting;
    111 	private InternalTestSuiteListener testSuiteListener;
    112 	private TestRunComponentEnabler componentEnabler;
    113 	private JCheckBox failTransferCheckBox;
    114 	private JButton runButton;
    115 	private JButton renameButton;
    116 	private JCheckBox setNullCheckBox;
    117 	private JCheckBox transferTextContentCheckBox;
    118 	private JCheckBox ignoreEmptyCheckBox;
    119 	private JCheckBox transferAllCheckBox;
    120 	private DesktopPanel resultDesktopPanel;
    121 	private TransfersTableModel transfersTableModel;
    122 	private InternalTestRunListener testRunListener;
    123 	private JComponentInspector logInspector;
    124 	private JCheckBox useXQueryCheckBox;
    125 	private JButton runAllButton;
    126 	private JInspectorPanel inspectorPanel;
    127
    128 	public TransferResponseValuesDesktopPanel(TransferResponseValuesTestStep testStep)
    129 	{
    130 		super( testStep );
    131 		this.transferStep = testStep;
    132 		componentEnabler = new TestRunComponentEnabler( testStep.getTestCase() );
    133
    134 		buildUI();
    135
    136 		testSuiteListener = new InternalTestSuiteListener();
    137 		transferStep.getTestCase().getTestSuite().addTestSuiteListener( testSuiteListener );
    138
    139 		testRunListener = new InternalTestRunListener();
    140 		transferStep.getTestCase().addTestRunListener( testRunListener );
    141 	}
    142
    143 	protected void buildUI()
    144 	{
    145 		JSplitPane splitPane = UISupport.createHorizontalSplit();
    146
    147 		listModel = new DefaultListModel();
    148
    149 		for( int c = 0; c < transferStep.getTransferCount(); c++ )
    150 		{
    151 			listModel.addElement( transferStep.getTransferAt( c  ).getName() );
    152 		}
    153
    154 		transferList = new JList( listModel );
    155 		transferList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
    156 		transferList.addListSelectionListener( new TransferListSelectionListener());
    157 		componentEnabler.add( transferList );
    158
    159 		JScrollPane listScrollPane = new JScrollPane( transferList );
    160 		UISupport.addTitledBorder( listScrollPane, "Transfers" );
    161
    162 		JPanel p = new JPanel( new BorderLayout() );
    163 		p.add( listScrollPane, BorderLayout.CENTER );
    164 		p.add( createPropertiesToolbar(), BorderLayout.NORTH );
    165
    166 		splitPane.setLeftComponent( p );
    167
    168 		JSplitPane innerSplit = UISupport.createVerticalSplit();
    169 		innerSplit.setBorder( null );
    170 		sourceArea = new JUndoableTextArea();
    171 		sourceArea.setToolTipText( "XPath selection from source property" );
    172 		sourceArea.setEnabled( false );
    173 		sourceArea.getDocument().addDocumentListener( new SourceAreaDocumentListener());
    174 		componentEnabler.add( sourceArea );
    175
    176 		targetArea = new JUndoableTextArea();
    177 		targetArea.setToolTipText( "XPath target in target property" );
    178 		targetArea.setEnabled( false );
    179 		targetArea.getDocument().addDocumentListener( new TargetAreaDocumentListener());
    180 		componentEnabler.add( targetArea );
    181
    182 		JPanel sourcePanel = new JPanel( new BorderLayout() );
    183 		sourcePanel.add( new JScrollPane( sourceArea ), BorderLayout.CENTER );
    184 		JXToolBar toolbar = createSourceToolbar();
    185 		sourcePanel.add( toolbar, BorderLayout.NORTH );
    186 		sourcePanel.setBorder( BorderFactory.createEmptyBorder( 0, 3, 3, 3 ));
    187 		innerSplit.setTopComponent( sourcePanel );
    188
    189 		JPanel targetPanel = new JPanel( new BorderLayout() );
    190 		targetPanel.add( new JScrollPane( targetArea ), BorderLayout.CENTER );
    191 		toolbar = createTargetToolbar();
    192 		targetPanel.add( toolbar, BorderLayout.NORTH );
    193 		targetPanel.setBorder( BorderFactory.createEmptyBorder( 0, 3, 3, 3 ));
    194
    195 		innerSplit.setBottomComponent( targetPanel );
    196
    197 		innerSplit.setResizeWeight( 0.5 );
    198 		innerSplit.setDividerLocation( 0.5 );
    199
    200 		JPanel panel = createTransferOptions();
    201
    202 		JPanel innerPanel = new JPanel( new BorderLayout() );
    203 		innerPanel.add( innerSplit, BorderLayout.CENTER );
    204 		innerPanel.add( panel, BorderLayout.SOUTH );
    205 		innerPanel.add( createConfigToolbar(), BorderLayout.NORTH );
    206
    207 		splitPane.setRightComponent( innerPanel );
    208 		splitPane.setResizeWeight( 0.1 );
    209 		splitPane.setDividerLocation( 120 );
    210
    211 		inspectorPanel = new JInspectorPanel( splitPane );
    212 		logInspector = new JComponentInspector( buildLog(), "Transfer Log (0)", "A log of performed transfers while the editor was open", true );
    213 		inspectorPanel.addInspector( logInspector );
    214 		add( inspectorPanel, BorderLayout.CENTER );
    215
    216 		setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ));
    217 		setPreferredSize( new Dimension( 550, 400 ));
    218
    219 		if( listModel.getSize() > 0 )
    220 			transferList.setSelectedIndex( 0 );
    221
    222 		componentEnabler.add( deleteButton );
    223 		componentEnabler.add( declareButton );
    224 		componentEnabler.add( runButton );
    225 		componentEnabler.add( runAllButton );
    226 		componentEnabler.add( copyButton );
    227 		componentEnabler.add( renameButton );
    228 		componentEnabler.add( failTransferCheckBox );
    229 		componentEnabler.add( setNullCheckBox );
    230 		componentEnabler.add( transferTextContentCheckBox );
    231 		componentEnabler.add( ignoreEmptyCheckBox );
    232 		componentEnabler.add( transferAllCheckBox );
    233 		componentEnabler.add( useXQueryCheckBox );
    234 	}
    235
    236 	private JComponent buildLog()
    237 	{
    238 		JPanel logPanel = new JPanel( new BorderLayout() );
    239
    240 		transfersTableModel = new TransfersTableModel();
    241 		JXTable table = new JXTable( transfersTableModel );
    242
    243 		table.setHorizontalScrollEnabled( true );
    244 		table.packAll();
    245
    246 		JXToolBar toolbar = UISupport.createSmallToolbar();
    247 		toolbar.add( new ClearLogAction() );
    248
    249 		JScrollPane scrollPane = new JScrollPane( table);
    250 		scrollPane.setBorder( BorderFactory.createCompoundBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ),
    251 					scrollPane.getBorder() ));
    252
    253 		logPanel.add( toolbar, BorderLayout.NORTH );
    254 		logPanel.add( scrollPane, BorderLayout.CENTER );
    255
    256 		return logPanel;
    257 	}
    258
    259 	protected JXToolBar createPropertiesToolbar()
    260 	{
    261 		JXToolBar toolbar = UISupport.createSmallToolbar();
    262 		toolbar.addFixed( new JButton( new AddAction() ) );
    263 		deleteButton = new JButton( new DeleteAction() );
    264 		deleteButton.setEnabled( false );
    265 		toolbar.addFixed( deleteButton);
    266 		copyButton = new JButton( new CopyAction() );
    267 		copyButton.setEnabled( false );
    268 		toolbar.addFixed( copyButton);
    269 		renameButton = new JButton( new RenameAction() );
    270 		renameButton.setEnabled( false );
    271 		toolbar.addFixed( renameButton);
    272 		return toolbar;
    273 	}
    274
    275 	protected JXToolBar createConfigToolbar()
    276 	{
    277 		JXToolBar toolbar = UISupport.createToolbar();
    278
    279 		toolbar.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
    280
    281 		runButton = new JButton( new RunAction() );
    282 		runButton.setEnabled( transferList.getSelectedIndex() != -1 );
    283 		toolbar.addFixed( runButton);
    284
    285 		runAllButton = new JButton( new RunAllAction() );
    286 		runAllButton.setEnabled( transferStep.getTransferCount() > 0 );
    287 		toolbar.addFixed( runAllButton);
    288
    289 		declareButton = new JButton( new DeclareNamespacesAction() );
    290 		declareButton.setEnabled( false );
    291 		toolbar.addFixed( declareButton);
    292 		toolbar.addGlue();
    293 		toolbar.addFixed( UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.TRANSFERSTEPEDITOR_HELP_URL )));
    294 		return toolbar;
    295 	}
    296
    297 	protected JPanel createTransferOptions()
    298 	{
    299 		JPanel panel = new JPanel( new GridLayout( 3, 2 ));
    300 		failTransferCheckBox = new JCheckBox( "Fail transfer on error", false );
    301 		failTransferCheckBox.setToolTipText( "Fails the Property Transfer Step if an error occurs" );
    302 		failTransferCheckBox.addChangeListener( new ChangeListener() {
    303
    304 			public void stateChanged(ChangeEvent e)
    305 			{
    306 				PropertyTransfer currentTransfer = getCurrentTransfer();
    307 				if( currentTransfer != null )
    308 				{
    309 					currentTransfer.setFailOnError( failTransferCheckBox.isSelected() );
    310 				}
    311 			}} );
    312
    313 		setNullCheckBox = new JCheckBox( "Set null on missing source", false );
    314 		setNullCheckBox.setToolTipText( "Will set target to null if source is missing or null" );
    315 		setNullCheckBox.addChangeListener( new ChangeListener() {
    316
    317 			public void stateChanged(ChangeEvent e)
    318 			{
    319 				PropertyTransfer currentTransfer = getCurrentTransfer();
    320 				if( currentTransfer != null )
    321 				{
    322 					currentTransfer.setSetNullOnMissingSource( setNullCheckBox.isSelected() );
    323 				}
    324 			}} );
    325
    326 		transferTextContentCheckBox = new JCheckBox( "Transfer text content", false );
    327 		transferTextContentCheckBox.setToolTipText( "Will only transfer text content of source/target elements" );
    328 		transferTextContentCheckBox.addChangeListener( new ChangeListener() {
    329
    330 			public void stateChanged(ChangeEvent e)
    331 			{
    332 				PropertyTransfer currentTransfer = getCurrentTransfer();
    333 				if( currentTransfer != null )
    334 				{
    335 					currentTransfer.setTransferTextContent( transferTextContentCheckBox.isSelected() );
    336 				}
    337 			}} );
    338
    339 		ignoreEmptyCheckBox = new JCheckBox( "Ignore empty/missing values", false );
    340 		ignoreEmptyCheckBox.setToolTipText( "Will not transfer empty or missing values" );
    341 		ignoreEmptyCheckBox.addChangeListener( new ChangeListener() {
    342
    343 			public void stateChanged(ChangeEvent e)
    344 			{
    345 				PropertyTransfer currentTransfer = getCurrentTransfer();
    346 				if( currentTransfer != null )
    347 				{
    348 					currentTransfer.setIgnoreEmpty( ignoreEmptyCheckBox.isSelected() );
    349 				}
    350 			}} );
    351
    352 		transferAllCheckBox = new JCheckBox( "Transfer to all", false );
    353 		transferAllCheckBox.setToolTipText( "Will transfer to all matching target selections" );
    354 		transferAllCheckBox.addChangeListener( new ChangeListener() {
    355
    356 			public void stateChanged(ChangeEvent e)
    357 			{
    358 				PropertyTransfer currentTransfer = getCurrentTransfer();
    359 				if( currentTransfer != null )
    360 				{
    361 					currentTransfer.setTransferToAll( transferAllCheckBox.isSelected() );
    362 				}
    363 			}} );
    364
    365 		useXQueryCheckBox = new JCheckBox( "Use XQuery", false );
    366 		useXQueryCheckBox.setToolTipText( "Interprets the source xpath as an XQuery expression" );
    367 		useXQueryCheckBox.addChangeListener( new ChangeListener() {
    368
    369 			public void stateChanged(ChangeEvent e)
    370 			{
    371 				PropertyTransfer currentTransfer = getCurrentTransfer();
    372 				if( currentTransfer != null )
    373 				{
    374 					currentTransfer.setUseXQuery( useXQueryCheckBox.isSelected() );
    375 				}
    376 			}} );
    377
    378 		panel.add( failTransferCheckBox );
    379 		panel.add( setNullCheckBox );
    380 		panel.add( transferTextContentCheckBox );
    381 		panel.add( ignoreEmptyCheckBox );
    382 		panel.add( transferAllCheckBox );
    383 		panel.add( useXQueryCheckBox );
    384 		panel.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
    385 		return panel;
    386 	}
    387
    388 	protected JXToolBar createTargetToolbar()
    389 	{
    390 		JXToolBar toolbar;
    391 		toolbar = UISupport.createToolbar();
    392 		toolbar.addSpace( 3 );
    393 		toolbar.addFixed( new JLabel( "<html><b>Target:</b></html>"));
    394 		toolbar.addGlue();
    395
    396 		targetStepCombo.setSelectedItem( null );
    397 		targetStepCombo.setToolTipText( "The step the value will be transferred to" );
    398 		targetStepCombo.setEnabled( false );
    399 		targetStepCombo.addItemListener(
    400 				new StepComboItemListener( targetPropertyCombo, targetStepPropertiesListener ) );
    401 		targetStepCombo.addItemListener( new ItemListener() {
    402
    403 			public void itemStateChanged(ItemEvent e)
    404 			{
    405 				if( e.getStateChange() == ItemEvent.SELECTED && !selecting )
    406 				{
    407 					String targetStep = (String) targetStepCombo.getSelectedItem();
    408 					PropertyTransfer valueTransfer = getCurrentTransfer();
    409
    410 					if( valueTransfer != null )
    411 					{
    412 						valueTransfer.setTargetStepName( targetStep );
    413 					}
    414 				}
    415 			}} );
    416
    417 		toolbar.addFixed( new JLabel( "Step:"));
    418 		toolbar.addRelatedGap();
    419 		toolbar.add( targetStepCombo );
    420 		toolbar.addRelatedGap();
    421
    422 		toolbar.addFixed( new JLabel( "Property:"));
    423 		toolbar.addRelatedGap();
    424
    425 		targetPropertyCombo.setToolTipText( "The property the value will be transferred to" );
    426 		targetPropertyCombo.setEnabled( false );
    427 		targetPropertyCombo.addItemListener( new ItemListener() {
    428
    429 			public void itemStateChanged(ItemEvent e)
    430 			{
    431 				if( e.getStateChange() == ItemEvent.SELECTED && !selecting )
    432 				{
    433 					String targetProperty = (String) targetPropertyCombo.getSelectedItem();
    434 					PropertyTransfer valueTransfer = getCurrentTransfer();
    435
    436 					if( valueTransfer != null )
    437 					{
    438 						valueTransfer.setTargetPropertyName( targetProperty );
    439 					}
    440 				}
    441 			}} );
    442
    443 		toolbar.add( targetPropertyCombo);
    444 		return toolbar;
    445 	}
    446
    447 	protected JXToolBar createSourceToolbar()
    448 	{
    449 		JXToolBar toolbar = UISupport.createToolbar();
    450 		toolbar.addSpace( 3 );
    451 		toolbar.addFixed( new JLabel( "<html><b>Source:</b></html>"));
    452 		toolbar.addGlue();
    453
    454 		sourcePropertyCombo = new JComboBox();
    455 		sourceStepModel = new DefaultComboBoxModel();
    456 		sourceStepCombo = new JComboBox( sourceStepModel );
    457 		sourceTestStepNameListener = new TestStepNameListener( sourceStepModel );
    458
    459 		componentEnabler.add( sourcePropertyCombo );
    460 		componentEnabler.add( sourceStepCombo );
    461
    462 		targetPropertyCombo = new JComboBox();
    463 		targetStepModel = new DefaultComboBoxModel();
    464 		targetStepCombo = new JComboBox( targetStepModel );
    465 		targetStepNameListener = new TestStepNameListener( targetStepModel );
    466
    467 		componentEnabler.add( targetPropertyCombo );
    468 		componentEnabler.add( targetStepCombo );
    469
    470 		sourceStepPropertiesListener = new TestStepPropertiesListener( sourcePropertyCombo );
    471 		targetStepPropertiesListener = new TestStepPropertiesListener( targetPropertyCombo );
    472
    473 		for( int c = 0; c < transferStep.getTestCase().getTestStepCount(); c++ )
    474 		{
    475 			WsdlTestStep testStep = (WsdlTestStep) transferStep.getTestCase().getTestStepAt( c );
    476 			if( testStep == transferStep )
    477 				continue;
    478
    479 			testStep.addPropertyChangeListener( TestStep.NAME_PROPERTY, sourceTestStepNameListener);
    480 			testStep.addPropertyChangeListener( TestStep.NAME_PROPERTY, targetStepNameListener);
    481
    482 			String nm = testStep.getName();
    483 			sourceStepModel.addElement( nm );
    484 			targetStepModel.addElement( nm );
    485 		}
    486
    487 		sourceStepCombo.setSelectedItem( null );
    488 		sourceStepCombo.setToolTipText( "The step the value will be transferred from" );
    489 		sourceStepCombo.setEnabled( false );
    490 		sourceStepCombo.addItemListener(
    491 				new StepComboItemListener( sourcePropertyCombo, sourceStepPropertiesListener ) );
    492 		sourceStepCombo.addItemListener( new ItemListener() {
    493
    494 			public void itemStateChanged(ItemEvent e)
    495 			{
    496 				if( e.getStateChange() == ItemEvent.SELECTED && !selecting )
    497 				{
    498 					String sourceStep = (String) sourceStepCombo.getSelectedItem();
    499 					PropertyTransfer valueTransfer = getCurrentTransfer();
    500
    501 					if( valueTransfer != null )
    502 					{
    503 						valueTransfer.setSourceStepName( sourceStep );
    504 					}
    505 				}
    506 			}} );
    507
    508 		toolbar.addFixed( new JLabel( "Step:"));
    509 		toolbar.addRelatedGap();
    510 		toolbar.add( sourceStepCombo );
    511 		toolbar.addRelatedGap();
    512
    513 		toolbar.addFixed( new JLabel( "Property:"));
    514 		toolbar.addRelatedGap();
    515
    516 		sourcePropertyCombo.setToolTipText( "The property the value will be transferred from" );
    517 		sourcePropertyCombo.setEnabled( false );
    518 		sourcePropertyCombo.addItemListener( new ItemListener() {
    519
    520 			public void itemStateChanged(ItemEvent e)
    521 			{
    522 				if( e.getStateChange() == ItemEvent.SELECTED && !selecting )
    523 				{
    524 					String sourceProperty = (String) sourcePropertyCombo.getSelectedItem();
    525 					PropertyTransfer valueTransfer = getCurrentTransfer();
    526
    527 					if( valueTransfer != null )
    528 					{
    529 						valueTransfer.setSourcePropertyName( sourceProperty );
    530 					}
    531 				}
    532 			}} );
    533
    534 		toolbar.add( sourcePropertyCombo);
    535 		return toolbar;
    536 	}
    537
    538 	public PropertyTransfer getCurrentTransfer()
    539 	{
    540 		int ix = transferList.getSelectedIndex();
    541 		return ix == -1 ? null : transferStep.getTransferAt( ix );
    542 	}
    543
    544 	/***
    545 	 * Listen for testStep property changes and update properties combo accordingly
    546 	 */
    547
    548 	private static final class TestStepPropertiesListener implements WsdlTestStepListener
    549 	{
    550 		private final JComboBox combo;
    551
    552 		public TestStepPropertiesListener(JComboBox combo)
    553 		{
    554 			this.combo = combo;
    555 		}
    556
    557 		public void propertyAdded(String name)
    558 		{
    559 			combo.addItem( name );
    560 			combo.setEnabled( true );
    561 		}
    562
    563 		public void propertyRemoved(String name)
    564 		{
    565 			if( combo.getSelectedItem().equals( name ))
    566 				combo.setSelectedItem( null );
    567
    568 			combo.removeItem( name );
    569 			combo.setEnabled( combo.getItemCount() > 0 );
    570 		}
    571
    572 		public void propertyRenamed(String oldName, String newName)
    573 		{
    574 			DefaultComboBoxModel model = (DefaultComboBoxModel) combo.getModel();
    575
    576 			int stepIndex = model.getIndexOf( oldName );
    577 			if( stepIndex != -1 )
    578 			{
    579 				Object selectedItem = model.getSelectedItem();
    580
    581 				model.removeElementAt( stepIndex );
    582 				model.insertElementAt( newName, stepIndex );
    583
    584 				// ensure selection
    585 				if( selectedItem.equals( oldName ) )
    586 					model.setSelectedItem( newName );
    587 			}
    588 		}
    589
    590 		public void propertyValueChanged(String name, String oldValue, String newValue)
    591 		{
    592 		}
    593 	}
    594
    595 	/***
    596 	 * Listen for teststep changes and update source/target step combos accordingly
    597 	 */
    598
    599 	private final class InternalTestSuiteListener extends TestSuiteListenerAdapter
    600 	{
    601 		public void testStepAdded(TestStep testStep, int index)
    602 		{
    603 			if( testStep.getTestCase() == transferStep.getTestCase() )
    604 			{
    605 				sourceStepModel.addElement( testStep.getName() );
    606 				targetStepModel.addElement( testStep.getName() );
    607
    608 				testStep.addPropertyChangeListener( TestStep.NAME_PROPERTY, sourceTestStepNameListener);
    609 				testStep.addPropertyChangeListener( TestStep.NAME_PROPERTY, targetStepNameListener);
    610 			}
    611 		}
    612
    613 		public void testStepMoved(TestStep testStep, int fromIndex, int offset)
    614 		{
    615 			if( testStep.getTestCase() == transferStep.getTestCase() )
    616 			{
    617 				String testStepName = testStep.getName();
    618 				if( sourceStepModel.getIndexOf( testStepName ) == fromIndex )
    619 				{
    620 					String sourceStep = ( String ) sourceStepCombo.getSelectedItem();
    621 					String sourceProperty = ( String ) sourcePropertyCombo.getSelectedItem();
    622
    623 					sourceStepModel.removeElementAt( fromIndex );
    624 					if( fromIndex + offset > sourceStepModel.getSize() )
    625 						sourceStepModel.addElement( testStepName );
    626 					else
    627 						sourceStepModel.insertElementAt( testStepName, fromIndex + offset );
    628
    629 					sourceStepCombo.setSelectedItem( sourceStep );
    630 					sourcePropertyCombo.setSelectedItem( sourceProperty );
    631 				}
    632
    633 				if( targetStepModel.getIndexOf( testStepName ) == fromIndex )
    634 				{
    635 					String targetStep = ( String ) targetStepCombo.getSelectedItem();
    636 					String targetProperty = ( String ) targetPropertyCombo.getSelectedItem();
    637
    638 					targetStepModel.removeElementAt( fromIndex );
    639 					if( fromIndex + offset > targetStepModel.getSize() )
    640 						targetStepModel.addElement( testStepName );
    641 					else
    642 						targetStepModel.insertElementAt( testStepName, fromIndex + offset );
    643
    644 					targetStepCombo.setSelectedItem( targetStep );
    645 					targetPropertyCombo.setSelectedItem( targetProperty );
    646 				}
    647 			}
    648 		}
    649
    650 		public void testStepRemoved(TestStep testStep, int index)
    651 		{
    652 			if( testStep.getTestCase() == transferStep.getTestCase() )
    653 			{
    654 				sourceStepModel.removeElement( testStep.getName() );
    655 				targetStepModel.removeElement( testStep.getName() );
    656
    657 				testStep.removePropertyChangeListener( TestStep.NAME_PROPERTY, sourceTestStepNameListener);
    658 				testStep.removePropertyChangeListener( TestStep.NAME_PROPERTY, targetStepNameListener);
    659 			}
    660 		}
    661 	}
    662
    663 	/***
    664 	 * Listen for testStep name changes and modify comboBox model accordingly
    665 	 */
    666
    667 	private final class TestStepNameListener implements PropertyChangeListener
    668 	{
    669 		private final DefaultComboBoxModel model;
    670
    671 		public TestStepNameListener(DefaultComboBoxModel model)
    672 		{
    673 			this.model = model;
    674 		}
    675
    676 		public void propertyChange(PropertyChangeEvent evt)
    677 		{
    678 			Object oldItem = evt.getOldValue();
    679 			int stepIndex = model.getIndexOf( oldItem );
    680 			if( stepIndex != -1 )
    681 			{
    682 				Object selectedItem = model.getSelectedItem();
    683 				Object newItem = evt.getNewValue();
    684
    685 				selecting = true;
    686 				model.removeElementAt( stepIndex );
    687 				model.insertElementAt( newItem, stepIndex );
    688 				selecting = false;
    689
    690 				// ensure selection
    691 				if( selectedItem.equals( oldItem ) )
    692 					model.setSelectedItem( newItem );
    693 			}
    694 		}
    695 	}
    696
    697 	/***
    698 	 * Listen to step selections and update properties combo accordingly
    699 	 */
    700
    701 	private final class StepComboItemListener implements ItemListener
    702 	{
    703 		private final JComboBox propertyCombo;
    704 		private final TestStepPropertiesListener testStepPropertiesListener;
    705
    706 		public StepComboItemListener(final JComboBox propertyCombo, TestStepPropertiesListener testStepPropertiesListener)
    707 		{
    708 			this.propertyCombo = propertyCombo;
    709 			this.testStepPropertiesListener = testStepPropertiesListener;
    710 		}
    711
    712 		public void itemStateChanged(ItemEvent e)
    713 		{
    714 			if( e.getStateChange() == ItemEvent.DESELECTED )
    715 			{
    716 				WsdlTestStep step = (WsdlTestStep) transferStep.getTestCase().getTestStepByName( (String) e.getItem() );
    717 				if( step != null )
    718 					step.removeTestStepListener( testStepPropertiesListener );
    719 			}
    720
    721 			if( e.getStateChange() == ItemEvent.SELECTED )
    722 			{
    723 				String selectedItem = (String) e.getItem();
    724 				WsdlTestStep step = (WsdlTestStep) transferStep.getTestCase().getTestStepByName( selectedItem );
    725
    726 				String[] propertyNames = step == null ? new String[0] : step.getPropertyNames();
    727
    728 				// remove read-only properties from target property
    729 				if( propertyCombo == targetPropertyCombo )
    730 				{
    731 					List<String> names = new ArrayList<String>();
    732 					for( String name : propertyNames )
    733 					{
    734 						TestStepProperty property = step.getProperty( name );
    735 						if( !property.isReadOnly() )
    736 							names.add( property.getName() );
    737 					}
    738
    739 					propertyNames = names.toArray( new String[names.size()] );
    740 				}
    741
    742 				propertyCombo.setModel( new DefaultComboBoxModel( propertyNames ));
    743 				propertyCombo.setEnabled( propertyNames.length > 0 );
    744
    745 				if( propertyCombo == targetPropertyCombo )
    746 					propertyCombo.setSelectedItem( getCurrentTransfer().getTargetPropertyName() );
    747 				else
    748 					propertyCombo.setSelectedItem( getCurrentTransfer().getSourcePropertyName() );
    749
    750 				step.addTestStepListener( testStepPropertiesListener );
    751 			}
    752 			else
    753 			{
    754 				propertyCombo.removeAllItems();
    755 				propertyCombo.setEnabled( false );
    756 			}
    757 		}
    758 	}
    759
    760 	/***
    761 	 * Handle updates to source path
    762 	 */
    763
    764 	private final class SourceAreaDocumentListener extends DocumentListenerAdapter
    765 	{
    766 		public void update(Document document)
    767 		{
    768 			int ix = transferList.getSelectedIndex();
    769 			if( ix != -1 )
    770 			{
    771 				transferStep.getTransferAt( ix ).setSourcePath( sourceArea.getText() );
    772 			}
    773 		}
    774 	}
    775
    776 	/***
    777 	 * Handle updates to target path
    778 	 */
    779
    780 	private final class TargetAreaDocumentListener extends DocumentListenerAdapter
    781 	{
    782 		public void update( Document document )
    783 		{
    784 			int ix = transferList.getSelectedIndex();
    785 			if( ix != -1 )
    786 			{
    787 				transferStep.getTransferAt( ix ).setTargetPath( targetArea.getText() );
    788 			}
    789 		}
    790 	}
    791
    792 	/***
    793 	 * Listen to selection changes in transfer list and update controls accordingly
    794 	 */
    795
    796 	private final class TransferListSelectionListener implements ListSelectionListener
    797 	{
    798 		private PropertyTransfer transfer;
    799
    800 		public void valueChanged(ListSelectionEvent e)
    801 		{
    802 			selecting = true;
    803
    804 			if( transfer != null )
    805 			{
    806 				transfer.removePropertyChangeListener( transferPropertyChangeListener );
    807 			}
    808
    809 			transfer = getCurrentTransfer();
    810
    811 			if( transfer == null )
    812 			{
    813 				sourceArea.setText( "" );
    814 				targetArea.setText( "" );
    815
    816 				sourcePropertyCombo.removeAllItems();
    817 				targetPropertyCombo.removeAllItems();
    818
    819 				sourceStepCombo.setSelectedIndex( -1 );
    820 				targetStepCombo.setSelectedIndex( -1 );
    821 			}
    822 			else
    823 			{
    824 				transfer.addPropertyChangeListener( transferPropertyChangeListener );
    825
    826 				sourceArea.setText( transfer.getSourcePath() );
    827 				targetArea.setText( transfer.getTargetPath() );
    828
    829 				sourceStepCombo.setSelectedItem( transfer.getSourceStepName() );
    830 				sourcePropertyCombo.setSelectedItem( transfer.getSourcePropertyName() );
    831
    832 				targetStepCombo.setSelectedItem( transfer.getTargetStepName() );
    833 				targetPropertyCombo.setSelectedItem( transfer.getTargetPropertyName() );
    834
    835 				failTransferCheckBox.setSelected( transfer.getFailOnError() );
    836 				setNullCheckBox.setSelected( transfer.getSetNullOnMissingSource() );
    837 				transferTextContentCheckBox.setSelected( transfer.getTransferTextContent() );
    838 				ignoreEmptyCheckBox.setSelected( transfer.getIgnoreEmpty() );
    839 				transferAllCheckBox.setSelected( transfer.getTransferToAll() );
    840 				useXQueryCheckBox.setSelected( transfer.getUseXQuery() );
    841 			}
    842
    843 			copyButton.setEnabled( transfer != null );
    844 			renameButton.setEnabled( transfer != null );
    845 			deleteButton.setEnabled( transfer != null );
    846 			declareButton.setEnabled( transfer != null );
    847 			sourceStepCombo.setEnabled( transfer != null );
    848 			targetStepCombo.setEnabled( transfer != null );
    849 			sourceArea.setEnabled( transfer != null );
    850 			targetArea.setEnabled( transfer != null );
    851 			failTransferCheckBox.setEnabled( transfer != null );
    852 			setNullCheckBox.setEnabled( transfer != null );
    853 			transferTextContentCheckBox.setEnabled( transfer != null );
    854 			ignoreEmptyCheckBox.setEnabled( transfer != null );
    855 			transferAllCheckBox.setEnabled( transfer != null );
    856 			useXQueryCheckBox.setEnabled( transfer != null );
    857
    858 			runAllButton.setEnabled( transferList.getModel().getSize() > 0 );
    859 			runButton.setEnabled( transfer != null );
    860
    861 			sourcePropertyCombo.setEnabled( transfer != null );
    862 			targetPropertyCombo.setEnabled( transfer != null );
    863
    864 			selecting = false;
    865 		}
    866 	}
    867
    868 	/***
    869 	 * Listen to property changes and update UI objects. These may have been triggered by UI so first check
    870 	 * for actual difference so we dont end up in loop.
    871 	 */
    872
    873 	private class TransferPropertyChangeListener implements PropertyChangeListener
    874 	{
    875 		public void propertyChange(PropertyChangeEvent evt)
    876 		{
    877 			Object newValue = evt.getNewValue();
    878
    879 			if( evt.getPropertyName().equals( PropertyTransfer.SOURCE_PATH_PROPERTY ))
    880 			{
    881 				if( !sourceArea.getText().equals( newValue ))
    882 					sourceArea.setText( (String) newValue );
    883 			}
    884 			else if( evt.getPropertyName().equals( PropertyTransfer.TARGET_PATH_PROPERTY ))
    885 			{
    886 				if( !targetArea.getText().equals( newValue ))
    887 					targetArea.setText( (String) newValue );
    888 			}
    889 			else if( evt.getPropertyName().equals( PropertyTransfer.SOURCE_STEP_PROPERTY ))
    890 			{
    891 				Object selectedItem = sourceStepCombo.getSelectedItem();
    892 				if( newValue == null || selectedItem == null || !selectedItem.equals( newValue ))
    893 				{
    894 					selecting = true;
    895 					sourceStepCombo.setSelectedItem( newValue );
    896 					selecting = false;
    897 				}
    898 			}
    899 			else if( evt.getPropertyName().equals( PropertyTransfer.TARGET_STEP_PROPERTY ))
    900 			{
    901 				Object selectedItem = targetStepCombo.getSelectedItem();
    902 				if( newValue == null || selectedItem == null || !selectedItem.equals( newValue ))
    903 				{
    904 					selecting = true;
    905 					targetStepCombo.setSelectedItem( newValue );
    906 					selecting = false;
    907 				}
    908 			}
    909 			else if( evt.getPropertyName().equals( PropertyTransfer.SOURCE_TYPE_PROPERTY ))
    910 			{
    911 				Object selectedItem = sourcePropertyCombo.getSelectedItem();
    912 				if( selectedItem == null || !selectedItem.equals( newValue ))
    913 					sourcePropertyCombo.setSelectedItem( newValue );
    914 			}
    915 			else if( evt.getPropertyName().equals( PropertyTransfer.TARGET_TYPE_PROPERTY ))
    916 			{
    917 				Object selectedItem = targetPropertyCombo.getSelectedItem();
    918 				if( selectedItem == null || !selectedItem.equals( newValue ))
    919 					targetPropertyCombo.setSelectedItem( newValue );
    920 			}
    921 		}
    922 	}
    923
    924 	private final class AddAction extends AbstractAction
    925 	{
    926 		public AddAction()
    927 		{
    928 			putValue( Action.SHORT_DESCRIPTION, "Adds a new Property Transfer" );
    929 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/add_property.gif" ));
    930 		}
    931
    932 		public void actionPerformed(ActionEvent e)
    933 		{
    934 			String name = UISupport.prompt( "Specify name for value transfer", "Add Transfer", "" );
    935 			if( name == null || name.trim().length() == 0 ) return;
    936
    937 			transferStep.addTransfer( name );
    938
    939 			listModel.addElement( name );
    940 			transferList.setSelectedIndex( listModel.getSize()-1 );
    941 		}
    942 	}
    943
    944 	private final class CopyAction extends AbstractAction
    945 	{
    946 		public CopyAction()
    947 		{
    948 			putValue( Action.SHORT_DESCRIPTION, "Copies the selected Property Transfer" );
    949 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clone_request.gif" ));
    950 		}
    951
    952 		public void actionPerformed(ActionEvent e)
    953 		{
    954 			int ix = transferList.getSelectedIndex();
    955 			PropertyTransfer config = transferStep.getTransferAt( ix );
    956
    957 			String name = UISupport.prompt( "Specify name for value transfer", "Copy Transfer", config.getName() );
    958 			if( name == null || name.trim().length() == 0 ) return;
    959
    960 			PropertyTransfer transfer = transferStep.addTransfer( name );
    961 			transfer.setSourceStepName( config.getSourceStepName() );
    962 			transfer.setSourcePropertyName( config.getSourcePropertyName() );
    963 			transfer.setSourcePath( config.getSourcePath() );
    964 			transfer.setTargetStepName( config.getTargetStepName() );
    965 			transfer.setTargetPropertyName( config.getTargetPropertyName() );
    966 			transfer.setTargetPath( config.getTargetPath() );
    967
    968 			listModel.addElement( name );
    969 			transferList.setSelectedIndex( listModel.getSize()-1 );
    970 		}
    971 	}
    972
    973 	private final class DeleteAction extends AbstractAction
    974 	{
    975 		public DeleteAction()
    976 		{
    977 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/remove_property.gif" ));
    978 			putValue( Action.SHORT_DESCRIPTION, "Deletes the selected Property Transfer" );
    979 		}
    980
    981 		public void actionPerformed(ActionEvent e)
    982 		{
    983 			if( UISupport.confirm( "Delete selected transfer", "Delete Transfer" ))
    984 			{
    985 				transferList.setSelectedIndex( -1 );
    986
    987 				int ix = transferList.getSelectedIndex();
    988 				transferStep.removeTransferAt( ix );
    989 				listModel.remove( ix );
    990
    991 				if( listModel.getSize() > 0 )
    992 				{
    993 					transferList.setSelectedIndex( ix > listModel.getSize()-1 ? listModel.getSize()-1 : ix );
    994 				}
    995 			}
    996 		}
    997 	}
    998
    999 	private final class ClearLogAction extends AbstractAction
    1000 	{
    1001 		public ClearLogAction()
    1002 		{
    1003 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clear_properties.gif" ));
    1004 			putValue( Action.SHORT_DESCRIPTION, "Clears the property-transfer log" );
    1005 		}
    1006
    1007 		public void actionPerformed(ActionEvent e)
    1008 		{
    1009 			transfersTableModel.clear();
    1010 		}
    1011 	}
    1012
    1013 	private final class RenameAction extends AbstractAction
    1014 	{
    1015 		public RenameAction()
    1016 		{
    1017 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/rename.gif" ));
    1018 			putValue( Action.SHORT_DESCRIPTION, "Renames the selected Property Transfer" );
    1019 		}
    1020
    1021 		public void actionPerformed(ActionEvent e)
    1022 		{
    1023 			PropertyTransfer transfer = getCurrentTransfer();
    1024
    1025 			String newName = UISupport.prompt( "Specify new name for transfer", "Rename Transfer", transfer.getName() );
    1026
    1027 			if( newName != null && !transfer.getName().equals( newName ))
    1028 			{
    1029 				listModel.setElementAt( newName, transferList.getSelectedIndex() );
    1030 				transfer.setName( newName );
    1031 			}
    1032 		}
    1033 	}
    1034
    1035 	private final class DeclareNamespacesAction extends AbstractAction
    1036 	{
    1037 		public DeclareNamespacesAction()
    1038 		{
    1039 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/declareNs.gif" ));
    1040 			putValue( Action.SHORT_DESCRIPTION, "Declare available response/request namespaces in source/target expressions" );
    1041 		}
    1042
    1043 		public void actionPerformed(ActionEvent e)
    1044 		{
    1045 			try
    1046 			{
    1047 				TestStep previousStep = getCurrentTransfer().getSourceStep();
    1048
    1049 				if ( previousStep instanceof WsdlTestRequestStep )
    1050 				{
    1051 					WsdlTestRequest testRequest = ((WsdlTestRequestStep)previousStep).getTestRequest();
    1052 					sourceArea.setText( XmlUtils.declareXPathNamespaces( testRequest.getOperation().getInterface() ) + sourceArea.getText() );
    1053 				}
    1054 				else UISupport.showErrorMessage( "Source step is not a request" );
    1055
    1056 				TestStep nextStep = getCurrentTransfer().getTargetStep();
    1057
    1058 				if (nextStep instanceof WsdlTestRequestStep)
    1059 				{
    1060 					WsdlTestRequest testRequest = ((WsdlTestRequestStep)nextStep).getTestRequest();
    1061 					targetArea.setText( XmlUtils.declareXPathNamespaces( testRequest.getOperation().getInterface()) + targetArea.getText() );
    1062 				}
    1063 				else UISupport.showErrorMessage( "Target step is not a request" );
    1064 			}
    1065 			catch (Exception e1)
    1066 			{
    1067 				UISupport.showErrorMessage( e1 );
    1068 			}
    1069 		}
    1070 	}
    1071
    1072 	private final class RunAllAction extends AbstractAction
    1073 	{
    1074 		public RunAllAction()
    1075 		{
    1076 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_all.gif" ));
    1077 			putValue( Action.SHORT_DESCRIPTION, "Runs all Property Transfers" );
    1078 		}
    1079
    1080 		public void actionPerformed(ActionEvent e)
    1081 		{
    1082 			if( listModel.getSize() == 0 )
    1083 			{
    1084 				UISupport.showErrorMessage( "Missing transfers!" );
    1085 				return;
    1086 			}
    1087
    1088 			WsdlTestRunContext context = new WsdlTestRunContext( transferStep );
    1089 			ValueTransferResult result = (ValueTransferResult) transferStep.run( null, context );
    1090 			transfersTableModel.addResult( result );
    1091 		}
    1092 	}
    1093
    1094 	private final class RunAction extends AbstractAction
    1095 	{
    1096 		public RunAction()
    1097 		{
    1098 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run.gif" ));
    1099 			putValue( Action.SHORT_DESCRIPTION, "Runs selected PropertyTransfer" );
    1100 		}
    1101
    1102 		public void actionPerformed(ActionEvent e)
    1103 		{
    1104 			if( transferList.getSelectedIndex() == -1 )
    1105 			{
    1106 				UISupport.showErrorMessage( "No transfer selectd!" );
    1107 				return;
    1108 			}
    1109
    1110 			WsdlTestRunContext context = new WsdlTestRunContext( transferStep );
    1111 			ValueTransferResult result = (ValueTransferResult) transferStep.run( null, context, getCurrentTransfer() );
    1112 			transfersTableModel.addResult( result );
    1113 		}
    1114 	}
    1115
    1116 	public boolean onClose( boolean canCancel )
    1117 	{
    1118 		super.release();
    1119 		transferStep.getTestCase().getTestSuite().removeTestSuiteListener( testSuiteListener );
    1120 		transferStep.getTestCase().removeTestRunListener( testRunListener );
    1121
    1122 		PropertyTransfer transfer = getCurrentTransfer();
    1123
    1124 		if( transfer != null )
    1125 		{
    1126 			transfer.removePropertyChangeListener( transferPropertyChangeListener );
    1127 		}
    1128
    1129 		for( int c = 0; c < transferStep.getTestCase().getTestStepCount(); c++ )
    1130 		{
    1131 			WsdlTestStep testStep = (WsdlTestStep) transferStep.getTestCase().getTestStepAt( c );
    1132
    1133 			testStep.removePropertyChangeListener( TestStep.NAME_PROPERTY, sourceTestStepNameListener);
    1134 			testStep.removePropertyChangeListener( TestStep.NAME_PROPERTY, targetStepNameListener);
    1135 		}
    1136
    1137 		Object item = sourceStepCombo.getSelectedItem();
    1138 		if( item != null )
    1139 		{
    1140 			WsdlTestStep step = (WsdlTestStep) transferStep.getTestCase().getTestStepByName( (String) item );
    1141 			if( step != null )
    1142 				step.removeTestStepListener( sourceStepPropertiesListener );
    1143 		}
    1144
    1145 		item = targetStepCombo.getSelectedItem();
    1146 		if( item != null )
    1147 		{
    1148 			WsdlTestStep step = (WsdlTestStep) transferStep.getTestCase().getTestStepByName( (String) item );
    1149 			if( step != null )
    1150 				step.removeTestStepListener( targetStepPropertiesListener );
    1151 		}
    1152
    1153 		componentEnabler.release();
    1154 		if( resultDesktopPanel != null )
    1155 			SoapUI.getDesktop().closeDesktopPanel( resultDesktopPanel );
    1156
    1157 		return true;
    1158 	}
    1159
    1160 	public JComponent getComponent()
    1161 	{
    1162 		return this;
    1163 	}
    1164
    1165 	public boolean dependsOn(ModelItem modelItem)
    1166 	{
    1167 		return modelItem == transferStep || modelItem == transferStep.getTestCase() ||
    1168 				modelItem == transferStep.getTestCase().getTestSuite() ||
    1169 				modelItem == transferStep.getTestCase().getTestSuite().getProject();
    1170 	}
    1171
    1172 	public boolean selectTransfer(PropertyTransfer transfer)
    1173 	{
    1174 		for( int c = 0; c < transferStep.getTransferCount(); c++ )
    1175 		{
    1176 			if( transferStep.getTransferAt( c ) == transfer )
    1177 			{
    1178 				transferList.setSelectedIndex( c );
    1179 				return true;
    1180 			}
    1181 		}
    1182
    1183 		return false;
    1184 	}
    1185
    1186 	private class TransfersTableModel extends AbstractTableModel
    1187 	{
    1188 		private List<ValueTransferResult> results = new ArrayList<ValueTransferResult>();
    1189
    1190 		public synchronized int getRowCount()
    1191 		{
    1192 			int sum = 0;
    1193 			for( ValueTransferResult result : results )
    1194 			{
    1195 				sum += result.getTransferCount();
    1196 			}
    1197
    1198 			return sum;
    1199 		}
    1200
    1201 		public synchronized void clear()
    1202 		{
    1203 			results.clear();
    1204 			fireTableDataChanged();
    1205 			logInspector.setTitle(  "Transfer Log (0)" );
    1206 		}
    1207
    1208 		public synchronized void addResult( ValueTransferResult result )
    1209 		{
    1210 			int rowCount = getRowCount();
    1211 			results.add( result );
    1212 			fireTableRowsInserted( rowCount, rowCount + result.getTransferCount() );
    1213
    1214 			logInspector.setTitle(  "Transfer Log (" + getRowCount() + ")" );
    1215 			inspectorPanel.activate( logInspector );
    1216 		}
    1217
    1218 		public int getColumnCount()
    1219 		{
    1220 			return 3;
    1221 		}
    1222
    1223 		public String getColumnName(int column)
    1224 		{
    1225 			switch( column )
    1226 			{
    1227 			case 0 : return "Timestamp";
    1228 			case 1 : return "Transfer Name";
    1229 			case 2 : return "Transferred Values";
    1230 			}
    1231
    1232 			return null;
    1233 		}
    1234
    1235 		public synchronized Object getValueAt(int rowIndex, int columnIndex)
    1236 		{
    1237 			// find correct transfer
    1238 			ValueTransferResult result = null;
    1239 			int sum = 0;
    1240
    1241 			for( int c = 0; c < results.size(); c++ )
    1242 			{
    1243 				if( sum + results.get( c ).getTransferCount() > rowIndex )
    1244 				{
    1245 					result = results.get( c );
    1246 					break;
    1247 				}
    1248 				else
    1249 				{
    1250 					sum += results.get( c ).getTransferCount();
    1251 				}
    1252 			}
    1253
    1254 			if( result != null )
    1255 			{
    1256 				switch( columnIndex )
    1257 				{
    1258 					case 0 : return new Date( result.getTimeStamp() ).toString();
    1259 					case 1 : return result.getTransferAt( rowIndex-sum ).getName();
    1260 					case 2 : return Arrays.toString( result.getTransferredValuesAt( rowIndex-sum ) );
    1261 				}
    1262 			}
    1263
    1264 			return null;
    1265 		}
    1266
    1267 	}
    1268
    1269 	private class InternalTestRunListener extends TestRunListenerAdapter
    1270 	{
    1271 		@Override
    1272 		public void afterStep( TestRunner testRunner, TestRunContext runContext, TestStepResult result )
    1273 		{
    1274 			if( result.getTestStep() == transferStep )
    1275 			{
    1276 				transfersTableModel.addResult( ( ValueTransferResult ) result );
    1277 			}
    1278 		}
    1279 	}
    1280 }