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

Last change on this file since 8131 was 8068, checked in by Don-vip, 9 years ago

fix #11076 - robustness to unsupported WMS rectifier imagery types

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