001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.preferences.display; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Color; 007import java.awt.Component; 008import java.awt.Dimension; 009import java.awt.GridBagLayout; 010import java.awt.event.ActionEvent; 011import java.awt.event.ActionListener; 012import java.util.ArrayList; 013import java.util.HashMap; 014import java.util.List; 015import java.util.Map; 016import java.util.TreeMap; 017import java.util.Vector; 018 019import javax.swing.BorderFactory; 020import javax.swing.Box; 021import javax.swing.JButton; 022import javax.swing.JColorChooser; 023import javax.swing.JLabel; 024import javax.swing.JOptionPane; 025import javax.swing.JPanel; 026import javax.swing.JScrollPane; 027import javax.swing.JTable; 028import javax.swing.ListSelectionModel; 029import javax.swing.event.ListSelectionEvent; 030import javax.swing.table.DefaultTableModel; 031import javax.swing.table.TableCellRenderer; 032 033import org.openstreetmap.josm.Main; 034import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors; 035import org.openstreetmap.josm.data.validation.Severity; 036import org.openstreetmap.josm.gui.MapScaler; 037import org.openstreetmap.josm.gui.MapStatus; 038import org.openstreetmap.josm.gui.conflict.ConflictColors; 039import org.openstreetmap.josm.gui.dialogs.ConflictDialog; 040import org.openstreetmap.josm.gui.layer.ImageryLayer; 041import org.openstreetmap.josm.gui.layer.OsmDataLayer; 042import org.openstreetmap.josm.gui.layer.gpx.GpxDrawHelper; 043import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer; 044import org.openstreetmap.josm.gui.preferences.PreferenceSetting; 045import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory; 046import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane; 047import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting; 048import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting; 049import org.openstreetmap.josm.gui.util.GuiHelper; 050import org.openstreetmap.josm.tools.ColorHelper; 051import org.openstreetmap.josm.tools.GBC; 052 053/** 054 * Color preferences. 055 */ 056public class ColorPreference implements SubPreferenceSetting { 057 058 /** 059 * Factory used to create a new {@code ColorPreference}. 060 */ 061 public static class Factory implements PreferenceSettingFactory { 062 @Override 063 public PreferenceSetting createPreferenceSetting() { 064 return new ColorPreference(); 065 } 066 } 067 068 private DefaultTableModel tableModel; 069 private JTable colors; 070 private final List<String> del = new ArrayList<>(); 071 072 private JButton colorEdit; 073 private JButton defaultSet; 074 private JButton remove; 075 076 /** 077 * Set the colors to be shown in the preference table. This method creates a table model if 078 * none exists and overwrites all existing values. 079 * @param colorMap the map holding the colors 080 * (key = color id (without prefixes, so only <code>background</code>; not <code>color.background</code>), 081 * value = html representation of the color. 082 */ 083 public void setColorModel(Map<String, String> colorMap) { 084 if (tableModel == null) { 085 tableModel = new DefaultTableModel(); 086 tableModel.addColumn(tr("Name")); 087 tableModel.addColumn(tr("Color")); 088 } 089 090 // clear old model: 091 while (tableModel.getRowCount() > 0) { 092 tableModel.removeRow(0); 093 } 094 // fill model with colors: 095 Map<String, String> colorKeyList = new TreeMap<>(); 096 Map<String, String> colorKeyList_mappaint = new TreeMap<>(); 097 Map<String, String> colorKeyList_layer = new TreeMap<>(); 098 for (String key : colorMap.keySet()) { 099 if (key.startsWith("layer ")) { 100 colorKeyList_layer.put(getName(key), key); 101 } else if (key.startsWith("mappaint.")) { 102 // use getName(key)+key, as getName() may be ambiguous 103 colorKeyList_mappaint.put(getName(key)+key, key); 104 } else { 105 colorKeyList.put(getName(key), key); 106 } 107 } 108 addColorRows(colorMap, colorKeyList); 109 addColorRows(colorMap, colorKeyList_mappaint); 110 addColorRows(colorMap, colorKeyList_layer); 111 if (this.colors != null) { 112 this.colors.repaint(); 113 } 114 } 115 116 private void addColorRows(Map<String, String> colorMap, Map<String, String> keyMap) { 117 for (String value : keyMap.values()) { 118 Vector<Object> row = new Vector<>(2); 119 String html = colorMap.get(value); 120 Color color = ColorHelper.html2color(html); 121 if (color == null) { 122 Main.warn("Unable to get color from '"+html+"' for color preference '"+value+'\''); 123 } 124 row.add(value); 125 row.add(color); 126 tableModel.addRow(row); 127 } 128 } 129 130 /** 131 * Returns a map with the colors in the table (key = color name without prefix, value = html color code). 132 * @return a map holding the colors. 133 */ 134 public Map<String, String> getColorModel() { 135 String key; 136 String value; 137 Map<String, String> colorMap = new HashMap<>(); 138 for (int row = 0; row < tableModel.getRowCount(); ++row) { 139 key = (String) tableModel.getValueAt(row, 0); 140 value = ColorHelper.color2html((Color) tableModel.getValueAt(row, 1)); 141 colorMap.put(key, value); 142 } 143 return colorMap; 144 } 145 146 private static String getName(String o) { 147 return Main.pref.getColorName(o); 148 } 149 150 @Override 151 public void addGui(final PreferenceTabbedPane gui) { 152 fixColorPrefixes(); 153 setColorModel(Main.pref.getAllColors()); 154 155 colorEdit = new JButton(tr("Choose")); 156 colorEdit.addActionListener(new ActionListener() { 157 @Override 158 public void actionPerformed(ActionEvent e) { 159 int sel = colors.getSelectedRow(); 160 JColorChooser chooser = new JColorChooser((Color) colors.getValueAt(sel, 1)); 161 int answer = JOptionPane.showConfirmDialog( 162 gui, chooser, 163 tr("Choose a color for {0}", getName((String) colors.getValueAt(sel, 0))), 164 JOptionPane.OK_CANCEL_OPTION, 165 JOptionPane.PLAIN_MESSAGE); 166 if (answer == JOptionPane.OK_OPTION) { 167 colors.setValueAt(chooser.getColor(), sel, 1); 168 } 169 } 170 }); 171 defaultSet = new JButton(tr("Set to default")); 172 defaultSet.addActionListener(new ActionListener() { 173 @Override 174 public void actionPerformed(ActionEvent e) { 175 int sel = colors.getSelectedRow(); 176 String name = (String) colors.getValueAt(sel, 0); 177 Color c = Main.pref.getDefaultColor(name); 178 if (c != null) { 179 colors.setValueAt(c, sel, 1); 180 } 181 } 182 }); 183 JButton defaultAll = new JButton(tr("Set all to default")); 184 defaultAll.addActionListener(new ActionListener() { 185 @Override 186 public void actionPerformed(ActionEvent e) { 187 for (int i = 0; i < colors.getRowCount(); ++i) { 188 String name = (String) colors.getValueAt(i, 0); 189 Color c = Main.pref.getDefaultColor(name); 190 if (c != null) { 191 colors.setValueAt(c, i, 1); 192 } 193 } 194 } 195 }); 196 remove = new JButton(tr("Remove")); 197 remove.addActionListener(new ActionListener() { 198 @Override 199 public void actionPerformed(ActionEvent e) { 200 int sel = colors.getSelectedRow(); 201 del.add((String) colors.getValueAt(sel, 0)); 202 tableModel.removeRow(sel); 203 } 204 }); 205 remove.setEnabled(false); 206 colorEdit.setEnabled(false); 207 defaultSet.setEnabled(false); 208 209 colors = new JTable(tableModel) { 210 @Override 211 public boolean isCellEditable(int row, int column) { 212 return false; 213 } 214 215 @Override public void valueChanged(ListSelectionEvent e) { 216 super.valueChanged(e); 217 int sel = getSelectedRow(); 218 remove.setEnabled(sel >= 0 && isRemoveColor(sel)); 219 colorEdit.setEnabled(sel >= 0); 220 defaultSet.setEnabled(sel >= 0); 221 } 222 }; 223 colors.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 224 final TableCellRenderer oldColorsRenderer = colors.getDefaultRenderer(Object.class); 225 colors.setDefaultRenderer(Object.class, new TableCellRenderer() { 226 @Override 227 public Component getTableCellRendererComponent(JTable t, Object o, boolean selected, boolean focus, int row, int column) { 228 if (o == null) 229 return new JLabel(); 230 if (column == 1) { 231 Color c = (Color) o; 232 JLabel l = new JLabel(ColorHelper.color2html(c)); 233 GuiHelper.setBackgroundReadable(l, c); 234 l.setOpaque(true); 235 return l; 236 } 237 return oldColorsRenderer.getTableCellRendererComponent(t, getName(o.toString()), selected, focus, row, column); 238 } 239 }); 240 colors.getColumnModel().getColumn(1).setWidth(100); 241 colors.setToolTipText(tr("Colors used by different objects in JOSM.")); 242 colors.setPreferredScrollableViewportSize(new Dimension(100, 112)); 243 244 JPanel panel = new JPanel(new GridBagLayout()); 245 panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 246 JScrollPane scrollpane = new JScrollPane(colors); 247 scrollpane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); 248 panel.add(scrollpane, GBC.eol().fill(GBC.BOTH)); 249 JPanel buttonPanel = new JPanel(new GridBagLayout()); 250 panel.add(buttonPanel, GBC.eol().insets(5, 0, 5, 5).fill(GBC.HORIZONTAL)); 251 buttonPanel.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL)); 252 buttonPanel.add(colorEdit, GBC.std().insets(0, 5, 0, 0)); 253 buttonPanel.add(defaultSet, GBC.std().insets(5, 5, 5, 0)); 254 buttonPanel.add(defaultAll, GBC.std().insets(0, 5, 0, 0)); 255 buttonPanel.add(remove, GBC.std().insets(0, 5, 0, 0)); 256 gui.getDisplayPreference().addSubTab(this, tr("Colors"), panel); 257 } 258 259 Boolean isRemoveColor(int row) { 260 return ((String) colors.getValueAt(row, 0)).startsWith("layer "); 261 } 262 263 /** 264 * Add all missing color entries. 265 */ 266 private static void fixColorPrefixes() { 267 PaintColors.getColors(); 268 ConflictColors.getColors(); 269 Severity.getColors(); 270 MarkerLayer.getGenericColor(); 271 GpxDrawHelper.getGenericColor(); 272 OsmDataLayer.getOutsideColor(); 273 ImageryLayer.getFadeColor(); 274 MapScaler.getColor(); 275 MapStatus.getColors(); 276 ConflictDialog.getColor(); 277 } 278 279 @Override 280 public boolean ok() { 281 boolean ret = false; 282 for (String d : del) { 283 Main.pref.put("color."+d, null); 284 } 285 for (int i = 0; i < colors.getRowCount(); ++i) { 286 String key = (String) colors.getValueAt(i, 0); 287 if (Main.pref.putColor(key, (Color) colors.getValueAt(i, 1))) { 288 if (key.startsWith("mappaint.")) { 289 ret = true; 290 } 291 } 292 } 293 OsmDataLayer.createHatchTexture(); 294 return ret; 295 } 296 297 @Override 298 public boolean isExpert() { 299 return false; 300 } 301 302 @Override 303 public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) { 304 return gui.getDisplayPreference(); 305 } 306}