001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.layer;
003
004import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005import static org.openstreetmap.josm.tools.I18n.tr;
006
007import java.awt.Color;
008import java.awt.Component;
009import java.awt.event.ActionEvent;
010import java.util.Collections;
011import java.util.List;
012import java.util.Objects;
013import java.util.stream.Collectors;
014
015import javax.swing.AbstractAction;
016import javax.swing.Action;
017import javax.swing.JColorChooser;
018import javax.swing.JMenuItem;
019import javax.swing.JOptionPane;
020
021import org.openstreetmap.josm.Main;
022import org.openstreetmap.josm.data.preferences.AbstractProperty;
023import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
024import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
025import org.openstreetmap.josm.gui.layer.Layer.MultiLayerAction;
026import org.openstreetmap.josm.tools.CheckParameterUtil;
027import org.openstreetmap.josm.tools.ImageProvider;
028
029public class CustomizeColor extends AbstractAction implements LayerAction, MultiLayerAction {
030    private final transient List<AbstractProperty<Color>> colors;
031
032    /**
033     * Constructs a new {@code CustomizeColor} for a given list of layers.
034     * @param l list of layers
035     */
036    public CustomizeColor(List<Layer> l) {
037        super(tr("Customize Color"), ImageProvider.get("colorchooser"));
038        colors = l.stream().map(Layer::getColorProperty).collect(Collectors.toList());
039        CheckParameterUtil.ensureThat(colors.stream().allMatch(Objects::nonNull), "All layers must have colors.");
040        putValue("help", ht("/Action/LayerCustomizeColor"));
041    }
042
043    /**
044     * Constructs a new {@code CustomizeColor} for a single layer.
045     * @param l layer
046     */
047    public CustomizeColor(Layer l) {
048        this(Collections.singletonList(l));
049    }
050
051    @Override
052    public boolean supportLayers(List<Layer> layers) {
053        return layers.stream().allMatch(l -> l.getColorProperty() != null);
054    }
055
056    @Override
057    public Component createMenuComponent() {
058        return new JMenuItem(this);
059    }
060
061    @Override
062    public Action getMultiLayerAction(List<Layer> layers) {
063        return new CustomizeColor(layers);
064    }
065
066    @Override
067    public void actionPerformed(ActionEvent e) {
068        Color cl = colors.stream().map(AbstractProperty::get).filter(Objects::nonNull).findAny().orElse(Color.GRAY);
069        JColorChooser c = new JColorChooser(cl);
070        Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
071        int answer = JOptionPane.showOptionDialog(
072                Main.parent,
073                c,
074                tr("Choose a color"),
075                JOptionPane.OK_CANCEL_OPTION,
076                JOptionPane.PLAIN_MESSAGE,
077                null,
078                options,
079                options[0]
080        );
081        switch (answer) {
082        case 0:
083            colors.stream().forEach(prop -> prop.put(c.getColor()));
084            break;
085        case 1:
086            return;
087        case 2:
088            colors.stream().forEach(prop -> prop.put(null));
089            break;
090        }
091        // TODO: Make the layer dialog listen to property change events so that this is not needed any more.
092        LayerListDialog.getInstance().repaint();
093    }
094}