source: josm/trunk/src/org/openstreetmap/josm/actions/AddImageryLayerAction.java@ 13494

Last change on this file since 13494 was 13388, checked in by Don-vip, 6 years ago

see #15880 - robustness to unsupported projections

  • Property svn:eol-style set to native
File size: 9.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.Dimension;
8import java.awt.GraphicsEnvironment;
9import java.awt.GridBagLayout;
10import java.awt.event.ActionEvent;
11import java.io.IOException;
12import java.net.MalformedURLException;
13import java.util.ArrayList;
14import java.util.Collection;
15import java.util.HashSet;
16import java.util.List;
17import java.util.Set;
18
19import javax.swing.JComboBox;
20import javax.swing.JOptionPane;
21import javax.swing.JPanel;
22import javax.swing.JScrollPane;
23
24import org.openstreetmap.josm.Main;
25import org.openstreetmap.josm.data.imagery.DefaultLayer;
26import org.openstreetmap.josm.data.imagery.ImageryInfo;
27import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
28import org.openstreetmap.josm.data.imagery.WMTSTileSource;
29import org.openstreetmap.josm.gui.ExtendedDialog;
30import org.openstreetmap.josm.gui.layer.AlignImageryPanel;
31import org.openstreetmap.josm.gui.layer.ImageryLayer;
32import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
33import org.openstreetmap.josm.gui.preferences.imagery.WMSLayerTree;
34import org.openstreetmap.josm.gui.util.GuiHelper;
35import org.openstreetmap.josm.io.imagery.WMSImagery;
36import org.openstreetmap.josm.io.imagery.WMSImagery.LayerDetails;
37import org.openstreetmap.josm.io.imagery.WMSImagery.WMSGetCapabilitiesException;
38import org.openstreetmap.josm.tools.CheckParameterUtil;
39import org.openstreetmap.josm.tools.GBC;
40import org.openstreetmap.josm.tools.ImageProvider;
41import org.openstreetmap.josm.tools.Logging;
42import org.openstreetmap.josm.tools.bugreport.ReportedException;
43
44/**
45 * Action displayed in imagery menu to add a new imagery layer.
46 * @since 3715
47 */
48public class AddImageryLayerAction extends JosmAction implements AdaptableAction {
49 private final transient ImageryInfo info;
50
51 static class SelectWmsLayersDialog extends ExtendedDialog {
52 SelectWmsLayersDialog(WMSLayerTree tree, JComboBox<String> formats) {
53 super(Main.parent, tr("Select WMS layers"), tr("Add layers"), tr("Cancel"));
54 final JScrollPane scrollPane = new JScrollPane(tree.getLayerTree());
55 scrollPane.setPreferredSize(new Dimension(400, 400));
56 final JPanel panel = new JPanel(new GridBagLayout());
57 panel.add(scrollPane, GBC.eol().fill());
58 panel.add(formats, GBC.eol().fill(GBC.HORIZONTAL));
59 setContent(panel);
60 }
61 }
62
63 /**
64 * Constructs a new {@code AddImageryLayerAction} for the given {@code ImageryInfo}.
65 * If an http:// icon is specified, it is fetched asynchronously.
66 * @param info The imagery info
67 */
68 public AddImageryLayerAction(ImageryInfo info) {
69 super(info.getMenuName(), /* ICON */"imagery_menu", tr("Add imagery layer {0}", info.getName()), null,
70 true, ToolbarPreferences.IMAGERY_PREFIX + info.getToolbarName(), false);
71 putValue("help", ht("/Preferences/Imagery"));
72 setTooltip(info.getToolTipText().replaceAll("</?html>", ""));
73 this.info = info;
74 installAdapters();
75
76 // change toolbar icon from if specified
77 String icon = info.getIcon();
78 if (icon != null) {
79 new ImageProvider(icon).setOptional(true).getResourceAsync(result -> {
80 if (result != null) {
81 GuiHelper.runInEDT(() -> result.attachImageIcon(this));
82 }
83 });
84 }
85 }
86
87 /**
88 * Converts general ImageryInfo to specific one, that does not need any user action to initialize
89 * see: https://josm.openstreetmap.de/ticket/13868
90 * @param info ImageryInfo that will be converted (or returned when no conversion needed)
91 * @return ImageryInfo object that's ready to be used to create TileSource
92 */
93 private ImageryInfo convertImagery(ImageryInfo info) {
94 try {
95 switch(info.getImageryType()) {
96 case WMS_ENDPOINT:
97 // convert to WMS type
98 return getWMSLayerInfo(info);
99 case WMTS:
100 // specify which layer to use
101 DefaultLayer layerId = new WMTSTileSource(info).userSelectLayer();
102 if (layerId != null) {
103 ImageryInfo copy = new ImageryInfo(info);
104 Collection<DefaultLayer> defaultLayers = new ArrayList<>(1);
105 defaultLayers.add(layerId);
106 copy.setDefaultLayers(defaultLayers);
107 return copy;
108 }
109 // layer not selected - refuse to add
110 return null;
111 default:
112 return info;
113 }
114 } catch (MalformedURLException ex) {
115 if (!GraphicsEnvironment.isHeadless()) {
116 JOptionPane.showMessageDialog(Main.parent, tr("Invalid service URL."),
117 tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
118 }
119 Logging.log(Logging.LEVEL_ERROR, ex);
120 } catch (IOException ex) {
121 if (!GraphicsEnvironment.isHeadless()) {
122 JOptionPane.showMessageDialog(Main.parent, tr("Could not retrieve WMS layer list."),
123 tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
124 }
125 Logging.log(Logging.LEVEL_ERROR, ex);
126 } catch (WMSGetCapabilitiesException ex) {
127 if (!GraphicsEnvironment.isHeadless()) {
128 JOptionPane.showMessageDialog(Main.parent, tr("Could not parse WMS layer list."),
129 tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
130 }
131 Logging.log(Logging.LEVEL_ERROR, "Could not parse WMS layer list. Incoming data:\n"+ex.getIncomingData(), ex);
132 }
133 return null;
134 }
135
136 @Override
137 public void actionPerformed(ActionEvent e) {
138 if (!isEnabled()) return;
139 ImageryLayer layer = null;
140 try {
141 final ImageryInfo infoToAdd = convertImagery(info);
142 if (infoToAdd != null) {
143 layer = ImageryLayer.create(infoToAdd);
144 getLayerManager().addLayer(layer);
145 AlignImageryPanel.addNagPanelIfNeeded(infoToAdd);
146 }
147 } catch (IllegalArgumentException | ReportedException ex) {
148 if (ex.getMessage() == null || ex.getMessage().isEmpty() || GraphicsEnvironment.isHeadless()) {
149 throw ex;
150 } else {
151 Logging.error(ex);
152 JOptionPane.showMessageDialog(Main.parent, ex.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE);
153 if (layer != null) {
154 getLayerManager().removeLayer(layer);
155 }
156 }
157 }
158 }
159
160 /**
161 * Asks user to choose a WMS layer from a WMS endpoint.
162 * @param info the WMS endpoint.
163 * @return chosen WMS layer, or null
164 * @throws IOException if any I/O error occurs while contacting the WMS endpoint
165 * @throws WMSGetCapabilitiesException if the WMS getCapabilities request fails
166 */
167 protected static ImageryInfo getWMSLayerInfo(ImageryInfo info) throws IOException, WMSGetCapabilitiesException {
168 CheckParameterUtil.ensureThat(ImageryType.WMS_ENDPOINT.equals(info.getImageryType()), "wms_endpoint imagery type expected");
169
170 final WMSImagery wms = new WMSImagery();
171 wms.attemptGetCapabilities(info.getUrl());
172
173 final WMSLayerTree tree = new WMSLayerTree();
174 tree.updateTree(wms);
175 List<String> wmsFormats = wms.getFormats();
176 final JComboBox<String> formats = new JComboBox<>(wmsFormats.toArray(new String[0]));
177 formats.setSelectedItem(wms.getPreferredFormats());
178 formats.setToolTipText(tr("Select image format for WMS layer"));
179
180 if (!GraphicsEnvironment.isHeadless() && 1 != new SelectWmsLayersDialog(tree, formats).showDialog().getValue()) {
181 return null;
182 }
183
184 final String url = wms.buildGetMapUrl(
185 tree.getSelectedLayers(), (String) formats.getSelectedItem());
186 Set<String> supportedCrs = new HashSet<>();
187 boolean first = true;
188 StringBuilder layersString = new StringBuilder();
189 for (LayerDetails layer: tree.getSelectedLayers()) {
190 if (first) {
191 supportedCrs.addAll(layer.getProjections());
192 first = false;
193 }
194 layersString.append(layer.name);
195 layersString.append(", ");
196 supportedCrs.retainAll(layer.getProjections());
197 }
198
199 // copy all information from WMS
200 ImageryInfo ret = new ImageryInfo(info);
201 // and update according to user choice
202 ret.setUrl(url);
203 ret.setImageryType(ImageryType.WMS);
204 if (layersString.length() > 2) {
205 ret.setName(ret.getName() + ' ' + layersString.substring(0, layersString.length() - 2));
206 }
207 ret.setServerProjections(supportedCrs);
208 return ret;
209 }
210
211 @Override
212 protected void updateEnabledState() {
213 if (info.isBlacklisted()) {
214 setEnabled(false);
215 } else {
216 setEnabled(true);
217 }
218 }
219
220 @Override
221 public String toString() {
222 return "AddImageryLayerAction [info=" + info + ']';
223 }
224}
Note: See TracBrowser for help on using the repository browser.