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

Last change on this file since 12878 was 12846, checked in by bastiK, 7 years ago

see #15229 - use Config.getPref() wherever possible

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