001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.admin.common;
005:
006: import java.lang.reflect.Method;
007: import java.util.ArrayList;
008: import java.util.HashMap;
009:
010: import javax.swing.table.AbstractTableModel;
011:
012: /**
013: * Displays an object's primitive properties in a PropertySheet-like way.
014: */
015:
016: public class PropertyTableModel extends AbstractTableModel {
017: private Class m_type;
018:
019: private Object m_instance;
020:
021: private String[] m_fieldNames;
022:
023: private String[] m_headings;
024:
025: protected Method m_getters[];
026:
027: protected Method m_setters[];
028:
029: protected Method m_ops[];
030:
031: protected static final HashMap m_primitiveMap = new HashMap();
032:
033: private static final String FIELD_HEADER = "Field";
034: private static final String VALUE_HEADER = "Value";
035:
036: public static final int FIELD_COLUMN = 0;
037: public static final int VALUE_COLUMN = 1;
038: public static final int COLUMN_COUNT = 2;
039:
040: static {
041: m_primitiveMap.put(Double.TYPE, Double.class);
042: m_primitiveMap.put(Integer.TYPE, Integer.class);
043: m_primitiveMap.put(Boolean.TYPE, Boolean.class);
044: m_primitiveMap.put(Character.TYPE, Character.class);
045: m_primitiveMap.put(Byte.TYPE, Byte.class);
046: m_primitiveMap.put(Float.TYPE, Float.class);
047: m_primitiveMap.put(Long.TYPE, Long.class);
048: }
049:
050: public PropertyTableModel() {
051: super ();
052: }
053:
054: public PropertyTableModel(Object instance) {
055: this (instance, null, null);
056: }
057:
058: public PropertyTableModel(Object instance, String[] fields) {
059: this (instance, fields, null);
060: }
061:
062: public PropertyTableModel(Class type) {
063: this (type, null, null);
064: }
065:
066: public PropertyTableModel(Class type, String[] fields) {
067: this (type, fields, null);
068: }
069:
070: public PropertyTableModel(Object instance, String[] fields,
071: String[] headings) {
072: this (instance.getClass(), fields, headings);
073: setInstance(instance);
074: }
075:
076: public PropertyTableModel(Class type, String[] fields,
077: String[] headers) {
078: super ();
079: init(type, fields, headers);
080: }
081:
082: public void setInstance(Object instance) {
083: m_instance = instance;
084: fireTableDataChanged();
085: }
086:
087: public Object getInstance() {
088: return m_instance;
089: }
090:
091: public void init(Class type, String[] fields, String[] headings) {
092: m_type = type;
093: m_fieldNames = determineFields(fields);
094: m_headings = determineHeadings(headings);
095:
096: setup();
097: }
098:
099: public void setup() {
100: if (m_type != null) {
101: int size = m_fieldNames.length;
102:
103: m_setters = new Method[size];
104: m_getters = new Method[size];
105: m_ops = new Method[size];
106:
107: for (int i = 0; i < m_fieldNames.length; i++) {
108: determineMethods(i, m_fieldNames[i]);
109: }
110: }
111: }
112:
113: private Class _mapPrimitive(Class c) {
114: return (Class) m_primitiveMap.get(c);
115: }
116:
117: /**
118: * If fieldNames == null, determine the set of primitive setters
119: * and construct a "fieldName" from the method name:
120: * void setMyCoolInteger(int) --> MyCoolInteger
121: */
122: private String[] determineFields(String fieldNames[]) {
123: if (fieldNames == null) {
124: if (m_type != null) {
125: Method method;
126: Method[] methods = m_type.getMethods();
127: ArrayList fieldList = new ArrayList();
128: String methodName;
129: Class returnType;
130: Class[] paramTypes;
131:
132: for (int i = 0; i < methods.length; i++) {
133: method = methods[i];
134: returnType = method.getReturnType();
135: paramTypes = method.getParameterTypes();
136: methodName = method.getName();
137:
138: if (paramTypes.length == 0
139: && (methodName.startsWith("get") || methodName
140: .startsWith("is"))
141: && (returnType.isPrimitive()
142: || returnType.equals(String.class)
143: || returnType
144: .equals(java.util.Date.class) || hasEditor(returnType))) {
145: int j = 0;
146:
147: while (!Character.isUpperCase(methodName
148: .charAt(j)))
149: j++;
150: fieldList.add(methodName.substring(j));
151: } else if (paramTypes.length == 0
152: && returnType == Void.TYPE) {
153: fieldList.add(methodName);
154: }
155: }
156:
157: fieldNames = (String[]) fieldList
158: .toArray(new String[] {});
159: }
160: }
161:
162: return fieldNames;
163: }
164:
165: /**
166: * Convert a Class field name to a reasonable display form:
167: * int myCoolInteger --> My cool integer
168: */
169: private static String fieldName2Heading(String fieldName) {
170: StringBuffer sb = new StringBuffer();
171: int len = fieldName.length();
172: char c;
173:
174: sb.append(Character.toUpperCase(fieldName.charAt(0)));
175:
176: for (int i = 1; i < len; i++) {
177: c = fieldName.charAt(i);
178:
179: if (Character.isUpperCase(c)) {
180: sb.append(" ");
181: sb.append(Character.toLowerCase(c));
182: } else {
183: sb.append(c);
184: }
185: }
186:
187: return sb.toString();
188: }
189:
190: private String[] determineHeadings(String headings[]) {
191: if (headings == null) {
192: ArrayList headingList = new ArrayList();
193:
194: for (int i = 0; i < m_fieldNames.length; i++) {
195: headingList.add(fieldName2Heading(m_fieldNames[i]));
196: }
197:
198: headings = (String[]) headingList.toArray(new String[] {});
199: }
200:
201: return headings;
202: }
203:
204: private void determineMethods(int index, String name) {
205: Method[] methods = m_type.getMethods();
206: Method method;
207: String methodName;
208: Class returnType;
209: Class[] paramTypes;
210:
211: for (int i = 0; i < methods.length; i++) {
212: method = methods[i];
213: returnType = method.getReturnType();
214: paramTypes = method.getParameterTypes();
215: methodName = method.getName();
216:
217: if (("set" + name).equals(methodName)
218: && paramTypes.length == 1
219: && (paramTypes[0].isPrimitive()
220: || paramTypes[0].equals(String.class)
221: || paramTypes[0]
222: .equals(java.util.Date.class) || hasEditor(paramTypes[0]))) {
223: m_setters[index] = method;
224: break;
225: }
226: }
227:
228: for (int i = 0; i < methods.length; i++) {
229: method = methods[i];
230: returnType = method.getReturnType();
231: paramTypes = method.getParameterTypes();
232: methodName = method.getName();
233:
234: if ((("get" + name).equals(methodName) || ("is" + name)
235: .equals(methodName))
236: && paramTypes.length == 0
237: && (returnType.isPrimitive()
238: || returnType.equals(String.class)
239: || returnType.equals(java.util.Date.class) || hasEditor(returnType))) {
240: m_getters[index] = method;
241: break;
242: }
243: }
244:
245: for (int i = 0; i < methods.length; i++) {
246: method = methods[i];
247: methodName = method.getName();
248:
249: if (name.equals(methodName)) {
250: m_ops[index] = method;
251: break;
252: }
253: }
254: }
255:
256: public int getRowCount() {
257: return m_instance != null ? m_fieldNames.length : 0;
258: }
259:
260: public int getColumnCount() {
261: return COLUMN_COUNT;
262: }
263:
264: public boolean isCellEditable(int row, int col) {
265: return (m_setters[row] != null) || (m_ops[row] != null);
266: }
267:
268: public String getColumnName(int col) {
269: switch (col) {
270: case FIELD_COLUMN:
271: return FIELD_HEADER;
272: case VALUE_COLUMN:
273: return VALUE_HEADER;
274: }
275:
276: return "PropertyTableModel: invalid column: " + col;
277: }
278:
279: public Class getColumnClass(int col) {
280: return Object.class;
281: }
282:
283: public Class getRowClass(int row) {
284: Method method = m_getters[row];
285:
286: if (method != null) {
287: Class rowClass = method.getReturnType();
288:
289: if (rowClass.isPrimitive()) {
290: rowClass = _mapPrimitive(rowClass);
291: }
292:
293: return rowClass;
294: }
295:
296: if ((method = m_ops[row]) != null) {
297: return Method.class;
298: }
299:
300: return Object.class;
301: }
302:
303: private Object _getFieldValue(int fieldIndex) {
304: try {
305: return m_getters[fieldIndex].invoke(m_instance,
306: new Object[] {});
307: } catch (Exception e) {
308: return e.getMessage();
309: }
310: }
311:
312: public String getFieldHeading(int row) {
313: return m_headings[row] != null ? m_headings[row]
314: : m_fieldNames[row];
315: }
316:
317: public Object getValueAt(int row, int col) {
318: switch (col) {
319: case FIELD_COLUMN: {
320: return getFieldHeading(row);
321: }
322: case VALUE_COLUMN: {
323: if (m_instance != null) {
324: Method method;
325:
326: if ((method = m_ops[row]) != null) {
327: return method;
328: } else {
329: return _getFieldValue(row);
330: }
331: }
332: }
333: }
334:
335: return "";
336: }
337:
338: public void setValueAt(Object value, int row, int col) {
339: Method setter = m_setters[col];
340:
341: if (setter != null) {
342: try {
343: setter.invoke(getValueAt(row, col),
344: new Object[] { value });
345: } catch (Exception e) {/*ignore*/
346: }
347: }
348: }
349:
350: public void clear() {
351: setInstance(null);
352: }
353:
354: public boolean hasEditor(Class type) {
355: return false;
356: }
357: }
|