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

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

see #15410 - highlight entries with modified color; fix "set to default"

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