View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 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.support;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Component;
17  import java.awt.Point;
18  import java.awt.datatransfer.DataFlavor;
19  import java.awt.datatransfer.Transferable;
20  import java.awt.dnd.DnDConstants;
21  import java.awt.dnd.DropTarget;
22  import java.awt.dnd.DropTargetDragEvent;
23  import java.awt.dnd.DropTargetDropEvent;
24  import java.awt.dnd.DropTargetEvent;
25  import java.awt.dnd.DropTargetListener;
26  import java.awt.event.ActionEvent;
27  import java.io.BufferedReader;
28  import java.io.File;
29  import java.io.FileReader;
30  import java.io.IOException;
31  import java.util.Arrays;
32  import java.util.HashSet;
33  import java.util.Set;
34  
35  import javax.swing.AbstractAction;
36  import javax.swing.Action;
37  import javax.swing.JButton;
38  import javax.swing.JPanel;
39  import javax.swing.JScrollPane;
40  import javax.swing.JTable;
41  import javax.swing.ListSelectionModel;
42  import javax.swing.SwingUtilities;
43  import javax.swing.TransferHandler;
44  import javax.swing.event.ListSelectionEvent;
45  import javax.swing.event.ListSelectionListener;
46  
47  import com.eviware.soapui.SoapUI;
48  import com.eviware.soapui.impl.wsdl.MutableTestPropertyHolder;
49  import com.eviware.soapui.model.TestPropertyHolder;
50  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
51  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionImpl;
52  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
53  import com.eviware.soapui.model.support.TestPropertyUtils;
54  import com.eviware.soapui.model.testsuite.TestProperty;
55  import com.eviware.soapui.model.testsuite.TestPropertyListener;
56  import com.eviware.soapui.model.tree.nodes.PropertyTreeNode.PropertyModelItem;
57  import com.eviware.soapui.support.StringUtils;
58  import com.eviware.soapui.support.UISupport;
59  import com.eviware.soapui.support.components.JXToolBar;
60  import com.eviware.soapui.support.xml.XmlUtils;
61  import com.eviware.x.form.XFormDialog;
62  import com.eviware.x.form.support.ADialogBuilder;
63  import com.eviware.x.form.support.AField;
64  import com.eviware.x.form.support.AForm;
65  import com.eviware.x.form.support.AField.AFieldType;
66  
67  public class PropertyHolderTable extends JPanel
68  {
69  	protected final TestPropertyHolder holder;
70  	protected PropertyHolderTableModel propertiesModel;
71  	protected RemovePropertyAction removePropertyAction;
72  	protected AddPropertyAction addPropertyAction;
73  	protected InternalTestPropertyListener testPropertyListener;
74  	protected JTable propertiesTable;
75  	protected JXToolBar toolbar;
76  	protected LoadPropertiesAction loadPropertiesAction;
77  	protected MovePropertyUpAction movePropertyUpAction;
78  	protected MovePropertyDownAction movePropertyDownAction;
79  
80  	public PropertyHolderTable( TestPropertyHolder holder )
81  	{
82  		super( new BorderLayout() );
83  		this.holder = holder;
84  
85  		loadPropertiesAction = new LoadPropertiesAction();
86  		testPropertyListener = new InternalTestPropertyListener();
87  		holder.addTestPropertyListener( testPropertyListener );
88  
89  		JScrollPane scrollPane = new JScrollPane( buildPropertiesTable() );
90  
91  		if( getHolder().getModelItem() != null )
92  		{
93  			DropTarget dropTarget = new DropTarget( scrollPane, new PropertyHolderTablePropertyExpansionDropTarget() );
94  			dropTarget.setDefaultActions( DnDConstants.ACTION_COPY_OR_MOVE );
95  		}
96  
97  		add( scrollPane, BorderLayout.CENTER );
98  		add( buildToolbar(), BorderLayout.NORTH );
99  	}
100 
101 	protected JTable buildPropertiesTable()
102 	{
103 		propertiesModel = new DefaultPropertyTableHolderModel( holder );
104 		propertiesTable = new PropertiesHolderJTable();
105 		propertiesTable.setSurrendersFocusOnKeystroke( true );
106 
107 		propertiesTable.putClientProperty( "terminateEditOnFocusLost", Boolean.TRUE );
108 		propertiesTable.getSelectionModel().addListSelectionListener( new ListSelectionListener()
109 		{
110 			public void valueChanged( ListSelectionEvent e )
111 			{
112 				int selectedRow = propertiesTable.getSelectedRow();
113 				if( removePropertyAction != null )
114 					removePropertyAction.setEnabled( selectedRow != -1 );
115 
116 				if( movePropertyUpAction != null )
117 					movePropertyUpAction.setEnabled( selectedRow > 0 );
118 
119 				if( movePropertyDownAction != null )
120 					movePropertyDownAction.setEnabled( selectedRow >= 0 && selectedRow < propertiesTable.getRowCount() - 1 );
121 			}
122 		} );
123 
124 		propertiesTable.setDragEnabled( true );
125 		propertiesTable.setTransferHandler( new TransferHandler( "testProperty" ) );
126 
127 		if( getHolder().getModelItem() != null )
128 		{
129 			DropTarget dropTarget = new DropTarget( propertiesTable, new PropertyHolderTablePropertyExpansionDropTarget() );
130 			dropTarget.setDefaultActions( DnDConstants.ACTION_COPY_OR_MOVE );
131 		}
132 
133 		return propertiesTable;
134 	}
135 
136 	public class PropertiesHolderJTable extends JTable
137 	{
138 		public PropertiesHolderJTable()
139 		{
140 			super( propertiesModel );
141 			setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
142 			// setAutoStartEditOnKeyStroke( true );
143 			setSurrendersFocusOnKeystroke( true );
144 			setRowHeight( 19 );
145 			// setHorizontalScrollEnabled(true);
146 		}
147 
148 		public PropertyModelItem getTestProperty()
149 		{
150 			int index = getSelectedRow();
151 			if( index == -1 )
152 				return null;
153 			TestProperty property = propertiesModel.getPropertyAtRow( index );
154 			return new PropertyModelItem( property, true );
155 		}
156 	}
157 
158 	private Component buildToolbar()
159 	{
160 		toolbar = UISupport.createSmallToolbar();
161 
162 		if( holder instanceof MutableTestPropertyHolder )
163 		{
164 			removePropertyAction = new RemovePropertyAction();
165 			addPropertyAction = new AddPropertyAction();
166 			movePropertyUpAction = new MovePropertyUpAction();
167 			movePropertyDownAction = new MovePropertyDownAction();
168 
169 			JButton addPropertyButton = UISupport.createToolbarButton( addPropertyAction );
170 			toolbar.add( addPropertyButton );
171 			JButton removePropertyButton = UISupport.createToolbarButton( removePropertyAction );
172 			toolbar.add( removePropertyButton );
173 
174 			toolbar.addRelatedGap();
175 			JButton movePropertyUpButton = UISupport.createToolbarButton( movePropertyUpAction );
176 			toolbar.add( movePropertyUpButton );
177 			JButton movePropertyDownButton = UISupport.createToolbarButton( movePropertyDownAction );
178 			toolbar.add( movePropertyDownButton );
179 			
180 			toolbar.addRelatedGap();
181 			toolbar.add( UISupport.createToolbarButton( new SortPropertiesAction() ));
182 			toolbar.addRelatedGap();
183 		}
184 
185 		JButton clearPropertiesButton = UISupport.createToolbarButton( new ClearPropertiesAction() );
186 		toolbar.add( clearPropertiesButton );
187 		JButton loadPropertiesButton = UISupport.createToolbarButton( loadPropertiesAction );
188 		toolbar.add( loadPropertiesButton );
189 		toolbar.add( UISupport.createToolbarButton( new SavePropertiesAction() ) );
190 
191 		return toolbar;
192 	}
193 
194 	public JXToolBar getToolbar()
195 	{
196 		return toolbar;
197 	}
198 
199 	public JTable getPropertiesTable()
200 	{
201 		return propertiesTable;
202 	}
203 
204 	public void release()
205 	{
206 		if( propertiesTable.isEditing() )
207 			propertiesTable.getCellEditor().stopCellEditing();
208 
209 		holder.removeTestPropertyListener( testPropertyListener );
210 	}
211 
212 	public void setEnabled( boolean enabled )
213 	{
214 		addPropertyAction.setEnabled( enabled );
215 		removePropertyAction.setEnabled( enabled );
216 		propertiesTable.setEnabled( enabled );
217 		loadPropertiesAction.setEnabled( enabled );
218 
219 		super.setEnabled( enabled );
220 	}
221 
222 	private final class InternalTestPropertyListener implements TestPropertyListener
223 	{
224 		private boolean enabled = true;
225 
226 		@SuppressWarnings( "unused" )
227 		public boolean isEnabled()
228 		{
229 			return enabled;
230 		}
231 
232 		@SuppressWarnings( "unused" )
233 		public void setEnabled( boolean enabled )
234 		{
235 			this.enabled = enabled;
236 		}
237 
238 		public void propertyAdded( String name )
239 		{
240 			if( enabled )
241 				propertiesModel.fireTableDataChanged();
242 		}
243 
244 		public void propertyRemoved( String name )
245 		{
246 			if( enabled )
247 				propertiesModel.fireTableDataChanged();
248 		}
249 
250 		public void propertyRenamed( String oldName, String newName )
251 		{
252 			if( enabled )
253 				propertiesModel.fireTableDataChanged();
254 		}
255 
256 		public void propertyValueChanged( String name, String oldValue, String newValue )
257 		{
258 			if( enabled )
259 				propertiesModel.fireTableDataChanged();
260 		}
261 
262 		public void propertyMoved( String name, int oldIndex, int newIndex )
263 		{
264 			if( enabled )
265 				propertiesModel.fireTableDataChanged();
266 		}
267 	}
268 
269 	private class AddPropertyAction extends AbstractAction
270 	{
271 		public AddPropertyAction()
272 		{
273 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/add_property.gif" ) );
274 			putValue( Action.SHORT_DESCRIPTION, "Adds a property to the property list" );
275 		}
276 
277 		public void actionPerformed( ActionEvent e )
278 		{
279 			String name = UISupport.prompt( "Specify unique property name", "Add Property", "" );
280 			if( StringUtils.hasContent( name ) )
281 			{
282 				if( holder.hasProperty( name ) )
283 				{
284 					UISupport.showErrorMessage( "Property name [" + name + "] already exists.." );
285 					return;
286 				}
287 
288 				( ( MutableTestPropertyHolder )holder ).addProperty( name );
289 				final int row = holder.getPropertyNames().length - 1;
290 				propertiesModel.fireTableRowsInserted( row, row );
291 				SwingUtilities.invokeLater( new Runnable()
292 				{
293 					public void run()
294 					{
295 						requestFocusInWindow();
296 						scrollRectToVisible( propertiesTable.getCellRect( row, 1, true ) );
297 						SwingUtilities.invokeLater( new Runnable()
298 						{
299 							public void run()
300 							{
301 								propertiesTable.editCellAt( row, 1 );
302 								Component editorComponent = propertiesTable.getEditorComponent();
303 								if( editorComponent != null )
304 									editorComponent.requestFocusInWindow();
305 							}
306 						} );
307 					}
308 				} );
309 
310 			}
311 		}
312 	}
313 
314 	protected class RemovePropertyAction extends AbstractAction
315 	{
316 		public RemovePropertyAction()
317 		{
318 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/remove_property.gif" ) );
319 			putValue( Action.SHORT_DESCRIPTION, "Removes the selected property from the property list" );
320 			setEnabled( false );
321 		}
322 
323 		public void actionPerformed( ActionEvent e )
324 		{
325 			int row = propertiesTable.getSelectedRow();
326 			if( row == -1 )
327 				return;
328 
329 			UISupport.stopCellEditing( propertiesTable );
330 
331 			String propertyName = propertiesModel.getValueAt( row, 0 ).toString();
332 			if( UISupport.confirm( "Remove property [" + propertyName + "]?", "Remove Property" ) )
333 			{
334 				( ( MutableTestPropertyHolder )holder ).removeProperty( propertyName );
335 				propertiesModel.fireTableRowsDeleted( row, row );
336 			}
337 		}
338 	}
339 
340 	protected class ClearPropertiesAction extends AbstractAction
341 	{
342 		public ClearPropertiesAction()
343 		{
344 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clear_properties.gif" ) );
345 			putValue( Action.SHORT_DESCRIPTION, "Clears all current property values" );
346 		}
347 
348 		public void actionPerformed( ActionEvent e )
349 		{
350 			if( UISupport.confirm( "Clear all property values?", "Clear Properties" ) )
351 			{
352 				for( String name : holder.getPropertyNames() )
353 				{
354 					holder.getProperty( name ).setValue( null );
355 				}
356 			}
357 		}
358 	}
359 
360 	protected class MovePropertyUpAction extends AbstractAction
361 	{
362 		public MovePropertyUpAction()
363 		{
364 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/up_arrow.gif" ) );
365 			putValue( Action.SHORT_DESCRIPTION, "Moves selected property up one row" );
366 			setEnabled( false );
367 		}
368 
369 		public void actionPerformed( ActionEvent e )
370 		{
371 			int ix = propertiesTable.getSelectedRow();
372 			if( ix != -1 )
373 			{
374 				( ( MutableTestPropertyHolder )holder ).moveProperty( holder.getPropertyAt( ix ).getName(), ix - 1 );
375 				propertiesTable.setRowSelectionInterval( ix - 1, ix - 1 );
376 			}
377 		}
378 	}
379 
380 	protected class MovePropertyDownAction extends AbstractAction
381 	{
382 		public MovePropertyDownAction()
383 		{
384 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/down_arrow.gif" ) );
385 			putValue( Action.SHORT_DESCRIPTION, "Moves selected property down one row" );
386 			setEnabled( false );
387 		}
388 
389 		public void actionPerformed( ActionEvent e )
390 		{
391 			int ix = propertiesTable.getSelectedRow();
392 			if( ix != -1 )
393 			{
394 				( ( MutableTestPropertyHolder )holder ).moveProperty( holder.getPropertyAt( ix ).getName(), ix + 1 );
395 
396 				propertiesTable.setRowSelectionInterval( ix + 1, ix + 1 );
397 			}
398 		}
399 	}
400 
401 	protected class LoadPropertiesAction extends AbstractAction
402 	{
403 		private XFormDialog dialog;
404 
405 		public LoadPropertiesAction()
406 		{
407 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/load_properties.gif" ) );
408 			putValue( Action.SHORT_DESCRIPTION, "Loads property values from an external file" );
409 		}
410 
411 		public void actionPerformed( ActionEvent e )
412 		{
413 			if( dialog == null )
414 				dialog = ADialogBuilder.buildDialog( LoadOptionsForm.class );
415 
416 			dialog.getFormField( LoadOptionsForm.DELETEREMAINING )
417 					.setEnabled( holder instanceof MutableTestPropertyHolder );
418 			dialog.getFormField( LoadOptionsForm.CREATEMISSING ).setEnabled( holder instanceof MutableTestPropertyHolder );
419 
420 			if( dialog.show() )
421 			{
422 				try
423 				{
424 					BufferedReader reader = new BufferedReader( new FileReader( dialog.getValue( LoadOptionsForm.FILE ) ) );
425 
426 					String line = reader.readLine();
427 					int count = 0;
428 
429 					Set<String> names = new HashSet<String>( Arrays.asList( holder.getPropertyNames() ) );
430 
431 					while( line != null )
432 					{
433 						if( line.trim().length() > 0 && !( line.charAt( 0 ) == '#' ) )
434 						{
435 							int ix = line.indexOf( '=' );
436 							if( ix > 0 )
437 							{
438 								String name = line.substring( 0, ix ).trim();
439 								String value = line.length() > ix ? line.substring( ix + 1 ) : "";
440 
441 								// read multiline value
442 								if( value.endsWith( "//" ) )
443 								{
444 									value = value.substring( 0, value.length() - 1 );
445 
446 									String ln = reader.readLine();
447 									while( ln != null && ln.endsWith( "//" ) )
448 									{
449 										value += ln.substring( 0, ln.length() - 1 );
450 										ln = reader.readLine();
451 									}
452 
453 									if( ln != null )
454 										value += ln;
455 									if( ln == null )
456 										break;
457 								}
458 
459 								if( holder.hasProperty( name ) )
460 								{
461 									count++ ;
462 									holder.setPropertyValue( name, value );
463 								}
464 								else if( dialog.getBooleanValue( LoadOptionsForm.CREATEMISSING )
465 										&& holder instanceof MutableTestPropertyHolder )
466 								{
467 									( ( MutableTestPropertyHolder )holder ).addProperty( name ).setValue( value );
468 									count++ ;
469 								}
470 
471 								names.remove( name );
472 							}
473 						}
474 
475 						line = reader.readLine();
476 					}
477 
478 					if( dialog.getBooleanValue( LoadOptionsForm.DELETEREMAINING )
479 							&& holder instanceof MutableTestPropertyHolder )
480 					{
481 						for( String name : names )
482 						{
483 							( ( MutableTestPropertyHolder )holder ).removeProperty( name );
484 						}
485 					}
486 
487 					reader.close();
488 					UISupport.showInfoMessage( "Added/Updated " + count + " properties from file" );
489 				}
490 				catch( Exception ex )
491 				{
492 					UISupport.showErrorMessage( ex );
493 				}
494 			}
495 		}
496 	}
497 
498 	private class SavePropertiesAction extends AbstractAction
499 	{
500 		public SavePropertiesAction()
501 		{
502 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/set_properties_target.gif" ) );
503 			putValue( Action.SHORT_DESCRIPTION, "Saves current property-values to a file" );
504 		}
505 
506 		public void actionPerformed( ActionEvent e )
507 		{
508 			if( holder.getPropertyCount() == 0 )
509 			{
510 				UISupport.showErrorMessage( "No properties to save!" );
511 				return;
512 			}
513 
514 			File file = UISupport.getFileDialogs().saveAs( this, "Save Properties" );
515 			if( file != null )
516 			{
517 				try
518 				{
519 					int cnt = TestPropertyUtils.saveTo( holder, file.getAbsolutePath() );
520 					UISupport.showInfoMessage( "Saved " + cnt + " propert" + ((cnt == 1)?"y":"ies") + " to file" );
521 				}
522 				catch( IOException e1 )
523 				{
524 					UISupport.showErrorMessage( e1 );
525 				}
526 			}
527 		}
528 	}
529 	
530 	private class SortPropertiesAction extends AbstractAction
531 	{
532 		public SortPropertiesAction()
533 		{
534 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/arrow_down.png" ) );
535 			putValue( Action.SHORT_DESCRIPTION, "Sorts properties alphabetically" );
536 		}
537 
538 		public void actionPerformed( ActionEvent e )
539 		{
540 			if( holder.getPropertyCount() == 0 )
541 			{
542 				UISupport.showErrorMessage( "No properties to sort!" );
543 				return;
544 			}
545 
546 			try
547 			{
548 				UISupport.setHourglassCursor();
549 				TestPropertyUtils.sortProperties( ( MutableTestPropertyHolder )holder );
550 			}
551 			finally
552 			{
553 				UISupport.resetCursor();
554 			}
555 			
556 		}
557 	}
558 
559 	@AForm( name = "Load Properties", description = "Set load options below" )
560 	private static interface LoadOptionsForm
561 	{
562 		@AField( name = "File", description = "The Properties file to load", type = AFieldType.FILE )
563 		public static final String FILE = "File";
564 
565 		@AField( name = "Create Missing", description = "Creates Missing Properties", type = AFieldType.BOOLEAN )
566 		public static final String CREATEMISSING = "Create Missing";
567 
568 		@AField( name = "Delete Remaining", description = "Deletes properties not in file", type = AFieldType.BOOLEAN )
569 		public static final String DELETEREMAINING = "Delete Remaining";
570 	}
571 
572 	public TestPropertyHolder getHolder()
573 	{
574 		return holder;
575 	}
576 
577 	public PropertyHolderTableModel getPropertiesModel()
578 	{
579 		return propertiesModel;
580 	}
581 
582 	public final class PropertyHolderTablePropertyExpansionDropTarget implements DropTargetListener
583 	{
584 		public PropertyHolderTablePropertyExpansionDropTarget()
585 		{
586 		}
587 
588 		public void dragEnter( DropTargetDragEvent dtde )
589 		{
590 			if( !isAcceptable( dtde.getTransferable(), dtde.getLocation() ) )
591 				dtde.rejectDrag();
592 		}
593 
594 		public void dragExit( DropTargetEvent dtde )
595 		{
596 		}
597 
598 		public void dragOver( DropTargetDragEvent dtde )
599 		{
600 			if( !isAcceptable( dtde.getTransferable(), dtde.getLocation() ) )
601 			{
602 				dtde.rejectDrag();
603 			}
604 			else
605 			{
606 				dtde.acceptDrag( dtde.getDropAction() );
607 			}
608 		}
609 
610 		public void drop( DropTargetDropEvent dtde )
611 		{
612 			if( !isAcceptable( dtde.getTransferable(), dtde.getLocation() ) )
613 			{
614 				dtde.rejectDrop();
615 			}
616 			else
617 			{
618 				try
619 				{
620 					Transferable transferable = dtde.getTransferable();
621 					Object transferData = transferable.getTransferData( transferable.getTransferDataFlavors()[0] );
622 					if( transferData instanceof PropertyModelItem )
623 					{
624 						dtde.acceptDrop( dtde.getDropAction() );
625 						PropertyModelItem modelItem = ( PropertyModelItem )transferData;
626 
627 						String xpath = modelItem.getXPath();
628 						if( xpath == null && XmlUtils.seemsToBeXml( modelItem.getProperty().getValue() ) )
629 						{
630 							xpath = UISupport.selectXPath( "Create PropertyExpansion", "Select XPath below", modelItem
631 									.getProperty().getValue(), null );
632 
633 							if( xpath != null )
634 								xpath = XmlUtils.removeXPathNamespaceDeclarations( xpath );
635 						}
636 
637 						PropertyExpansion propertyExpansion = new PropertyExpansionImpl( modelItem.getProperty(), xpath );
638 
639 						Point point = dtde.getLocation();
640 						int column = getPropertiesTable().columnAtPoint( point );
641 						int row = getPropertiesTable().rowAtPoint( point );
642 
643 						if( row == -1 )
644 						{
645 							if( holder instanceof MutableTestPropertyHolder )
646 							{
647 								MutableTestPropertyHolder mtph = ( MutableTestPropertyHolder )holder;
648 								String name = UISupport.prompt( "Specify unique name of property", "Add Property", modelItem
649 										.getProperty().getName() );
650 								while( name != null && mtph.hasProperty( name ) )
651 								{
652 									name = UISupport.prompt( "Specify unique name of property", "Add Property", modelItem
653 											.getProperty().getName() );
654 								}
655 
656 								if( name != null )
657 									mtph.addProperty( name ).setValue( propertyExpansion.toString() );
658 							}
659 						}
660 						else
661 						{
662 							getPropertiesTable().setValueAt( propertyExpansion.toString(), row, column );
663 						}
664 
665 						dtde.dropComplete( true );
666 					}
667 				}
668 				catch( Exception e )
669 				{
670 					SoapUI.logError( e );
671 				}
672 			}
673 		}
674 
675 		public void dropActionChanged( DropTargetDragEvent dtde )
676 		{
677 		}
678 
679 		public boolean isAcceptable( Transferable transferable, Point point )
680 		{
681 			int row = getPropertiesTable().rowAtPoint( point );
682 			if( row >= 0 )
683 			{
684 				int column = getPropertiesTable().columnAtPoint( point );
685 				if( column != 1 )
686 					return false;
687 
688 				if( !getPropertiesTable().isCellEditable( row, column ) )
689 					return false;
690 			}
691 			else if( !( getHolder() instanceof MutableTestPropertyHolder ) )
692 			{
693 				return false;
694 			}
695 
696 			DataFlavor[] flavors = transferable.getTransferDataFlavors();
697 			for( int i = 0; i < flavors.length; i++ )
698 			{
699 				DataFlavor flavor = flavors[i];
700 				if( flavor.isMimeTypeEqual( DataFlavor.javaJVMLocalObjectMimeType ) )
701 				{
702 					try
703 					{
704 						Object modelItem = transferable.getTransferData( flavor );
705 						if( modelItem instanceof PropertyModelItem
706 								&& ( ( PropertyModelItem )modelItem ).getProperty().getModelItem() != getHolder()
707 										.getModelItem() )
708 						{
709 							return PropertyExpansionUtils.canExpandProperty( getHolder().getModelItem(),
710 									( ( PropertyModelItem )modelItem ).getProperty() );
711 						}
712 					}
713 					catch( Exception ex )
714 					{
715 						SoapUI.logError( ex );
716 					}
717 				}
718 			}
719 
720 			return false;
721 		}
722 	}
723 }