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