package com.link_intersystems.swing; import javax.swing.ListSelectionModel; import javax.swing.RowSorter; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; public class RowSorterAwareListSelectionModelUpdater { private ListSelectionModelSync targetModelSync = new ListSelectionModelSync(); private ListSelectionModelSync sourceModelSync = new ListSelectionModelSync(); private ListSelectionModel targetModel; private ListSelectionModel sourceModel; public void setTargetModel(ListSelectionModel targetModel) { if (this.targetModel != null) { this.targetModel.removeListSelectionListener(sourceModelSync); } this.targetModel = targetModel; if (this.targetModel != null) { targetModelSync.setTargetModel(targetModel, sourceModelSync); this.targetModel.addListSelectionListener(sourceModelSync); } } public void setSourceModel(ListSelectionModel listSelectionModel, RowSorter<?> rowSorter) { if (this.sourceModel != null) { this.sourceModel.removeListSelectionListener(targetModelSync); } if (rowSorter == null) { targetModelSync.setIndexConverter(null); sourceModelSync.setIndexConverter(null); } else { targetModelSync .setIndexConverter(new ViewToModelRowSorterConverter( rowSorter)); sourceModelSync .setIndexConverter(new ModelToViewRowSorterConverter( rowSorter)); } this.sourceModel = listSelectionModel; if (this.sourceModel != null) { sourceModelSync.setTargetModel(sourceModel, targetModelSync); this.sourceModel.addListSelectionListener(targetModelSync); } } private class ListSelectionModelSync implements ListSelectionListener { private ListSelectionModel targetModel; private IndexConverter indexConverter = NoopIndexConverter.INSTANCE; private ListSelectionListener targetModelSync; public void setTargetModel(ListSelectionModel targetModel, ListSelectionListener targetModelSync) { this.targetModel = targetModel; this.targetModelSync = targetModelSync; } public void setIndexConverter(IndexConverter indexConverter) { if (indexConverter == null) { indexConverter = NoopIndexConverter.INSTANCE; } this.indexConverter = indexConverter; } @Override public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting() && targetModel != null) { ListSelectionModel sourceModel = (ListSelectionModel) e .getSource(); int minIndex = sourceModel.getMinSelectionIndex(); int maxIndex = sourceModel.getMaxSelectionIndex(); targetModel.removeListSelectionListener(targetModelSync); targetModel.setValueIsAdjusting(true); targetModel.clearSelection(); for (int index = minIndex; index <= maxIndex; index++) { if (sourceModel.isSelectedIndex(index)) { int targetIndex = indexConverter.convert(index); targetModel.addSelectionInterval(targetIndex, targetIndex); } } targetModel.setValueIsAdjusting(false); targetModel.addListSelectionListener(targetModelSync); } } } private static interface IndexConverter { public int convert(int index); } private static class ViewToModelRowSorterConverter implements IndexConverter { private RowSorter<?> rowSorter; public ViewToModelRowSorterConverter(RowSorter<?> rowSorter) { this.rowSorter = rowSorter; } @Override public int convert(int index) { return rowSorter.convertRowIndexToModel(index); } } private static class ModelToViewRowSorterConverter implements IndexConverter { private RowSorter<?> rowSorter; public ModelToViewRowSorterConverter(RowSorter<?> rowSorter) { this.rowSorter = rowSorter; } @Override public int convert(int index) { return rowSorter.convertRowIndexToView(index); } } private static class NoopIndexConverter implements IndexConverter { public static final NoopIndexConverter INSTANCE = new NoopIndexConverter(); @Override public int convert(int index) { return index; } } }