// Near Infinity - An Infinity Engine Browser and Editor
// Copyright (C) 2001 - 2005 Jon Olav Hauglid
// See LICENSE.txt for license information
package org.infinity.gui;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import org.infinity.icon.Icons;
public final class SortableTable extends JTable
{
private final SortableTableModel tableModel;
private boolean sortAscending;
private int sortByColumn;
public SortableTable(List<String> columnNames, List<Class<? extends Object>> columnClasses, List<Integer> columnWidths)
{
tableModel = new SortableTableModel(columnNames, columnClasses);
setModel(tableModel);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
setDefaultRenderer(Object.class, new ToolTipTableCellRenderer());
getTableHeader().setDefaultRenderer(new TableHeaderRenderer());
getTableHeader().addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent event)
{
TableColumnModel columnModel = getColumnModel();
int viewColumn = columnModel.getColumnIndexAtX(event.getX());
int column = convertColumnIndexToModel(viewColumn);
if (column == sortByColumn)
sortAscending = !sortAscending;
else {
sortByColumn = column;
sortAscending = false;
}
getTableHeader().repaint();
tableModel.sort();
}
});
for (int i = 0; i < columnWidths.size(); i++)
getColumnModel().getColumn(i).setPreferredWidth(columnWidths.get(i));
}
public void addTableItem(TableItem item)
{
tableModel.addTableItem(item);
}
public void clear()
{
tableModel.clear();
}
public TableItem getTableItemAt(int rowIndex)
{
return tableModel.getTableItemAt(rowIndex);
}
public void tableComplete()
{
tableModel.sort();
}
public void tableComplete(int sortByColumn)
{
this.sortByColumn = sortByColumn;
tableModel.sort();
}
// -------------------------- INNER CLASSES --------------------------
private final class TableHeaderRenderer extends DefaultTableCellRenderer
{
private TableHeaderRenderer()
{
setHorizontalTextPosition(DefaultTableCellRenderer.LEFT);
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column)
{
if (table != null) {
JTableHeader header = table.getTableHeader();
if (header != null) {
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
setText(' ' + table.getModel().getColumnName(column));
}
}
if (sortByColumn == column)
setIcon(sortAscending ? Icons.getIcon(Icons.ICON_UP_16) : Icons.getIcon(Icons.ICON_DOWN_16));
else
setIcon(null);
return this;
}
}
private final class SortableTableModel implements TableModel, Comparator<TableItem>
{
private final List<TableModelListener> listeners = new ArrayList<TableModelListener>();
private final List<TableItem> tableItems = new ArrayList<TableItem>();
private final List<Class<? extends Object>> columnClasses;
private final List<String> columnNames;
private SortableTableModel(List<String> columnNames, List<Class<? extends Object>> columnClasses)
{
if (columnNames != null) {
this.columnNames = columnNames;
} else {
this.columnNames = new ArrayList<String>();
}
if (columnClasses != null) {
this.columnClasses = columnClasses;
} else {
this.columnClasses = new ArrayList<Class<? extends Object>>();
}
}
private void addTableItem(TableItem item)
{
tableItems.add(item);
}
private TableItem getTableItemAt(int rowIndex)
{
return tableItems.get(rowIndex);
}
public void sort()
{
Collections.sort(tableItems, this);
TableModelEvent event = new TableModelEvent(this);
for (int i = 0; i < listeners.size(); i++)
listeners.get(i).tableChanged(event);
}
private void clear()
{
tableItems.clear();
TableModelEvent event = new TableModelEvent(this);
for (int i = 0; i < listeners.size(); i++)
listeners.get(i).tableChanged(event);
}
@Override
public Class<? extends Object> getColumnClass(int columnIndex)
{
return columnClasses.get(columnIndex);
}
@Override
public int getColumnCount()
{
return columnClasses.size();
}
@Override
public String getColumnName(int columnIndex)
{
return columnNames.get(columnIndex);
}
@Override
public int getRowCount()
{
return tableItems.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex)
{
return tableItems.get(rowIndex).getObjectAt(columnIndex);
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex)
{
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex)
{
return false;
}
@Override
public void addTableModelListener(TableModelListener l)
{
listeners.add(l);
}
@Override
public void removeTableModelListener(TableModelListener l)
{
listeners.remove(l);
}
@Override
public int compare(TableItem o1, TableItem o2)
{
int res;
if (getColumnClass(sortByColumn) == Integer.class) {
Integer int1 = (Integer)o1.getObjectAt(sortByColumn);
Integer int2 = (Integer)o2.getObjectAt(sortByColumn);
res = int1.compareTo(int2);
}
else {
String string1 = o1.getObjectAt(sortByColumn).toString();
String string2 = o2.getObjectAt(sortByColumn).toString();
res = string1.compareToIgnoreCase(string2);
}
if (sortAscending)
res = -res;
return res;
}
}
}