001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.download; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Component; 007import java.io.BufferedReader; 008import java.io.File; 009import java.io.FileInputStream; 010import java.io.IOException; 011import java.io.InputStreamReader; 012import java.util.ArrayList; 013import java.util.Arrays; 014import java.util.Collection; 015import java.util.Collections; 016import java.util.LinkedList; 017import java.util.List; 018import java.util.regex.Matcher; 019import java.util.regex.Pattern; 020 021import javax.swing.DefaultListModel; 022import javax.swing.ImageIcon; 023import javax.swing.JLabel; 024import javax.swing.JList; 025import javax.swing.JOptionPane; 026import javax.swing.ListCellRenderer; 027import javax.swing.UIManager; 028 029import org.openstreetmap.josm.Main; 030import org.openstreetmap.josm.data.Bounds; 031import org.openstreetmap.josm.tools.ImageProvider; 032import org.openstreetmap.josm.tools.Utils; 033 034/** 035 * List class that read and save its content from the bookmark file. 036 * @since 6340 037 */ 038public class BookmarkList extends JList { 039 040 /** 041 * Class holding one bookmarkentry. 042 */ 043 public static class Bookmark implements Comparable<Bookmark> { 044 private String name; 045 private Bounds area; 046 047 /** 048 * Constructs a new {@code Bookmark} with the given contents. 049 * @param list Bookmark contents as a list of 5 elements. First item is the name, then come bounds arguments (minlat, minlon, maxlat, maxlon) 050 * @throws NumberFormatException If the bounds arguments are not numbers 051 * @throws IllegalArgumentException If list contain less than 5 elements 052 */ 053 public Bookmark(Collection<String> list) throws NumberFormatException, IllegalArgumentException { 054 List<String> array = new ArrayList<String>(list); 055 if(array.size() < 5) 056 throw new IllegalArgumentException(tr("Wrong number of arguments for bookmark")); 057 name = array.get(0); 058 area = new Bounds(Double.parseDouble(array.get(1)), Double.parseDouble(array.get(2)), 059 Double.parseDouble(array.get(3)), Double.parseDouble(array.get(4))); 060 } 061 062 /** 063 * Constructs a new empty {@code Bookmark}. 064 */ 065 public Bookmark() { 066 area = null; 067 name = null; 068 } 069 070 /** 071 * Constructs a new unamed {@code Bookmark} for the given area. 072 * @param area The bookmark area 073 */ 074 public Bookmark(Bounds area) { 075 this.area = area; 076 } 077 078 @Override public String toString() { 079 return name; 080 } 081 082 @Override 083 public int compareTo(Bookmark b) { 084 return name.toLowerCase().compareTo(b.name.toLowerCase()); 085 } 086 087 @Override 088 public int hashCode() { 089 final int prime = 31; 090 int result = 1; 091 result = prime * result + ((area == null) ? 0 : area.hashCode()); 092 result = prime * result + ((name == null) ? 0 : name.hashCode()); 093 return result; 094 } 095 096 @Override 097 public boolean equals(Object obj) { 098 if (this == obj) 099 return true; 100 if (obj == null) 101 return false; 102 if (getClass() != obj.getClass()) 103 return false; 104 Bookmark other = (Bookmark) obj; 105 if (area == null) { 106 if (other.area != null) 107 return false; 108 } else if (!area.equals(other.area)) 109 return false; 110 if (name == null) { 111 if (other.name != null) 112 return false; 113 } else if (!name.equals(other.name)) 114 return false; 115 return true; 116 } 117 118 /** 119 * Returns the bookmark area 120 * @return The bookmark area 121 */ 122 public Bounds getArea() { 123 return area; 124 } 125 126 /** 127 * Returns the bookmark name 128 * @return The bookmark name 129 */ 130 public String getName() { 131 return name; 132 } 133 134 /** 135 * Sets the bookmark name 136 * @param name The bookmark name 137 */ 138 public void setName(String name) { 139 this.name = name; 140 } 141 142 /** 143 * Sets the bookmark area 144 * @param area The bookmark area 145 */ 146 public void setArea(Bounds area) { 147 this.area = area; 148 } 149 } 150 151 /** 152 * Creates a bookmark list as well as the Buttons add and remove. 153 */ 154 public BookmarkList() { 155 setModel(new DefaultListModel()); 156 load(); 157 setVisibleRowCount(7); 158 setCellRenderer(new BookmarkCellRenderer()); 159 } 160 161 /** 162 * Loads the bookmarks from file. 163 */ 164 public final void load() { 165 DefaultListModel model = (DefaultListModel)getModel(); 166 model.removeAllElements(); 167 Collection<Collection<String>> args = Main.pref.getArray("bookmarks", null); 168 if(args != null) { 169 LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>(); 170 for(Collection<String> entry : args) { 171 try { 172 bookmarks.add(new Bookmark(entry)); 173 } 174 catch (Exception e) { 175 Main.error(tr("Error reading bookmark entry: %s", e.getMessage())); 176 } 177 } 178 Collections.sort(bookmarks); 179 for (Bookmark b : bookmarks) { 180 model.addElement(b); 181 } 182 } 183 else if(!Main.applet) { /* FIXME: remove else clause after spring 2011, but fix windows installer before */ 184 File bookmarkFile = new File(Main.pref.getPreferencesDir(),"bookmarks"); 185 try { 186 LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>(); 187 if (bookmarkFile.exists()) { 188 Main.info("Try loading obsolete bookmarks file"); 189 BufferedReader in = new BufferedReader(new InputStreamReader( 190 new FileInputStream(bookmarkFile), "utf-8")); 191 192 for (String line = in.readLine(); line != null; line = in.readLine()) { 193 Matcher m = Pattern.compile("^(.+)[,\u001e](-?\\d+.\\d+)[,\u001e](-?\\d+.\\d+)[,\u001e](-?\\d+.\\d+)[,\u001e](-?\\d+.\\d+)$").matcher(line); 194 if (!m.matches() || m.groupCount() != 5) { 195 Main.error(tr("Unexpected line ''{0}'' in bookmark file ''{1}''",line, bookmarkFile.toString())); 196 continue; 197 } 198 Bookmark b = new Bookmark(); 199 b.setName(m.group(1)); 200 double[] values= new double[4]; 201 for (int i = 0; i < 4; ++i) { 202 try { 203 values[i] = Double.parseDouble(m.group(i+2)); 204 } catch (NumberFormatException e) { 205 Main.error(tr("Illegal double value ''{0}'' on line ''{1}'' in bookmark file ''{2}''",m.group(i+2),line, bookmarkFile.toString())); 206 continue; 207 } 208 } 209 b.setArea(new Bounds(values)); 210 bookmarks.add(b); 211 } 212 Utils.close(in); 213 Collections.sort(bookmarks); 214 for (Bookmark b : bookmarks) { 215 model.addElement(b); 216 } 217 save(); 218 Main.info("Removing obsolete bookmarks file"); 219 if (!bookmarkFile.delete()) { 220 bookmarkFile.deleteOnExit(); 221 } 222 } 223 } catch (IOException e) { 224 Main.error(e); 225 JOptionPane.showMessageDialog( 226 Main.parent, 227 tr("<html>Could not read bookmarks from<br>''{0}''<br>Error was: {1}</html>", 228 bookmarkFile.toString(), 229 e.getMessage() 230 ), 231 tr("Error"), 232 JOptionPane.ERROR_MESSAGE 233 ); 234 } 235 } 236 } 237 238 /** 239 * Saves all bookmarks to the preferences file 240 */ 241 public final void save() { 242 LinkedList<Collection<String>> coll = new LinkedList<Collection<String>>(); 243 for (Object o : ((DefaultListModel)getModel()).toArray()) { 244 String[] array = new String[5]; 245 Bookmark b = (Bookmark)o; 246 array[0] = b.getName(); 247 Bounds area = b.getArea(); 248 array[1] = String.valueOf(area.getMinLat()); 249 array[2] = String.valueOf(area.getMinLon()); 250 array[3] = String.valueOf(area.getMaxLat()); 251 array[4] = String.valueOf(area.getMaxLon()); 252 coll.add(Arrays.asList(array)); 253 } 254 Main.pref.putArray("bookmarks", coll); 255 } 256 257 static class BookmarkCellRenderer extends JLabel implements ListCellRenderer { 258 259 private ImageIcon icon; 260 261 public BookmarkCellRenderer() { 262 setOpaque(true); 263 icon = ImageProvider.get("dialogs", "bookmark"); 264 setIcon(icon); 265 } 266 267 protected void renderColor(boolean selected) { 268 if (selected) { 269 setBackground(UIManager.getColor("List.selectionBackground")); 270 setForeground(UIManager.getColor("List.selectionForeground")); 271 } else { 272 setBackground(UIManager.getColor("List.background")); 273 setForeground(UIManager.getColor("List.foreground")); 274 } 275 } 276 277 protected String buildToolTipText(Bookmark b) { 278 Bounds area = b.getArea(); 279 StringBuffer sb = new StringBuffer(); 280 sb.append("<html>min[latitude,longitude]=<strong>[") 281 .append(area.getMinLat()).append(",").append(area.getMinLon()).append("]</strong>") 282 .append("<br>") 283 .append("max[latitude,longitude]=<strong>[") 284 .append(area.getMaxLat()).append(",").append(area.getMaxLon()).append("]</strong>") 285 .append("</html>"); 286 return sb.toString(); 287 288 } 289 @Override 290 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, 291 boolean cellHasFocus) { 292 293 Bookmark b = (Bookmark) value; 294 renderColor(isSelected); 295 setText(b.getName()); 296 setToolTipText(buildToolTipText(b)); 297 return this; 298 } 299 } 300}