693 lines
14 KiB
Java
693 lines
14 KiB
Java
package org.hwo.models.TableMapper;
|
|
|
|
import java.awt.event.KeyEvent;
|
|
import java.awt.event.MouseAdapter;
|
|
import java.awt.event.MouseEvent;
|
|
import java.awt.event.MouseListener;
|
|
import java.io.File;
|
|
import java.lang.reflect.Constructor;
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Hashtable;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
|
|
import javax.swing.JTable;
|
|
import javax.swing.event.ListSelectionListener;
|
|
import javax.swing.table.AbstractTableModel;
|
|
|
|
import org.hwo.csv.CSV;
|
|
import org.hwo.csv.CSVRecord;
|
|
import org.hwo.interactiveobjects.InteractiveObjectHelper;
|
|
import org.hwo.ui.KeyStrokeHelper;
|
|
import org.hwo.ui.KeyStrokeListener;
|
|
import org.hwo.ui.KeyStrokeParameters;
|
|
|
|
public class TableMapper extends AbstractTableModel
|
|
{
|
|
|
|
private static final long serialVersionUID = -6556060772230310664L;
|
|
|
|
public class ColumnInfo
|
|
{
|
|
private TableColumn p_annotation;
|
|
|
|
private Field p_field;
|
|
private Method p_method;
|
|
private String p_label;
|
|
private boolean p_readonly;
|
|
private Class<?> p_columnclass;
|
|
private int width;
|
|
private TableColumn tableColumn;
|
|
|
|
private ColumnInfo nextColumn;
|
|
|
|
protected ColumnInfo(TableColumn tc,Field field)
|
|
{
|
|
tableColumn = tc;
|
|
p_annotation = field.getAnnotation(TableColumn.class);
|
|
|
|
p_method = null;
|
|
p_field = field;
|
|
p_columnclass = field.getType();
|
|
|
|
initialize();
|
|
|
|
if (p_label.equals(""))
|
|
p_label = field.getName();
|
|
|
|
field.setAccessible(true);
|
|
}
|
|
protected ColumnInfo(TableColumn tc,Method method)
|
|
{
|
|
tableColumn = tc;
|
|
p_annotation = method.getAnnotation(TableColumn.class);
|
|
|
|
p_method = method;
|
|
p_field = null;
|
|
p_columnclass = method.getReturnType();
|
|
|
|
initialize();
|
|
|
|
if (p_label.equals(""))
|
|
p_label = method.getName();
|
|
|
|
method.setAccessible(true);
|
|
|
|
p_readonly = true;
|
|
}
|
|
|
|
private void initialize()
|
|
{
|
|
p_label = p_annotation.label();
|
|
p_readonly = p_annotation.readonly();
|
|
setWidth(p_annotation.width());
|
|
}
|
|
|
|
public void appendAtEnd(ColumnInfo column)
|
|
{
|
|
if (nextColumn == null)
|
|
nextColumn = column;
|
|
else
|
|
nextColumn.appendAtEnd(column);
|
|
}
|
|
|
|
public List<ColumnInfo> toList()
|
|
{
|
|
List<ColumnInfo> list = new LinkedList<TableMapper.ColumnInfo>();
|
|
appendToList(list);
|
|
return list;
|
|
}
|
|
|
|
public void appendToList(List<ColumnInfo> list)
|
|
{
|
|
list.add(this);
|
|
if (nextColumn != null)
|
|
nextColumn.appendToList(list);
|
|
}
|
|
|
|
public void removeColumn(ColumnInfo ci)
|
|
{
|
|
if (nextColumn == ci)
|
|
{
|
|
nextColumn = ci.nextColumn;
|
|
ci.nextColumn = null;
|
|
} else if (nextColumn != null)
|
|
nextColumn.removeColumn(ci);
|
|
}
|
|
|
|
public ColumnInfo findColumnByName(String name)
|
|
{
|
|
if (this.p_label.equals(name))
|
|
return this;
|
|
if (nextColumn!=null)
|
|
return nextColumn.findColumnByName(name);
|
|
else
|
|
return null;
|
|
}
|
|
|
|
public void append(ColumnInfo ci)
|
|
{
|
|
ci.nextColumn = nextColumn;
|
|
nextColumn = ci;
|
|
}
|
|
|
|
|
|
public String getLabel()
|
|
{
|
|
return this.p_label;
|
|
}
|
|
public void setLabel(String label)
|
|
{
|
|
this.p_label = label;
|
|
}
|
|
|
|
public boolean getReadOnly()
|
|
{
|
|
return this.p_readonly;
|
|
}
|
|
public void setReadOnly(boolean readOnly)
|
|
{
|
|
this.p_readonly = readOnly;
|
|
}
|
|
|
|
public void setColumnClass(Class<?> cl)
|
|
{
|
|
this.p_columnclass = cl;
|
|
}
|
|
public Class<?> getColumnClass()
|
|
{
|
|
return this.p_columnclass;
|
|
}
|
|
|
|
public Object getValue(Object instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
|
|
{
|
|
if (p_field != null)
|
|
return p_field.get(instance);
|
|
if (p_method != null)
|
|
return p_method.invoke(instance, null);
|
|
return null;
|
|
}
|
|
|
|
public void setValue(Object instance,Object value) throws IllegalAccessException
|
|
{
|
|
if (p_field != null)
|
|
p_field.set(instance, value);
|
|
}
|
|
|
|
public int getWidth() {
|
|
return width;
|
|
}
|
|
|
|
public void setWidth(int width) {
|
|
this.width = width;
|
|
}
|
|
|
|
public ColumnInfo getNextColumn() {
|
|
return nextColumn;
|
|
}
|
|
|
|
public void setNextColumn(ColumnInfo nextColumn) {
|
|
this.nextColumn = nextColumn;
|
|
}
|
|
|
|
public TableColumn getTableColumn() {
|
|
return tableColumn;
|
|
}
|
|
|
|
public void setTableColumn(TableColumn tableColumn) {
|
|
this.tableColumn = tableColumn;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
private Class<?> p_class;
|
|
|
|
private ColumnInfo firstColumn;
|
|
|
|
private List<Object> p_rows;
|
|
private List<ColumnInfo> p_columns;
|
|
private boolean p_readonly; // Table readonly...
|
|
|
|
private TableMapperColumnModel
|
|
columnModel;
|
|
|
|
private JTable jTable;
|
|
|
|
private TableMapperObject
|
|
tableMapperObject;
|
|
private Field editorObjectField;
|
|
private Class<?> editorObjectClass;
|
|
|
|
private MouseAdapter mouseAdapter;
|
|
|
|
private boolean editorEnabled;
|
|
|
|
private LinkedList<TableMapperListener> tableMapperListeners;
|
|
|
|
private KeyStrokeHelper keyStrokeHelper;
|
|
|
|
public TableMapper(Class<?> clazz,JTable table)
|
|
{
|
|
this.tableMapperListeners = new LinkedList<TableMapperListener>();
|
|
this.p_class = clazz;
|
|
this.jTable = table;
|
|
|
|
this.firstColumn = null;
|
|
|
|
this.p_rows = new LinkedList<Object>();
|
|
this.p_columns = new ArrayList<TableMapper.ColumnInfo>();
|
|
this.p_readonly = false;
|
|
|
|
this.keyStrokeHelper = new KeyStrokeHelper(jTable);
|
|
this.keyStrokeHelper.registerKeyStrokeListener(new KeyStrokeListener() {
|
|
|
|
@Override
|
|
public void keyStroke(KeyStrokeParameters parameters) {
|
|
switch (parameters.getKeyCode())
|
|
{
|
|
case KeyEvent.VK_ENTER:
|
|
openEditor();
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
this.keyStrokeHelper.addKeyCode(KeyEvent.VK_ENTER);
|
|
|
|
initializeMapper();
|
|
initializeColumnInfo();
|
|
|
|
table.setModel(this);
|
|
table.setColumnModel(new TableMapperColumnModel(this));
|
|
|
|
table.setAutoCreateRowSorter(true);
|
|
|
|
mouseAdapter = new MouseAdapter() {
|
|
|
|
@Override
|
|
public void mouseClicked(MouseEvent e) {
|
|
switch (e.getButton())
|
|
{
|
|
case 1:
|
|
if (e.getClickCount()==2)
|
|
{
|
|
openEditor();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
if (InteractiveObjectHelper.isInteractiveObject(editorObjectClass))
|
|
setEditorEnabled(true);
|
|
|
|
}
|
|
|
|
private void initializeMapper()
|
|
{
|
|
tableMapperObject = p_class.getAnnotation(TableMapperObject.class);
|
|
if (tableMapperObject != null)
|
|
{
|
|
if (tableMapperObject.editorField() != null)
|
|
{
|
|
try {
|
|
editorObjectField = p_class.getDeclaredField(tableMapperObject.editorField());
|
|
editorObjectField.setAccessible(true);
|
|
|
|
editorObjectClass = editorObjectField.getType();
|
|
|
|
} catch (SecurityException e) {
|
|
// TODO Auto-generated catch block
|
|
e.printStackTrace();
|
|
} catch (NoSuchFieldException e) {
|
|
// TODO Auto-generated catch block
|
|
e.printStackTrace();
|
|
}
|
|
|
|
}
|
|
} else
|
|
{
|
|
editorObjectClass = p_class;
|
|
}
|
|
|
|
}
|
|
|
|
public void addListSelectionListener(ListSelectionListener listener)
|
|
{
|
|
jTable.getSelectionModel().addListSelectionListener(listener);
|
|
}
|
|
public void removeListSelectionListener(ListSelectionListener listener)
|
|
{
|
|
jTable.getSelectionModel().removeListSelectionListener(listener);
|
|
}
|
|
|
|
public void addTableMapperListener(TableMapperListener listener)
|
|
{
|
|
tableMapperListeners.add(listener);
|
|
}
|
|
public void removeTableMapperListener(TableMapperListener listener)
|
|
{
|
|
tableMapperListeners.remove(listener);
|
|
}
|
|
|
|
protected void fireValueChanged(int row,int column)
|
|
{
|
|
for (TableMapperListener listener: tableMapperListeners)
|
|
listener.ValueChanged(row, column);
|
|
}
|
|
|
|
private Object getEditorObject()
|
|
{
|
|
if (jTable.getSelectedRow()!=-1)
|
|
{
|
|
int row = jTable.convertRowIndexToModel(jTable.getSelectedRow());
|
|
Object rowObject = p_rows.get(row);
|
|
if (editorObjectField == null)
|
|
return rowObject;
|
|
|
|
try {
|
|
Object editorObject = editorObjectField.get(rowObject);
|
|
return editorObject;
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
// TODO Auto-generated catch block
|
|
e.printStackTrace();
|
|
} catch (IllegalAccessException e) {
|
|
// TODO Auto-generated catch block
|
|
e.printStackTrace();
|
|
}
|
|
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void openEditor()
|
|
{
|
|
Object editorObject = getEditorObject();
|
|
if (editorObject!=null)
|
|
InteractiveObjectHelper.showEditor(editorObject);
|
|
}
|
|
|
|
public List<ColumnInfo> getColumnInfo()
|
|
{
|
|
return p_columns;
|
|
}
|
|
|
|
public void setRows(List rows)
|
|
{
|
|
this.p_rows = rows;
|
|
fireTableDataChanged();
|
|
}
|
|
|
|
public void setRows(Object[] rows)
|
|
{
|
|
this.p_rows = Arrays.asList(rows);
|
|
fireTableDataChanged();
|
|
}
|
|
|
|
public List getRows()
|
|
{
|
|
return this.p_rows;
|
|
}
|
|
|
|
public <T> List<T> getRows(Class<T> clazz)
|
|
{
|
|
return (List<T>) p_rows;
|
|
}
|
|
|
|
public void clear()
|
|
{
|
|
this.p_rows.clear();
|
|
fireTableDataChanged();
|
|
}
|
|
|
|
public boolean isEditorEnabled()
|
|
{
|
|
return editorEnabled;
|
|
}
|
|
|
|
public void setEditorEnabled(boolean enabled)
|
|
{
|
|
if (enabled)
|
|
jTable.addMouseListener(mouseAdapter);
|
|
else
|
|
jTable.removeMouseListener(mouseAdapter);
|
|
|
|
editorEnabled = enabled;
|
|
}
|
|
|
|
private void addColumnInfo(ColumnInfo ci)
|
|
{
|
|
if (ci.getTableColumn().firstColumn())
|
|
p_columns.add(0,ci);
|
|
else
|
|
p_columns.add(ci);
|
|
/*
|
|
if (firstColumn == null)
|
|
firstColumn = ci;
|
|
else
|
|
{
|
|
if (ci.getTableColumn().firstColumn())
|
|
{
|
|
ci.setNextColumn(firstColumn);
|
|
firstColumn = ci;
|
|
} else
|
|
firstColumn.appendAtEnd(ci);
|
|
}
|
|
*/
|
|
}
|
|
|
|
private void addFieldsOfClass(Class<?> clazz)
|
|
{
|
|
if (clazz.getSuperclass() != null)
|
|
addFieldsOfClass(clazz.getSuperclass());
|
|
|
|
for (Field field: clazz.getDeclaredFields())
|
|
{
|
|
if (field.getAnnotation(TableColumn.class)!=null)
|
|
{
|
|
ColumnInfo ci = new ColumnInfo(field.getAnnotation(TableColumn.class),field);
|
|
addColumnInfo(ci);
|
|
}
|
|
}
|
|
|
|
for (Method method: clazz.getDeclaredMethods())
|
|
{
|
|
if (method.getAnnotation(TableColumn.class)!=null)
|
|
{
|
|
ColumnInfo ci = new ColumnInfo(method.getAnnotation(TableColumn.class),method);
|
|
addColumnInfo(ci);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
private int findColumnIndexByName(String name)
|
|
{
|
|
for (int i=0;i<p_columns.size();i++)
|
|
{
|
|
if (p_columns.get(i).p_label.equals(name))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
private void reorderColumns()
|
|
{
|
|
List<ColumnInfo> lc = new ArrayList<TableMapper.ColumnInfo>(p_columns);
|
|
|
|
for (ColumnInfo ci:lc)
|
|
{
|
|
if (!ci.getTableColumn().after().equals(""))
|
|
{
|
|
int indColumn = p_columns.indexOf(ci);
|
|
int indBefore = findColumnIndexByName(ci.getTableColumn().after());
|
|
if (indBefore != -1)
|
|
{
|
|
if (indBefore < indColumn)
|
|
{
|
|
List<ColumnInfo> subset = new ArrayList<TableMapper.ColumnInfo>(p_columns.subList(indColumn, p_columns.size()));
|
|
p_columns.removeAll(subset);
|
|
p_columns.addAll(indBefore+1, subset);
|
|
} else
|
|
{
|
|
List<ColumnInfo> subset = new ArrayList<TableMapper.ColumnInfo>(p_columns.subList(indColumn, indBefore));
|
|
p_columns.removeAll(subset);
|
|
p_columns.addAll(indColumn+1, subset);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void initializeColumnInfo()
|
|
{
|
|
addFieldsOfClass(p_class);
|
|
reorderColumns();
|
|
}
|
|
|
|
public void setReadOnly(boolean readOnly)
|
|
{
|
|
this.p_readonly = readOnly;
|
|
}
|
|
public boolean getReadOnly()
|
|
{
|
|
return this.p_readonly;
|
|
}
|
|
|
|
public void addRow(Object row)
|
|
{
|
|
this.p_rows.add(row);
|
|
//fireTableRowsInserted(getRowCount()-1, getRowCount()-1);
|
|
fireTableDataChanged();
|
|
}
|
|
public void removeRow(Object row)
|
|
{
|
|
int index = this.p_rows.indexOf(row);
|
|
if (index != -1)
|
|
{
|
|
this.p_rows.remove(index);
|
|
fireTableRowsDeleted(index, index);
|
|
};
|
|
}
|
|
|
|
public Object getRow(int index)
|
|
{
|
|
return this.p_rows.get(index);
|
|
}
|
|
|
|
public <T> T getRow(int index,Class<T> clazz)
|
|
{
|
|
return (T)this.p_rows.get(index);
|
|
}
|
|
|
|
public Object appendNewInstance()
|
|
{
|
|
try
|
|
{
|
|
Object instance = this.p_class.newInstance();
|
|
if (instance != null)
|
|
addRow(instance);
|
|
return instance;
|
|
} catch (Exception ex)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
public int getColumnCount() {
|
|
return this.p_columns.size();
|
|
}
|
|
|
|
@Override
|
|
public int getRowCount() {
|
|
return this.p_rows.size();
|
|
}
|
|
|
|
@Override
|
|
public Object getValueAt(int rowIndex, int columnIndex) {
|
|
if ( (rowIndex < this.p_rows.size()) && (columnIndex < this.p_columns.size()))
|
|
{
|
|
try
|
|
{
|
|
return this.p_columns.get(columnIndex).getValue(this.p_rows.get(rowIndex));
|
|
} catch (Exception ex)
|
|
{
|
|
System.err.println("Exception: " + ex);
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|
|
@Override
|
|
public void setValueAt(Object aValue,
|
|
int rowIndex,
|
|
int columnIndex)
|
|
{
|
|
try
|
|
{
|
|
this.p_columns.get(columnIndex).setValue(this.p_rows.get(rowIndex), aValue);
|
|
fireValueChanged(rowIndex, columnIndex);
|
|
} catch (IllegalAccessException ex)
|
|
{
|
|
System.err.println("IllegalAccessException: " + ex);
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isCellEditable(int rowIndex,int columnIndex)
|
|
{
|
|
if (this.p_readonly)
|
|
return false;
|
|
return !this.p_columns.get(columnIndex).getReadOnly();
|
|
}
|
|
|
|
@Override
|
|
public Class<?> getColumnClass(int columnIndex)
|
|
{
|
|
Class<?> c = this.p_columns.get(columnIndex).getColumnClass();
|
|
return c;
|
|
}
|
|
|
|
@Override
|
|
public String getColumnName(int columnIndex)
|
|
{
|
|
return this.p_columns.get(columnIndex).getLabel();
|
|
}
|
|
|
|
public Object getSelectedRow()
|
|
{
|
|
if (jTable.getSelectedRow()!=-1)
|
|
{
|
|
return this.p_rows.get(jTable.convertRowIndexToModel(jTable.getSelectedRow()));
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public Object[] getSelectedRows()
|
|
{
|
|
int[] idx = jTable.getSelectedRows();
|
|
Object[] result = new Object[ idx.length ];
|
|
|
|
for (int i=0;i<result.length;i++){
|
|
result[i] = this.p_rows.get(jTable.convertRowIndexToModel(idx[i]));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public <T> T[] getSelectedRows(T[] template){
|
|
Object[] l = getSelectedRows();
|
|
T[] result = Arrays.copyOf(template, l.length);
|
|
|
|
for (int i=0;i<l.length;i++){
|
|
result[i] = (T)l[i];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
public boolean exportToFile(File exportFile)
|
|
{
|
|
CSV csv = new CSV();
|
|
|
|
List<CSVRecord> cells = csv.getRecords();
|
|
|
|
CSVRecord header = new CSVRecord();
|
|
for (int i=0;i<getColumnCount();i++)
|
|
header.appendValue(p_columns.get(i).getLabel());
|
|
|
|
cells.add(header);
|
|
|
|
for (int row=0;row<getRowCount();row++)
|
|
{
|
|
CSVRecord record = new CSVRecord();
|
|
|
|
for (int column=0;column<getColumnCount();column++)
|
|
if (getValueAt(row, column)!=null)
|
|
record.appendValue(getValueAt(row, column).toString());
|
|
else
|
|
record.appendValue("");
|
|
|
|
cells.add(record);
|
|
}
|
|
|
|
csv.saveToFile(exportFile);
|
|
return true;
|
|
}
|
|
|
|
|
|
};
|