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.util.ArrayList;
008import java.util.Arrays;
009import java.util.Collection;
010import java.util.Collections;
011import java.util.LinkedList;
012import java.util.List;
013
014import javax.swing.DefaultListModel;
015import javax.swing.ImageIcon;
016import javax.swing.JLabel;
017import javax.swing.JList;
018import javax.swing.ListCellRenderer;
019import javax.swing.UIManager;
020
021import org.openstreetmap.josm.Main;
022import org.openstreetmap.josm.data.Bounds;
023import org.openstreetmap.josm.tools.ImageProvider;
024
025/**
026 * List class that read and save its content from the bookmark file.
027 * @since 6340
028 */
029public class BookmarkList extends JList<BookmarkList.Bookmark> {
030
031    /**
032     * Class holding one bookmarkentry.
033     */
034    public static class Bookmark implements Comparable<Bookmark> {
035        private String name;
036        private Bounds area;
037
038        /**
039         * Constructs a new {@code Bookmark} with the given contents.
040         * @param list Bookmark contents as a list of 5 elements. First item is the name, then come bounds arguments (minlat, minlon, maxlat, maxlon)
041         * @throws NumberFormatException If the bounds arguments are not numbers
042         * @throws IllegalArgumentException If list contain less than 5 elements
043         */
044        public Bookmark(Collection<String> list) throws NumberFormatException, IllegalArgumentException {
045            List<String> array = new ArrayList<>(list);
046            if(array.size() < 5)
047                throw new IllegalArgumentException(tr("Wrong number of arguments for bookmark"));
048            name = array.get(0);
049            area = new Bounds(Double.parseDouble(array.get(1)), Double.parseDouble(array.get(2)),
050                              Double.parseDouble(array.get(3)), Double.parseDouble(array.get(4)));
051        }
052
053        /**
054         * Constructs a new empty {@code Bookmark}.
055         */
056        public Bookmark() {
057            area = null;
058            name = null;
059        }
060
061        /**
062         * Constructs a new unamed {@code Bookmark} for the given area.
063         * @param area The bookmark area
064         */
065        public Bookmark(Bounds area) {
066            this.area = area;
067        }
068
069        @Override public String toString() {
070            return name;
071        }
072
073        @Override
074        public int compareTo(Bookmark b) {
075            return name.toLowerCase().compareTo(b.name.toLowerCase());
076        }
077
078        @Override
079        public int hashCode() {
080            final int prime = 31;
081            int result = 1;
082            result = prime * result + ((area == null) ? 0 : area.hashCode());
083            result = prime * result + ((name == null) ? 0 : name.hashCode());
084            return result;
085        }
086
087        @Override
088        public boolean equals(Object obj) {
089            if (this == obj)
090                return true;
091            if (obj == null)
092                return false;
093            if (getClass() != obj.getClass())
094                return false;
095            Bookmark other = (Bookmark) obj;
096            if (area == null) {
097                if (other.area != null)
098                    return false;
099            } else if (!area.equals(other.area))
100                return false;
101            if (name == null) {
102                if (other.name != null)
103                    return false;
104            } else if (!name.equals(other.name))
105                return false;
106            return true;
107        }
108
109        /**
110         * Returns the bookmark area
111         * @return The bookmark area
112         */
113        public Bounds getArea() {
114            return area;
115        }
116
117        /**
118         * Returns the bookmark name
119         * @return The bookmark name
120         */
121        public String getName() {
122            return name;
123        }
124
125        /**
126         * Sets the bookmark name
127         * @param name The bookmark name
128         */
129        public void setName(String name) {
130            this.name = name;
131        }
132
133        /**
134         * Sets the bookmark area
135         * @param area The bookmark area
136         */
137        public void setArea(Bounds area) {
138            this.area = area;
139        }
140    }
141
142    /**
143     * Creates a bookmark list as well as the Buttons add and remove.
144     */
145    public BookmarkList() {
146        setModel(new DefaultListModel<Bookmark>());
147        load();
148        setVisibleRowCount(7);
149        setCellRenderer(new BookmarkCellRenderer());
150    }
151
152    /**
153     * Loads the bookmarks from file.
154     */
155    public final void load() {
156        DefaultListModel<Bookmark> model = (DefaultListModel<Bookmark>)getModel();
157        model.removeAllElements();
158        Collection<Collection<String>> args = Main.pref.getArray("bookmarks", null);
159        if(args != null) {
160            LinkedList<Bookmark> bookmarks = new LinkedList<>();
161            for(Collection<String> entry : args) {
162                try {
163                    bookmarks.add(new Bookmark(entry));
164                }
165                catch (Exception e) {
166                    Main.error(tr("Error reading bookmark entry: %s", e.getMessage()));
167                }
168            }
169            Collections.sort(bookmarks);
170            for (Bookmark b : bookmarks) {
171                model.addElement(b);
172            }
173        }
174    }
175
176    /**
177     * Saves all bookmarks to the preferences file
178     */
179    public final void save() {
180        LinkedList<Collection<String>> coll = new LinkedList<>();
181        for (Object o : ((DefaultListModel<Bookmark>)getModel()).toArray()) {
182            String[] array = new String[5];
183            Bookmark b = (Bookmark) o;
184            array[0] = b.getName();
185            Bounds area = b.getArea();
186            array[1] = String.valueOf(area.getMinLat());
187            array[2] = String.valueOf(area.getMinLon());
188            array[3] = String.valueOf(area.getMaxLat());
189            array[4] = String.valueOf(area.getMaxLon());
190            coll.add(Arrays.asList(array));
191        }
192        Main.pref.putArray("bookmarks", coll);
193    }
194
195    static class BookmarkCellRenderer extends JLabel implements ListCellRenderer<BookmarkList.Bookmark> {
196
197        private ImageIcon icon;
198
199        public BookmarkCellRenderer() {
200            setOpaque(true);
201            icon = ImageProvider.get("dialogs", "bookmark");
202            setIcon(icon);
203        }
204
205        protected void renderColor(boolean selected) {
206            if (selected) {
207                setBackground(UIManager.getColor("List.selectionBackground"));
208                setForeground(UIManager.getColor("List.selectionForeground"));
209            } else {
210                setBackground(UIManager.getColor("List.background"));
211                setForeground(UIManager.getColor("List.foreground"));
212            }
213        }
214
215        protected String buildToolTipText(Bookmark b) {
216            Bounds area = b.getArea();
217            StringBuilder sb = new StringBuilder();
218            sb.append("<html>min[latitude,longitude]=<strong>[")
219            .append(area.getMinLat()).append(",").append(area.getMinLon()).append("]</strong>")
220            .append("<br>")
221            .append("max[latitude,longitude]=<strong>[")
222            .append(area.getMaxLat()).append(",").append(area.getMaxLon()).append("]</strong>")
223            .append("</html>");
224            return sb.toString();
225
226        }
227
228        @Override
229        public Component getListCellRendererComponent(JList<? extends Bookmark> list, Bookmark value, int index, boolean isSelected, boolean cellHasFocus) {
230            renderColor(isSelected);
231            setText(value.getName());
232            setToolTipText(buildToolTipText(value));
233            return this;
234        }
235    }
236}