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 add(wmsInstruction = new JLabel(tr("4. Verify generated WMS URL")), GBC.eol()); 069 wmsInstruction.setLabelFor(wmsUrl); 070 add(wmsUrl, GBC.eop().fill()); 071 wmsUrl.setLineWrap(true); 072 073 add(new JLabel(tr("5. Enter name for this layer")), GBC.eol()); 074 add(name, GBC.eop().fill()); 075 076 getLayers.addActionListener(new ActionListener() { 077 @Override 078 public void actionPerformed(ActionEvent e) { 079 try { 080 wms.attemptGetCapabilities(rawUrl.getText()); 081 tree.updateTree(wms); 082 formats.setModel(new DefaultComboBoxModel<>(wms.getFormats().toArray(new String[0]))); 083 formats.setSelectedItem(wms.getPreferredFormats()); 084 } catch (MalformedURLException ex) { 085 JOptionPane.showMessageDialog(getParent(), tr("Invalid service URL."), 086 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 087 } catch (IOException ex) { 088 JOptionPane.showMessageDialog(getParent(), tr("Could not retrieve WMS layer list."), 089 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 090 } catch (WMSImagery.WMSGetCapabilitiesException ex) { 091 String incomingData = ex.getIncomingData().trim(); 092 String title = tr("WMS Error"); 093 String message = tr("Could not parse WMS layer list."); 094 Main.error("Could not parse WMS layer list. Incoming data:\n"+incomingData); 095 if (incomingData != null 096 && (incomingData.startsWith("<html>") || incomingData.startsWith("<HTML>")) 097 && (incomingData.endsWith("</html>") || incomingData.endsWith("</HTML>"))) { 098 GuiHelper.notifyUserHtmlError(AddWMSLayerPanel.this, title, message, incomingData); 099 } else { 100 JOptionPane.showMessageDialog(getParent(), message, title, JOptionPane.ERROR_MESSAGE); 101 } 102 } 103 } 104 }); 105 106 endpoint.addItemListener(new ItemListener() { 107 @Override 108 public void itemStateChanged(ItemEvent e) { 109 tree.getLayerTree().setEnabled(!endpoint.isSelected()); 110 showBounds.setEnabled(!endpoint.isSelected()); 111 wmsInstruction.setEnabled(!endpoint.isSelected()); 112 formats.setEnabled(!endpoint.isSelected()); 113 wmsUrl.setEnabled(!endpoint.isSelected()); 114 if (endpoint.isSelected()) { 115 URL url = wms.getServiceUrl(); 116 if (url != null) { 117 name.setText(url.getHost()); 118 } 119 } else { 120 onLayerSelectionChanged(); 121 } 122 } 123 }); 124 125 tree.getLayerTree().addPropertyChangeListener("selectedLayers", new PropertyChangeListener() { 126 @Override 127 public void propertyChange(PropertyChangeEvent evt) { 128 onLayerSelectionChanged(); 129 } 130 }); 131 132 formats.addActionListener(new ActionListener() { 133 @Override 134 public void actionPerformed(ActionEvent e) { 135 onLayerSelectionChanged(); 136 } 137 }); 138 139 showBounds.addActionListener(new ActionListener() { 140 @Override 141 public void actionPerformed(ActionEvent e) { 142 if (tree.getSelectedLayers().get(0).bounds != null) { 143 SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser(); 144 mapPanel.setBoundingBox(tree.getSelectedLayers().get(0).bounds); 145 JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE); 146 } else { 147 JOptionPane.showMessageDialog(null, tr("No bounding box was found for this layer."), 148 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 149 } 150 } 151 }); 152 153 registerValidableComponent(endpoint); 154 registerValidableComponent(rawUrl); 155 registerValidableComponent(wmsUrl); 156 } 157 158 protected final void onLayerSelectionChanged() { 159 if (wms.getServiceUrl() != null) { 160 wmsUrl.setText(wms.buildGetMapUrl(tree.getSelectedLayers(), (String) formats.getSelectedItem())); 161 name.setText(wms.getServiceUrl().getHost() + ": " + Utils.join(", ", tree.getSelectedLayers())); 162 } 163 showBounds.setEnabled(tree.getSelectedLayers().size() == 1); 164 } 165 166 @Override 167 public ImageryInfo getImageryInfo() { 168 final ImageryInfo info; 169 if (endpoint.isSelected()) { 170 info = new ImageryInfo(getImageryName(), getImageryRawUrl()); 171 info.setImageryType(ImageryInfo.ImageryType.WMS_ENDPOINT); 172 } else { 173 info = wms.toImageryInfo(getImageryName(), tree.getSelectedLayers()); 174 info.setUrl(getWmsUrl()); 175 } 176 return info; 177 } 178 179 protected final String getWmsUrl() { 180 return sanitize(wmsUrl.getText(), ImageryInfo.ImageryType.WMS); 181 } 182 183 @Override 184 protected boolean isImageryValid() { 185 if (getImageryName().isEmpty()) { 186 return false; 187 } 188 if (endpoint.isSelected()) { 189 return !getImageryRawUrl().isEmpty(); 190 } else { 191 return !getWmsUrl().isEmpty(); 192 } 193 } 194}