001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.actions;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Dimension;
007import java.awt.GridBagLayout;
008import java.awt.event.ActionEvent;
009import java.io.IOException;
010import java.net.MalformedURLException;
011
012import javax.swing.Action;
013import javax.swing.ImageIcon;
014import javax.swing.JComboBox;
015import javax.swing.JOptionPane;
016import javax.swing.JPanel;
017import javax.swing.JScrollPane;
018
019import org.openstreetmap.josm.Main;
020import org.openstreetmap.josm.data.imagery.ImageryInfo;
021import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
022import org.openstreetmap.josm.gui.ExtendedDialog;
023import org.openstreetmap.josm.gui.actionsupport.AlignImageryPanel;
024import org.openstreetmap.josm.gui.layer.ImageryLayer;
025import org.openstreetmap.josm.gui.preferences.imagery.WMSLayerTree;
026import org.openstreetmap.josm.gui.util.GuiHelper;
027import org.openstreetmap.josm.io.imagery.WMSImagery;
028import org.openstreetmap.josm.tools.GBC;
029import org.openstreetmap.josm.tools.ImageProvider;
030import org.openstreetmap.josm.tools.ImageProvider.ImageCallback;
031
032/**
033 * Action displayed in imagery menu to add a new imagery layer.
034 * @since 3715
035 */
036public class AddImageryLayerAction extends JosmAction implements AdaptableAction {
037
038    private static final int MAX_ICON_SIZE = 24;
039    private final ImageryInfo info;
040
041    /**
042     * Constructs a new {@code AddImageryLayerAction} for the given {@code ImageryInfo}.
043     * If an http:// icon is specified, it is fetched asynchronously.
044     * @param info The imagery info
045     */
046    public AddImageryLayerAction(ImageryInfo info) {
047        super(info.getMenuName(), /* ICON */"imagery_menu", tr("Add imagery layer {0}",info.getName()), null, false, false);
048        putValue("toolbar", "imagery_" + info.getToolbarName());
049        this.info = info;
050        installAdapters();
051
052        // change toolbar icon from if specified
053        try {
054            if (info.getIcon() != null) {
055                new ImageProvider(info.getIcon()).setOptional(true).
056                        setMaxHeight(MAX_ICON_SIZE).setMaxWidth(MAX_ICON_SIZE).getInBackground(new ImageCallback() {
057                            @Override
058                            public void finished(final ImageIcon result) {
059                                if (result != null) {
060                                    GuiHelper.runInEDT(new Runnable() {
061                                        @Override
062                                        public void run() {
063                                            putValue(Action.SMALL_ICON, result);
064                                        }
065                                    });
066                                }
067                            }
068                        });
069            }
070        } catch (Exception ex) {
071            throw new RuntimeException(ex.getMessage(), ex);
072        }
073    }
074
075    @Override
076    public void actionPerformed(ActionEvent e) {
077        if (!isEnabled()) return;
078        try {
079            final ImageryInfo infoToAdd = ImageryType.WMS_ENDPOINT.equals(info.getImageryType())
080                    ? getWMSLayerInfo() : info;
081            if (infoToAdd != null) {
082                Main.main.addLayer(ImageryLayer.create(infoToAdd));
083                AlignImageryPanel.addNagPanelIfNeeded();
084            }
085        } catch (IllegalArgumentException ex) {
086            if (ex.getMessage() == null || ex.getMessage().isEmpty()) {
087                throw ex;
088            } else {
089                JOptionPane.showMessageDialog(Main.parent,
090                        ex.getMessage(), tr("Error"),
091                        JOptionPane.ERROR_MESSAGE);
092            }
093        }
094    }
095
096    protected ImageryInfo getWMSLayerInfo() {
097        try {
098            assert (ImageryType.WMS_ENDPOINT.equals(info.getImageryType()));
099            final WMSImagery wms = new WMSImagery();
100            wms.attemptGetCapabilities(info.getUrl());
101
102            final WMSLayerTree tree = new WMSLayerTree();
103            tree.updateTree(wms);
104            final JComboBox<String> formats = new JComboBox<>(wms.getFormats().toArray(new String[0]));
105            formats.setSelectedItem(wms.getPreferredFormats());
106            formats.setToolTipText(tr("Select image format for WMS layer"));
107
108            if (1 != new ExtendedDialog(Main.parent, tr("Select WMS layers"), new String[]{tr("Add layers"), tr("Cancel")}) {{
109                final JScrollPane scrollPane = new JScrollPane(tree.getLayerTree());
110                scrollPane.setPreferredSize(new Dimension(400, 400));
111                final JPanel panel = new JPanel(new GridBagLayout());
112                panel.add(scrollPane, GBC.eol().fill());
113                panel.add(formats, GBC.eol().fill(GBC.HORIZONTAL));
114                setContent(panel);
115            }}.showDialog().getValue()) {
116                return null;
117            }
118
119            final String url = wms.buildGetMapUrl(
120                    tree.getSelectedLayers(), (String) formats.getSelectedItem());
121            return new ImageryInfo(info.getName(), url, "wms", info.getEulaAcceptanceRequired(), info.getCookies());
122        } // exception handling from AddWMSLayerPanel.java
123        catch (MalformedURLException ex) {
124            JOptionPane.showMessageDialog(Main.parent, tr("Invalid service URL."),
125                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
126        } catch (IOException ex) {
127            JOptionPane.showMessageDialog(Main.parent, tr("Could not retrieve WMS layer list."),
128                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
129        } catch (WMSImagery.WMSGetCapabilitiesException ex) {
130            JOptionPane.showMessageDialog(Main.parent, tr("Could not parse WMS layer list."),
131                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
132            Main.error("Could not parse WMS layer list. Incoming data:\n"+ex.getIncomingData());
133        }
134        return null;
135    }
136
137    protected boolean isLayerAlreadyPresent() {
138        if (Main.isDisplayingMapView()) {
139            for (ImageryLayer layer : Main.map.mapView.getLayersOfType(ImageryLayer.class)) {
140                if (info.equals(layer.getInfo())) {
141                    return true;
142                }
143            }
144        }
145        return false;
146    }
147
148    @Override
149    protected void updateEnabledState() {
150        // never enable blacklisted entries. Do not add same imagery layer twice (fix #2519)
151        if (info.isBlacklisted() /*|| isLayerAlreadyPresent()*/) { // FIXME check disabled to allow several instances with different settings (see #7981)
152            setEnabled(false);
153        } else if (info.getImageryType() == ImageryType.TMS || info.getImageryType() == ImageryType.BING || info.getImageryType() == ImageryType.SCANEX) {
154            setEnabled(true);
155        } else if (Main.isDisplayingMapView() && !Main.map.mapView.getAllLayers().isEmpty()) {
156            setEnabled(true);
157        } else {
158            setEnabled(false);
159        }
160    }
161}