source: josm/trunk/src/org/openstreetmap/josm/data/osm/history/HistoryDataSet.java@ 16123

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

fix #18918 - Enable Ctrl-H shortcut to display history of primitives selected in changeset manager

  • Property svn:eol-style set to native
File size: 8.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm.history;
3
4import java.text.MessageFormat;
5import java.util.ArrayList;
6import java.util.Collection;
7import java.util.HashMap;
8import java.util.HashSet;
9import java.util.List;
10import java.util.Map;
11import java.util.Objects;
12import java.util.Set;
13import java.util.concurrent.CopyOnWriteArrayList;
14
15import org.openstreetmap.josm.data.osm.Changeset;
16import org.openstreetmap.josm.data.osm.IPrimitive;
17import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
18import org.openstreetmap.josm.data.osm.PrimitiveId;
19import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
20import org.openstreetmap.josm.gui.MainApplication;
21import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
22import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
23import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
24import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
25import org.openstreetmap.josm.tools.CheckParameterUtil;
26
27/**
28 * A data set holding histories of OSM primitives.
29 * @since 1670
30 * @since 10386 (new LayerChangeListener interface)
31 */
32public class HistoryDataSet implements LayerChangeListener {
33 /** the unique instance */
34 private static HistoryDataSet historyDataSet;
35
36 /**
37 * Replies the unique instance of the history data set
38 *
39 * @return the unique instance of the history data set
40 */
41 public static synchronized HistoryDataSet getInstance() {
42 if (historyDataSet == null) {
43 historyDataSet = new HistoryDataSet();
44 MainApplication.getLayerManager().addLayerChangeListener(historyDataSet);
45 }
46 return historyDataSet;
47 }
48
49 /** the history data */
50 private final Map<PrimitiveId, ArrayList<HistoryOsmPrimitive>> data;
51 private final CopyOnWriteArrayList<HistoryDataSetListener> listeners;
52 private final Map<Long, Changeset> changesets;
53
54 /**
55 * Constructs a new {@code HistoryDataSet}.
56 */
57 public HistoryDataSet() {
58 data = new HashMap<>();
59 listeners = new CopyOnWriteArrayList<>();
60 changesets = new HashMap<>();
61 }
62
63 /**
64 * Adds a listener that listens to history data set events.
65 * @param listener The listener
66 */
67 public void addHistoryDataSetListener(HistoryDataSetListener listener) {
68 if (listener != null) {
69 listeners.addIfAbsent(listener);
70 }
71 }
72
73 /**
74 * Removes a listener that listens to history data set events.
75 * @param listener The listener
76 */
77 public void removeHistoryDataSetListener(HistoryDataSetListener listener) {
78 listeners.remove(listener);
79 }
80
81 protected void fireHistoryUpdated(PrimitiveId id) {
82 for (HistoryDataSetListener l : listeners) {
83 l.historyUpdated(this, id);
84 }
85 }
86
87 protected void fireCacheCleared() {
88 for (HistoryDataSetListener l : listeners) {
89 l.historyDataSetCleared(this);
90 }
91 }
92
93 /**
94 * Replies the history primitive for the primitive with id <code>id</code>
95 * and version <code>version</code>. null, if no such primitive exists.
96 *
97 * @param id the id of the primitive. &gt; 0 required.
98 * @param type the primitive type. Must not be null.
99 * @param version the version of the primitive. &gt; 0 required
100 * @return the history primitive for the primitive with id <code>id</code>,
101 * type <code>type</code>, and version <code>version</code>
102 */
103 public HistoryOsmPrimitive get(long id, OsmPrimitiveType type, long version) {
104 if (id <= 0)
105 throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0 expected, got {1}", "id", id));
106 CheckParameterUtil.ensureParameterNotNull(type, "type");
107 if (version <= 0)
108 throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0 expected, got {1}", "version", version));
109
110 SimplePrimitiveId pid = new SimplePrimitiveId(id, type);
111 List<HistoryOsmPrimitive> versions = data.get(pid);
112 if (versions == null)
113 return null;
114 for (HistoryOsmPrimitive primitive: versions) {
115 if (primitive.matches(id, version))
116 return primitive;
117 }
118 return null;
119 }
120
121 /**
122 * Adds a history primitive to the data set
123 *
124 * @param primitive the history primitive to add
125 */
126 public void put(HistoryOsmPrimitive primitive) {
127 PrimitiveId id = new SimplePrimitiveId(primitive.getId(), primitive.getType());
128 data.computeIfAbsent(id, k-> new ArrayList<>()).add(primitive);
129 fireHistoryUpdated(id);
130 }
131
132 /**
133 * Adds a changeset to the data set
134 *
135 * @param changeset the changeset to add
136 */
137 public void putChangeset(Changeset changeset) {
138 changesets.put((long) changeset.getId(), changeset);
139 fireHistoryUpdated(null);
140 }
141
142 /**
143 * Replies the history for a given primitive with id <code>id</code>
144 * and type <code>type</code>.
145 *
146 * @param id the id the if of the primitive. &gt; 0 required
147 * @param type the type of the primitive. Must not be null.
148 * @return the history. null, if there isn't a history for <code>id</code> and
149 * <code>type</code>.
150 * @throws IllegalArgumentException if id &lt;= 0
151 * @throws IllegalArgumentException if type is null
152 */
153 public History getHistory(long id, OsmPrimitiveType type) {
154 if (id <= 0)
155 throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0 expected, got {1}", "id", id));
156 CheckParameterUtil.ensureParameterNotNull(type, "type");
157 SimplePrimitiveId pid = new SimplePrimitiveId(id, type);
158 return getHistory(pid);
159 }
160
161 /**
162 * Replies the history for a primitive with id <code>id</code>. null, if no
163 * such history exists.
164 *
165 * @param pid the primitive id. Must not be null.
166 * @return the history for a primitive with id <code>id</code>. null, if no
167 * such history exists
168 * @throws NullPointerException if pid is null
169 */
170 public History getHistory(PrimitiveId pid) {
171 PrimitiveId key = pid instanceof IPrimitive ? ((IPrimitive) pid).getPrimitiveId()
172 : pid instanceof HistoryOsmPrimitive ? ((HistoryOsmPrimitive) pid).getPrimitiveId()
173 : pid;
174 List<HistoryOsmPrimitive> versions = data.get(Objects.requireNonNull(key, "key"));
175 if (versions == null)
176 return null;
177 for (HistoryOsmPrimitive i : versions) {
178 i.setChangeset(changesets.get(i.getChangesetId()));
179 }
180 return new History(pid.getUniqueId(), pid.getType(), versions);
181 }
182
183 /**
184 * merges the histories from the {@link HistoryDataSet} other in this history data set
185 *
186 * @param other the other history data set. Ignored if null.
187 */
188 public void mergeInto(HistoryDataSet other) {
189 if (other == null)
190 return;
191 this.data.putAll(other.data);
192 this.changesets.putAll(other.changesets);
193 fireHistoryUpdated(null);
194 }
195
196 /**
197 * Gets a unsorted set of all changeset ids that were used by the primitives in this data set
198 * @return The ids
199 */
200 public Collection<Long> getChangesetIds() {
201 final Set<Long> ids = new HashSet<>();
202 for (Collection<HistoryOsmPrimitive> i : data.values()) {
203 for (HistoryOsmPrimitive j : i) {
204 ids.add(j.getChangesetId());
205 }
206 }
207 return ids;
208 }
209
210 /* ------------------------------------------------------------------------------ */
211 /* interface LayerChangeListener */
212 /* ------------------------------------------------------------------------------ */
213 @Override
214 public void layerOrderChanged(LayerOrderChangeEvent e) {
215 /* irrelevant in this context */
216 }
217
218 @Override
219 public void layerAdded(LayerAddEvent e) {
220 /* irrelevant in this context */
221 }
222
223 @Override
224 public void layerRemoving(LayerRemoveEvent e) {
225 if (!MainApplication.isDisplayingMapView()) return;
226 if (MainApplication.getLayerManager().getLayers().isEmpty()) {
227 data.clear();
228 fireCacheCleared();
229 }
230 }
231}
Note: See TracBrowser for help on using the repository browser.