На суд общественности модель данных для JTable
От: rov63rus  
Дата: 07.11.10 13:01
Оценка:
Вполне рабочая 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;

    }
    
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.