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.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
143 setSurrendersFocusOnKeystroke( true );
144 setRowHeight( 19 );
145
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
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 }