Вполне рабочая table model для Swing компонента JTable.
Создан для поддержки фильтрации в таблице.
Поддерживает фильтрацию по регулярными выражениями.
Поддерживает так называемый сложный фильтр по полю со структурой: параметр1Значение1параметр2Значение2...
Например, p23h34j23. МОжно задать фильтрацию такую 10<p<25 и тп по каждому параметру.
Размещаю здесь ибо не устраивает производительность.
Хочу оптимизировать с вашей помощью коллеги.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;
import rov.ColumnFilter;
/**
*
* @author Oleg Rachaev
* You may use this code for free by GPL license
*/
public class FilteredTableModel extends AbstractTableModel {
private final HashMap<Integer, ColumnFilter> columnFilter = new HashMap<Integer, ColumnFilter>();
private boolean useFilter = false, useComplexFilter = false;
private ArrayList<ColumnFilter> columnComplexFilter = new ArrayList<ColumnFilter>();
private final HashSet<Integer> complexFields = new HashSet<Integer>();
private boolean eventsEnabled = true;
private int undefComplexVal = 20;
private int rowCount;
protected ArrayList data;
protected ArrayList columnIdentifiers;
private static final Pattern digits = Pattern.compile("\\d+");
public FilteredTableModel() {
}
public FilteredTableModel(ArrayList data, ArrayList columnNames) {
setData(data, columnNames);
}
public FilteredTableModel(Object[][] data, Object[] columnNames) {
setData(data, columnNames);
}
@Override
public void fireTableRowsDeleted(int firstRow, int lastRow) {
recalcRowCount();
super.fireTableRowsDeleted(firstRow, lastRow);
}
@Override
public void fireTableRowsInserted(int firstRow, int lastRow) {
recalcRowCount();
super.fireTableRowsInserted(firstRow, lastRow);
}
@Override
public void fireTableDataChanged() {
recalcRowCount();
fireTableChanged(new TableModelEvent(this));
}
public void setColumnFilter(int col, ColumnFilter filter) {
if ((filter == null) || (col > getColumnCount() - 1) || (col < 0)) {
return;
}
ColumnFilter old = columnFilter.put(Integer.valueOf(col), filter);
if ((old == null) || ((old != null) && (!old.equals(filter)))) {
fireTableDataChanged();
}
}
public void setColumnFilter(int col, String regexp) {
if ((regexp == null) || (regexp.isEmpty())) {
removeColumnFilter(col);
return;
}
ColumnFilter f = new ColumnFilter(ColumnFilter.REGEXP);
f.setRegExp(regexp);
setColumnFilter(col, f);
}
public void setColumnFilter(int col, float min, float max) {
ColumnFilter f = new ColumnFilter(ColumnFilter.LIMITS);
f.setLimits(min, max);
setColumnFilter(col, f);
}
public void removeColumnFilter(int col) {
if ((col > getColumnCount() - 1) || (col < 0)) {
return;
}
Object old = columnFilter.remove(Integer.valueOf(col));
if (old != null) {
fireTableDataChanged();
}
}
public void setComplexColumnFilter(int col, String attr, float min, float max, boolean enabled) {
if ((col > getColumnCount() - 1) || (col < 0)) {
return;
}
ColumnFilter f = new ColumnFilter(ColumnFilter.LIMITS);
f.setLimits(min, max);
f.attr = attr;
f.column = col;
f.enabled = enabled;
int old = indexOfComplexFilter(col, attr);
if (old == -1) {
columnComplexFilter.add(f);
complexFields.add(col);
fireTableDataChanged();
} else {
//update params
ColumnFilter ff = columnComplexFilter.get(old);
if (!ff.equals(f)) {
ff.copyFrom(f);
fireTableDataChanged();
}
}
}
public int indexOfComplexFilter(int col, String attr) {
int size = columnComplexFilter.size();
ColumnFilter f;
for (int i = 0; i < size; i++) {
f = columnComplexFilter.get(i);
if ((col == f.column) && (attr.equals(f.attr))) {
return i;
}
}
return -1;
}
public void removeComplexColumnFilter(int col, String attr) {
if ((col > getColumnCount() - 1) || (col < 0)) {
return;
}
boolean removed = false;
for (ColumnFilter f : columnComplexFilter) {
if ((f.column == col) && (f.attr.equals(attr))) {
removed = columnComplexFilter.remove(f);
complexFields.remove(col);
}
}
if (removed) {
fireTableDataChanged();
}
}
public void setData(ArrayList dataVector, ArrayList columnIdentifiers) {
this.data = nonNullArray(dataVector);
this.columnIdentifiers = nonNullArray(columnIdentifiers);
fireTableStructureChanged();
}
private static ArrayList nonNullArray(ArrayList v) {
return (v != null) ? v : new ArrayList();
}
public void setData(Object[][] dataVector, Object[] columnIdentifiers) {
setData(convertToArray(dataVector), convertToArray(columnIdentifiers));
}
protected static ArrayList convertToArray(Object[] anArray) {
if (anArray == null) {
return null;
}
ArrayList v = new ArrayList(anArray.length);
v.addAll(Arrays.asList(anArray));
return v;
}
protected static ArrayList convertToArray(Object[][] anArray) {
if (anArray == null) {
return null;
}
ArrayList v = new ArrayList(anArray.length);
for (int i = 0; i < anArray.length; i++) {
v.add(convertToArray(anArray[i]));
}
return v;
}
@Override
public Object getValueAt(int row, int column) {
//TODO
int row2 = 0;
ArrayList rowVector;
for (int i = 0; i < data.size(); i++) {
rowVector = (ArrayList) data.get(i);
if (filterOk(rowVector)) {
if (row2 == row) {
if ((column < 0) || (column > rowVector.size() - 1)) {
return null;
} else {
return rowVector.get(column);
}
}
row2++;
}
}
return null;
}
@Override
public void setValueAt(Object aValue, int row, int column) {
if (!checkRanges(row, column)) return;
int row2 = 0;
ArrayList rowVector;
for (int i = 0; i < data.size(); i++) {
rowVector = (ArrayList) data.get(i);
if (filterOk(rowVector)) {
if (row2 == row) {//found row
fullFillRow(rowVector);
if (column<rowVector.size()) rowVector.set(column, aValue);
}
row2++;
}
}
}
private void fullFillRow(ArrayList rowVector) {
while (rowVector.size()<columnIdentifiers.size()) rowVector.add(new String());
}
private boolean checkRanges(int row,int col) {
boolean b=true;
if ((row<0) || (row>data.size()-1)) b=false;
if ((col<0) || (col>columnIdentifiers.size()-1)) b=false;
return b;
}
@Override
public int getRowCount() {
return rowCount;
}
public void recalcRowCount() {
int count = 0;
ArrayList rowVector;
for (int i = 0; i < data.size(); i++) {
rowVector = (ArrayList) data.get(i);
if (filterOk(rowVector)) {
count++;
}
}
rowCount = count;
}
private boolean filterOk(ArrayList rowData) {
if (((columnFilter == null) || (columnFilter.isEmpty()) || (!isUseFilter()))
&& ((columnComplexFilter == null) || (columnComplexFilter.isEmpty()) || (!isUseComplexFilter()))) {
return true;
}
boolean res = true;
int v;
ColumnFilter f;
int size = rowData.size();
Object o;
String s;
for (int i = 0; i < size; i++) {
f = columnFilter.get(Integer.valueOf(i));
o = rowData.get(i);
if (o == null) {
s = null;
} else {
s = rowData.get(i).toString();
}
if (f == null) //nofilter
;//nothing
else {
if (f.type == ColumnFilter.REGEXP) {
if (!s.matches(".*" + f.regexp + ".*")) {
return false;
}
} else if (f.type == ColumnFilter.LIMITS) {
//o = rowData.get(i);
if ((s == null) || (s.isEmpty())) {
continue;//return false;
}
v = Integer.valueOf(s);
if ((f.min > v) || (v > f.max)) {
return false;
}
}
}
if ((complexFields.contains(i)) && (!complexFilterOk(s))) {
return false;
}
}
return res;
}
private boolean complexFilterOk(String val) {
if (useComplexFilter) {
if ((val == null) || (val.isEmpty())) {
return true;//allow undefined
}
int size2 = columnComplexFilter.size();
ColumnFilter f;
//digits = Pattern.compile("\\d+");
for (int j = 0; j < size2; j++) {
f = columnComplexFilter.get(j);
// && (val.matches(".*"+f.attr+"\\d*.*"))
if ((f != null) && (f.enabled)) {
if ((f.type == ColumnFilter.LIMITS) && (!f.attr.isEmpty())) {
Pattern p = Pattern.compile(f.attr + "\\d*");
Matcher m = p.matcher(val);
if (m.find()) {
m = digits.matcher(m.group());
int v;
if (m.find()) {
String ss = m.group();
v = Integer.valueOf(ss);
} else {
v = getUndefComplexVal();
}
if ((f.min > v) || (v > f.max)) {
return false;
}
} else {
return false;
}
}
}
}
}
return true;
}
public void toggleComplexFilter(int col, String attr, boolean flag) {
int size2 = columnComplexFilter.size();
ColumnFilter f;
boolean old = false;
for (int j = 0; j < size2; j++) {
f = columnComplexFilter.get(j);
if ((f != null) && (f.type == ColumnFilter.LIMITS) && (f.attr.equals(attr))) {
old = f.enabled;
f.enabled = flag;
if (old != flag) {
fireTableDataChanged();
}
}
}
}
public boolean isUseFilter() {
return useFilter;
}
public void setUseFilter(boolean useFilter) {
boolean old = this.useFilter;
if (old != useFilter) {
this.useFilter = useFilter;
fireTableDataChanged();
}
}
public void setUseComplexFilter(boolean useComplexFilter) {
boolean old = this.useComplexFilter;
if (old != useComplexFilter) {
this.useComplexFilter = useComplexFilter;
fireTableDataChanged();
}
}
public boolean isUseComplexFilter() {
return useComplexFilter;
}
public boolean isEventsEnabled() {
return eventsEnabled;
}
public void setEventsEnabled(boolean eventsEnabled) {
boolean old = this.eventsEnabled;
if (old != eventsEnabled) {
this.eventsEnabled = eventsEnabled;
if (eventsEnabled)
fireTableDataChanged();
}
}
public int getUndefComplexVal() {
return undefComplexVal;
}
public void setUndefComplexVal(int undefComplexVal) {
this.undefComplexVal = undefComplexVal;
}
@Override
public int getColumnCount() {
if (columnIdentifiers == null) {
return 0;
}
return columnIdentifiers.size();
}
public void insertRow(int row, ArrayList rowData) {
data.add(row, rowData);
//justifyRows(row, row+1);
fireTableRowsInserted(row, row);
}
public void addRow(ArrayList rowData) {
insertRow(data.size(), rowData);
fullFillRow((ArrayList)data.get(data.size()-1));
}
public void addRow(Object[] rowData) {
addRow(convertToArray(rowData));
}
public void clear(boolean notify) {
data.clear();
if (notify) {
fireTableDataChanged();
}
}
@Override
public String getColumnName(int column) {
return columnIdentifiers.get(column).toString();
}
}
/**
*
* @author Oleg Rachaev
*/
public class ColumnFilter {
public static final int REGEXP = 1;
public static final int LIMITS = 2;
public int type = REGEXP;
public float min=-999999999,max=999999999;
public String regexp="";
public int column = -1;
public String attr="";//attribute pattern in complex field
public boolean enabled = true;
//complex files: a10bf25line7 ==> a=10 bf =25 line = 7
public ColumnFilter(int type) {
this.type = type;
}
public void setRegExp(String regexp) {
this.regexp = regexp;
}
public void setLimits(float min, float max) {
this.min = min;
this.max = max;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ColumnFilter)) return false;
ColumnFilter v = (ColumnFilter) obj;
if (type==REGEXP)
return ((this.type == v.type) && (this.regexp == null ? v.regexp == null : this.regexp.equals(v.regexp)));
else if (type==LIMITS)
return ( (this.type == v.type)
&& (Math.abs(this.min - v.min) < 0.00001)
&& (Math.abs(this.max - v.max) < 0.00001)
&& (attr.equals(v.attr)));
else return (this.type == v.type);
}
@Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + this.type;
hash = 17 * hash + Float.floatToIntBits(this.min);
hash = 17 * hash + Float.floatToIntBits(this.max);
hash = 17 * hash + (this.regexp != null ? this.regexp.hashCode() : 0);
return hash;
}
public void copyFrom(ColumnFilter from) {
if (from == null) return;
this.attr = String.valueOf(from.attr);
this.column = from.column;
this.min = from.min;
this.max = from.max;
this.regexp = String.valueOf(from.regexp);
this.type = from.type;
}
}