com.github.brunothg.swing2.model.table.DefaultObjectTableModel Maven / Gradle / Ivy
package com.github.brunothg.swing2.model.table;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import javax.swing.table.AbstractTableModel;
import com.github.brunothg.swing2.utils.ClassUtils;
public class DefaultObjectTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private Vector rows = new Vector();
private Class type;
private ObjectColumn[] columns;
public DefaultObjectTableModel(Class type) {
this.type = type;
initialize();
}
@SuppressWarnings("unchecked")
private void initialize() {
List> columns = new LinkedList>();
// Search fields
Field[] fields = type.getDeclaredFields();
for (Field field : fields) {
for (Annotation annotation : field.getDeclaredAnnotations()) {
if (annotation instanceof Column) {
Column _column = (Column) annotation;
ObjectColumn column = new FieldColumn(_column, type,
field);
columns.add(column);
if (_column.index() >= 0) {
column.setIndex(_column.index());
}
}
}
}
// Search methods
Method[] methods = type.getDeclaredMethods();
for (Method method : methods) {
for (Annotation annotation : method.getDeclaredAnnotations()) {
if (annotation instanceof Column) {
Column _column = (Column) annotation;
ObjectColumn column = new MethodColumn(_column, type,
method);
columns.add(column);
if (_column.index() >= 0) {
column.setIndex(_column.index());
}
}
}
}
Collections.sort(columns);
this.columns = columns.toArray(new ObjectColumn[columns.size()]);
}
protected ObjectColumn getColumn(int columnIndex) {
return columns[columnIndex];
}
/**
* Returns the value given by the {@link Column} Annotation.
*
* @see Column#value()
*/
public String getColumnName(int columnIndex) {
return getColumn(columnIndex).getName();
}
/**
* Override the columnName grabbed from the {@link Column} annotation
*
* @param columnIndex
* The column to change
* @param columnName
* The new column name
*/
public void setColumnName(int columnIndex, String columnName) {
getColumn(columnIndex).setName(columnName);
}
@Override
public int getRowCount() {
return rows.size();
}
@Override
public int getColumnCount() {
return columns.length;
}
/**
* Returns the value given by the {@link Column} Annotation.
*
* @see Column#editable()
*/
public boolean isCellEditable(int rowIndex, int columnIndex) {
return getColumn(columnIndex).isEditable();
}
/**
* Returns the type of the annotated field or the return type of the
* annotated method.
*/
public Class> getColumnClass(int columnIndex) {
return getColumn(columnIndex).getType();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
try {
return getColumn(columnIndex).getValue(rows.get(rowIndex));
} catch (IllegalArgumentException | InvocationTargetException
| IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* Sets the annotated field value
*
* @see #getValueAt(int, int)
* @throws RuntimeException
* if there are problems with the access through reflection
*/
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
try {
getColumn(columnIndex).setValue(rows.get(rowIndex), aValue);
} catch (IllegalArgumentException | InvocationTargetException
| IllegalAccessException e) {
throw new RuntimeException(e);
}
fireTableCellUpdated(rowIndex, columnIndex);
}
/**
* Add a new row to the table model
*
* @param object
* The object, that represents the new row
*/
public void addRow(T object) {
addRow(-1, object);
}
/**
* Add a new row at specific position to the table model. The element at
* this position (and the ones behind) will be shift to the right.
*
* @param rowIndex
* The index for the new row.
* @param object
* The object, that represents the new row
*/
public void addRow(int rowIndex, T object) {
if (object == null) {
throw new NullPointerException("No null values allowed");
}
if (rowIndex < 0) {
rowIndex = rows.size();
rows.add(object);
} else {
rows.add(rowIndex, object);
}
fireTableRowsInserted(rowIndex, rowIndex);
}
/**
* Get the row object at a specific position.
*
* @param rowIndex
* The index of the row
* @return The object for the row
*/
public T getRow(int rowIndex) {
return rows.get(rowIndex);
}
/**
* Search for the object (using equals method) and then delete it. Return
* null if it could not be found. Otherwise the row object is returned.
*
* @param object
* The object, that should be deleted
* @return Null or the row object
*/
public T removeRow(T object) {
for (int i = 0; i < rows.size(); i++) {
if (rows.get(i).equals(object)) {
return removeRow(i);
}
}
return null;
}
/**
* Removes a row by its index.
*
* @param rowIndex
* The index of the row
* @return The row object that was deleted
*/
public T removeRow(int rowIndex) {
T removed = rows.remove(rowIndex);
fireTableRowsDeleted(rowIndex, rowIndex);
return removed;
}
protected static abstract class ObjectColumn implements
Comparable> {
private Class> self;
private int index;
private String name;
private Class> type;
private boolean editable;
private Method setter;
public ObjectColumn(Column column, Class> self) {
this.setSelf(self);
this.name = column.value();
this.editable = column.editable();
}
protected static Method findSetter(String name, Class> type,
Class> self) {
if (name == null || name.trim().isEmpty()) {
return null;
}
Method[] methods = self.getDeclaredMethods();
for (Method method : methods) {
if (!method.getName().equals(name)) {
continue;
}
Class>[] parameters = method.getParameterTypes();
if (parameters.length != 1) {
continue;
}
if (ClassUtils.isAssignable(parameters[0], type)) {
return method;
}
}
return null;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Class> getType() {
return type;
}
public void setType(Class> type) {
this.type = type;
}
public boolean isEditable() {
return editable;
}
public void setEditable(boolean editable) {
this.editable = editable;
}
public Class> getSelf() {
return self;
}
public void setSelf(Class> self) {
this.self = self;
}
public Method getSetter() {
return setter;
}
public void setSetter(Method setter) {
this.setter = setter;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
@Override
public int compareTo(ObjectColumn> comp) {
return new Integer(getIndex()).compareTo(new Integer(comp
.getIndex()));
}
public abstract Object getValue(V row) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException;
public abstract void setValue(V row, Object value)
throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException;
}
protected static class FieldColumn extends ObjectColumn {
private Field f;
public FieldColumn(Column column, Class> self, Field f) {
super(column, self);
this.f = f;
setType(f.getType());
setSetter(ObjectColumn.findSetter(column.setter(), getType(),
getSelf()));
}
@Override
public Object getValue(V row) throws IllegalArgumentException,
IllegalAccessException {
try {
f.setAccessible(true);
} catch (SecurityException e) {
}
return f.get(row);
}
@Override
public void setValue(V row, Object value)
throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
if (getSetter() != null) {
try {
getSetter().setAccessible(true);
} catch (SecurityException e) {
}
getSetter().invoke(row, value);
} else {
try {
f.setAccessible(true);
} catch (SecurityException e) {
}
f.set(row, value);
}
}
}
protected static class MethodColumn extends ObjectColumn {
private Method m;
public MethodColumn(Column column, Class> self, Method m) {
super(column, self);
this.m = m;
setType(m.getReturnType());
setSetter(ObjectColumn.findSetter(column.setter(), getType(),
getSelf()));
}
@Override
public boolean isEditable() {
if (getSetter() == null) {
return false;
}
return super.isEditable();
}
@Override
public Object getValue(V row) throws IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
try {
m.setAccessible(true);
} catch (SecurityException e) {
}
return m.invoke(row);
}
@Override
public void setValue(V row, Object value)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
if (getSetter() != null) {
try {
getSetter().setAccessible(true);
} catch (SecurityException e) {
}
getSetter().invoke(row, value);
} else {
throw new IllegalAccessException(
"No setter is set for this column");
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy