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

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

PMD - Strict Exceptions

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