source: josm/trunk/src/org/openstreetmap/josm/gui/download/BookmarkList.java@ 12606

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

fix #15148 - increase home location zoom level to 15 to allow direct download in urban areas

  • Property svn:eol-style set to native
File size: 14.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.download;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.awt.GraphicsEnvironment;
8import java.util.ArrayList;
9import java.util.Arrays;
10import java.util.Collection;
11import java.util.Collections;
12import java.util.Comparator;
13import java.util.LinkedList;
14import java.util.List;
15import java.util.Locale;
16import java.util.Objects;
17
18import javax.swing.DefaultListModel;
19import javax.swing.ImageIcon;
20import javax.swing.JLabel;
21import javax.swing.JList;
22import javax.swing.ListCellRenderer;
23import javax.swing.UIManager;
24
25import org.openstreetmap.josm.Main;
26import org.openstreetmap.josm.actions.downloadtasks.ChangesetQueryTask;
27import org.openstreetmap.josm.data.Bounds;
28import org.openstreetmap.josm.data.coor.LatLon;
29import org.openstreetmap.josm.data.osm.Changeset;
30import org.openstreetmap.josm.data.osm.UserInfo;
31import org.openstreetmap.josm.data.preferences.IntegerProperty;
32import org.openstreetmap.josm.data.projection.Projection;
33import org.openstreetmap.josm.data.projection.Projections;
34import org.openstreetmap.josm.gui.JosmUserIdentityManager;
35import org.openstreetmap.josm.gui.MapViewState;
36import org.openstreetmap.josm.gui.dialogs.changeset.ChangesetCacheManager;
37import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
38import org.openstreetmap.josm.gui.util.GuiHelper;
39import org.openstreetmap.josm.io.ChangesetQuery;
40import org.openstreetmap.josm.tools.ImageProvider;
41import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
42
43/**
44 * List class that read and save its content from the bookmark file.
45 * @since 6340
46 */
47public class BookmarkList extends JList<BookmarkList.Bookmark> {
48
49 /**
50 * The maximum number of changeset bookmarks to maintain in list.
51 * @since 12495
52 */
53 public static final IntegerProperty MAX_CHANGESET_BOOKMARKS = new IntegerProperty("bookmarks.changesets.max-entries", 15);
54
55 /**
56 * Class holding one bookmarkentry.
57 */
58 public static class Bookmark implements Comparable<Bookmark> {
59 private String name;
60 private Bounds area;
61 private ImageIcon icon;
62
63 /**
64 * Constructs a new {@code Bookmark} with the given contents.
65 * @param list Bookmark contents as a list of 5 elements.
66 * First item is the name, then come bounds arguments (minlat, minlon, maxlat, maxlon)
67 * @throws NumberFormatException if the bounds arguments are not numbers
68 * @throws IllegalArgumentException if list contain less than 5 elements
69 */
70 public Bookmark(Collection<String> list) {
71 List<String> array = new ArrayList<>(list);
72 if (array.size() < 5)
73 throw new IllegalArgumentException(tr("Wrong number of arguments for bookmark"));
74 icon = ImageProvider.get("dialogs", "bookmark");
75 name = array.get(0);
76 area = new Bounds(Double.parseDouble(array.get(1)), Double.parseDouble(array.get(2)),
77 Double.parseDouble(array.get(3)), Double.parseDouble(array.get(4)));
78 }
79
80 /**
81 * Constructs a new empty {@code Bookmark}.
82 */
83 public Bookmark() {
84 this(null, null);
85 }
86
87 /**
88 * Constructs a new unamed {@code Bookmark} for the given area.
89 * @param area The bookmark area
90 */
91 public Bookmark(Bounds area) {
92 this(null, area);
93 }
94
95 /**
96 * Constructs a new {@code Bookmark} for the given name and area.
97 * @param name The bookmark name
98 * @param area The bookmark area
99 * @since 12495
100 */
101 protected Bookmark(String name, Bounds area) {
102 this.icon = ImageProvider.get("dialogs", "bookmark");
103 this.name = name;
104 this.area = area;
105 }
106
107 @Override
108 public String toString() {
109 return name;
110 }
111
112 @Override
113 public int compareTo(Bookmark b) {
114 return name.toLowerCase(Locale.ENGLISH).compareTo(b.name.toLowerCase(Locale.ENGLISH));
115 }
116
117 @Override
118 public int hashCode() {
119 return Objects.hash(name, area);
120 }
121
122 @Override
123 public boolean equals(Object obj) {
124 if (this == obj) return true;
125 if (obj == null || getClass() != obj.getClass()) return false;
126 Bookmark bookmark = (Bookmark) obj;
127 return Objects.equals(name, bookmark.name) &&
128 Objects.equals(area, bookmark.area);
129 }
130
131 /**
132 * Returns the bookmark area
133 * @return The bookmark area
134 */
135 public Bounds getArea() {
136 return area;
137 }
138
139 /**
140 * Returns the bookmark name
141 * @return The bookmark name
142 */
143 public String getName() {
144 return name;
145 }
146
147 /**
148 * Sets the bookmark name
149 * @param name The bookmark name
150 */
151 public void setName(String name) {
152 this.name = name;
153 }
154
155 /**
156 * Sets the bookmark area
157 * @param area The bookmark area
158 */
159 public void setArea(Bounds area) {
160 this.area = area;
161 }
162
163 /**
164 * Returns the bookmark icon.
165 * @return the bookmark icon
166 * @since 12495
167 */
168 public ImageIcon getIcon() {
169 return icon;
170 }
171
172 /**
173 * Sets the bookmark icon.
174 * @param icon the bookmark icon
175 * @since 12495
176 */
177 public void setIcon(ImageIcon icon) {
178 this.icon = icon;
179 }
180 }
181
182 /**
183 * A specific optional bookmark for the "home location" configured on osm.org website.
184 * @since 12495
185 */
186 public static class HomeLocationBookmark extends Bookmark {
187 /**
188 * Constructs a new {@code HomeLocationBookmark}.
189 */
190 public HomeLocationBookmark() {
191 setName(tr("Home location"));
192 setIcon(ImageProvider.get("help", "home", ImageSizes.SMALLICON));
193 UserInfo info = JosmUserIdentityManager.getInstance().getUserInfo();
194 if (info == null) {
195 throw new IllegalStateException("User not identified");
196 }
197 LatLon home = info.getHome();
198 if (home == null) {
199 throw new IllegalStateException("User home location not set");
200 }
201 int zoom = info.getHomeZoom();
202 if (zoom <= 3) {
203 // 3 is the default zoom level in OSM database, but the real zoom level was not correct
204 // for a long time, see https://github.com/openstreetmap/openstreetmap-website/issues/1592
205 zoom = 15;
206 }
207 Projection mercator = Projections.getProjectionByCode("EPSG:3857");
208 setArea(MapViewState.createDefaultState(430, 400) // Size of map on osm.org user profile settings
209 .usingProjection(mercator)
210 .usingScale(Selector.GeneralSelector.level2scale(zoom) / 100)
211 .usingCenter(mercator.latlon2eastNorth(home))
212 .getViewArea()
213 .getLatLonBoundsBox());
214 }
215 }
216
217 /**
218 * A specific optional bookmark for the boundaries of recent changesets.
219 * @since 12495
220 */
221 public static class ChangesetBookmark extends Bookmark {
222 /**
223 * Constructs a new {@code ChangesetBookmark}.
224 * @param cs changeset from which the boundaries are read. Its id, name and comment are used to name the bookmark
225 */
226 public ChangesetBookmark(Changeset cs) {
227 setName(String.format("%d - %tF - %s", cs.getId(), cs.getCreatedAt(), cs.getComment()));
228 setIcon(ImageProvider.get("data", "changeset", ImageSizes.SMALLICON));
229 setArea(cs.getBounds());
230 }
231 }
232
233 /**
234 * Creates a bookmark list as well as the Buttons add and remove.
235 */
236 public BookmarkList() {
237 setModel(new DefaultListModel<Bookmark>());
238 load();
239 setVisibleRowCount(7);
240 setCellRenderer(new BookmarkCellRenderer());
241 }
242
243 /**
244 * Loads the home location bookmark from OSM API,
245 * the manual bookmarks from preferences file,
246 * the changeset bookmarks from changeset cache.
247 */
248 public final void load() {
249 final DefaultListModel<Bookmark> model = (DefaultListModel<Bookmark>) getModel();
250 model.removeAllElements();
251 JosmUserIdentityManager im = JosmUserIdentityManager.getInstance();
252 // Add home location bookmark first, if user fully identified
253 if (im.isFullyIdentified()) {
254 try {
255 model.addElement(new HomeLocationBookmark());
256 } catch (IllegalStateException e) {
257 Main.info(e.getMessage());
258 Main.trace(e);
259 }
260 }
261 // Then add manual bookmarks previously saved in local preferences
262 Collection<Collection<String>> args = Main.pref.getArray("bookmarks", null);
263 if (args != null) {
264 List<Bookmark> bookmarks = new LinkedList<>();
265 for (Collection<String> entry : args) {
266 try {
267 bookmarks.add(new Bookmark(entry));
268 } catch (IllegalArgumentException e) {
269 Main.error(e, tr("Error reading bookmark entry: %s", e.getMessage()));
270 }
271 }
272 Collections.sort(bookmarks);
273 for (Bookmark b : bookmarks) {
274 model.addElement(b);
275 }
276 }
277 // Finally add recent changeset bookmarks, if user name is known
278 final int n = MAX_CHANGESET_BOOKMARKS.get();
279 if (n > 0 && !im.isAnonymous()) {
280 final UserInfo userInfo = im.getUserInfo();
281 if (userInfo != null) {
282 final ChangesetCacheManager ccm = ChangesetCacheManager.getInstance();
283 final int userId = userInfo.getId();
284 int found = 0;
285 for (int i = 0; i < ccm.getModel().getRowCount() && found < n; i++) {
286 Changeset cs = ccm.getModel().getValueAt(i, 0);
287 if (cs.getUser().getId() == userId && cs.getBounds() != null) {
288 model.addElement(new ChangesetBookmark(cs));
289 found++;
290 }
291 }
292 }
293 }
294 }
295
296 /**
297 * Saves all manual bookmarks to the preferences file.
298 */
299 public final void save() {
300 List<Collection<String>> coll = new LinkedList<>();
301 for (Object o : ((DefaultListModel<Bookmark>) getModel()).toArray()) {
302 if (o instanceof HomeLocationBookmark || o instanceof ChangesetBookmark) {
303 continue;
304 }
305 String[] array = new String[5];
306 Bookmark b = (Bookmark) o;
307 array[0] = b.getName();
308 Bounds area = b.getArea();
309 array[1] = String.valueOf(area.getMinLat());
310 array[2] = String.valueOf(area.getMinLon());
311 array[3] = String.valueOf(area.getMaxLat());
312 array[4] = String.valueOf(area.getMaxLon());
313 coll.add(Arrays.asList(array));
314 }
315 Main.pref.putArray("bookmarks", coll);
316 }
317
318 /**
319 * Refreshes the changeset bookmarks.
320 * @since 12495
321 */
322 public void refreshChangesetBookmarks() {
323 final int n = MAX_CHANGESET_BOOKMARKS.get();
324 if (n > 0) {
325 final DefaultListModel<Bookmark> model = (DefaultListModel<Bookmark>) getModel();
326 for (int i = model.getSize() - 1; i >= 0; i--) {
327 if (model.get(i) instanceof ChangesetBookmark) {
328 model.remove(i);
329 }
330 }
331 ChangesetQuery query = ChangesetQuery.forCurrentUser();
332 if (!GraphicsEnvironment.isHeadless()) {
333 final ChangesetQueryTask task = new ChangesetQueryTask(this, query);
334 ChangesetCacheManager.getInstance().runDownloadTask(task);
335 Main.worker.submit(() -> {
336 if (task.isCanceled() || task.isFailed())
337 return;
338 GuiHelper.runInEDT(() -> task.getDownloadedData().stream()
339 .filter(cs -> cs.getBounds() != null)
340 .sorted(Comparator.reverseOrder())
341 .limit(n)
342 .forEachOrdered(cs -> model.addElement(new ChangesetBookmark(cs))));
343 });
344 }
345 }
346 }
347
348 static class BookmarkCellRenderer extends JLabel implements ListCellRenderer<BookmarkList.Bookmark> {
349
350 /**
351 * Constructs a new {@code BookmarkCellRenderer}.
352 */
353 BookmarkCellRenderer() {
354 setOpaque(true);
355 }
356
357 protected void renderColor(boolean selected) {
358 if (selected) {
359 setBackground(UIManager.getColor("List.selectionBackground"));
360 setForeground(UIManager.getColor("List.selectionForeground"));
361 } else {
362 setBackground(UIManager.getColor("List.background"));
363 setForeground(UIManager.getColor("List.foreground"));
364 }
365 }
366
367 protected String buildToolTipText(Bookmark b) {
368 Bounds area = b.getArea();
369 StringBuilder sb = new StringBuilder(128);
370 if (area != null) {
371 sb.append("<html>min[latitude,longitude]=<strong>[")
372 .append(area.getMinLat()).append(',').append(area.getMinLon()).append("]</strong>"+
373 "<br>max[latitude,longitude]=<strong>[")
374 .append(area.getMaxLat()).append(',').append(area.getMaxLon()).append("]</strong>"+
375 "</html>");
376 }
377 return sb.toString();
378 }
379
380 @Override
381 public Component getListCellRendererComponent(JList<? extends Bookmark> list, Bookmark value, int index, boolean isSelected,
382 boolean cellHasFocus) {
383 renderColor(isSelected);
384 setIcon(value.getIcon());
385 setText(value.getName());
386 setToolTipText(buildToolTipText(value));
387 return this;
388 }
389 }
390}
Note: See TracBrowser for help on using the repository browser.