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

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

see #15410 - better sorting

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