source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetListModel.java@ 14344

Last change on this file since 14344 was 14344, checked in by Don-vip, 6 years ago

fix #6524, fix #11240 - add synchronization in ChangesetListModel

  • Property svn:eol-style set to native
File size: 7.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs.changeset;
3
4import java.util.ArrayList;
5import java.util.Collection;
6import java.util.Comparator;
7import java.util.HashSet;
8import java.util.List;
9import java.util.Set;
10
11import javax.swing.DefaultListModel;
12import javax.swing.DefaultListSelectionModel;
13
14import org.openstreetmap.josm.data.osm.Changeset;
15import org.openstreetmap.josm.data.osm.ChangesetCache;
16import org.openstreetmap.josm.data.osm.ChangesetCacheEvent;
17import org.openstreetmap.josm.data.osm.ChangesetCacheListener;
18import org.openstreetmap.josm.data.osm.DataSet;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.Storage;
21import org.openstreetmap.josm.gui.util.GuiHelper;
22
23/**
24 * This is the model that backs a list of changesets
25 */
26public class ChangesetListModel extends DefaultListModel<Changeset> implements ChangesetCacheListener {
27 private final transient List<Changeset> data = new ArrayList<>();
28 private final transient Storage<Changeset> shownChangesets = new Storage<>(true);
29 private final DefaultListSelectionModel selectionModel;
30
31 /**
32 * Creates a new {@link ChangesetListModel}
33 * @param selectionModel The selection model to use for this list
34 */
35 public ChangesetListModel(DefaultListSelectionModel selectionModel) {
36 this.selectionModel = selectionModel;
37 }
38
39 /**
40 * Gets the list of changesets that are currently selected
41 * @return The selected changesets
42 */
43 public synchronized Set<Changeset> getSelectedChangesets() {
44 Set<Changeset> ret = new HashSet<>();
45 for (int i = 0; i < getSize(); i++) {
46 if (selectionModel.isSelectedIndex(i)) {
47 ret.add(data.get(i));
48 }
49 }
50 return ret;
51 }
52
53 /**
54 * Gets the IDs of the changesets that are selected
55 * @return The selected ids
56 */
57 public synchronized Set<Integer> getSelectedChangesetIds() {
58 Set<Integer> ret = new HashSet<>();
59 for (int i = 0; i < getSize(); i++) {
60 if (selectionModel.isSelectedIndex(i)) {
61 ret.add(data.get(i).getId());
62 }
63 }
64 return ret;
65 }
66
67 /**
68 * Sets the changesets to select
69 * @param changesets The changesets
70 */
71 public synchronized void setSelectedChangesets(Collection<Changeset> changesets) {
72 selectionModel.setValueIsAdjusting(true);
73 selectionModel.clearSelection();
74 if (changesets != null) {
75 for (Changeset cs: changesets) {
76 int idx = data.indexOf(cs);
77 if (idx >= 0) {
78 selectionModel.addSelectionInterval(idx, idx);
79 }
80 }
81 }
82 selectionModel.setValueIsAdjusting(false);
83 }
84
85 protected void setChangesets(Collection<Changeset> changesets) {
86 shownChangesets.clear();
87 if (changesets != null) {
88 shownChangesets.addAll(changesets);
89 }
90 updateModel();
91 }
92
93 private synchronized void updateModel() {
94 Set<Changeset> sel = getSelectedChangesets();
95 data.clear();
96 data.addAll(shownChangesets);
97 ChangesetCache cache = ChangesetCache.getInstance();
98 for (Changeset cs: data) {
99 if (cache.contains(cs) && cache.get(cs.getId()) != cs) {
100 cs.mergeFrom(cache.get(cs.getId()));
101 }
102 }
103 sort();
104 fireIntervalAdded(this, 0, getSize());
105 setSelectedChangesets(sel);
106 }
107
108 /**
109 * Loads this list with the given changesets
110 * @param ids The ids of the changesets to display
111 */
112 public void initFromChangesetIds(Collection<Integer> ids) {
113 if (ids == null || ids.isEmpty()) {
114 setChangesets(null);
115 return;
116 }
117 Set<Changeset> changesets = new HashSet<>(ids.size());
118 for (int id: ids) {
119 if (id <= 0) {
120 continue;
121 }
122 changesets.add(new Changeset(id));
123 }
124 setChangesets(changesets);
125 }
126
127 /**
128 * Loads this list with the given changesets
129 * @param primitives The primitives of which the changesets should be displayed
130 */
131 public void initFromPrimitives(Collection<? extends OsmPrimitive> primitives) {
132 if (primitives == null) {
133 setChangesets(null);
134 return;
135 }
136 Set<Changeset> changesets = new HashSet<>();
137 for (OsmPrimitive p: primitives) {
138 if (p.getChangesetId() <= 0) {
139 continue;
140 }
141 changesets.add(new Changeset(p.getChangesetId()));
142 }
143 setChangesets(changesets);
144 }
145
146 /**
147 * Loads this list with the given changesets
148 * @param ds The data set to get all changesets from
149 */
150 public void initFromDataSet(DataSet ds) {
151 if (ds == null) {
152 setChangesets(null);
153 return;
154 }
155 Set<Changeset> changesets = new HashSet<>();
156 for (OsmPrimitive p: ds.allPrimitives()) {
157 if (p.getChangesetId() <= 0) {
158 continue;
159 }
160 changesets.add(new Changeset(p.getChangesetId()));
161 }
162 setChangesets(changesets);
163 }
164
165 @Override
166 public synchronized Changeset getElementAt(int idx) {
167 return data.get(idx);
168 }
169
170 @Override
171 public synchronized int getSize() {
172 return data.size();
173 }
174
175 protected synchronized void sort() {
176 data.sort(Comparator.comparingInt(Changeset::getId).reversed());
177 }
178
179 /**
180 * Replies true if there is at least one selected open changeset
181 *
182 * @return true if there is at least one selected open changeset
183 */
184 public boolean hasSelectedOpenChangesets() {
185 return !getSelectedOpenChangesets().isEmpty();
186 }
187
188 /**
189 * Replies the selected open changesets
190 *
191 * @return the selected open changesets
192 */
193 public synchronized List<Changeset> getSelectedOpenChangesets() {
194 List<Changeset> ret = new ArrayList<>();
195 for (int i = 0; i < getSize(); i++) {
196 if (selectionModel.isSelectedIndex(i)) {
197 Changeset cs = data.get(i);
198 if (cs.isOpen()) {
199 ret.add(cs);
200 }
201 }
202 }
203 return ret;
204 }
205
206 /* ---------------------------------------------------------------------------- */
207 /* Interface ChangesetCacheListener */
208 /* ---------------------------------------------------------------------------- */
209 @Override
210 public synchronized void changesetCacheUpdated(ChangesetCacheEvent event) {
211 Set<Changeset> sel = getSelectedChangesets();
212 for (Changeset cs: event.getAddedChangesets()) {
213 int idx = data.indexOf(cs);
214 if (idx >= 0 && data.get(idx) != cs) {
215 data.get(idx).mergeFrom(cs);
216 }
217 }
218 for (Changeset cs: event.getUpdatedChangesets()) {
219 int idx = data.indexOf(cs);
220 if (idx >= 0 && data.get(idx) != cs) {
221 data.get(idx).mergeFrom(cs);
222 }
223 }
224 for (Changeset cs: event.getRemovedChangesets()) {
225 int idx = data.indexOf(cs);
226 if (idx >= 0) {
227 // replace with an incomplete changeset
228 data.set(idx, new Changeset(cs.getId()));
229 }
230 }
231 GuiHelper.runInEDT(() -> {
232 fireContentsChanged(this, 0, getSize());
233 setSelectedChangesets(sel);
234 });
235 }
236}
Note: See TracBrowser for help on using the repository browser.