source: josm/trunk/src/org/openstreetmap/josm/gui/preferences/display/ColorPreference.java @ 12952

Last change on this file since 12952 was 12952, checked in by bastiK, 12 months ago

see #15410 - don't map translated values to keys; locale sensitive sorting

  • Property svn:eol-style set to native
File size: 12.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.preferences.display;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.awt.Component;
8import java.awt.Dimension;
9import java.awt.GridBagLayout;
10import java.awt.event.MouseAdapter;
11import java.awt.event.MouseEvent;
12import java.text.Collator;
13import java.util.ArrayList;
14import java.util.Collections;
15import java.util.HashMap;
16import java.util.List;
17import java.util.Map;
18
19import javax.swing.BorderFactory;
20import javax.swing.Box;
21import javax.swing.JButton;
22import javax.swing.JColorChooser;
23import javax.swing.JLabel;
24import javax.swing.JOptionPane;
25import javax.swing.JPanel;
26import javax.swing.JScrollPane;
27import javax.swing.JTable;
28import javax.swing.ListSelectionModel;
29import javax.swing.event.ListSelectionEvent;
30import javax.swing.table.AbstractTableModel;
31import javax.swing.table.DefaultTableCellRenderer;
32
33import org.openstreetmap.josm.Main;
34import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
35import org.openstreetmap.josm.data.validation.Severity;
36import org.openstreetmap.josm.gui.MapScaler;
37import org.openstreetmap.josm.gui.MapStatus;
38import org.openstreetmap.josm.gui.conflict.ConflictColors;
39import org.openstreetmap.josm.gui.dialogs.ConflictDialog;
40import org.openstreetmap.josm.gui.layer.OsmDataLayer;
41import org.openstreetmap.josm.gui.layer.gpx.GpxDrawHelper;
42import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
43import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
44import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
45import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
46import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
47import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
48import org.openstreetmap.josm.gui.util.GuiHelper;
49import org.openstreetmap.josm.tools.ColorHelper;
50import org.openstreetmap.josm.tools.GBC;
51import org.openstreetmap.josm.tools.Logging;
52
53/**
54 * Color preferences.
55 */
56public class ColorPreference implements SubPreferenceSetting {
57
58    /**
59     * Factory used to create a new {@code ColorPreference}.
60     */
61    public static class Factory implements PreferenceSettingFactory {
62        @Override
63        public PreferenceSetting createPreferenceSetting() {
64            return new ColorPreference();
65        }
66    }
67
68    private ColorTableModel tableModel;
69    private JTable colors;
70
71    private JButton colorEdit;
72    private JButton defaultSet;
73    private JButton remove;
74
75    private static class ColorEntry implements Comparable<ColorEntry> {
76        String key;
77        Color color;
78
79        public ColorEntry(String key, String colorHtml) {
80            this.key = key;
81            this.color = ColorHelper.html2color(colorHtml);
82            if (this.color == null) {
83                Logging.warn("Unable to get color from '"+colorHtml+"' for color preference '"+key+'\'');
84            }
85        }
86
87        @Override
88        public int compareTo(ColorEntry o) {
89            return Collator.getInstance().compare(getName(key), getName(o.key));
90        }
91    }
92
93    private static class ColorTableModel extends AbstractTableModel {
94
95        private final List<ColorEntry> data;
96        private final List<ColorEntry> deleted;
97
98        public ColorTableModel() {
99            this.data = new ArrayList<>();
100            this.deleted = new ArrayList<>();
101        }
102
103        public void addEntry(ColorEntry entry) {
104            data.add(entry);
105        }
106
107        public void removeEntry(int row) {
108            deleted.add(data.get(row));
109            data.remove(row);
110            fireTableDataChanged();
111        }
112
113        public List<ColorEntry> getData() {
114            return data;
115        }
116
117        public List<ColorEntry> getDeleted() {
118            return deleted;
119        }
120
121        public void clear() {
122            data.clear();
123            deleted.clear();
124        }
125
126        @Override
127        public int getRowCount() {
128            return data.size();
129        }
130
131        @Override
132        public int getColumnCount() {
133            return 2;
134        }
135
136        @Override
137        public Object getValueAt(int rowIndex, int columnIndex) {
138            return columnIndex == 0 ? getName(data.get(rowIndex).key) : data.get(rowIndex).color;
139        }
140
141        @Override
142        public String getColumnName(int column) {
143            return column == 0 ? tr("Name") : tr("Color");
144        }
145
146        @Override
147        public boolean isCellEditable(int rowIndex, int columnIndex) {
148            return false;
149        }
150
151        @Override
152        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
153            if (columnIndex == 1 && aValue instanceof Color) {
154                data.get(rowIndex).color = (Color) aValue;
155                fireTableCellUpdated(rowIndex, columnIndex);
156            }
157        }
158    }
159
160    /**
161     * Set the colors to be shown in the preference table. This method creates a table model if
162     * none exists and overwrites all existing values.
163     * @param colorMap the map holding the colors
164     * (key = color id (without prefixes, so only <code>background</code>; not <code>color.background</code>),
165     * value = html representation of the color.
166     */
167    public void setColorModel(Map<String, String> colorMap) {
168        if (tableModel == null) {
169            tableModel = new ColorTableModel();
170        }
171
172        tableModel.clear();
173        // fill model with colors:
174        List<ColorEntry> colorKeyList = new ArrayList<>();
175        List<ColorEntry> colorKeyListMappaint = new ArrayList<>();
176        List<ColorEntry> colorKeyListLayer = new ArrayList<>();
177        for (Map.Entry<String, String> e : colorMap.entrySet()) {
178            String key = e.getKey();
179            String html = e.getValue();
180            if (key.startsWith("layer.")) {
181                colorKeyListLayer.add(new ColorEntry(key, html));
182            } else if (key.startsWith("mappaint.")) {
183                colorKeyListMappaint.add(new ColorEntry(key, html));
184            } else {
185                colorKeyList.add(new ColorEntry(key, html));
186            }
187        }
188        addColorRows(colorKeyList);
189        addColorRows(colorKeyListMappaint);
190        addColorRows(colorKeyListLayer);
191        if (this.colors != null) {
192            this.colors.repaint();
193        }
194    }
195
196    private void addColorRows(List<ColorEntry> entries) {
197        Collections.sort(entries);
198        entries.forEach(tableModel::addEntry);
199    }
200
201    /**
202     * Returns a map with the colors in the table (key = color name without prefix, value = html color code).
203     * @return a map holding the colors.
204     */
205    public Map<String, String> getColorModel() {
206        Map<String, String> colorMap = new HashMap<>();
207        for (ColorEntry e : tableModel.getData()) {
208            colorMap.put(e.key, ColorHelper.color2html(e.color));
209        }
210        return colorMap;
211    }
212
213    private static String getName(String o) {
214        return Main.pref.getColorName(o);
215    }
216
217    @Override
218    public void addGui(final PreferenceTabbedPane gui) {
219        fixColorPrefixes();
220        setColorModel(Main.pref.getAllColors());
221
222        colorEdit = new JButton(tr("Choose"));
223        colorEdit.addActionListener(e -> {
224            int sel = colors.getSelectedRow();
225            JColorChooser chooser = new JColorChooser((Color) colors.getValueAt(sel, 1));
226            int answer = JOptionPane.showConfirmDialog(
227                    gui, chooser,
228                    tr("Choose a color for {0}", getName((String) colors.getValueAt(sel, 0))),
229                    JOptionPane.OK_CANCEL_OPTION,
230                    JOptionPane.PLAIN_MESSAGE);
231            if (answer == JOptionPane.OK_OPTION) {
232                colors.setValueAt(chooser.getColor(), sel, 1);
233            }
234        });
235        defaultSet = new JButton(tr("Set to default"));
236        defaultSet.addActionListener(e -> {
237            int sel = colors.getSelectedRow();
238            String name = (String) colors.getValueAt(sel, 0);
239            Color c = Main.pref.getDefaultColor(name);
240            if (c != null) {
241                colors.setValueAt(c, sel, 1);
242            }
243        });
244        JButton defaultAll = new JButton(tr("Set all to default"));
245        defaultAll.addActionListener(e -> {
246            for (int i = 0; i < colors.getRowCount(); ++i) {
247                String name = (String) colors.getValueAt(i, 0);
248                Color c = Main.pref.getDefaultColor(name);
249                if (c != null) {
250                    colors.setValueAt(c, i, 1);
251                }
252            }
253        });
254        remove = new JButton(tr("Remove"));
255        remove.addActionListener(e -> {
256            int sel = colors.getSelectedRow();
257            tableModel.removeEntry(sel);
258        });
259        remove.setEnabled(false);
260        colorEdit.setEnabled(false);
261        defaultSet.setEnabled(false);
262
263        colors = new JTable(tableModel) {
264            @Override public void valueChanged(ListSelectionEvent e) {
265                super.valueChanged(e);
266                int sel = getSelectedRow();
267                remove.setEnabled(sel >= 0 && isRemoveColor(sel));
268                colorEdit.setEnabled(sel >= 0);
269                defaultSet.setEnabled(sel >= 0);
270            }
271        };
272        colors.addMouseListener(new MouseAdapter() {
273            @Override
274            public void mousePressed(MouseEvent me) {
275                if (me.getClickCount() == 2) {
276                    colorEdit.doClick();
277                }
278            }
279        });
280        colors.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
281        colors.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer() {
282            @Override
283            public Component getTableCellRendererComponent(
284                    JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
285                Component comp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
286                if (value != null && comp instanceof JLabel) {
287                    JLabel label = (JLabel) comp;
288                    Color c = (Color) value;
289                    label.setText(ColorHelper.color2html(c));
290                    GuiHelper.setBackgroundReadable(label, c);
291                    label.setOpaque(true);
292                    return label;
293                }
294                return comp;
295            }
296        });
297        colors.getColumnModel().getColumn(1).setWidth(100);
298        colors.setToolTipText(tr("Colors used by different objects in JOSM."));
299        colors.setPreferredScrollableViewportSize(new Dimension(100, 112));
300
301        JPanel panel = new JPanel(new GridBagLayout());
302        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
303        JScrollPane scrollpane = new JScrollPane(colors);
304        scrollpane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
305        panel.add(scrollpane, GBC.eol().fill(GBC.BOTH));
306        JPanel buttonPanel = new JPanel(new GridBagLayout());
307        panel.add(buttonPanel, GBC.eol().insets(5, 0, 5, 5).fill(GBC.HORIZONTAL));
308        buttonPanel.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
309        buttonPanel.add(colorEdit, GBC.std().insets(0, 5, 0, 0));
310        buttonPanel.add(defaultSet, GBC.std().insets(5, 5, 5, 0));
311        buttonPanel.add(defaultAll, GBC.std().insets(0, 5, 0, 0));
312        buttonPanel.add(remove, GBC.std().insets(0, 5, 0, 0));
313        gui.getDisplayPreference().addSubTab(this, tr("Colors"), panel);
314    }
315
316    Boolean isRemoveColor(int row) {
317        return tableModel.getData().get(row).key.startsWith("layer.");
318    }
319
320    /**
321     * Add all missing color entries.
322     */
323    private static void fixColorPrefixes() {
324        PaintColors.values();
325        ConflictColors.getColors();
326        Severity.getColors();
327        MarkerLayer.getGenericColor();
328        GpxDrawHelper.getGenericColor();
329        OsmDataLayer.getOutsideColor();
330        MapScaler.getColor();
331        MapStatus.getColors();
332        ConflictDialog.getColor();
333    }
334
335    @Override
336    public boolean ok() {
337        boolean ret = false;
338        for (ColorEntry d : tableModel.getDeleted()) {
339            Main.pref.putColor(d.key, null);
340        }
341        for (ColorEntry e : tableModel.getData()) {
342            if (Main.pref.putColor(e.key, e.color) && e.key.startsWith("mappaint.")) {
343                ret = true;
344            }
345        }
346        OsmDataLayer.createHatchTexture();
347        return ret;
348    }
349
350    @Override
351    public boolean isExpert() {
352        return false;
353    }
354
355    @Override
356    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
357        return gui.getDisplayPreference();
358    }
359}
Note: See TracBrowser for help on using the repository browser.