001package jmri.swing; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.Objects; 006import javax.annotation.Nonnull; 007import javax.swing.RowSorter; 008import javax.swing.RowSorter.SortKey; 009import javax.swing.SortOrder; 010import javax.swing.event.RowSorterEvent; 011import javax.swing.event.RowSorterListener; 012import javax.swing.table.TableModel; 013 014/** 015 * Utilities for handling JTable row sorting, assuming only a single column 016 * influences the table sort order. 017 * <p> 018 * Multi-column sorting should be controlled by directly manipulating the 019 * {@link javax.swing.RowSorter.SortKey}s returned by 020 * {@link javax.swing.RowSorter#getSortKeys()}. 021 * 022 * @author Randall Wood 023 */ 024public final class RowSorterUtil { 025 026 /** 027 * Get the sort order for a column given a RowSorter for the TableModel 028 * containing the column. 029 * 030 * @param rowSorter the sorter 031 * @param column the column index in the model, not the view 032 * @return the sort order or {@link javax.swing.SortOrder#UNSORTED}. 033 */ 034 @Nonnull 035 public static SortOrder getSortOrder(@Nonnull RowSorter<? extends TableModel> rowSorter, int column) { 036 for (SortKey key : rowSorter.getSortKeys()) { 037 if (key.getColumn() == column) { 038 return key.getSortOrder(); 039 } 040 } 041 return SortOrder.UNSORTED; 042 } 043 044 /** 045 * Set the sort order for a table using the specified column given a 046 * RowSorter for the TableModel containing the column. 047 * <p> 048 * This makes all other columns unsorted, even if the specified column is 049 * also specified to be unsorted. 050 * 051 * @param rowSorter the sorter 052 * @param column the column index in the model, not the view 053 * @param sortOrder the sort order 054 */ 055 public static void setSortOrder(@Nonnull RowSorter<? extends TableModel> rowSorter, int column, @Nonnull SortOrder sortOrder) { 056 List<SortKey> keys = new ArrayList<>(); 057 if (!sortOrder.equals(SortOrder.UNSORTED)) { 058 keys.add(new RowSorter.SortKey(column, sortOrder)); 059 } 060 rowSorter.setSortKeys(keys); 061 } 062 063 /** 064 * Add a RowSorterListener to the rowSorter that prevents multiple columns 065 * from being considered while sorting. 066 * 067 * @param rowSorter the sorter to add the listener to 068 * @return the added listener 069 * @throws NullPointerException if rowSorter is null 070 */ 071 public static RowSorterListener addSingleSortableColumnListener(@Nonnull RowSorter<? extends TableModel> rowSorter) { 072 Objects.requireNonNull(rowSorter, "rowSorter must be nonnull."); 073 RowSorterListener listener = new RowSorterListener() { 074 List<? extends SortKey> priorSortKeys = new ArrayList<>(); 075 076 @Override 077 public void sorterChanged(RowSorterEvent e) { 078 if (e.getType().equals(RowSorterEvent.Type.SORT_ORDER_CHANGED)) { 079 RowSorter<?> source = e.getSource(); 080 List<? extends SortKey> newSortKeys = new ArrayList<>(source.getSortKeys()); 081 newSortKeys.removeAll(priorSortKeys); 082 if (!newSortKeys.isEmpty()) { 083 priorSortKeys = newSortKeys; 084 source.setSortKeys(priorSortKeys); 085 source.allRowsChanged(); 086 } 087 } 088 } 089 }; 090 rowSorter.addRowSorterListener(listener); 091 return listener; 092 } 093}