[Git][debian-gis-team/jmapviewer][upstream] 2 commits: New upstream version 2.20+dfsg

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Tue Aug 13 04:34:01 BST 2024



Bas Couwenberg pushed to branch upstream at Debian GIS Project / jmapviewer


Commits:
4d2ae77e by Bas Couwenberg at 2024-07-17T05:25:59+02:00
New upstream version 2.20+dfsg
- - - - -
1ffe1cc1 by Bas Couwenberg at 2024-08-13T05:16:51+02:00
New upstream version 2.21+dfsg
- - - - -


26 changed files:

- build.xml
- src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java
- src/org/openstreetmap/gui/jmapviewer/Coordinate.java
- src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java
- src/org/openstreetmap/gui/jmapviewer/Demo.java
- src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java
- src/org/openstreetmap/gui/jmapviewer/JMapViewer.java
- + src/org/openstreetmap/gui/jmapviewer/JMapViewerRuntimeException.java
- src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java
- src/org/openstreetmap/gui/jmapviewer/OsmMercator.java
- src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java
- src/org/openstreetmap/gui/jmapviewer/Projected.java
- src/org/openstreetmap/gui/jmapviewer/Style.java
- src/org/openstreetmap/gui/jmapviewer/Tile.java
- src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java
- src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodePanel.java
- src/org/openstreetmap/gui/jmapviewer/events/JMVCommandEvent.java
- src/org/openstreetmap/gui/jmapviewer/interfaces/IProjected.java
- src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java
- src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java
- src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
- + src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java.rej
- src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java
- src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java
- src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java
- src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java


Changes:

=====================================
build.xml
=====================================
@@ -2,31 +2,23 @@
 <project default="all" name="jmapviewer"
          xmlns:jacoco="antlib:org.jacoco.ant"
          xmlns:if="ant:if"
-         xmlns:ivy="antlib:org.apache.ivy.ant"
+         xmlns:mvn="antlib:org.apache.maven.resolver.ant"
 >
 
     <property name="java.lang.version" value="8" />
     <dirname property="base.dir" file="${ant.file.jmapviewer}"/>
-    <property name="tools.dir" location="${base.dir}/tools"/>
+    <property name="maven.artifact.resolver.version" value="1.5.1"/>
+    <property name="maven.artifact.resolver.parent.dir" value="${user.home}/.m2/repository/org/apache/maven/resolver/maven-resolver-ant-tasks/${maven.artifact.resolver.version}/"/>
     <property name="jacoco.includes" value="org.openstreetmap.gui.jmapviewer.*" />
     <property name="jacoco.inclbootstrapclasses" value="false" />
     <property name="jacoco.inclnolocationclasses" value="false" />
     <!-- For Java specific stuff by version -->
     <condition property="isJava9"><matches string="${ant.java.version}" pattern="(1.)?(9|1[0-9])" /></condition>
-    <condition property="isJava10"><matches string="${ant.java.version}" pattern="(1|2)[0-9]" /></condition>
-    <condition property="isJava11"><matches string="${ant.java.version}" pattern="1[1-9]|[2-9][0-9]" /></condition>
-    <condition property="isJava12"><matches string="${ant.java.version}" pattern="1[2-9]|[2-9][0-9]" /></condition>
-    <condition property="isJava13"><matches string="${ant.java.version}" pattern="1[3-9]|[2-9][0-9]" /></condition>
-    <condition property="isJava14"><matches string="${ant.java.version}" pattern="1[4-9]|[2-9][0-9]" /></condition>
-    <condition property="isJava16"><matches string="${ant.java.version}" pattern="1[6-9]|[2-9][0-9]" /></condition>
-    <condition property="isJava18"><matches string="${ant.java.version}" pattern="1[8-9]|[2-9][0-9]" /></condition>
-    <condition property="isJava19"><matches string="${ant.java.version}" pattern="19|[2-9][0-9]" /></condition>
-    <condition property="isJava20"><matches string="${ant.java.version}" pattern="[2-9][0-9]" /></condition>
-    <condition property="isJava21"><matches string="${ant.java.version}" pattern="2[1-9]|[3-9][0-9]" /></condition>
-    <!-- Disable jacoco on Java 18+, see https://github.com/jacoco/jacoco/pull/1132 -->
+    <condition property="isJava23"><matches string="${ant.java.version}" pattern="2[3-9]|[3-9][0-9]" /></condition>
+    <!-- Disable jacoco 0.8.11 on Java 23+, see https://www.jacoco.org/jacoco/trunk/doc/changes.html for latest supported version -->
     <condition property="coverageByDefault">
         <not>
-            <isset property="isJava18"/>
+            <isset property="isJava23"/>
         </not>
     </condition>
     <path id="test.classpath">
@@ -82,10 +74,6 @@
         </copy>
     </target>
 
-    <target name="checkdepsupdate" depends="resolve">
-        <ivy:checkdepsupdate/>
-    </target>
-
     <target name="svn_info" description="Get SVN info for use in JAR/ZIP filenames.">
         <!-- Get the svn ReleaseVersion property -->
         <exec executable="svn" outputproperty="svnReleaseVersion">
@@ -177,12 +165,47 @@
         </javadoc>
     </target>
 
