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