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