001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.preferences.imagery;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.event.ActionEvent;
007import java.awt.event.ActionListener;
008import java.awt.event.ItemEvent;
009import java.awt.event.ItemListener;
010import java.beans.PropertyChangeEvent;
011import java.beans.PropertyChangeListener;
012import java.io.IOException;
013import java.net.MalformedURLException;
014import java.net.URL;
015
016import javax.swing.DefaultComboBoxModel;
017import javax.swing.JButton;
018import javax.swing.JCheckBox;
019import javax.swing.JComboBox;
020import javax.swing.JLabel;
021import javax.swing.JOptionPane;
022import javax.swing.JScrollPane;
023
024import org.openstreetmap.josm.Main;
025import org.openstreetmap.josm.data.imagery.ImageryInfo;
026import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
027import org.openstreetmap.josm.gui.widgets.JosmTextArea;
028import org.openstreetmap.josm.io.imagery.WMSImagery;
029import org.openstreetmap.josm.tools.GBC;
030import org.openstreetmap.josm.tools.Utils;
031
032public class AddWMSLayerPanel extends AddImageryPanel {
033
034    private final WMSImagery wms = new WMSImagery();
035    private final JCheckBox endpoint = new JCheckBox(tr("Store WMS endpoint only, select layers at usage"));
036    private final WMSLayerTree tree = new WMSLayerTree();
037    private final JComboBox formats = new JComboBox();
038    private final JLabel wmsInstruction;
039    private final JosmTextArea wmsUrl = new JosmTextArea(3, 40);
040    private final JButton showBounds = new JButton(tr("Show bounds"));
041
042    /**
043     * Constructs a new {@code AddWMSLayerPanel}.
044     */
045    public AddWMSLayerPanel() {
046
047        add(new JLabel(tr("1. Enter service URL")), GBC.eol());
048        add(rawUrl, GBC.eol().fill());
049        rawUrl.setLineWrap(true);
050        JButton getLayers = new JButton(tr("Get layers"));
051        add(getLayers, GBC.eop().fill());
052
053        add(new JLabel(tr("2. Select layers")), GBC.eol());
054        add(endpoint, GBC.eol().fill());
055        add(new JScrollPane(tree.getLayerTree()), GBC.eol().fill().weight(1, 100));
056
057        showBounds.setEnabled(false);
058        add(new JScrollPane(showBounds), GBC.eop().fill());
059
060        add(new JLabel(tr("3. Select image format")), GBC.eol());
061        add(formats, GBC.eol().fill());
062
063        add(wmsInstruction = new JLabel(tr("4. Verify generated WMS URL")), GBC.eol());
064        add(wmsUrl, GBC.eop().fill());
065        wmsUrl.setLineWrap(true);
066
067        add(new JLabel(tr("5. Enter name for this layer")), GBC.eol());
068        add(name, GBC.eop().fill());
069
070        getLayers.addActionListener(new ActionListener() {
071            @Override
072            public void actionPerformed(ActionEvent e) {
073                try {
074                    wms.attemptGetCapabilities(rawUrl.getText());
075                    tree.updateTree(wms);
076                    formats.setModel(new DefaultComboBoxModel(wms.getFormats().toArray()));
077                } catch (MalformedURLException ex) {
078                    JOptionPane.showMessageDialog(getParent(), tr("Invalid service URL."),
079                            tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
080                } catch (IOException ex) {
081                    JOptionPane.showMessageDialog(getParent(), tr("Could not retrieve WMS layer list."),
082                            tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
083                } catch (WMSImagery.WMSGetCapabilitiesException ex) {
084                    JOptionPane.showMessageDialog(getParent(), tr("Could not parse WMS layer list."),
085                            tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
086                    Main.error("Could not parse WMS layer list. Incoming data:\n"+ex.getIncomingData());
087                }
088            }
089        });
090
091        endpoint.addItemListener(new ItemListener() {
092            @Override
093            public void itemStateChanged(ItemEvent e) {
094                tree.getLayerTree().setEnabled(!endpoint.isSelected());
095                showBounds.setEnabled(!endpoint.isSelected());
096                wmsInstruction.setEnabled(!endpoint.isSelected());
097                formats.setEnabled(!endpoint.isSelected());
098                wmsUrl.setEnabled(!endpoint.isSelected());
099                if (endpoint.isSelected()) {
100                    URL url = wms.getServiceUrl();
101                    if (url != null) {
102                        name.setText(url.getHost());
103                    }
104                } else {
105                    onLayerSelectionChanged();
106                }
107            }
108        });
109
110        tree.getLayerTree().addPropertyChangeListener("selectedLayers", new PropertyChangeListener() {
111            @Override
112            public void propertyChange(PropertyChangeEvent evt) {
113                onLayerSelectionChanged();
114            }
115        });
116
117        formats.addActionListener(new ActionListener() {
118            @Override
119            public void actionPerformed(ActionEvent e) {
120                onLayerSelectionChanged();
121            }
122        });
123
124        showBounds.addActionListener(new ActionListener() {
125            @Override
126            public void actionPerformed(ActionEvent e) {
127                if (tree.getSelectedLayers().get(0).bounds != null) {
128                    SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser();
129                    mapPanel.setBoundingBox(tree.getSelectedLayers().get(0).bounds);
130                    JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE);
131                } else {
132                    JOptionPane.showMessageDialog(null, tr("No bounding box was found for this layer."),
133                            tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
134                }
135            }
136        });
137
138        registerValidableComponent(endpoint);
139        registerValidableComponent(rawUrl);
140        registerValidableComponent(wmsUrl);
141    }
142
143    protected final void onLayerSelectionChanged() {
144        if (wms.getServiceUrl() != null) {
145            wmsUrl.setText(wms.buildGetMapUrl(tree.getSelectedLayers(), (String) formats.getSelectedItem()));
146            name.setText(wms.getServiceUrl().getHost() + ": " + Utils.join(", ", tree.getSelectedLayers()));
147        }
148        showBounds.setEnabled(tree.getSelectedLayers().size() == 1);
149    }
150
151    @Override
152    public ImageryInfo getImageryInfo() {
153        final ImageryInfo info;
154        if (endpoint.isSelected()) {
155            info = new ImageryInfo(getImageryName(), getImageryRawUrl());
156            info.setImageryType(ImageryInfo.ImageryType.WMS_ENDPOINT);
157        } else {
158            info = wms.toImageryInfo(getImageryName(), tree.getSelectedLayers());
159            info.setUrl(getWmsUrl());
160        }
161        return info;
162    }
163
164    protected final String getWmsUrl() {
165        return sanitize(wmsUrl.getText());
166    }
167
168    @Override
169    protected boolean isImageryValid() {
170        if (getImageryName().isEmpty()) {
171            return false;
172        }
173        if (endpoint.isSelected()) {
174            return !getImageryRawUrl().isEmpty();
175        } else {
176            return !getWmsUrl().isEmpty();
177        }
178    }
179}