1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.wotonomy.ui.swing.components;
20
21 import java.awt.Color;
22 import java.awt.Component;
23 import java.awt.Font;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
26 import java.lang.reflect.Method;
27 import java.util.Hashtable;
28 import java.util.Vector;
29
30 import javax.swing.Timer;
31 import javax.swing.table.AbstractTableModel;
32
33 /***
34 * PropertyEditorTableModel introspects an object to facilitate
35 * editing it in a PropertyTable.
36 *
37 * Because the model always reflects the current state of the
38 * inspected object, it is useful to have a table update at
39 * automated intervals. By default, this feature is turned off.
40 * If you turn it on, you'll want to remember to turn it off
41 * when you're done with the table model.
42 *
43 * @author michael@mpowers.net
44 * @author $Author: cgruber $
45 * @version $Revision: 904 $
46 */
47 public class PropertyEditorTableModel extends AbstractTableModel implements ActionListener
48 {
49 protected Object inspectedObject = null;
50
51 final String[] columnNames = { "Property", "Value" };
52 static final String METHOD_TAG = " ";
53
54 Vector properties = new Vector();
55 Hashtable methods = new Hashtable(0);
56
57 public void setObject( Object o ) {
58 inspectedObject = o;
59 Class c = o.getClass();
60 Method[] m = c.getMethods();
61
62 properties = new Vector();
63 methods = new Hashtable(m.length, 1F);
64 String name, propertyName;
65 for ( int i = 0; i < m.length; i++ ) {
66
67
68
69
70 if (
71 ( ( m[i].getName().startsWith( "get" ) ) || ( m[i].getName().startsWith( "is" ) ) )
72 && ( m[i].getParameterTypes().length == 0 )
73 ) {
74 name = m[i].getName();
75 if ( m[i].getName().startsWith( "is" ) ) {
76 propertyName = name.substring( 2, name.length() );
77
78 } else {
79 propertyName = name.substring( 3, name.length() );
80 }
81 if (
82 ( m[i].getReturnType().getName().equals( String.class.getName() ) )
83 || ( m[i].getReturnType().getName().equals( "boolean" ) )
84 || ( m[i].getReturnType().getName().equals( "int" ) )
85 || ( m[i].getReturnType().getName().equals( "float" ) )
86 || ( m[i].getReturnType().getName().equals( "char" ) )
87 || ( m[i].getReturnType().getName().equals( Color.class.getName() ) )
88 || ( m[i].getReturnType().getName().equals( Font.class.getName() ) )
89 ) {
90 properties.addElement( propertyName );
91 methods.put( name, m[i] );
92 }
93 else
94 {
95
96 properties.addElement( propertyName + METHOD_TAG );
97 methods.put( propertyName + METHOD_TAG, m[i] );
98 }
99 }
100 else
101
102 if ( ( m[i].getName().startsWith( "set" ) ) &&
103 ( m[i].getParameterTypes().length == 1 ) ) {
104 name = m[i].getName();
105 if (
106 ( m[i].getParameterTypes()[0].getName().equals( String.class.getName() ) )
107 || ( m[i].getParameterTypes()[0].getName().equals( "boolean" ) )
108 || ( m[i].getParameterTypes()[0].getName().equals( "int" ) )
109 || ( m[i].getParameterTypes()[0].getName().equals( "float" ) )
110 || ( m[i].getParameterTypes()[0].getName().equals( Color.class.getName() ) )
111
112 ) {
113
114 methods.put( name, m[i] );
115 } else {
116
117 }
118 }
119 else
120
121 if ( m[i].getParameterTypes().length == 0 )
122 {
123 properties.addElement( m[i].getName() + METHOD_TAG );
124 methods.put( m[i].getName() + METHOD_TAG, m[i] );
125 }
126
127 }
128
129 sort(properties);
130 fireTableDataChanged();
131 }
132
133 public int getColumnCount() {
134 return columnNames.length;
135 }
136
137 public int getRowCount() {
138 return properties.size();
139 }
140
141 public String getColumnName(int col) {
142 return columnNames[col];
143 }
144
145 public Object getValueAt(int row, int col) {
146 if ( col == 0 )
147 return properties.elementAt( row );
148 else
149 {
150 Method m = null;
151 m = (Method) methods.get( "get" + ( (String) properties.elementAt( row ) ) ) ;
152 if ( m == null )
153 m = (Method) methods.get( "is" + ( (String) properties.elementAt( row ) ) ) ;
154 if ( m == null ) {
155 m = (Method) methods.get( (String) properties.elementAt( row ) ) ;
156 if ( m != null ) return m;
157 }
158 try {
159 return m.invoke( inspectedObject, (Object[])null );
160 } catch ( Exception exc ) {
161 System.out.println( "InspectorFrame.tableModel.getValueAt: error occured while reflecting: " );
162 System.out.println( exc );
163 }
164 return null;
165 }
166 }
167
168 public Class getColumnClass( int col ) {
169
170
171
172
173
174
175 return new String().getClass();
176 }
177
178 public Class getCellClass(int row, int col) {
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203 Object o = getValueAt( row, col );
204 if ( o == null ) o = "null";
205 return o.getClass();
206 }
207
208
209
210
211
212 public boolean isCellEditable(int row, int col) {
213
214
215 if (col < 1) {
216 return false;
217 } else {
218
219 if ( ((String)properties.elementAt(row)).endsWith(METHOD_TAG) ) return true;
220
221 Method m = (Method) methods.get( "set" + ( (String) properties.elementAt( row ) ) ) ;
222 if ( m == null )
223 return false;
224 else
225 return true;
226 }
227 }
228
229
230
231
232
233 public void setValueAt(Object value, int row, int col) {
234
235 if ( inspectedObject == null ) return;
236
237 if ( ((String)properties.elementAt(row)).endsWith( METHOD_TAG ) )
238 {
239 fireTableDataChanged();
240 return;
241 };
242
243
244 Method m = (Method) methods.get( "set" + ( (String) properties.elementAt( row ) ) ) ;
245 String parameterType = m.getParameterTypes()[0].getName();
246
247
248 if (
249 ( parameterType.equals( "int" ) )
250 || ( parameterType.equals( "java.lang.Integer" ) )
251 )
252 {
253 try {
254 value = new Integer((String)value);
255 } catch (NumberFormatException e) {
256 System.out.println("PropertyEditorTableModel.setValueAt: User attempted to enter non-integer"
257 + " value (" + value
258 + ") into an integer-only column.");
259 }
260 }
261 Object[] parameters = { value };
262 try {
263 m.invoke( inspectedObject, parameters );
264 if ( inspectedObject instanceof Component ) {
265 Component c = (Component)inspectedObject;
266 if ( c.getParent() != null )
267 c.getParent().repaint();
268 }
269 } catch ( Exception exc ) {
270 System.out.println( "PropertyEditorTableModel.setValueAt: error occured while reflecting: " );
271 System.out.println( exc );
272 }
273
274 fireTableDataChanged();
275 }
276
277
278 protected void sort(Vector v){
279 quickSort(v, 0, v.size()-1);
280 }
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299 private void quickSort(Vector v, int lo0, int hi0) {
300 int lo = lo0;
301 int hi = hi0;
302 String mid;
303
304 if (hi0 > lo0) {
305
306
307 mid = (String) v.elementAt((lo0 + hi0) / 2);
308
309
310 while(lo <= hi) {
311
312
313
314
315
316 while((lo < hi0) && lt((String)v.elementAt(lo), mid)) {
317 ++lo;
318 }
319
320
321
322 while((hi > lo0) && lt(mid, (String)v.elementAt(hi))) {
323 --hi;
324 }
325
326
327 if(lo <= hi) {
328 swap(v, lo, hi);
329 ++lo;
330 --hi;
331 }
332 }
333
334
335
336
337 if(lo0 < hi) {
338 quickSort(v, lo0, hi);
339 }
340
341
342
343 if(lo < hi0) {
344 quickSort(v, lo, hi0);
345 }
346
347 }
348 }
349
350 private void swap(Vector a, int i, int j) {
351 Object T = a.elementAt(i);
352 a.setElementAt(a.elementAt(j), i);
353 a.setElementAt(T, j);
354 }
355
356 protected boolean lt(String a, String b) {
357 return a.compareTo(b) < 0;
358 }
359
360
361
362 private boolean autoUpdating = false;
363 private int updateInterval = 2000;
364 protected Timer timer = null;
365
366 public boolean isAutoUpdating()
367 {
368 return autoUpdating;
369 }
370
371 public void setAutoUpdating( boolean shouldAutoUpdate )
372 {
373 if ( shouldAutoUpdate )
374 {
375 if ( timer == null )
376 {
377 timer = new Timer( updateInterval, this );
378 timer.setRepeats( true );
379 timer.start();
380 }
381 }
382 else
383 {
384 if ( timer != null )
385 {
386 timer.stop();
387 timer = null;
388 }
389 }
390
391 autoUpdating = shouldAutoUpdate;
392 }
393
394 public int getUpdateInterval()
395 {
396 return updateInterval;
397 }
398
399 public void setUpdateInterval( int anInterval )
400 {
401 if ( timer != null )
402 {
403 timer.setDelay( anInterval );
404 }
405
406 updateInterval = anInterval;
407 }
408
409 public void actionPerformed( ActionEvent evt )
410 {
411 if ( evt.getSource() == timer )
412 {
413 fireTableDataChanged();
414 }
415 }
416
417 }
418