package org.hwo.models.TableMapper; import java.awt.Dimension; import java.awt.MouseInfo; import java.awt.Point; import java.awt.Window; 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.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import javax.swing.JFrame; import javax.swing.JTable; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableRowSorter; import org.hwo.csv.CSV; import org.hwo.csv.CSVRecord; import org.hwo.interactiveobjects.IInteractiveObjectEditor; import org.hwo.interactiveobjects.InteractiveObjectHelper; import org.hwo.interactiveobjects.ObjectEditorUIHelper; import org.hwo.ui.KeyStrokeHelper; import org.hwo.ui.KeyStrokeListener; import org.hwo.ui.KeyStrokeParameters; import org.w3c.dom.views.AbstractView; 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, p_method_w; private String p_label; private boolean p_readonly; private Class p_columnclass; private int width; private TableColumn tableColumn; private ColumnInfo nextColumn; private int order; private Integer extractField; 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; if (p_method.getName().startsWith("get")){ Class clz = p_method.getDeclaringClass(); String w_name = "set" + p_method.getName().substring(3); System.err.println(w_name); System.err.println(clz.getName()); try{ p_method_w = clz.getDeclaredMethod(w_name,new Class[]{ p_method.getReturnType() }); System.err.println(String.format("TableMapper found setter %s",p_method_w.getName())); } catch (NoSuchMethodException e){ System.err.println(String.format("Setter %s not found.",w_name)); } }; p_field = null; p_columnclass = method.getReturnType(); initialize(); if (p_label.equals("")) p_label = method.getName(); method.setAccessible(true); if (p_method_w != null) p_method_w.setAccessible(true); if (!p_readonly){ p_readonly = (p_method_w==null); } } private void initialize() { p_label = p_annotation.label(); p_readonly = p_annotation.readonly(); setWidth(p_annotation.width()); order = p_annotation.order(); } public void appendAtEnd(ColumnInfo column) { if (nextColumn == null) nextColumn = column; else nextColumn.appendAtEnd(column); } public List toList() { List list = new LinkedList(); appendToList(list); return list; } public void appendToList(List 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 int getOrder() { return order; } public void setOrder(int order) { this.order = order; } public String getColumnLabel(){ return String.format(this.p_label, extractField); } 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; } private Object fetchValue(Object instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { Object v = null; if (p_field != null) v = p_field.get(instance); if (p_method != null) v = p_method.invoke(instance); return v; } public Object getValue(Object instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { Object v = fetchValue(instance); if (v.getClass().isArray() && (extractField != null)){ v = ((Object[])v)[extractField]; } if (!p_annotation.format().equals("")){ v = String.format(p_annotation.format(), v); } return v; } public void setValue(Object instance,Object value) throws IllegalAccessException,InvocationTargetException { if (extractField != null){ Object v = fetchValue(instance); ((Object[])v)[extractField] = value; if (p_method_w != null){ try { p_method_w.invoke(instance, v); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } else { if (p_field != null) p_field.set(instance, value); if (p_method_w != null){ try { p_method_w.invoke(instance, value); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } } 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; } public Integer getExtractField() { return extractField; } public void setExtractField(Integer extractField) { this.extractField = extractField; } } private Class p_class; private ColumnInfo firstColumn; private List p_rows; private List p_columns; private boolean p_readonly; // Table readonly... private boolean p_editoronpointer; private TableMapperColumnModel columnModel; private JTable jTable; private TableMapperObject tableMapperObject; private Field editorObjectField; private Class editorObjectClass; private MouseAdapter mouseAdapter; private boolean editorEnabled; private boolean sortingEnabled; private LinkedList tableMapperListeners; private KeyStrokeHelper keyStrokeHelper; public TableMapper(Class clazz,JTable table) { this.tableMapperListeners = new LinkedList(); this.p_class = clazz; this.jTable = table; this.firstColumn = null; this.p_rows = new LinkedList(); this.p_columns = new ArrayList(); 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(false); setSortingEnabled(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); if (ObjectEditorUIHelper.isEditable(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; } } private void initializeJTable(){ if (sortingEnabled){ this.jTable.setRowSorter(new TableRowSorter(this)); } else { this.jTable.setRowSorter(null); } int minwidth = 0; for (ColumnInfo ci: p_columns){ minwidth += ci.getWidth(); } //jTable.setMinSize(new Dimension(minwidth, 24)); jTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); } public boolean isSortingEnabled() { return sortingEnabled; } public void setSortingEnabled(boolean sortingEnabled) { this.sortingEnabled = sortingEnabled; initializeJTable(); } 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 centerWindowOnPointer(Object _w){ if (p_editoronpointer && Window.class.isInstance(_w)){ Window w = (Window)_w; Point mp = MouseInfo.getPointerInfo().getLocation(); mp.x -= w.getWidth()/2; mp.y -= w.getHeight()/2; w.setLocation(mp); } } public void openEditor() { System.err.println("TableMapper.openEditor()"); for (TableMapperListener listener: this.tableMapperListeners){ if (listener.editorRequest(this, getSelectedRow())){ return; } } try { Object editorObject = getEditorObject(); if (editorObject != null){ centerWindowOnPointer( ObjectEditorUIHelper.editor(editorObject) ); if (ObjectEditorUIHelper.edit(editorObject)){ fireTableDataChanged(); } } return; } catch (NoClassDefFoundError e){ }; Object editorObject = getEditorObject(); if (editorObject!=null){ IInteractiveObjectEditor oe = InteractiveObjectHelper.getEditor(editorObject); if (oe != null){ centerWindowOnPointer(oe); oe.setVisible(true); } InteractiveObjectHelper.showEditor(editorObject); } } public List getColumnInfo() { return p_columns; } public void setRows(List rows) { this.p_rows = rows; fireTableDataChanged(); } public void setRows(Object[] rows) { this.p_rows = new ArrayList<>(); this.p_rows.addAll(Arrays.asList(rows)); fireTableDataChanged(); } public List getRows() { return this.p_rows; } public List getRows(Class clazz) { return (List) 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) { int fl = field.getAnnotation(TableColumn.class).fieldlength(); if (fl > 0){ for (int i=0;i 0){ for (int i=0;i() { @Override public int compare(ColumnInfo o1, ColumnInfo o2) { return o1.getOrder()-o2.getOrder(); } }); /* List lc = new ArrayList(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 subset = new ArrayList(p_columns.subList(indColumn, p_columns.size())); p_columns.removeAll(subset); p_columns.addAll(indBefore+1, subset); } else { List subset = new ArrayList(p_columns.subList(indColumn, indBefore)); p_columns.removeAll(subset); p_columns.addAll(indColumn+1, subset); } } } } */ } private void initializeColumnInfo() { addFieldsOfClass(p_class); reorderColumns(); for (ColumnInfo ci: p_columns){ System.err.println("TableMapper Column: " + ci.getLabel()); } } public void setReadOnly(boolean readOnly) { this.p_readonly = readOnly; } public boolean getReadOnly() { return this.p_readonly; } public void addRow(Object row,Object before){ if (before != null){ int ind = this.p_rows.indexOf(before); this.p_rows.add(ind, row); fireTableRowsInserted(ind, ind); } else { this.p_rows.add(row); fireTableRowsInserted(this.p_rows.indexOf(row),this.p_rows.indexOf(row)); }; } public void addRows(Object[] rows,Object before){ int ind = (before != null) ? this.p_rows.indexOf(before) : p_rows.size(); int n = ind; for (Object row: rows){ this.p_rows.add(n++, row); } fireTableDataChanged(); } public void addRow(Object row) { addRow(row,null); } 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 getRow(int index,Class 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(); } catch (InvocationTargetException 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 T getSelectedRow(Class c){ return (T)getSelectedRow(); } 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 T[] getSelectedRows(T[] template){ Object[] l = getSelectedRows(); T[] result = Arrays.copyOf(template, l.length); for (int i=0;i cells = csv.getRecords(); CSVRecord header = new CSVRecord(); for (int i=0;i