package jadex.commons.jtable;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.Comparator;
import java.util.Vector;
import javax.swing.JTable;
import javax.swing.table.TableModel;
public class SorterFilterTableModel extends AbstractIndexTableModel implements ISorterFilterTableModel
{
public static final int PAUSE_DISPLAYING_OFF = -1;
// Current filter
protected Vector filter = new Vector();
// if filter is enabled
protected boolean doFilter = false;
// Vector of sorting columns
protected Vector sortColumns = new Vector();
// Current sort column
protected int sortColumn = -1;
// Current sort direction
protected int sortDirection = NONE;
// stop displaying data
protected boolean pauseDisplaying = false;
// index of last row when paused displaying
// if pauseRow is PAUSE_DISPLAYING_OFF diplaying isnt paused
protected int pauseRow = PAUSE_DISPLAYING_OFF;
public SorterFilterTableModel(TableModel delegate)
{
super(delegate);
renewIndex();
}
public void renewIndex()
{
indexList.clear();
//TODO: adjust pauseRow on delegate.tableChanged event
if (pauseRow > delegate.getRowCount())
{
pauseRow = delegate.getRowCount();
}
int rows = pauseRow != PAUSE_DISPLAYING_OFF ? pauseRow : delegate.getRowCount();
for (int row = 0; row < rows; row++)
{
if (isFiltered(getRowData(row)))
{
indexList.add(new Integer(row));
}
}
if (isDoSort())
{
RowComparator rowComparator = new RowComparator(sortColumn, sortDirection == ASCENDING);
Collections.sort(indexList, rowComparator);
}
fireTableDataChanged();
}
public void tableRowsDeleted(int column, int firstRow, int lastRow)
{
for (int row = firstRow; row <= lastRow; row++)
{
int index = indexList.indexOf(new Integer(row));
if (index != -1)
{
indexList.remove(index);
fireTableRowsDeleted(index, index);
}
}
}
public void tableRowsInserted(int column, int firstRow, int lastRow)
{
if (isPausedDisplaying())
{
return;
}
for (int row = firstRow; row <= lastRow; row++)
{
// insert index if filter matches
if (isFiltered(getRowData(row)))
{
int index = getRowCount();
if (isDoSort())
{
// if sort then find the position to insert element
RowComparator rowComparator = new RowComparator(sortColumn, sortDirection == ASCENDING);
// the return value of binarySerach is (-(insertion point) - 1)
// insertion point is the index in the list
// at which the new element would be inserted
// if result >=0 then this is the position of an element found in the list
// note: If the list contains multiple elements equal to the specified object,
// there is no guarantee which one will be found
int result = Collections.binarySearch(indexList, new Integer(row), rowComparator);
index = result < 0 ? -1 - result : result;
}
indexList.add(index, new Integer(row));
fireTableRowsInserted(index, index);
}
}
}
public void tableRowsUpdated(int column, int firstRow, int lastRow)
{
// All data has changed
if (lastRow == Integer.MAX_VALUE)
{
renewIndex();
}
else
{
for (int row = firstRow; row <= lastRow; row++)
{
int index = indexList.indexOf(new Integer(row));
if (index != -1)
{
fireTableRowsUpdated(index, index);
}
}
}
}
private Vector getRowData(int row)
{
Vector rowData = new Vector();
int columns = delegate.getColumnCount();
for (int column = 0; column < columns; column++)
{
rowData.add(delegate.getValueAt(row, column));
}
return rowData;
}
private boolean isFiltered(Vector rowData)
{
if (filter == null || !doFilter)
{
return true;
}
boolean rowLogic[] = new boolean[filter.size() - 1];
for (int i = 0; i < filter.size() - 1; i++)
{
Vector rowFilter = (Vector) filter.elementAt(i);
rowLogic[i] = true;
for (int j = 0; j < rowFilter.size() - 1; j++)
{
if (rowFilter.elementAt(j) != null && rowData.elementAt(j) != null)
{
String cellFilter = rowFilter.elementAt(j).toString().trim();
String cellData = rowData.elementAt(j).toString().trim();
if (cellFilter.length() != 0)
{
// if (!cellData.equalsIgnoreCase(cellFilter))
try
{
if (!cellData.matches(cellFilter))
{
rowLogic[i] = false;
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
}
boolean result = rowLogic.length == 0;
for (int i = 0; i < rowLogic.length; i++)
{
result = result || rowLogic[i];
}
return result;
}
public void addMouseListener(final JTable table)
{
table.getTableHeader().setDefaultRenderer(new SortHeaderRenderer());
table.getTableHeader().addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent event)
{
// check for left button click
if (event.getButton() == MouseEvent.BUTTON1)
{
// find column of click and
int tableColumn = table.columnAtPoint(event.getPoint());
Rectangle r = table.getTableHeader().getHeaderRect(tableColumn);
r.grow(-3, 0);
if (r.contains(event.getPoint()))
{
// translate to table model index
int modelColumn = table.convertColumnIndexToModel(tableColumn);
sortDirection = (modelColumn == sortColumn) ? (++sortDirection) % 3 : DESCENDING;
sortColumn = modelColumn;
RowComparator rowComparator = new RowComparator(sortColumn, sortDirection == ASCENDING);
Collections.sort(indexList, isDoSort() ? rowComparator : null);
fireTableDataChanged();
// need to call resizeAndRepaint here to
// update the header properly
table.getTableHeader().resizeAndRepaint();
}
}
}
});
}
private class RowComparator implements Comparator
{
private boolean reverse = false;
private int column;
public RowComparator(int column, boolean reverse)
{
this.column = column;
this.reverse = reverse;
}
public int compare(Object o1, Object o2)
{
int result = 0;
int rowA = ((Integer) o1).intValue();
int rowB = ((Integer) o2).intValue();
Object a = delegate.getValueAt(rowA, column);
Object b = delegate.getValueAt(rowB, column);
// todo: a.getClass() == b.getClass() does not work for subclasses, use isAssignableFrom
boolean areTheyCompareable = (a instanceof Comparable && b instanceof Comparable && a.getClass() == b.getClass());
if (areTheyCompareable)
{
result = ((Comparable) a).compareTo((Comparable) b);
}
else
{
result = a.toString().compareTo(b.toString());
}
if (result == 0)
{
// if objects equal, take natural ordering (rowIndex) into account
result = ((Integer) o1).compareTo((Integer) o2);
}
return reverse ? result * (-1) : result;
}
}
public int getSortColumn()
{
return sortColumn;
}
public void setSortColumn(int sortColumn)
{
this.sortColumn = sortColumn;
}
public int getSortDirection()
{
return sortDirection;
}
public void setSortDirection(int sortDirection)
{
this.sortDirection = sortDirection;
}
public boolean isDoSort()
{
return sortColumn != -1 && sortDirection != NONE;
}
/**
* Filter the table using the values in the given vector.
* @param filter A Vector of filter expressions
*/
public void setFilter(Vector filter)
{
this.filter = filter;
}
public Vector getFilter()
{
return filter;
}
public boolean isDoFilter()
{
return doFilter;
}
public void setDoFilter(boolean doFilter)
{
this.doFilter = doFilter;
}
public boolean isPausedDisplaying()
{
return pauseRow != PAUSE_DISPLAYING_OFF;
}
public void setPauseDisplaying(boolean pauseDisplaying)
{
this.pauseRow = pauseDisplaying ? delegate.getRowCount() : PAUSE_DISPLAYING_OFF;
}
}