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.data.imagery.ImageryInfo; 020import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType; 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.Logging; 027import org.openstreetmap.josm.tools.Utils; 028 029/** 030 * An imagery panel used to add WMS imagery sources. 031 * @since 2599 032 */ 033public class AddWMSLayerPanel extends AddImageryPanel { 034 035 private final transient WMSImagery wms = new WMSImagery(); 036 private final JCheckBox endpoint = new JCheckBox(tr("Store WMS endpoint only, select layers at usage")); 037 private final transient WMSLayerTree tree = new WMSLayerTree(); 038 private final JComboBox<String> formats = new JComboBox<>(); 039 private final JLabel wmsInstruction; 040 private final JosmTextArea wmsUrl = new JosmTextArea(3, 40).transferFocusOnTab(); 041 private final JButton showBounds = new JButton(tr("Show bounds")); 042 043 /** 044 * Constructs a new {@code AddWMSLayerPanel}. 045 */ 046 public AddWMSLayerPanel() { 047 048 add(new JLabel(tr("{0} Make sure OSM has the permission to use this service", "1.")), GBC.eol()); 049 add(new JLabel(tr("{0} Enter GetCapabilities URL", "2.")), GBC.eol()); 050 add(rawUrl, GBC.eol().fill()); 051 rawUrl.setLineWrap(true); 052 JButton getLayers = new JButton(tr("{0} Get layers", "3.")); 053 add(getLayers, GBC.eop().fill()); 054 055 add(new JLabel(tr("{0} Select layers", "4.")), GBC.eol()); 056 add(endpoint, GBC.eol().fill()); 057 add(new JScrollPane(tree.getLayerTree()), GBC.eol().fill().weight(1, 100)); 058 059 showBounds.setEnabled(false); 060 add(showBounds, GBC.eop().fill()); 061 062 add(new JLabel(tr("{0} Select image format", "5.")), GBC.eol()); 063 add(formats, GBC.eol().fill()); 064 065 wmsInstruction = new JLabel(tr("{0} Edit generated {1} URL (optional)", "6.", "WMS")); 066 add(wmsInstruction, GBC.eol()); 067 wmsInstruction.setLabelFor(wmsUrl); 068 add(wmsUrl, GBC.eop().fill()); 069 wmsUrl.setLineWrap(true); 070 071 add(new JLabel(tr("{0} Enter name for this layer", "7.")), GBC.eol()); 072 add(name, GBC.eop().fill()); 073 074 getLayers.addActionListener(e -> { 075 try { 076 wms.attemptGetCapabilities(rawUrl.getText()); 077 tree.updateTree(wms); 078 List<String> wmsFormats = wms.getFormats(); 079 formats.setModel(new DefaultComboBoxModel<>(wmsFormats.toArray(new String[0]))); 080 formats.setSelectedItem(wms.getPreferredFormats()); 081 } catch (MalformedURLException ex1) { 082 Logging.log(Logging.LEVEL_ERROR, ex1); 083 JOptionPane.showMessageDialog(getParent(), tr("Invalid service URL."), 084 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 085 } catch (IOException ex2) { 086 Logging.log(Logging.LEVEL_ERROR, ex2); 087 JOptionPane.showMessageDialog(getParent(), tr("Could not retrieve WMS layer list."), 088 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 089 } catch (WMSImagery.WMSGetCapabilitiesException ex3) { 090 String incomingData = ex3.getIncomingData() != null ? ex3.getIncomingData().trim() : ""; 091 String title = tr("WMS Error"); 092 StringBuilder message = new StringBuilder(tr("Could not parse WMS layer list.")); 093 Logging.log(Logging.LEVEL_ERROR, "Could not parse WMS layer list. Incoming data:\n"+incomingData, ex3); 094 if ((incomingData.startsWith("<html>") || incomingData.startsWith("<HTML>")) 095 && (incomingData.endsWith("</html>") || incomingData.endsWith("</HTML>"))) { 096 GuiHelper.notifyUserHtmlError(this, title, message.toString(), incomingData); 097 } else { 098 if (ex3.getMessage() != null) { 099 message.append('\n').append(ex3.getMessage()); 100 } 101 JOptionPane.showMessageDialog(getParent(), message.toString(), title, JOptionPane.ERROR_MESSAGE); 102 } 103 } 104 }); 105 106 endpoint.addItemListener(e -> { 107 tree.getLayerTree().setEnabled(!endpoint.isSelected()); 108 showBounds.setEnabled(!endpoint.isSelected()); 109 wmsInstruction.setEnabled(!endpoint.isSelected()); 110 formats.setEnabled(!endpoint.isSelected()); 111 wmsUrl.setEnabled(!endpoint.isSelected()); 112 if (endpoint.isSelected()) { 113 URL url = wms.getServiceUrl(); 114 if (url != null) { 115 name.setText(url.getHost()); 116 } 117 } else { 118 onLayerSelectionChanged(); 119 } 120 }); 121 122 tree.getLayerTree().addPropertyChangeListener("selectedLayers", evt -> onLayerSelectionChanged()); 123 124 formats.addActionListener(e -> onLayerSelectionChanged()); 125 126 showBounds.addActionListener(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 registerValidableComponent(endpoint); 138 registerValidableComponent(rawUrl); 139 registerValidableComponent(wmsUrl); 140 } 141 142 protected final void onLayerSelectionChanged() { 143 if (wms.getServiceUrl() != null) { 144 wmsUrl.setText(wms.buildGetMapUrl(tree.getSelectedLayers(), (String) formats.getSelectedItem())); 145 name.setText(wms.getServiceUrl().getHost() + ": " + Utils.join(", ", tree.getSelectedLayers())); 146 } 147 showBounds.setEnabled(tree.getSelectedLayers().size() == 1); 148 } 149 150 @Override 151 public ImageryInfo getImageryInfo() { 152 final ImageryInfo info; 153 if (endpoint.isSelected()) { 154 info = new ImageryInfo(getImageryName(), getImageryRawUrl()); 155 info.setImageryType(ImageryInfo.ImageryType.WMS_ENDPOINT); 156 } else { 157 info = wms.toImageryInfo(getImageryName(), tree.getSelectedLayers()); 158 info.setUrl(getWmsUrl()); 159 info.setImageryType(ImageryType.WMS); 160 } 161 return info; 162 } 163 164 protected final String getWmsUrl() { 165 return sanitize(wmsUrl.getText(), ImageryInfo.ImageryType.WMS); 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}