View Javadoc

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