001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.history;
003
004import java.util.HashSet;
005import java.util.Set;
006
007import javax.swing.DefaultListSelectionModel;
008import javax.swing.ListSelectionModel;
009import javax.swing.event.ListSelectionEvent;
010import javax.swing.event.ListSelectionListener;
011
012/**
013 * Helper class to ensure that two (or more) {@link javax.swing.JTable}s always
014 * have the same entries selected.
015 * 
016 * The tables are usually displayed side-by-side.
017 */
018public class SelectionSynchronizer implements ListSelectionListener {
019
020    private final Set<ListSelectionModel> participants;
021    private boolean preventRecursion;
022
023    /**
024     * Constructs a new {@code SelectionSynchronizer}.
025     */
026    public SelectionSynchronizer() {
027        participants = new HashSet<>();
028    }
029
030    /**
031     * Add {@link ListSelectionModel} of the table to participate in selection
032     * synchronization.
033     * 
034     * Call this method for all tables that should have their selection synchronized.
035     * @param model the selection model of the table
036     */
037    public void participateInSynchronizedSelection(ListSelectionModel model) {
038        if (model == null)
039            return;
040        if (participants.contains(model))
041            return;
042        participants.add(model);
043        model.addListSelectionListener(this);
044    }
045
046    @Override
047    public void valueChanged(ListSelectionEvent e) {
048        if (preventRecursion) {
049            return;
050        }
051        preventRecursion = true;
052        DefaultListSelectionModel referenceModel = (DefaultListSelectionModel) e.getSource();
053        int i = referenceModel.getMinSelectionIndex();
054        int j = referenceModel.getMaxSelectionIndex();
055        for (ListSelectionModel model : participants) {
056            if (model == e.getSource()) {
057                continue;
058            }
059            model.setSelectionInterval(i, j);
060        }
061        preventRecursion = false;
062    }
063}