diff -Nru jmapviewer-2.7+dfsg/build.xml jmapviewer-2.10+dfsg/build.xml --- jmapviewer-2.7+dfsg/build.xml 2018-03-25 17:06:26.000000000 +0000 +++ jmapviewer-2.10+dfsg/build.xml 2018-12-02 02:23:08.000000000 +0000 @@ -1,30 +1,67 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - @@ -32,52 +69,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + classpath="tools/checkstyle/checkstyle-all.jar"/> @@ -86,7 +123,7 @@ + classpath="tools/spotbugs/spotbugs-ant.jar"/> @@ -103,7 +140,7 @@ - + - + JMapViewer - Javadoc]]> JMapViewer]]> + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru jmapviewer-2.7+dfsg/debian/changelog jmapviewer-2.10+dfsg/debian/changelog --- jmapviewer-2.7+dfsg/debian/changelog 2018-03-26 05:39:33.000000000 +0000 +++ jmapviewer-2.10+dfsg/debian/changelog 2019-06-10 08:00:00.000000000 +0000 @@ -1,3 +1,61 @@ +jmapviewer (2.10+dfsg-1~bionic0) bionic; urgency=medium + + * No change rebuild for Bionic. + + -- Angelos Tzotsos Mon, 10 Jun 2019 10:00:00 +0200 + +jmapviewer (2.10+dfsg-1~exp1) experimental; urgency=medium + + * New upstream release. + * Remove package name from lintian overrides. + * Update copyright years for Vincent Privat. + + -- Bas Couwenberg Fri, 31 May 2019 06:02:30 +0200 + +jmapviewer (2.9+dfsg-1) unstable; urgency=medium + + * New upstream release. + * Bump Standards-Version to 4.3.0, no changes. + + -- Bas Couwenberg Tue, 01 Jan 2019 10:16:40 +0100 + +jmapviewer (2.8+dfsg-1) unstable; urgency=medium + + * New upstream release. + * Bump Standards-Version to 4.2.1, no changes. + * Update copyright file, changes: + - Add Robert Scott to copyright holders. + - Add license & copyright for ScanexTileSource.java. + * Refresh patches. + + -- Bas Couwenberg Sun, 02 Dec 2018 11:47:36 +0100 + +jmapviewer (2.7+dfsg-4) unstable; urgency=medium + + * Remove .gitigore file. + * Bump Standards-Version to 4.2.0, no changes. + * Update watch file to handle changed HTML. + + -- Bas Couwenberg Sat, 18 Aug 2018 19:13:56 +0200 + +jmapviewer (2.7+dfsg-3) unstable; urgency=medium + + * Drop autopkgtest to test installability. + * Add lintian override for testsuite-autopkgtest-missing. + + -- Bas Couwenberg Tue, 31 Jul 2018 19:22:25 +0200 + +jmapviewer (2.7+dfsg-2) unstable; urgency=medium + + * Update Vcs-* URLs for Salsa. + * Drop override for vcs-deprecated-in-debian-infrastructure. + * Bump Standards-Version to 4.1.5, no changes. + * Document repacking in copyright file, drop obsolete README.source & + get-orig-source target. + * Strip trailing whitespace from control & rules files. + + -- Bas Couwenberg Thu, 19 Jul 2018 16:34:23 +0200 + jmapviewer (2.7+dfsg-1) unstable; urgency=medium * New upstream release. diff -Nru jmapviewer-2.7+dfsg/debian/control jmapviewer-2.10+dfsg/debian/control --- jmapviewer-2.7+dfsg/debian/control 2018-03-07 06:22:48.000000000 +0000 +++ jmapviewer-2.10+dfsg/debian/control 2019-01-06 07:15:19.000000000 +0000 @@ -12,9 +12,9 @@ docbook-xsl, docbook-xml, xsltproc -Standards-Version: 4.1.3 -Vcs-Browser: https://anonscm.debian.org/cgit/pkg-grass/jmapviewer.git -Vcs-Git: https://anonscm.debian.org/git/pkg-grass/jmapviewer.git +Standards-Version: 4.3.0 +Vcs-Browser: https://salsa.debian.org/debian-gis-team/jmapviewer +Vcs-Git: https://salsa.debian.org/debian-gis-team/jmapviewer.git Homepage: https://wiki.openstreetmap.org/wiki/JMapViewer Package: jmapviewer @@ -28,4 +28,3 @@ specific location on the map. . This package includes both the library and a demo application. - diff -Nru jmapviewer-2.7+dfsg/debian/copyright jmapviewer-2.10+dfsg/debian/copyright --- jmapviewer-2.7+dfsg/debian/copyright 2018-02-01 06:29:08.000000000 +0000 +++ jmapviewer-2.10+dfsg/debian/copyright 2019-05-31 04:02:05.000000000 +0000 @@ -1,6 +1,8 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: JMapViewer Source: https://svn.openstreetmap.org/applications/viewer/jmapviewer +Comment: The upstream source is repacked to exclude the Bing logo which is + non-free, see: https://lists.debian.org/debian-gis/2014/10/msg00147.html Files-Excluded: src/org/openstreetmap/gui/jmapviewer/images/bing_maps.png Files: * @@ -21,10 +23,15 @@ 2012-2016, Simon Legner 2015-2016, Wiktor Niesiobędzki 2011-2017, Paul Hartmann + 2017, Robert Scott 2009-2018, Dirk Stöcker - 2011-2018, Vincent Privat + 2011-2019, Vincent Privat License: GPL-2+ +Files: src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java +Copyright: 2011-2016, Gleb Smirnoff & Andrey Boltenkov +License: BSD-2-Clause or GPL-2+ + Files: debian/* Copyright: 2011-2013, Andrew Harvey 2013, Felix Natter diff -Nru jmapviewer-2.7+dfsg/debian/jmapviewer.lintian-overrides jmapviewer-2.10+dfsg/debian/jmapviewer.lintian-overrides --- jmapviewer-2.7+dfsg/debian/jmapviewer.lintian-overrides 2017-01-18 06:25:51.000000000 +0000 +++ jmapviewer-2.10+dfsg/debian/jmapviewer.lintian-overrides 2019-03-15 14:55:59.000000000 +0000 @@ -1,3 +1,3 @@ # this is a convenience jar for /usr/bin/jmapviewer which only contains Main-Class and Class-Path -jmapviewer binary: codeless-jar usr/share/jmapviewer/JMapViewer_Demo.jar +codeless-jar usr/share/jmapviewer/JMapViewer_Demo.jar diff -Nru jmapviewer-2.7+dfsg/debian/patches/01-build_less.patch jmapviewer-2.10+dfsg/debian/patches/01-build_less.patch --- jmapviewer-2.7+dfsg/debian/patches/01-build_less.patch 2017-12-02 17:15:55.000000000 +0000 +++ jmapviewer-2.10+dfsg/debian/patches/01-build_less.patch 2018-12-07 06:04:48.000000000 +0000 @@ -1,19 +1,16 @@ -From: Andrew Harvey -Subject: Adjustments to the ant build file +Description: Adjustments to the ant build file. + Only build the components required for the Debian package. +Author: Andrew Harvey Forwarded: not-needed -Last-Update: 2011-11-19 - -Adjustment to the ant build.xml file. Only building the components required for -this Debian package. --- a/build.xml +++ b/build.xml -@@ -1,7 +1,7 @@ - - +@@ -26,7 +26,7 @@ + + -- -+ +- ++ - - + + diff -Nru jmapviewer-2.7+dfsg/debian/patches/03-use-installed-library-in-demo.patch jmapviewer-2.10+dfsg/debian/patches/03-use-installed-library-in-demo.patch --- jmapviewer-2.7+dfsg/debian/patches/03-use-installed-library-in-demo.patch 2015-10-09 08:53:14.000000000 +0000 +++ jmapviewer-2.10+dfsg/debian/patches/03-use-installed-library-in-demo.patch 2018-12-07 06:04:48.000000000 +0000 @@ -1,19 +1,15 @@ -From: Andrew Harvey -Subject: Use installed library for the demo application +Description: Use installed library for the demo application. +Author: Andrew Harvey Forwarded: not-needed -Last-Update: 2013-03-15 - -Adjustment to the ant build.xml file. Using the system wide jmapviewer.jar -library for the JMapViewer_Demo application. --- a/build.xml +++ b/build.xml -@@ -50,7 +50,7 @@ - - - -- -+ - - - +@@ -87,7 +87,7 @@ + + + +- ++ + + + diff -Nru jmapviewer-2.7+dfsg/debian/README.source jmapviewer-2.10+dfsg/debian/README.source --- jmapviewer-2.7+dfsg/debian/README.source 2014-12-29 20:36:27.000000000 +0000 +++ jmapviewer-2.10+dfsg/debian/README.source 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -JMapViewer-1.0-Source.tar.gz is generated by 'get-orig-source' target. - -+dfsg1 suffix has been added because bing_maps.png shall be removed at import: - gbp import-orig --filter bing_maps.png --filter-pristine-tar --pristine-tar -u1.0+dfsg1 \ - ../JMapViewer-1.0-Source.tar.gz - -As an alternative, you can use the result of uscan (get-orig-source target), -which is also configured for removal of bing_maps.png (by means of Files-Excluded: -in debian/copyright). \ No newline at end of file diff -Nru jmapviewer-2.7+dfsg/debian/rules jmapviewer-2.10+dfsg/debian/rules --- jmapviewer-2.7+dfsg/debian/rules 2017-11-27 07:28:49.000000000 +0000 +++ jmapviewer-2.10+dfsg/debian/rules 2018-12-07 06:04:48.000000000 +0000 @@ -32,7 +32,3 @@ install -m 644 $(CURDIR)/JMapViewer_Demo.jar $(CURDIR)/debian/jmapviewer/usr/share/jmapviewer/JMapViewer_Demo.jar install -m 755 $(CURDIR)/debian/jmapviewer_demo.sh $(CURDIR)/debian/jmapviewer/usr/bin/jmapviewer - -get-orig-source: - uscan --verbose --force-download --repack --compress xz --destdir .. - diff -Nru jmapviewer-2.7+dfsg/debian/source/lintian-overrides jmapviewer-2.10+dfsg/debian/source/lintian-overrides --- jmapviewer-2.7+dfsg/debian/source/lintian-overrides 2018-03-26 05:39:03.000000000 +0000 +++ jmapviewer-2.10+dfsg/debian/source/lintian-overrides 2018-12-07 06:04:48.000000000 +0000 @@ -1,3 +1,3 @@ -# Package not officially migrated to Salsa yet. -jmapviewer source: vcs-deprecated-in-debian-infrastructure * https://anonscm.debian.org/* +# Not worth the effort +testsuite-autopkgtest-missing diff -Nru jmapviewer-2.7+dfsg/debian/tests/control jmapviewer-2.10+dfsg/debian/tests/control --- jmapviewer-2.7+dfsg/debian/tests/control 2017-07-08 08:39:42.000000000 +0000 +++ jmapviewer-2.10+dfsg/debian/tests/control 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -# Test installability -Depends: @ -Test-Command: /bin/true diff -Nru jmapviewer-2.7+dfsg/debian/watch jmapviewer-2.10+dfsg/debian/watch --- jmapviewer-2.7+dfsg/debian/watch 2016-08-18 08:07:59.000000000 +0000 +++ jmapviewer-2.10+dfsg/debian/watch 2018-12-07 06:04:48.000000000 +0000 @@ -1,3 +1,10 @@ version=3 -opts=dversionmangle=s/\+(debian|dfsg|ds|deb)\d*$//,repacksuffix=+dfsg \ -https://svn.openstreetmap.org/applications/viewer/jmapviewer/releases/(\d+(?:\.\d+)*)/JMapViewer-(\d\S*)-Source\.(?:tar\.(?:gz|bz2|xz)|tgz|tbz2|txz|zip) +opts="\ +dversionmangle=s/\+(debian|dfsg|ds|deb)\d*$//,\ +uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/;s/RC/rc/,\ +pagemangle=s//$1<\/a>/g,\ +downloadurlmangle=s/(\d+(?:\.\d+)*)/$1\/JMapViewer-$1-Source.zip/,\ +filenamemangle=s/(\d+(?:\.\d+)*)/JMapViewer-$1-Source.zip/,\ +repacksuffix=+dfsg" \ +https://svn.openstreetmap.org/applications/viewer/jmapviewer/releases/ \ +(\d+(?:\.\d+)*) diff -Nru jmapviewer-2.7+dfsg/Readme.txt jmapviewer-2.10+dfsg/Readme.txt --- jmapviewer-2.7+dfsg/Readme.txt 2018-03-25 17:06:26.000000000 +0000 +++ jmapviewer-2.10+dfsg/Readme.txt 2019-05-30 21:13:34.000000000 +0000 @@ -10,7 +10,7 @@ (c) 2010-2011, Michael Vigovsky (c) 2011-2017, Paul Hartmann (c) 2011-2016, Gleb Smirnoff -(c) 2011-2018, Vincent Privat +(c) 2011-2019, Vincent Privat (c) 2011, Jason Huntley (c) 2012-2016, Simon Legner (c) 2012, Teemu Koskinen diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxTree.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxTree.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxTree.java 2018-03-25 17:06:26.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxTree.java 2018-12-02 02:22:54.000000000 +0000 @@ -9,8 +9,6 @@ import javax.swing.JTree; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; @@ -108,13 +106,6 @@ final CheckBoxTree tree = new CheckBoxTree(root); ((DefaultMutableTreeNode) tree.getModel().getRoot()).add(new DefaultMutableTreeNode(new CheckBoxNodeData("gggg", null))); ((DefaultTreeModel) tree.getModel()).reload(); - // listen for changes in the selection - tree.addTreeSelectionListener(new TreeSelectionListener() { - @Override - public void valueChanged(final TreeSelectionEvent e) { - //System.out.println("selection changed"); - } - }); // show the tree on screen final JFrame frame = new JFrame("CheckBox Tree"); final JScrollPane scrollPane = new JScrollPane(tree); diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/Coordinate.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/Coordinate.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/Coordinate.java 2018-03-25 17:06:26.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/Coordinate.java 2018-10-29 12:03:12.000000000 +0000 @@ -19,6 +19,11 @@ public class Coordinate implements ICoordinate { private transient Point2D.Double data; + /** + * Constructs a new {@code Coordinate}. + * @param lat latitude in degrees + * @param lon longitude in degrees + */ public Coordinate(double lat, double lon) { data = new Point2D.Double(lon, lat); } @@ -61,20 +66,16 @@ @Override public int hashCode() { - int hash = 3; - hash = 61 * hash + Objects.hashCode(this.data); - return hash; + return Objects.hashCode(data); } @Override public boolean equals(Object obj) { - if (obj == null) { + if (this == obj) + return true; + if (obj == null || !(obj instanceof Coordinate)) return false; - } - if (getClass() != obj.getClass()) { - return false; - } final Coordinate other = (Coordinate) obj; - return Objects.equals(this.data, other.data); + return Objects.equals(data, other.data); } } diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/Demo.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/Demo.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/Demo.java 2018-03-25 17:06:22.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/Demo.java 2018-12-31 14:00:16.000000000 +0000 @@ -4,8 +4,6 @@ import java.awt.BorderLayout; import java.awt.Cursor; import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; @@ -79,15 +77,10 @@ + "left double click or mouse wheel to zoom."); helpPanel.add(helpLabel); JButton button = new JButton("setDisplayToFitMapMarkers"); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setDisplayToFitMapMarkers(); - } - }); + button.addActionListener(e -> map().setDisplayToFitMapMarkers()); JComboBox tileSourceSelector = new JComboBox<>(new TileSource[] { new OsmTileSource.Mapnik(), - new OsmTileSource.CycleMap(), + new OsmTileSource.TransportMap(), new BingAerialTileSource(), }); tileSourceSelector.addItemListener(new ItemListener() { @@ -109,57 +102,27 @@ panelTop.add(tileLoaderSelector); final JCheckBox showMapMarker = new JCheckBox("Map markers visible"); showMapMarker.setSelected(map().getMapMarkersVisible()); - showMapMarker.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setMapMarkerVisible(showMapMarker.isSelected()); - } - }); + showMapMarker.addActionListener(e -> map().setMapMarkerVisible(showMapMarker.isSelected())); panelBottom.add(showMapMarker); /// final JCheckBox showTreeLayers = new JCheckBox("Tree Layers visible"); - showTreeLayers.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - treeMap.setTreeVisible(showTreeLayers.isSelected()); - } - }); + showTreeLayers.addActionListener(e -> treeMap.setTreeVisible(showTreeLayers.isSelected())); panelBottom.add(showTreeLayers); /// final JCheckBox showToolTip = new JCheckBox("ToolTip visible"); - showToolTip.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setToolTipText(null); - } - }); + showToolTip.addActionListener(e -> map().setToolTipText(null)); panelBottom.add(showToolTip); /// final JCheckBox showTileGrid = new JCheckBox("Tile grid visible"); showTileGrid.setSelected(map().isTileGridVisible()); - showTileGrid.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setTileGridVisible(showTileGrid.isSelected()); - } - }); + showTileGrid.addActionListener(e -> map().setTileGridVisible(showTileGrid.isSelected())); panelBottom.add(showTileGrid); final JCheckBox showZoomControls = new JCheckBox("Show zoom controls"); showZoomControls.setSelected(map().getZoomControlsVisible()); - showZoomControls.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setZoomContolsVisible(showZoomControls.isSelected()); - } - }); + showZoomControls.addActionListener(e -> map().setZoomControlsVisible(showZoomControls.isSelected())); panelBottom.add(showZoomControls); final JCheckBox scrollWrapEnabled = new JCheckBox("Scrollwrap enabled"); - scrollWrapEnabled.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - map().setScrollWrapEnabled(scrollWrapEnabled.isSelected()); - } - }); + scrollWrapEnabled.addActionListener(e -> map().setScrollWrapEnabled(scrollWrapEnabled.isSelected())); panelBottom.add(scrollWrapEnabled); panelBottom.add(button); diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java 2018-03-25 17:06:22.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java 2019-05-30 13:46:40.000000000 +0000 @@ -2,17 +2,30 @@ package org.openstreetmap.gui.jmapviewer; import java.awt.Desktop; +import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.net.URL; import java.text.MessageFormat; +import java.util.Map; +import java.util.Objects; +import java.util.TreeMap; +import java.util.logging.Level; import java.util.logging.Logger; +import javax.imageio.ImageIO; + +/** + * Feature adapter allows to override JMapViewer behaviours from a client application such as JOSM. + */ public final class FeatureAdapter { private static BrowserAdapter browserAdapter = new DefaultBrowserAdapter(); + private static ImageAdapter imageAdapter = new DefaultImageAdapter(); private static TranslationAdapter translationAdapter = new DefaultTranslationAdapter(); private static LoggingAdapter loggingAdapter = new DefaultLoggingAdapter(); + private static SettingsAdapter settingsAdapter = new DefaultSettingsAdapter(); private FeatureAdapter() { // private constructor for utility classes @@ -31,22 +44,65 @@ Logger getLogger(String name); } + public interface ImageAdapter { + BufferedImage read(URL input, boolean readMetadata, boolean enforceTransparency) throws IOException; + } + + /** + * Basic settings system allowing to store/retrieve String key/value pairs. + */ + public interface SettingsAdapter { + /** + * Get settings value for a certain key and provide a default value. + * @param key the identifier for the setting + * @param def the default value. For each call of get() with a given key, the + * default value must be the same. {@code def} may be null. + * @return the corresponding value if the property has been set before, {@code def} otherwise + */ + String get(String key, String def); + + /** + * Set a value for a certain setting. + * @param key the unique identifier for the setting + * @param value the value of the setting. Can be null or "" which both removes the key-value entry. + * @return {@code true}, if something has changed (i.e. value is different than before) + */ + boolean put(String key, String value); + } + public static void registerBrowserAdapter(BrowserAdapter browserAdapter) { - FeatureAdapter.browserAdapter = browserAdapter; + FeatureAdapter.browserAdapter = Objects.requireNonNull(browserAdapter); + } + + public static void registerImageAdapter(ImageAdapter imageAdapter) { + FeatureAdapter.imageAdapter = Objects.requireNonNull(imageAdapter); } public static void registerTranslationAdapter(TranslationAdapter translationAdapter) { - FeatureAdapter.translationAdapter = translationAdapter; + FeatureAdapter.translationAdapter = Objects.requireNonNull(translationAdapter); } public static void registerLoggingAdapter(LoggingAdapter loggingAdapter) { - FeatureAdapter.loggingAdapter = loggingAdapter; + FeatureAdapter.loggingAdapter = Objects.requireNonNull(loggingAdapter); + } + + /** + * Registers settings adapter. + * @param settingsAdapter settings adapter, must not be null + * @throws NullPointerException if settingsAdapter is null + */ + public static void registerSettingsAdapter(SettingsAdapter settingsAdapter) { + FeatureAdapter.settingsAdapter = Objects.requireNonNull(settingsAdapter); } public static void openLink(String url) { browserAdapter.openLink(url); } + public static BufferedImage readImage(URL url) throws IOException { + return imageAdapter.read(url, false, false); + } + public static String tr(String text, Object... objects) { return translationAdapter.tr(text, objects); } @@ -55,6 +111,42 @@ return loggingAdapter.getLogger(name); } + public static Logger getLogger(Class klass) { + return loggingAdapter.getLogger(klass.getSimpleName()); + } + + /** + * Get settings value for a certain key and provide a default value. + * @param key the identifier for the setting + * @param def the default value. For each call of get() with a given key, the + * default value must be the same. {@code def} may be null. + * @return the corresponding value if the property has been set before, {@code def} otherwise + */ + public static String getSetting(String key, String def) { + return settingsAdapter.get(key, def); + } + + /** + * Get settings value for a certain key and provide a default value. + * @param key the identifier for the setting + * @param def the default value. For each call of get() with a given key, the + * default value must be the same. {@code def} may be null. + * @return the corresponding value if the property has been set before, {@code def} otherwise + */ + public static int getIntSetting(String key, int def) { + return Integer.parseInt(settingsAdapter.get(key, Integer.toString(def))); + } + + /** + * Set a value for a certain setting. + * @param key the unique identifier for the setting + * @param value the value of the setting. Can be null or "" which both removes the key-value entry. + * @return {@code true}, if something has changed (i.e. value is different than before) + */ + public static boolean putSetting(String key, String value) { + return settingsAdapter.put(key, value); + } + public static class DefaultBrowserAdapter implements BrowserAdapter { @Override public void openLink(String url) { @@ -67,11 +159,18 @@ e.printStackTrace(); } } else { - System.err.println(tr("Opening link not supported on current platform (''{0}'')", url)); + getLogger(FeatureAdapter.class).log(Level.SEVERE, tr("Opening link not supported on current platform (''{0}'')", url)); } } } + public static class DefaultImageAdapter implements ImageAdapter { + @Override + public BufferedImage read(URL input, boolean readMetadata, boolean enforceTransparency) throws IOException { + return ImageIO.read(input); + } + } + public static class DefaultTranslationAdapter implements TranslationAdapter { @Override public String tr(String text, Object... objects) { @@ -85,4 +184,21 @@ return Logger.getLogger(name); } } + + /** + * Default settings adapter keeping settings in memory only. + */ + public static class DefaultSettingsAdapter implements SettingsAdapter { + private final Map settings = new TreeMap<>(); + + @Override + public String get(String key, String def) { + return settings.getOrDefault(key, def); + } + + @Override + public boolean put(String key, String value) { + return !Objects.equals(value == null || value.isEmpty() ? settings.remove(key) : settings.put(key, value), value); + } + } } diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/interfaces/ICoordinate.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/interfaces/ICoordinate.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/interfaces/ICoordinate.java 2018-03-25 17:06:26.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/interfaces/ICoordinate.java 2018-10-29 12:03:12.000000000 +0000 @@ -1,13 +1,32 @@ // License: GPL. For details, see Readme.txt file. package org.openstreetmap.gui.jmapviewer.interfaces; +/** + * Latitude/Longitude coordinates. + */ public interface ICoordinate { + /** + * Returns latitude. + * @return latitude in degrees + */ double getLat(); + /** + * Sets latitude. + * @param lat latitude in degrees + */ void setLat(double lat); + /** + * Returns longitude. + * @return longitude in degrees + */ double getLon(); + /** + * Sets longitude. + * @param lon longitude in degrees + */ void setLon(double lon); } diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java 2018-03-25 17:06:22.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java 2018-12-31 14:00:16.000000000 +0000 @@ -82,7 +82,6 @@ /** * @return default tile size, for this tile source - * TODO: @since */ int getDefaultTileSize(); @@ -92,7 +91,7 @@ * @param lo1 longitude of first point * @param la2 latitude of second point * @param lo2 longitude of second point - * @return the distance betwen first and second point, in m. + * @return the distance between first and second point, in m. */ double getDistance(double la1, double lo1, double la2, double lo2); diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java 2018-03-25 17:06:26.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java 2018-12-01 20:16:50.000000000 +0000 @@ -6,9 +6,8 @@ import java.awt.Graphics; import java.awt.Insets; import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.MouseEvent; +import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; @@ -18,8 +17,6 @@ import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JSlider; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent; @@ -163,18 +160,12 @@ zoomSlider.setOrientation(JSlider.VERTICAL); zoomSlider.setBounds(10, 10, 30, 150); zoomSlider.setOpaque(false); - zoomSlider.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - setZoom(zoomSlider.getValue()); - } - }); + zoomSlider.addChangeListener(e -> setZoom(zoomSlider.getValue())); zoomSlider.setFocusable(false); add(zoomSlider); int size = 18; - URL url = JMapViewer.class.getResource("images/plus.png"); - if (url != null) { - ImageIcon icon = new ImageIcon(url); + ImageIcon icon = getImageIcon("images/plus.png"); + if (icon != null) { zoomInButton = new JButton(icon); } else { zoomInButton = new JButton("+"); @@ -182,18 +173,11 @@ zoomInButton.setMargin(new Insets(0, 0, 0, 0)); } zoomInButton.setBounds(4, 155, size, size); - zoomInButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - zoomIn(); - } - }); + zoomInButton.addActionListener(e -> zoomIn()); zoomInButton.setFocusable(false); add(zoomInButton); - url = JMapViewer.class.getResource("images/minus.png"); - if (url != null) { - ImageIcon icon = new ImageIcon(url); + icon = getImageIcon("images/minus.png"); + if (icon != null) { zoomOutButton = new JButton(icon); } else { zoomOutButton = new JButton("-"); @@ -201,17 +185,23 @@ zoomOutButton.setMargin(new Insets(0, 0, 0, 0)); } zoomOutButton.setBounds(8 + size, 155, size, size); - zoomOutButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - zoomOut(); - } - }); + zoomOutButton.addActionListener(e -> zoomOut()); zoomOutButton.setFocusable(false); add(zoomOutButton); } + private static ImageIcon getImageIcon(String name) { + URL url = JMapViewer.class.getResource(name); + if (url != null) { + try { + return new ImageIcon(FeatureAdapter.readImage(url)); + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + /** * Changes the map pane so that it is centered on the specified coordinate * at the given zoom level. diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java 2018-03-25 17:06:22.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java 2018-12-01 20:16:50.000000000 +0000 @@ -3,8 +3,6 @@ import java.awt.BorderLayout; import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.List; @@ -93,21 +91,15 @@ } else if (layer.isVisibleTexts()) popup.add(menuItemHide); else popup.add(menuItemShow); - menuItemShow.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - setVisibleTexts(layer, true); - if (layer.getParent() != null) layer.getParent().calculateVisibleTexts(); - map.repaint(); - } + menuItemShow.addActionListener(e -> { + setVisibleTexts(layer, true); + if (layer.getParent() != null) layer.getParent().calculateVisibleTexts(); + map.repaint(); }); - menuItemHide.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - setVisibleTexts(layer, false); - if (layer.getParent() != null) layer.getParent().calculateVisibleTexts(); - map.repaint(); - } + menuItemHide.addActionListener(e -> { + setVisibleTexts(layer, false); + if (layer.getParent() != null) layer.getParent().calculateVisibleTexts(); + map.repaint(); }); return popup; diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java 2018-03-25 17:06:26.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java 2019-05-30 21:11:16.000000000 +0000 @@ -1,6 +1,8 @@ // License: GPL. For details, see Readme.txt file. package org.openstreetmap.gui.jmapviewer; +import static org.openstreetmap.gui.jmapviewer.FeatureAdapter.tr; + import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; @@ -11,6 +13,8 @@ import java.util.Map.Entry; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; +import java.util.logging.Level; +import java.util.logging.Logger; import org.openstreetmap.gui.jmapviewer.interfaces.TileJob; import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; @@ -22,7 +26,22 @@ * @author Jan Peter Stotz */ public class OsmTileLoader implements TileLoader { - private static final ThreadPoolExecutor jobDispatcher = (ThreadPoolExecutor) Executors.newFixedThreadPool(8); + + private static final Logger LOG = FeatureAdapter.getLogger(OsmTileLoader.class); + + /** Setting key for number of threads */ + public static final String THREADS_SETTING = "jmapviewer.osm-tile-loader.threads"; + private static final int DEFAULT_THREADS_NUMBER = 8; + private static int nThreads = DEFAULT_THREADS_NUMBER; + static { + try { + nThreads = FeatureAdapter.getIntSetting(THREADS_SETTING, DEFAULT_THREADS_NUMBER); + } catch (Exception e) { + LOG.log(Level.SEVERE, e.getMessage(), e); + } + } + + private static final ThreadPoolExecutor jobDispatcher = (ThreadPoolExecutor) Executors.newFixedThreadPool(nThreads); private final class OsmTileJob implements TileJob { private final Tile tile; @@ -49,7 +68,7 @@ } loadTileMetadata(tile, conn); if ("no-tile".equals(tile.getValue("tile-info"))) { - tile.setError("No tile at this zoom level"); + tile.setError(tr("No tiles at this zoom level")); } else { input = conn.getInputStream(); try { @@ -66,10 +85,10 @@ listener.tileLoadingFinished(tile, false); if (input == null) { try { - System.err.println("Failed loading " + tile.getUrl() +": " + LOG.log(Level.SEVERE, "Failed loading " + tile.getUrl() +": " +e.getClass() + ": " + e.getMessage()); } catch (IOException ioe) { - ioe.printStackTrace(); + LOG.log(Level.SEVERE, ioe.getMessage(), ioe); } } } finally { @@ -100,12 +119,17 @@ protected TileLoaderListener listener; + /** + * Constructs a new {@code OsmTileLoader}. + * @param listener tile loader listener + */ public OsmTileLoader(TileLoaderListener listener) { this(listener, null); } public OsmTileLoader(TileLoaderListener listener, Map headers) { this.headers.put("Accept", "text/html, image/png, image/jpeg, image/gif, */*"); + this.headers.put("User-Agent", "JMapViewer Java/"+System.getProperty("java.version")); if (headers != null) { this.headers.putAll(headers); } @@ -188,7 +212,7 @@ /** * Sets the maximum number of concurrent connections the tile loader will do - * @param num number of conncurent connections + * @param num number of concurrent connections */ public static void setConcurrentConnections(int num) { jobDispatcher.setMaximumPoolSize(num); diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/Projected.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/Projected.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/Projected.java 2018-03-25 17:06:26.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/Projected.java 2018-10-29 12:03:12.000000000 +0000 @@ -52,21 +52,16 @@ @Override public int hashCode() { - int hash = 3; - hash = 61 * hash + Objects.hashCode(this.data); - return hash; + return Objects.hashCode(data); } @Override public boolean equals(Object obj) { - if (obj == null) { + if (this == obj) + return true; + if (obj == null || !(obj instanceof Projected)) return false; - } - if (getClass() != obj.getClass()) { - return false; - } final Projected other = (Projected) obj; - return Objects.equals(this.data, other.data); + return Objects.equals(data, other.data); } } - diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/Tile.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/Tile.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/Tile.java 2018-03-25 17:06:22.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/Tile.java 2019-05-30 21:06:32.000000000 +0000 @@ -9,6 +9,7 @@ import java.io.InputStream; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.concurrent.Callable; import javax.imageio.ImageIO; @@ -80,7 +81,7 @@ private static BufferedImage loadImage(String path) { try { - return ImageIO.read(JMapViewer.class.getResourceAsStream(path)); + return FeatureAdapter.readImage(JMapViewer.class.getResource(path)); } catch (IOException | IllegalArgumentException ex) { ex.printStackTrace(); return null; @@ -339,18 +340,13 @@ public boolean equals(Object obj) { if (this == obj) return true; - if (obj == null) + if (obj == null || !(obj instanceof Tile)) return false; - if (getClass() != obj.getClass()) - return false; - Tile other = (Tile) obj; - if (xtile != other.xtile) - return false; - if (ytile != other.ytile) - return false; - if (zoom != other.zoom) - return false; - return getTileSource().equals(other.getTileSource()); + final Tile other = (Tile) obj; + return xtile == other.xtile + && ytile == other.ytile + && zoom == other.zoom + && Objects.equals(source, other.source); } public static String getTileKey(TileSource source, int xtile, int ytile, int zoom) { @@ -459,5 +455,4 @@ loading = false; loaded = false; } - } diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java 2018-03-25 17:06:20.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java 2019-05-30 13:45:16.000000000 +0000 @@ -3,7 +3,6 @@ import java.awt.Image; import java.io.IOException; -import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; @@ -15,9 +14,10 @@ import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Pattern; -import javax.imageio.ImageIO; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -28,6 +28,7 @@ import javax.xml.xpath.XPathFactory; import org.openstreetmap.gui.jmapviewer.Coordinate; +import org.openstreetmap.gui.jmapviewer.FeatureAdapter; import org.openstreetmap.gui.jmapviewer.JMapViewer; import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; import org.w3c.dom.Document; @@ -38,11 +39,26 @@ /** * Tile source for the Bing Maps REST Imagery API. - * @see MSDN + * @see MSDN (1) + * and MSDN (2) */ public class BingAerialTileSource extends TMSTileSource { + private static final Logger LOG = FeatureAdapter.getLogger(BingAerialTileSource.class); + + /** Setting key for Bing metadata API URL. Must contain {@link #API_KEY_PLACEHOLDER} */ + public static final String METADATA_API_SETTING = "jmapviewer.bing.metadata-api-url"; + /** Setting key for Bing API key */ + public static final String API_KEY_SETTING = "jmapviewer.bing.api-key"; + /** Placeholder to specify Bing API key in metadata API URL*/ + public static final String API_KEY_PLACEHOLDER = "{apiKey}"; + + /** Bing Metadata API URL */ + private static final String METADATA_API_URL = + "https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&output=xml&key=" + API_KEY_PLACEHOLDER; + /** Original Bing API key created by Potlatch2 developers in 2010 */ private static final String API_KEY = "Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU"; + private static volatile Future> attributions; // volatile is required for getAttribution(), see below. private static String imageUrlTemplate; private static Integer imageryZoomMax; @@ -58,6 +74,7 @@ */ public BingAerialTileSource() { super(new TileSourceInfo("Bing", null, null)); + minZoom = 1; } /** @@ -93,8 +110,8 @@ } protected URL getAttributionUrl() throws MalformedURLException { - return new URL("https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&output=xml&key=" - + API_KEY); + return new URL(FeatureAdapter.getSetting(METADATA_API_SETTING, METADATA_API_URL) + .replace(API_KEY_PLACEHOLDER, FeatureAdapter.getSetting(API_KEY_SETTING, API_KEY))); } protected List parseAttributionText(InputSource xml) throws IOException { @@ -158,11 +175,8 @@ } return attributionsList; - } catch (SAXException e) { - System.err.println("Could not parse Bing aerials attribution metadata."); - e.printStackTrace(); - } catch (ParserConfigurationException | XPathExpressionException | NumberFormatException e) { - e.printStackTrace(); + } catch (SAXException | ParserConfigurationException | XPathExpressionException | NumberFormatException e) { + LOG.log(Level.SEVERE, "Could not parse Bing aerials attribution metadata.", e); } return null; } @@ -190,9 +204,9 @@ @Override public Image getAttributionImage() { try { - final InputStream imageResource = JMapViewer.class.getResourceAsStream("images/bing_maps.png"); + final URL imageResource = JMapViewer.class.getResource("images/bing_maps.png"); if (imageResource != null) { - return ImageIO.read(imageResource); + return FeatureAdapter.readImage(imageResource); } else { // Some Linux distributions (like Debian) will remove Bing logo from sources, so get it at runtime for (int i = 0; i < 5 && getAttribution() == null; i++) { @@ -203,11 +217,11 @@ } if (brandLogoUri != null && !brandLogoUri.isEmpty()) { System.out.println("Reading Bing logo from "+brandLogoUri); - return ImageIO.read(new URL(brandLogoUri)); + return FeatureAdapter.readImage(new URL(brandLogoUri)); } } } catch (IOException e) { - System.err.println("Error while retrieving Bing logo: "+e.getMessage()); + LOG.log(Level.SEVERE, "Error while retrieving Bing logo: "+e.getMessage()); } return null; } @@ -240,7 +254,7 @@ System.out.println("Successfully loaded Bing attribution data."); return r; } catch (IOException ex) { - System.err.println("Could not connect to Bing API. Will retry in " + waitTimeSec + " seconds."); + LOG.log(Level.SEVERE, "Could not connect to Bing API. Will retry in " + waitTimeSec + " seconds."); Thread.sleep(TimeUnit.SECONDS.toMillis(waitTimeSec)); waitTimeSec *= 2; } @@ -263,11 +277,11 @@ try { return attributions.get(0, TimeUnit.MILLISECONDS); } catch (TimeoutException ex) { - System.err.println("Bing: attribution data is not yet loaded."); + LOG.log(Level.WARNING, "Bing: attribution data is not yet loaded."); } catch (ExecutionException ex) { throw new RuntimeException(ex.getCause()); } catch (InterruptedException ign) { - System.err.println("InterruptedException: " + ign.getMessage()); + LOG.log(Level.SEVERE, "InterruptedException: " + ign.getMessage()); } return null; } diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java 2018-03-25 17:06:22.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java 2018-12-31 14:00:16.000000000 +0000 @@ -25,7 +25,7 @@ * Constructs a new {@code "Mapnik"} tile source. */ public Mapnik() { - super("Mapnik", PATTERN, "MAPNIK"); + super("OpenStreetMap Carto", PATTERN, "standard"); modTileFeatures = true; } @@ -40,9 +40,9 @@ /** * The "Cycle Map" OSM tile source. */ - public static class CycleMap extends AbstractOsmTileSource { + public abstract static class CycleMap extends AbstractOsmTileSource { - private static final String PATTERN = "http://%s.tile.opencyclemap.org/cycle"; + private static final String PATTERN = "https://%s.tile.thunderforest.com/cycle"; private static final String[] SERVER = {"a", "b", "c"}; @@ -52,7 +52,7 @@ * Constructs a new {@code CycleMap} tile source. */ public CycleMap() { - super("Cyclemap", PATTERN, "opencyclemap"); + super("OpenCycleMap", PATTERN, "opencyclemap"); } @Override @@ -62,45 +62,45 @@ return url; } + /** + * Get the thunderforest API key. + * + * Needs to be registered at their web site. + * @return the API key + */ + protected abstract String getApiKey(); + @Override public int getMaxZoom() { return 18; } + + @Override + public String getTileUrl(int zoom, int tilex, int tiley) throws IOException { + return this.getBaseUrl() + getTilePath(zoom, tilex, tiley) + "?apikey=" + getApiKey(); + } + + @Override + public String getTermsOfUseText() { + return "Maps © Thunderforest"; + } + + @Override + public String getTermsOfUseURL() { + return "https://thunderforest.com/terms/"; + } } /** * The "Transport Map" OSM tile source. - * - * Template for thunderforest.com. */ - public abstract static class TransportMap extends AbstractOsmTileSource { - - private static final String PATTERN = "https://%s.tile.thunderforest.com/transport"; - - private static final String[] SERVER = {"a", "b", "c"}; - - private int serverNum; + public static class TransportMap extends AbstractOsmTileSource { /** * Constructs a new {@code TransportMap} tile source. */ public TransportMap() { - super("OSM Transport Map", PATTERN, "osmtransportmap"); - } - - /** - * Get the thunderforest API key. - * - * Needs to be registered at their web site. - * @return the API key - */ - protected abstract String getApiKey(); - - @Override - public String getBaseUrl() { - String url = String.format(this.baseUrl, new Object[] {SERVER[serverNum]}); - serverNum = (serverNum + 1) % SERVER.length; - return url; + super("Public Transport", "https://tile.memomaps.de/tilegen", "public_transport_oepnv"); } @Override @@ -109,19 +109,13 @@ } @Override - public String getTileUrl(int zoom, int tilex, int tiley) throws IOException { - return this.getBaseUrl() + getTilePath(zoom, tilex, tiley) + "?apikey=" + getApiKey(); - } - - @Override public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) { - return "Maps © Thunderforest, Data © OpenStreetMap contributors"; + return "© OpenStreetMap contributors, CC-BY-SA"; } @Override public String getAttributionLinkURL() { - return "http://www.thunderforest.com/"; + return "https://öpnvkarte.de/<"; } } - } diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java 2018-03-25 17:06:22.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java 2018-12-31 14:00:16.000000000 +0000 @@ -1,4 +1,6 @@ -// License: GPL. For details, see Readme.txt file. +// License: BSD or GPL. For details, see Readme.txt file. +// Authors of this file, namely Gleb Smirnoff and Andrey Boltenkov, allow +// to reuse the code under BSD license. package org.openstreetmap.gui.jmapviewer.tilesources; import java.awt.Point; @@ -26,8 +28,7 @@ private static final String API_KEY = "4018C5A9AECAD8868ED5DEB2E41D09F7"; private enum ScanexLayer { - IRS("irs", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=BAC78D764F0443BD9AF93E7A998C9F5B"), - SPOT("spot", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=F51CE95441284AF6B2FC319B609C7DEC"); + IRS("irs", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=BAC78D764F0443BD9AF93E7A998C9F5B"); private final String name; private final String uri; @@ -187,7 +188,7 @@ double f = Math.tan(Math.PI/4+lat/2) - ec * Math.pow(Math.tan(Math.PI/4 + Math.asin(E * sinl)/2), E); double df = 1/(1 - sinl) - ec * E * cosl/((1 - E * sinl) * - (Math.sqrt(1 - E * E * sinl * sinl))); + Math.sqrt(1 - E * E * sinl * sinl)); return f/df; } diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java 2018-03-25 17:06:22.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java 2018-12-01 20:16:50.000000000 +0000 @@ -33,19 +33,22 @@ private Random rand; private String[] randomParts; private final Map headers = new HashMap<>(); + private boolean inverse_zoom = false; + private int zoom_offset = 0; // CHECKSTYLE.OFF: SingleSpaceSeparator private static final String COOKIE_HEADER = "Cookie"; - private static final String PATTERN_ZOOM = "\\{(?:(\\d+)-)?z(?:oom)?([+-]\\d+)?\\}"; - private static final String PATTERN_X = "\\{x\\}"; - private static final String PATTERN_Y = "\\{y\\}"; - private static final String PATTERN_Y_YAHOO = "\\{!y\\}"; - private static final String PATTERN_NEG_Y = "\\{-y\\}"; - private static final String PATTERN_SWITCH = "\\{switch:([^}]+)\\}"; - private static final String PATTERN_HEADER = "\\{header\\(([^,]+),([^}]+)\\)\\}"; + private static final Pattern PATTERN_ZOOM = Pattern.compile("\\{(?:(\\d+)-)?z(?:oom)?([+-]\\d+)?\\}"); + private static final Pattern PATTERN_X = Pattern.compile("\\{x\\}"); + private static final Pattern PATTERN_Y = Pattern.compile("\\{y\\}"); + private static final Pattern PATTERN_Y_YAHOO = Pattern.compile("\\{!y\\}"); + private static final Pattern PATTERN_NEG_Y = Pattern.compile("\\{-y\\}"); + private static final Pattern PATTERN_SWITCH = Pattern.compile("\\{switch:([^}]+)\\}"); + private static final Pattern PATTERN_HEADER = Pattern.compile("\\{header\\(([^,]+),([^}]+)\\)\\}"); + private static final Pattern PATTERN_PARAM = Pattern.compile("\\{((?:\\d+-)?z(?:oom)?(:?[+-]\\d+)?|x|y|!y|-y|switch:([^}]+))\\}"); // CHECKSTYLE.ON: SingleSpaceSeparator - private static final String[] ALL_PATTERNS = { + private static final Pattern[] ALL_PATTERNS = { PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y, PATTERN_SWITCH }; @@ -64,20 +67,33 @@ private void handleTemplate() { // Capturing group pattern on switch values - Matcher m = Pattern.compile(".*"+PATTERN_SWITCH+".*").matcher(baseUrl); - if (m.matches()) { + Matcher m = PATTERN_SWITCH.matcher(baseUrl); + if (m.find()) { rand = new Random(); randomParts = m.group(1).split(","); } - Pattern pattern = Pattern.compile(PATTERN_HEADER); StringBuffer output = new StringBuffer(); - Matcher matcher = pattern.matcher(baseUrl); + Matcher matcher = PATTERN_HEADER.matcher(baseUrl); while (matcher.find()) { headers.put(matcher.group(1), matcher.group(2)); matcher.appendReplacement(output, ""); } matcher.appendTail(output); baseUrl = output.toString(); + m = PATTERN_ZOOM.matcher(this.baseUrl); + if (m.find()) { + if (m.group(1) != null) { + inverse_zoom = true; + zoom_offset = Integer.parseInt(m.group(1)); + } + if (m.group(2) != null) { + String ofs = m.group(2); + if (ofs.startsWith("+")) + ofs = ofs.substring(1); + zoom_offset += Integer.parseInt(ofs); + } + } + } @Override @@ -87,29 +103,44 @@ @Override public String getTileUrl(int zoom, int tilex, int tiley) { - int finalZoom = zoom; - Matcher m = Pattern.compile(".*"+PATTERN_ZOOM+".*").matcher(this.baseUrl); - if (m.matches()) { - if (m.group(1) != null) { - finalZoom = Integer.parseInt(m.group(1))-zoom; - } - if (m.group(2) != null) { - String ofs = m.group(2); - if (ofs.startsWith("+")) - ofs = ofs.substring(1); - finalZoom += Integer.parseInt(ofs); + StringBuffer url = new StringBuffer(baseUrl.length()); + Matcher matcher = PATTERN_PARAM.matcher(baseUrl); + while (matcher.find()) { + String replacement = "replace"; + switch (matcher.group(1)) { + case "z": // PATTERN_ZOOM + case "zoom": + replacement = Integer.toString((inverse_zoom ? -1 * zoom : zoom) + zoom_offset); + break; + case "x": // PATTERN_X + replacement = Integer.toString(tilex); + break; + case "y": // PATTERN_Y + replacement = Integer.toString(tiley); + break; + case "!y": // PATTERN_Y_YAHOO + replacement = Integer.toString((int) Math.pow(2, zoom-1)-1-tiley); + break; + case "-y": // PATTERN_NEG_Y + replacement = Integer.toString((int) Math.pow(2, zoom)-1-tiley); + break; + case "switch:": + replacement = randomParts[rand.nextInt(randomParts.length)]; + break; + default: + // handle switch/zoom here, as group will contain parameters and switch will not work + if (PATTERN_ZOOM.matcher("{" + matcher.group(1) + "}").matches()) { + replacement = Integer.toString((inverse_zoom ? -1 * zoom : zoom) + zoom_offset); + } else if (PATTERN_SWITCH.matcher("{" + matcher.group(1) + "}").matches()) { + replacement = randomParts[rand.nextInt(randomParts.length)]; + } else { + replacement = '{' + matcher.group(1) + '}'; + } } + matcher.appendReplacement(url, replacement); } - String r = this.baseUrl - .replaceAll(PATTERN_ZOOM, Integer.toString(finalZoom)) - .replaceAll(PATTERN_X, Integer.toString(tilex)) - .replaceAll(PATTERN_Y, Integer.toString(tiley)) - .replaceAll(PATTERN_Y_YAHOO, Integer.toString((int) Math.pow(2, zoom-1)-1-tiley)) - .replaceAll(PATTERN_NEG_Y, Integer.toString((int) Math.pow(2, zoom)-1-tiley)); - if (rand != null) { - r = r.replaceAll(PATTERN_SWITCH, randomParts[rand.nextInt(randomParts.length)]); - } - return r; + matcher.appendTail(url); + return url.toString().replace(" ", "%20"); } /** @@ -121,8 +152,8 @@ Matcher m = Pattern.compile("\\{[^}]*\\}").matcher(url); while (m.find()) { boolean isSupportedPattern = false; - for (String pattern : ALL_PATTERNS) { - if (m.group().matches(pattern)) { + for (Pattern pattern : ALL_PATTERNS) { + if (pattern.matcher(m.group()).matches()) { isSupportedPattern = true; break; } diff -Nru jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java --- jmapviewer-2.7+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java 2018-03-25 17:06:22.000000000 +0000 +++ jmapviewer-2.10+dfsg/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java 2018-12-02 02:22:54.000000000 +0000 @@ -107,7 +107,7 @@ } /** - * Checkusm for empty tiles for servers delivering such tile types + * Checksum for empty tiles for servers delivering such tile types * @return map of checksums, that when detected, means that this is "no tile at this zoom level" situation * @since 32022 */ @@ -192,6 +192,14 @@ } /** + * Sets the cookies to be sent together with request + * @param cookies cookies to be sent along with request to tile source + */ + public final void setCookies(String cookies) { + this.cookies = cookies; + } + + /** * Determines if this imagery supports "/status" and "/dirty" mode (tile re-rendering). * @return true if it supports "/status" and "/dirty" mode (tile re-rendering) */