-    <target name="resolve" description="Resolve Ivy dependencies">
-        <ivy:resolve/>
-        <ivy:cachepath pathid="checkstyle.classpath" conf="checkstyle"/>
-        <ivy:cachepath pathid="testlib.classpath" conf="test"/>
-        <ivy:cachepath pathid="jacoco.classpath" conf="jacocoant"/>
-        <ivy:cachepath pathid="spotbugs.classpath" conf="spotbugs"/>
+    <target name="download-artifact-resolver">
+        <mkdir dir="${maven.artifact.resolver.parent.dir}"/>
+        <get src="https://repo1.maven.org/maven2/org/apache/maven/resolver/maven-resolver-ant-tasks/${maven.artifact.resolver.version}/maven-resolver-ant-tasks-${maven.artifact.resolver.version}-uber.jar"
+             dest="${maven.artifact.resolver.parent.dir}/maven-resolver-ant-tasks-${maven.artifact.resolver.version}-uber.jar"
+             usetimestamp="true" />
+    </target>
+    <target name="init-maven" depends="download-artifact-resolver">
+        <path id="maven.lib.path">
+            <fileset dir="${maven.artifact.resolver.parent.dir}" includes="maven-resolver-ant-tasks-${maven.artifact.resolver.version}-uber.jar"/>
+        </path>
+        <taskdef uri="antlib:org.apache.maven.resolver.ant" resource="org/apache/maven/resolver/ant/antlib.xml" classpathref="maven.lib.path"/>
+    </target>
+    <target name="resolve" depends="init-maven" description="Resolve Maven dependencies">
+        <mvn:pom file="pom.xml"/>
+        <!-- This stanza is necessary since the maven resolver doesn't read repo settings from the pom.xml file -->
+        <!-- resolver.repositories makes it global -->
+        <mvn:remoterepos id="resolver.repositories">
+            <mvn:remoterepo id="JOSM-central" url="https://josm.openstreetmap.de/nexus/content/repositories/central/" />
+        </mvn:remoterepos>
+        <mvn:resolve>
+            <mvn:path refid="testlib.classpath" classpath="test"/>
+        </mvn:resolve>
+        <mvn:resolve>
+            <mvn:dependencies>
+                <mvn:dependency groupId="org.jacoco" artifactId="org.jacoco.ant" version="${pom.properties.version.maven.jacoco}" classifier="nodeps" type="jar" scope="test"/>
+            </mvn:dependencies>
+            <mvn:path refid="jacoco.classpath" classpath="test"/>
+        </mvn:resolve>
+        <mvn:resolve>
+            <mvn:dependencies>
+                <mvn:dependency groupId="com.puppycrawl.tools" artifactId="checkstyle" version="${pom.properties.version.maven.checkstyle}" scope="compile"/>
+            </mvn:dependencies>
+            <mvn:path refid="checkstyle.classpath" classpath="compile"/>
+        </mvn:resolve>
+        <mvn:resolve>
+            <mvn:dependencies>
+                <mvn:dependency groupId="com.github.spotbugs" artifactId="spotbugs" version="${pom.properties.version.maven.spotbugs}" scope="compile"/>
+                <mvn:dependency groupId="com.github.spotbugs" artifactId="spotbugs-ant" version="${pom.properties.version.maven.spotbugs}" scope="compile"/>
+            </mvn:dependencies>
+            <mvn:path refid="spotbugs.classpath" classpath="compile"/>
+        </mvn:resolve>
     </target>
 
     <target name="test" depends="clean, build, resolve">
@@ -197,8 +220,9 @@
                 <path refid="test.classpath"/>
             </classpath>
         </javac>
-        <jacoco:agent enabled="@{coverage}" includes="${jacoco.includes}"
-                      inclbootstrapclasses="${jacoco.inclbootstrapclasses}" inclnolocationclasses="${jacoco.inclnolocationclasses}" property="jacocoagent@{testfamily}@{testITsuffix}" if:true="@{coverage}"/>
+        <jacoco:agent destfile="report/jacoco.exec" enabled="${coverageByDefault}" includes="${jacoco.includes}" dumponexit="true"
+                      inclbootstrapclasses="${jacoco.inclbootstrapclasses}" inclnolocationclasses="${jacoco.inclnolocationclasses}"
+                      property="jacocoagent" if:true="${coverageByDefault}"/>
         <junitlauncher printsummary="yes">
             <classpath>
                 <path refid="testlib.classpath"/>
@@ -208,6 +232,7 @@
             <testclasses outputdir="report">
                 <fileset dir="bintest" includes="**/*Test.class"/>
                 <fork>
+                    <jvmarg value="${jacocoagent}" if:set="jacocoagent" />
                     <jvmarg value="-Dfile.encoding=UTF-8"/>
                 </fork>
                 <listener type="legacy-brief" sendSysOut="true" sendSysErr="true"/>
@@ -215,6 +240,20 @@
                 <listener type="legacy-xml" />
             </testclasses>
         </junitlauncher>
+        <jacoco:report>
+            <executiondata>
+                <fileset dir="report" includes="*.exec"/>
+            </executiondata>
+            <structure name="JMapViewer Test Coverage">
+                <classfiles>
+                    <fileset dir="bin" includes="org/openstreetmap/"/>
+                </classfiles>
+                <sourcefiles encoding="UTF-8">
+                    <fileset dir="src" includes="org/openstreetmap/"/>
+                </sourcefiles>
+            </structure>
+            <xml destfile="report/jacoco.xml"/>
+        </jacoco:report>
     </target>
 
 </project>


=====================================
src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java
=====================================
@@ -18,14 +18,14 @@ import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;
 import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 
 public class AttributionSupport {
+    public static final Font ATTR_FONT = new Font("Arial", Font.PLAIN, 10);
+    public static final Font ATTR_LINK_FONT;
 
     private Attributed source;
 
     private Image attrImage;
     private String attrTermsText;
     private String attrTermsUrl;
-    public static final Font ATTR_FONT = new Font("Arial", Font.PLAIN, 10);
-    public static final Font ATTR_LINK_FONT;
 
     protected Rectangle attrTextBounds;
     protected Rectangle attrToUBounds;


=====================================
src/org/openstreetmap/gui/jmapviewer/Coordinate.java
=====================================
@@ -73,7 +73,7 @@ public class Coordinate implements ICoordinate, Serializable {
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (!(o instanceof Coordinate)) return false;
+        if (o == null || !this.getClass().equals(o.getClass())) return false;
         Coordinate that = (Coordinate) o;
         return Double.compare(that.x, x) == 0 && Double.compare(that.y, y) == 0;
     }


=====================================
src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java
=====================================
@@ -136,7 +136,7 @@ MouseWheelListener {
                 movementMouseButtonMask = MouseEvent.BUTTON3_DOWN_MASK;
                 break;
             default:
-                throw new RuntimeException("Unsupported button");
+                throw new JMapViewerRuntimeException("Unsupported button");
         }
     }
 


=====================================
src/org/openstreetmap/gui/jmapviewer/Demo.java
=====================================
@@ -4,8 +4,6 @@ package org.openstreetmap.gui.jmapviewer;
 import java.awt.BorderLayout;
 import java.awt.Cursor;
 import java.awt.Point;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 
@@ -83,20 +81,10 @@ public class Demo extends JFrame implements JMapViewerEventListener {
                 new OsmTileSource.TransportMap(),
                 new BingAerialTileSource(),
         });
