001    // License: GPL. Copyright 2007 by Immanuel Scholz and others
002    package org.openstreetmap.josm.gui;
003    
004    import static org.openstreetmap.josm.tools.I18n.tr;
005    
006    import java.awt.Component;
007    import java.io.IOException;
008    import java.io.BufferedReader;
009    import java.io.InputStreamReader;
010    import java.io.File;
011    import java.io.FileInputStream;
012    import java.io.FileOutputStream;
013    import java.io.OutputStreamWriter;
014    import java.io.PrintWriter;
015    import java.util.Arrays;
016    import java.util.ArrayList;
017    import java.util.Collection;
018    import java.util.Collections;
019    import java.util.LinkedList;
020    import java.util.regex.Matcher;
021    import java.util.regex.Pattern;
022    
023    import javax.swing.DefaultListModel;
024    import javax.swing.ImageIcon;
025    import javax.swing.JLabel;
026    import javax.swing.JList;
027    import javax.swing.JOptionPane;
028    import javax.swing.ListCellRenderer;
029    import javax.swing.UIManager;
030    
031    import org.openstreetmap.josm.Main;
032    import org.openstreetmap.josm.data.Bounds;
033    import org.openstreetmap.josm.tools.ImageProvider;
034    
035    /**
036     * List class that read and save its content from the bookmark file.
037     * @author imi
038     */
039    public class BookmarkList extends JList {
040    
041        /**
042         * Class holding one bookmarkentry.
043         * @author imi
044         */
045        public static class Bookmark implements Comparable<Bookmark> {
046            private String name;
047            private Bounds area;
048    
049            public Bookmark(Collection<String> list) throws NumberFormatException, IllegalArgumentException {
050                ArrayList<String> array = new ArrayList<String>(list);
051                if(array.size() < 5)
052                    throw new IllegalArgumentException(tr("Wrong number of arguments for bookmark"));
053                name = array.get(0);
054                area = new Bounds(Double.parseDouble(array.get(1)), Double.parseDouble(array.get(2)),
055                                  Double.parseDouble(array.get(3)), Double.parseDouble(array.get(4)));
056            }
057    
058            public Bookmark() {
059                area = null;
060                name = null;
061            }
062    
063            public Bookmark(Bounds area) {
064                this.area = area;
065            }
066    
067            @Override public String toString() {
068                return name;
069            }
070    
071            public int compareTo(Bookmark b) {
072                return name.toLowerCase().compareTo(b.name.toLowerCase());
073            }
074    
075            public Bounds getArea() {
076                return area;
077            }
078    
079            public String getName() {
080                return name;
081            }
082    
083            public void setName(String name) {
084                this.name = name;
085            }
086    
087            public void setArea(Bounds area) {
088                this.area = area;
089            }
090        }
091    
092        /**
093         * Create a bookmark list as well as the Buttons add and remove.
094         */
095        public BookmarkList() {
096            setModel(new DefaultListModel());
097            load();
098            setVisibleRowCount(7);
099            setCellRenderer(new BookmarkCellRenderer());
100        }
101    
102        /**
103         * Loads the bookmarks from file.
104         */
105        public void load() {
106            DefaultListModel model = (DefaultListModel)getModel();
107            model.removeAllElements();
108            Collection<Collection<String>> args = Main.pref.getArray("bookmarks", null);
109            if(args != null) {
110                LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>();
111                for(Collection<String> entry : args) {
112                    try {
113                        bookmarks.add(new Bookmark(entry));
114                    }
115                    catch(Exception e) {
116                        System.err.println(tr("Error reading bookmark entry: %s", e.getMessage()));
117                    }
118                }
119                Collections.sort(bookmarks);
120                for (Bookmark b : bookmarks) {
121                    model.addElement(b);
122                }
123            }
124            else if(!Main.applet) { /* FIXME: remove else clause after spring 2011, but fix windows installer before */
125                File bookmarkFile = new File(Main.pref.getPreferencesDir(),"bookmarks");
126                try {
127                    LinkedList<Bookmark> bookmarks = new LinkedList<Bookmark>();
128                    if (bookmarkFile.exists()) {
129                        System.out.println("Try loading obsolete bookmarks file");
130                        BufferedReader in = new BufferedReader(new InputStreamReader(
131                                new FileInputStream(bookmarkFile), "utf-8"));
132    
133                        for (String line = in.readLine(); line != null; line = in.readLine()) {
134                            Matcher m = Pattern.compile("^(.+)[,\u001e](-?\\d+.\\d+)[,\u001e](-?\\d+.\\d+)[,\u001e](-?\\d+.\\d+)[,\u001e](-?\\d+.\\d+)$").matcher(line);
135                            if (!m.matches() || m.groupCount() != 5) {
136                                System.err.println(tr("Error: Unexpected line ''{0}'' in bookmark file ''{1}''",line, bookmarkFile.toString()));
137                                continue;
138                            }
139                            Bookmark b = new Bookmark();
140                            b.setName(m.group(1));
141                            double[] values= new double[4];
142                            for (int i = 0; i < 4; ++i) {
143                                try {
144                                    values[i] = Double.parseDouble(m.group(i+2));
145                                } catch(NumberFormatException e) {
146                                    System.err.println(tr("Error: Illegal double value ''{0}'' on line ''{1}'' in bookmark file ''{2}''",m.group(i+2),line, bookmarkFile.toString()));
147                                    continue;
148                                }
149                            }
150                            b.setArea(new Bounds(values));
151                            bookmarks.add(b);
152                        }
153                        in.close();
154                        Collections.sort(bookmarks);
155                        for (Bookmark b : bookmarks) {
156                            model.addElement(b);
157                        }
158                        save();
159                        System.out.println("Removing obsolete bookmarks file");
160                        bookmarkFile.delete();
161                    }
162                } catch (IOException e) {
163                    e.printStackTrace();
164                    JOptionPane.showMessageDialog(
165                            Main.parent,
166                            tr("<html>Could not read bookmarks from<br>''{0}''<br>Error was: {1}</html>",
167                                    bookmarkFile.toString(),
168                                    e.getMessage()
169                            ),
170                            tr("Error"),
171                            JOptionPane.ERROR_MESSAGE
172                    );
173                }
174            }
175        }
176    
177        /**
178         * Save all bookmarks to the preferences file
179         */
180        public void save() {
181            LinkedList<Collection<String>> coll = new LinkedList<Collection<String>>();
182            for (Object o : ((DefaultListModel)getModel()).toArray()) {
183                String[] array = new String[5];
184                Bookmark b = (Bookmark)o;
185                array[0] = b.getName();
186                Bounds area = b.getArea();
187                array[1] = String.valueOf(area.getMin().lat());
188                array[2] = String.valueOf(area.getMin().lon());
189                array[3] = String.valueOf(area.getMax().lat());
190                array[4] = String.valueOf(area.getMax().lon());
191                coll.add(Arrays.asList(array));
192            }
193            Main.pref.putArray("bookmarks", coll);
194        }
195    
196        static class BookmarkCellRenderer extends JLabel implements ListCellRenderer {
197    
198            private ImageIcon icon;
199    
200            public BookmarkCellRenderer() {
201                setOpaque(true);
202                icon = ImageProvider.get("dialogs", "bookmark");
203                setIcon(icon);
204            }
205    
206            protected void renderColor(boolean selected) {
207                if (selected) {
208                    setBackground(UIManager.getColor("List.selectionBackground"));
209                    setForeground(UIManager.getColor("List.selectionForeground"));
210                } else {
211                    setBackground(UIManager.getColor("List.background"));
212                    setForeground(UIManager.getColor("List.foreground"));
213                }
214            }
215    
216            protected String buildToolTipText(Bookmark b) {
217                Bounds area = b.getArea();
218                StringBuffer sb = new StringBuffer();
219                sb.append("<html>min[latitude,longitude]=<strong>[")
220                .append(area.getMin().lat()).append(",").append(area.getMin().lon()).append("]</strong>")
221                .append("<br>")
222                .append("max[latitude,longitude]=<strong>[")
223                .append(area.getMax().lat()).append(",").append(area.getMax().lon()).append("]</strong>")
224                .append("</html>");
225                return sb.toString();
226    
227            }
228            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
229                    boolean cellHasFocus) {
230    
231                Bookmark b = (Bookmark) value;
232                renderColor(isSelected);
233                setText(b.getName());
234                setToolTipText(buildToolTipText(b));
235                return this;
236            }
237        }
238    }