1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.support.components;
14
15 import java.awt.BorderLayout;
16 import java.awt.Color;
17 import java.awt.Component;
18 import java.awt.Font;
19 import java.awt.Toolkit;
20 import java.awt.datatransfer.StringSelection;
21 import java.awt.event.ActionEvent;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.lang.reflect.InvocationTargetException;
25 import java.util.ArrayList;
26 import java.util.List;
27
28 import javax.swing.AbstractAction;
29 import javax.swing.Action;
30 import javax.swing.BorderFactory;
31 import javax.swing.DefaultCellEditor;
32 import javax.swing.JComboBox;
33 import javax.swing.JComponent;
34 import javax.swing.JPanel;
35 import javax.swing.JScrollPane;
36 import javax.swing.JTable;
37 import javax.swing.JTextField;
38 import javax.swing.TransferHandler;
39 import javax.swing.border.TitledBorder;
40 import javax.swing.table.AbstractTableModel;
41 import javax.swing.table.DefaultTableCellRenderer;
42 import javax.swing.table.TableCellEditor;
43 import javax.swing.table.TableModel;
44
45 import org.apache.commons.beanutils.BeanUtils;
46 import org.apache.commons.beanutils.PropertyUtils;
47
48 import com.eviware.soapui.SoapUI;
49 import com.eviware.soapui.support.PropertyChangeNotifier;
50
51 /***
52 * Table for displaying property name/value pairs
53 *
54 * @author Ole.Matzura
55 */
56
57 public class JPropertiesTable<T> extends JPanel
58 {
59 public final static Object[] BOOLEAN_OPTIONS = new Object[] {Boolean.TRUE, Boolean.FALSE };
60
61 private PropertiesTableModel<T> tableModel;
62 private JTable table;
63
64 public JPropertiesTable( String title )
65 {
66 this( title, null );
67 }
68
69 public JPropertiesTable( String title, T propertyObject )
70 {
71 super( new BorderLayout());
72
73 tableModel = new PropertiesTableModel<T>( propertyObject );
74 table = new PTable( tableModel );
75
76 table.getColumnModel().getColumn(0).setHeaderValue( "Property" );
77 table.getColumnModel().getColumn(1).setHeaderValue( "Value" );
78 table.getColumnModel().getColumn(0).setCellRenderer( new PropertiesTableCellRenderer() );
79 table.getColumnModel().getColumn(1).setCellRenderer( new PropertiesTableCellRenderer() );
80
81 add( new JScrollPane( table ), BorderLayout.CENTER );
82 if( title != null )
83 {
84 TitledBorder titledBorder = BorderFactory.createTitledBorder( BorderFactory.createEmptyBorder(), title );
85 titledBorder.setTitleFont( titledBorder.getTitleFont().deriveFont( Font.PLAIN, 11 ));
86 setBorder( titledBorder);
87 }
88
89 table.setBackground( Color.WHITE );
90 setPreferredSize( table.getPreferredSize());
91 }
92
93 @Override
94 public void removeNotify()
95 {
96 getTableModel().release();
97 super.removeNotify();
98 }
99
100 @Override
101 public void addNotify()
102 {
103 getTableModel().attach();
104 super.addNotify();
105 }
106
107 public void setPropertyObject( T propertyObject )
108 {
109 if( table.isEditing() )
110 table.getCellEditor().stopCellEditing();
111
112 tableModel.setPropertyObject( propertyObject );
113 }
114
115 public PropertiesTableModel getTableModel()
116 {
117 return tableModel;
118 }
119
120 public PropertyDescriptor addProperty( String caption, String name)
121 {
122 return addProperty( caption, name, false );
123 }
124
125 public PropertyDescriptor addProperty( String caption, String name, boolean editable )
126 {
127 return addProperty( caption, name, editable, null );
128 }
129
130 public PropertyDescriptor addProperty( String caption, String name, boolean editable, PropertyFormatter formatter )
131 {
132 return tableModel.addProperty( caption, name, editable, formatter );
133 }
134
135 public static final class PropertiesTableModel<T> extends AbstractTableModel implements PropertyChangeListener
136 {
137 private List<PropertyDescriptor> properties = new ArrayList<PropertyDescriptor>();
138 private T propertyObject;
139 private boolean attached;
140
141 public PropertiesTableModel(T propertyObject)
142 {
143 this.propertyObject = propertyObject;
144 }
145
146 public void attach()
147 {
148 if( !attached && propertyObject instanceof PropertyChangeNotifier )
149 {
150 ((PropertyChangeNotifier)propertyObject).addPropertyChangeListener( this );
151 attached = true;
152 }
153 }
154
155 public void setPropertyObject(T propertyObject)
156 {
157 release();
158 this.propertyObject = propertyObject;
159 attach();
160 fireTableDataChanged();
161 }
162
163 public PropertyDescriptor addProperty( String caption, String name, boolean editable, PropertyFormatter formatter )
164 {
165 PropertyDescriptor propertyDescriptor = new PropertyDescriptor( caption, name, editable, formatter );
166 properties.add( propertyDescriptor);
167 return propertyDescriptor;
168 }
169
170 public PropertyDescriptor addProperty( String caption, String name, Object [] options )
171 {
172 PropertyDescriptor propertyDescriptor = new PropertyDescriptor( caption, name, options );
173 properties.add( propertyDescriptor);
174 return propertyDescriptor;
175 }
176
177 public int getRowCount()
178 {
179 return properties.size();
180 }
181
182 public int getColumnCount()
183 {
184 return 2;
185 }
186
187 public boolean isCellEditable(int rowIndex, int columnIndex)
188 {
189 if( columnIndex == 0 || propertyObject == null ) return false;
190 return properties.get( rowIndex ).isEditable() &&
191 PropertyUtils.isWriteable( propertyObject, properties.get( rowIndex ).getName() );
192 }
193
194 public void setValueAt(Object aValue, int rowIndex, int columnIndex)
195 {
196 try
197 {
198 if( propertyObject != null && columnIndex == 1 && properties.get( rowIndex ).isEditable() )
199 {
200 BeanUtils.setProperty( propertyObject, properties.get( rowIndex ).getName(), aValue );
201 }
202 }
203 catch (IllegalAccessException e)
204 {
205 SoapUI.logError( e );
206 }
207 catch (InvocationTargetException e)
208 {
209 SoapUI.logError( e );
210 }
211 }
212
213 public Object getValueAt(int rowIndex, int columnIndex)
214 {
215 if( propertyObject == null )
216 return null;
217
218 try
219 {
220 PropertyDescriptor propertyDescriptor = properties.get(rowIndex);
221 switch (columnIndex)
222 {
223 case 0:
224 return propertyDescriptor.getCaption();
225 case 1:
226 {
227 Object value = PropertyUtils.getSimpleProperty(propertyObject,propertyDescriptor.getName());
228 return propertyDescriptor.getFormatter().format( propertyDescriptor.getName(), value );
229 }
230 }
231 }
232 catch (IllegalAccessException e)
233 {
234 SoapUI.logError( e );
235 }
236 catch (InvocationTargetException e)
237 {
238 SoapUI.logError( e );
239 }
240 catch (NoSuchMethodException e)
241 {
242 SoapUI.logError( e );
243 }
244
245 return null;
246 }
247
248 public PropertyDescriptor getPropertyDescriptorAt( int row )
249 {
250 return properties.get( row );
251 }
252
253 public void propertyChange(PropertyChangeEvent evt)
254 {
255 fireTableDataChanged();
256 }
257
258 public void release()
259 {
260 if( propertyObject instanceof PropertyChangeNotifier && attached )
261 {
262 ((PropertyChangeNotifier)propertyObject).removePropertyChangeListener( this );
263 attached = false;
264 }
265 }}
266
267 public static class PropertyDescriptor
268 {
269 private final String caption;
270 private final String name;
271 private boolean editable;
272 private PropertyFormatter formatter ;
273 private Object [] options;
274 private DefaultCellEditor cellEditor;
275
276 public PropertyDescriptor(String caption, String name, boolean editable, PropertyFormatter formatter)
277 {
278 this.caption = caption;
279 this.name = name;
280 this.editable = editable;
281 this.formatter = formatter;
282
283 JTextField textField = new JTextField();
284 textField.setBorder(BorderFactory.createEmptyBorder());
285 cellEditor = new DefaultCellEditor( textField );
286 }
287
288 public PropertyDescriptor(String caption, String name, Object[] options)
289 {
290 this.caption = caption;
291 this.name = name;
292 this.options = options;
293 editable = true;
294
295 JComboBox comboBox = new JComboBox( options );
296
297 if( options[0] == null )
298 {
299 comboBox.setEditable( true );
300 comboBox.removeItemAt( 0 );
301 }
302
303 comboBox.setBorder(null);
304 cellEditor = new DefaultCellEditor( comboBox );
305 }
306
307 public void setFormatter( PropertyFormatter formatter )
308 {
309 this.formatter = formatter;
310 }
311
312 public PropertyFormatter getFormatter()
313 {
314 return formatter == null ? DefaultFormatter.getInstance() : formatter;
315 }
316
317 public String getCaption()
318 {
319 return caption;
320 }
321
322 public boolean isEditable()
323 {
324 return editable;
325 }
326
327 public Object[] getOptions()
328 {
329 return options;
330 }
331
332 public boolean hasOptions()
333 {
334 return options != null;
335 }
336
337 public String getName()
338 {
339 return name;
340 }
341
342 public TableCellEditor getCellEditor()
343 {
344 return cellEditor;
345 }
346 }
347
348 private static class PropertiesTableCellRenderer extends DefaultTableCellRenderer
349 {
350 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
351 {
352 Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
353 row, column);
354
355 if( component instanceof JComponent )
356 {
357 if( value != null && value.toString().trim().length() > 0 )
358 {
359 ((JComponent)component).setToolTipText( value.toString() );
360 }
361 else
362 {
363 ((JComponent)component).setToolTipText( null );
364 }
365 }
366
367 return component;
368 }
369 }
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413 /***
414 * Formatter used for displaying property values
415 *
416 * @author Ole.Matzura
417 */
418
419 public interface PropertyFormatter
420 {
421 public Object format( String propertyName, Object value );
422 }
423
424 private static class DefaultFormatter implements PropertyFormatter
425 {
426 private static PropertyFormatter instance;
427
428 public static PropertyFormatter getInstance()
429 {
430 if( instance == null )
431 instance = new DefaultFormatter();
432
433 return instance;
434 }
435
436 public Object format(String propertyName, Object value)
437 {
438 return value;
439 }
440 }
441
442 public void addProperty(String caption, String name, Object [] options)
443 {
444 tableModel.addProperty( caption, name, options );
445 }
446
447 private class PTable extends JTable
448 {
449 public PTable( TableModel tableModel )
450 {
451 super( tableModel );
452
453
454
455 getActionMap().put( TransferHandler.getCopyAction().getValue(Action.NAME), new AbstractAction()
456 {
457 public void actionPerformed(ActionEvent e)
458 {
459 int row = getSelectedRow();
460 if( row == -1 )
461 return;
462
463 StringSelection selection = new StringSelection( getValueAt( row, 1 ).toString() );
464 Toolkit.getDefaultToolkit().getSystemClipboard().setContents( selection, selection );
465 }});
466
467 putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
468
469
470
471
472
473
474
475
476 }
477
478 public TableCellEditor getCellEditor(int row, int column)
479 {
480 if( column == 0 )
481 return super.getCellEditor(row, column);
482 else
483 return tableModel.getPropertyDescriptorAt( row ).getCellEditor();
484 }
485 }
486 }