package net.sourceforge.javautil.ui.model.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import net.sourceforge.javautil.common.reflection.cache.ClassCache;
import net.sourceforge.javautil.common.reflection.cache.ClassConstructor;
import net.sourceforge.javautil.common.reflection.cache.ClassDescriptor;
import net.sourceforge.javautil.common.reflection.cache.ClassMember;
import net.sourceforge.javautil.common.reflection.cache.ClassMethod;
import net.sourceforge.javautil.common.reflection.cache.ClassMethodAbstract;
import net.sourceforge.javautil.common.reflection.cache.ClassProperty;
import net.sourceforge.javautil.ui.model.UIModelAbstract;
import net.sourceforge.javautil.ui.model.UITableModel;
/**
* A standard/default implementation for UI table models.
*
* @author elponderador
* @author $Author: ponderator $
* @version $Id: UITableModelDefault.java 912 2009-09-09 20:43:46Z ponderator $
*/
public class UITableModelDefault extends UIModelAbstract<UITableModelDefault> implements UITableModel {
/**
* If not null, the fixed column widths for the table columns. If it is
* shorter than the amount of columns, those extra columns are considered
* to be auto width which is the same as setting any of the widths to
* lesser than or equal to zero.
*/
private int[] columnWidths;
/**
* If not null, the headers for each column. If it is shorter than the amount of
* columns those extra columns will have a blank header, which is the same as
* setting any of the headers to null or "".
*/
private String[] columnHeaders;
/**
* If not null, the alignment for each column. If it is shorter than the
* amount of columns those extra columns will be considered to be left
* aligned, which is the same as setting any of the headers to 0.
*/
private int[] columnAlignment;
/**
* The rows of data that make up this table
*/
private List<Object[]> rows = new ArrayList<Object[]>();
/**
* The maximum columns found on the largest row added
*/
private int maxColumns = 0;
public UITableModelDefault () {}
public UITableModelDefault (String header, List<ClassConstructor> constructors) {
this.attributes.put("caption", header);
for (ClassConstructor constructor : constructors) {
StringBuffer types = new StringBuffer();
for (Class type : constructor.getParameterTypes()) {
if (types.length() > 0) types.append(",");
types.append(type.getSimpleName());
}
this.addRow(types, constructor.isVariableArgument() ? "VarArgs" : "");
}
}
/**
* @param descriptor The descriptor to display class members for
*/
public UITableModelDefault (String header, Map<String, Object> members) {
this.attributes.put("caption", header);
for (String name : members.keySet()) {
if (members.get(name) instanceof List) {
List<ClassMethod> methods = (List) members.get(name);
for (ClassMethod method : methods) {
if (method.isPropertyMethod()) continue;
StringBuffer types = new StringBuffer();
for (Class type : method.getParameterTypes()) {
if (types.length() > 0) types.append(",");
types.append(type.getSimpleName());
}
this.addRow(name, method.getReturnType(), types, method.isVariableArgument() ? "VarArgs" : "");
}
} else {
ClassProperty property = (ClassProperty) members.get(name);
this.addRow(name, property.getType(), property.isReadable() ? "Readable" : "", property.isWritable() ? "Writable" : "");
}
}
}
/**
* Create a table model using a collection of objects. If an item
* in the collection is a one-dimensional array of type {@link Object}
* then it will use the array for the columns, otherwise it will add
* a single column row with the contents of the item.
*
* @param collection The collection of objects
* @param headers The headers for the columns
*/
public UITableModelDefault (Collection collection, String... headers) {
this.setColumnHeaders(headers);
for (Object o : collection) {
if (o instanceof Object[]) {
this.addRow( (Object[]) o );
} else {
this.addRow( new Object[] { o } );
}
}
}
/**
* Create a table model from the contents of a map. The key will be the first
* column of data and the value will be the second column. The two headers
* will be used for their corresponding columns.
*
* @param map
* @param keyHeader
* @param valueHeader
*/
public UITableModelDefault (Map<?,?> map, String keyHeader, String valueHeader) {
this.setColumnHeaders(keyHeader, valueHeader);
for (Map.Entry entry : map.entrySet()) {
this.addRow(entry.getKey(), entry.getValue());
}
}
/**
* Use specific properties on the objects in a collection in order to produce
* columns.
*
* @param <T> The type of object
* @param collection The list of objects of the specified type
* @param clazz The class to use for getting properties
* @param properties The properties of the objects that should compose the columns
*/
public <T> UITableModelDefault (Collection<T> collection, Class<T> clazz, String... properties) {
ClassDescriptor descriptor = ClassCache.getFor(clazz);
for (T item : collection) {
List<Object> rowData = new ArrayList<Object>();
for (String property : properties) {
Object value = descriptor.getPropertyValue(item, property);
rowData.add( value == null ? "" : value );
}
this.addRow( rowData.toArray(new Object[rowData.size()]) );
}
}
/**
* Add a row of data to the table model.
*
* @param data A row of data
*/
public UITableModelDefault addRow (Object... data) {
if (maxColumns < data.length) maxColumns = data.length;
this.rows.add(data);
return this;
}
/**
* Remove a previously added row
*
* @param row The index of the row to remove
*/
public UITableModelDefault removeRow (int row) {
if (row >= rows.size() || row < 0)
throw new IllegalArgumentException("No such row: " + row);
this.rows.remove(row);
return this;
}
/**
* @return The {@link #columnWidths}
*/
public int[] getColumnWidths() { return columnWidths; }
public UITableModelDefault setColumnWidths(int... columnWidths) { this.columnWidths = columnWidths; return this; }
/**
* @return The {@link #columnHeaders}
*/
public String[] getColumnHeaders() { return columnHeaders; }
public UITableModelDefault setColumnHeaders(String... columnHeaders) { this.columnHeaders = columnHeaders; return this; }
/**
* @return The {@link #columnAlignment}
*/
public int[] getColumnAlignment() { return columnAlignment; }
public UITableModelDefault setColumnAlignment(int... columnAlignment) { this.columnAlignment = columnAlignment; return this; }
public boolean isHasFixedColumnWidths() { return this.columnWidths != null; }
public boolean isShowHeaders() { return this.columnHeaders != null; }
public int getAlignment(int column) {
return this.columnAlignment != null && this.columnAlignment.length > column ?
this.columnAlignment[column] : -1;
}
public int getColumnCount() { return this.maxColumns; }
public String getHeader(int column) {
String header = this.columnHeaders != null && this.columnHeaders.length > column ? this.columnHeaders[column] : null;
return header == null ? "" : header;
}
public int getRowCount() { return this.rows.size(); }
public Object getValueAt(int row, int column) {
if (row >= this.rows.size() || row < 0)
throw new IllegalArgumentException("No such row: " + row);
return this.rows.get(row).length > column ? this.rows.get(row)[column] : null;
}
public int getWidth(int column) {
return this.columnWidths != null && this.columnWidths.length > column ?
this.columnWidths[column] : -1;
}
}