source: josm/trunk/src/org/openstreetmap/josm/gui/layer/imagery/TileSourceDisplaySettings.java@ 16488

Last change on this file since 16488 was 16488, checked in by simon04, 4 years ago

fix #19281, see #19174 - Use Objects.hash where it is not used (patch by hiddewie, modified)

  • Property svn:eol-style set to native
File size: 12.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.layer.imagery;
3
4import java.util.HashMap;
5import java.util.Locale;
6import java.util.Map;
7import java.util.Objects;
8import java.util.concurrent.CopyOnWriteArrayList;
9
10import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
11import org.openstreetmap.josm.data.coor.EastNorth;
12import org.openstreetmap.josm.data.imagery.OffsetBookmark;
13import org.openstreetmap.josm.data.preferences.BooleanProperty;
14import org.openstreetmap.josm.data.projection.ProjectionRegistry;
15import org.openstreetmap.josm.gui.layer.AbstractTileSourceLayer;
16import org.openstreetmap.josm.io.session.SessionAwareReadApply;
17import org.openstreetmap.josm.spi.preferences.Config;
18import org.openstreetmap.josm.tools.CheckParameterUtil;
19import org.openstreetmap.josm.tools.JosmRuntimeException;
20import org.openstreetmap.josm.tools.bugreport.BugReport;
21
22/**
23 * This are the preferences of how to display a {@link TileSource}.
24 * <p>
25 * They have been extracted from the {@link AbstractTileSourceLayer}. Each layer has one set of such settings.
26 * @author michael
27 * @since 10568
28 */
29public class TileSourceDisplaySettings implements SessionAwareReadApply {
30 /**
31 * A string returned by {@link DisplaySettingsChangeEvent#getChangedSetting()} if auto load was changed.
32 * @see TileSourceDisplaySettings#isAutoLoad()
33 */
34 public static final String AUTO_LOAD = "automatic-downloading";
35
36 /**
37 * A string returned by {@link DisplaySettingsChangeEvent#getChangedSetting()} if auto zoom was changed.
38 * @see TileSourceDisplaySettings#isAutoZoom()
39 */
40 public static final String AUTO_ZOOM = "automatically-change-resolution";
41
42 /**
43 * A string returned by {@link DisplaySettingsChangeEvent#getChangedSetting()} if the show errors property was changed.
44 * @see TileSourceDisplaySettings#isShowErrors()
45 */
46 private static final String SHOW_ERRORS = "show-errors";
47
48 private static final String DISPLACEMENT = "displacement";
49
50 private static final String PREFERENCE_PREFIX = "imagery.generic";
51
52 /**
53 * The default auto load property
54 */
55 public static final BooleanProperty PROP_AUTO_LOAD = new BooleanProperty(PREFERENCE_PREFIX + ".default_autoload", true);
56
57 /**
58 * The default auto zoom property
59 */
60 public static final BooleanProperty PROP_AUTO_ZOOM = new BooleanProperty(PREFERENCE_PREFIX + ".default_autozoom", true);
61
62
63 /** if layers changes automatically, when user zooms in */
64 private boolean autoZoom;
65 /** if layer automatically loads new tiles */
66 private boolean autoLoad;
67 /** if layer should show errors on tiles */
68 private boolean showErrors;
69
70 private OffsetBookmark previousOffsetBookmark;
71 private OffsetBookmark offsetBookmark;
72 /**
73 * the displacement (basically caches the displacement from the offsetBookmark
74 * in the current projection)
75 */
76 private EastNorth displacement = EastNorth.ZERO;
77
78 private final CopyOnWriteArrayList<DisplaySettingsChangeListener> listeners = new CopyOnWriteArrayList<>();
79
80 /**
81 * Create a new {@link TileSourceDisplaySettings}
82 */
83 public TileSourceDisplaySettings() {
84 this(new String[] {PREFERENCE_PREFIX});
85 }
86
87 /**
88 * Create a new {@link TileSourceDisplaySettings}
89 * @param preferencePrefix The additional prefix to scan for preferences.
90 */
91 public TileSourceDisplaySettings(String preferencePrefix) {
92 this(PREFERENCE_PREFIX, preferencePrefix);
93 }
94
95 private TileSourceDisplaySettings(String... prefixes) {
96 autoZoom = getProperty(prefixes, "default_autozoom", PROP_AUTO_ZOOM.getDefaultValue());
97 autoLoad = getProperty(prefixes, "default_autoload", PROP_AUTO_LOAD.getDefaultValue());
98 showErrors = getProperty(prefixes, "default_showerrors", Boolean.TRUE);
99 }
100
101 private static boolean getProperty(String[] prefixes, String name, Boolean def) {
102 // iterate through all values to force the preferences to receive the default value.
103 // we only support a default value of true.
104 boolean value = true;
105 for (String p : prefixes) {
106 String key = p + "." + name;
107 boolean currentValue = Config.getPref().getBoolean(key, true);
108 if (!Config.getPref().get(key, def.toString()).isEmpty()) {
109 value = currentValue;
110 }
111 }
112 return value;
113 }
114
115 /**
116 * Let the layer zoom automatically if the user zooms in
117 * @return auto zoom
118 */
119 public boolean isAutoZoom() {
120 return autoZoom;
121 }
122
123 /**
124 * Sets the auto zoom property
125 * @param autoZoom {@code true} to let the layer zoom automatically if the user zooms in
126 * @see #isAutoZoom()
127 * @see #AUTO_ZOOM
128 */
129 public void setAutoZoom(boolean autoZoom) {
130 this.autoZoom = autoZoom;
131 fireSettingsChange(AUTO_ZOOM);
132 }
133
134 /**
135 * Gets if the layer should automatically load new tiles.
136 * @return <code>true</code> if it should
137 */
138 public boolean isAutoLoad() {
139 return autoLoad;
140 }
141
142 /**
143 * Sets the auto load property
144 * @param autoLoad {@code true} if the layer should automatically load new tiles
145 * @see #isAutoLoad()
146 * @see #AUTO_LOAD
147 */
148 public void setAutoLoad(boolean autoLoad) {
149 this.autoLoad = autoLoad;
150 fireSettingsChange(AUTO_LOAD);
151 }
152
153 /**
154 * If the layer should display the errors it encountered while loading the tiles.
155 * @return <code>true</code> to show errors.
156 */
157 public boolean isShowErrors() {
158 return showErrors;
159 }
160
161 /**
162 * Sets the show errors property. Fires a change event.
163 * @param showErrors {@code true} if the layer should display the errors it encountered while loading the tiles
164 * @see #isShowErrors()
165 * @see #SHOW_ERRORS
166 */
167 public void setShowErrors(boolean showErrors) {
168 this.showErrors = showErrors;
169 fireSettingsChange(SHOW_ERRORS);
170 }
171
172 /**
173 * Gets the displacement in x (east) direction
174 * @return The displacement.
175 * @see #getDisplacement()
176 * @since 10571
177 */
178 public double getDx() {
179 return getDisplacement().east();
180 }
181
182 /**
183 * Gets the displacement in y (north) direction
184 * @return The displacement.
185 * @see #getDisplacement()
186 * @since 10571
187 */
188 public double getDy() {
189 return getDisplacement().north();
190 }
191
192 /**
193 * Gets the displacement of the image
194 * @return The displacement.
195 * @since 10571
196 */
197 public EastNorth getDisplacement() {
198 return displacement;
199 }
200
201 /**
202 * Gets the displacement of the image formatted as a string
203 * @param locale the locale used to format the decimals
204 * @return the displacement string
205 * @see #getDisplacement()
206 * @since 15733
207 */
208 public String getDisplacementString(final Locale locale) {
209 // Support projections with very small numbers (e.g. 4326)
210 int precision = ProjectionRegistry.getProjection().getDefaultZoomInPPD() >= 1.0 ? 2 : 7;
211 return String.format(locale, "%1." + precision + "f; %1." + precision + "f", getDx(), getDy());
212 }
213
214 /**
215 * Sets an offset bookmark to use. Loads the displacement from the bookmark.
216 *
217 * @param offsetBookmark the offset bookmark, may be null
218 */
219 public void setOffsetBookmark(OffsetBookmark offsetBookmark) {
220 if (this.offsetBookmark != null) {
221 this.previousOffsetBookmark = this.offsetBookmark;
222 }
223 this.offsetBookmark = offsetBookmark;
224 if (offsetBookmark == null) {
225 setDisplacement(EastNorth.ZERO);
226 } else {
227 setDisplacement(offsetBookmark.getDisplacement(ProjectionRegistry.getProjection()));
228 }
229 }
230
231 /**
232 * Gets the offset bookmark in use.
233 * @return the offset bookmark, may be null
234 */
235 public OffsetBookmark getOffsetBookmark() {
236 return this.offsetBookmark;
237 }
238
239 /**
240 * Gets the offset bookmark previously in use.
241 * @return the previously used offset bookmark, may be null
242 */
243 public OffsetBookmark getPreviousOffsetBookmark() {
244 return previousOffsetBookmark;
245 }
246
247 private void setDisplacement(EastNorth displacement) {
248 CheckParameterUtil.ensureThat(displacement.isValid(), () -> displacement + " invalid");
249 this.displacement = displacement;
250 fireSettingsChange(DISPLACEMENT);
251 }
252
253 /**
254 * Notifies all listeners that the paint settings have changed
255 * @param changedSetting The setting name
256 */
257 private void fireSettingsChange(String changedSetting) {
258 DisplaySettingsChangeEvent e = new DisplaySettingsChangeEvent(changedSetting);
259 for (DisplaySettingsChangeListener l : listeners) {
260 l.displaySettingsChanged(e);
261 }
262 }
263
264 /**
265 * Add a listener that listens to display settings changes.
266 * @param l The listener
267 */
268 public void addSettingsChangeListener(DisplaySettingsChangeListener l) {
269 listeners.add(l);
270 }
271
272 /**
273 * Remove a listener that listens to display settings changes.
274 * @param l The listener
275 */
276 public void removeSettingsChangeListener(DisplaySettingsChangeListener l) {
277 listeners.remove(l);
278 }
279
280 /**
281 * Stores the current settings object to the given hashmap.
282 * The offset data is not stored and needs to be handled separately.
283 * @see #applyFromPropertiesMap(Map)
284 * @see OffsetBookmark#toPropertiesMap()
285 */
286 @Override
287 public Map<String, String> toPropertiesMap() {
288 Map<String, String> data = new HashMap<>();
289 data.put(AUTO_LOAD, Boolean.toString(autoLoad));
290 data.put(AUTO_ZOOM, Boolean.toString(autoZoom));
291 data.put(SHOW_ERRORS, Boolean.toString(showErrors));
292 return data;
293 }
294
295 /**
296 * Load the settings from the given data instance.
297 * The offset data is not loaded and needs to be handled separately.
298 * @param data The data
299 * @see #toPropertiesMap()
300 * @see OffsetBookmark#fromPropertiesMap(java.util.Map)
301 */
302 @Override
303 public void applyFromPropertiesMap(Map<String, String> data) {
304 try {
305 String doAutoLoad = data.get(AUTO_LOAD);
306 if (doAutoLoad != null) {
307 setAutoLoad(Boolean.parseBoolean(doAutoLoad));
308 }
309
310 String doAutoZoom = data.get(AUTO_ZOOM);
311 if (doAutoZoom != null) {
312 setAutoZoom(Boolean.parseBoolean(doAutoZoom));
313 }
314
315 String doShowErrors = data.get(SHOW_ERRORS);
316 if (doShowErrors != null) {
317 setShowErrors(Boolean.parseBoolean(doShowErrors));
318 }
319 } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) {
320 throw BugReport.intercept(e).put("data", data);
321 }
322 }
323
324 @Override
325 public int hashCode() {
326 return Objects.hash(autoLoad, autoZoom, showErrors);
327 }
328
329 @Override
330 public boolean equals(Object obj) {
331 if (this == obj)
332 return true;
333 if (obj == null || getClass() != obj.getClass())
334 return false;
335 TileSourceDisplaySettings other = (TileSourceDisplaySettings) obj;
336 return autoLoad == other.autoLoad
337 && autoZoom == other.autoZoom
338 && showErrors == other.showErrors;
339 }
340
341 @Override
342 public String toString() {
343 return "TileSourceDisplaySettings [autoZoom=" + autoZoom + ", autoLoad=" + autoLoad + ", showErrors="
344 + showErrors + ']';
345 }
346
347 /**
348 * A listener that listens to changes to the {@link TileSourceDisplaySettings} object.
349 * @author Michael Zangl
350 * @since 10600 (functional interface)
351 */
352 @FunctionalInterface
353 public interface DisplaySettingsChangeListener {
354 /**
355 * Called whenever the display settings have changed.
356 * @param e The change event.
357 */
358 void displaySettingsChanged(DisplaySettingsChangeEvent e);
359 }
360
361 /**
362 * An event that is created whenever the display settings change.
363 * @author Michael Zangl
364 */
365 public static final class DisplaySettingsChangeEvent {
366 private final String changedSetting;
367
368 DisplaySettingsChangeEvent(String changedSetting) {
369 this.changedSetting = changedSetting;
370 }
371
372 /**
373 * Gets the setting that was changed
374 * @return The name of the changed setting.
375 */
376 public String getChangedSetting() {
377 return changedSetting;
378 }
379
380 @Override
381 public String toString() {
382 return "DisplaySettingsChangeEvent [changedSetting=" + changedSetting + ']';
383 }
384 }
385}
Note: See TracBrowser for help on using the repository browser.