Ticket #13868: 13868.patch
| File 13868.patch, 21.1 KB (added by , 9 years ago) |
|---|
-
src/org/openstreetmap/josm/actions/AddImageryLayerAction.java
10 10 import java.awt.event.ActionEvent; 11 11 import java.io.IOException; 12 12 import java.net.MalformedURLException; 13 import java.util.ArrayList; 14 import java.util.Collection; 13 15 import java.util.HashSet; 14 16 import java.util.List; 15 17 import java.util.Set; … … 22 24 import org.openstreetmap.josm.Main; 23 25 import org.openstreetmap.josm.data.imagery.ImageryInfo; 24 26 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType; 27 import org.openstreetmap.josm.data.imagery.WMTSTileSource; 25 28 import org.openstreetmap.josm.gui.ExtendedDialog; 26 29 import org.openstreetmap.josm.gui.layer.AlignImageryPanel; 27 30 import org.openstreetmap.josm.gui.layer.ImageryLayer; … … 30 33 import org.openstreetmap.josm.io.imagery.WMSImagery; 31 34 import org.openstreetmap.josm.io.imagery.WMSImagery.LayerDetails; 32 35 import org.openstreetmap.josm.io.imagery.WMSImagery.WMSGetCapabilitiesException; 36 import org.openstreetmap.josm.tools.CheckParameterUtil; 33 37 import org.openstreetmap.josm.tools.GBC; 34 38 import org.openstreetmap.josm.tools.ImageProvider; 35 39 … … 63 67 } 64 68 } 65 69 70 /** 71 * Converts general ImageryInfo to specific one, that does not need any user action to initialize 72 * see: https://josm.openstreetmap.de/ticket/13868 73 * @param info 74 * @return 75 */ 76 private ImageryInfo convertImagery(ImageryInfo info) { 77 try { 78 switch(info.getImageryType()) { 79 case WMS_ENDPOINT: 80 // convert to WMS type 81 return getWMSLayerInfo(); 82 case WMTS: 83 // specify which layer to use 84 String layerId = new WMTSTileSource(info).userSelectLayer(); 85 if (layerId != null) { 86 ImageryInfo copy = new ImageryInfo(info); 87 Collection<String> defaultLayers = new ArrayList<>(1); 88 defaultLayers.add(layerId); 89 copy.setDefaultLayers(defaultLayers); 90 return copy; 91 } 92 // layer not selected - refuse to add 93 return null; 94 default: 95 return info; 96 } 97 } catch (MalformedURLException ex) { 98 if (!GraphicsEnvironment.isHeadless()) { 99 JOptionPane.showMessageDialog(Main.parent, tr("Invalid service URL."), 100 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 101 } 102 Main.error(ex, false); 103 } catch (IOException ex) { 104 if (!GraphicsEnvironment.isHeadless()) { 105 JOptionPane.showMessageDialog(Main.parent, tr("Could not retrieve WMS layer list."), 106 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 107 } 108 Main.error(ex, false); 109 } catch (WMSGetCapabilitiesException ex) { 110 if (!GraphicsEnvironment.isHeadless()) { 111 JOptionPane.showMessageDialog(Main.parent, tr("Could not parse WMS layer list."), 112 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 113 } 114 Main.error(ex, "Could not parse WMS layer list. Incoming data:\n"+ex.getIncomingData()); 115 } 116 return null; 117 } 118 66 119 @Override 67 120 public void actionPerformed(ActionEvent e) { 68 121 if (!isEnabled()) return; 69 122 try { 70 final ImageryInfo infoToAdd = ImageryType.WMS_ENDPOINT.equals(info.getImageryType()) 71 ? getWMSLayerInfo() : info; 123 final ImageryInfo infoToAdd = convertImagery(info); 72 124 if (infoToAdd != null) { 73 125 Main.getLayerManager().addLayer(ImageryLayer.create(infoToAdd)); 74 126 AlignImageryPanel.addNagPanelIfNeeded(infoToAdd); … … 84 136 } 85 137 } 86 138 87 protected ImageryInfo getWMSLayerInfo() { 88 try { 89 assert ImageryType.WMS_ENDPOINT.equals(info.getImageryType()); 90 final WMSImagery wms = new WMSImagery(); 91 wms.attemptGetCapabilities(info.getUrl()); 139 protected ImageryInfo getWMSLayerInfo() throws IOException, WMSGetCapabilitiesException { 140 CheckParameterUtil.ensureThat(ImageryType.WMS_ENDPOINT.equals(info.getImageryType()), "wms_endpoint imagery type expected"); 92 141 93 final WMSLayerTree tree = new WMSLayerTree(); 94 tree.updateTree(wms); 95 List<String> wmsFormats = wms.getFormats(); 96 final JComboBox<String> formats = new JComboBox<>(wmsFormats.toArray(new String[wmsFormats.size()])); 97 formats.setSelectedItem(wms.getPreferredFormats()); 98 formats.setToolTipText(tr("Select image format for WMS layer")); 142 final WMSImagery wms = new WMSImagery(); 143 wms.attemptGetCapabilities(info.getUrl()); 99 144 100 if (!GraphicsEnvironment.isHeadless()) { 101 if (1 != new ExtendedDialog(Main.parent, tr("Select WMS layers"), new String[]{tr("Add layers"), tr("Cancel")}) { { 102 final JScrollPane scrollPane = new JScrollPane(tree.getLayerTree()); 103 scrollPane.setPreferredSize(new Dimension(400, 400)); 104 final JPanel panel = new JPanel(new GridBagLayout()); 105 panel.add(scrollPane, GBC.eol().fill()); 106 panel.add(formats, GBC.eol().fill(GBC.HORIZONTAL)); 107 setContent(panel); 108 } }.showDialog().getValue()) { 109 return null; 110 } 111 } 145 final WMSLayerTree tree = new WMSLayerTree(); 146 tree.updateTree(wms); 147 List<String> wmsFormats = wms.getFormats(); 148 final JComboBox<String> formats = new JComboBox<>(wmsFormats.toArray(new String[wmsFormats.size()])); 149 formats.setSelectedItem(wms.getPreferredFormats()); 150 formats.setToolTipText(tr("Select image format for WMS layer")); 112 151 113 final String url = wms.buildGetMapUrl( 114 tree.getSelectedLayers(), (String) formats.getSelectedItem()); 115 Set<String> supportedCrs = new HashSet<>(); 116 boolean first = true; 117 StringBuilder layersString = new StringBuilder(); 118 for (LayerDetails layer: tree.getSelectedLayers()) { 119 if (first) { 120 supportedCrs.addAll(layer.getProjections()); 121 first = false; 122 } 123 layersString.append(layer.name); 124 layersString.append(", "); 125 supportedCrs.retainAll(layer.getProjections()); 152 if (!GraphicsEnvironment.isHeadless()) { 153 if (1 != new ExtendedDialog(Main.parent, tr("Select WMS layers"), new String[]{tr("Add layers"), tr("Cancel")}) { { 154 final JScrollPane scrollPane = new JScrollPane(tree.getLayerTree()); 155 scrollPane.setPreferredSize(new Dimension(400, 400)); 156 final JPanel panel = new JPanel(new GridBagLayout()); 157 panel.add(scrollPane, GBC.eol().fill()); 158 panel.add(formats, GBC.eol().fill(GBC.HORIZONTAL)); 159 setContent(panel); 160 } }.showDialog().getValue()) { 161 return null; 126 162 } 163 } 127 164 128 ImageryInfo ret = new ImageryInfo(info.getName(), url, "wms", info.getEulaAcceptanceRequired(), info.getCookies()); 129 if (layersString.length() > 2) { 130 ret.setName(ret.getName() + ' ' + layersString.substring(0, layersString.length() - 2)); 165 final String url = wms.buildGetMapUrl( 166 tree.getSelectedLayers(), (String) formats.getSelectedItem()); 167 Set<String> supportedCrs = new HashSet<>(); 168 boolean first = true; 169 StringBuilder layersString = new StringBuilder(); 170 for (LayerDetails layer: tree.getSelectedLayers()) { 171 if (first) { 172 supportedCrs.addAll(layer.getProjections()); 173 first = false; 131 174 } 132 ret.setServerProjections(supportedCrs); 133 return ret; 134 } catch (MalformedURLException ex) { 135 if (!GraphicsEnvironment.isHeadless()) { 136 JOptionPane.showMessageDialog(Main.parent, tr("Invalid service URL."), 137 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 138 } 139 Main.error(ex, false); 140 } catch (IOException ex) { 141 if (!GraphicsEnvironment.isHeadless()) { 142 JOptionPane.showMessageDialog(Main.parent, tr("Could not retrieve WMS layer list."), 143 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 144 } 145 Main.error(ex, false); 146 } catch (WMSGetCapabilitiesException ex) { 147 if (!GraphicsEnvironment.isHeadless()) { 148 JOptionPane.showMessageDialog(Main.parent, tr("Could not parse WMS layer list."), 149 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 150 } 151 Main.error(ex, "Could not parse WMS layer list. Incoming data:\n"+ex.getIncomingData()); 175 layersString.append(layer.name); 176 layersString.append(", "); 177 supportedCrs.retainAll(layer.getProjections()); 152 178 } 153 return null; 179 180 ImageryInfo ret = new ImageryInfo(info.getName(), url, "wms", info.getEulaAcceptanceRequired(), info.getCookies()); 181 if (layersString.length() > 2) { 182 ret.setName(ret.getName() + ' ' + layersString.substring(0, layersString.length() - 2)); 183 } 184 ret.setServerProjections(supportedCrs); 185 return ret; 154 186 } 155 187 156 188 @Override -
src/org/openstreetmap/josm/data/imagery/ImageryInfo.java
16 16 import java.util.TreeSet; 17 17 import java.util.regex.Matcher; 18 18 import java.util.regex.Pattern; 19 import java.util.stream.Collectors; 19 20 20 21 import javax.swing.ImageIcon; 21 22 … … 192 193 private String icon; 193 194 private boolean isGeoreferenceValid; 194 195 private boolean isEpsg4326To3857Supported; 196 /** which layers should be activated by default on layer addition. **/ 197 private Collection<String> defaultLayers = Collections.emptyList(); 195 198 // when adding a field, also adapt the ImageryInfo(ImageryInfo) 196 199 // and ImageryInfo(ImageryPreferenceEntry) constructor, equals method, and ImageryPreferenceEntry 197 200 … … 226 229 @pref Map<String, String> metadataHeaders; 227 230 @pref boolean valid_georeference; 228 231 @pref boolean supports_epsg_4326_to_3857_conversion; 232 // TODO: disabled until change of layers is implemented 233 // @pref String default_layers; 229 234 230 235 /** 231 236 * Constructs a new empty WMS {@code ImageryPreferenceEntry}. … … 270 275 shapes = shapesString.toString(); 271 276 } 272 277 } 273 if (!i.serverProjections.isEmpty()) { 274 StringBuilder val = new StringBuilder(); 275 for (String p : i.serverProjections) { 276 if (val.length() > 0) { 277 val.append(','); 278 } 279 val.append(p); 280 } 281 projections = val.toString(); 282 } 278 projections = i.serverProjections.stream().collect(Collectors.joining(",")); 283 279 if (i.noTileHeaders != null && !i.noTileHeaders.isEmpty()) { 284 280 noTileHeaders = new MultiMap<>(i.noTileHeaders); 285 281 } … … 296 292 297 293 valid_georeference = i.isGeoreferenceValid(); 298 294 supports_epsg_4326_to_3857_conversion = i.isEpsg4326To3857Supported(); 295 // TODO disabled until change of layers is implemented 296 // default_layers = i.defaultLayers.stream().collect(Collectors.joining(",")); 299 297 } 300 298 301 299 @Override … … 422 420 metadataHeaders = e.metadataHeaders; 423 421 isEpsg4326To3857Supported = e.supports_epsg_4326_to_3857_conversion; 424 422 isGeoreferenceValid = e.valid_georeference; 423 // TODO disabled until change of layers is implemented 424 // defaultLayers = Arrays.asList(e.default_layers.split(",")); 425 425 } 426 426 427 427 /** … … 453 453 this.metadataHeaders = i.metadataHeaders; 454 454 this.isEpsg4326To3857Supported = i.isEpsg4326To3857Supported; 455 455 this.isGeoreferenceValid = i.isGeoreferenceValid; 456 this.defaultLayers = i.defaultLayers; 456 457 } 457 458 458 459 @Override … … 496 497 Objects.equals(this.description, other.description) && 497 498 Objects.equals(this.noTileHeaders, other.noTileHeaders) && 498 499 Objects.equals(this.noTileChecksums, other.noTileChecksums) && 499 Objects.equals(this.metadataHeaders, other.metadataHeaders); 500 Objects.equals(this.metadataHeaders, other.metadataHeaders) && 501 Objects.equals(this.defaultLayers, other.defaultLayers); 500 502 } 501 503 502 504 @Override … … 1146 1148 } 1147 1149 return l; 1148 1150 } 1151 1152 /** 1153 * Returns default layers that should be shown for this Imagery (if at all supported by imagery provider) 1154 * If no layer is set to default and there is more than one imagery available, then user will be asked to choose the layer 1155 * to work on 1156 * @return Collection of the layer names 1157 */ 1158 public Collection<String> getDefaultLayers() { 1159 return defaultLayers; 1160 } 1161 1162 /** 1163 * Sets the default layers that user will work with 1164 * @param layers 1165 */ 1166 public void setDefaultLayers(Collection<String> layers) { 1167 this.defaultLayers = layers; 1168 } 1149 1169 } -
src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java
15 15 import java.util.HashSet; 16 16 import java.util.List; 17 17 import java.util.Map; 18 import java.util.Map.Entry; 18 19 import java.util.Set; 19 20 import java.util.SortedSet; 20 21 import java.util.Stack; … … 22 23 import java.util.concurrent.ConcurrentHashMap; 23 24 import java.util.regex.Matcher; 24 25 import java.util.regex.Pattern; 26 import java.util.stream.Collectors; 25 27 26 28 import javax.swing.JPanel; 27 29 import javax.swing.JScrollPane; … … 158 160 } 159 161 160 162 private static final class SelectLayerDialog extends ExtendedDialog { 161 private final transient L ayer[]layers;163 private final transient List<Entry<String,List<Layer>>> layers; 162 164 private final JTable list; 163 165 164 166 SelectLayerDialog(Collection<Layer> layers) { 165 167 super(Main.parent, tr("Select WMTS layer"), new String[]{tr("Add layers"), tr("Cancel")}); 166 this.layers = layers.toArray(new Layer[layers.size()]);168 this.layers = groupLayersByName(layers); 167 169 //getLayersTable(layers, Main.getProjection()) 168 170 this.list = new JTable( 169 171 new AbstractTableModel() { … … 171 173 public Object getValueAt(int rowIndex, int columnIndex) { 172 174 switch (columnIndex) { 173 175 case 0: 174 return SelectLayerDialog.this.layers [rowIndex].name;176 return SelectLayerDialog.this.layers.get(rowIndex).getKey(); 175 177 case 1: 176 return SelectLayerDialog.this.layers[rowIndex].tileMatrixSet.crs; 178 return SelectLayerDialog.this.layers.get(rowIndex).getValue() 179 .stream() 180 .map(x -> x.tileMatrixSet.crs) 181 .collect(Collectors.joining(", ")); 177 182 case 2: 178 return SelectLayerDialog.this.layers[rowIndex].tileMatrixSet.identifier; 183 return SelectLayerDialog.this.layers.get(rowIndex).getValue() 184 .stream() 185 .map(x -> x.tileMatrixSet.identifier) 186 .collect(Collectors.joining(", ")); 179 187 default: 180 188 throw new IllegalArgumentException(); 181 189 } … … 183 191 184 192 @Override 185 193 public int getRowCount() { 186 return SelectLayerDialog.this.layers. length;194 return SelectLayerDialog.this.layers.size(); 187 195 } 188 196 189 197 @Override … … 195 203 public String getColumnName(int column) { 196 204 switch (column) { 197 205 case 0: return tr("Layer name"); 198 case 1: return tr("Projection ");199 case 2: return tr("Matrix set identifier ");206 case 1: return tr("Projections"); 207 case 2: return tr("Matrix set identifiers"); 200 208 default: 201 209 throw new IllegalArgumentException(); 202 210 } … … 215 223 setContent(panel); 216 224 } 217 225 218 public Layer getSelectedLayer() { 226 private List<Entry<String, List<Layer>>> groupLayersByName(Collection<Layer> layers) { 227 Map<String, List<Layer>> layerByName = layers.stream().collect(Collectors.groupingBy(x -> x.name)); 228 return layerByName.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toList()); 229 } 230 231 public String getSelectedLayer() { 219 232 int index = list.getSelectedRow(); 220 233 if (index < 0) { 221 234 return null; //nothing selected 222 235 } 223 return layers [index];236 return layers.get(index).getKey(); 224 237 } 225 238 } 226 239 … … 233 246 234 247 private ScaleList nativeScaleList; 235 248 249 private String defaultLayer; 250 236 251 /** 237 252 * Creates a tile source based on imagery info 238 253 * @param info imagery info … … 241 256 */ 242 257 public WMTSTileSource(ImageryInfo info) throws IOException { 243 258 super(info); 259 CheckParameterUtil.ensureThat(info.getDefaultLayers().size() < 2, "At most 1 default layer for WMTS is supported"); 260 244 261 this.baseUrl = GetCapabilitiesParseHelper.normalizeCapabilitiesUrl(handleTemplate(info.getUrl())); 245 262 this.layers = getCapabilities(); 263 this.defaultLayer = info.getDefaultLayers().isEmpty() ? null : info.getDefaultLayers().iterator().next(); 246 264 if (this.layers.isEmpty()) 247 265 throw new IllegalArgumentException(tr("No layers defined by getCapabilities document: {0}", info.getUrl())); 248 266 } 249 267 250 private static Layer userSelectLayer(Collection<Layer> layers) { 251 if (layers.size() == 1) 252 return layers.iterator().next(); 253 Layer ret = null; 268 /** 269 * Creates a dialog based on this tile source with all available layers and returns the name of selected layer 270 * @return Name of selected layer 271 */ 272 public String userSelectLayer() { 273 Collection<String> layerNames = layers.stream().map(x -> x.name).collect(Collectors.toSet()); 254 274 275 // if there is only one layer name no point in asking 276 if (layerNames.size() == 1) 277 return layerNames.iterator().next(); 278 255 279 final SelectLayerDialog layerSelection = new SelectLayerDialog(layers); 256 280 if (layerSelection.showDialog().getValue() == 1) { 257 ret = layerSelection.getSelectedLayer(); 258 // TODO: save layer information into ImageryInfo / ImageryPreferences? 281 return layerSelection.getSelectedLayer(); 259 282 } 260 if (ret == null) { 261 // user canceled operation or did not choose any layer 262 throw new IllegalArgumentException(tr("No layer selected")); 263 } 264 return ret; 283 return null; 265 284 } 266 285 267 286 private String handleTemplate(String url) { … … 535 554 public void initProjection(Projection proj) { 536 555 // getLayers will return only layers matching the name, if the user already choose the layer 537 556 // so we will not ask the user again to chose the layer, if he just changes projection 538 Collection<Layer> candidates = getLayers(currentLayer != null ? currentLayer.name : null, proj.toCode()); 539 if (!candidates.isEmpty()) { 540 Layer newLayer = userSelectLayer(candidates); 557 Collection<Layer> candidates = getLayers(currentLayer != null ? currentLayer.name : defaultLayer, proj.toCode()); 558 if (candidates.size() == 1) { 559 560 Layer newLayer = candidates.iterator().next(); 541 561 if (newLayer != null) { 542 562 this.currentTileMatrixSet = newLayer.tileMatrixSet; 543 563 this.currentLayer = newLayer;
