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