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.io.IOException; 007import java.net.MalformedURLException; 008import java.net.URL; 009import java.util.List; 010 011import javax.swing.DefaultComboBoxModel; 012import javax.swing.JButton; 013import javax.swing.JCheckBox; 014import javax.swing.JComboBox; 015import javax.swing.JLabel; 016import javax.swing.JOptionPane; 017import javax.swing.JScrollPane; 018 019import org.openstreetmap.josm.Main; 020import org.openstreetmap.josm.data.imagery.ImageryInfo; 021import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser; 022import org.openstreetmap.josm.gui.util.GuiHelper; 023import org.openstreetmap.josm.gui.widgets.JosmTextArea; 024import org.openstreetmap.josm.io.imagery.WMSImagery; 025import org.openstreetmap.josm.tools.GBC; 026import org.openstreetmap.josm.tools.Utils; 027 028/** 029 * An imagery panel used to add WMS imagery sources. 030 * @since 2599 031 */ 032public class AddWMSLayerPanel extends AddImageryPanel { 033 034 private final transient WMSImagery wms = new WMSImagery(); 035 private final JCheckBox endpoint = new JCheckBox(tr("Store WMS endpoint only, select layers at usage")); 036 private final transient WMSLayerTree tree = new WMSLayerTree(); 037 private final JComboBox<String> 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(showBounds, GBC.eop().fill()); 059 060 add(new JLabel(tr("3. Select image format")), GBC.eol()); 061 add(formats, GBC.eol().fill()); 062 063 wmsInstruction = new JLabel(tr("4. Verify generated WMS URL")); 064 add(wmsInstruction, GBC.eol()); 065 wmsInstruction.setLabelFor(wmsUrl); 066 add(wmsUrl, GBC.eop().fill()); 067 wmsUrl.setLineWrap(true); 068 069 add(new JLabel(tr("5. Enter name for this layer")), GBC.eol()); 070 add(name, GBC.eop().fill()); 071 072 getLayers.addActionListener(e -> { 073 try { 074 wms.attemptGetCapabilities(rawUrl.getText()); 075 tree.updateTree(wms); 076 List<String> wmsFormats = wms.getFormats(); 077 formats.setModel(new DefaultComboBoxModel<>(wmsFormats.toArray(new String[wmsFormats.size()]))); 078 formats.setSelectedItem(wms.getPreferredFormats()); 079 } catch (MalformedURLException ex1) { 080 Main.error(ex1, false); 081 JOptionPane.showMessageDialog(getParent(), tr("Invalid service URL."), 082 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 083 } catch (IOException ex2) { 084 Main.error(ex2, false); 085 JOptionPane.showMessageDialog(getParent(), tr("Could not retrieve WMS layer list."), 086 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 087 } catch (WMSImagery.WMSGetCapabilitiesException ex3) { 088 String incomingData = ex3.getIncomingData().trim(); 089 String title = tr("WMS Error"); 090 String message = tr("Could not parse WMS layer list."); 091 Main.error(ex3, "Could not parse WMS layer list. Incoming data:\n"+incomingData); 092 if ((incomingData.startsWith("<html>") || incomingData.startsWith("<HTML>")) 093 && (incomingData.endsWith("</html>") || incomingData.endsWith("</HTML>"))) { 094 GuiHelper.notifyUserHtmlError(this, title, message, incomingData); 095 } else { 096 if (ex3.getMessage() != null) { 097 message += '\n' + ex3.getMessage(); 098 } 099 JOptionPane.showMessageDialog(getParent(), message, title, JOptionPane.ERROR_MESSAGE); 100 } 101 } 102 }); 103 104 endpoint.addItemListener(e -> { 105 tree.getLayerTree().setEnabled(!endpoint.isSelected()); 106 showBounds.setEnabled(!endpoint.isSelected()); 107 wmsInstruction.setEnabled(!endpoint.isSelected()); 108 formats.setEnabled(!endpoint.isSelected()); 109 wmsUrl.setEnabled(!endpoint.isSelected()); 110 if (endpoint.isSelected()) { 111 URL url = wms.getServiceUrl(); 112 if (url != null) { 113 name.setText(url.getHost()); 114 } 115 } else { 116 onLayerSelectionChanged(); 117 } 118 }); 119 120 tree.getLayerTree().addPropertyChangeListener("selectedLayers", evt -> onLayerSelectionChanged()); 121 122 formats.addActionListener(e -> onLayerSelectionChanged()); 123 124 showBounds.addActionListener(e -> { 125 if (tree.getSelectedLayers().get(0).bounds != null) { 126 SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser(); 127 mapPanel.setBoundingBox(tree.getSelectedLayers().get(0).bounds); 128 JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE); 129 } else { 130 JOptionPane.showMessageDialog(null, tr("No bounding box was found for this layer."), 131 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 132 } 133 }); 134 135 registerValidableComponent(endpoint); 136 registerValidableComponent(rawUrl); 137 registerValidableComponent(wmsUrl); 138 } 139 140 protected final void onLayerSelectionChanged() { 141 if (wms.getServiceUrl() != null) { 142 wmsUrl.setText(wms.buildGetMapUrl(tree.getSelectedLayers(), (String) formats.getSelectedItem())); 143 name.setText(wms.getServiceUrl().getHost() + ": " + Utils.join(", ", tree.getSelectedLayers())); 144 } 145 showBounds.setEnabled(tree.getSelectedLayers().size() == 1); 146 } 147 148 @Override 149 public ImageryInfo getImageryInfo() { 150 final ImageryInfo info; 151 if (endpoint.isSelected()) { 152 info = new ImageryInfo(getImageryName(), getImageryRawUrl()); 153 info.setImageryType(ImageryInfo.ImageryType.WMS_ENDPOINT); 154 } else { 155 info = wms.toImageryInfo(getImageryName(), tree.getSelectedLayers()); 156 info.setUrl(getWmsUrl()); 157 } 158 return info; 159 } 160 161 protected final String getWmsUrl() { 162 return sanitize(wmsUrl.getText(), ImageryInfo.ImageryType.WMS); 163 } 164 165 @Override 166 protected boolean isImageryValid() { 167 if (getImageryName().isEmpty()) { 168 return false; 169 } 170 if (endpoint.isSelected()) { 171 return !getImageryRawUrl().isEmpty(); 172 } else { 173 return !getWmsUrl().isEmpty(); 174 } 175 } 176}