/*
* Beanfabrics Framework Copyright (C) by Michael Karneim, beanfabrics.org
* Use is subject to license terms. See license.txt.
*/
package org.beanfabrics.swing.table;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import org.beanfabrics.Path;
import org.beanfabrics.model.IListPM;
/**
* @author Michael Karneim
*/
public class BnTableRowSorter extends RowSorter<BnTableModel> {
public static BnTableRowSorter install(BnTable table) {
table.setUpdateSelectionOnSort(false);
BnTableModel model = (BnTableModel)table.getModel();
BnTableRowSorter rowSorter = new BnTableRowSorter(model);
table.setRowSorter(rowSorter);
return rowSorter;
}
public static void uninstall(BnTable table) {
@SuppressWarnings("rawtypes")
RowSorter rowSorter = table.getRowSorter();
if (rowSorter instanceof BnTableRowSorter) {
((BnTableRowSorter)rowSorter).dismiss();
}
table.setRowSorter(null);
}
private final BnTableModel model;
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
sortKeys.refresh();
fireSortOrderChanged();
}
};
private class SortKeys {
private RowSorter.SortKey[] sortKeyByColumn;
private RowSorter.SortKey[] sortKeyByPrecedence;
private List<RowSorter.SortKey> cachedSortKeyListByPrecedence;
public SortKeys(int columns) {
sortKeyByColumn = new RowSorter.SortKey[columns];
sortKeyByPrecedence = new RowSorter.SortKey[columns];
}
public int size() {
return asListByPrecedence().size();
}
public RowSorter.SortKey getSortKey(int col) {
return sortKeyByColumn[col];
}
public void clear() {
Arrays.fill(this.sortKeyByColumn, null);
Arrays.fill(this.sortKeyByPrecedence, null);
this.cachedSortKeyListByPrecedence = null;
}
public List<RowSorter.SortKey> asListByPrecedence() {
if (cachedSortKeyListByPrecedence == null) {
ArrayList<RowSorter.SortKey> newSortKeyList = new ArrayList<RowSorter.SortKey>();
for( RowSorter.SortKey sortKey: sortKeyByPrecedence) {
if ( sortKey != null) {
newSortKeyList.add(sortKey);
}
}
this.cachedSortKeyListByPrecedence = Collections.unmodifiableList(newSortKeyList);
}
return this.cachedSortKeyListByPrecedence;
}
public void refresh() {
if ( sortKeyByColumn.length==0) {
return;
}
clear();
Collection<org.beanfabrics.model.SortKey> modelSortKeysByPrecedence = model.getSortKeys();
int pos = 0;
for( org.beanfabrics.model.SortKey modelSortKey: modelSortKeysByPrecedence) {
int col = getFirstColumnIndexOf(modelSortKey.getSortPath());
if ( col == -1) {
// no column with that path was found.
// -> safely ignore this.
continue;
}
SortOrder sortOrder = modelSortKey.isAscending() ? SortOrder.ASCENDING : SortOrder.DESCENDING;
RowSorter.SortKey viewSortKey = new RowSorter.SortKey(col, sortOrder);
sortKeyByPrecedence[pos] = viewSortKey;
sortKeyByColumn[col] = viewSortKey;
pos++;
}
}
private int getFirstColumnIndexOf(Path path) {
List<BnColumn> colDefs = model.getColDefs();
int index = 0;
for( BnColumn colDef: colDefs) {
if ( path.equals(colDef.getPath())) {
return index;
}
index++;
}
return -1;
}
}
private final SortKeys sortKeys;
@SuppressWarnings("rawtypes")
private final IListPM list;
public BnTableRowSorter(BnTableModel model) {
super();
this.model = model;
int colNum = model.getColumnCount();
this.sortKeys = new SortKeys(colNum);
this.sortKeys.refresh();
this.list = model.getPresentationModel();
this.list.addPropertyChangeListener("sortKeys", pcl);
}
public void dismiss() {
this.list.removePropertyChangeListener("sortKeys", pcl);
}
@Override
public int convertRowIndexToModel(int index) {
return index;
}
@Override
public int convertRowIndexToView(int index) {
return index;
}
@Override
public BnTableModel getModel() {
return model;
}
@Override
public int getModelRowCount() {
return model.getRowCount();
}
@Override
public List<? extends RowSorter.SortKey> getSortKeys() {
return this.sortKeys.asListByPrecedence();
}
@Override
public int getViewRowCount() {
return model.getRowCount();
}
@Override
public void setSortKeys(List<? extends RowSorter.SortKey> keys) {
org.beanfabrics.model.SortKey[] modelSortKeys = new org.beanfabrics.model.SortKey[this.sortKeys.size()];
Iterator<? extends RowSorter.SortKey> it = this.sortKeys.asListByPrecedence().iterator();
for (int i = 0; i < modelSortKeys.length; ++i) {
RowSorter.SortKey key = it.next();
Path path = model.getColumnPath(key.getColumn());
boolean ascending = key.getSortOrder() == SortOrder.ASCENDING;
modelSortKeys[i] = new org.beanfabrics.model.SortKey(ascending, path);
}
list.sortBy(modelSortKeys);
fireRowSorterChanged(null);
}
@Override
public void toggleSortOrder(int column) {
RowSorter.SortKey sk = this.sortKeys.getSortKey(column);
boolean ascending;
if (sk == null) {
ascending = true;
} else {
ascending = sk.getSortOrder() != SortOrder.ASCENDING;
}
Path path = model.getColumnPath(column);
list.sortBy(ascending, path);
}
/// Callback methods that we don't use in Beanfabrics:
@Override
public void modelStructureChanged() {
// nothing to do here
// fireSortOrderChanged();
// fireRowSorterChanged(null);
}
@Override
public void rowsDeleted(int firstRow, int endRow) {
// nothing to do here
// fireSortOrderChanged();
// fireRowSorterChanged(null);
}
@Override
public void rowsInserted(int firstRow, int endRow) {
// nothing to do here
// fireSortOrderChanged();
// fireRowSorterChanged(null);
}
@Override
public void rowsUpdated(int firstRow, int endRow) {
// nothing to do here
// fireSortOrderChanged();
// fireRowSorterChanged(null);
}
@Override
public void rowsUpdated(int firstRow, int endRow, int column) {
// nothing to do here
// fireSortOrderChanged();
// fireRowSorterChanged(null);
}
@Override
public void allRowsChanged() {
// nothing to do here
// fireSortOrderChanged();
// fireRowSorterChanged(null);
}
}