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