001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.dialogs;
003
004import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005import static org.openstreetmap.josm.tools.I18n.tr;
006
007import java.awt.Component;
008import java.awt.Dimension;
009import java.awt.event.ActionEvent;
010import java.util.ArrayList;
011import java.util.Arrays;
012import java.util.Collections;
013import java.util.List;
014
015import javax.swing.AbstractAction;
016import javax.swing.Action;
017import javax.swing.JMenuItem;
018import javax.swing.JOptionPane;
019import javax.swing.JPopupMenu;
020
021import org.openstreetmap.josm.Main;
022import org.openstreetmap.josm.gui.ExtendedDialog;
023import org.openstreetmap.josm.gui.layer.Layer;
024import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
025import org.openstreetmap.josm.gui.layer.Layer.MultiLayerAction;
026import org.openstreetmap.josm.gui.layer.Layer.SeparatorLayerAction;
027import org.openstreetmap.josm.tools.ImageProvider;
028
029/**
030 * Popup menu handler for the layer list.
031 */
032public class LayerListPopup extends JPopupMenu {
033
034    public static final class InfoAction extends AbstractAction {
035        private final transient Layer layer;
036
037        /**
038         * Constructs a new {@code InfoAction} for the given layer.
039         * @param layer The layer
040         */
041        public InfoAction(Layer layer) {
042            super(tr("Info"), ImageProvider.get("info"));
043            putValue("help", ht("/Action/LayerInfo"));
044            this.layer = layer;
045        }
046
047        @Override
048        public void actionPerformed(ActionEvent e) {
049            Object object = layer.getInfoComponent();
050            if (object instanceof Component) {
051                ExtendedDialog ed = new ExtendedDialog(
052                        Main.parent, tr("Information about layer"),
053                        new String[] {tr("OK")});
054                ed.setButtonIcons(new String[] {"ok"});
055                ed.setIcon(JOptionPane.INFORMATION_MESSAGE);
056                ed.setContent((Component) object);
057                ed.setResizable(layer.isInfoResizable());
058                ed.setMinimumSize(new Dimension(270, 170));
059                ed.showDialog();
060            } else {
061                JOptionPane.showMessageDialog(
062                        Main.parent, object,
063                        tr("Information about layer"),
064                        JOptionPane.INFORMATION_MESSAGE
065                        );
066            }
067        }
068    }
069
070    /**
071     * Constructs a new {@code LayerListPopup}.
072     * @param selectedLayers list of selected layers
073     */
074    public LayerListPopup(List<Layer> selectedLayers) {
075
076        List<Action> actions;
077        if (selectedLayers.size() == 1) {
078            Action[] entries = selectedLayers.get(0).getMenuEntries();
079            actions = entries != null ? Arrays.asList(entries) : Collections.emptyList();
080        } else {
081            // Very simple algorithm - first selected layer has actions order as in getMenuEntries, actions from other layers go to the end
082            actions = new ArrayList<>();
083            boolean separatorAdded = true;
084            for (Action a: selectedLayers.get(0).getMenuEntries()) {
085                if (!separatorAdded && a instanceof SeparatorLayerAction) {
086                    separatorAdded = true;
087                    actions.add(a);
088                } else if (a instanceof LayerAction && ((LayerAction) a).supportLayers(selectedLayers)) {
089                    separatorAdded = false;
090                    if (a instanceof MultiLayerAction)
091                        a = ((MultiLayerAction) a).getMultiLayerAction(selectedLayers);
092                    actions.add(a);
093                }
094            }
095            // This will usually add no action, because if some action support all selected layers then it was probably used also in first layer
096            for (int i = 1; i < selectedLayers.size(); i++) {
097                separatorAdded = false;
098                for (Action a: selectedLayers.get(i).getMenuEntries()) {
099                    if (a instanceof LayerAction && !(a instanceof MultiLayerAction)
100                    && ((LayerAction) a).supportLayers(selectedLayers) && !actions.contains(a)) {
101                        if (!separatorAdded) {
102                            separatorAdded = true;
103                            actions.add(SeparatorLayerAction.INSTANCE);
104                        }
105                        actions.add(a);
106                    }
107                }
108            }
109        }
110        if (!actions.isEmpty() && actions.get(actions.size() - 1) instanceof SeparatorLayerAction) {
111            actions.remove(actions.size() - 1);
112        }
113        for (Action a : actions) {
114            if (a instanceof LayerAction) {
115                add(((LayerAction) a).createMenuComponent());
116            } else {
117                add(new JMenuItem(a));
118            }
119        }
120    }
121}