-        tileSourceSelector.addItemListener(new ItemListener() {
-            @Override
-            public void itemStateChanged(ItemEvent e) {
-                map().setTileSource((TileSource) e.getItem());
-            }
-        });
+        tileSourceSelector.addItemListener(e -> map().setTileSource((TileSource) e.getItem()));
         JComboBox<TileLoader> tileLoaderSelector;
         tileLoaderSelector = new JComboBox<>(new TileLoader[] {new OsmTileLoader(map())});
-        tileLoaderSelector.addItemListener(new ItemListener() {
-            @Override
-            public void itemStateChanged(ItemEvent e) {
-                map().setTileLoader((TileLoader) e.getItem());
-            }
-        });
+        tileLoaderSelector.addItemListener(e -> map().setTileLoader((TileLoader) e.getItem()));
         map().setTileLoader((TileLoader) tileLoaderSelector.getSelectedItem());
         panelTop.add(tileSourceSelector);
         panelTop.add(tileLoaderSelector);


=====================================
src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java
=====================================
@@ -215,6 +215,17 @@ public final class FeatureAdapter {
         return imageAdapter.read(url, false, false);
     }
 
+    /**
+     * Reads an image using the current {@link ImageAdapter}.
+     * @param url image URI to read
+     * @return a <code>BufferedImage</code> containing the decoded contents of the input, or <code>null</code>.
+     * @throws java.net.MalformedURLException if the URI could not be converted to a URL
+     * @throws IOException if an error occurs during reading.
+     */
+    public static BufferedImage readImage(URI url) throws IOException {
+        return imageAdapter.read(url.toURL(), false, false);
+    }
+
     /**
      * Translates a text using the current {@link TranslationAdapter}.
      * @param text the text to translate.
@@ -298,10 +309,8 @@ public final class FeatureAdapter {
             if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
                 try {
                     Desktop.getDesktop().browse(new URI(url));
-                } catch (IOException e) {
-                    e.printStackTrace();
-                } catch (URISyntaxException e) {
-                    e.printStackTrace();
+                } catch (IOException | URISyntaxException e) {
+                    getLogger(FeatureAdapter.class).log(Level.SEVERE, e.getMessage(), e);
                 }
             } else {
                 getLogger(FeatureAdapter.class).log(Level.SEVERE, tr("Opening link not supported on current platform (''{0}'')", url));


=====================================
src/org/openstreetmap/gui/jmapviewer/JMapViewer.java
=====================================
@@ -12,6 +12,7 @@ import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.logging.Level;
 
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
@@ -136,9 +137,9 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
     public JMapViewer(TileCache tileCache) {
         tileSource = new OsmTileSource.Mapnik();
         tileController = new TileController(tileSource, tileCache, this);
-        mapMarkerList = Collections.synchronizedList(new ArrayList<MapMarker>());
-        mapPolygonList = Collections.synchronizedList(new ArrayList<MapPolygon>());
-        mapRectangleList = Collections.synchronizedList(new ArrayList<MapRectangle>());
+        mapMarkerList = Collections.synchronizedList(new ArrayList<>());
+        mapPolygonList = Collections.synchronizedList(new ArrayList<>());
+        mapRectangleList = Collections.synchronizedList(new ArrayList<>());
         mapMarkersVisible = true;
         mapRectanglesVisible = true;
         mapPolygonsVisible = true;
@@ -196,7 +197,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
             try {
                 return new ImageIcon(FeatureAdapter.readImage(url));
             } catch (IOException e) {
-                e.printStackTrace();
+                FeatureAdapter.getLogger(JMapViewer.class).log(Level.FINE, e.getMessage(), e);
             }
         }
         return null;
@@ -501,7 +502,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
             return (int) marker.getRadius();
         else if (p != null) {
             Integer radius = getLatOffset(marker.getLat(), marker.getLon(), marker.getRadius(), false);
-            radius = radius == null ? null : p.y - radius;
+            radius = radius == null ? null : (p.y - radius);
             return radius;
         } else
             return null;
@@ -542,12 +543,12 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
      */
     public double getMeterPerPixel() {
         Point origin = new Point(5, 5);
-        Point center = new Point(getWidth() / 2, getHeight() / 2);
+        Point centerPixel = new Point(getWidth() / 2, getHeight() / 2);
 
-        double pDistance = center.distance(origin);
+        double pDistance = centerPixel.distance(origin);
 
         ICoordinate originCoord = getPosition(origin);
-        ICoordinate centerCoord = getPosition(center);
+        ICoordinate centerCoord = getPosition(centerPixel);
 
         double mDistance = tileSource.getDistance(originCoord.getLat(), originCoord.getLon(),
                 centerCoord.getLat(), centerCoord.getLon());
@@ -559,7 +560,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
     protected void paintComponent(Graphics g) {
         super.paintComponent(g);
 
-        int iMove = 0;
+        int iMove;
 
         int tilesize = tileSource.getTileSize();
         int tilex = center.x / tilesize;
@@ -1100,9 +1101,9 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
      */
     public void setTileSource(TileSource tileSource) {
         if (tileSource.getMaxZoom() > MAX_ZOOM)
-            throw new RuntimeException("Maximum zoom level too high");
+            throw new JMapViewerRuntimeException("Maximum zoom level too high");
         if (tileSource.getMinZoom() < MIN_ZOOM)
-            throw new RuntimeException("Minimum zoom level too low");
+            throw new JMapViewerRuntimeException("Minimum zoom level too low");
         ICoordinate position = getPosition();
         this.tileSource = tileSource;
         tileController.setTileSource(tileSource);


=====================================
src/org/openstreetmap/gui/jmapviewer/JMapViewerRuntimeException.java
=====================================
@@ -0,0 +1,46 @@
+// License: GPL. For details, see Readme.txt file.
+package org.openstreetmap.gui.jmapviewer;
+
+/**
+ * A {@link RuntimeException} specific to JMapViewer
+ * @since JMapViewer 2.20
+ */
+public class JMapViewerRuntimeException extends RuntimeException {
+
+    /**
+     * Create a new exception without a specified cause or message
+     * @see Exception#Exception()
+     */
+    public JMapViewerRuntimeException() {
+        super();
+    }
+
+    /**
+     * Create a new exception with a message
+     * @param message The message for the exception
+     * @see Exception#Exception(String)
+     */
+    public JMapViewerRuntimeException(String message) {
+        super(message);
+    }
+
+    /**
+     * Create a new message with a given message and cause
+     * @param message The message for the exception
+     * @param cause The cause of the exception
+     * @see Exception#Exception(String, Throwable)
+     */
+    public JMapViewerRuntimeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause
+     *
+     * @param cause the cause of the exception
+     * @see Exception#Exception(Throwable)
+     */
+    public JMapViewerRuntimeException(Throwable cause) {
+        super(cause);
+    }
+}


=====================================
src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java
=====================================
@@ -1,9 +1,12 @@
 // License: GPL. For details, see Readme.txt file.
 package org.openstreetmap.gui.jmapviewer;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.logging.Level;
 import java.util.logging.Logger;
+import java.util.stream.Collectors;
 
 import org.openstreetmap.gui.jmapviewer.interfaces.TileCache;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
@@ -17,7 +20,12 @@ import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
  */
 public class MemoryTileCache implements TileCache {
 
-    protected static final Logger log = Logger.getLogger(MemoryTileCache.class.getName());
+    private static final Logger LOGGER = Logger.getLogger(MemoryTileCache.class.getName());
+    /**
+     * @deprecated since 2.20 (create a class specific logger)
+     */
+    @Deprecated
+    protected static final Logger log = LOGGER;
 
     /**
      * Default cache size
@@ -78,7 +86,7 @@ public class MemoryTileCache implements TileCache {
                 removeEntry(lruTiles.getLastElement());
             }
         } catch (NullPointerException e) {
-            log.warning(e.getMessage());
+            LOGGER.log(Level.WARNING, e.getMessage(), e);
         }
     }
 
@@ -97,6 +105,13 @@ public class MemoryTileCache implements TileCache {
         lruTiles.clear();
     }
 
+    @Override
+    public synchronized void clearErrorTiles() {
+        Collection<CacheEntry> toRemove = hash.values().stream().filter(cacheEntry -> cacheEntry.tile.hasError()).collect(Collectors.toList());
+        hash.values().removeAll(toRemove);
+        toRemove.forEach(lruTiles::removeEntry);
+    }
+
     @Override
     public synchronized int getTileCount() {
         return hash.size();


=====================================
src/org/openstreetmap/gui/jmapviewer/OsmMercator.java
=====================================
@@ -57,7 +57,7 @@ public class OsmMercator {
      * @return number of pixels
      */
     public long getMaxPixels(int aZoomlevel) {
-        return tileSize * (1 << aZoomlevel);
+        return tileSize * (1L << aZoomlevel);
     }
 
     public long falseEasting(int aZoomlevel) {
@@ -161,7 +161,7 @@ public class OsmMercator {
         double log = Math.log((1.0 + sinLat) / (1.0 - sinLat));
         long mp = getMaxPixels(aZoomlevel);
         double y = mp * (0.5 - (log / (4.0 * Math.PI)));
-        return Math.min(y, mp - 1);
+        return Math.min(y, mp - 1d);
     }
 
     /**


=====================================
src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java
=====================================
@@ -176,7 +176,7 @@ public class OsmTileLoader implements TileLoader {
             } catch (NumberFormatException e) {
                 // ignore malformed Cache-Control headers
                 if (JMapViewer.debug) {
-                    System.err.println(e.getMessage());
+                    LOG.log(Level.FINE, e.getMessage(), e);
                 }
             }
         }


=====================================
src/org/openstreetmap/gui/jmapviewer/Projected.java
=====================================
@@ -61,7 +61,7 @@ public class Projected implements IProjected, Serializable {
     public boolean equals(Object obj) {
         if (this == obj)
             return true;
-        if (!(obj instanceof Projected))
+        if (obj == null || !this.getClass().equals(obj.getClass()))
             return false;
         final Projected other = (Projected) obj;
         return Objects.equals(data, other.data);


=====================================
src/org/openstreetmap/gui/jmapviewer/Style.java
=====================================
@@ -7,14 +7,14 @@ import java.awt.Font;
 import java.awt.Stroke;
 
 public class Style {
+    private static final AlphaComposite TRANSPARENCY = AlphaComposite.getInstance(AlphaComposite.SRC_OVER);
+    private static final AlphaComposite OPAQUE = AlphaComposite.getInstance(AlphaComposite.SRC);
+
     private Color color;
     private Color backColor;
     private Stroke stroke;
     private Font font;
 
-    private static final AlphaComposite TRANSPARENCY = AlphaComposite.getInstance(AlphaComposite.SRC_OVER);
-    private static final AlphaComposite OPAQUE = AlphaComposite.getInstance(AlphaComposite.SRC);
-
     public Style() {
         super();
     }


=====================================
src/org/openstreetmap/gui/jmapviewer/Tile.java
=====================================
@@ -11,6 +11,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.Callable;
+import java.util.logging.Level;
 
 import javax.imageio.ImageIO;
 
@@ -83,7 +84,7 @@ public class Tile {
         try {
             return FeatureAdapter.readImage(JMapViewer.class.getResource(path));
         } catch (IOException | IllegalArgumentException ex) {
-            ex.printStackTrace();
+            FeatureAdapter.getLogger(Tile.class).log(Level.SEVERE, ex.getMessage(), ex);
             return null;
         }
     }
@@ -109,7 +110,7 @@ public class Tile {
                 return result;
             } catch (Exception e) {
                 // this should not happen here
-                throw new RuntimeException(e);
+                throw new JMapViewerRuntimeException(e);
             }
         }
     }
@@ -124,12 +125,8 @@ public class Tile {
          *  use LazyTask as creation of BufferedImage is very expensive
          *  this way we can avoid object creation until we're sure it's needed
          */
-        final CachedCallable<BufferedImage> tmpImage = new CachedCallable<>(new Callable<BufferedImage>() {
-            @Override
-            public BufferedImage call() throws Exception {
-                return new BufferedImage(source.getTileSize(), source.getTileSize(), BufferedImage.TYPE_INT_ARGB);
-            }
-        });
+        final CachedCallable<BufferedImage> tmpImage = new CachedCallable<>(() ->
+                new BufferedImage(source.getTileSize(), source.getTileSize(), BufferedImage.TYPE_INT_ARGB));
 
         for (int zoomDiff = 1; zoomDiff < 5; zoomDiff++) {
             // first we check if there are already the 2^x tiles
@@ -145,13 +142,10 @@ public class Tile {
                  * use LazyTask for graphics to avoid evaluation of tmpImage, until we have
                  * something to draw
                  */
-                CachedCallable<Graphics2D> graphics = new CachedCallable<>(new Callable<Graphics2D>() {
-                    @Override
-                    public Graphics2D call() throws Exception {
-                        Graphics2D g = (Graphics2D) tmpImage.call().getGraphics();
-                        g.setTransform(AffineTransform.getScaleInstance(scale, scale));
-                        return g;
-                    }
+                CachedCallable<Graphics2D> graphics = new CachedCallable<>(() -> {
+                    Graphics2D g = (Graphics2D) tmpImage.call().getGraphics();
+                    g.setTransform(AffineTransform.getScaleInstance(scale, scale));
+                    return g;
                 });
 
                 int paintedTileCount = 0;
@@ -176,18 +170,14 @@ public class Tile {
                 int ytileLow = ytile >> zoomDiff;
                 final int factor = 1 << zoomDiff;
                 final double scale = factor;
-                CachedCallable<Graphics2D> graphics = new CachedCallable<>(new Callable<Graphics2D>() {
-                    @Override
-                    public Graphics2D call() throws Exception {
-                        Graphics2D g = (Graphics2D) tmpImage.call().getGraphics();
-                        AffineTransform at = new AffineTransform();
-                        int translateX = (xtile % factor) * source.getTileSize();
-                        int translateY = (ytile % factor) * source.getTileSize();
-                        at.setTransform(scale, 0, 0, scale, -translateX, -translateY);
-                        g.setTransform(at);
-                        return g;
-                    }
-
+                CachedCallable<Graphics2D> graphics = new CachedCallable<>(() -> {
+                    Graphics2D g = (Graphics2D) tmpImage.call().getGraphics();
+                    AffineTransform at = new AffineTransform();
+                    int translateX = (xtile % factor) * source.getTileSize();
+                    int translateY = (ytile % factor) * source.getTileSize();
+                    at.setTransform(scale, 0, 0, scale, -translateX, -translateY);
+                    g.setTransform(at);
+                    return g;
                 });
 
                 Tile tile = cache.getTile(source, xtileLow, ytileLow, zoomLow);
@@ -340,7 +330,7 @@ public class Tile {
     public boolean equals(Object obj) {
         if (this == obj)
             return true;
-        if (obj == null || !(obj instanceof Tile))
+        if (obj == null || !this.getClass().equals(obj.getClass()))
             return false;
         final Tile other = (Tile) obj;
         return xtile == other.xtile


=====================================
src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java
=====================================
@@ -2,7 +2,6 @@
 package org.openstreetmap.gui.jmapviewer.checkBoxTree;
 
 import java.awt.Component;
-import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
@@ -84,13 +83,9 @@ public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEd
                 row, true);
 
         // editor always selected / focused
-        final ItemListener itemListener = new ItemListener() {
-
-            @Override
-            public void itemStateChanged(final ItemEvent itemEvent) {
-                if (stopCellEditing()) {
-                    fireEditingStopped();
-                }
+        final ItemListener itemListener = itemEvent -> {
+            if (stopCellEditing()) {
+                fireEditingStopped();
             }
         };
         if (editor instanceof CheckBoxNodePanel) {


=====================================
src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodePanel.java
=====================================
@@ -32,7 +32,7 @@ public class CheckBoxNodePanel extends JPanel {
             check.getModel().setPressed(true);
             check.getModel().setArmed(true);
         } else {
-            check.setSelected(bool.booleanValue());
+            check.setSelected(bool);
             check.getModel().setArmed(false);
         }
     }


=====================================
src/org/openstreetmap/gui/jmapviewer/events/JMVCommandEvent.java
=====================================
@@ -16,12 +16,13 @@ public class JMVCommandEvent extends EventObject {
         ZOOM
     }
 
-    private COMMAND command;
     /**
      *
      */
     private static final long serialVersionUID = 8701544867914969620L;
 
+    private COMMAND command;
+
     public JMVCommandEvent(COMMAND cmd, Object source) {
         super(source);
 


=====================================
src/org/openstreetmap/gui/jmapviewer/interfaces/IProjected.java
=====================================
@@ -3,7 +3,7 @@ package org.openstreetmap.gui.jmapviewer.interfaces;
 
 /**
  * Projected coordinates (east / north space).
- *
+ * <p>
  * For most projections, one unit in projected space is roughly one meter, but
  * can also be degrees or feet.
  */


=====================================
src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java
=====================================
@@ -48,6 +48,14 @@ public interface TileCache {
      */
     void clear();
 
+    /**
+     * Removes error tiles from memory.
+     * This is implementation specific; the default calls {@link #clear()}.
+     */
+    default void clearErrorTiles() {
+        this.clear();
+    }
+
     /**
      * Size of the cache.
      * @return maximum number of tiles in cache


=====================================
src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java
=====================================
@@ -178,9 +178,9 @@ public abstract class AbstractTMSTileSource extends AbstractTileSource {
                 int j = 0;
                 for (final int v : byteDigest) {
                     int vn = (v & 0xf0) >> 4;
-                    hexChars[j++] = (char) (vn + (vn >= 10 ? 'a' - 10 : '0'));
+                    hexChars[j++] = (char) (vn + (vn >= 10 ? ('a' - 10) : '0'));
                     vn = (v & 0xf);
-                    hexChars[j++] = (char) (vn + (vn >= 10 ? 'a' - 10 : '0'));
+                    hexChars[j++] = (char) (vn + (vn >= 10 ? ('a' - 10) : '0'));
                 }
                 for (String val: searchEntry.getValue()) {
                     if (new String(hexChars).equalsIgnoreCase(val)) {


=====================================
src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
=====================================
@@ -4,6 +4,8 @@ package org.openstreetmap.gui.jmapviewer.tilesources;
 import java.awt.Image;
 import java.io.IOException;
 import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
@@ -31,6 +33,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.JMapViewerRuntimeException;
 import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
@@ -61,15 +64,15 @@ public class BingAerialTileSource extends TMSTileSource {
             "https://dev.virtualearth.net/REST/v1/Imagery/Metadata/{layer}?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 final Pattern PATTERN_SUBDOMAIN = Pattern.compile("\\{subdomain}");
+    private static final Pattern PATTERN_QUADKEY = Pattern.compile("\\{quadkey}");
+    private static final Pattern PATTERN_CULTURE = Pattern.compile("\\{culture}");
+
     private volatile Future<List<Attribution>> attributions; // volatile is required for getAttribution(), see below.
     private String imageUrlTemplate;
     private int imageryZoomMax = Integer.MIN_VALUE;
     private String[] subdomains;
-
-    private static final Pattern subdomainPattern = Pattern.compile("\\{subdomain}");
-    private static final Pattern quadkeyPattern = Pattern.compile("\\{quadkey}");
-    private static final Pattern culturePattern = Pattern.compile("\\{culture}");
     private String brandLogoUri;
     private String layer = "Aerial";
 
@@ -107,8 +110,8 @@ public class BingAerialTileSource extends TMSTileSource {
         String subdomain = subdomains[t];
 
         String url = imageUrlTemplate;
-        url = subdomainPattern.matcher(url).replaceAll(subdomain);
-        url = quadkeyPattern.matcher(url).replaceAll(computeQuadTree(zoom, tilex, tiley));
+        url = PATTERN_SUBDOMAIN.matcher(url).replaceAll(subdomain);
+        url = PATTERN_QUADKEY.matcher(url).replaceAll(computeQuadTree(zoom, tilex, tiley));
 
         return url;
     }
@@ -126,9 +129,15 @@ public class BingAerialTileSource extends TMSTileSource {
     }
 
     protected URL getAttributionUrl() throws MalformedURLException {
-        return new URL(FeatureAdapter.getSetting(METADATA_API_SETTING, METADATA_API_URL)
-                .replace(API_KEY_PLACEHOLDER, FeatureAdapter.getSetting(API_KEY_SETTING, API_KEY))
-                .replace(API_KEY_LAYER, this.layer));
+        try {
+            return new URI(FeatureAdapter.getSetting(METADATA_API_SETTING, METADATA_API_URL)
+                    .replace(API_KEY_PLACEHOLDER, FeatureAdapter.getSetting(API_KEY_SETTING, API_KEY))
+                    .replace(API_KEY_LAYER, this.layer)).toURL();
+        } catch (URISyntaxException e) {
+            MalformedURLException malformedURLException = new MalformedURLException(e.getMessage());
+            malformedURLException.initCause(e);
+            throw malformedURLException;
+        }
     }
 
     protected List<Attribution> parseAttributionText(InputSource xml) throws IOException {
@@ -231,11 +240,11 @@ public class BingAerialTileSource extends TMSTileSource {
                 }
                 if (brandLogoUri != null && !brandLogoUri.isEmpty()) {
                     LOG.log(Level.FINE, "Reading Bing logo from {0}", brandLogoUri);
-                    return FeatureAdapter.readImage(new URL(brandLogoUri));
+                    return FeatureAdapter.readImage(new URI(brandLogoUri));
                 }
             }
-        } catch (IOException e) {
-            LOG.log(Level.SEVERE, "Error while retrieving Bing logo: "+e.getMessage());
+        } catch (URISyntaxException | IOException e) {
+            LOG.log(Level.SEVERE, String.format("Error while retrieving Bing logo: %s", e.getMessage()));
         }
         return null;
     }
@@ -265,7 +274,7 @@ public class BingAerialTileSource extends TMSTileSource {
                     LOG.log(Level.FINE, "Successfully loaded Bing attribution data.");
                     return r;
                 } catch (IOException ex) {
-                    LOG.log(Level.SEVERE, "Could not connect to Bing API. Will retry in " + waitTimeSec + " seconds.");
+                    LOG.log(Level.SEVERE, String.format("Could not connect to Bing API. Will retry in %d seconds.", waitTimeSec));
                     LOG.log(Level.FINE, ex.getMessage(), ex);
                     Thread.sleep(TimeUnit.SECONDS.toMillis(waitTimeSec));
                     waitTimeSec *= 2;
@@ -274,6 +283,10 @@ public class BingAerialTileSource extends TMSTileSource {
         };
     }
 
+    /**
+     * Get the attribution data that is currently loaded
+     * @return The list of {@link Attribution} data or {@code null}, if no attribution data has been loaded yet.
+     */
     protected List<Attribution> getAttribution() {
         if (attributions == null) {
             // see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
@@ -285,14 +298,16 @@ public class BingAerialTileSource extends TMSTileSource {
                 }
             }
         }
-        try {
-            return attributions.get();
-        } catch (ExecutionException ex) {
-            throw new RuntimeException(ex);
-        } catch (InterruptedException ign) {
-            LOG.log(Level.SEVERE, "InterruptedException: {0}", ign.getMessage());
-            LOG.log(Level.FINE, ign.getMessage(), ign);
-            Thread.currentThread().interrupt();
+        if (attributions.isDone()) {
+            try {
+                return attributions.get();
+            } catch (ExecutionException ex) {
+                throw new JMapViewerRuntimeException(ex);
+            } catch (InterruptedException ign) {
+                LOG.log(Level.SEVERE, "InterruptedException: {0}", ign.getMessage());
+                LOG.log(Level.FINE, ign.getMessage(), ign);
+                Thread.currentThread().interrupt();
+            }
         }
         return null;
     }
@@ -318,7 +333,7 @@ public class BingAerialTileSource extends TMSTileSource {
     private void setImageUrlTemplate(String template) {
         String noHttpTemplate = template.replace("http://ecn.{subdomain}.tiles.virtualearth.net/",
                 "https://ecn.{subdomain}.tiles.virtualearth.net/");
-        this.imageUrlTemplate = culturePattern.matcher(noHttpTemplate).replaceAll(Locale.getDefault().toString());
+        this.imageUrlTemplate = PATTERN_CULTURE.matcher(noHttpTemplate).replaceAll(Locale.getDefault().toString());
     }
 
     private void setImageryZoomMax(int maxZoom) {


=====================================
src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java.rej
=====================================
@@ -0,0 +1,25 @@
+@@ -286,14 +286,16 @@
+                 }
+             }
+         }
+-        try {
+-            return attributions.get();
+-        } catch (ExecutionException ex) {
+-            throw new JMapViewerRuntimeException(ex);
+-        } catch (InterruptedException ign) {
+-            LOG.log(Level.SEVERE, "InterruptedException: {0}", ign.getMessage());
+-            LOG.log(Level.FINE, ign.getMessage(), ign);
+-            Thread.currentThread().interrupt();
++        if (attributions.isDone()) {
++            try {
++                return attributions.get();
++            } catch (ExecutionException ex) {
++                throw new JMapViewerRuntimeException(ex);
++            } catch (InterruptedException ign) {
++                LOG.log(Level.SEVERE, "InterruptedException: {0}", ign.getMessage());
++                LOG.log(Level.FINE, ign.getMessage(), ign);
++                Thread.currentThread().interrupt();
++            }
+         }
+         return null;
+     }


=====================================
src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java
=====================================
@@ -31,7 +31,7 @@ public class OsmTileSource {
 
         @Override
         public String getBaseUrl() {
-            String url = String.format(this.baseUrl, new Object[] {SERVER[serverNum]});
+            String url = String.format(this.baseUrl, SERVER[serverNum]);
             serverNum = (serverNum + 1) % SERVER.length;
             return url;
         }
@@ -57,15 +57,15 @@ public class OsmTileSource {
 
         @Override
         public String getBaseUrl() {
-            String url = String.format(this.baseUrl, new Object[] {SERVER[serverNum]});
+            String url = String.format(this.baseUrl, SERVER[serverNum]);
             serverNum = (serverNum + 1) % SERVER.length;
             return url;
         }
 
         /**
          * Get the thunderforest API key.
-         *
-         * Needs to be registered at their web site.
+         * <p>
+         * Needs to be registered at their website.
          * @return the API key
          */
         protected abstract String getApiKey();


=====================================
src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java
=====================================
@@ -13,20 +13,25 @@ import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 
 /**
  * This tilesource uses different to OsmMercator projection.
- *
+ * <p>
  * Earth is assumed an ellipsoid in this projection, unlike
  * sphere in OsmMercator, so latitude calculation differs a lot.
- *
+ * <p>
  * The longitude calculation is the same as in OsmMercator,
  * we inherit it from AbstractTMSTileSource.
  *
  * TODO: correct getDistance() method.
  */
 public class ScanexTileSource extends TMSTileSource {
-    private static final String DEFAULT_URL = "http://maps.kosmosnimki.ru";
+    private static final String DEFAULT_URL = "https://maps.kosmosnimki.ru";
     private static final int DEFAULT_MAXZOOM = 14;
     private static final String API_KEY = "4018C5A9AECAD8868ED5DEB2E41D09F7";
 
+    // Latitude to Y and back calculations.
+    private static final double RADIUS_E = 6_378_137;   /* radius of Earth at equator, m */
+    private static final double EQUATOR = 40075016.68557849; /* equator length, m */
+    private static final double E = 0.0818191908426;  /* eccentricity of Earth's ellipsoid */
+
     private enum ScanexLayer {
         IRS("irs", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=BAC78D764F0443BD9AF93E7A998C9F5B");
 
@@ -49,7 +54,7 @@ public class ScanexTileSource extends TMSTileSource {
 
     /** IRS by default */
     private ScanexLayer layer = ScanexLayer.IRS;
-    private TemplatedTMSTileSource TemplateSource = null;
+    private TemplatedTMSTileSource templateSource;
 
     /** cached latitude used in {@link #tileYToLat(double, int)} */
     private double cachedLat;
@@ -62,10 +67,10 @@ public class ScanexTileSource extends TMSTileSource {
         super(info);
         String url = info.getUrl();
 
-        /**
+        /*
          * The formulae in tileYToLat() and latToTileY() have 2^8
          * hardcoded in them, so explicitly state that.  For now
-         * the assignment matches OsmMercator.DEFAUL_TILE_SIZE, and
+         * the assignment matches OsmMercator.DEFAULT_TILE_SIZE, and
          * thus is extraneous.  But let it be there just in case if
          * OsmMercator changes.
          */
@@ -81,9 +86,9 @@ public class ScanexTileSource extends TMSTileSource {
                 return;
             }
         }
-        /** If not "irs" or "spot" keyword, then a custom URL. */
+        /* If not "irs" or "spot" keyword, then a custom URL. */
         TemplatedTMSTileSource.checkUrl(info.getUrl());
-        this.TemplateSource = new TemplatedTMSTileSource(info);
+        this.templateSource = new TemplatedTMSTileSource(info);
     }
 
     @Override
@@ -93,15 +98,15 @@ public class ScanexTileSource extends TMSTileSource {
 
    @Override
     public String getTileUrl(int zoom, int tilex, int tiley) {
-        if (this.TemplateSource != null)
-            return this.TemplateSource.getTileUrl(zoom, tilex, tiley);
+        if (this.templateSource != null)
+            return this.templateSource.getTileUrl(zoom, tilex, tiley);
         else
             return this.getBaseUrl() + getTilePath(zoom, tilex, tiley);
     }
 
     @Override
     public String getTilePath(int zoom, int tilex, int tiley) {
-        int tmp = (int) Math.pow(2.0, zoom - 1);
+        int tmp = (int) Math.pow(2.0, zoom - 1d);
 
         tilex = tilex - tmp;
         tiley = tmp - tiley - 1;
@@ -109,11 +114,6 @@ public class ScanexTileSource extends TMSTileSource {
         return this.layer.getUri() + "&apikey=" + API_KEY + "&x=" + tilex + "&y=" + tiley + "&z=" + zoom;
     }
 
-    // Latitude to Y and back calculations.
-    private static final double RADIUS_E = 6378137;   /* radius of Earth at equator, m */
-    private static final double EQUATOR = 40075016.68557849; /* equator length, m */
-    private static final double E = 0.0818191908426;  /* eccentricity of Earth's ellipsoid */
-
     @Override
     public Point latLonToXY(double lat, double lon, int zoom) {
         return new Point(
@@ -142,11 +142,11 @@ public class ScanexTileSource extends TMSTileSource {
     public ICoordinate tileXYToLatLon(int x, int y, int zoom) {
         return new Coordinate(
                 tileYToLat(y, zoom),
-                osmMercator.xToLon(x * getTileSize(), zoom)
+                osmMercator.xToLon((long) x * getTileSize(), zoom)
                 );
     }
 
-    private double latToTileY(double lat, int zoom) {
+    private static double latToTileY(double lat, int zoom) {
         double tmp = Math.tan(Math.PI/4 * (1 + lat/90));
         double pow = Math.pow(Math.tan(Math.PI/4 + Math.asin(E * Math.sin(Math.toRadians(lat)))/2), E);
 
@@ -182,7 +182,7 @@ public class ScanexTileSource extends TMSTileSource {
         double sinl = Math.sin(lat);
         double cosl = Math.cos(lat);
 
-        zoom = (int) Math.pow(2.0, zoom - 1);
+        zoom = (int) Math.pow(2.0, zoom - 1d);
         double ec = Math.exp((1 - y/zoom)*Math.PI);
 
         double f = Math.tan(Math.PI/4+lat/2) -


=====================================
src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java
=====================================
@@ -74,8 +74,8 @@ public class TMSTileSource extends AbstractTMSTileSource {
     @Override
     public ICoordinate tileXYToLatLon(int x, int y, int zoom) {
         return new Coordinate(
-                osmMercator.yToLat(y * getTileSize(), zoom),
-                osmMercator.xToLon(x * getTileSize(), zoom)
+                osmMercator.yToLat((long) y * getTileSize(), zoom),
+                osmMercator.xToLon((long) x * getTileSize(), zoom)
                 );
     }
 


=====================================
src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java
=====================================
@@ -16,49 +16,51 @@ import org.openstreetmap.gui.jmapviewer.interfaces.TemplatedTileSource;
 /**
  * Handles templated TMS Tile Source. Templated means, that some patterns within
  * URL gets substituted.
- *
+ * <p>
  * Supported parameters
- * {zoom} - substituted with zoom level
- * {z} - as above
- * {NUMBER-zoom} - substituted with result of equation "NUMBER - zoom",
- *                  eg. {20-zoom} for zoom level 15 will result in 5 in this place
- * {zoom+number} - substituted with result of equation "zoom + number",
- *                 eg. {zoom+5} for zoom level 15 will result in 20.
- * {x} - substituted with X tile number
- * {y} - substituted with Y tile number
- * {!y} - substituted with Yahoo Y tile number
- * {-y} - substituted with reversed Y tile number
- * {apikey} - substituted with API key retrieved for the imagery id
- * {switch:VAL_A,VAL_B,VAL_C,...} - substituted with one of VAL_A, VAL_B, VAL_C. Usually
- *                                  used to specify many tile servers
- * {header:(HEADER_NAME,HEADER_VALUE)} - sets the headers to be sent to tile server
+ * <ul>
+ * <li>{zoom} - substituted with zoom level</li>
+ * <li>{z} - as above</li>
+ * <li>{NUMBER-zoom} - substituted with result of equation "NUMBER - zoom",
+ *                  eg. {20-zoom} for zoom level 15 will result in 5 in this place</li>
+ * <li>{zoom+number} - substituted with result of equation "zoom + number",
+ *                 eg. {zoom+5} for zoom level 15 will result in 20.</li>
+ * <li>{x} - substituted with X tile number</li>
+ * <li>{y} - substituted with Y tile number</li>
+ * <li>{!y} - substituted with Yahoo Y tile number</li>
+ * <li>{-y} - substituted with reversed Y tile number</li>
+ * <li>{apikey} - substituted with API key retrieved for the imagery id</li>
+ * <li>{switch:VAL_A,VAL_B,VAL_C,...} - substituted with one of VAL_A, VAL_B, VAL_C. Usually
+ *                                  used to specify many tile servers</li>
+ * <li>{header:(HEADER_NAME,HEADER_VALUE)} - sets the headers to be sent to tile server</li>
+ * </ul>
  */
 public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTileSource {
 
-    private Random rand;
-    private String[] randomParts;
-    private final Map<String, String> 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 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_API_KEY = Pattern.compile("\\{apikey\\}");
-    private static final Pattern PATTERN_PARAM  = Pattern.compile("\\{((?:\\d+-)?z(?:oom)?(:?[+-]\\d+)?|x|y|!y|-y|switch:([^}]+))\\}");
+    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_API_KEY = Pattern.compile("\\{apikey}");
+    private static final Pattern PATTERN_PARAM  = Pattern.compile("\\{((?:\\d+-)?z(?:oom)?(:?[+-]\\d+)?|x|y|!y|-y|switch:([^}]+))}");
 
     // CHECKSTYLE.ON: SingleSpaceSeparator
 
     private static final Pattern[] ALL_PATTERNS = {
-        PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y, PATTERN_SWITCH, PATTERN_API_KEY
+            PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y, PATTERN_SWITCH, PATTERN_API_KEY
     };
 
+    private Random rand;
+    private String[] randomParts;
+    private final Map<String, String> headers = new HashMap<>();
+    private boolean inverse_zoom;
+    private int zoom_offset;
+
     /**
      * Creates Templated TMS Tile Source based on ImageryInfo
      * @param info imagery info
@@ -136,7 +138,7 @@ public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
             switch (matcher.group(1)) {
             case "z": // PATTERN_ZOOM
             case "zoom":
-                replacement = Integer.toString((inverse_zoom ? -1 * zoom : zoom) + zoom_offset);
+                replacement = Integer.toString((inverse_zoom ? -zoom : zoom) + zoom_offset);
                 break;
             case "x": // PATTERN_X
                 replacement = Integer.toString(tilex);
@@ -145,7 +147,7 @@ public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
                 replacement = Integer.toString(tiley);
                 break;
             case "!y": // PATTERN_Y_YAHOO
-                replacement = Integer.toString((int) Math.pow(2, zoom-1)-1-tiley);
+                replacement = Integer.toString((int) Math.pow(2, zoom - 1d) - 1 - tiley);
                 break;
             case "-y": // PATTERN_NEG_Y
                 replacement = Integer.toString((int) Math.pow(2, zoom)-1-tiley);
@@ -156,7 +158,7 @@ public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
             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);
+                    replacement = Integer.toString((inverse_zoom ? -zoom : zoom) + zoom_offset);
                 } else if (PATTERN_SWITCH.matcher("{" + matcher.group(1) + "}").matches()) {
                     replacement = getRandomPart(randomParts);
                 } else {
@@ -179,7 +181,7 @@ public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
      */
     public static void checkUrl(String url) {
         assert url != null && !"".equals(url) : "URL cannot be null or empty";
-        Matcher m = Pattern.compile("\\{[^}]*\\}").matcher(url);
+        Matcher m = Pattern.compile("\\{[^}]*}").matcher(url);
         while (m.find()) {
             boolean isSupportedPattern = Arrays.stream(ALL_PATTERNS).anyMatch(pattern -> pattern.matcher(m.group()).matches());
             if (!isSupportedPattern) {



View it on GitLab: https://salsa.debian.org/debian-gis-team/jmapviewer/-/compare/fb1c3dbdc3a83ef8896a24aae0638d17faf0b54a...1ffe1cc140e2ee877c78e364306f4ee272322d86

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/jmapviewer/-/compare/fb1c3dbdc3a83ef8896a24aae0638d17faf0b54a...1ffe1cc140e2ee877c78e364306f4ee272322d86
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20240813/956296ab/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list