// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.actions; import static org.openstreetmap.josm.gui.help.HelpUtil.ht; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.BorderLayout; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.Optional; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.gui.ExtendedDialog; import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.gui.MapView; import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; import org.openstreetmap.josm.gui.widgets.JosmTextField; import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator; import org.openstreetmap.josm.tools.GBC; import org.openstreetmap.josm.tools.ImageProvider; import org.openstreetmap.josm.tools.Logging; import org.openstreetmap.josm.tools.OsmUrlToBounds; import org.openstreetmap.josm.tools.Shortcut; /** * Allows to jump to a specific location. * @since 2575 */ public class JumpToAction extends JosmAction { private final JosmTextField url = new JosmTextField(); private final JosmTextField lat = new JosmTextField(); private final JosmTextField lon = new JosmTextField(); private final JosmTextField zm = new JosmTextField(); /** * Constructs a new {@code JumpToAction}. */ public JumpToAction() { super(tr("Jump To Position"), (ImageProvider) null, tr("Opens a dialog that allows to jump to a specific location"), Shortcut.registerShortcut("tools:jumpto", tr("Tool: {0}", tr("Jump To Position")), KeyEvent.VK_J, Shortcut.CTRL), true, "action/jumpto", true); putValue("help", ht("/Action/JumpToPosition")); } static class JumpToPositionDialog extends ExtendedDialog { JumpToPositionDialog(String[] buttons, JPanel panel) { super(Main.parent, tr("Jump to Position"), buttons); setContent(panel); setCancelButton(2); } } class OsmURLListener implements DocumentListener { @Override public void changedUpdate(DocumentEvent e) { parseURL(); } @Override public void insertUpdate(DocumentEvent e) { parseURL(); } @Override public void removeUpdate(DocumentEvent e) { parseURL(); } } class OsmLonLatListener implements DocumentListener { @Override public void changedUpdate(DocumentEvent e) { updateUrl(false); } @Override public void insertUpdate(DocumentEvent e) { updateUrl(false); } @Override public void removeUpdate(DocumentEvent e) { updateUrl(false); } } /** * Displays the "Jump to" dialog. */ public void showJumpToDialog() { if (!MainApplication.isDisplayingMapView()) { return; } MapView mv = MainApplication.getMap().mapView; final Optional boundsFromClipboard = Optional .ofNullable(ClipboardUtils.getClipboardStringContent()) .map(OsmUrlToBounds::parse); if (boundsFromClipboard.isPresent()) { setBounds(boundsFromClipboard.get()); } else { setBounds(mv.getState().getViewArea().getCornerBounds()); } updateUrl(true); JPanel panel = new JPanel(new BorderLayout()); panel.add(new JLabel("" + tr("Enter Lat/Lon to jump to position.") + "
" + tr("You can also paste an URL from www.openstreetmap.org") + "
" + ""), BorderLayout.NORTH); OsmLonLatListener x = new OsmLonLatListener(); lat.getDocument().addDocumentListener(x); lon.getDocument().addDocumentListener(x); zm.getDocument().addDocumentListener(x); url.getDocument().addDocumentListener(new OsmURLListener()); SelectAllOnFocusGainedDecorator.decorate(lat); SelectAllOnFocusGainedDecorator.decorate(lon); SelectAllOnFocusGainedDecorator.decorate(zm); SelectAllOnFocusGainedDecorator.decorate(url); JPanel p = new JPanel(new GridBagLayout()); panel.add(p, BorderLayout.NORTH); p.add(new JLabel(tr("Latitude")), GBC.eol()); p.add(lat, GBC.eol().fill(GBC.HORIZONTAL)); p.add(new JLabel(tr("Longitude")), GBC.eol()); p.add(lon, GBC.eol().fill(GBC.HORIZONTAL)); p.add(new JLabel(tr("Zoom (in metres)")), GBC.eol()); p.add(zm, GBC.eol().fill(GBC.HORIZONTAL)); p.add(new JLabel(tr("URL")), GBC.eol()); p.add(url, GBC.eol().fill(GBC.HORIZONTAL)); String[] buttons = {tr("Jump there"), tr("Cancel")}; LatLon ll = null; double zoomLvl = 100; while (ll == null) { final int option = new JumpToPositionDialog(buttons, panel).showDialog().getValue(); if (option != 1) return; try { zoomLvl = Double.parseDouble(zm.getText()); ll = new LatLon(Double.parseDouble(lat.getText()), Double.parseDouble(lon.getText())); } catch (NumberFormatException ex) { try { ll = LatLon.parse(lat.getText() + "; " + lon.getText()); } catch (IllegalArgumentException ex2) { JOptionPane.showMessageDialog(Main.parent, tr("Could not parse Latitude, Longitude or Zoom. Please check."), tr("Unable to parse Lon/Lat"), JOptionPane.ERROR_MESSAGE); } } } double zoomFactor = 1/ mv.getDist100Pixel(); mv.zoomToFactor(mv.getProjection().latlon2eastNorth(ll), zoomFactor * zoomLvl); } private void parseURL() { if (!url.hasFocus()) return; String urlText = url.getText(); Bounds b = OsmUrlToBounds.parse(urlText); setBounds(b); } private void setBounds(Bounds b) { if (b != null) { final LatLon center = b.getCenter(); lat.setText(Double.toString(center.lat())); lon.setText(Double.toString(center.lon())); zm.setText(Double.toString(OsmUrlToBounds.getZoom(b))); } } private void updateUrl(boolean force) { if (!lat.hasFocus() && !lon.hasFocus() && !zm.hasFocus() && !force) return; try { double dlat = Double.parseDouble(lat.getText()); double dlon = Double.parseDouble(lon.getText()); double zoomLvl = Double.parseDouble(zm.getText()); url.setText(OsmUrlToBounds.getURL(dlat, dlon, (int) zoomLvl)); } catch (NumberFormatException e) { Logging.debug(e.getMessage()); } } @Override public void actionPerformed(ActionEvent e) { showJumpToDialog(); } @Override protected void updateEnabledState() { setEnabled(MainApplication.isDisplayingMapView()); } @Override protected void installAdapters() { super.installAdapters(); // make this action listen to mapframe change events MainApplication.addMapFrameListener((o, n) -> updateEnabledState()); } }