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