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 setRowHeight( 19 );
121
122 }
123
124 public PropertyModelItem getTestProperty()
125 {
126 int index = getSelectedRow();
127 if( index == -1 )
128 return null;
129 TestProperty property = propertiesModel.getPropertyAtRow( index );
130 return new PropertyModelItem( property, true );
131 }
132 }
133
134 private Component buildToolbar()
135 {
136 toolbar = UISupport.createSmallToolbar();
137
138 if( holder instanceof MutableTestPropertyHolder )
139 {
140 removePropertyAction = new RemovePropertyAction();
141 addPropertyAction = new AddPropertyAction();
142 movePropertyUpAction = new MovePropertyUpAction();
143 movePropertyDownAction = new MovePropertyDownAction();
144
145 JButton addPropertyButton = UISupport.createToolbarButton( addPropertyAction );
146 toolbar.add( addPropertyButton );
147 JButton removePropertyButton = UISupport.createToolbarButton( removePropertyAction );
148 toolbar.add( removePropertyButton );
149
150 JButton movePropertyUpButton = UISupport.createToolbarButton( movePropertyUpAction );
151 toolbar.add( movePropertyUpButton );
152 JButton movePropertyDownButton = UISupport.createToolbarButton( movePropertyDownAction );
153 toolbar.add( movePropertyDownButton );
154 }
155
156 JButton clearPropertiesButton = UISupport.createToolbarButton( new ClearPropertiesAction() );
157 toolbar.add( clearPropertiesButton );
158 JButton loadPropertiesButton = UISupport.createToolbarButton( loadPropertiesAction );
159 toolbar.add( loadPropertiesButton );
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 @Override
314 public Class<?> getColumnClass( int columnIndex )
315 {
316 return String.class;
317 }
318
319 public TestProperty getPropertyAtRow( int rowIndex )
320 {
321 return holder.getProperty( names.get( rowIndex ) );
322 }
323
324 public Object getValueAt( int rowIndex, int columnIndex )
325 {
326 TestProperty property = holder.getProperty( names.get( rowIndex ) );
327 if( property == null )
328 return null;
329
330 switch( columnIndex )
331 {
332 case 0:
333 return property.getName();
334 case 1:
335 return property.getValue();
336 }
337
338 return null;
339 }
340 }
341
342 private class AddPropertyAction extends AbstractAction
343 {
344 public AddPropertyAction()
345 {
346 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/add_property.gif" ) );
347 putValue( Action.SHORT_DESCRIPTION, "Adds a property to the property list" );
348 }
349
350 public void actionPerformed( ActionEvent e )
351 {
352 String name = UISupport.prompt( "Specify unique property name", "Add Property", "" );
353 if( StringUtils.hasContent( name ) )
354 {
355 if( holder.hasProperty( name ) )
356 {
357 UISupport.showErrorMessage( "Property name [" + name + "] already exists.." );
358 return;
359 }
360
361 ( (MutableTestPropertyHolder) holder ).addProperty( name );
362 final int row = holder.getPropertyNames().length - 1;
363 propertiesModel.fireTableRowsInserted( row, row );
364 SwingUtilities.invokeLater( new Runnable()
365 {
366 public void run()
367 {
368 requestFocusInWindow();
369 scrollRectToVisible( propertiesTable.getCellRect( row, 1, true ) );
370 SwingUtilities.invokeLater( new Runnable()
371 {
372 public void run()
373 {
374 propertiesTable.editCellAt( row, 1 );
375 Component editorComponent = propertiesTable.getEditorComponent();
376 if( editorComponent != null )
377 editorComponent.requestFocusInWindow();
378 }
379 } );
380 }
381 } );
382
383 }
384 }
385 }
386
387 private class RemovePropertyAction extends AbstractAction
388 {
389 public RemovePropertyAction()
390 {
391 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/remove_property.gif" ) );
392 putValue( Action.SHORT_DESCRIPTION, "Removes the selected property from the property list" );
393 setEnabled( false );
394 }
395
396 public void actionPerformed( ActionEvent e )
397 {
398 int row = propertiesTable.getSelectedRow();
399 if( row == -1 )
400 return;
401
402 UISupport.stopCellEditing( propertiesTable );
403
404 String propertyName = propertiesModel.getValueAt( row, 0 ).toString();
405 if( UISupport.confirm( "Remove property [" + propertyName + "]?", "Remove Property" ) )
406 {
407 ( (MutableTestPropertyHolder) holder ).removeProperty( propertyName );
408 propertiesModel.fireTableRowsDeleted( row, row );
409 }
410 }
411 }
412
413 private class ClearPropertiesAction extends AbstractAction
414 {
415 public ClearPropertiesAction()
416 {
417 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clear_properties.gif" ) );
418 putValue( Action.SHORT_DESCRIPTION, "Clears all current property values" );
419 }
420
421 public void actionPerformed( ActionEvent e )
422 {
423 if( UISupport.confirm( "Clear all property values?", "Clear Properties" ) )
424 {
425 for( String name : holder.getPropertyNames() )
426 {
427 holder.getProperty( name ).setValue( null );
428 }
429 }
430 }
431 }
432
433 private class MovePropertyUpAction extends AbstractAction
434 {
435 public MovePropertyUpAction()
436 {
437 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/up_arrow.gif" ) );
438 putValue( Action.SHORT_DESCRIPTION, "Moves selected property up one row" );
439 setEnabled( false );
440 }
441
442 public void actionPerformed( ActionEvent e )
443 {
444 int ix = propertiesTable.getSelectedRow();
445 if( ix != -1 )
446 {
447 ( (MutableTestPropertyHolder) holder ).moveProperty(
448 holder.getPropertyAt( ix ).getName(), ix - 1 );
449 propertiesTable.setRowSelectionInterval( ix - 1, ix - 1 );
450 }
451 }
452 }
453
454 private class MovePropertyDownAction extends AbstractAction
455 {
456 public MovePropertyDownAction()
457 {
458 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/down_arrow.gif" ) );
459 putValue( Action.SHORT_DESCRIPTION, "Moves selected property down one row" );
460 setEnabled( false );
461 }
462
463 public void actionPerformed( ActionEvent e )
464 {
465 int ix = propertiesTable.getSelectedRow();
466 if( ix != -1 )
467 {
468 ( (MutableTestPropertyHolder) holder ).moveProperty(
469 holder.getPropertyAt( ix ).getName(), ix + 1 );
470
471 propertiesTable.setRowSelectionInterval( ix + 1, ix + 1 );
472 }
473 }
474 }
475
476 private class LoadPropertiesAction extends AbstractAction
477 {
478 public LoadPropertiesAction()
479 {
480 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/load_properties.gif" ) );
481 putValue( Action.SHORT_DESCRIPTION, "Loads property values from an external file" );
482 }
483
484 public void actionPerformed( ActionEvent e )
485 {
486 File file = UISupport.getFileDialogs().open( this, "Set properties source", null, null, null );
487 if( file != null )
488 {
489 try
490 {
491 boolean createMissing =
492 holder instanceof MutableTestPropertyHolder &&
493 UISupport.confirm( "Create missing properties?", "Set Properties Source" );
494
495 Properties props = new Properties();
496 props.load( new FileInputStream( file ) );
497 for( Object obj : props.keySet() )
498 {
499 String name = obj.toString();
500 if( holder.hasProperty( name ) )
501 {
502 holder.setPropertyValue( name, props.getProperty( name ) );
503 }
504 else if( createMissing )
505 {
506 ( (MutableTestPropertyHolder) holder ).addProperty( name ).setValue( props.getProperty( name ) );
507 }
508 }
509
510 UISupport.showInfoMessage( "Loaded " + props.size() + " properties from [" + file.getAbsolutePath() + "]" );
511 }
512 catch( Exception e1 )
513 {
514 UISupport.showErrorMessage( "Failed to load properties from [" + file.getAbsolutePath() + "]; " + e1 );
515 }
516 }
517 }
518 }
519
520 public TestPropertyHolder getHolder()
521 {
522 return holder;
523 }
524
525 public PropertiesModel getPropertiesModel()
526 {
527 return propertiesModel;
528 }
529
530 public final class PropertyHolderTablePropertyExpansionDropTarget implements DropTargetListener
531 {
532 public PropertyHolderTablePropertyExpansionDropTarget()
533 {
534 }
535
536 public void dragEnter( DropTargetDragEvent dtde )
537 {
538 if( !isAcceptable( dtde.getTransferable(), dtde.getLocation() ) )
539 dtde.rejectDrag();
540 }
541
542 public void dragExit( DropTargetEvent dtde )
543 {
544 }
545
546 public void dragOver( DropTargetDragEvent dtde )
547 {
548 if( !isAcceptable( dtde.getTransferable(), dtde.getLocation() ) )
549 {
550 dtde.rejectDrag();
551 }
552 else
553 {
554 dtde.acceptDrag( dtde.getDropAction() );
555 }
556 }
557
558 public void drop( DropTargetDropEvent dtde )
559 {
560 if( !isAcceptable( dtde.getTransferable(), dtde.getLocation() ) )
561 {
562 dtde.rejectDrop();
563 }
564 else
565 {
566 try
567 {
568 Transferable transferable = dtde.getTransferable();
569 Object transferData = transferable.getTransferData( transferable.getTransferDataFlavors()[0] );
570 if( transferData instanceof PropertyModelItem )
571 {
572 dtde.acceptDrop( dtde.getDropAction() );
573 PropertyModelItem modelItem = (PropertyModelItem) transferData;
574
575 String xpath = modelItem.getXPath();
576 if( xpath == null && XmlUtils.seemsToBeXml( modelItem.getProperty().getValue() ) )
577 {
578 xpath = UISupport.selectXPath( "Create PropertyExpansion", "Select XPath below",
579 modelItem.getProperty().getValue(), null );
580
581 if( xpath != null )
582 xpath = XmlUtils.removeXPathNamespaceDeclarations( xpath );
583 }
584
585 PropertyExpansion propertyExpansion = new PropertyExpansionImpl( modelItem.getProperty(), xpath );
586
587 Point point = dtde.getLocation();
588 int column = getPropertiesTable().columnAtPoint( point );
589 int row = getPropertiesTable().rowAtPoint( point );
590
591 if( row == -1 )
592 {
593 if( holder instanceof MutableTestPropertyHolder )
594 {
595 MutableTestPropertyHolder mtph = (MutableTestPropertyHolder) holder;
596 String name = UISupport.prompt( "Specify unique name of property", "Add Property", modelItem.getProperty().getName() );
597 while( name != null && mtph.hasProperty( name ) )
598 {
599 name = UISupport.prompt( "Specify unique name of property", "Add Property", modelItem.getProperty().getName() );
600 }
601
602 if( name != null )
603 mtph.addProperty( name ).setValue( propertyExpansion.toString() );
604 }
605 }
606 else
607 {
608 getPropertiesTable().setValueAt( propertyExpansion.toString(), row, column );
609 }
610
611 dtde.dropComplete( true );
612 }
613 }
614 catch( Exception e )
615 {
616 SoapUI.logError( e );
617 }
618 }
619 }
620
621 public void dropActionChanged( DropTargetDragEvent dtde )
622 {
623 }
624
625 public boolean isAcceptable( Transferable transferable, Point point )
626 {
627 int row = getPropertiesTable().rowAtPoint( point );
628 if( row >= 0 )
629 {
630 int column = getPropertiesTable().columnAtPoint( point );
631 if( column != 1 )
632 return false;
633
634 if( !getPropertiesTable().isCellEditable( row, column ) )
635 return false;
636 }
637 else if( !( getHolder() instanceof MutableTestPropertyHolder ) )
638 {
639 return false;
640 }
641
642 DataFlavor[] flavors = transferable.getTransferDataFlavors();
643 for( int i = 0; i < flavors.length; i++ )
644 {
645 DataFlavor flavor = flavors[i];
646 if( flavor.isMimeTypeEqual( DataFlavor.javaJVMLocalObjectMimeType ) )
647 {
648 try
649 {
650 Object modelItem = transferable.getTransferData( flavor );
651 if( modelItem instanceof PropertyModelItem &&
652 ( (PropertyModelItem) modelItem ).getProperty().getModelItem() != getHolder().getModelItem() )
653 {
654 return PropertyExpansionUtils.canExpandProperty( getHolder().getModelItem(),
655 ( (PropertyModelItem) modelItem ).getProperty() );
656 }
657 }
658 catch( Exception ex )
659 {
660 SoapUI.logError( ex );
661 }
662 }
663 }
664
665 return false;
666 }
667 }
668 }