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

Last change on this file since 13828 was 13828, checked in by wiktorn, 6 years ago

Sonar fixes, javadocs.

See: #16249

  • Property svn:eol-style set to native
File size: 11.3 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.List;
16import java.util.stream.Collectors;
17
18import javax.swing.JComboBox;
19import javax.swing.JOptionPane;
20import javax.swing.JPanel;
21import javax.swing.JScrollPane;
22
23import org.openstreetmap.josm.Main;
24import org.openstreetmap.josm.data.imagery.DefaultLayer;
25import org.openstreetmap.josm.data.imagery.ImageryInfo;
26import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
27import org.openstreetmap.josm.data.imagery.LayerDetails;
28import org.openstreetmap.josm.data.imagery.WMTSTileSource;
29import org.openstreetmap.josm.data.imagery.WMTSTileSource.WMTSGetCapabilitiesException;
30import org.openstreetmap.josm.gui.ExtendedDialog;
31import org.openstreetmap.josm.gui.layer.AlignImageryPanel;
32import org.openstreetmap.josm.gui.layer.ImageryLayer;
33import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
34import org.openstreetmap.josm.gui.preferences.imagery.WMSLayerTree;
35import org.openstreetmap.josm.gui.util.GuiHelper;
36import org.openstreetmap.josm.io.imagery.WMSImagery;
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 if (info.getDefaultLayers() == null || info.getDefaultLayers().isEmpty()) {
99 return getWMSLayerInfo(info);
100 } else {
101 return info;
102 }
103 case WMTS:
104 // specify which layer to use
105 if (info.getDefaultLayers() == null || info.getDefaultLayers().isEmpty()) {
106 DefaultLayer layerId = new WMTSTileSource(info).userSelectLayer();
107 if (layerId != null) {
108 ImageryInfo copy = new ImageryInfo(info);
109 List<DefaultLayer> defaultLayers = new ArrayList<>(1);
110 defaultLayers.add(layerId);
111 copy.setDefaultLayers(defaultLayers);
112 return copy;
113 }
114 return null;
115 } else {
116 return info;
117 }
118 default:
119 return info;
120 }
121 } catch (MalformedURLException ex) {
122 if (!GraphicsEnvironment.isHeadless()) {
123 JOptionPane.showMessageDialog(Main.parent, tr("Invalid service URL."),
124 tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
125 }
126 Logging.log(Logging.LEVEL_ERROR, ex);
127 } catch (IOException ex) {
128 if (!GraphicsEnvironment.isHeadless()) {
129 JOptionPane.showMessageDialog(Main.parent, tr("Could not retrieve WMS layer list."),
130 tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
131 }
132 Logging.log(Logging.LEVEL_ERROR, ex);
133 } catch (WMSGetCapabilitiesException ex) {
134 if (!GraphicsEnvironment.isHeadless()) {
135 JOptionPane.showMessageDialog(Main.parent, tr("Could not parse WMS layer list."),
136 tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
137 }
138 Logging.log(Logging.LEVEL_ERROR, "Could not parse WMS layer list. Incoming data:\n"+ex.getIncomingData(), ex);
139 } catch (WMTSGetCapabilitiesException e) {
140 if (!GraphicsEnvironment.isHeadless()) {
141 JOptionPane.showMessageDialog(Main.parent, tr("Could not parse WMTS layer list."),
142 tr("WMTS Error"), JOptionPane.ERROR_MESSAGE);
143 }
144 Logging.log(Logging.LEVEL_ERROR, "Could not parse WMTS layer list.", e);
145 }
146 return null;
147 }
148
149 @Override
150 public void actionPerformed(ActionEvent e) {
151 if (!isEnabled()) return;
152 ImageryLayer layer = null;
153 try {
154 final ImageryInfo infoToAdd = convertImagery(info);
155 if (infoToAdd != null) {
156 layer = ImageryLayer.create(infoToAdd);
157 getLayerManager().addLayer(layer);
158 AlignImageryPanel.addNagPanelIfNeeded(infoToAdd);
159 }
160 } catch (IllegalArgumentException | ReportedException ex) {
161 if (ex.getMessage() == null || ex.getMessage().isEmpty() || GraphicsEnvironment.isHeadless()) {
162 throw ex;
163 } else {
164 Logging.error(ex);
165 JOptionPane.showMessageDialog(Main.parent, ex.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE);
166 if (layer != null) {
167 getLayerManager().removeLayer(layer);
168 }
169 }
170 }
171 }
172
173 /**
174 * Asks user to choose a WMS layer from a WMS endpoint.
175 * @param info the WMS endpoint.
176 * @return chosen WMS layer, or null
177 * @throws IOException if any I/O error occurs while contacting the WMS endpoint
178 * @throws WMSGetCapabilitiesException if the WMS getCapabilities request fails
179 */
180 protected static ImageryInfo getWMSLayerInfo(ImageryInfo info) throws IOException, WMSGetCapabilitiesException {
181 try {
182 CheckParameterUtil.ensureThat(ImageryType.WMS_ENDPOINT.equals(info.getImageryType()), "wms_endpoint imagery type expected");
183 final WMSImagery wms = new WMSImagery(info.getUrl());
184
185 final WMSLayerTree tree = new WMSLayerTree();
186 tree.updateTree(wms);
187
188 Collection<String> wmsFormats = wms.getFormats();
189 final JComboBox<String> formats = new JComboBox<>(wmsFormats.toArray(new String[0]));
190 formats.setSelectedItem(wms.getPreferredFormat());
191 formats.setToolTipText(tr("Select image format for WMS layer"));
192
193 if (!GraphicsEnvironment.isHeadless() &&
194 1 != new ExtendedDialog(Main.parent, tr("Select WMS layers"), tr("Add layers"), tr("Cancel")) { {
195 final JScrollPane scrollPane = new JScrollPane(tree.getLayerTree());
196 scrollPane.setPreferredSize(new Dimension(400, 400));
197 final JPanel panel = new JPanel(new GridBagLayout());
198 panel.add(scrollPane, GBC.eol().fill());
199 panel.add(formats, GBC.eol().fill(GBC.HORIZONTAL));
200 setContent(panel);
201 } }.showDialog().getValue()) {
202 return null;
203 }
204
205 final String url = wms.buildGetMapUrl(
206 tree.getSelectedLayers().stream().map(LayerDetails::getName).collect(Collectors.toList()),
207 (List<String>) null,
208 (String) formats.getSelectedItem(),
209 true // TODO: ask the user if transparent layer is wanted
210 );
211
212 String selectedLayers = tree.getSelectedLayers().stream()
213 .map(LayerDetails::getName)
214 .collect(Collectors.joining(", "));
215 ImageryInfo ret = new ImageryInfo(info.getName() + selectedLayers,
216 url,
217 "wms",
218 info.getEulaAcceptanceRequired(),
219 info.getCookies());
220
221 ret.setServerProjections(wms.getServerProjections(tree.getSelectedLayers()));
222
223 return ret;
224 } catch (MalformedURLException ex) {
225 if (!GraphicsEnvironment.isHeadless()) {
226 JOptionPane.showMessageDialog(Main.parent, tr("Invalid service URL."),
227 tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
228 }
229 Logging.log(Logging.LEVEL_ERROR, ex);
230 } catch (IOException ex) {
231 if (!GraphicsEnvironment.isHeadless()) {
232 JOptionPane.showMessageDialog(Main.parent, tr("Could not retrieve WMS layer list."),
233 tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
234 }
235 Logging.log(Logging.LEVEL_ERROR, ex);
236 } catch (WMSGetCapabilitiesException ex) {
237 if (!GraphicsEnvironment.isHeadless()) {
238 JOptionPane.showMessageDialog(Main.parent, tr("Could not parse WMS layer list."),
239 tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
240 }
241 Logging.log(Logging.LEVEL_ERROR, "Could not parse WMS layer list. Incoming data:\n"+ex.getIncomingData(), ex);
242 }
243 return null;
244 }
245
246 @Override
247 protected void updateEnabledState() {
248 if (info.isBlacklisted()) {
249 setEnabled(false);
250 } else {
251 setEnabled(true);
252 }
253 }
254
255 @Override
256 public String toString() {
257 return "AddImageryLayerAction [info=" + info + ']';
258 }
259}
Note: See TracBrowser for help on using the repository browser.