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.gui.MainApplication;
022import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
023import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
024import org.openstreetmap.josm.gui.layer.Layer.MultiLayerAction;
025import org.openstreetmap.josm.tools.ImageProvider;
026
027/**
028 * Action to show a dialog for picking a color.
029 *
030 * By calling this action, the user can choose a color to customize the painting
031 * of a certain {@link GpxLayer} or {@link org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer}.
032 */
033public class CustomizeColor extends AbstractAction implements LayerAction, MultiLayerAction {
034    private final transient List<Layer> colorLayers;
035
036    /**
037     * Constructs a new {@code CustomizeColor} for a given list of layers.
038     * @param l list of layers
039     */
040    public CustomizeColor(List<Layer> l) {
041        super(tr("Customize Color"));
042        new ImageProvider("colorchooser").getResource().attachImageIcon(this, true);
043        colorLayers = l.stream().filter(Objects::nonNull).filter(Layer::hasColor).collect(Collectors.toList());
044        putValue("help", ht("/Action/LayerCustomizeColor"));
045    }
046
047    /**
048     * Constructs a new {@code CustomizeColor} for a single layer.
049     * @param l layer
050     */
051    public CustomizeColor(Layer l) {
052        this(Collections.singletonList(l));
053    }
054
055    @Override
056    public boolean supportLayers(List<Layer> layers) {
057        return layers.stream().allMatch(Layer::hasColor);
058    }
059
060    @Override
061    public Component createMenuComponent() {
062        return new JMenuItem(this);
063    }
064
065    @Override
066    public Action getMultiLayerAction(List<Layer> layers) {
067        return new CustomizeColor(layers);
068    }
069
070    @Override
071    public void actionPerformed(ActionEvent e) {
072        Color cl = colorLayers.stream().filter(Objects::nonNull).map(Layer::getColor).filter(Objects::nonNull).findAny().orElse(Color.GRAY);
073        JColorChooser c = new JColorChooser(cl);
074        Object[] options = {tr("OK"), tr("Cancel"), tr("Default")};
075        int answer = JOptionPane.showOptionDialog(
076                MainApplication.getMainFrame(),
077                c,
078                tr("Choose a color"),
079                JOptionPane.OK_CANCEL_OPTION,
080                JOptionPane.PLAIN_MESSAGE,
081                null,
082                options,
083                options[0]
084        );
085        switch (answer) {
086        case 0:
087            colorLayers.stream().forEach(l -> l.setColor(c.getColor()));
088            break;
089        case 1:
090            return;
091        case 2:
092            colorLayers.stream().forEach(l -> l.setColor(null));
093            break;
094        }
095        // TODO: Make the layer dialog listen to property change events so that this is not needed any more.
096        LayerListDialog.getInstance().repaint();
097    }
098}