/* * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing; import javax.swing.SortOrder; import javax.swing.event.*; import java.util.*; /** * RowSorter provides the basis for sorting and filtering. * Beyond creating and installing a RowSorter, you very rarely * need to interact with one directly. Refer to * {@link javax.swing.table.TableRowSorter TableRowSorter} for a concrete * implementation of RowSorter for JTable. *

* RowSorter's primary role is to provide a mapping between * two coordinate systems: that of the view (for example a * JTable) and that of the underlying data source, typically a * model. *

* The view invokes the following methods on the RowSorter: *

* Because the view makes extensive use of the * convertRowIndexToModel, * convertRowIndexToView and getViewRowCount methods, * these methods need to be fast. *

* RowSorter provides notification of changes by way of * RowSorterListener. Two types of notification are sent: *

* RowSorter implementations typically don't have a one-to-one * mapping with the underlying model, but they can. * For example, if a database does the sorting, * toggleSortOrder might call through to the database * (on a background thread), and override the mapping methods to return the * argument that is passed in. *

* Concrete implementations of RowSorter * need to reference a model such as TableModel or * ListModel. The view classes, such as * JTable and JList, will also have a * reference to the model. To avoid ordering dependencies, * RowSorter implementations should not install a * listener on the model. Instead the view class will call into the * RowSorter when the model changes. For * example, if a row is updated in a TableModel * JTable invokes rowsUpdated. * When the model changes, the view may call into any of the following methods: * modelStructureChanged, allRowsChanged, * rowsInserted, rowsDeleted and * rowsUpdated. * * @param the type of the underlying model * @see javax.swing.table.TableRowSorter * @since 1.6 */ public abstract class RowSorter { private EventListenerList listenerList = new EventListenerList(); /** * Creates a RowSorter. */ public RowSorter() { } /** * Returns the underlying model. * * @return the underlying model */ public abstract M getModel(); /** * Reverses the sort order of the specified column. It is up to * subclasses to provide the exact behavior when invoked. Typically * this will reverse the sort order from ascending to descending (or * descending to ascending) if the specified column is already the * primary sorted column; otherwise, makes the specified column * the primary sorted column, with an ascending sort order. If * the specified column is not sortable, this method has no * effect. *

* If this results in changing the sort order and sorting, the * appropriate RowSorterListener notification will be * sent. * * @param column the column to toggle the sort ordering of, in * terms of the underlying model * @throws IndexOutOfBoundsException if column is outside the range of * the underlying model */ public abstract void toggleSortOrder(int column); /** * Returns the location of index in terms of the * underlying model. That is, for the row index in * the coordinates of the view this returns the row index in terms * of the underlying model. * * @param index the row index in terms of the underlying view * @return row index in terms of the view * @throws IndexOutOfBoundsException if index is outside the * range of the view */ public abstract int convertRowIndexToModel(int index); /** * Returns the location of index in terms of the * view. That is, for the row index in the * coordinates of the underlying model this returns the row index * in terms of the view. * * @param index the row index in terms of the underlying model * @return row index in terms of the view, or -1 if index has been * filtered out of the view * @throws IndexOutOfBoundsException if index is outside * the range of the model */ public abstract int convertRowIndexToView(int index); /** * Sets the current sort keys. * * @param keys the new SortKeys; null * is a shorthand for specifying an empty list, * indicating that the view should be unsorted */ public abstract void setSortKeys(List keys); /** * Returns the current sort keys. This must return a {@code * non-null List} and may return an unmodifiable {@code List}. If * you need to change the sort keys, make a copy of the returned * {@code List}, mutate the copy and invoke {@code setSortKeys} * with the new list. * * @return the current sort order */ public abstract List getSortKeys(); /** * Returns the number of rows in the view. If the contents have * been filtered this might differ from the row count of the * underlying model. * * @return number of rows in the view * @see #getModelRowCount */ public abstract int getViewRowCount(); /** * Returns the number of rows in the underlying model. * * @return number of rows in the underlying model * @see #getViewRowCount */ public abstract int getModelRowCount(); /** * Invoked when the underlying model structure has completely * changed. For example, if the number of columns in a * TableModel changed, this method would be invoked. *

* You normally do not call this method. This method is public * to allow view classes to call it. */ public abstract void modelStructureChanged(); /** * Invoked when the contents of the underlying model have * completely changed. The structure of the table is the same, * only the contents have changed. This is typically sent when it * is too expensive to characterize the change in terms of the * other methods. *

* You normally do not call this method. This method is public * to allow view classes to call it. */ public abstract void allRowsChanged(); /** * Invoked when rows have been inserted into the underlying model * in the specified range (inclusive). *

* The arguments give the indices of the effected range. * The first argument is in terms of the model before the change, and * must be less than or equal to the size of the model before the change. * The second argument is in terms of the model after the change and must * be less than the size of the model after the change. For example, * if you have a 5-row model and add 3 items to the end of the model * the indices are 5, 7. *

* You normally do not call this method. This method is public * to allow view classes to call it. * * @param firstRow the first row * @param endRow the last row * @throws IndexOutOfBoundsException if either argument is invalid, or * firstRow > endRow */ public abstract void rowsInserted(int firstRow, int endRow); /** * Invoked when rows have been deleted from the underlying model * in the specified range (inclusive). *

* The arguments give the indices of the effected range and * are in terms of the model before the change. * For example, if you have a 5-row model and delete 3 items from the end * of the model the indices are 2, 4. *

* You normally do not call this method. This method is public * to allow view classes to call it. * * @param firstRow the first row * @param endRow the last row * @throws IndexOutOfBoundsException if either argument is outside * the range of the model before the change, or * firstRow > endRow */ public abstract void rowsDeleted(int firstRow, int endRow); /** * Invoked when rows have been changed in the underlying model * between the specified range (inclusive). *

* You normally do not call this method. This method is public * to allow view classes to call it. * * @param firstRow the first row, in terms of the underlying model * @param endRow the last row, in terms of the underlying model * @throws IndexOutOfBoundsException if either argument is outside * the range of the underlying model, or * firstRow > endRow */ public abstract void rowsUpdated(int firstRow, int endRow); /** * Invoked when the column in the rows have been updated in * the underlying model between the specified range. *

* You normally do not call this method. This method is public * to allow view classes to call it. * * @param firstRow the first row, in terms of the underlying model * @param endRow the last row, in terms of the underlying model * @param column the column that has changed, in terms of the underlying * model * @throws IndexOutOfBoundsException if either argument is outside * the range of the underlying model after the change, * firstRow > endRow, or * column is outside the range of the underlying * model */ public abstract void rowsUpdated(int firstRow, int endRow, int column); /** * Adds a RowSorterListener to receive notification * about this RowSorter. If the same * listener is added more than once it will receive multiple * notifications. If l is null nothing * is done. * * @param l the RowSorterListener */ public void addRowSorterListener(RowSorterListener l) { listenerList.add(RowSorterListener.class, l); } /** * Removes a RowSorterListener. If * l is null nothing is done. * * @param l the RowSorterListener */ public void removeRowSorterListener(RowSorterListener l) { listenerList.remove(RowSorterListener.class, l); } /** * Notifies listener that the sort order has changed. */ protected void fireSortOrderChanged() { fireRowSorterChanged(new RowSorterEvent(this)); } /** * Notifies listener that the mapping has changed. * * @param lastRowIndexToModel the mapping from model indices to * view indices prior to the sort, may be null */ protected void fireRowSorterChanged(int[] lastRowIndexToModel) { fireRowSorterChanged(new RowSorterEvent(this, RowSorterEvent.Type.SORTED, lastRowIndexToModel)); } void fireRowSorterChanged(RowSorterEvent event) { Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == RowSorterListener.class) { ((RowSorterListener)listeners[i + 1]). sorterChanged(event); } } } /** * SortKey describes the sort order for a particular column. The * column index is in terms of the underlying model, which may differ * from that of the view. * * @since 1.6 */ public static class SortKey { private int column; private SortOrder sortOrder; /** * Creates a SortKey for the specified column with * the specified sort order. * * @param column index of the column, in terms of the model * @param sortOrder the sorter order * @throws IllegalArgumentException if sortOrder is * null */ public SortKey(int column, SortOrder sortOrder) { if (sortOrder == null) { throw new IllegalArgumentException( "sort order must be non-null"); } this.column = column; this.sortOrder = sortOrder; } /** * Returns the index of the column. * * @return index of column */ public final int getColumn() { return column; } /** * Returns the sort order of the column. * * @return the sort order of the column */ public final SortOrder getSortOrder() { return sortOrder; } /** * Returns the hash code for this SortKey. * * @return hash code */ public int hashCode() { int result = 17; result = 37 * result + column; result = 37 * result + sortOrder.hashCode(); return result; } /** * Returns true if this object equals the specified object. * If the specified object is a SortKey and * references the same column and sort order, the two objects * are equal. * * @param o the object to compare to * @return true if o is equal to this SortKey */ public boolean equals(Object o) { if (o == this) { return true; } if (o instanceof SortKey) { return (((SortKey)o).column == column && ((SortKey)o).sortOrder == sortOrder); } return false; } } }