1 | // License: GPL. For details, see LICENSE file.
|
---|
2 | package org.openstreetmap.josm.gui.history;
|
---|
3 |
|
---|
4 | import java.util.Arrays;
|
---|
5 | import java.util.HashSet;
|
---|
6 | import java.util.Objects;
|
---|
7 | import java.util.Set;
|
---|
8 | import java.util.function.BiFunction;
|
---|
9 | import java.util.stream.IntStream;
|
---|
10 |
|
---|
11 | import javax.swing.ListSelectionModel;
|
---|
12 | import javax.swing.event.ListSelectionEvent;
|
---|
13 | import javax.swing.event.ListSelectionListener;
|
---|
14 |
|
---|
15 | import org.openstreetmap.josm.gui.util.TableHelper;
|
---|
16 |
|
---|
17 | /**
|
---|
18 | * Helper class to ensure that two (or more) {@link javax.swing.JTable}s always
|
---|
19 | * have the same entries selected.
|
---|
20 | *
|
---|
21 | * The tables are usually displayed side-by-side.
|
---|
22 | */
|
---|
23 | public class SelectionSynchronizer implements ListSelectionListener {
|
---|
24 |
|
---|
25 | private final Set<ListSelectionModel> participants;
|
---|
26 | private boolean preventRecursion;
|
---|
27 | private BiFunction<Integer, ListSelectionModel, IntStream> selectionIndexMapper = (i, model) -> IntStream.of(i);
|
---|
28 |
|
---|
29 | /**
|
---|
30 | * Constructs a new {@code SelectionSynchronizer}.
|
---|
31 | */
|
---|
32 | public SelectionSynchronizer() {
|
---|
33 | participants = new HashSet<>();
|
---|
34 | }
|
---|
35 |
|
---|
36 | /**
|
---|
37 | * Add {@link ListSelectionModel} of the table to participate in selection
|
---|
38 | * synchronization.
|
---|
39 | *
|
---|
40 | * Call this method for all tables that should have their selection synchronized.
|
---|
41 | * @param model the selection model of the table
|
---|
42 | */
|
---|
43 | public void participateInSynchronizedSelection(ListSelectionModel model) {
|
---|
44 | if (model == null)
|
---|
45 | return;
|
---|
46 | if (participants.contains(model))
|
---|
47 | return;
|
---|
48 | participants.add(model);
|
---|
49 | model.addListSelectionListener(this);
|
---|
50 | }
|
---|
51 |
|
---|
52 | void setSelectionIndexMapper(BiFunction<Integer, ListSelectionModel, IntStream> selectionIndexMapper) {
|
---|
53 | this.selectionIndexMapper = Objects.requireNonNull(selectionIndexMapper);
|
---|
54 | }
|
---|
55 |
|
---|
56 | @Override
|
---|
57 | public void valueChanged(ListSelectionEvent e) {
|
---|
58 | if (preventRecursion) {
|
---|
59 | return;
|
---|
60 | }
|
---|
61 | preventRecursion = true;
|
---|
62 | ListSelectionModel referenceModel = (ListSelectionModel) e.getSource();
|
---|
63 | int[] selectedIndices = TableHelper.getSelectedIndices(referenceModel);
|
---|
64 | for (ListSelectionModel model : participants) {
|
---|
65 | if (model == referenceModel) {
|
---|
66 | continue;
|
---|
67 | }
|
---|
68 | TableHelper.setSelectedIndices(model,
|
---|
69 | Arrays.stream(selectedIndices).flatMap(i -> selectionIndexMapper.apply(i, referenceModel)));
|
---|
70 | }
|
---|
71 | preventRecursion = false;
|
---|
72 | }
|
---|
73 | }
|
---|