import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
public class ListProperties {
static class CustomTableModel extends AbstractTableModel {
Vector keys = new Vector();
Vector values = new Vector();
private static final String columnNames[] = { "Property String", "Value" };
public int getColumnCount() {
return columnNames.length;
}
public String getColumnName(int column) {
return columnNames[column];
}
public int getRowCount() {
return keys.size();
}
public Object getValueAt(int row, int column) {
Object returnValue = null;
if (column == 0) {
returnValue = keys.elementAt(row);
} else if (column == 1) {
returnValue = values.elementAt(row);
}
return returnValue;
}
public synchronized void uiDefaultsUpdate(UIDefaults defaults) {
Enumeration newKeys = defaults.keys();
keys.removeAllElements();
while (newKeys.hasMoreElements()) {
keys.addElement(newKeys.nextElement());
}
Enumeration newValues = defaults.elements();
values.removeAllElements();
while (newValues.hasMoreElements()) {
values.addElement(newValues.nextElement());
}
fireTableDataChanged();
}
}
public static void main(String args[]) {
final JFrame frame = new JFrame("List Properties");
final CustomTableModel model = new CustomTableModel();
model.uiDefaultsUpdate(UIManager.getDefaults());
TableSorter sorter = new TableSorter(model);
JTable table = new JTable(sorter);
TableHeaderSorter.install(sorter, table);
table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
Container content = frame.getContentPane();
JScrollPane scrollPane = new JScrollPane(table);
content.add(scrollPane, BorderLayout.CENTER);
frame.setSize(400, 400);
frame.setVisible(true);
}
}
class TableSorter extends TableMap implements TableModelListener {
int indexes[] = new int[0];
Vector sortingColumns = new Vector();
boolean ascending = true;
public TableSorter() {
}
public TableSorter(TableModel model) {
setModel(model);
}
public void setModel(TableModel model) {
super.setModel(model);
reallocateIndexes();
sortByColumn(0);
fireTableDataChanged();
}
public int compareRowsByColumn(int row1, int row2, int column) {
Class type = model.getColumnClass(column);
TableModel data = model;
// Check for nulls
Object o1 = data.getValueAt(row1, column);
Object o2 = data.getValueAt(row2, column);
// If both values are null return 0
if (o1 == null && o2 == null) {
return 0;
} else if (o1 == null) { // Define null less than everything.
return -1;
} else if (o2 == null) {
return 1;
}
if (type.getSuperclass() == Number.class) {
Number n1 = (Number) data.getValueAt(row1, column);
double d1 = n1.doubleValue();
Number n2 = (Number) data.getValueAt(row2, column);
double d2 = n2.doubleValue();
if (d1 < d2)
return -1;
else if (d1 > d2)
return 1;
else
return 0;
} else if (type == String.class) {
String s1 = (String) data.getValueAt(row1, column);
String s2 = (String) data.getValueAt(row2, column);
int result = s1.compareTo(s2);
if (result < 0)
return -1;
else if (result > 0)
return 1;
else
return 0;
} else if (type == java.util.Date.class) {
Date d1 = (Date) data.getValueAt(row1, column);
long n1 = d1.getTime();
Date d2 = (Date) data.getValueAt(row2, column);
long n2 = d2.getTime();
if (n1 < n2)
return -1;
else if (n1 > n2)
return 1;
else
return 0;
} else if (type == Boolean.class) {
Boolean bool1 = (Boolean) data.getValueAt(row1, column);
boolean b1 = bool1.booleanValue();
Boolean bool2 = (Boolean) data.getValueAt(row2, column);
boolean b2 = bool2.booleanValue();
if (b1 == b2)
return 0;
else if (b1) // Define false < true
return 1;
else
return -1;
} else {
Object v1 = data.getValueAt(row1, column);
String s1 = v1.toString();
Object v2 = data.getValueAt(row2, column);
String s2 = v2.toString();
int result = s1.compareTo(s2);
if (result < 0)
return -1;
else if (result > 0)
return 1;
else
return 0;
}
}
public int compare(int row1, int row2) {
for (int level = 0, n = sortingColumns.size(); level < n; level++) {
Integer column = (Integer) sortingColumns.elementAt(level);
int result = compareRowsByColumn(row1, row2, column.intValue());
if (result != 0) {
return (ascending ? result : -result);
}
}
return 0;
}
public void reallocateIndexes() {
int rowCount = model.getRowCount();
indexes = new int[rowCount];
for (int row = 0; row < rowCount; row++) {
indexes[row] = row;
}
}
public void tableChanged(TableModelEvent tableModelEvent) {
super.tableChanged(tableModelEvent);
reallocateIndexes();
sortByColumn(0);
fireTableStructureChanged();
}
public void checkModel() {
if (indexes.length != model.getRowCount()) {
System.err.println("Sorter not informed of a change in model.");
}
}
public void sort() {
checkModel();
shuttlesort((int[]) indexes.clone(), indexes, 0, indexes.length);
fireTableDataChanged();
}
public void shuttlesort(int from[], int to[], int low, int high) {
if (high - low < 2) {
return;
}
int middle = (low + high) / 2;
shuttlesort(to, from, low, middle);
shuttlesort(to, from, middle, high);
int p = low;
int q = middle;
for (int i = low; i < high; i++) {
if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) {
to[i] = from[p++];
} else {
to[i] = from[q++];
}
}
}
private void swap(int first, int second) {
int temp = indexes[first];
indexes[first] = indexes[second];
indexes[second] = temp;
}
public Object getValueAt(int row, int column) {
checkModel();
return model.getValueAt(indexes[row], column);
}
public void setValueAt(Object aValue, int row, int column) {
checkModel();
model.setValueAt(aValue, indexes[row], column);
}
public void sortByColumn(int column) {
sortByColumn(column, true);
}
public void sortByColumn(int column, boolean ascending) {
this.ascending = ascending;
sortingColumns.removeAllElements();
sortingColumns.addElement(new Integer(column));
sort();
super.tableChanged(new TableModelEvent(this));
}
}
class TableHeaderSorter extends MouseAdapter {
private TableSorter sorter;
private JTable table;
private TableHeaderSorter() {
}
public static void install(TableSorter sorter, JTable table) {
TableHeaderSorter tableHeaderSorter = new TableHeaderSorter();
tableHeaderSorter.sorter = sorter;
tableHeaderSorter.table = table;
JTableHeader tableHeader = table.getTableHeader();
tableHeader.addMouseListener(tableHeaderSorter);
}
public void mouseClicked(MouseEvent mouseEvent) {
TableColumnModel columnModel = table.getColumnModel();
int viewColumn = columnModel.getColumnIndexAtX(mouseEvent.getX());
int column = table.convertColumnIndexToModel(viewColumn);
if (mouseEvent.getClickCount() == 1 && column != -1) {
System.out.println("Sorting ...");
int shiftPressed = (mouseEvent.getModifiers() & InputEvent.SHIFT_MASK);
boolean ascending = (shiftPressed == 0);
sorter.sortByColumn(column, ascending);
}
}
}
class TableMap extends AbstractTableModel implements TableModelListener {
TableModel model;
public TableModel getModel() {
return model;
}
public void setModel(TableModel model) {
if (this.model != null) {
this.model.removeTableModelListener(this);
}
this.model = model;
if (this.model != null) {
this.model.addTableModelListener(this);
}
}
public Class getColumnClass(int column) {
return model.getColumnClass(column);
}
public int getColumnCount() {
return ((model == null) ? 0 : model.getColumnCount());
}
public String getColumnName(int column) {
return model.getColumnName(column);
}
public int getRowCount() {
return ((model == null) ? 0 : model.getRowCount());
}
public Object getValueAt(int row, int column) {
return model.getValueAt(row, column);
}
public void setValueAt(Object value, int row, int column) {
model.setValueAt(value, row, column);
}
public boolean isCellEditable(int row, int column) {
return model.isCellEditable(row, column);
}
public void tableChanged(TableModelEvent tableModelEvent) {
fireTableChanged(tableModelEvent);
}
}