/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/gui/FilteredTableModel.java
Java | 298 lines | 150 code | 34 blank | 114 comment | 27 complexity | 6563d7245567d0cefd3670a3340c2c74 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
- /*
- * FilteredTableModel.java - A Filtered table model decorator
- * :tabSize=8:indentSize=8:noTabs=false:
- * :folding=explicit:collapseFolds=1:
- *
- * Copyright (C) 2007 Shlomy Reinstein
- * Copyright (C) 2007 Matthieu Casanova
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- package org.gjt.sp.jedit.gui;
- import javax.swing.*;
- import javax.swing.event.TableModelEvent;
- import javax.swing.event.TableModelListener;
- import javax.swing.table.AbstractTableModel;
- import javax.swing.table.TableModel;
- import java.util.*;
- /**
- * This TableModel delegates another model to add some filtering features to any
- * JTable.
- * To use it you must implement the abstract method passFilter().
- * This method is called for each row, and must return true if the row should be
- * visible, and false otherwise.
- * It is also possible to override the method prepareFilter() that allow you to
- * transform the filter String. Usually you can return it as lowercase
- * <p/>
- * Here is an example of how to use it extracted from the InstallPanel
- * <code>
- * PluginTableModel tableModel = new PluginTableModel();
- * filteredTableModel = new FilteredTableModel<PluginTableModel>(tableModel)
- * {
- * public String prepareFilter(String filter)
- * {
- * return filter.toLowerCase();
- * }
- * <p/>
- * public boolean passFilter(int row, String filter)
- * {
- * String pluginName = (String) delegated.getValueAt(row, 1);
- * return pluginName.toLowerCase().contains(filter);
- * }
- * };
- * table = new JTable(filteredTableModel);
- * filteredTableModel.setTable(table);
- * </code>
- * It is not mandatory but highly recommended to give the JTable instance to the
- * model in order to keep the selection after the filter has been updated
- *
- * @author Shlomy Reinstein
- * @author Matthieu Casanova
- * @version $Id: Buffer.java 8190 2006-12-07 07:58:34Z kpouer $
- * @since jEdit 4.3pre11
- */
- public abstract class FilteredTableModel<E extends TableModel> extends AbstractTableModel implements TableModelListener
- {
- /**
- * The delegated table model.
- */
- protected E delegated;
- private Vector<Integer> filteredIndices;
- /**
- * This map contains the delegated indices as key and true indices as values.
- */
- private Map<Integer, Integer> invertedIndices;
- private String filter;
- private JTable table;
- //{{{ FilteredTableModel() constructor
- protected FilteredTableModel(E delegated)
- {
- this.delegated = delegated;
- delegated.addTableModelListener(this);
- resetFilter();
- } //}}}
- //{{{ setTable() method
- /**
- * Set the JTable that uses this model.
- * It is used to restore the selection after the filter has been applied
- * If it is null,
- *
- * @param table the table that uses the model
- */
- public void setTable(JTable table)
- {
- if (table.getModel() != this)
- throw new IllegalArgumentException("The given table " + table + " doesn't use this model " + this);
- this.table = table;
- } //}}}
- //{{{ getDelegated() method
- public E getDelegated()
- {
- return delegated;
- } //}}}
- //{{{ setDelegated() method
- public void setDelegated(E delegated)
- {
- this.delegated.removeTableModelListener(this);
- delegated.addTableModelListener(this);
- this.delegated = delegated;
- } //}}}
- //{{{ resetFilter() method
- private void resetFilter()
- {
- filteredIndices = null;
- } //}}}
- //{{{ setFilter() method
- public void setFilter(String filter)
- {
- Set<Integer> selectedIndices = saveSelection();
- this.filter = filter;
- if (filter != null && filter.length() > 0)
- {
- int size = delegated.getRowCount();
- filter = prepareFilter(filter);
- Vector<Integer> indices = new Vector<Integer>(size);
- Map<Integer, Integer> invertedIndices = new HashMap<Integer, Integer>();
- for (int i = 0; i < size; i++)
- {
- if (passFilter(i, filter))
- {
- Integer delegatedIndice = Integer.valueOf(i);
- indices.add(delegatedIndice);
- invertedIndices.put(delegatedIndice, indices.size() - 1);
- }
- }
- this.invertedIndices = invertedIndices;
- filteredIndices = indices;
- }
- else
- resetFilter();
- fireTableDataChanged();
- restoreSelection(selectedIndices);
- } //}}}
- //{{{ prepareFilter() method
- public String prepareFilter(String filter)
- {
- return filter;
- } //}}}
- //{{{ passFilter() method
- /**
- * This callback indicates if a row passes the filter.
- *
- * @param row the row number the delegate row count
- * @param filter the filter string
- * @return true if the row must be visible
- */
- public abstract boolean passFilter(int row, String filter);
- //}}}
- //{{{ saveSelection()
- private Set<Integer> saveSelection()
- {
- if (table == null)
- return null;
- int[] rows = table.getSelectedRows();
- if (rows.length == 0)
- return null;
- Set<Integer> selectedRows = new HashSet<Integer>(rows.length);
- for (int row : rows)
- {
- selectedRows.add(getTrueRow(row));
- }
- return selectedRows;
- } //}}}
- //{{{ restoreSelection() method
- private void restoreSelection(Set<Integer> selectedIndices)
- {
- if (selectedIndices == null || getRowCount() == 0)
- return;
-
- for (Integer selectedIndex : selectedIndices)
- {
- int i = getInternal2ExternalRow(selectedIndex.intValue());
- if (i != -1)
- table.getSelectionModel().setSelectionInterval(i, i);
- }
- } //}}}
- //{{{ getRowCount() method
- public int getRowCount()
- {
- if (filteredIndices == null)
- return delegated.getRowCount();
- return filteredIndices.size();
- } //}}}
- //{{{ getColumnCount() method
- public int getColumnCount()
- {
- return delegated.getColumnCount();
- } //}}}
- //{{{ getColumnName() method
- public String getColumnName(int columnIndex)
- {
- return delegated.getColumnName(columnIndex);
- } //}}}
- //{{{ getColumnClass() method
- public Class<?> getColumnClass(int columnIndex)
- {
- return delegated.getColumnClass(columnIndex);
- } //}}}
- //{{{ isCellEditable() method
- public boolean isCellEditable(int rowIndex, int columnIndex)
- {
- int trueRowIndex = getTrueRow(rowIndex);
- return delegated.isCellEditable(trueRowIndex, columnIndex);
- } //}}}
- //{{{ getValueAt() method
- public Object getValueAt(int rowIndex, int columnIndex)
- {
- int trueRowIndex = getTrueRow(rowIndex);
- return delegated.getValueAt(trueRowIndex, columnIndex);
- } //}}}
- //{{{ setValueAt() method
- public void setValueAt(Object aValue, int rowIndex, int columnIndex)
- {
- int trueRowIndex = getTrueRow(rowIndex);
- delegated.setValueAt(aValue, trueRowIndex, columnIndex);
- } //}}}
- //{{{ getTrueRow() method
- /**
- * Converts a row index from the JTable to an internal row index from the delegated model.
- *
- * @param rowIndex the row index
- * @return the row index in the delegated model
- */
- public int getTrueRow(int rowIndex)
- {
- if (filteredIndices == null)
- return rowIndex;
- return filteredIndices.get(rowIndex).intValue();
- } //}}}
- //{{{ getInternal2ExternalRow() method
- /**
- * Converts a row index from the delegated table model into a row index of the JTable.
- *
- * @param internalRowIndex the internal row index
- * @return the table row index or -1 if this row is not visible
- */
- public int getInternal2ExternalRow(int internalRowIndex)
- {
- if (invertedIndices == null)
- return internalRowIndex;
- Integer externalRowIndex = invertedIndices.get(internalRowIndex);
- if (externalRowIndex == null)
- return -1;
- return externalRowIndex.intValue();
- } //}}}
- /**
- * This fine grain notification tells listeners the exact range
- * of cells, rows, or columns that changed.
- */
- public void tableChanged(TableModelEvent e)
- {
- setFilter(filter);
- }
- }