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.util.GuiHelper;
028import org.openstreetmap.josm.gui.widgets.JosmTextArea;
029import org.openstreetmap.josm.io.imagery.WMSImagery;
030import org.openstreetmap.josm.tools.GBC;
031import org.openstreetmap.josm.tools.Utils;
032
033/**
034 * An imagery panel used to add WMS imagery sources.
035 * @since 2599
036 */
037public class AddWMSLayerPanel extends AddImageryPanel {
038
039    private final transient WMSImagery wms = new WMSImagery();
040    private final JCheckBox endpoint = new JCheckBox(tr("Store WMS endpoint only, select layers at usage"));
041    private final transient WMSLayerTree tree = new WMSLayerTree();
042    private final JComboBox<String> formats = new JComboBox<>();
043    private final JLabel wmsInstruction;
044    private final JosmTextArea wmsUrl = new JosmTextArea(3, 40);
045    private final JButton showBounds = new JButton(tr("Show bounds"));
046
047    /**
048     * Constructs a new {@code AddWMSLayerPanel}.
049     */
050    public AddWMSLayerPanel() {
051
052        add(new JLabel(tr("1. Enter service URL")), GBC.eol());
053        add(rawUrl, GBC.eol().fill());
054        rawUrl.setLineWrap(true);
055        JButton getLayers = new JButton(tr("Get layers"));
056        add(getLayers, GBC.eop().fill());
057
058        add(new JLabel(tr("2. Select layers")), GBC.eol());
059        add(endpoint, GBC.eol().fill());
060        add(new JScrollPane(tree.getLayerTree()), GBC.eol().fill().weight(1, 100));
061
062        showBounds.setEnabled(false);
063        add(showBounds, GBC.eop().fill());
064
065        add(new JLabel(tr("3. Select image format")), GBC.eol());
066        add(formats, GBC.eol().fill());
067
068        wmsInstruction = new JLabel(tr("4. Verify generated WMS URL"));
069        add(wmsInstruction, GBC.eol());
070        wmsInstruction.setLabelFor(wmsUrl);
071        add(wmsUrl, GBC.eop().fill());
072        wmsUrl.setLineWrap(true);
073
074        add(new JLabel(tr("5. Enter name for this layer")), GBC.eol());
075        add(name, GBC.eop().fill());
076
077        getLayers.addActionListener(new ActionListener() {
078            @Override
079            public void actionPerformed(ActionEvent e) {
080                try {
081                    wms.attemptGetCapabilities(rawUrl.getText());
082                    tree.updateTree(wms);
083                    formats.setModel(new DefaultComboBoxModel<>(wms.getFormats().toArray(new String[0])));
084                    formats.setSelectedItem(wms.getPreferredFormats());
085                } catch (MalformedURLException ex) {
086                    JOptionPane.showMessageDialog(getParent(), tr("Invalid service URL."),
087                            tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
088                } catch (IOException ex) {
089                    JOptionPane.showMessageDialog(getParent(), tr("Could not retrieve WMS layer list."),
090                            tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
091                } catch (WMSImagery.WMSGetCapabilitiesException ex) {
092                    String incomingData = ex.getIncomingData().trim();
093                    String title = tr("WMS Error");
094                    String message = tr("Could not parse WMS layer list.");
095                    Main.error("Could not parse WMS layer list. Incoming data:\n"+incomingData);
096                    if (incomingData != null
097                            && (incomingData.startsWith("<html>") || incomingData.startsWith("<HTML>"))
098                            && (incomingData.endsWith("</html>") || incomingData.endsWith("</HTML>"))) {
099                        GuiHelper.notifyUserHtmlError(AddWMSLayerPanel.this, title, message, incomingData);
100                    } else {
101                        JOptionPane.showMessageDialog(getParent(), message, title, JOptionPane.ERROR_MESSAGE);
102                    }
103                }
104            }
105        });
106
107        endpoint.addItemListener(new ItemListener() {
108            @Override
109            public void itemStateChanged(ItemEvent e) {
110                tree.getLayerTree().setEnabled(!endpoint.isSelected());
111                showBounds.setEnabled(!endpoint.isSelected());
112                wmsInstruction.setEnabled(!endpoint.isSelected());
113                formats.setEnabled(!endpoint.isSelected());
114                wmsUrl.setEnabled(!endpoint.isSelected());
115                if (endpoint.isSelected()) {
116                    URL url = wms.getServiceUrl();
117                    if (url != null) {
118                        name.setText(url.getHost());
119                    }
120                } else {
121                    onLayerSelectionChanged();
122                }
123            }
124        });
125
126        tree.getLayerTree().addPropertyChangeListener("selectedLayers", new PropertyChangeListener() {
127            @Override
128            public void propertyChange(PropertyChangeEvent evt) {
129                onLayerSelectionChanged();
130            }
131        });
132
133        formats.addActionListener(new ActionListener() {
134            @Override
135            public void actionPerformed(ActionEvent e) {
136                onLayerSelectionChanged();
137            }
138        });
139
140        showBounds.addActionListener(new ActionListener() {
141            @Override
142            public void actionPerformed(ActionEvent e) {
143                if (tree.getSelectedLayers().get(0).bounds != null) {
144                    SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser();
145                    mapPanel.setBoundingBox(tree.getSelectedLayers().get(0).bounds);
146                    JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE);
147                } else {
148                    JOptionPane.showMessageDialog(null, tr("No bounding box was found for this layer."),
149                            tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
150                }
151            }
152        });
153
154        registerValidableComponent(endpoint);
155        registerValidableComponent(rawUrl);
156        registerValidableComponent(wmsUrl);
157    }
158
159    protected final void onLayerSelectionChanged() {
160        if (wms.getServiceUrl() != null) {
161            wmsUrl.setText(wms.buildGetMapUrl(tree.getSelectedLayers(), (String) formats.getSelectedItem()));
162            name.setText(wms.getServiceUrl().getHost() + ": " + Utils.join(", ", tree.getSelectedLayers()));
163        }
164        showBounds.setEnabled(tree.getSelectedLayers().size() == 1);
165    }
166
167    @Override
168    public ImageryInfo getImageryInfo() {
169        final ImageryInfo info;
170        if (endpoint.isSelected()) {
171            info = new ImageryInfo(getImageryName(), getImageryRawUrl());
172            info.setImageryType(ImageryInfo.ImageryType.WMS_ENDPOINT);
173        } else {
174            info = wms.toImageryInfo(getImageryName(), tree.getSelectedLayers());
175            info.setUrl(getWmsUrl());
176        }
177        return info;
178    }
179
180    protected final String getWmsUrl() {
181        return sanitize(wmsUrl.getText(), ImageryInfo.ImageryType.WMS);
182    }
183
184    @Override
185    protected boolean isImageryValid() {
186        if (getImageryName().isEmpty()) {
187            return false;
188        }
189        if (endpoint.isSelected()) {
190            return !getImageryRawUrl().isEmpty();
191        } else {
192            return !getWmsUrl().isEmpty();
193        }
194    }
195}