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