source: josm/trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialogManager.java@ 11519

Last change on this file since 11519 was 11461, checked in by Don-vip, 7 years ago

sonar - fb-contrib:SPP_USE_CONTAINSKEY - Style - Method calls keySet() just to call contains, use containsKey instead

  • Property svn:eol-style set to native
File size: 7.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.history;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Dimension;
7import java.awt.Point;
8import java.util.ArrayList;
9import java.util.Collection;
10import java.util.HashMap;
11import java.util.Iterator;
12import java.util.List;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Objects;
16import java.util.function.Predicate;
17
18import javax.swing.JOptionPane;
19import javax.swing.SwingUtilities;
20
21import org.openstreetmap.josm.Main;
22import org.openstreetmap.josm.data.osm.PrimitiveId;
23import org.openstreetmap.josm.data.osm.history.History;
24import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
25import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
26import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
27import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
28import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
29import org.openstreetmap.josm.tools.SubclassFilteredCollection;
30import org.openstreetmap.josm.tools.WindowGeometry;
31import org.openstreetmap.josm.tools.bugreport.BugReportExceptionHandler;
32
33/**
34 * Manager allowing to show/hide history dialogs.
35 * @since 2019
36 */
37public final class HistoryBrowserDialogManager implements LayerChangeListener {
38
39 static final class UnloadedHistoryPredicate implements Predicate<PrimitiveId> {
40 private final HistoryDataSet hds = HistoryDataSet.getInstance();
41
42 @Override
43 public boolean test(PrimitiveId p) {
44 History h = hds.getHistory(p);
45 if (h == null)
46 // reload if the history is not in the cache yet
47 return true;
48 else
49 // reload if the history object of the selected object is not in the cache yet
50 return !p.isNew() && h.getByVersion(p.getUniqueId()) == null;
51 }
52 }
53
54 private static final String WINDOW_GEOMETRY_PREF = HistoryBrowserDialogManager.class.getName() + ".geometry";
55
56 private static HistoryBrowserDialogManager instance;
57
58 private final Map<Long, HistoryBrowserDialog> dialogs;
59
60 private final Predicate<PrimitiveId> unloadedHistoryPredicate = new UnloadedHistoryPredicate();
61
62 private final Predicate<PrimitiveId> notNewPredicate = p -> !p.isNew();
63
64 protected HistoryBrowserDialogManager() {
65 dialogs = new HashMap<>();
66 Main.getLayerManager().addLayerChangeListener(this);
67 }
68
69 /**
70 * Replies the unique instance.
71 * @return the unique instance
72 */
73 public static synchronized HistoryBrowserDialogManager getInstance() {
74 if (instance == null) {
75 instance = new HistoryBrowserDialogManager();
76 }
77 return instance;
78 }
79
80 /**
81 * Determines if an history dialog exists for the given object id.
82 * @param id the object id
83 * @return {@code true} if an history dialog exists for the given object id, {@code false} otherwise
84 */
85 public boolean existsDialog(long id) {
86 return dialogs.containsKey(id);
87 }
88
89 private void show(long id, HistoryBrowserDialog dialog) {
90 if (dialogs.containsValue(dialog)) {
91 show(id);
92 } else {
93 placeOnScreen(dialog);
94 dialog.setVisible(true);
95 dialogs.put(id, dialog);
96 }
97 }
98
99 private void show(long id) {
100 if (dialogs.containsKey(id)) {
101 dialogs.get(id).toFront();
102 }
103 }
104
105 private boolean hasDialogWithCloseUpperLeftCorner(Point p) {
106 for (HistoryBrowserDialog dialog: dialogs.values()) {
107 Point corner = dialog.getLocation();
108 if (p.x >= corner.x -5 && corner.x + 5 >= p.x
109 && p.y >= corner.y -5 && corner.y + 5 >= p.y)
110 return true;
111 }
112 return false;
113 }
114
115 private void placeOnScreen(HistoryBrowserDialog dialog) {
116 WindowGeometry geometry = new WindowGeometry(WINDOW_GEOMETRY_PREF, WindowGeometry.centerOnScreen(new Dimension(850, 500)));
117 geometry.applySafe(dialog);
118 Point p = dialog.getLocation();
119 while (hasDialogWithCloseUpperLeftCorner(p)) {
120 p.x += 20;
121 p.y += 20;
122 }
123 dialog.setLocation(p);
124 }
125
126 /**
127 * Hides the specified history dialog and cleans associated resources.
128 * @param dialog History dialog to hide
129 */
130 public void hide(HistoryBrowserDialog dialog) {
131 for (Iterator<Entry<Long, HistoryBrowserDialog>> it = dialogs.entrySet().iterator(); it.hasNext();) {
132 if (Objects.equals(it.next().getValue(), dialog)) {
133 it.remove();
134 if (dialogs.isEmpty()) {
135 new WindowGeometry(dialog).remember(WINDOW_GEOMETRY_PREF);
136 }
137 break;
138 }
139 }
140 dialog.setVisible(false);
141 dialog.dispose();
142 }
143
144 /**
145 * Hides and destroys all currently visible history browser dialogs
146 *
147 */
148 public void hideAll() {
149 List<HistoryBrowserDialog> dialogs = new ArrayList<>();
150 dialogs.addAll(this.dialogs.values());
151 for (HistoryBrowserDialog dialog: dialogs) {
152 dialog.unlinkAsListener();
153 hide(dialog);
154 }
155 }
156
157 /**
158 * Show history dialog for the given history.
159 * @param h History to show
160 */
161 public void show(History h) {
162 if (h == null)
163 return;
164 if (existsDialog(h.getId())) {
165 show(h.getId());
166 } else {
167 HistoryBrowserDialog dialog = new HistoryBrowserDialog(h);
168 show(h.getId(), dialog);
169 }
170 }
171
172 /* ----------------------------------------------------------------------------- */
173 /* LayerChangeListener */
174 /* ----------------------------------------------------------------------------- */
175 @Override
176 public void layerAdded(LayerAddEvent e) {
177 // Do nothing
178 }
179
180 @Override
181 public void layerRemoving(LayerRemoveEvent e) {
182 // remove all history browsers if the number of layers drops to 0
183 if (e.getSource().getLayers().isEmpty()) {
184 hideAll();
185 }
186 }
187
188 @Override
189 public void layerOrderChanged(LayerOrderChangeEvent e) {
190 // Do nothing
191 }
192
193 /**
194 * Show history dialog(s) for the given primitive(s).
195 * @param primitives The primitive(s) for which history will be displayed
196 */
197 public void showHistory(final Collection<? extends PrimitiveId> primitives) {
198 final Collection<? extends PrimitiveId> notNewPrimitives = SubclassFilteredCollection.filter(primitives, notNewPredicate);
199 if (notNewPrimitives.isEmpty()) {
200 JOptionPane.showMessageDialog(
201 Main.parent,
202 tr("Please select at least one already uploaded node, way, or relation."),
203 tr("Warning"),
204 JOptionPane.WARNING_MESSAGE);
205 return;
206 }
207
208 Collection<? extends PrimitiveId> toLoad = SubclassFilteredCollection.filter(primitives, unloadedHistoryPredicate);
209 if (!toLoad.isEmpty()) {
210 HistoryLoadTask task = new HistoryLoadTask();
211 for (PrimitiveId p : notNewPrimitives) {
212 task.add(p);
213 }
214 Main.worker.submit(task);
215 }
216
217 Runnable r = () -> {
218 try {
219 for (PrimitiveId p : notNewPrimitives) {
220 final History h = HistoryDataSet.getInstance().getHistory(p);
221 if (h == null) {
222 continue;
223 }
224 SwingUtilities.invokeLater(() -> show(h));
225 }
226 } catch (final RuntimeException e) {
227 BugReportExceptionHandler.handleException(e);
228 }
229 };
230 Main.worker.submit(r);
231 }
232}
Note: See TracBrowser for help on using the repository browser.