1
2
3
4
5
6
7
8
9
10
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.File;
28 import java.io.FileInputStream;
29 import java.util.Properties;
30
31 import javax.swing.AbstractAction;
32 import javax.swing.Action;
33 import javax.swing.JButton;
34 import javax.swing.JPanel;
35 import javax.swing.JScrollPane;
36 import javax.swing.JTable;
37 import javax.swing.ListSelectionModel;
38 import javax.swing.SwingUtilities;
39 import javax.swing.TransferHandler;
40 import javax.swing.event.ListSelectionEvent;
41 import javax.swing.event.ListSelectionListener;
42 import javax.swing.table.AbstractTableModel;
43
44 import com.eviware.soapui.SoapUI;
45 import com.eviware.soapui.impl.wsdl.MutableTestPropertyHolder;
46 import com.eviware.soapui.model.TestPropertyHolder;
47 import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
48 import com.eviware.soapui.model.propertyexpansion.PropertyExpansionImpl;
49 import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
50 import com.eviware.soapui.model.testsuite.TestProperty;
51 import com.eviware.soapui.model.testsuite.TestPropertyListener;
52 import com.eviware.soapui.model.tree.nodes.PropertyTreeNode.PropertyModelItem;
53 import com.eviware.soapui.support.StringUtils;
54 import com.eviware.soapui.support.UISupport;
55 import com.eviware.soapui.support.components.JXToolBar;
56 import com.eviware.soapui.support.types.StringList;
57 import com.eviware.soapui.support.xml.XmlUtils;
58
59 public class PropertyHolderTable extends JPanel
60 {
61 private final TestPropertyHolder holder;
62 private PropertiesModel propertiesModel;
63 private RemovePropertyAction removePropertyAction;
64 private AddPropertyAction addPropertyAction;
65 private InternalTestPropertyListener testPropertyListener;
66 private JTable propertiesTable;
67 private JXToolBar toolbar;
68 private LoadPropertiesAction loadPropertiesAction;
69
70 public PropertyHolderTable( TestPropertyHolder holder )
71 {
72 super( new BorderLayout() );
73 this.holder = holder;
74
75 removePropertyAction = new RemovePropertyAction();
76 addPropertyAction = new AddPropertyAction();
77 loadPropertiesAction = new LoadPropertiesAction();
78
79 testPropertyListener = new InternalTestPropertyListener();
80 holder.addTestPropertyListener( testPropertyListener );
81
82 JScrollPane scrollPane = new JScrollPane( buildPropertiesTable() );
83
84 if( getHolder().getModelItem() != null )
85 {
86 DropTarget dropTarget = new DropTarget( scrollPane, new PropertyHolderTablePropertyExpansionDropTarget() );
87 dropTarget.setDefaultActions( DnDConstants.ACTION_COPY_OR_MOVE );
88 }
89
90 add( scrollPane, BorderLayout.CENTER );
91 add( buildToolbar(), BorderLayout.NORTH );
92 }
93
94 protected JTable buildPropertiesTable()
95 {
96 propertiesModel = new PropertiesModel();
97 propertiesTable = new PropertiesHolderJTable();
98 propertiesTable.setSurrendersFocusOnKeystroke( true );
99
100 propertiesTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
101 propertiesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener()
102 {
103 public void valueChanged(ListSelectionEvent e)
104 {
105 removePropertyAction.setEnabled(propertiesTable.getSelectedRow() != -1);
106 }
107 });
108
109 propertiesTable.setDragEnabled( true );
110 propertiesTable.setTransferHandler( new TransferHandler( "testProperty"));
111
112 if( getHolder().getModelItem() != null )
113 {
114 DropTarget dropTarget = new DropTarget( propertiesTable, new PropertyHolderTablePropertyExpansionDropTarget() );
115 dropTarget.setDefaultActions( DnDConstants.ACTION_COPY_OR_MOVE );
116 }
117
118 return propertiesTable;
119 }
120
121 public class PropertiesHolderJTable extends JTable
122 {
123 public PropertiesHolderJTable()
124 {
125 super( propertiesModel );
126 setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
127 }
128
129 public PropertyModelItem getTestProperty()
130 {
131 int index = getSelectedRow();
132 if( index == -1 )
133 return null;
134 TestProperty property = propertiesModel.getPropertyAtRow( index );
135 return new PropertyModelItem( property, true );
136 }
137 }
138
139 private Component buildToolbar()
140 {
141 toolbar = UISupport.createSmallToolbar();
142
143 if( holder instanceof MutableTestPropertyHolder )
144 {
145 JButton addPropertyButton = UISupport.createToolbarButton(addPropertyAction);
146 toolbar.add(addPropertyButton);
147 JButton removePropertyButton = UISupport.createToolbarButton(removePropertyAction);
148 toolbar.add(removePropertyButton);
149 }
150
151 JButton clearPropertiesButton = UISupport.createToolbarButton(new ClearPropertiesAction());
152 toolbar.add(clearPropertiesButton);
153 JButton loadPropertiesButton = UISupport.createToolbarButton(loadPropertiesAction);
154 toolbar.add(loadPropertiesButton);
155
156
157 return toolbar;
158 }
159
160 public JXToolBar getToolbar()
161 {
162 return toolbar;
163 }
164
165 public JTable getPropertiesTable()
166 {
167 return propertiesTable;
168 }
169
170 public void release()
171 {
172 if( propertiesTable.isEditing() )
173 propertiesTable.getCellEditor().stopCellEditing();
174
175 holder.removeTestPropertyListener( testPropertyListener );
176 }
177
178 public void setEnabled( boolean enabled )
179 {
180 addPropertyAction.setEnabled( enabled );
181 removePropertyAction.setEnabled( enabled );
182 propertiesTable.setEnabled( enabled );
183 loadPropertiesAction.setEnabled( enabled );
184
185 super.setEnabled( enabled );
186 }
187
188 private final class InternalTestPropertyListener implements TestPropertyListener
189 {
190 private boolean enabled = true;
191
192 public boolean isEnabled()
193 {
194 return enabled;
195 }
196
197 public void setEnabled(boolean enabled)
198 {
199 this.enabled = enabled;
200 }
201
202 public void propertyAdded(String name)
203 {
204 if (enabled)
205 propertiesModel.fireTableDataChanged();
206 }
207
208 public void propertyRemoved(String name)
209 {
210 if (enabled)
211 propertiesModel.fireTableDataChanged();
212 }
213
214 public void propertyRenamed(String oldName, String newName)
215 {
216 if (enabled)
217 propertiesModel.fireTableDataChanged();
218 }
219
220 public void propertyValueChanged(String name, String oldValue, String newValue)
221 {
222 if (enabled)
223 propertiesModel.fireTableDataChanged();
224 }
225 }
226
227 private class PropertiesModel extends AbstractTableModel
228 {
229 private StringList names = new StringList();
230
231 public PropertiesModel()
232 {
233 names = new StringList( holder.getPropertyNames() );
234 }
235
236 public int getRowCount()
237 {
238 return names.size();
239 }
240
241 public int getColumnCount()
242 {
243 return 2;
244 }
245
246 @Override
247 public void fireTableDataChanged()
248 {
249 names = new StringList( holder.getPropertyNames() );
250 super.fireTableDataChanged();
251 }
252
253 public String getColumnName(int columnIndex)
254 {
255 switch (columnIndex)
256 {
257 case 0:
258 return "Name";
259 case 1:
260 return "Value";
261 }
262
263 return null;
264 }
265
266 public boolean isCellEditable(int rowIndex, int columnIndex)
267 {
268 if( columnIndex == 0 )
269 {
270 return holder instanceof MutableTestPropertyHolder;
271 }
272
273 return !holder.getProperty( names.get( rowIndex ) ).isReadOnly();
274 }
275
276 public void setValueAt(Object aValue, int rowIndex, int columnIndex)
277 {
278 TestProperty property = holder.getProperty(names.get( rowIndex ));
279 switch (columnIndex)
280 {
281 case 0:
282 {
283 if( holder instanceof MutableTestPropertyHolder)
284 {
285 TestProperty prop = holder.getProperty( aValue.toString() );
286 if (prop != null && prop != property)
287 {
288 UISupport.showErrorMessage("Property name exists!");
289 return;
290 }
291 ((MutableTestPropertyHolder)holder).renameProperty( property.getName(), aValue.toString() );
292 }
293 break;
294 }
295 case 1:
296 {
297 property.setValue(aValue.toString());
298 break;
299 }
300 }
301 }
302
303 public TestProperty getPropertyAtRow( int rowIndex )
304 {
305 return holder.getProperty(names.get( rowIndex ));
306 }
307
308 public Object getValueAt(int rowIndex, int columnIndex)
309 {
310 TestProperty property = holder.getProperty(names.get( rowIndex ));
311
312 switch (columnIndex)
313 {
314 case 0:
315 return property.getName();
316 case 1:
317 return property.getValue();
318 }
319
320 return null;
321 }
322 }
323
324 private class AddPropertyAction extends AbstractAction
325 {
326 public AddPropertyAction()
327 {
328 putValue(Action.SMALL_ICON, UISupport.createImageIcon("/add_property.gif"));
329 putValue(Action.SHORT_DESCRIPTION, "Adds a property to the property list");
330 }
331
332 public void actionPerformed(ActionEvent e)
333 {
334 String name = UISupport.prompt("Specify unique property name", "Add Property", "");
335 if ( StringUtils.hasContent( name ))
336 {
337 if( holder.hasProperty( name ))
338 {
339 UISupport.showErrorMessage( "Property name [" + name + "] already exists.." );
340 return;
341 }
342
343 ((MutableTestPropertyHolder)holder).addProperty(name);
344 final int row = holder.getPropertyNames().length - 1;
345 propertiesModel.fireTableRowsInserted(row, row);
346 SwingUtilities.invokeLater( new Runnable()
347 {
348 public void run()
349 {
350 requestFocusInWindow();
351 scrollRectToVisible( propertiesTable.getCellRect( row,1,true ) );
352 SwingUtilities.invokeLater( new Runnable()
353 {
354 public void run()
355 {
356 propertiesTable.editCellAt(row, 1);
357 propertiesTable.getEditorComponent().requestFocusInWindow();
358 }
359 } );
360 }
361 } );
362
363 }
364 }
365 }
366
367 private class RemovePropertyAction extends AbstractAction
368 {
369 public RemovePropertyAction()
370 {
371 putValue(Action.SMALL_ICON, UISupport.createImageIcon("/remove_property.gif"));
372 putValue(Action.SHORT_DESCRIPTION, "Removes the selected property from the property list");
373 setEnabled(false);
374 }
375
376 public void actionPerformed(ActionEvent e)
377 {
378 int row = propertiesTable.getSelectedRow();
379 if (row == -1)
380 return;
381
382 UISupport.stopCellEditing(propertiesTable);
383
384 String propertyName = propertiesModel.getValueAt(row, 0).toString();
385 if (UISupport.confirm("Remove property [" + propertyName + "]?", "Remove Property"))
386 {
387 ((MutableTestPropertyHolder)holder).removeProperty( propertyName );
388 propertiesModel.fireTableRowsDeleted(row, row);
389 }
390 }
391 }
392
393 private class ClearPropertiesAction extends AbstractAction
394 {
395 public ClearPropertiesAction()
396 {
397 putValue(Action.SMALL_ICON, UISupport.createImageIcon("/clear_properties.gif"));
398 putValue(Action.SHORT_DESCRIPTION, "Clears all current property values");
399 }
400
401 public void actionPerformed(ActionEvent e)
402 {
403 if( UISupport.confirm("Clear all property values?", "Clear Properties"))
404 {
405 for( String name : holder.getPropertyNames() )
406 {
407 holder.getProperty( name ).setValue( null );
408 }
409 }
410 }
411 }
412
413 private class LoadPropertiesAction extends AbstractAction
414 {
415 public LoadPropertiesAction()
416 {
417 putValue(Action.SMALL_ICON, UISupport.createImageIcon("/load_properties.gif"));
418 putValue(Action.SHORT_DESCRIPTION, "Loads property values from an external file");
419 }
420
421 public void actionPerformed(ActionEvent e)
422 {
423 File file = UISupport.getFileDialogs().open(this, "Set properties source", null, null, null);
424 if (file != null)
425 {
426 try
427 {
428 boolean createMissing =
429 holder instanceof MutableTestPropertyHolder &&
430 UISupport.confirm("Create missing properties?", "Set Properties Source");
431
432 int cnt = 0;
433
434 Properties props = new Properties();
435 props.load( new FileInputStream( file ) );
436 for( Object obj : props.keySet() )
437 {
438 String name = obj.toString();
439 if( holder.hasProperty( name ))
440 {
441 holder.setPropertyValue( name, props.getProperty( name ) );
442 }
443 else if( createMissing )
444 {
445 ((MutableTestPropertyHolder)holder).addProperty( name ).setValue( props.getProperty( name ) );
446 }
447 }
448
449 UISupport.showInfoMessage("Loaded " + cnt + " properties from [" + file.getAbsolutePath() + "]");
450 }
451 catch (Exception e1)
452 {
453 UISupport.showErrorMessage("Failed to load properties from [" + file.getAbsolutePath() + "]; " + e1);
454 }
455 }
456 }
457 }
458
459 public TestPropertyHolder getHolder()
460 {
461 return holder;
462 }
463
464 public PropertiesModel getPropertiesModel()
465 {
466 return propertiesModel;
467 }
468
469 public final class PropertyHolderTablePropertyExpansionDropTarget implements DropTargetListener
470 {
471 public PropertyHolderTablePropertyExpansionDropTarget()
472 {
473 }
474
475 public void dragEnter( DropTargetDragEvent dtde )
476 {
477 if( !isAcceptable( dtde.getTransferable(), dtde.getLocation() ) )
478 dtde.rejectDrag();
479 }
480
481 public void dragExit( DropTargetEvent dtde )
482 {
483 }
484
485 public void dragOver( DropTargetDragEvent dtde )
486 {
487 if( !isAcceptable( dtde.getTransferable(), dtde.getLocation() ) )
488 {
489 dtde.rejectDrag();
490 }
491 else
492 {
493 dtde.acceptDrag( dtde.getDropAction() );
494 }
495 }
496
497 public void drop( DropTargetDropEvent dtde )
498 {
499 if( !isAcceptable( dtde.getTransferable(), dtde.getLocation() ) )
500 {
501 dtde.rejectDrop();
502 }
503 else
504 {
505 try
506 {
507 Transferable transferable = dtde.getTransferable();
508 Object transferData = transferable.getTransferData( transferable.getTransferDataFlavors()[0] );
509 if( transferData instanceof PropertyModelItem )
510 {
511 dtde.acceptDrop( dtde.getDropAction() );
512 PropertyModelItem modelItem = ( PropertyModelItem ) transferData;
513
514 String xpath = modelItem.getXPath();
515 if( xpath == null && XmlUtils.seemsToBeXml( modelItem.getProperty().getValue() ))
516 {
517 xpath = UISupport.selectXPath( "Create PropertyExpansion", "Select XPath below",
518 modelItem.getProperty().getValue(), null );
519
520 if( xpath != null )
521 xpath = XmlUtils.removeXPathNamespaceDeclarations( xpath );
522 }
523
524 PropertyExpansion propertyExpansion = new PropertyExpansionImpl( modelItem.getProperty(), xpath );
525
526 Point point = dtde.getLocation();
527 int column = getPropertiesTable().columnAtPoint( point );
528 int row = getPropertiesTable().rowAtPoint( point );
529
530 if( row == -1 )
531 {
532 if( holder instanceof MutableTestPropertyHolder )
533 {
534 MutableTestPropertyHolder mtph = ( MutableTestPropertyHolder ) holder;
535 String name = UISupport.prompt( "Specify unique name of property", "Add Property", modelItem.getProperty().getName() );
536 while( name != null && mtph.hasProperty( name ) )
537 {
538 name = UISupport.prompt( "Specify unique name of property", "Add Property", modelItem.getProperty().getName() );
539 }
540
541 if( name != null )
542 mtph.addProperty( name ).setValue( propertyExpansion.toString() );
543 }
544 }
545 else
546 {
547 getPropertiesTable().setValueAt( propertyExpansion.toString(), row, column );
548 }
549
550 dtde.dropComplete( true );
551 }
552 }
553 catch( Exception e )
554 {
555 SoapUI.logError( e );
556 }
557 }
558 }
559
560 public void dropActionChanged( DropTargetDragEvent dtde )
561 {
562 }
563
564 public boolean isAcceptable( Transferable transferable, Point point )
565 {
566 int row = getPropertiesTable().rowAtPoint( point );
567 if( row >= 0 )
568 {
569 int column = getPropertiesTable().columnAtPoint( point );
570 if( column != 1 )
571 return false;
572
573 if( !getPropertiesTable().isCellEditable( row, column ))
574 return false;
575 }
576 else if( !(getHolder() instanceof MutableTestPropertyHolder ))
577 {
578 return false;
579 }
580
581 DataFlavor[] flavors = transferable.getTransferDataFlavors();
582 for( int i = 0; i < flavors.length; i++ )
583 {
584 DataFlavor flavor = flavors[i];
585 if( flavor.isMimeTypeEqual( DataFlavor.javaJVMLocalObjectMimeType ) )
586 {
587 try
588 {
589 Object modelItem = transferable.getTransferData( flavor );
590 if( modelItem instanceof PropertyModelItem &&
591 ((PropertyModelItem)modelItem).getProperty().getModelItem() != getHolder().getModelItem() )
592 {
593 return PropertyExpansionUtils.canExpandProperty( getHolder().getModelItem(),
594 ((PropertyModelItem)modelItem).getProperty() );
595 }
596 }
597 catch( Exception ex )
598 {
599 SoapUI.logError( ex );
600 }
601 }
602 }
603
604 return false;
605 }
606 }
607 }