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