source: josm/trunk/src/org/openstreetmap/josm/actions/MapRectifierWMSmenuAction.java@ 12517

Last change on this file since 12517 was 12469, checked in by Don-vip, 7 years ago

fix #15012 - Support WMS endpoint in Imagery -> Rectified Image

  • Property svn:eol-style set to native
File size: 10.4 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.GridBagConstraints;
8import java.awt.GridBagLayout;
9import java.awt.event.ActionEvent;
10import java.awt.event.KeyEvent;
11import java.io.IOException;
12import java.util.ArrayList;
13import java.util.List;
14import java.util.regex.Matcher;
15import java.util.regex.Pattern;
16
17import javax.swing.ButtonGroup;
18import javax.swing.JLabel;
19import javax.swing.JOptionPane;
20import javax.swing.JPanel;
21import javax.swing.JRadioButton;
22
23import org.openstreetmap.josm.Main;
24import org.openstreetmap.josm.data.imagery.ImageryInfo;
25import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
26import org.openstreetmap.josm.gui.ExtendedDialog;
27import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
28import org.openstreetmap.josm.gui.layer.WMSLayer;
29import org.openstreetmap.josm.gui.widgets.JosmTextField;
30import org.openstreetmap.josm.gui.widgets.UrlLabel;
31import org.openstreetmap.josm.io.imagery.WMSImagery.WMSGetCapabilitiesException;
32import org.openstreetmap.josm.tools.GBC;
33import org.openstreetmap.josm.tools.Shortcut;
34
35/**
36 * Download rectified images from various services.
37 * @since 3715
38 */
39public class MapRectifierWMSmenuAction extends JosmAction {
40
41 /**
42 * Class that bundles all required information of a rectifier service
43 */
44 public static class RectifierService {
45 private final String name;
46 private final String url;
47 private final String wmsUrl;
48 private final Pattern urlRegEx;
49 private final Pattern idValidator;
50 private JRadioButton btn;
51
52 /**
53 * @param name Name of the rectifing service
54 * @param url URL to the service where users can register, upload, etc.
55 * @param wmsUrl URL to the WMS server where JOSM will grab the images. Insert __s__ where the ID should be placed
56 * @param urlRegEx a regular expression that determines if a given URL is one of the service and returns the WMS id if so
57 * @param idValidator regular expression that checks if a given ID is syntactically valid
58 */
59 public RectifierService(String name, String url, String wmsUrl, String urlRegEx, String idValidator) {
60 this.name = name;
61 this.url = url;
62 this.wmsUrl = wmsUrl;
63 this.urlRegEx = Pattern.compile(urlRegEx);
64 this.idValidator = Pattern.compile(idValidator);
65 }
66
67 private boolean isSelected() {
68 return btn.isSelected();
69 }
70 }
71
72 /**
73 * List of available rectifier services.
74 */
75 private final transient List<RectifierService> services = new ArrayList<>();
76
77 /**
78 * Constructs a new {@code MapRectifierWMSmenuAction}.
79 */
80 public MapRectifierWMSmenuAction() {
81 super(tr("Rectified Image..."),
82 "OLmarker",
83 tr("Download Rectified Images From Various Services"),
84 Shortcut.registerShortcut("imagery:rectimg",
85 tr("Imagery: {0}", tr("Rectified Image...")),
86 KeyEvent.CHAR_UNDEFINED, Shortcut.NONE),
87 true
88 );
89 putValue("help", ht("/Menu/Imagery"));
90
91 // Add default services
92 services.add(
93 new RectifierService("Metacarta Map Rectifier",
94 "http://labs.metacarta.com/rectifier/",
95 "http://labs.metacarta.com/rectifier/wms.cgi?id=__s__&srs=EPSG:4326"
96 + "&Service=WMS&Version=1.1.0&Request=GetMap&format=image/png&",
97 // This matches more than the "classic" WMS link, so users can pretty much
98 // copy any link as long as it includes the ID
99 "labs\\.metacarta\\.com/(?:.*?)(?:/|=)([0-9]+)(?:\\?|/|\\.|$)",
100 "^[0-9]+$")
101 );
102 services.add(
103 new RectifierService("Map Warper",
104 "http://mapwarper.net/",
105 "http://mapwarper.net/maps/wms/__s__?request=GetMap&version=1.1.1"
106 + "&styles=&format=image/png&srs=epsg:4326&exceptions=application/vnd.ogc.se_inimage&",
107 // This matches more than the "classic" WMS link, so users can pretty much
108 // copy any link as long as it includes the ID
109 "(?:mapwarper\\.net|warper\\.geothings\\.net)/(?:.*?)/([0-9]+)(?:\\?|/|\\.|$)",
110 "^[0-9]+$")
111 );
112
113 // This service serves the purpose of "just this once" without forcing the user
114 // to commit the link to the preferences
115
116 // Clipboard content gets trimmed, so matching whitespace only ensures that this
117 // service will never be selected automatically.
118 services.add(new RectifierService(tr("Custom WMS Link"), "", "", "^\\s+$", ""));
119 }
120
121 @Override
122 public void actionPerformed(ActionEvent e) {
123 if (!isEnabled()) return;
124 JPanel panel = new JPanel(new GridBagLayout());
125 panel.add(new JLabel(tr("Supported Rectifier Services:")), GBC.eol());
126
127 JosmTextField tfWmsUrl = new JosmTextField(30);
128
129 String clip = ClipboardUtils.getClipboardStringContent();
130 clip = clip == null ? "" : clip.trim();
131 ButtonGroup group = new ButtonGroup();
132
133 JRadioButton firstBtn = null;
134 for (RectifierService s : services) {
135 JRadioButton serviceBtn = new JRadioButton(s.name);
136 if (firstBtn == null) {
137 firstBtn = serviceBtn;
138 }
139 // Checks clipboard contents against current service if no match has been found yet.
140 // If the contents match, they will be inserted into the text field and the corresponding
141 // service will be pre-selected.
142 if (!clip.isEmpty() && tfWmsUrl.getText().isEmpty()
143 && (s.urlRegEx.matcher(clip).find() || s.idValidator.matcher(clip).matches())) {
144 serviceBtn.setSelected(true);
145 tfWmsUrl.setText(clip);
146 }
147 s.btn = serviceBtn;
148 group.add(serviceBtn);
149 if (!s.url.isEmpty()) {
150 panel.add(serviceBtn, GBC.std());
151 panel.add(new UrlLabel(s.url, tr("Visit Homepage")), GBC.eol().anchor(GridBagConstraints.EAST));
152 } else {
153 panel.add(serviceBtn, GBC.eol().anchor(GridBagConstraints.WEST));
154 }
155 }
156
157 // Fallback in case no match was found
158 if (tfWmsUrl.getText().isEmpty() && firstBtn != null) {
159 firstBtn.setSelected(true);
160 }
161
162 panel.add(new JLabel(tr("WMS URL or Image ID:")), GBC.eol());
163 panel.add(tfWmsUrl, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
164
165 ExtendedDialog diag = new ExtendedDialog(Main.parent,
166 tr("Add Rectified Image"),
167 tr("Add Rectified Image"), tr("Cancel"))
168 .setContent(panel)
169 .setButtonIcons("OLmarker", "cancel");
170
171 // This repeatedly shows the dialog in case there has been an error.
172 // The loop is break;-ed if the users cancels
173 outer: while (true) {
174 diag.showDialog();
175 int answer = diag.getValue();
176 // Break loop when the user cancels
177 if (answer != 1) {
178 break;
179 }
180
181 String text = tfWmsUrl.getText().trim();
182 // Loop all services until we find the selected one
183 for (RectifierService s : services) {
184 if (!s.isSelected()) {
185 continue;
186 }
187
188 // We've reached the custom WMS URL service
189 // Just set the URL and hope everything works out
190 if (s.wmsUrl.isEmpty()) {
191 try {
192 addWMSLayer(s.name + " (" + text + ')', text);
193 break outer;
194 } catch (IllegalStateException ex) {
195 Main.error(ex, false);
196 }
197 }
198
199 // First try to match if the entered string as an URL
200 Matcher m = s.urlRegEx.matcher(text);
201 if (m.find()) {
202 String id = m.group(1);
203 String newURL = s.wmsUrl.replaceAll("__s__", id);
204 String title = s.name + " (" + id + ')';
205 addWMSLayer(title, newURL);
206 break outer;
207 }
208 // If not, look if it's a valid ID for the selected service
209 if (s.idValidator.matcher(text).matches()) {
210 String newURL = s.wmsUrl.replaceAll("__s__", text);
211 String title = s.name + " (" + text + ')';
212 addWMSLayer(title, newURL);
213 break outer;
214 }
215
216 // We've found the selected service, but the entered string isn't suitable for
217 // it. So quit checking the other radio buttons
218 break;
219 }
220
221 // and display an error message. The while loop ensures that the dialog pops up again
222 JOptionPane.showMessageDialog(Main.parent,
223 tr("Couldn''t match the entered link or id to the selected service. Please try again."),
224 tr("No valid WMS URL or id"),
225 JOptionPane.ERROR_MESSAGE);
226 diag.setVisible(true);
227 }
228 }
229
230 /**
231 * Adds a WMS Layer with given title and URL
232 * @param title Name of the layer as it will shop up in the layer manager
233 * @param url URL to the WMS server
234 * @throws IllegalStateException if imagery time is neither HTML nor WMS
235 */
236 private static void addWMSLayer(String title, String url) {
237 ImageryInfo info = new ImageryInfo(title, url);
238 if (info.getImageryType() == ImageryType.WMS_ENDPOINT) {
239 try {
240 info = AddImageryLayerAction.getWMSLayerInfo(info);
241 } catch (IOException | WMSGetCapabilitiesException e) {
242 Main.error(e);
243 JOptionPane.showMessageDialog(Main.parent, e.getMessage(), tr("No valid WMS URL or id"), JOptionPane.ERROR_MESSAGE);
244 return;
245 }
246 }
247 Main.getLayerManager().addLayer(new WMSLayer(info));
248 }
249
250 @Override
251 protected void updateEnabledState() {
252 setEnabled(!Main.getLayerManager().getLayers().isEmpty());
253 }
254}
Note: See TracBrowser for help on using the repository browser.