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

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

see #15229 - deprecate Main.parent and Main itself

  • Property svn:eol-style set to native
File size: 11.0 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.Collection;
14import java.util.Collections;
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.data.imagery.DefaultLayer;
24import org.openstreetmap.josm.data.imagery.ImageryInfo;
25import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
26import org.openstreetmap.josm.data.imagery.LayerDetails;
27import org.openstreetmap.josm.data.imagery.WMTSTileSource;
28import org.openstreetmap.josm.data.imagery.WMTSTileSource.Layer;
29import org.openstreetmap.josm.data.imagery.WMTSTileSource.WMTSGetCapabilitiesException;
30import org.openstreetmap.josm.gui.ExtendedDialog;
31import org.openstreetmap.josm.gui.MainApplication;
32import org.openstreetmap.josm.gui.layer.AlignImageryPanel;
33import org.openstreetmap.josm.gui.layer.ImageryLayer;
34import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
35import org.openstreetmap.josm.gui.preferences.imagery.WMSLayerTree;
36import org.openstreetmap.josm.gui.util.GuiHelper;
37import org.openstreetmap.josm.io.imagery.WMSImagery;
38import org.openstreetmap.josm.io.imagery.WMSImagery.WMSGetCapabilitiesException;
39import org.openstreetmap.josm.tools.CheckParameterUtil;
40import org.openstreetmap.josm.tools.GBC;
41import org.openstreetmap.josm.tools.ImageProvider;
42import org.openstreetmap.josm.tools.Logging;
43import org.openstreetmap.josm.tools.bugreport.ReportedException;
44
45/**
46 * Action displayed in imagery menu to add a new imagery layer.
47 * @since 3715
48 */
49public class AddImageryLayerAction extends JosmAction implements AdaptableAction {
50 private final transient ImageryInfo info;
51
52 static class SelectWmsLayersDialog extends ExtendedDialog {
53 SelectWmsLayersDialog(WMSLayerTree tree, JComboBox<String> formats) {
54 super(MainApplication.getMainFrame(), tr("Select WMS layers"), tr("Add layers"), tr("Cancel"));
55 final JScrollPane scrollPane = new JScrollPane(tree.getLayerTree());
56 scrollPane.setPreferredSize(new Dimension(400, 400));
57 final JPanel panel = new JPanel(new GridBagLayout());
58 panel.add(scrollPane, GBC.eol().fill());
59 panel.add(formats, GBC.eol().fill(GBC.HORIZONTAL));
60 setContent(panel);
61 }
62 }
63
64 /**
65 * Constructs a new {@code AddImageryLayerAction} for the given {@code ImageryInfo}.
66 * If an http:// icon is specified, it is fetched asynchronously.
67 * @param info The imagery info
68 */
69 public AddImageryLayerAction(ImageryInfo info) {
70 super(info.getMenuName(), /* ICON */"imagery_menu", tr("Add imagery layer {0}", info.getName()), null,
71 true, ToolbarPreferences.IMAGERY_PREFIX + info.getToolbarName(), false);
72 putValue("help", ht("/Preferences/Imagery"));
73 setTooltip(info.getToolTipText().replaceAll("</?html>", ""));
74 this.info = info;
75 installAdapters();
76
77 // change toolbar icon from if specified
78 String icon = info.getIcon();
79 if (icon != null) {
80 new ImageProvider(icon).setOptional(true).getResourceAsync(result -> {
81 if (result != null) {
82 GuiHelper.runInEDT(() -> result.attachImageIcon(this));
83 }
84 });
85 }
86 }
87
88 /**
89 * Converts general ImageryInfo to specific one, that does not need any user action to initialize
90 * see: https://josm.openstreetmap.de/ticket/13868
91 * @param info ImageryInfo that will be converted (or returned when no conversion needed)
92 * @return ImageryInfo object that's ready to be used to create TileSource
93 */
94 private ImageryInfo convertImagery(ImageryInfo info) {
95 try {
96 switch(info.getImageryType()) {
97 case WMS_ENDPOINT:
98 // convert to WMS type
99 if (info.getDefaultLayers() == null || info.getDefaultLayers().isEmpty()) {
100 return getWMSLayerInfo(info);
101 } else {
102 return info;
103 }
104 case WMTS:
105 // specify which layer to use
106 if (info.getDefaultLayers() == null || info.getDefaultLayers().isEmpty()) {
107 WMTSTileSource tileSource = new WMTSTileSource(info);
108 DefaultLayer layerId = tileSource.userSelectLayer();
109 if (layerId != null) {
110 ImageryInfo copy = new ImageryInfo(info);
111 copy.setDefaultLayers(Collections.singletonList(layerId));
112 String layerName = tileSource.getLayers().stream()
113 .filter(x -> x.getIdentifier().equals(layerId.getLayerName()))
114 .map(Layer::getUserTitle)
115 .findFirst()
116 .orElse("");
117 copy.setName(copy.getName() + ": " + layerName);
118 return copy;
119 }
120 return null;
121 } else {
122 return info;
123 }
124 default:
125 return info;
126 }
127 } catch (MalformedURLException ex) {
128 handleException(ex, tr("Invalid service URL."), tr("WMS Error"), null);
129 } catch (IOException ex) {
130 handleException(ex, tr("Could not retrieve WMS layer list."), tr("WMS Error"), null);
131 } catch (WMSGetCapabilitiesException ex) {
132 handleException(ex, tr("Could not parse WMS layer list."), tr("WMS Error"),
133 "Could not parse WMS layer list. Incoming data:\n" + ex.getIncomingData());
134 } catch (WMTSGetCapabilitiesException ex) {
135 handleException(ex, tr("Could not parse WMTS layer list."), tr("WMTS Error"),
136 "Could not parse WMTS layer list.");
137 }
138 return null;
139 }
140
141 @Override
142 public void actionPerformed(ActionEvent e) {
143 if (!isEnabled()) return;
144 ImageryLayer layer = null;
145 try {
146 final ImageryInfo infoToAdd = convertImagery(info);
147 if (infoToAdd != null) {
148 layer = ImageryLayer.create(infoToAdd);
149 getLayerManager().addLayer(layer);
150 AlignImageryPanel.addNagPanelIfNeeded(infoToAdd);
151 }
152 } catch (IllegalArgumentException | ReportedException ex) {
153 if (ex.getMessage() == null || ex.getMessage().isEmpty() || GraphicsEnvironment.isHeadless()) {
154 throw ex;
155 } else {
156 Logging.error(ex);
157 JOptionPane.showMessageDialog(MainApplication.getMainFrame(), ex.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE);
158 if (layer != null) {
159 getLayerManager().removeLayer(layer);
160 }
161 }
162 }
163 }
164
165 /**
166 * Asks user to choose a WMS layer from a WMS endpoint.
167 * @param info the WMS endpoint.
168 * @return chosen WMS layer, or null
169 * @throws IOException if any I/O error occurs while contacting the WMS endpoint
170 * @throws WMSGetCapabilitiesException if the WMS getCapabilities request fails
171 */
172 protected static ImageryInfo getWMSLayerInfo(ImageryInfo info) throws IOException, WMSGetCapabilitiesException {
173 try {
174 CheckParameterUtil.ensureThat(ImageryType.WMS_ENDPOINT.equals(info.getImageryType()), "wms_endpoint imagery type expected");
175 final WMSImagery wms = new WMSImagery(info.getUrl(), info.getCustomHttpHeaders());
176
177 final WMSLayerTree tree = new WMSLayerTree();
178 tree.updateTree(wms);
179
180 Collection<String> wmsFormats = wms.getFormats();
181 final JComboBox<String> formats = new JComboBox<>(wmsFormats.toArray(new String[0]));
182 formats.setSelectedItem(wms.getPreferredFormat());
183 formats.setToolTipText(tr("Select image format for WMS layer"));
184
185 if (!GraphicsEnvironment.isHeadless()) {
186 ExtendedDialog dialog = new ExtendedDialog(MainApplication.getMainFrame(),
187 tr("Select WMS layers"), tr("Add layers"), tr("Cancel"));
188 final JScrollPane scrollPane = new JScrollPane(tree.getLayerTree());
189 scrollPane.setPreferredSize(new Dimension(400, 400));
190 final JPanel panel = new JPanel(new GridBagLayout());
191 panel.add(scrollPane, GBC.eol().fill());
192 panel.add(formats, GBC.eol().fill(GBC.HORIZONTAL));
193 dialog.setContent(panel);
194
195 if (dialog.showDialog().getValue() != 1) {
196 return null;
197 }
198 }
199
200 final String url = wms.buildGetMapUrl(
201 tree.getSelectedLayers().stream().map(LayerDetails::getName).collect(Collectors.toList()),
202 (List<String>) null,
203 (String) formats.getSelectedItem(),
204 true // TODO: ask the user if transparent layer is wanted
205 );
206
207 String selectedLayers = tree.getSelectedLayers().stream()
208 .map(LayerDetails::getName)
209 .collect(Collectors.joining(", "));
210 // Use full copy of original Imagery info to copy all attributes. Only overwrite what's different
211 ImageryInfo ret = new ImageryInfo(info);
212 ret.setUrl(url);
213 ret.setImageryType(ImageryType.WMS);
214 ret.setName(info.getName() + selectedLayers);
215 ret.setServerProjections(wms.getServerProjections(tree.getSelectedLayers()));
216 return ret;
217 } catch (MalformedURLException ex) {
218 handleException(ex, tr("Invalid service URL."), tr("WMS Error"), null);
219 } catch (IOException ex) {
220 handleException(ex, tr("Could not retrieve WMS layer list."), tr("WMS Error"), null);
221 } catch (WMSGetCapabilitiesException ex) {
222 handleException(ex, tr("Could not parse WMS layer list."), tr("WMS Error"),
223 "Could not parse WMS layer list. Incoming data:\n" + ex.getIncomingData());
224 }
225 return null;
226 }
227
228 private static void handleException(Exception ex, String uiMessage, String uiTitle, String logMessage) {
229 if (!GraphicsEnvironment.isHeadless()) {
230 JOptionPane.showMessageDialog(MainApplication.getMainFrame(), uiMessage, uiTitle, JOptionPane.ERROR_MESSAGE);
231 }
232 Logging.log(Logging.LEVEL_ERROR, logMessage, ex);
233 }
234
235 @Override
236 protected void updateEnabledState() {
237 if (info.isBlacklisted()) {
238 setEnabled(false);
239 } else {
240 setEnabled(true);
241 }
242 }
243
244 @Override
245 public String toString() {
246 return "AddImageryLayerAction [info=" + info + ']';
247 }
248}
Note: See TracBrowser for help on using the repository browser.