Changeset 23454 in osm for applications/editors/josm/plugins/wmsplugin
- Timestamp:
- 2010-10-03T16:13:54+02:00 (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/wmsplugin/src/wmsplugin/AddWMSLayerPanel.java
r23304 r23454 59 59 60 60 public class AddWMSLayerPanel extends JPanel { 61 private List<LayerDetails> selectedLayers; 62 private URL serviceUrl; 63 private LayerDetails selectedLayer; 64 65 private JTextField menuName; 66 private JTextArea resultingLayerField; 67 private MutableTreeNode treeRootNode; 68 private DefaultTreeModel treeData; 69 private JTree layerTree; 70 private JButton showBoundsButton; 71 72 private boolean previouslyShownUnsupportedCrsError = false; 73 74 public AddWMSLayerPanel() { 75 JPanel wmsFetchPanel = new JPanel(new GridBagLayout()); 76 menuName = new JTextField(40); 77 menuName.setText(tr("Unnamed WMS Layer")); 78 final JTextArea serviceUrl = new JTextArea(3, 40); 79 serviceUrl.setLineWrap(true); 80 serviceUrl.setText("http://sample.com/wms?"); 81 wmsFetchPanel.add(new JLabel(tr("Menu Name")), GBC.std().insets(0,0,5,0)); 82 wmsFetchPanel.add(menuName, GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL)); 83 wmsFetchPanel.add(new JLabel(tr("Service URL")), GBC.std().insets(0,0,5,0)); 84 JScrollPane scrollPane = new JScrollPane(serviceUrl, 85 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 86 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 87 wmsFetchPanel.add(scrollPane, GBC.eop().insets(5,0,0,0)); 88 JButton getLayersButton = new JButton(tr("Get Layers")); 89 getLayersButton.addActionListener(new ActionListener() { 90 public void actionPerformed(ActionEvent e) { 91 Cursor beforeCursor = getCursor(); 92 try { 93 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 94 attemptGetCapabilities(serviceUrl.getText()); 95 } finally { 96 setCursor(beforeCursor); 97 } 98 } 99 }); 100 wmsFetchPanel.add(getLayersButton, GBC.eop().anchor(GridBagConstraints.EAST)); 101 102 treeRootNode = new DefaultMutableTreeNode(); 103 treeData = new DefaultTreeModel(treeRootNode); 104 layerTree = new JTree(treeData); 105 layerTree.setCellRenderer(new LayerTreeCellRenderer()); 106 layerTree.addTreeSelectionListener(new TreeSelectionListener() { 107 108 public void valueChanged(TreeSelectionEvent e) { 109 TreePath[] selectionRows = layerTree.getSelectionPaths(); 110 if(selectionRows == null) { 111 showBoundsButton.setEnabled(false); 112 selectedLayer = null; 113 return; 114 } 115 116 selectedLayers = new LinkedList<LayerDetails>(); 117 for (TreePath i : selectionRows) { 118 Object userObject = ((DefaultMutableTreeNode) i.getLastPathComponent()).getUserObject(); 119 if(userObject instanceof LayerDetails) { 120 LayerDetails detail = (LayerDetails) userObject; 121 if(!detail.isSupported()) { 122 layerTree.removeSelectionPath(i); 123 if(!previouslyShownUnsupportedCrsError) { 124 JOptionPane.showMessageDialog(null, tr("That layer does not support any of JOSM's projections,\n" + 125 "so you can not use it. This message will not show again."), 126 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 127 previouslyShownUnsupportedCrsError = true; 128 } 129 } else if(detail.ident != null) { 130 selectedLayers.add(detail); 131 } 132 } 133 } 134 135 if (!selectedLayers.isEmpty()) { 136 resultingLayerField.setText(buildGetMapUrl()); 137 138 if(selectedLayers.size() == 1) { 139 showBoundsButton.setEnabled(true); 140 selectedLayer = selectedLayers.get(0); 141 } 142 } else { 143 showBoundsButton.setEnabled(false); 144 selectedLayer = null; 145 } 146 } 147 }); 148 wmsFetchPanel.add(new JScrollPane(layerTree), GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL)); 149 150 JPanel layerManipulationButtons = new JPanel(); 151 showBoundsButton = new JButton(tr("Show Bounds")); 152 showBoundsButton.setEnabled(false); 153 showBoundsButton.addActionListener(new ActionListener() { 154 public void actionPerformed(ActionEvent e) { 155 if(selectedLayer.bounds != null) { 156 SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser(); 157 mapPanel.setBoundingBox(selectedLayer.bounds); 158 JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE); 159 } else { 160 JOptionPane.showMessageDialog(null, tr("No bounding box was found for this layer."), 161 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 162 } 163 } 164 }); 165 layerManipulationButtons.add(showBoundsButton); 166 167 wmsFetchPanel.add(layerManipulationButtons, GBC.eol().insets(0,0,5,0)); 168 wmsFetchPanel.add(new JLabel(tr("WMS URL")), GBC.std().insets(0,0,5,0)); 169 resultingLayerField = new JTextArea(3, 40); 170 resultingLayerField.setLineWrap(true); 171 wmsFetchPanel.add(new JScrollPane(resultingLayerField, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL)); 172 173 add(wmsFetchPanel); 174 } 175 176 private String buildRootUrl() { 177 StringBuilder a = new StringBuilder(serviceUrl.getProtocol()); 178 a.append("://"); 179 a.append(serviceUrl.getHost()); 180 if(serviceUrl.getPort() != -1) { 181 a.append(":"); 182 a.append(serviceUrl.getPort()); 183 } 184 a.append(serviceUrl.getPath()); 185 a.append("?"); 186 if(serviceUrl.getQuery() != null) { 187 a.append(serviceUrl.getQuery()); 188 if (!serviceUrl.getQuery().isEmpty() && !serviceUrl.getQuery().endsWith("&")) { 189 a.append("&"); 190 } 191 } 192 return a.toString(); 193 } 194 195 private String buildGetMapUrl() { 196 StringBuilder a = new StringBuilder(); 197 a.append(buildRootUrl()); 198 a.append("FORMAT=image/jpeg&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&Layers="); 199 a.append(commaSepLayerList()); 200 a.append("&"); 201 202 return a.toString(); 203 } 204 205 private String commaSepLayerList() { 206 StringBuilder b = new StringBuilder(); 207 208 Iterator<LayerDetails> iterator = selectedLayers.iterator(); 209 while (iterator.hasNext()) { 210 LayerDetails layerDetails = iterator.next(); 211 b.append(layerDetails.ident); 212 if(iterator.hasNext()) { 213 b.append(","); 214 } 215 } 216 217 return b.toString(); 218 } 219 220 private void attemptGetCapabilities(String serviceUrlStr) { 221 URL getCapabilitiesUrl = null; 222 try { 223 if (!serviceUrlStr.trim().contains("capabilities")) { 224 // If the url doesn't already have GetCapabilities, add it in 225 getCapabilitiesUrl = new URL(serviceUrlStr + "VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities"); 226 } else { 227 // Otherwise assume it's a good URL and let the subsequent error 228 // handling systems deal with problems 229 getCapabilitiesUrl = new URL(serviceUrlStr); 230 } 231 serviceUrl = new URL(serviceUrlStr); 232 } catch (HeadlessException e) { 233 return; 234 } catch (MalformedURLException e) { 235 JOptionPane.showMessageDialog(this, tr("Invalid service URL."), 236 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 237 return; 238 } 239 240 String incomingData; 241 try { 242 URLConnection openConnection = getCapabilitiesUrl.openConnection(); 243 InputStream inputStream = openConnection.getInputStream(); 244 BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); 245 String line; 246 StringBuilder ba = new StringBuilder(); 247 while((line = br.readLine()) != null) { 248 ba.append(line); 249 ba.append("\n"); 250 } 251 incomingData = ba.toString(); 252 } catch (IOException e) { 253 JOptionPane.showMessageDialog(this, tr("Could not retrieve WMS layer list."), 254 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 255 return; 256 } 257 258 Document document; 259 try { 260 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); 261 builderFactory.setValidating(false); 262 builderFactory.setNamespaceAware(true); 263 DocumentBuilder builder = builderFactory.newDocumentBuilder(); 264 builder.setEntityResolver(new EntityResolver() { 265 public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { 266 System.out.println("Ignoring DTD " + publicId + ", " + systemId); 267 return new InputSource(new StringReader("")); 268 } 269 }); 270 document = builder.parse(new InputSource(new StringReader(incomingData))); 271 } catch (ParserConfigurationException e) { 272 JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."), 273 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 274 return; 275 } catch (SAXException e) { 276 JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."), 277 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 278 return; 279 } catch (IOException e) { 280 JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."), 281 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 282 return; 283 } 284 285 // Some WMS service URLs specify a different base URL for their GetMap service 286 Element child = getChild(document.getDocumentElement(), "Capability"); 287 child = getChild(child, "Request"); 288 child = getChild(child, "GetMap"); 289 child = getChild(child, "DCPType"); 290 child = getChild(child, "HTTP"); 291 child = getChild(child, "Get"); 292 child = getChild(child, "OnlineResource"); 293 String baseURL = child.getAttribute("xlink:href"); 294 if(baseURL != null) { 295 try { 296 System.out.println("GetCapabilities specifies a different service URL: " + baseURL); 297 serviceUrl = new URL(baseURL); 298 } catch (MalformedURLException e1) { 299 } 300 } 301 302 try { 303 treeRootNode.setUserObject(getCapabilitiesUrl.getHost()); 304 Element capabilityElem = getChild(document.getDocumentElement(), "Capability"); 305 List<Element> children = getChildren(capabilityElem, "Layer"); 306 List<LayerDetails> layers = parseLayers(children, new HashSet<String>()); 307 updateTreeList(layers); 308 } catch(Exception e) { 309 JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."), 310 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 311 e.printStackTrace(); 312 return; 313 } 314 } 315 316 private void updateTreeList(List<LayerDetails> layers) { 317 addLayersToTreeData(treeRootNode, layers); 318 layerTree.expandRow(0); 319 } 320 321 private void addLayersToTreeData(MutableTreeNode parent, List<LayerDetails> layers) { 322 for (LayerDetails layerDetails : layers) { 323 DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(layerDetails); 324 addLayersToTreeData(treeNode, layerDetails.children); 325 treeData.insertNodeInto(treeNode, parent, 0); 326 } 327 } 328 329 private List<LayerDetails> parseLayers(List<Element> children, Set<String> parentCrs) { 330 List<LayerDetails> details = new LinkedList<LayerDetails>(); 331 for (Element element : children) { 332 details.add(parseLayer(element, parentCrs)); 333 } 334 return details; 335 } 336 337 private LayerDetails parseLayer(Element element, Set<String> parentCrs) { 338 String name = getChildContent(element, "Title", null, null); 339 String ident = getChildContent(element, "Name", null, null); 340 341 // The set of supported CRS/SRS for this layer 342 Set<String> crsList = new HashSet<String>(); 343 // ...including this layer's already-parsed parent projections 344 crsList.addAll(parentCrs); 345 346 // Parse the CRS/SRS pulled out of this layer's XML element 347 // I think CRS and SRS are the same at this point 348 List<Element> crsChildren = getChildren(element, "CRS"); 349 crsChildren.addAll(getChildren(element, "SRS")); 350 for (Element child : crsChildren) { 351 String crs = (String) getContent(child); 352 if(crs != null) { 353 String upperCase = crs.trim().toUpperCase(); 354 crsList.add(upperCase); 355 } 356 } 357 358 // Check to see if any of the specified projections are supported by JOSM 359 boolean josmSupportsThisLayer = false; 360 for (String crs : crsList) { 361 josmSupportsThisLayer |= isProjSupported(crs); 362 } 363 364 Bounds bounds = null; 365 Element bboxElem = getChild(element, "EX_GeographicBoundingBox"); 366 if(bboxElem != null) { 367 // Attempt to use EX_GeographicBoundingBox for bounding box 368 double left = Double.parseDouble(getChildContent(bboxElem, "westBoundLongitude", null, null)); 369 double top = Double.parseDouble(getChildContent(bboxElem, "northBoundLatitude", null, null)); 370 double right = Double.parseDouble(getChildContent(bboxElem, "eastBoundLongitude", null, null)); 371 double bot = Double.parseDouble(getChildContent(bboxElem, "southBoundLatitude", null, null)); 372 bounds = new Bounds(bot, left, top, right); 373 } else { 374 // If that's not available, try LatLonBoundingBox 375 bboxElem = getChild(element, "LatLonBoundingBox"); 376 if(bboxElem != null) { 377 double left = Double.parseDouble(bboxElem.getAttribute("minx")); 378 double top = Double.parseDouble(bboxElem.getAttribute("maxy")); 379 double right = Double.parseDouble(bboxElem.getAttribute("maxx")); 380 double bot = Double.parseDouble(bboxElem.getAttribute("miny")); 381 bounds = new Bounds(bot, left, top, right); 382 } 383 } 384 385 List<Element> layerChildren = getChildren(element, "Layer"); 386 List<LayerDetails> childLayers = parseLayers(layerChildren, crsList); 387 388 return new LayerDetails(name, ident, crsList, josmSupportsThisLayer, bounds, childLayers); 389 } 390 391 private boolean isProjSupported(String crs) { 392 for (Projection proj : Projection.allProjections) { 393 if (proj instanceof ProjectionSubPrefs) { 394 if (((ProjectionSubPrefs) proj).getPreferencesFromCode(crs) == null) { 395 return true; 396 } 397 } else { 398 if (proj.toCode().equals(crs)) { 399 return true; 400 } 401 } 402 } 403 return false; 404 } 405 406 public String getUrlName() { 407 return menuName.getText(); 408 } 409 410 public String getUrl() { 411 return resultingLayerField.getText(); 412 } 413 414 public static void main(String[] args) { 415 JFrame f = new JFrame("Test"); 416 f.setContentPane(new AddWMSLayerPanel()); 417 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 418 f.pack(); 419 f.setVisible(true); 420 } 421 422 private static String getChildContent(Element parent, String name, String missing, String empty) { 423 Element child = getChild(parent, name); 424 if (child == null) { 425 return missing; 426 } else { 427 String content = (String) getContent(child); 428 return (content != null) ? content : empty; 429 } 430 } 431 432 private static Object getContent(Element element) { 433 NodeList nl = element.getChildNodes(); 434 StringBuffer content = new StringBuffer(); 435 for (int i = 0; i < nl.getLength(); i++) { 436 Node node = nl.item(i); 437 switch (node.getNodeType()) { 438 case Node.ELEMENT_NODE: 439 return node; 440 case Node.CDATA_SECTION_NODE: 441 case Node.TEXT_NODE: 442 content.append(node.getNodeValue()); 443 break; 444 } 445 } 446 return content.toString().trim(); 447 } 448 449 private static List<Element> getChildren(Element parent, String name) { 450 List<Element> retVal = new LinkedList<Element>(); 451 for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { 452 if (child instanceof Element && name.equals(child.getNodeName())) { 453 retVal.add((Element) child); 454 } 455 } 456 return retVal; 457 } 458 459 private static Element getChild(Element parent, String name) { 460 for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { 461 if (child instanceof Element && name.equals(child.getNodeName())) { 462 return (Element) child; 463 } 464 } 465 return null; 466 } 467 468 class LayerDetails { 469 470 private String name; 471 private String ident; 472 private Set<String> crsList; 473 private List<LayerDetails> children; 474 private Bounds bounds; 475 private boolean supported; 476 477 public LayerDetails(String name, String ident, Set<String> crsList, 478 boolean supportedLayer, Bounds bounds, 479 List<LayerDetails> childLayers) { 480 this.name = name; 481 this.ident = ident; 482 this.crsList = crsList; 483 this.supported = supportedLayer; 484 this.children = childLayers; 485 this.bounds = bounds; 486 } 487 488 public boolean isSupported() { 489 return this.supported; 490 } 491 492 @Override 493 public String toString() { 494 if(this.name == null || this.name.isEmpty()) { 495 return this.ident; 496 } else { 497 return this.name; 498 } 499 } 500 501 } 502 503 class LayerTreeCellRenderer extends DefaultTreeCellRenderer { 504 @Override 505 public Component getTreeCellRendererComponent(JTree tree, Object value, 506 boolean sel, boolean expanded, boolean leaf, int row, 507 boolean hasFocus) { 508 super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, 509 row, hasFocus); 510 DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value; 511 Object userObject = treeNode.getUserObject(); 512 if (userObject instanceof LayerDetails) { 513 LayerDetails layer = (LayerDetails) userObject; 514 setEnabled(layer.isSupported()); 515 } 516 return this; 517 } 518 } 61 private List<LayerDetails> selectedLayers; 62 private URL serviceUrl; 63 private LayerDetails selectedLayer; 64 65 private JTextField menuName; 66 private JTextArea resultingLayerField; 67 private MutableTreeNode treeRootNode; 68 private DefaultTreeModel treeData; 69 private JTree layerTree; 70 private JButton showBoundsButton; 71 72 private boolean previouslyShownUnsupportedCrsError = false; 73 74 public AddWMSLayerPanel() { 75 JPanel wmsFetchPanel = new JPanel(new GridBagLayout()); 76 menuName = new JTextField(40); 77 menuName.setText(tr("Unnamed WMS Layer")); 78 final JTextArea serviceUrl = new JTextArea(3, 40); 79 serviceUrl.setLineWrap(true); 80 serviceUrl.setText("http://sample.com/wms?"); 81 wmsFetchPanel.add(new JLabel(tr("Menu Name")), GBC.std().insets(0,0,5,0)); 82 wmsFetchPanel.add(menuName, GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL)); 83 wmsFetchPanel.add(new JLabel(tr("Service URL")), GBC.std().insets(0,0,5,0)); 84 JScrollPane scrollPane = new JScrollPane(serviceUrl, 85 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 86 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 87 wmsFetchPanel.add(scrollPane, GBC.eop().insets(5,0,0,0)); 88 JButton getLayersButton = new JButton(tr("Get Layers")); 89 getLayersButton.addActionListener(new ActionListener() { 90 public void actionPerformed(ActionEvent e) { 91 Cursor beforeCursor = getCursor(); 92 try { 93 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 94 attemptGetCapabilities(serviceUrl.getText()); 95 } finally { 96 setCursor(beforeCursor); 97 } 98 } 99 }); 100 wmsFetchPanel.add(getLayersButton, GBC.eop().anchor(GridBagConstraints.EAST)); 101 102 treeRootNode = new DefaultMutableTreeNode(); 103 treeData = new DefaultTreeModel(treeRootNode); 104 layerTree = new JTree(treeData); 105 layerTree.setCellRenderer(new LayerTreeCellRenderer()); 106 layerTree.addTreeSelectionListener(new TreeSelectionListener() { 107 108 public void valueChanged(TreeSelectionEvent e) { 109 TreePath[] selectionRows = layerTree.getSelectionPaths(); 110 if(selectionRows == null) { 111 showBoundsButton.setEnabled(false); 112 selectedLayer = null; 113 return; 114 } 115 116 selectedLayers = new LinkedList<LayerDetails>(); 117 for (TreePath i : selectionRows) { 118 Object userObject = ((DefaultMutableTreeNode) i.getLastPathComponent()).getUserObject(); 119 if(userObject instanceof LayerDetails) { 120 LayerDetails detail = (LayerDetails) userObject; 121 if(!detail.isSupported()) { 122 layerTree.removeSelectionPath(i); 123 if(!previouslyShownUnsupportedCrsError) { 124 JOptionPane.showMessageDialog(null, tr("That layer does not support any of JOSM's projections,\n" + 125 "so you can not use it. This message will not show again."), 126 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 127 previouslyShownUnsupportedCrsError = true; 128 } 129 } else if(detail.ident != null) { 130 selectedLayers.add(detail); 131 } 132 } 133 } 134 135 if (!selectedLayers.isEmpty()) { 136 resultingLayerField.setText(buildGetMapUrl()); 137 138 if(selectedLayers.size() == 1) { 139 showBoundsButton.setEnabled(true); 140 selectedLayer = selectedLayers.get(0); 141 } 142 } else { 143 showBoundsButton.setEnabled(false); 144 selectedLayer = null; 145 } 146 } 147 }); 148 wmsFetchPanel.add(new JScrollPane(layerTree), GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL)); 149 150 JPanel layerManipulationButtons = new JPanel(); 151 showBoundsButton = new JButton(tr("Show Bounds")); 152 showBoundsButton.setEnabled(false); 153 showBoundsButton.addActionListener(new ActionListener() { 154 public void actionPerformed(ActionEvent e) { 155 if(selectedLayer.bounds != null) { 156 SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser(); 157 mapPanel.setBoundingBox(selectedLayer.bounds); 158 JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE); 159 } else { 160 JOptionPane.showMessageDialog(null, tr("No bounding box was found for this layer."), 161 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 162 } 163 } 164 }); 165 layerManipulationButtons.add(showBoundsButton); 166 167 wmsFetchPanel.add(layerManipulationButtons, GBC.eol().insets(0,0,5,0)); 168 wmsFetchPanel.add(new JLabel(tr("WMS URL")), GBC.std().insets(0,0,5,0)); 169 resultingLayerField = new JTextArea(3, 40); 170 resultingLayerField.setLineWrap(true); 171 wmsFetchPanel.add(new JScrollPane(resultingLayerField, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL)); 172 173 add(wmsFetchPanel); 174 } 175 176 private String buildRootUrl() { 177 StringBuilder a = new StringBuilder(serviceUrl.getProtocol()); 178 a.append("://"); 179 a.append(serviceUrl.getHost()); 180 if(serviceUrl.getPort() != -1) { 181 a.append(":"); 182 a.append(serviceUrl.getPort()); 183 } 184 a.append(serviceUrl.getPath()); 185 a.append("?"); 186 if(serviceUrl.getQuery() != null) { 187 a.append(serviceUrl.getQuery()); 188 if (!serviceUrl.getQuery().isEmpty() && !serviceUrl.getQuery().endsWith("&")) { 189 a.append("&"); 190 } 191 } 192 return a.toString(); 193 } 194 195 private String buildGetMapUrl() { 196 StringBuilder a = new StringBuilder(); 197 a.append(buildRootUrl()); 198 a.append("FORMAT=image/jpeg&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&Layers="); 199 a.append(commaSepLayerList()); 200 a.append("&"); 201 202 return a.toString(); 203 } 204 205 private String commaSepLayerList() { 206 StringBuilder b = new StringBuilder(); 207 208 Iterator<LayerDetails> iterator = selectedLayers.iterator(); 209 while (iterator.hasNext()) { 210 LayerDetails layerDetails = iterator.next(); 211 b.append(layerDetails.ident); 212 if(iterator.hasNext()) { 213 b.append(","); 214 } 215 } 216 217 return b.toString(); 218 } 219 220 private void showError(String incomingData, Exception e) { 221 JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."), 222 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 223 System.err.println("Could not parse WMS layer list. Incoming data:"); 224 System.err.println(incomingData); 225 e.printStackTrace(); 226 } 227 228 private void attemptGetCapabilities(String serviceUrlStr) { 229 URL getCapabilitiesUrl = null; 230 try { 231 if (!serviceUrlStr.trim().contains("capabilities")) { 232 // If the url doesn't already have GetCapabilities, add it in 233 getCapabilitiesUrl = new URL(serviceUrlStr + "VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities"); 234 } else { 235 // Otherwise assume it's a good URL and let the subsequent error 236 // handling systems deal with problems 237 getCapabilitiesUrl = new URL(serviceUrlStr); 238 } 239 serviceUrl = new URL(serviceUrlStr); 240 } catch (HeadlessException e) { 241 return; 242 } catch (MalformedURLException e) { 243 JOptionPane.showMessageDialog(this, tr("Invalid service URL."), 244 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 245 return; 246 } 247 248 String incomingData; 249 try { 250 URLConnection openConnection = getCapabilitiesUrl.openConnection(); 251 InputStream inputStream = openConnection.getInputStream(); 252 BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); 253 String line; 254 StringBuilder ba = new StringBuilder(); 255 while((line = br.readLine()) != null) { 256 ba.append(line); 257 ba.append("\n"); 258 } 259 incomingData = ba.toString(); 260 } catch (IOException e) { 261 JOptionPane.showMessageDialog(this, tr("Could not retrieve WMS layer list."), 262 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 263 return; 264 } 265 266 Document document; 267 try { 268 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); 269 builderFactory.setValidating(false); 270 builderFactory.setNamespaceAware(true); 271 DocumentBuilder builder = builderFactory.newDocumentBuilder(); 272 builder.setEntityResolver(new EntityResolver() { 273 public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { 274 System.out.println("Ignoring DTD " + publicId + ", " + systemId); 275 return new InputSource(new StringReader("")); 276 } 277 }); 278 document = builder.parse(new InputSource(new StringReader(incomingData))); 279 } catch (ParserConfigurationException e) { 280 showError(incomingData, e); 281 return; 282 } catch (SAXException e) { 283 showError(incomingData, e); 284 return; 285 } catch (IOException e) { 286 showError(incomingData, e); 287 return; 288 } 289 290 // Some WMS service URLs specify a different base URL for their GetMap service 291 Element child = getChild(document.getDocumentElement(), "Capability"); 292 child = getChild(child, "Request"); 293 child = getChild(child, "GetMap"); 294 child = getChild(child, "DCPType"); 295 child = getChild(child, "HTTP"); 296 child = getChild(child, "Get"); 297 child = getChild(child, "OnlineResource"); 298 if (child != null) { 299 String baseURL = child.getAttribute("xlink:href"); 300 if(baseURL != null) { 301 try { 302 System.out.println("GetCapabilities specifies a different service URL: " + baseURL); 303 serviceUrl = new URL(baseURL); 304 } catch (MalformedURLException e1) { 305 } 306 } 307 } 308 309 try { 310 treeRootNode.setUserObject(getCapabilitiesUrl.getHost()); 311 Element capabilityElem = getChild(document.getDocumentElement(), "Capability"); 312 List<Element> children = getChildren(capabilityElem, "Layer"); 313 List<LayerDetails> layers = parseLayers(children, new HashSet<String>()); 314 updateTreeList(layers); 315 } catch(Exception e) { 316 showError(incomingData, e); 317 return; 318 } 319 } 320 321 private void updateTreeList(List<LayerDetails> layers) { 322 addLayersToTreeData(treeRootNode, layers); 323 layerTree.expandRow(0); 324 } 325 326 private void addLayersToTreeData(MutableTreeNode parent, List<LayerDetails> layers) { 327 for (LayerDetails layerDetails : layers) { 328 DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(layerDetails); 329 addLayersToTreeData(treeNode, layerDetails.children); 330 treeData.insertNodeInto(treeNode, parent, 0); 331 } 332 } 333 334 private List<LayerDetails> parseLayers(List<Element> children, Set<String> parentCrs) { 335 List<LayerDetails> details = new LinkedList<LayerDetails>(); 336 for (Element element : children) { 337 details.add(parseLayer(element, parentCrs)); 338 } 339 return details; 340 } 341 342 private LayerDetails parseLayer(Element element, Set<String> parentCrs) { 343 String name = getChildContent(element, "Title", null, null); 344 String ident = getChildContent(element, "Name", null, null); 345 346 // The set of supported CRS/SRS for this layer 347 Set<String> crsList = new HashSet<String>(); 348 // ...including this layer's already-parsed parent projections 349 crsList.addAll(parentCrs); 350 351 // Parse the CRS/SRS pulled out of this layer's XML element 352 // I think CRS and SRS are the same at this point 353 List<Element> crsChildren = getChildren(element, "CRS"); 354 crsChildren.addAll(getChildren(element, "SRS")); 355 for (Element child : crsChildren) { 356 String crs = (String) getContent(child); 357 if(crs != null) { 358 String upperCase = crs.trim().toUpperCase(); 359 crsList.add(upperCase); 360 } 361 } 362 363 // Check to see if any of the specified projections are supported by JOSM 364 boolean josmSupportsThisLayer = false; 365 for (String crs : crsList) { 366 josmSupportsThisLayer |= isProjSupported(crs); 367 } 368 369 Bounds bounds = null; 370 Element bboxElem = getChild(element, "EX_GeographicBoundingBox"); 371 if(bboxElem != null) { 372 // Attempt to use EX_GeographicBoundingBox for bounding box 373 double left = Double.parseDouble(getChildContent(bboxElem, "westBoundLongitude", null, null)); 374 double top = Double.parseDouble(getChildContent(bboxElem, "northBoundLatitude", null, null)); 375 double right = Double.parseDouble(getChildContent(bboxElem, "eastBoundLongitude", null, null)); 376 double bot = Double.parseDouble(getChildContent(bboxElem, "southBoundLatitude", null, null)); 377 bounds = new Bounds(bot, left, top, right); 378 } else { 379 // If that's not available, try LatLonBoundingBox 380 bboxElem = getChild(element, "LatLonBoundingBox"); 381 if(bboxElem != null) { 382 double left = Double.parseDouble(bboxElem.getAttribute("minx")); 383 double top = Double.parseDouble(bboxElem.getAttribute("maxy")); 384 double right = Double.parseDouble(bboxElem.getAttribute("maxx")); 385 double bot = Double.parseDouble(bboxElem.getAttribute("miny")); 386 bounds = new Bounds(bot, left, top, right); 387 } 388 } 389 390 List<Element> layerChildren = getChildren(element, "Layer"); 391 List<LayerDetails> childLayers = parseLayers(layerChildren, crsList); 392 393 return new LayerDetails(name, ident, crsList, josmSupportsThisLayer, bounds, childLayers); 394 } 395 396 private boolean isProjSupported(String crs) { 397 for (Projection proj : Projection.allProjections) { 398 if (proj instanceof ProjectionSubPrefs) { 399 if (((ProjectionSubPrefs) proj).getPreferencesFromCode(crs) == null) { 400 return true; 401 } 402 } else { 403 if (proj.toCode().equals(crs)) { 404 return true; 405 } 406 } 407 } 408 return false; 409 } 410 411 public String getUrlName() { 412 return menuName.getText(); 413 } 414 415 public String getUrl() { 416 return resultingLayerField.getText(); 417 } 418 419 public static void main(String[] args) { 420 JFrame f = new JFrame("Test"); 421 f.setContentPane(new AddWMSLayerPanel()); 422 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 423 f.pack(); 424 f.setVisible(true); 425 } 426 427 private static String getChildContent(Element parent, String name, String missing, String empty) { 428 Element child = getChild(parent, name); 429 if (child == null) { 430 return missing; 431 } else { 432 String content = (String) getContent(child); 433 return (content != null) ? content : empty; 434 } 435 } 436 437 private static Object getContent(Element element) { 438 NodeList nl = element.getChildNodes(); 439 StringBuffer content = new StringBuffer(); 440 for (int i = 0; i < nl.getLength(); i++) { 441 Node node = nl.item(i); 442 switch (node.getNodeType()) { 443 case Node.ELEMENT_NODE: 444 return node; 445 case Node.CDATA_SECTION_NODE: 446 case Node.TEXT_NODE: 447 content.append(node.getNodeValue()); 448 break; 449 } 450 } 451 return content.toString().trim(); 452 } 453 454 private static List<Element> getChildren(Element parent, String name) { 455 List<Element> retVal = new LinkedList<Element>(); 456 for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { 457 if (child instanceof Element && name.equals(child.getNodeName())) { 458 retVal.add((Element) child); 459 } 460 } 461 return retVal; 462 } 463 464 private static Element getChild(Element parent, String name) { 465 if (parent == null) { 466 return null; 467 } 468 for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { 469 if (child instanceof Element && name.equals(child.getNodeName())) { 470 return (Element) child; 471 } 472 } 473 return null; 474 } 475 476 class LayerDetails { 477 478 private String name; 479 private String ident; 480 private List<LayerDetails> children; 481 private Bounds bounds; 482 private boolean supported; 483 484 public LayerDetails(String name, String ident, Set<String> crsList, 485 boolean supportedLayer, Bounds bounds, 486 List<LayerDetails> childLayers) { 487 this.name = name; 488 this.ident = ident; 489 this.supported = supportedLayer; 490 this.children = childLayers; 491 this.bounds = bounds; 492 } 493 494 public boolean isSupported() { 495 return this.supported; 496 } 497 498 @Override 499 public String toString() { 500 if(this.name == null || this.name.isEmpty()) { 501 return this.ident; 502 } else { 503 return this.name; 504 } 505 } 506 507 } 508 509 class LayerTreeCellRenderer extends DefaultTreeCellRenderer { 510 @Override 511 public Component getTreeCellRendererComponent(JTree tree, Object value, 512 boolean sel, boolean expanded, boolean leaf, int row, 513 boolean hasFocus) { 514 super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, 515 row, hasFocus); 516 DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value; 517 Object userObject = treeNode.getUserObject(); 518 if (userObject instanceof LayerDetails) { 519 LayerDetails layer = (LayerDetails) userObject; 520 setEnabled(layer.isSupported()); 521 } 522 return this; 523 } 524 } 519 525 520 526 }
Note:
See TracChangeset
for help on using the changeset viewer.