-
diff --git .checkstyle .checkstyle
index 66b7500..25cd9c8 100644
|
|
|
|
| 5 | 5 | <additional-data name="protect-config-file" value="false"/> |
| 6 | 6 | </local-check-config> |
| 7 | 7 | <fileset name="all" enabled="true" check-config-name="JMapViewer" local="true"> |
| 8 | | <file-match-pattern match-pattern="." include-pattern="true"/> |
| | 8 | <file-match-pattern match-pattern="\.java$" include-pattern="true"/> |
| 9 | 9 | </fileset> |
| 10 | 10 | <filter name="FilesFromPackage" enabled="true"> |
| 11 | 11 | <filter-data value="src/org/openstreetmap/gui/jmapviewer/images"/> |
-
diff --git .classpath .classpath
index cf1198a..2c27265 100644
|
|
|
|
| 6 | 6 | <attribute name="test" value="true"/> |
| 7 | 7 | </attributes> |
| 8 | 8 | </classpathentry> |
| 9 | | <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> |
| 10 | | <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> |
| | 9 | <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"> |
| | 10 | <attributes> |
| | 11 | <attribute name="module" value="true"/> |
| | 12 | </attributes> |
| | 13 | </classpathentry> |
| | 14 | <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/> |
| 11 | 15 | <classpathentry kind="output" path="bin"/> |
| 12 | 16 | </classpath> |
-
diff --git .gitignore .gitignore
index 6befe71..44747be 100644
|
|
|
|
| 2 | 2 | JMapViewer.jar |
| 3 | 3 | JMapViewer_Demo.jar |
| 4 | 4 | JMapViewer_src.jar |
| 5 | | JMapViewer.zip |
| 6 | 5 | /bin/ |
| 7 | 6 | /bintest/ |
| 8 | 7 | /javadoc/ |
| 9 | 8 | /report/ |
| 10 | | /tiles/ |
| 11 | 9 | /checkstyle-jmapviewer.xml |
| 12 | | /findbugs-jmapviewer.xml |
| 13 | 10 | /spotbugs-jmapviewer.xml |
| 14 | 11 | *.exec |
| 15 | 12 | |
| 16 | 13 | # Maven output |
| 17 | 14 | /target/ |
| | 15 | /releases/*-SNAPSHOT/ |
| 18 | 16 | |
| 19 | 17 | # SVN working copy metadata (this tree is an svn checkout) |
| 20 | 18 | /.svn/ |
-
diff --git .project .project
index ad7e557..8a037ad 100644
|
|
|
|
| 27 | 27 | </buildCommand> |
| 28 | 28 | </buildSpec> |
| 29 | 29 | <natures> |
| 30 | | <nature>org.sonar.ide.eclipse.core.sonarNature</nature> |
| 31 | 30 | <nature>org.eclipse.jdt.core.javanature</nature> |
| 32 | 31 | <nature>net.sf.eclipsecs.core.CheckstyleNature</nature> |
| 33 | 32 | <nature>edu.umd.cs.findbugs.plugin.eclipse.findbugsNature</nature> |
-
diff --git .settings/edu.umd.cs.findbugs.core.prefs .settings/edu.umd.cs.findbugs.core.prefs
index e406091..99abdf4 100644
|
|
|
|
| 1 | 1 | #FindBugs User Preferences |
| 2 | 2 | #Sat Aug 01 22:46:10 CEST 2015 |
| 3 | | cloud_id=edu.umd.cs.findbugs.cloud.doNothingCloud |
| 4 | 3 | detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true |
| 5 | 4 | detectorAtomicityProblem=AtomicityProblem|true |
| 6 | 5 | detectorBadAppletConstructor=BadAppletConstructor|false |
-
diff --git .settings/org.eclipse.jdt.core.prefs .settings/org.eclipse.jdt.core.prefs
index c4e4a7f..a04d4e1 100644
|
|
|
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonN
|
| 15 | 15 | org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault |
| 16 | 16 | org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable |
| 17 | 17 | org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled |
| 18 | | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled |
| 19 | | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 |
| | 18 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 |
| 20 | 19 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve |
| 21 | | org.eclipse.jdt.core.compiler.compliance=1.8 |
| | 20 | org.eclipse.jdt.core.compiler.compliance=11 |
| 22 | 21 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate |
| 23 | 22 | org.eclipse.jdt.core.compiler.debug.localVariable=generate |
| 24 | 23 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate |
| … |
… |
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
| 121 | 120 | org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore |
| 122 | 121 | org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning |
| 123 | 122 | org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning |
| 124 | | org.eclipse.jdt.core.compiler.source=1.8 |
| | 123 | org.eclipse.jdt.core.compiler.release=enabled |
| | 124 | org.eclipse.jdt.core.compiler.source=11 |
| 125 | 125 | org.eclipse.jdt.core.formatter.align_type_members_on_columns=false |
| 126 | 126 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 |
| 127 | 127 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 |
-
diff --git .settings/org.sonar.ide.eclipse.core.prefs .settings/org.sonar.ide.eclipse.core.prefs
deleted file mode 100644
index 4ab0dd3..0000000
|
+
|
-
|
|
| 1 | | eclipse.preferences.version=1 |
| 2 | | extraProperties= |
| 3 | | lastAnalysisDate=1438527074033 |
| 4 | | projectKey=jmapviewer |
| 5 | | serverUrl=https\://josm.openstreetmap.de/sonar |
| 6 | | version=2 |
-
diff --git CONTRIBUTING.md CONTRIBUTING.md
index ee9f19a..416fa57 100644
|
|
|
|
| 1 | 1 | # Contributing |
| | 2 | ## Requirements |
| | 3 | * JDK 11 or later |
| 2 | 4 | ## How to test |
| 3 | 5 | * Unit tests: `mvn test` |
| 4 | 6 | * Manual testing: `mvn compile exec:java -Dexec.mainClass=org.openstreetmap.gui.jmapviewer.Demo` |
| … |
… |
See [https://josm.openstreetmap.de/wiki/DevelopersGuide/PatchGuide](https://josm
|
| 22 | 24 | * `ant test` -> `mvn test` |
| 23 | 25 | * `ant svn_info` -> manual pom.xml editing or `mvn release:update-versions -DdevelopmentVersion=$(svn propget ReleaseVersion .)-SNAPSHOT` |
| 24 | 26 | * `ant pack` -> `mvn package` (note: slightly different source filename, doesn't merge source and class jars) |
| 25 | | * `ant create_run_jar` -> not migrated (use `mvn exec:java -Dexec.mainClass="org.openstreetmap.gui.jmapviewer.Demo"` instead) |
| | 27 | * `ant create_run_jar` -> not needed, the jar from `mvn package` is runnable |
| 26 | 28 | * `ant spotbugs` -> `mvn spotbugs:check` |
| 27 | 29 | * `ant checkstyle` -> `mvn checkstyle:checkstyle` |
| 28 | 30 | * `ant javadoc` -> `mvn javadoc:javadoc` |
| 29 | | * `ant create_release_zip` -> `mvn jar:jar` |
| 30 | | * `ant create_source_release_zip` -> `mvn source:jar` |
| | 31 | * `ant create_release_zip`, `ant create_source_release_zip` -> `mvn -Prelease package`, written to `releases/${version}` |
| 31 | 32 | * `ant checkdepsupdate` -> `mvn versions:display-dependency-updates` (note: please try to keep the version information in sync) |
-
diff --git Readme.txt Readme.txt
index 9346474..3e8d6f6 100644
|
|
|
JMapViewer
|
| 21 | 21 | (c) 2015-2019, Wiktor Niesiobędzki |
| 22 | 22 | (c) 2017, Robert Scott |
| 23 | 23 | |
| 24 | | This work bases partly on the JOSM plugin "Slippy Map Chooser" by Tim Haussmann |
| | 24 | This work is partly based on the JOSM plugin "Slippy Map Chooser" by Tim Haussmann |
| 25 | 25 | |
| 26 | 26 | License: GPL |
| 27 | 27 | |
| … |
… |
FAQ:
|
| 29 | 29 | |
| 30 | 30 | 1. What is JMapViewer? |
| 31 | 31 | |
| 32 | | JMapViewer is a Java Swing component for integrating OSM maps in to your Java |
| 33 | | application. JMapViewer allows you to set markers on the map or zoom to a specific |
| | 32 | JMapViewer is a Java Swing component for integrating OSM maps into your Java |
| | 33 | application. JMapViewer lets you set markers on the map or zoom to a specific |
| 34 | 34 | location on the map. |
| 35 | 35 | |
| 36 | 36 | 2. How does JMapViewer work? |
| 37 | 37 | |
| 38 | | JMapViewer loads bitmap tiles from the OpenStreetmap tile server (Mapnik renderer). |
| 39 | | Therefore any application using JMapViewer requires a working Internet connection. |
| | 38 | JMapViewer loads bitmap tiles from the OpenStreetMap tile server (Mapnik renderer). |
| | 39 | Therefore, any application using JMapViewer requires a working Internet connection. |
| 40 | 40 | |
| 41 | 41 | 3. How do I use JMapViewer in my application? |
| 42 | 42 | |
| 43 | | You can just create an instance of the class org.openstreetmap.gui.jmapviewer.JMapViewer |
| 44 | | using the default constructor and add it to your panel/frame/windows. |
| 45 | | For more details please see the Demo class in the same package. |
| | 43 | Just create an instance of the class org.openstreetmap.gui.jmapviewer.JMapViewer |
| | 44 | using the default constructor and add it to your panel, frame or window. |
| | 45 | For more details, please see the Demo class in the same package. |
| | 46 | |
| | 47 | 4. What do I need to run JMapViewer? |
| | 48 | |
| | 49 | Java 11 or later. JMapViewer only uses the java.desktop and java.logging modules of the |
| | 50 | Java runtime, and no other libraries. |
-
diff --git build.xml build.xml
index 3d07301..a4cd871 100644
|
|
|
|
| 5 | 5 | xmlns:mvn="antlib:org.apache.maven.resolver.ant" |
| 6 | 6 | > |
| 7 | 7 | |
| 8 | | <property name="java.lang.version" value="8" /> |
| 9 | | <dirname property="base.dir" file="${ant.file.jmapviewer}"/> |
| 10 | | <property name="maven.artifact.resolver.version" value="1.5.1"/> |
| | 8 | <!-- Keep in sync with maven.compiler.release and jmapviewer.buildJdk in pom.xml --> |
| | 9 | <property name="java.lang.version" value="11" /> |
| | 10 | <property name="java.build.version" value="11" /> |
| | 11 | <fail message="Building JMapViewer needs JDK ${java.build.version} or later, the classes are compiled for Java ${java.lang.version}"> |
| | 12 | <condition><not><javaversion atleast="${java.build.version}"/></not></condition> |
| | 13 | </fail> |
| | 14 | <property name="maven.artifact.resolver.version" value="2.0.0"/> |
| 11 | 15 | <property name="maven.artifact.resolver.parent.dir" value="${user.home}/.m2/repository/org/apache/maven/resolver/maven-resolver-ant-tasks/${maven.artifact.resolver.version}/"/> |
| 12 | 16 | <property name="jacoco.includes" value="org.openstreetmap.gui.jmapviewer.*" /> |
| 13 | 17 | <property name="jacoco.inclbootstrapclasses" value="false" /> |
| 14 | 18 | <property name="jacoco.inclnolocationclasses" value="false" /> |
| 15 | | <!-- For Java specific stuff by version --> |
| 16 | | <condition property="isJava9"><matches string="${ant.java.version}" pattern="(1.)?(9|[2-9][0-9])" /></condition> |
| 17 | | <condition property="isJava23"><matches string="${ant.java.version}" pattern="2[3-9]|[3-9][0-9]" /></condition> |
| 18 | | <!-- Disable jacoco 0.8.11 on Java 23+, see https://www.jacoco.org/jacoco/trunk/doc/changes.html for latest supported version --> |
| | 19 | <!-- Disable jacoco on the Java versions it does not support yet, see https://www.jacoco.org/jacoco/trunk/doc/changes.html. |
| | 20 | Update the pattern together with version.maven.jacoco in pom.xml. --> |
| | 21 | <condition property="isJavaUnsupportedByJacoco"><matches string="${ant.java.version}" pattern="2[8-9]|[3-9][0-9]" /></condition> |
| 19 | 22 | <condition property="coverageByDefault"> |
| 20 | 23 | <not> |
| 21 | | <isset property="isJava23"/> |
| | 24 | <isset property="isJavaUnsupportedByJacoco"/> |
| 22 | 25 | </not> |
| 23 | 26 | </condition> |
| 24 | 27 | <path id="test.classpath"> |
| … |
… |
|
| 50 | 53 | </target> |
| 51 | 54 | |
| 52 | 55 | <target name="build" depends="clean"> |
| 53 | | <!-- compile module info - we need to compile everything to ensure that all requires are there --> |
| 54 | | <javac srcdir="src" destdir="bin" release="9" debug="true" includeantruntime="false" encoding="UTF-8" if:set="isJava9"> |
| 55 | | <include name="module-info.java" /> |
| 56 | | <include name="org/openstreetmap/gui/jmapviewer/**" /> |
| 57 | | </javac> |
| 58 | | |
| 59 | | <!-- Remove the files compiled with Java 9 so that the next compile stage will compile to the appropriate version --> |
| 60 | | <delete> |
| 61 | | <fileset dir="bin"> |
| 62 | | <include name="org/openstreetmap/gui/jmapviewer/**" /> |
| 63 | | </fileset> |
| 64 | | </delete> |
| 65 | | |
| 66 | 56 | <javac srcdir="src" destdir="bin" release="${java.lang.version}" debug="true" includeantruntime="false" encoding="UTF-8"> |
| 67 | | <include name="org/openstreetmap/gui/jmapviewer/**" /> |
| | 57 | <compilerarg value="-Xlint:all"/> |
| | 58 | <compilerarg value="-Xlint:-serial"/> |
| 68 | 59 | </javac> |
| 69 | 60 | |
| 70 | 61 | <copy todir="bin"> |
| … |
… |
|
| 81 | 72 | <env key="LANG" value="en_US"/> |
| 82 | 73 | </exec> |
| 83 | 74 | </target> |
| 84 | | |
| | 75 | |
| 85 | 76 | <target name="pack" depends="build"> |
| 86 | 77 | <!-- Create the JAR file containing the compiled class files --> |
| 87 | | <jar destfile="JMapViewer.jar" filesetmanifest="mergewithoutmain"> |
| 88 | | <fileset dir="bin" includes="module-info.class,**/jmapviewer/**" /> |
| 89 | | </jar> |
| | 78 | <jar destfile="JMapViewer.jar" basedir="bin" filesetmanifest="mergewithoutmain"/> |
| 90 | 79 | <!-- Create the JAR file containing the source java files --> |
| 91 | | <jar destfile="JMapViewer_src.jar" filesetmanifest="mergewithoutmain"> |
| 92 | | <fileset dir="src" includes="module-info.java,**/jmapviewer/**" /> |
| 93 | | </jar> |
| | 80 | <jar destfile="JMapViewer_src.jar" basedir="src" filesetmanifest="mergewithoutmain"/> |
| 94 | 81 | </target> |
| 95 | | |
| 96 | | <!-- if you want to build outside of svn, use "ant clean build [pack]" --> |
| 97 | | |
| | 82 | |
| 98 | 83 | <target name="create_run_jar" description="Create a JAR file that can be used to execute the JMapViewer demo app. Requires JMapViewer.jar to be present."> |
| 99 | 84 | <jar destfile="JMapViewer_Demo.jar" filesetmanifest="mergewithoutmain"> |
| 100 | 85 | <manifest> |
| … |
… |
|
| 112 | 97 | </zip> |
| 113 | 98 | <delete> |
| 114 | 99 | <fileset dir="." includes="JMapViewer*.jar"/> |
| 115 | | </delete> |
| | 100 | </delete> |
| 116 | 101 | </target> |
| 117 | | |
| | 102 | |
| 118 | 103 | <target name="create_source_release_zip" description="Create a release zip file containing the source files"> |
| | 104 | <!-- Same content as tools/assembly/source-release.xml, so that the unpacked zip builds with Ant and Maven --> |
| 119 | 105 | <zip destfile="releases/${svnReleaseVersion}/JMapViewer-${svnReleaseVersion}-Source.zip"> |
| 120 | | <zipfileset file="Readme.txt" prefix="jmapviewer-${svnReleaseVersion}"/> |
| 121 | | <zipfileset file="build.xml" prefix="jmapviewer-${svnReleaseVersion}"/> |
| 122 | | <zipfileset file="Gpl.txt" prefix="jmapviewer-${svnReleaseVersion}"/> |
| 123 | | <zipfileset dir="src" includes="**/jmapviewer/**" prefix="jmapviewer-${svnReleaseVersion}/src"/> |
| | 106 | <zipfileset dir="." includes="Readme.txt,Gpl.txt,build.xml,pom.xml,src/**,test/**,tools/**" |
| | 107 | prefix="jmapviewer-${svnReleaseVersion}"/> |
| 124 | 108 | </zip> |
| 125 | 109 | </target> |
| 126 | 110 | |
| … |
… |
|
| 128 | 112 | <taskdef resource="com/puppycrawl/tools/checkstyle/ant/checkstyle-ant-task.properties" |
| 129 | 113 | classpathref="checkstyle.classpath"/> |
| 130 | 114 | <checkstyle config="${basedir}/tools/checkstyle/jmapviewer_checks.xml"> |
| 131 | | <!-- Exclude the module-info since checkstyle currently cannot parse it --> |
| 132 | | <fileset dir="${basedir}/src" includes="**/*.java" excludes="module-info.java" /> |
| | 115 | <property key="config_loc" value="${basedir}/tools/checkstyle"/> |
| | 116 | <fileset dir="${basedir}/src" includes="**/*.java" /> |
| | 117 | <fileset dir="${basedir}/test" includes="**/*.java" /> |
| 133 | 118 | <formatter type="xml" toFile="checkstyle-jmapviewer.xml"/> |
| 134 | 119 | </checkstyle> |
| 135 | 120 | </target> |
| 136 | 121 | |
| 137 | 122 | <target name="spotbugs" depends="pack,resolve"> |
| 138 | | <taskdef name="spotbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask" |
| | 123 | <taskdef name="spotbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask" |
| 139 | 124 | classpathref="spotbugs.classpath"/> |
| 140 | 125 | <property name="spotbugs-classpath" refid="spotbugs.classpath"/> |
| 141 | 126 | <spotbugs output="xml" |
| … |
… |
|
| 149 | 134 | </target> |
| 150 | 135 | |
| 151 | 136 | <target name="javadoc"> |
| 152 | | <javadoc destdir="javadoc" |
| | 137 | <javadoc destdir="javadoc" |
| 153 | 138 | sourcepath="src" |
| 154 | | encoding="UTF-8" |
| | 139 | encoding="UTF-8" |
| 155 | 140 | packagenames="org.openstreetmap.gui.jmapviewer.*" |
| 156 | 141 | windowtitle="JMapViewer" |
| 157 | 142 | use="true" |
| 158 | 143 | private="true" |
| 159 | 144 | linksource="true" |
| 160 | 145 | author="false"> |
| 161 | | <link href="https://docs.oracle.com/javase/8/docs/api"/> |
| | 146 | <link href="https://docs.oracle.com/en/java/javase/${java.lang.version}/docs/api"/> |
| 162 | 147 | <doctitle><![CDATA[<h2>JMapViewer - Javadoc</h2>]]></doctitle> |
| 163 | 148 | <bottom><![CDATA[<a href="https://josm.openstreetmap.de/">JMapViewer</a>]]></bottom> |
| 164 | | <arg value="-html5" if:set="isJava9" /> |
| | 149 | <arg value="--release"/> |
| | 150 | <arg value="${java.lang.version}"/> |
| 165 | 151 | </javadoc> |
| 166 | 152 | </target> |
| 167 | 153 | |
| … |
… |
|
| 204 | 190 | <mvn:dependency groupId="com.github.spotbugs" artifactId="spotbugs" version="${pom.properties.version.maven.spotbugs}" scope="compile"/> |
| 205 | 191 | <mvn:dependency groupId="com.github.spotbugs" artifactId="spotbugs-ant" version="${pom.properties.version.maven.spotbugs}" scope="compile"/> |
| 206 | 192 | </mvn:dependencies> |
| 207 | | <mvn:path refid="spotbugs.classpath" classpath="compile"/> |
| | 193 | <!-- SpotBugs needs its runtime dependencies (jaxen) to load its own plugin descriptor --> |
| | 194 | <mvn:path refid="spotbugs.classpath" classpath="runtime"/> |
| 208 | 195 | </mvn:resolve> |
| 209 | 196 | </target> |
| 210 | 197 | |
| 211 | | <target name="test" depends="clean, build, resolve"> |
| | 198 | <target name="test" depends="build, resolve"> |
| 212 | 199 | <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml" classpathref="jacoco.classpath"/> |
| 213 | 200 | <javac srcdir="test" destdir="bintest" |
| 214 | | target="${java.lang.version}" source="${java.lang.version}" debug="on" |
| | 201 | release="${java.lang.version}" debug="on" |
| 215 | 202 | includeantruntime="false" createMissingPackageInfoClass="false" encoding="UTF-8"> |
| 216 | 203 | <compilerarg value="-Xlint:all"/> |
| 217 | 204 | <compilerarg value="-Xlint:-serial"/> |
-
diff --git pom.xml pom.xml
index 926c75d..5cae331 100644
|
|
|
|
| 11 | 11 | <url>https://josm.openstreetmap.de/browser/osm/applications/viewer/jmapviewer</url> |
| 12 | 12 | <properties> |
| 13 | 13 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
| 14 | | <maven.compiler.release>8</maven.compiler.release> |
| 15 | | <version.maven.spotbugs>4.8.6</version.maven.spotbugs> |
| 16 | | <version.maven.jacoco>0.8.12</version.maven.jacoco> |
| 17 | | <version.maven.checkstyle>9.3</version.maven.checkstyle> |
| | 14 | <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
| | 15 | <maven.compiler.release>11</maven.compiler.release> |
| | 16 | <!-- The JDK needed to run the build tools; the classes are compiled for maven.compiler.release --> |
| | 17 | <jmapviewer.buildJdk>11</jmapviewer.buildJdk> |
| | 18 | <jmapviewer.mainClass>org.openstreetmap.gui.jmapviewer.Demo</jmapviewer.mainClass> |
| | 19 | <!-- Overwritten by the JaCoCo agent, see maven-surefire-plugin --> |
| | 20 | <argLine></argLine> |
| | 21 | <version.maven.spotbugs>4.10.4</version.maven.spotbugs> |
| | 22 | <version.maven.jacoco>0.8.15</version.maven.jacoco> |
| | 23 | <!-- 10.x is the last line that runs on Java 11, see jmapviewer.buildJdk --> |
| | 24 | <version.maven.checkstyle>10.26.1</version.maven.checkstyle> |
| 18 | 25 | <sonar.host.url>https://josm.openstreetmap.de/sonar</sonar.host.url> |
| 19 | 26 | <sonar.projectKey>jmapviewer</sonar.projectKey> |
| 20 | 27 | </properties> |
| … |
… |
|
| 97 | 104 | <dependency> |
| 98 | 105 | <groupId>org.junit</groupId> |
| 99 | 106 | <artifactId>junit-bom</artifactId> |
| 100 | | <version>5.10.2</version> |
| | 107 | <!-- JUnit 6 needs Java 17, while the tests are compiled for maven.compiler.release --> |
| | 108 | <version>5.14.4</version> |
| 101 | 109 | <type>pom</type> |
| 102 | 110 | <scope>import</scope> |
| 103 | 111 | </dependency> |
| … |
… |
|
| 105 | 113 | </dependencyManagement> |
| 106 | 114 | |
| 107 | 115 | <dependencies> |
| 108 | | <dependency> |
| 109 | | <groupId>com.github.spotbugs</groupId> |
| 110 | | <artifactId>spotbugs-annotations</artifactId> |
| 111 | | <version>${version.maven.spotbugs}</version> |
| 112 | | <scope>test</scope> |
| 113 | | </dependency> |
| 114 | | <dependency> |
| 115 | | <groupId>org.junit.platform</groupId> |
| 116 | | <artifactId>junit-platform-launcher</artifactId> |
| 117 | | <scope>test</scope> |
| 118 | | </dependency> |
| 119 | | <dependency> |
| 120 | | <groupId>org.junit.platform</groupId> |
| 121 | | <artifactId>junit-platform-suite</artifactId> |
| 122 | | <scope>test</scope> |
| 123 | | </dependency> |
| 124 | 116 | <dependency> |
| 125 | 117 | <groupId>org.junit.jupiter</groupId> |
| 126 | 118 | <artifactId>junit-jupiter-api</artifactId> |
| … |
… |
|
| 132 | 124 | <scope>test</scope> |
| 133 | 125 | </dependency> |
| 134 | 126 | <dependency> |
| 135 | | <groupId>org.junit.jupiter</groupId> |
| 136 | | <artifactId>junit-jupiter-params</artifactId> |
| | 127 | <!-- Surefire brings its own, but the Ant "junitlauncher" task runs off the test classpath --> |
| | 128 | <groupId>org.junit.platform</groupId> |
| | 129 | <artifactId>junit-platform-launcher</artifactId> |
| 137 | 130 | <scope>test</scope> |
| 138 | 131 | </dependency> |
| 139 | 132 | </dependencies> |
| … |
… |
|
| 143 | 136 | <testSourceDirectory>${project.basedir}/test</testSourceDirectory> |
| 144 | 137 | <finalName>${project.name}-${project.version}</finalName> |
| 145 | 138 | <resources> |
| | 139 | <!-- Images live next to the sources, as the source layout predates the Maven conventions --> |
| 146 | 140 | <resource> |
| 147 | 141 | <directory>${project.build.sourceDirectory}</directory> |
| 148 | 142 | <includes> |
| … |
… |
|
| 155 | 149 | <plugins> |
| 156 | 150 | <plugin> |
| 157 | 151 | <groupId>org.apache.maven.plugins</groupId> |
| 158 | | <artifactId>maven-jar-plugin</artifactId> |
| 159 | | <version>3.4.2</version> |
| 160 | | <configuration> |
| 161 | | <outputDirectory>releases/${project.version}</outputDirectory> |
| 162 | | </configuration> |
| 163 | | </plugin> |
| 164 | | <plugin> |
| 165 | | <groupId>org.apache.maven.plugins</groupId> |
| 166 | | <artifactId>maven-source-plugin</artifactId> |
| 167 | | <version>3.3.1</version> |
| 168 | | <configuration> |
| 169 | | <outputDirectory>releases/${project.version}</outputDirectory> |
| 170 | | </configuration> |
| | 152 | <artifactId>maven-enforcer-plugin</artifactId> |
| | 153 | <version>3.6.3</version> |
| 171 | 154 | <executions> |
| 172 | 155 | <execution> |
| 173 | | <id>attach-sources</id> |
| 174 | | <phase>package</phase> |
| | 156 | <id>enforce</id> |
| 175 | 157 | <goals> |
| 176 | | <goal>jar-no-fork</goal> |
| | 158 | <goal>enforce</goal> |
| 177 | 159 | </goals> |
| | 160 | <configuration> |
| | 161 | <rules> |
| | 162 | <requireMavenVersion> |
| | 163 | <version>3.6.3</version> |
| | 164 | </requireMavenVersion> |
| | 165 | <requireJavaVersion> |
| | 166 | <version>${jmapviewer.buildJdk}</version> |
| | 167 | </requireJavaVersion> |
| | 168 | </rules> |
| | 169 | </configuration> |
| 178 | 170 | </execution> |
| 179 | 171 | </executions> |
| 180 | 172 | </plugin> |
| | 173 | <plugin> |
| | 174 | <groupId>org.apache.maven.plugins</groupId> |
| | 175 | <artifactId>maven-resources-plugin</artifactId> |
| | 176 | <version>3.5.0</version> |
| | 177 | </plugin> |
| 181 | 178 | <plugin> |
| 182 | 179 | <groupId>org.apache.maven.plugins</groupId> |
| 183 | 180 | <artifactId>maven-compiler-plugin</artifactId> |
| 184 | | <version>3.13.0</version> |
| | 181 | <version>3.16.0</version> |
| | 182 | <configuration> |
| | 183 | <compilerArgs> |
| | 184 | <arg>-Xlint:all</arg> |
| | 185 | <arg>-Xlint:-serial</arg> |
| | 186 | </compilerArgs> |
| | 187 | </configuration> |
| 185 | 188 | <executions> |
| 186 | 189 | <execution> |
| 187 | | <id>default-compile</id> |
| | 190 | <id>default-testCompile</id> |
| 188 | 191 | <configuration> |
| 189 | | <release>11</release> |
| | 192 | <!-- The tests live in the same packages as the classes they test, so they run on the classpath --> |
| | 193 | <useModulePath>false</useModulePath> |
| 190 | 194 | </configuration> |
| 191 | 195 | </execution> |
| | 196 | </executions> |
| | 197 | </plugin> |
| | 198 | <plugin> |
| | 199 | <groupId>org.apache.maven.plugins</groupId> |
| | 200 | <artifactId>maven-surefire-plugin</artifactId> |
| | 201 | <version>3.6.0</version> |
| | 202 | <configuration> |
| | 203 | <!-- @{argLine} picks up the JaCoCo agent; the argLine property is empty when JaCoCo is skipped --> |
| | 204 | <argLine>@{argLine} -Dfile.encoding=UTF-8</argLine> |
| | 205 | <useModulePath>false</useModulePath> |
| | 206 | </configuration> |
| | 207 | </plugin> |
| | 208 | <plugin> |
| | 209 | <groupId>org.apache.maven.plugins</groupId> |
| | 210 | <artifactId>maven-jar-plugin</artifactId> |
| | 211 | <version>3.5.1</version> |
| | 212 | <configuration> |
| | 213 | <archive> |
| | 214 | <manifest> |
| | 215 | <!-- Makes the jar runnable, replacing the Ant-only JMapViewer_Demo.jar --> |
| | 216 | <mainClass>${jmapviewer.mainClass}</mainClass> |
| | 217 | </manifest> |
| | 218 | </archive> |
| | 219 | </configuration> |
| | 220 | </plugin> |
| | 221 | <plugin> |
| | 222 | <groupId>org.apache.maven.plugins</groupId> |
| | 223 | <artifactId>maven-source-plugin</artifactId> |
| | 224 | <version>3.4.0</version> |
| | 225 | <executions> |
| 192 | 226 | <execution> |
| 193 | | <id>base-compile</id> |
| | 227 | <id>attach-sources</id> |
| | 228 | <phase>package</phase> |
| 194 | 229 | <goals> |
| 195 | | <goal>compile</goal> |
| | 230 | <goal>jar-no-fork</goal> |
| 196 | 231 | </goals> |
| 197 | | <configuration> |
| 198 | | <release>8</release> |
| 199 | | <excludes> |
| 200 | | <exclude>module-info.java</exclude> |
| 201 | | </excludes> |
| 202 | | </configuration> |
| 203 | 232 | </execution> |
| 204 | 233 | </executions> |
| 205 | 234 | </plugin> |
| | 235 | <plugin> |
| | 236 | <groupId>org.apache.maven.plugins</groupId> |
| | 237 | <artifactId>maven-javadoc-plugin</artifactId> |
| | 238 | <version>3.12.0</version> |
| | 239 | <configuration> |
| | 240 | <show>private</show> |
| | 241 | <linksource>true</linksource> |
| | 242 | <windowtitle>${project.name}</windowtitle> |
| | 243 | <doctitle><h2>${project.name} - Javadoc</h2></doctitle> |
| | 244 | <bottom><a href="https://josm.openstreetmap.de/">${project.name}</a></bottom> |
| | 245 | </configuration> |
| | 246 | </plugin> |
| | 247 | <plugin> |
| | 248 | <groupId>org.apache.maven.plugins</groupId> |
| | 249 | <artifactId>maven-clean-plugin</artifactId> |
| | 250 | <version>3.5.0</version> |
| | 251 | <configuration> |
| | 252 | <!-- The reports that the quality plugins write outside of target/ --> |
| | 253 | <filesets> |
| | 254 | <fileset> |
| | 255 | <directory>${project.basedir}</directory> |
| | 256 | <includes> |
| | 257 | <include>checkstyle-jmapviewer.xml</include> |
| | 258 | <include>spotbugs-jmapviewer.xml</include> |
| | 259 | </includes> |
| | 260 | </fileset> |
| | 261 | </filesets> |
| | 262 | </configuration> |
| | 263 | </plugin> |
| | 264 | <plugin> |
| | 265 | <groupId>org.codehaus.mojo</groupId> |
| | 266 | <artifactId>exec-maven-plugin</artifactId> |
| | 267 | <version>3.6.4</version> |
| | 268 | <configuration> |
| | 269 | <mainClass>${jmapviewer.mainClass}</mainClass> |
| | 270 | </configuration> |
| | 271 | </plugin> |
| | 272 | <plugin> |
| | 273 | <groupId>org.codehaus.mojo</groupId> |
| | 274 | <artifactId>versions-maven-plugin</artifactId> |
| | 275 | <version>2.22.0</version> |
| | 276 | </plugin> |
| 206 | 277 | <!-- Start optional plugins (these can be removed by Linux distributions for building) --> |
| 207 | 278 | <plugin> |
| 208 | 279 | <groupId>org.jacoco</groupId> |
| … |
… |
|
| 214 | 285 | <goals> |
| 215 | 286 | <goal>prepare-agent</goal> |
| 216 | 287 | </goals> |
| | 288 | <configuration> |
| | 289 | <!-- Measure JMapViewer only, not JUnit and the other classes on the test classpath --> |
| | 290 | <includes> |
| | 291 | <include>org.openstreetmap.gui.jmapviewer.*</include> |
| | 292 | </includes> |
| | 293 | </configuration> |
| 217 | 294 | </execution> |
| 218 | 295 | <execution> |
| 219 | 296 | <id>default-report</id> |
| … |
… |
|
| 226 | 303 | <plugin> |
| 227 | 304 | <groupId>com.github.spotbugs</groupId> |
| 228 | 305 | <artifactId>spotbugs-maven-plugin</artifactId> |
| 229 | | <version>4.8.6.2</version> |
| | 306 | <!-- 4.10.4.1 and later require Maven 3.8.9, see maven-enforcer-plugin --> |
| | 307 | <version>4.10.3.0</version> |
| | 308 | <dependencies> |
| | 309 | <dependency> |
| | 310 | <groupId>com.github.spotbugs</groupId> |
| | 311 | <artifactId>spotbugs</artifactId> |
| | 312 | <version>${version.maven.spotbugs}</version> |
| | 313 | </dependency> |
| | 314 | </dependencies> |
| 230 | 315 | <configuration> |
| 231 | 316 | <xmlOutput>true</xmlOutput> |
| | 317 | <spotbugsXmlOutputDirectory>${project.basedir}</spotbugsXmlOutputDirectory> |
| 232 | 318 | <spotbugsXmlOutputFilename>spotbugs-jmapviewer.xml</spotbugsXmlOutputFilename> |
| 233 | 319 | <effort>max</effort> |
| 234 | 320 | </configuration> |
| 235 | | <!-- This is commented out until all the current bugs are fixed. TODO uncomment! |
| 236 | | <executions> |
| 237 | | <execution> |
| 238 | | <id>validate</id> |
| 239 | | <phase>validate</phase> |
| 240 | | <goals> |
| 241 | | <goal>check</goal> |
| 242 | | </goals> |
| 243 | | </execution> |
| 244 | | </executions> |
| 245 | | --> |
| 246 | 321 | </plugin> |
| 247 | 322 | <plugin> |
| 248 | 323 | <groupId>org.apache.maven.plugins</groupId> |
| 249 | 324 | <artifactId>maven-checkstyle-plugin</artifactId> |
| 250 | | <version>3.4.0</version> |
| | 325 | <version>3.6.0</version> |
| 251 | 326 | <configuration> |
| 252 | 327 | <configLocation>${project.basedir}/tools/checkstyle/jmapviewer_checks.xml</configLocation> |
| 253 | 328 | <includeTestSourceDirectory>true</includeTestSourceDirectory> |
| 254 | 329 | <outputFile>${project.basedir}/checkstyle-jmapviewer.xml</outputFile> |
| 255 | | <!-- checkstyle cannot parse module-info.java yet --> |
| 256 | | <excludes>module-info.java</excludes> |
| | 330 | <!-- The checks are declared with severity "warning", so the build has to fail on those --> |
| | 331 | <violationSeverity>warning</violationSeverity> |
| | 332 | <!-- Lets the rules reference the suppressions file the same way under Maven, Ant and Eclipse --> |
| | 333 | <propertyExpansion>config_loc=${project.basedir}/tools/checkstyle</propertyExpansion> |
| 257 | 334 | </configuration> |
| 258 | 335 | <dependencies> |
| 259 | 336 | <dependency> |
| … |
… |
|
| 272 | 349 | </execution> |
| 273 | 350 | </executions> |
| 274 | 351 | </plugin> |
| 275 | | <plugin> |
| 276 | | <groupId>org.apache.maven.plugins</groupId> |
| 277 | | <artifactId>maven-enforcer-plugin</artifactId> |
| 278 | | <version>3.5.0</version> |
| 279 | | <executions> |
| 280 | | <execution> |
| 281 | | <id>enforce-maven</id> |
| 282 | | <goals> |
| 283 | | <goal>enforce</goal> |
| 284 | | </goals> |
| 285 | | <configuration> |
| 286 | | <rules> |
| 287 | | <requireMavenVersion> |
| 288 | | <version>3.6.3</version> |
| 289 | | </requireMavenVersion> |
| 290 | | </rules> |
| 291 | | </configuration> |
| 292 | | </execution> |
| 293 | | </executions> |
| 294 | | </plugin> |
| | 352 | <!-- End optional plugins --> |
| 295 | 353 | </plugins> |
| 296 | 354 | </build> |
| 297 | 355 | |
| | 356 | <profiles> |
| | 357 | <!-- Builds the release zips below releases/, like the Ant "create_*_release_zip" targets --> |
| | 358 | <profile> |
| | 359 | <id>release</id> |
| | 360 | <build> |
| | 361 | <plugins> |
| | 362 | <plugin> |
| | 363 | <groupId>org.apache.maven.plugins</groupId> |
| | 364 | <artifactId>maven-assembly-plugin</artifactId> |
| | 365 | <version>3.8.0</version> |
| | 366 | <configuration> |
| | 367 | <outputDirectory>${project.basedir}/releases/${project.version}</outputDirectory> |
| | 368 | <attach>false</attach> |
| | 369 | </configuration> |
| | 370 | <executions> |
| | 371 | <execution> |
| | 372 | <id>release-zip</id> |
| | 373 | <phase>package</phase> |
| | 374 | <goals> |
| | 375 | <goal>single</goal> |
| | 376 | </goals> |
| | 377 | <configuration> |
| | 378 | <appendAssemblyId>false</appendAssemblyId> |
| | 379 | <descriptors> |
| | 380 | <descriptor>${project.basedir}/tools/assembly/release.xml</descriptor> |
| | 381 | </descriptors> |
| | 382 | </configuration> |
| | 383 | </execution> |
| | 384 | <execution> |
| | 385 | <id>source-release-zip</id> |
| | 386 | <phase>package</phase> |
| | 387 | <goals> |
| | 388 | <goal>single</goal> |
| | 389 | </goals> |
| | 390 | <configuration> |
| | 391 | <descriptors> |
| | 392 | <descriptor>${project.basedir}/tools/assembly/source-release.xml</descriptor> |
| | 393 | </descriptors> |
| | 394 | </configuration> |
| | 395 | </execution> |
| | 396 | </executions> |
| | 397 | </plugin> |
| | 398 | </plugins> |
| | 399 | </build> |
| | 400 | </profile> |
| | 401 | </profiles> |
| | 402 | |
| 298 | 403 | <reporting> |
| 299 | 404 | <plugins> |
| 300 | 405 | <plugin> |
| 301 | 406 | <groupId>org.apache.maven.plugins</groupId> |
| 302 | 407 | <artifactId>maven-surefire-report-plugin</artifactId> |
| 303 | | <version>3.3.1</version> |
| | 408 | <version>3.6.0</version> |
| 304 | 409 | </plugin> |
| 305 | 410 | <plugin> |
| 306 | 411 | <groupId>org.jacoco</groupId> |
-
diff --git src/module-info.java src/module-info.java
index f116957..2d95f0a 100644
|
|
|
|
| 1 | 1 | // License: GPL. For details, see Readme.txt file. |
| 2 | 2 | module org.openstreetmap.gui.jmapviewer { |
| 3 | | requires java.desktop; |
| 4 | | requires java.logging; |
| | 3 | // java.desktop and java.logging types are part of the public API (JMapViewer is a JPanel, FeatureAdapter returns loggers) |
| | 4 | requires transitive java.desktop; |
| | 5 | requires transitive java.logging; |
| 5 | 6 | exports org.openstreetmap.gui.jmapviewer; |
| 6 | 7 | exports org.openstreetmap.gui.jmapviewer.checkBoxTree; |
| 7 | 8 | exports org.openstreetmap.gui.jmapviewer.events; |
-
diff --git src/org/openstreetmap/gui/jmapviewer/AbstractLayer.java src/org/openstreetmap/gui/jmapviewer/AbstractLayer.java
index 4e5216e..57fd3db 100644
|
|
|
public class AbstractLayer {
|
| 36 | 36 | this(parent, name, null, style); |
| 37 | 37 | } |
| 38 | 38 | |
| | 39 | @SuppressWarnings("this-escape") |
| 39 | 40 | public AbstractLayer(LayerGroup parent, String name, String description, Style style) { |
| 40 | 41 | setParent(parent); |
| 41 | 42 | setName(name); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java
index 9d67ae6..4e003c7 100644
|
|
|
import java.awt.Rectangle;
|
| 12 | 12 | import java.awt.font.TextAttribute; |
| 13 | 13 | import java.awt.geom.Rectangle2D; |
| 14 | 14 | import java.awt.image.ImageObserver; |
| 15 | | import java.util.HashMap; |
| 16 | 15 | import java.util.Map; |
| 17 | 16 | |
| 18 | 17 | import org.openstreetmap.gui.jmapviewer.interfaces.Attributed; |
| 19 | 18 | import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; |
| 20 | 19 | |
| | 20 | /** |
| | 21 | * Paints the attribution of a tile source onto the map and handles clicks on it. |
| | 22 | */ |
| 21 | 23 | public class AttributionSupport { |
| 22 | 24 | public static final Font ATTR_FONT = new Font("Arial", Font.PLAIN, 10); |
| 23 | | public static final Font ATTR_LINK_FONT; |
| | 25 | public static final Font ATTR_LINK_FONT = ATTR_FONT.deriveFont(Map.of(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON)); |
| 24 | 26 | private static final int PADDING = 5; |
| 25 | 27 | |
| 26 | 28 | private Attributed source; |
| … |
… |
public class AttributionSupport {
|
| 33 | 35 | protected Rectangle attrToUBounds; |
| 34 | 36 | protected Rectangle attrImageBounds; |
| 35 | 37 | |
| 36 | | static { |
| 37 | | Map<TextAttribute, Integer> aUnderline = new HashMap<>(); |
| 38 | | aUnderline.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); |
| 39 | | ATTR_LINK_FONT = ATTR_FONT.deriveFont(aUnderline); |
| | 38 | /** |
| | 39 | * Constructs a new {@code AttributionSupport}, to be initialized with {@link #initialize(Attributed)}. |
| | 40 | */ |
| | 41 | public AttributionSupport() { |
| | 42 | // Nothing to do |
| 40 | 43 | } |
| 41 | 44 | |
| 42 | 45 | public void initialize(Attributed source) { |
| 43 | 46 | this.source = source; |
| 44 | | boolean requireAttr = source.requiresAttribution(); |
| 45 | | if (requireAttr) { |
| | 47 | if (source.requiresAttribution()) { |
| 46 | 48 | attrImage = source.getAttributionImage(); |
| 47 | 49 | attrTermsText = source.getTermsOfUseText(); |
| 48 | 50 | attrTermsUrl = source.getTermsOfUseURL(); |
| … |
… |
public class AttributionSupport {
|
| 51 | 53 | } |
| 52 | 54 | } else { |
| 53 | 55 | attrImage = null; |
| | 56 | attrTermsText = null; |
| 54 | 57 | attrTermsUrl = null; |
| 55 | 58 | } |
| 56 | 59 | } |
| … |
… |
public class AttributionSupport {
|
| 75 | 78 | |
| 76 | 79 | if (attrTermsText != null) { |
| 77 | 80 | Rectangle2D termsStringBounds = g.getFontMetrics().getStringBounds(attrTermsText, g); |
| 78 | | int textRealHeight = (int) termsStringBounds.getHeight(); |
| 79 | | termsTextHeight = textRealHeight; |
| | 81 | termsTextHeight = (int) termsStringBounds.getHeight(); |
| 80 | 82 | int termsTextWidth = (int) termsStringBounds.getWidth(); |
| 81 | | attrToUBounds = new Rectangle(PADDING, textY - termsTextHeight + fontDescent, termsTextWidth, textRealHeight); |
| | 83 | attrToUBounds = new Rectangle(PADDING, textY - termsTextHeight + fontDescent, termsTextWidth, termsTextHeight); |
| 82 | 84 | drawShadedText(g, attrTermsText, PADDING, textY); |
| 83 | 85 | } else { |
| 84 | 86 | attrToUBounds = null; |
| … |
… |
public class AttributionSupport {
|
| 90 | 92 | int imgHeight = attrImage.getHeight(observer); |
| 91 | 93 | int y = textY - imgHeight - termsTextHeight; |
| 92 | 94 | attrImageBounds = new Rectangle(PADDING, y, imgWidth, imgHeight); |
| 93 | | g.drawImage(attrImage, PADDING, y, null); |
| | 95 | g.drawImage(attrImage, PADDING, y, observer); |
| 94 | 96 | } else { |
| 95 | 97 | attrImageBounds = null; |
| 96 | 98 | } |
| … |
… |
public class AttributionSupport {
|
| 139 | 141 | } |
| 140 | 142 | |
| 141 | 143 | public boolean handleAttribution(Point p, boolean click) { |
| 142 | | if (source == null || !source.requiresAttribution()) |
| | 144 | if (p == null || source == null || !source.requiresAttribution()) |
| 143 | 145 | return false; |
| 144 | 146 | |
| 145 | 147 | if (attrTextBounds != null && attrTextBounds.contains(p)) { |
| … |
… |
public class AttributionSupport {
|
| 154 | 156 | String attributionImageURL = source.getAttributionImageURL(); |
| 155 | 157 | if (attributionImageURL != null) { |
| 156 | 158 | if (click) { |
| 157 | | FeatureAdapter.openLink(source.getAttributionImageURL()); |
| | 159 | FeatureAdapter.openLink(attributionImageURL); |
| 158 | 160 | } |
| 159 | 161 | return true; |
| 160 | 162 | } |
| … |
… |
public class AttributionSupport {
|
| 169 | 171 | } |
| 170 | 172 | return false; |
| 171 | 173 | } |
| 172 | | |
| 173 | 174 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/Coordinate.java src/org/openstreetmap/gui/jmapviewer/Coordinate.java
index 3c9c2e2..ea6c6fb 100644
|
|
|
import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
|
| 13 | 13 | * A geographical coordinate consisting of latitude and longitude. |
| 14 | 14 | * |
| 15 | 15 | * @author Jan Peter Stotz |
| 16 | | * |
| 17 | 16 | */ |
| 18 | 17 | public class Coordinate implements ICoordinate, Serializable { |
| | 18 | // Java 14: annotate with @Serial |
| 19 | 19 | private static final long serialVersionUID = 1L; |
| 20 | 20 | private double x; |
| 21 | 21 | private double y; |
| … |
… |
public class Coordinate implements ICoordinate, Serializable {
|
| 25 | 25 | * @param lat latitude in degrees |
| 26 | 26 | * @param lon longitude in degrees |
| 27 | 27 | */ |
| | 28 | @SuppressWarnings("this-escape") |
| 28 | 29 | public Coordinate(double lat, double lon) { |
| 29 | 30 | setLat(lat); |
| 30 | 31 | setLon(lon); |
| … |
… |
public class Coordinate implements ICoordinate, Serializable {
|
| 50 | 51 | x = lon; |
| 51 | 52 | } |
| 52 | 53 | |
| | 54 | // Java 14: annotate with @Serial |
| 53 | 55 | private void writeObject(ObjectOutputStream out) throws IOException { |
| 54 | 56 | out.writeObject(x); |
| 55 | 57 | out.writeObject(y); |
| 56 | 58 | } |
| 57 | 59 | |
| | 60 | // Java 14: annotate with @Serial |
| 58 | 61 | private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { |
| 59 | 62 | x = (Double) in.readObject(); |
| 60 | 63 | y = (Double) in.readObject(); |
| … |
… |
public class Coordinate implements ICoordinate, Serializable {
|
| 73 | 76 | @Override |
| 74 | 77 | public boolean equals(Object o) { |
| 75 | 78 | if (this == o) return true; |
| 76 | | if (o == null || !this.getClass().equals(o.getClass())) return false; |
| | 79 | if (o == null || !getClass().equals(o.getClass())) return false; |
| 77 | 80 | Coordinate that = (Coordinate) o; |
| 78 | 81 | return Double.compare(that.x, x) == 0 && Double.compare(that.y, y) == 0; |
| 79 | 82 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java
index ae79b0d..4fc9207 100644
|
|
|
import java.util.Locale;
|
| 14 | 14 | * mouse button and zooming by double click or by mouse wheel. |
| 15 | 15 | * |
| 16 | 16 | * @author Jan Peter Stotz |
| 17 | | * |
| 18 | 17 | */ |
| 19 | 18 | public class DefaultMapController extends JMapController implements MouseListener, MouseMotionListener, |
| 20 | | MouseWheelListener { |
| | 19 | MouseWheelListener { |
| 21 | 20 | |
| 22 | 21 | private static final int MOUSE_BUTTONS_MASK = MouseEvent.BUTTON3_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK |
| 23 | | | MouseEvent.BUTTON2_DOWN_MASK; |
| | 22 | | MouseEvent.BUTTON2_DOWN_MASK; |
| 24 | 23 | |
| 25 | 24 | private static final int MAC_MOUSE_BUTTON3_MASK = MouseEvent.CTRL_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK; |
| 26 | 25 | |
| … |
… |
MouseWheelListener {
|
| 51 | 50 | // Is only the selected mouse button pressed? |
| 52 | 51 | if ((e.getModifiersEx() & MOUSE_BUTTONS_MASK) == movementMouseButtonMask |
| 53 | 52 | || (isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK)) { |
| 54 | | Point p = e.getPoint(); |
| 55 | | if (lastDragPoint != null) { |
| 56 | | int diffx = lastDragPoint.x - p.x; |
| 57 | | int diffy = lastDragPoint.y - p.y; |
| 58 | | map.moveMap(diffx, diffy); |
| 59 | | } |
| 60 | | lastDragPoint = p; |
| | 53 | dragTo(e.getPoint()); |
| | 54 | } |
| | 55 | } |
| | 56 | |
| | 57 | /** |
| | 58 | * Moves the map by the distance from the previous drag point to {@code p}. |
| | 59 | * @param p the current mouse position |
| | 60 | */ |
| | 61 | private void dragTo(Point p) { |
| | 62 | if (lastDragPoint != null) { |
| | 63 | map.moveMap(lastDragPoint.x - p.x, lastDragPoint.y - p.y); |
| 61 | 64 | } |
| | 65 | lastDragPoint = p; |
| 62 | 66 | } |
| 63 | 67 | |
| 64 | 68 | @Override |
| … |
… |
MouseWheelListener {
|
| 125 | 129 | */ |
| 126 | 130 | public void setMovementMouseButton(int movementMouseButton) { |
| 127 | 131 | this.movementMouseButton = movementMouseButton; |
| | 132 | // Java 14: use a switch expression |
| 128 | 133 | switch (movementMouseButton) { |
| 129 | 134 | case MouseEvent.BUTTON1: |
| 130 | 135 | movementMouseButtonMask = MouseEvent.BUTTON1_DOWN_MASK; |
| … |
… |
MouseWheelListener {
|
| 168 | 173 | |
| 169 | 174 | @Override |
| 170 | 175 | public void mouseMoved(MouseEvent e) { |
| 171 | | // Mac OSX simulates with ctrl + mouse 1 the second mouse button hence no dragging events get fired. |
| 172 | | // |
| | 176 | // Mac OSX simulates the second mouse button with ctrl + mouse 1, hence no dragging events get fired. |
| 173 | 177 | if (isPlatformOsx()) { |
| 174 | 178 | if (!movementEnabled || !isMoving) |
| 175 | 179 | return; |
| 176 | 180 | // Is only the selected mouse button pressed? |
| 177 | 181 | if (e.getModifiersEx() == MouseEvent.CTRL_DOWN_MASK) { |
| 178 | | Point p = e.getPoint(); |
| 179 | | if (lastDragPoint != null) { |
| 180 | | int diffx = lastDragPoint.x - p.x; |
| 181 | | int diffy = lastDragPoint.y - p.y; |
| 182 | | map.moveMap(diffx, diffy); |
| 183 | | } |
| 184 | | lastDragPoint = p; |
| | 182 | dragTo(e.getPoint()); |
| 185 | 183 | } |
| 186 | 184 | } |
| 187 | 185 | } |
| 188 | 186 | |
| 189 | 187 | /** |
| 190 | | * Replies true if we are currently running on OSX |
| | 188 | * Determines whether we are currently running on OSX. |
| 191 | 189 | * |
| 192 | 190 | * @return true if we are currently running on OSX |
| 193 | 191 | */ |
-
diff --git src/org/openstreetmap/gui/jmapviewer/Demo.java src/org/openstreetmap/gui/jmapviewer/Demo.java
index 551005b..b3d1917 100644
|
|
|
import javax.swing.JComboBox;
|
| 13 | 13 | import javax.swing.JFrame; |
| 14 | 14 | import javax.swing.JLabel; |
| 15 | 15 | import javax.swing.JPanel; |
| | 16 | import javax.swing.SwingUtilities; |
| 16 | 17 | |
| 17 | 18 | import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent; |
| 18 | 19 | import org.openstreetmap.gui.jmapviewer.interfaces.JMapViewerEventListener; |
| … |
… |
import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource;
|
| 26 | 27 | * Demonstrates the usage of {@link JMapViewer} |
| 27 | 28 | * |
| 28 | 29 | * @author Jan Peter Stotz |
| 29 | | * |
| 30 | 30 | */ |
| 31 | | public class Demo extends JFrame implements JMapViewerEventListener { |
| | 31 | public final class Demo extends JFrame implements JMapViewerEventListener { |
| 32 | 32 | |
| | 33 | // Java 14: annotate with @Serial |
| 33 | 34 | private static final long serialVersionUID = 1L; |
| 34 | 35 | |
| 35 | 36 | private final JMapViewerTree treeMap; |
| … |
… |
public class Demo extends JFrame implements JMapViewerEventListener {
|
| 62 | 63 | JPanel helpPanel = new JPanel(); |
| 63 | 64 | |
| 64 | 65 | mperpLabelName = new JLabel("Meters/Pixels: "); |
| 65 | | mperpLabelValue = new JLabel(String.format("%s", map().getMeterPerPixel())); |
| | 66 | mperpLabelValue = new JLabel(String.valueOf(map().getMeterPerPixel())); |
| 66 | 67 | |
| 67 | 68 | zoomLabel = new JLabel("Zoom: "); |
| 68 | | zoomValue = new JLabel(String.format("%s", map().getZoom())); |
| | 69 | zoomValue = new JLabel(String.valueOf(map().getZoom())); |
| 69 | 70 | |
| 70 | 71 | add(panel, BorderLayout.NORTH); |
| 71 | 72 | add(helpPanel, BorderLayout.SOUTH); |
| 72 | 73 | panel.add(panelTop, BorderLayout.NORTH); |
| 73 | 74 | panel.add(panelBottom, BorderLayout.SOUTH); |
| 74 | | JLabel helpLabel = new JLabel("Use right mouse button to move,\n " |
| 75 | | + "left double click or mouse wheel to zoom."); |
| | 75 | JLabel helpLabel = new JLabel("Use right mouse button to move, left double click or mouse wheel to zoom."); |
| 76 | 76 | helpPanel.add(helpLabel); |
| 77 | 77 | JButton button = new JButton("setDisplayToFitMapMarkers"); |
| 78 | 78 | button.addActionListener(e -> map().setDisplayToFitMapMarkers()); |
| … |
… |
public class Demo extends JFrame implements JMapViewerEventListener {
|
| 82 | 82 | new BingAerialTileSource(), |
| 83 | 83 | }); |
| 84 | 84 | tileSourceSelector.addItemListener(e -> map().setTileSource((TileSource) e.getItem())); |
| 85 | | JComboBox<TileLoader> tileLoaderSelector; |
| 86 | | tileLoaderSelector = new JComboBox<>(new TileLoader[] {new OsmTileLoader(map())}); |
| | 85 | JComboBox<TileLoader> tileLoaderSelector = new JComboBox<>(new TileLoader[] {new OsmTileLoader(map())}); |
| 87 | 86 | tileLoaderSelector.addItemListener(e -> map().setTileLoader((TileLoader) e.getItem())); |
| 88 | 87 | map().setTileLoader((TileLoader) tileLoaderSelector.getSelectedItem()); |
| 89 | 88 | panelTop.add(tileSourceSelector); |
| … |
… |
public class Demo extends JFrame implements JMapViewerEventListener {
|
| 92 | 91 | showMapMarker.setSelected(map().getMapMarkersVisible()); |
| 93 | 92 | showMapMarker.addActionListener(e -> map().setMapMarkerVisible(showMapMarker.isSelected())); |
| 94 | 93 | panelBottom.add(showMapMarker); |
| 95 | | /// |
| 96 | 94 | final JCheckBox showTreeLayers = new JCheckBox("Tree Layers visible"); |
| 97 | 95 | showTreeLayers.addActionListener(e -> treeMap.setTreeVisible(showTreeLayers.isSelected())); |
| 98 | 96 | panelBottom.add(showTreeLayers); |
| 99 | | /// |
| 100 | 97 | final JCheckBox showToolTip = new JCheckBox("ToolTip visible"); |
| 101 | 98 | showToolTip.addActionListener(e -> map().setToolTipText(null)); |
| 102 | 99 | panelBottom.add(showToolTip); |
| 103 | | /// |
| 104 | 100 | final JCheckBox showTileGrid = new JCheckBox("Tile grid visible"); |
| 105 | 101 | showTileGrid.setSelected(map().isTileGridVisible()); |
| 106 | 102 | showTileGrid.addActionListener(e -> map().setTileGridVisible(showTileGrid.isSelected())); |
| … |
… |
public class Demo extends JFrame implements JMapViewerEventListener {
|
| 121 | 117 | |
| 122 | 118 | add(treeMap, BorderLayout.CENTER); |
| 123 | 119 | |
| 124 | | // |
| 125 | 120 | LayerGroup germanyGroup = new LayerGroup("Germany"); |
| 126 | 121 | Layer germanyWestLayer = germanyGroup.addLayer("Germany West"); |
| 127 | 122 | Layer germanyEastLayer = germanyGroup.addLayer("Germany East"); |
| … |
… |
public class Demo extends JFrame implements JMapViewerEventListener {
|
| 153 | 148 | Layer wales = treeMap.addLayer("UK"); |
| 154 | 149 | map().addMapRectangle(new MapRectangleImpl(wales, "Wales", c(53.35, -4.57), c(51.64, -2.63))); |
| 155 | 150 | |
| 156 | | // map.setDisplayPosition(new Coordinate(49.807, 8.6), 11); |
| 157 | | // map.setTileGridVisible(true); |
| 158 | | |
| 159 | 151 | map().addMouseListener(new MouseAdapter() { |
| 160 | 152 | @Override |
| 161 | 153 | public void mouseClicked(MouseEvent e) { |
| … |
… |
public class Demo extends JFrame implements JMapViewerEventListener {
|
| 170 | 162 | public void mouseMoved(MouseEvent e) { |
| 171 | 163 | Point p = e.getPoint(); |
| 172 | 164 | boolean cursorHand = map().getAttribution().handleAttributionCursor(p); |
| 173 | | if (cursorHand) { |
| 174 | | map().setCursor(new Cursor(Cursor.HAND_CURSOR)); |
| 175 | | } else { |
| 176 | | map().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); |
| 177 | | } |
| | 165 | map().setCursor(Cursor.getPredefinedCursor(cursorHand ? Cursor.HAND_CURSOR : Cursor.DEFAULT_CURSOR)); |
| 178 | 166 | if (showToolTip.isSelected()) map().setToolTipText(map().getPosition(p).toString()); |
| 179 | 167 | } |
| 180 | 168 | }); |
| … |
… |
public class Demo extends JFrame implements JMapViewerEventListener {
|
| 192 | 180 | * @param args Main program arguments |
| 193 | 181 | */ |
| 194 | 182 | public static void main(String[] args) { |
| 195 | | new Demo().setVisible(true); |
| | 183 | SwingUtilities.invokeLater(() -> new Demo().setVisible(true)); |
| 196 | 184 | } |
| 197 | 185 | |
| 198 | 186 | private void updateZoomParameters() { |
| | 187 | // the map fires events while the constructor is still running, before the labels exist |
| 199 | 188 | if (mperpLabelValue != null) |
| 200 | | mperpLabelValue.setText(String.format("%s", map().getMeterPerPixel())); |
| | 189 | mperpLabelValue.setText(String.valueOf(map().getMeterPerPixel())); |
| 201 | 190 | if (zoomValue != null) |
| 202 | | zoomValue.setText(String.format("%s", map().getZoom())); |
| | 191 | zoomValue.setText(String.valueOf(map().getZoom())); |
| 203 | 192 | } |
| 204 | 193 | |
| 205 | 194 | @Override |
| 206 | 195 | public void processCommand(JMVCommandEvent command) { |
| 207 | | if (command.getCommand().equals(JMVCommandEvent.COMMAND.ZOOM) || |
| 208 | | command.getCommand().equals(JMVCommandEvent.COMMAND.MOVE)) { |
| | 196 | if (command.getCommand() == JMVCommandEvent.COMMAND.ZOOM || command.getCommand() == JMVCommandEvent.COMMAND.MOVE) { |
| 209 | 197 | updateZoomParameters(); |
| 210 | 198 | } |
| 211 | 199 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java
index 44650a3..b820917 100644
|
|
|
public final class FeatureAdapter {
|
| 61 | 61 | /** |
| 62 | 62 | * Translation support. |
| 63 | 63 | */ |
| | 64 | @FunctionalInterface |
| 64 | 65 | public interface TranslationAdapter { |
| 65 | 66 | /** |
| 66 | 67 | * Translates some text for the current locale. |
| … |
… |
public final class FeatureAdapter {
|
| 76 | 77 | * @return the translated string. |
| 77 | 78 | */ |
| 78 | 79 | String tr(String text, Object... objects); |
| 79 | | // TODO: more i18n functions |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | 82 | /** |
| … |
… |
public final class FeatureAdapter {
|
| 217 | 217 | |
| 218 | 218 | /** |
| 219 | 219 | * Reads an image using the current {@link ImageAdapter}. |
| 220 | | * @param url image URI to read |
| | 220 | * @param uri image URI to read |
| 221 | 221 | * @return a <code>BufferedImage</code> containing the decoded contents of the input, or <code>null</code>. |
| 222 | 222 | * @throws java.net.MalformedURLException if the URI could not be converted to a URL |
| 223 | 223 | * @throws IOException if an error occurs during reading. |
| 224 | 224 | */ |
| 225 | | public static BufferedImage readImage(URI url) throws IOException { |
| 226 | | return imageAdapter.read(url.toURL(), false, false); |
| | 225 | public static BufferedImage readImage(URI uri) throws IOException { |
| | 226 | return imageAdapter.read(uri.toURL(), false, false); |
| 227 | 227 | } |
| 228 | 228 | |
| 229 | 229 | /** |
| … |
… |
public final class FeatureAdapter {
|
| 270 | 270 | } |
| 271 | 271 | |
| 272 | 272 | /** |
| 273 | | * Get settings value for a certain key and provide a default value. |
| | 273 | * Get the integer settings value for a certain key and provide a default value. |
| 274 | 274 | * @param key the identifier for the setting |
| 275 | 275 | * @param def the default value. For each call of get() with a given key, the |
| 276 | | * default value must be the same. {@code def} may be null. |
| | 276 | * default value must be the same. |
| 277 | 277 | * @return the corresponding value if the property has been set before, {@code def} otherwise |
| | 278 | * @throws NumberFormatException if the value that has been set is not an integer |
| 278 | 279 | */ |
| 279 | 280 | public static int getIntSetting(String key, int def) { |
| 280 | 281 | return Integer.parseInt(settingsAdapter.get(key, Integer.toString(def))); |
| … |
… |
public final class FeatureAdapter {
|
| 294 | 295 | * Default API key support that relies on system property named {@code <imageryId>.api-key}. |
| 295 | 296 | */ |
| 296 | 297 | public static class DefaultApiKeyAdapter implements ApiKeyAdapter { |
| | 298 | /** |
| | 299 | * Constructs a new {@code DefaultApiKeyAdapter}. |
| | 300 | */ |
| | 301 | public DefaultApiKeyAdapter() { |
| | 302 | // Nothing to do |
| | 303 | } |
| | 304 | |
| 297 | 305 | @Override |
| 298 | 306 | public String retrieveApiKey(String imageryId) { |
| 299 | 307 | return System.getProperty(imageryId + ".api-key"); |
| … |
… |
public final class FeatureAdapter {
|
| 304 | 312 | * Default browser support that relies on Java Desktop API. |
| 305 | 313 | */ |
| 306 | 314 | public static class DefaultBrowserAdapter implements BrowserAdapter { |
| | 315 | /** |
| | 316 | * Constructs a new {@code DefaultBrowserAdapter}. |
| | 317 | */ |
| | 318 | public DefaultBrowserAdapter() { |
| | 319 | // Nothing to do |
| | 320 | } |
| | 321 | |
| 307 | 322 | @Override |
| 308 | 323 | public void openLink(String url) { |
| 309 | 324 | if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { |
| … |
… |
public final class FeatureAdapter {
|
| 322 | 337 | * Default image support that relies on Java Image IO API. |
| 323 | 338 | */ |
| 324 | 339 | public static class DefaultImageAdapter implements ImageAdapter { |
| | 340 | /** |
| | 341 | * Constructs a new {@code DefaultImageAdapter}. |
| | 342 | */ |
| | 343 | public DefaultImageAdapter() { |
| | 344 | // Nothing to do |
| | 345 | } |
| | 346 | |
| 325 | 347 | @Override |
| 326 | 348 | public BufferedImage read(URL input, boolean readMetadata, boolean enforceTransparency) throws IOException { |
| 327 | 349 | return ImageIO.read(input); |
| … |
… |
public final class FeatureAdapter {
|
| 329 | 351 | } |
| 330 | 352 | |
| 331 | 353 | /** |
| 332 | | * Default "translation" support that do not really translates strings, but only takes care of formatting arguments. |
| | 354 | * Default "translation" support that does not really translate strings, but only takes care of formatting arguments. |
| 333 | 355 | */ |
| 334 | 356 | public static class DefaultTranslationAdapter implements TranslationAdapter { |
| | 357 | /** |
| | 358 | * Constructs a new {@code DefaultTranslationAdapter}. |
| | 359 | */ |
| | 360 | public DefaultTranslationAdapter() { |
| | 361 | // Nothing to do |
| | 362 | } |
| | 363 | |
| 335 | 364 | @Override |
| 336 | 365 | public String tr(String text, Object... objects) { |
| 337 | 366 | return MessageFormat.format(text, objects); |
| … |
… |
public final class FeatureAdapter {
|
| 342 | 371 | * Default logging support that relies on Java Logging API. |
| 343 | 372 | */ |
| 344 | 373 | public static class DefaultLoggingAdapter implements LoggingAdapter { |
| | 374 | /** |
| | 375 | * Constructs a new {@code DefaultLoggingAdapter}. |
| | 376 | */ |
| | 377 | public DefaultLoggingAdapter() { |
| | 378 | // Nothing to do |
| | 379 | } |
| | 380 | |
| 345 | 381 | @Override |
| 346 | 382 | public Logger getLogger(String name) { |
| 347 | 383 | return Logger.getLogger(name); |
| … |
… |
public final class FeatureAdapter {
|
| 354 | 390 | public static class DefaultSettingsAdapter implements SettingsAdapter { |
| 355 | 391 | private final Map<String, String> settings = new TreeMap<>(); |
| 356 | 392 | |
| | 393 | /** |
| | 394 | * Constructs a new {@code DefaultSettingsAdapter}. |
| | 395 | */ |
| | 396 | public DefaultSettingsAdapter() { |
| | 397 | // Nothing to do |
| | 398 | } |
| | 399 | |
| 357 | 400 | @Override |
| 358 | 401 | public String get(String key, String def) { |
| 359 | 402 | return settings.getOrDefault(key, def); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/JMapController.java src/org/openstreetmap/gui/jmapviewer/JMapController.java
index 8de5300..76d5c91 100644
|
|
|
public abstract class JMapController {
|
| 21 | 21 | |
| 22 | 22 | protected JMapViewer map; |
| 23 | 23 | |
| 24 | | public JMapController(JMapViewer map) { |
| | 24 | /** |
| | 25 | * Constructs a new {@code JMapController} and registers it as listener of the map, |
| | 26 | * for each of the listener interfaces that it implements. |
| | 27 | * @param map the map to control |
| | 28 | */ |
| | 29 | @SuppressWarnings("this-escape") |
| | 30 | protected JMapController(JMapViewer map) { |
| 25 | 31 | this.map = map; |
| | 32 | // Java 16: use instanceof pattern matching instead of the casts |
| 26 | 33 | if (this instanceof MouseListener) |
| 27 | 34 | map.addMouseListener((MouseListener) this); |
| 28 | 35 | if (this instanceof MouseWheelListener) |
| … |
… |
public abstract class JMapController {
|
| 30 | 37 | if (this instanceof MouseMotionListener) |
| 31 | 38 | map.addMouseMotionListener((MouseMotionListener) this); |
| 32 | 39 | } |
| 33 | | |
| 34 | 40 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/JMapViewer.java src/org/openstreetmap/gui/jmapviewer/JMapViewer.java
index d998d03..3411279 100644
|
|
|
import java.awt.Font;
|
| 6 | 6 | import java.awt.Graphics; |
| 7 | 7 | import java.awt.Insets; |
| 8 | 8 | import java.awt.Point; |
| 9 | | import java.awt.event.MouseEvent; |
| 10 | 9 | import java.io.IOException; |
| 11 | 10 | import java.net.URL; |
| 12 | 11 | import java.util.ArrayList; |
| … |
… |
import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource;
|
| 42 | 41 | */ |
| 43 | 42 | public class JMapViewer extends JPanel implements TileLoaderListener { |
| 44 | 43 | |
| | 44 | // Java 14: annotate with @Serial |
| 45 | 45 | private static final long serialVersionUID = 1L; |
| 46 | 46 | |
| 47 | 47 | /** whether debug mode is enabled or not */ |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 53 | 53 | /** |
| 54 | 54 | * Vectors for clock-wise tile painting |
| 55 | 55 | */ |
| 56 | | private static final Point[] move = {new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1)}; |
| | 56 | private static final Point[] MOVE = {new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1)}; |
| 57 | 57 | |
| 58 | 58 | /** Maximum zoom level */ |
| 59 | 59 | public static final int MAX_ZOOM = 24; |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 110 | 110 | * Creates a standard {@link JMapViewer} instance that can be controlled via |
| 111 | 111 | * mouse: hold right mouse button for moving, double click left mouse button |
| 112 | 112 | * or use mouse wheel for zooming. Loaded tiles are stored in a |
| 113 | | * {@link MemoryTileCache} and the tile loader uses 4 parallel threads for |
| 114 | | * retrieving the tiles. |
| | 113 | * {@link MemoryTileCache} and retrieved by an {@link OsmTileLoader}. |
| 115 | 114 | */ |
| | 115 | @SuppressWarnings("this-escape") |
| 116 | 116 | public JMapViewer() { |
| 117 | 117 | this(new MemoryTileCache()); |
| 118 | 118 | new DefaultMapController(this); |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 121 | 121 | /** |
| 122 | 122 | * Creates a new {@link JMapViewer} instance. |
| 123 | 123 | * @param tileCache The cache where to store tiles |
| 124 | | * @param downloadThreadCount not used anymore |
| 125 | | * @deprecated use {@link #JMapViewer(TileCache)} |
| 126 | | */ |
| 127 | | @Deprecated |
| 128 | | public JMapViewer(TileCache tileCache, int downloadThreadCount) { |
| 129 | | this(tileCache); |
| 130 | | } |
| 131 | | |
| 132 | | /** |
| 133 | | * Creates a new {@link JMapViewer} instance. |
| 134 | | * @param tileCache The cache where to store tiles |
| 135 | | * |
| 136 | 124 | */ |
| | 125 | @SuppressWarnings("this-escape") |
| 137 | 126 | public JMapViewer(TileCache tileCache) { |
| 138 | 127 | tileSource = new OsmTileSource.Mapnik(); |
| 139 | 128 | tileController = new TileController(tileSource, tileCache, this); |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 151 | 140 | setDisplayPosition(new Coordinate(50, 9), 3); |
| 152 | 141 | } |
| 153 | 142 | |
| 154 | | @Override |
| 155 | | public String getToolTipText(MouseEvent event) { |
| 156 | | return super.getToolTipText(event); |
| 157 | | } |
| 158 | | |
| 159 | 143 | protected void initializeZoomSlider() { |
| 160 | 144 | zoomSlider = new JSlider(MIN_ZOOM, tileController.getTileSource().getMaxZoom()); |
| 161 | 145 | zoomSlider.setOrientation(JSlider.VERTICAL); |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 309 | 293 | |
| 310 | 294 | if (markers && mapMarkerList != null) { |
| 311 | 295 | synchronized (this) { |
| 312 | | for (MapMarker marker : mapMarkerList) { |
| | 296 | for (MapMarker marker : snapshot(mapMarkerList)) { |
| 313 | 297 | if (marker.isVisible()) { |
| 314 | 298 | Point p = tileSource.latLonToXY(marker.getCoordinate(), mapZoomMax); |
| 315 | 299 | xMax = Math.max(xMax, p.x); |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 323 | 307 | |
| 324 | 308 | if (rectangles && mapRectangleList != null) { |
| 325 | 309 | synchronized (this) { |
| 326 | | for (MapRectangle rectangle : mapRectangleList) { |
| | 310 | for (MapRectangle rectangle : snapshot(mapRectangleList)) { |
| 327 | 311 | if (rectangle.isVisible()) { |
| 328 | 312 | Point bottomRight = tileSource.latLonToXY(rectangle.getBottomRight(), mapZoomMax); |
| 329 | 313 | Point topLeft = tileSource.latLonToXY(rectangle.getTopLeft(), mapZoomMax); |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 338 | 322 | |
| 339 | 323 | if (polygons && mapPolygonList != null) { |
| 340 | 324 | synchronized (this) { |
| 341 | | for (MapPolygon polygon : mapPolygonList) { |
| | 325 | for (MapPolygon polygon : snapshot(mapPolygonList)) { |
| 342 | 326 | if (polygon.isVisible()) { |
| 343 | 327 | for (ICoordinate c : polygon.getPoints()) { |
| 344 | 328 | Point p = tileSource.latLonToXY(c, mapZoomMax); |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 473 | 457 | } |
| 474 | 458 | |
| 475 | 459 | /** |
| 476 | | * Calculates the position on the map of a given coordinate |
| | 460 | * Calculates the y position on the map of a coordinate that is shifted by an offset in latitude. |
| 477 | 461 | * |
| 478 | 462 | * @param lat Latitude |
| 479 | 463 | * @param lon longitude |
| 480 | 464 | * @param offset Offset respect Latitude |
| 481 | 465 | * @param checkOutside check if the point is outside the displayed area |
| 482 | | * @return Integer the radius in pixels |
| | 466 | * @return the y position in pixels, or <code>null</code> if it is not visible and checkOutside is set to <code>true</code> |
| 483 | 467 | */ |
| 484 | 468 | public Integer getLatOffset(double lat, double lon, double offset, boolean checkOutside) { |
| 485 | 469 | Point p = tileSource.latLonToXY(lat + offset, lon, zoom); |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 491 | 475 | } |
| 492 | 476 | |
| 493 | 477 | /** |
| 494 | | * Calculates the position on the map of a given coordinate |
| | 478 | * Calculates the radius of a map marker on the map. |
| 495 | 479 | * |
| 496 | 480 | * @param marker MapMarker object that define the x,y coordinate |
| 497 | | * @param p coordinate |
| 498 | | * @return Integer the radius in pixels |
| | 481 | * @param p position of the marker on the map |
| | 482 | * @return the radius in pixels, or <code>null</code> if it cannot be determined |
| 499 | 483 | */ |
| 500 | 484 | public Integer getRadius(MapMarker marker, Point p) { |
| 501 | 485 | if (marker.getMarkerStyle() == MapMarker.STYLE.FIXED) |
| 502 | 486 | return (int) marker.getRadius(); |
| 503 | 487 | else if (p != null) { |
| 504 | | Integer radius = getLatOffset(marker.getLat(), marker.getLon(), marker.getRadius(), false); |
| 505 | | radius = radius == null ? null : (p.y - radius); |
| 506 | | return radius; |
| | 488 | Integer offset = getLatOffset(marker.getLat(), marker.getLon(), marker.getRadius(), false); |
| | 489 | return offset == null ? null : (p.y - offset); |
| 507 | 490 | } else |
| 508 | 491 | return null; |
| 509 | 492 | } |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 593 | 576 | } else { |
| 594 | 577 | iMove = 0; |
| 595 | 578 | } |
| 596 | | } // calculate the visibility borders |
| | 579 | } |
| | 580 | // calculate the visibility borders |
| 597 | 581 | int xMin = -tilesize; |
| 598 | 582 | int yMin = -tilesize; |
| 599 | 583 | int xMax = getWidth(); |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 617 | 601 | Tile tile; |
| 618 | 602 | if (scrollWrapEnabled) { |
| 619 | 603 | // in case tilex is out of bounds, grab the tile to use for wrapping |
| 620 | | int tilexWrap = ((tilex % gridLength) + gridLength) % gridLength; |
| | 604 | int tilexWrap = Math.floorMod(tilex, gridLength); |
| 621 | 605 | tile = tileController.getTile(tilexWrap, tiley, zoom); |
| 622 | 606 | } else { |
| 623 | 607 | tile = tileController.getTile(tilex, tiley, zoom); |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 630 | 614 | } |
| 631 | 615 | painted = true; |
| 632 | 616 | } |
| 633 | | Point p = move[iMove]; |
| | 617 | Point p = MOVE[iMove]; |
| 634 | 618 | posx += p.x * tilesize; |
| 635 | 619 | posy += p.y * tilesize; |
| 636 | 620 | tilex += p.x; |
| 637 | 621 | tiley += p.y; |
| 638 | 622 | } |
| 639 | | iMove = (iMove + 1) % move.length; |
| | 623 | iMove = (iMove + 1) % MOVE.length; |
| 640 | 624 | } |
| 641 | 625 | } |
| 642 | 626 | // outer border of the map |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 648 | 632 | g.drawRect(w2 - center.x, h2 - center.y, mapSize, mapSize); |
| 649 | 633 | } |
| 650 | 634 | |
| 651 | | // g.drawString("Tiles in cache: " + tileCache.getTileCount(), 50, 20); |
| 652 | | |
| 653 | 635 | // keep x-coordinates from growing without bound if scroll-wrap is enabled |
| 654 | 636 | if (scrollWrapEnabled) { |
| 655 | 637 | center.x = center.x % mapSize; |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 657 | 639 | |
| 658 | 640 | if (mapPolygonsVisible && mapPolygonList != null) { |
| 659 | 641 | synchronized (this) { |
| 660 | | for (MapPolygon polygon : mapPolygonList) { |
| | 642 | for (MapPolygon polygon : snapshot(mapPolygonList)) { |
| 661 | 643 | if (polygon.isVisible()) |
| 662 | 644 | paintPolygon(g, polygon); |
| 663 | 645 | } |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 666 | 648 | |
| 667 | 649 | if (mapRectanglesVisible && mapRectangleList != null) { |
| 668 | 650 | synchronized (this) { |
| 669 | | for (MapRectangle rectangle : mapRectangleList) { |
| | 651 | for (MapRectangle rectangle : snapshot(mapRectangleList)) { |
| 670 | 652 | if (rectangle.isVisible()) |
| 671 | 653 | paintRectangle(g, rectangle); |
| 672 | 654 | } |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 675 | 657 | |
| 676 | 658 | if (mapMarkersVisible && mapMarkerList != null) { |
| 677 | 659 | synchronized (this) { |
| 678 | | for (MapMarker marker : mapMarkerList) { |
| | 660 | for (MapMarker marker : snapshot(mapMarkerList)) { |
| 679 | 661 | if (marker.isVisible()) |
| 680 | 662 | paintMarker(g, marker); |
| 681 | 663 | } |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 685 | 667 | attribution.paintAttribution(g, getWidth(), getHeight(), getPosition(0, 0), getPosition(getWidth(), getHeight()), zoom, this); |
| 686 | 668 | } |
| 687 | 669 | |
| | 670 | /** |
| | 671 | * Copies a list of map objects, so that it can be iterated while other threads change it. |
| | 672 | * Copying a {@link Collections#synchronizedList} is atomic, unlike iterating over it. |
| | 673 | * @param <T> type of the map objects |
| | 674 | * @param list list to copy |
| | 675 | * @return a copy of the list |
| | 676 | */ |
| | 677 | private static <T> List<T> snapshot(List<T> list) { |
| | 678 | return new ArrayList<>(list); |
| | 679 | } |
| | 680 | |
| 688 | 681 | /** |
| 689 | 682 | * Paint a single marker. |
| 690 | 683 | * @param g Graphics used for painting |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 818 | 811 | center.x += x; |
| 819 | 812 | center.y += y; |
| 820 | 813 | repaint(); |
| 821 | | this.fireJMVEvent(new JMVCommandEvent(COMMAND.MOVE, this)); |
| | 814 | fireJMVEvent(new JMVCommandEvent(COMMAND.MOVE, this)); |
| 822 | 815 | } |
| 823 | 816 | |
| 824 | 817 | /** |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 870 | 863 | || zoom == this.zoom) |
| 871 | 864 | return; |
| 872 | 865 | ICoordinate zoomPos = getPosition(mapPoint); |
| 873 | | tileController.cancelOutstandingJobs(); // Clearing outstanding load |
| 874 | | // requests |
| | 866 | tileController.cancelOutstandingJobs(); // Clearing outstanding load requests |
| 875 | 867 | setDisplayPosition(mapPoint, zoomPos, zoom); |
| 876 | 868 | |
| 877 | | this.fireJMVEvent(new JMVCommandEvent(COMMAND.ZOOM, this)); |
| | 869 | fireJMVEvent(new JMVCommandEvent(COMMAND.ZOOM, this)); |
| 878 | 870 | } |
| 879 | 871 | |
| 880 | 872 | /** |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 1067 | 1059 | repaint(); |
| 1068 | 1060 | } |
| 1069 | 1061 | |
| 1070 | | /** |
| 1071 | | * Sets whether zoom controls are displayed or not. |
| 1072 | | * @param visible {@code true} if zoom controls are displayed, {@code false} otherwise |
| 1073 | | * @deprecated use {@link #setZoomControlsVisible(boolean)} |
| 1074 | | */ |
| 1075 | | @Deprecated |
| 1076 | | public void setZoomContolsVisible(boolean visible) { |
| 1077 | | setZoomControlsVisible(visible); |
| 1078 | | } |
| 1079 | | |
| 1080 | 1062 | /** |
| 1081 | 1063 | * Sets whether zoom controls are displayed or not. |
| 1082 | 1064 | * @param visible {@code true} if zoom controls are displayed, {@code false} otherwise |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 1182 | 1164 | } |
| 1183 | 1165 | |
| 1184 | 1166 | /** |
| 1185 | | * Returns the zoom controls apparence style (horizontal/vertical). |
| | 1167 | * Returns the zoom controls appearance style (horizontal/vertical). |
| 1186 | 1168 | * @return {@link ZOOM_BUTTON_STYLE#VERTICAL} or {@link ZOOM_BUTTON_STYLE#HORIZONTAL} |
| 1187 | 1169 | */ |
| 1188 | 1170 | public ZOOM_BUTTON_STYLE getZoomButtonStyle() { |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 1190 | 1172 | } |
| 1191 | 1173 | |
| 1192 | 1174 | /** |
| 1193 | | * Sets the zoom controls apparence style (horizontal/vertical). |
| | 1175 | * Sets the zoom controls appearance style (horizontal/vertical). |
| 1194 | 1176 | * @param style {@link ZOOM_BUTTON_STYLE#VERTICAL} or {@link ZOOM_BUTTON_STYLE#HORIZONTAL} |
| 1195 | 1177 | */ |
| 1196 | 1178 | public void setZoomButtonStyle(ZOOM_BUTTON_STYLE style) { |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 1198 | 1180 | if (zoomSlider == null || zoomInButton == null || zoomOutButton == null) { |
| 1199 | 1181 | return; |
| 1200 | 1182 | } |
| | 1183 | // Java 14: use a switch expression with arrow labels |
| 1201 | 1184 | switch (style) { |
| 1202 | 1185 | case VERTICAL: |
| 1203 | 1186 | zoomSlider.setBounds(10, 27, 30, 150); |
| … |
… |
public class JMapViewer extends JPanel implements TileLoaderListener {
|
| 1267 | 1250 | * @param evt event to dispatch |
| 1268 | 1251 | */ |
| 1269 | 1252 | private void fireJMVEvent(JMVCommandEvent evt) { |
| 1270 | | Object[] listeners = evtListenerList.getListenerList(); |
| 1271 | | for (int i = 0; i < listeners.length; i += 2) { |
| 1272 | | if (listeners[i] == JMapViewerEventListener.class) { |
| 1273 | | ((JMapViewerEventListener) listeners[i + 1]).processCommand(evt); |
| 1274 | | } |
| | 1253 | // getListeners returns the most recently added listener first, notify in the order they were added |
| | 1254 | JMapViewerEventListener[] listeners = evtListenerList.getListeners(JMapViewerEventListener.class); |
| | 1255 | for (int i = listeners.length - 1; i >= 0; i--) { |
| | 1256 | listeners[i].processCommand(evt); |
| 1275 | 1257 | } |
| 1276 | 1258 | } |
| 1277 | 1259 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/JMapViewerRuntimeException.java src/org/openstreetmap/gui/jmapviewer/JMapViewerRuntimeException.java
index fc6222a..6746a65 100644
|
|
|
public class JMapViewerRuntimeException extends RuntimeException {
|
| 12 | 12 | * @see Exception#Exception() |
| 13 | 13 | */ |
| 14 | 14 | public JMapViewerRuntimeException() { |
| 15 | | super(); |
| 16 | 15 | } |
| 17 | 16 | |
| 18 | 17 | /** |
-
diff --git src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java
index 20e44d7..1ff002e 100644
|
|
|
import java.awt.BorderLayout;
|
| 5 | 5 | import java.awt.Dimension; |
| 6 | 6 | import java.awt.event.MouseAdapter; |
| 7 | 7 | import java.awt.event.MouseEvent; |
| 8 | | import java.util.List; |
| 9 | 8 | |
| 10 | 9 | import javax.swing.JLabel; |
| 11 | 10 | import javax.swing.JMenuItem; |
| … |
… |
import org.openstreetmap.gui.jmapviewer.interfaces.MapObject;
|
| 24 | 23 | * @author galo |
| 25 | 24 | */ |
| 26 | 25 | public class JMapViewerTree extends JPanel { |
| 27 | | /** Serial Version UID */ |
| | 26 | // Java 14: annotate with @Serial |
| 28 | 27 | private static final long serialVersionUID = 3050203054402323972L; |
| 29 | 28 | |
| 30 | 29 | private final JMapViewer map; |
| … |
… |
public class JMapViewerTree extends JPanel {
|
| 36 | 35 | this(name, false); |
| 37 | 36 | } |
| 38 | 37 | |
| | 38 | @SuppressWarnings("this-escape") |
| 39 | 39 | public JMapViewerTree(String name, boolean treeVisible) { |
| 40 | | super(); |
| 41 | 40 | splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); |
| 42 | 41 | |
| 43 | 42 | tree = new CheckBoxTree(name); |
| … |
… |
public class JMapViewerTree extends JPanel {
|
| 49 | 48 | splitPane.setOneTouchExpandable(true); |
| 50 | 49 | splitPane.setDividerLocation(150); |
| 51 | 50 | |
| 52 | | //Provide minimum sizes for the two components in the split pane |
| 53 | | Dimension minimumSize = new Dimension(100, 50); |
| 54 | | //tree.setMinimumSize(minimumSize); |
| 55 | | map.setMinimumSize(minimumSize); |
| | 51 | map.setMinimumSize(new Dimension(100, 50)); |
| 56 | 52 | createRefresh(); |
| 57 | 53 | setLayout(new BorderLayout()); |
| 58 | 54 | setTreeVisible(treeVisible); |
| … |
… |
public class JMapViewerTree extends JPanel {
|
| 71 | 67 | if (e.isPopupTrigger()) { |
| 72 | 68 | AbstractLayer layer = ((CheckBoxNodePanel) e.getComponent()).getData().getAbstractLayer(); |
| 73 | 69 | if (layer != null) |
| 74 | | JMapViewerTree.this.createPopupMenu(layer).show(e.getComponent(), e.getX(), e.getY()); |
| | 70 | createPopupMenu(layer).show(e.getComponent(), e.getX(), e.getY()); |
| 75 | 71 | } |
| 76 | 72 | } |
| 77 | 73 | }); |
| … |
… |
public class JMapViewerTree extends JPanel {
|
| 81 | 77 | JMenuItem menuItemShow = new JMenuItem("show texts"); |
| 82 | 78 | JMenuItem menuItemHide = new JMenuItem("hide texts"); |
| 83 | 79 | |
| 84 | | //Create the popup menu. |
| 85 | 80 | JPopupMenu popup = new JPopupMenu(); |
| 86 | 81 | |
| 87 | 82 | // Create items |
| … |
… |
public class JMapViewerTree extends JPanel {
|
| 107 | 102 | |
| 108 | 103 | private static void setVisibleTexts(AbstractLayer layer, boolean visible) { |
| 109 | 104 | layer.setVisibleTexts(visible); |
| | 105 | // Java 16: use instanceof pattern matching instead of the casts |
| 110 | 106 | if (layer instanceof LayerGroup) { |
| 111 | 107 | LayerGroup group = (LayerGroup) layer; |
| 112 | 108 | if (group.getLayers() != null) |
| … |
… |
public class JMapViewerTree extends JPanel {
|
| 118 | 114 | |
| 119 | 115 | public Layer addLayer(String name) { |
| 120 | 116 | Layer layer = new Layer(name); |
| 121 | | this.addLayer(layer); |
| | 117 | addLayer(layer); |
| 122 | 118 | return layer; |
| 123 | 119 | } |
| 124 | 120 | |
| … |
… |
public class JMapViewerTree extends JPanel {
|
| 128 | 124 | } |
| 129 | 125 | |
| 130 | 126 | public JMapViewerTree addLayer(MapObject element) { |
| 131 | | //element.getLayer().add(element); |
| 132 | 127 | return addLayer(element.getLayer()); |
| 133 | 128 | } |
| 134 | 129 | |
| … |
… |
public class JMapViewerTree extends JPanel {
|
| 137 | 132 | return element.getLayer(); |
| 138 | 133 | } |
| 139 | 134 | |
| 140 | | public static int size(List<?> list) { |
| 141 | | return list == null ? 0 : list.size(); |
| 142 | | } |
| 143 | | |
| 144 | 135 | public JMapViewer getViewer() { |
| 145 | 136 | return map; |
| 146 | 137 | } |
| … |
… |
public class JMapViewerTree extends JPanel {
|
| 149 | 140 | return tree; |
| 150 | 141 | } |
| 151 | 142 | |
| 152 | | public void addMapObject(MapObject o){ |
| 153 | | |
| 154 | | } |
| 155 | | |
| 156 | 143 | public void setTreeVisible(boolean visible) { |
| 157 | 144 | removeAll(); |
| 158 | 145 | revalidate(); |
| … |
… |
public class JMapViewerTree extends JPanel {
|
| 172 | 159 | } |
| 173 | 160 | |
| 174 | 161 | @Override |
| 175 | | public void treeNodesInserted(TreeModelEvent arg0) { |
| 176 | | // TODO Auto-generated method stub |
| | 162 | public void treeNodesInserted(TreeModelEvent e) { |
| | 163 | // Nothing to do |
| 177 | 164 | } |
| 178 | 165 | |
| 179 | 166 | @Override |
| 180 | | public void treeNodesRemoved(TreeModelEvent arg0) { |
| 181 | | // TODO Auto-generated method stub |
| | 167 | public void treeNodesRemoved(TreeModelEvent e) { |
| | 168 | // Nothing to do |
| 182 | 169 | } |
| 183 | 170 | |
| 184 | 171 | @Override |
| 185 | | public void treeStructureChanged(TreeModelEvent arg0) { |
| 186 | | // TODO Auto-generated method stub |
| | 172 | public void treeStructureChanged(TreeModelEvent e) { |
| | 173 | // Nothing to do |
| 187 | 174 | } |
| 188 | 175 | }); |
| 189 | 176 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/LayerGroup.java src/org/openstreetmap/gui/jmapviewer/LayerGroup.java
index 47b158b..e26dc6c 100644
|
|
|
public class LayerGroup extends AbstractLayer {
|
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | public LayerGroup(LayerGroup parent, String name, String description, Style style) { |
| 30 | | super(name, description, style); |
| | 30 | super(parent, name, description, style); |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | public List<AbstractLayer> getLayers() { |
-
diff --git src/org/openstreetmap/gui/jmapviewer/MapMarkerCircle.java src/org/openstreetmap/gui/jmapviewer/MapMarkerCircle.java
index 0fc018d..8c2863a 100644
|
|
|
import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker;
|
| 16 | 16 | * color. |
| 17 | 17 | * |
| 18 | 18 | * @author Jan Peter Stotz |
| 19 | | * |
| 20 | 19 | */ |
| 21 | 20 | public class MapMarkerCircle extends MapObjectImpl implements MapMarker { |
| 22 | 21 | |
| … |
… |
public class MapMarkerCircle extends MapObjectImpl implements MapMarker {
|
| 128 | 127 | |
| 129 | 128 | @Override |
| 130 | 129 | public void paint(Graphics g, Point position, int radius) { |
| 131 | | int sizeH = radius; |
| 132 | | int size = sizeH * 2; |
| | 130 | int size = radius * 2; |
| 133 | 131 | |
| | 132 | // Java 16: use instanceof pattern matching instead of the casts |
| 134 | 133 | if (g instanceof Graphics2D && getBackColor() != null) { |
| 135 | 134 | Graphics2D g2 = (Graphics2D) g; |
| 136 | 135 | Composite oldComposite = g2.getComposite(); |
| 137 | 136 | g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); |
| 138 | 137 | g2.setPaint(getBackColor()); |
| 139 | | g.fillOval(position.x - sizeH, position.y - sizeH, size, size); |
| | 138 | g.fillOval(position.x - radius, position.y - radius, size, size); |
| 140 | 139 | g2.setComposite(oldComposite); |
| 141 | 140 | } |
| 142 | 141 | g.setColor(getColor()); |
| 143 | | g.drawOval(position.x - sizeH, position.y - sizeH, size, size); |
| | 142 | g.drawOval(position.x - radius, position.y - radius, size, size); |
| 144 | 143 | |
| 145 | 144 | if (getLayer() == null || getLayer().isVisibleTexts()) paintText(g, position); |
| 146 | 145 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/MapMarkerDot.java src/org/openstreetmap/gui/jmapviewer/MapMarkerDot.java
index 2765a33..fa28c08 100644
|
|
|
import java.awt.Color;
|
| 6 | 6 | import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker; |
| 7 | 7 | |
| 8 | 8 | /** |
| 9 | | * A simple implementation of the {@link MapMarker} interface. Each map marker |
| 10 | | * is painted as a circle with a black border line and filled with a specified |
| 11 | | * color. |
| | 9 | * A {@link MapMarker} painted as a small circle of fixed size ({@link #DOT_RADIUS}), by default with a |
| | 10 | * black border line and filled yellow. |
| 12 | 11 | * |
| 13 | 12 | * @author Jan Peter Stotz |
| 14 | | * |
| 15 | 13 | */ |
| 16 | 14 | public class MapMarkerDot extends MapMarkerCircle { |
| 17 | 15 | |
| … |
… |
public class MapMarkerDot extends MapMarkerCircle {
|
| 33 | 31 | this(layer, name, coord, getDefaultStyle()); |
| 34 | 32 | } |
| 35 | 33 | |
| | 34 | @SuppressWarnings("this-escape") |
| 36 | 35 | public MapMarkerDot(Color color, double lat, double lon) { |
| 37 | 36 | this(null, null, lat, lon); |
| 38 | 37 | setColor(color); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/MapObjectImpl.java src/org/openstreetmap/gui/jmapviewer/MapObjectImpl.java
index d89bb97..41cd087 100644
|
|
|
public abstract class MapObjectImpl {
|
| 24 | 24 | } |
| 25 | 25 | |
| 26 | 26 | public MapObjectImpl(Layer layer, String name, Style style) { |
| 27 | | super(); |
| 28 | 27 | this.layer = layer; |
| 29 | 28 | this.name = name; |
| 30 | 29 | this.style = style; |
| … |
… |
public abstract class MapObjectImpl {
|
| 52 | 51 | |
| 53 | 52 | public Color getColor() { |
| 54 | 53 | Style styleAssigned = getStyleAssigned(); |
| 55 | | return styleAssigned == null ? null : getStyleAssigned().getColor(); |
| | 54 | return styleAssigned == null ? null : styleAssigned.getColor(); |
| 56 | 55 | } |
| 57 | 56 | |
| 58 | 57 | public void setColor(Color color) { |
| … |
… |
public abstract class MapObjectImpl {
|
| 62 | 61 | |
| 63 | 62 | public Color getBackColor() { |
| 64 | 63 | Style styleAssigned = getStyleAssigned(); |
| 65 | | return styleAssigned == null ? null : getStyleAssigned().getBackColor(); |
| | 64 | return styleAssigned == null ? null : styleAssigned.getBackColor(); |
| 66 | 65 | } |
| 67 | 66 | |
| 68 | 67 | public void setBackColor(Color backColor) { |
| … |
… |
public abstract class MapObjectImpl {
|
| 72 | 71 | |
| 73 | 72 | public Stroke getStroke() { |
| 74 | 73 | Style styleAssigned = getStyleAssigned(); |
| 75 | | return styleAssigned == null ? null : getStyleAssigned().getStroke(); |
| | 74 | return styleAssigned == null ? null : styleAssigned.getStroke(); |
| 76 | 75 | } |
| 77 | 76 | |
| 78 | 77 | public void setStroke(Stroke stroke) { |
| … |
… |
public abstract class MapObjectImpl {
|
| 82 | 81 | |
| 83 | 82 | public Font getFont() { |
| 84 | 83 | Style styleAssigned = getStyleAssigned(); |
| 85 | | return styleAssigned == null ? null : getStyleAssigned().getFont(); |
| | 84 | return styleAssigned == null ? null : styleAssigned.getFont(); |
| 86 | 85 | } |
| 87 | 86 | |
| 88 | 87 | public void setFont(Font font) { |
| … |
… |
public abstract class MapObjectImpl {
|
| 121 | 120 | public void paintText(Graphics g, Point position) { |
| 122 | 121 | if (name != null && g != null && position != null) { |
| 123 | 122 | if (getFont() == null) { |
| 124 | | Font f = getDefaultFont(); |
| 125 | | setFont(new Font(f.getName(), Font.BOLD, f.getSize())); |
| | 123 | setFont(getDefaultFont()); |
| 126 | 124 | } |
| 127 | 125 | g.setColor(Color.DARK_GRAY); |
| 128 | 126 | g.setFont(getFont()); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java
index fe62723..4cc9887 100644
|
|
|
public class MapPolygonImpl extends MapObjectImpl implements MapPolygon {
|
| 74 | 74 | Color oldColor = g.getColor(); |
| 75 | 75 | g.setColor(getColor()); |
| 76 | 76 | |
| | 77 | // Java 16: use instanceof pattern matching instead of the casts |
| 77 | 78 | Stroke oldStroke = null; |
| 78 | 79 | if (g instanceof Graphics2D) { |
| 79 | 80 | Graphics2D g2 = (Graphics2D) g; |
-
diff --git src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java
index 6ba140b..5d569c7 100644
|
|
|
public class MapRectangleImpl extends MapObjectImpl implements MapRectangle {
|
| 52 | 52 | // Prepare graphics |
| 53 | 53 | Color oldColor = g.getColor(); |
| 54 | 54 | g.setColor(getColor()); |
| | 55 | // Java 16: use instanceof pattern matching instead of the casts |
| 55 | 56 | Stroke oldStroke = null; |
| 56 | 57 | if (g instanceof Graphics2D) { |
| 57 | 58 | Graphics2D g2 = (Graphics2D) g; |
| … |
… |
public class MapRectangleImpl extends MapObjectImpl implements MapRectangle {
|
| 59 | 60 | g2.setStroke(getStroke()); |
| 60 | 61 | } |
| 61 | 62 | // Draw |
| 62 | | g.drawRect(topLeft.x, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y); |
| | 63 | int width = bottomRight.x - topLeft.x; |
| | 64 | int height = bottomRight.y - topLeft.y; |
| | 65 | g.drawRect(topLeft.x, topLeft.y, width, height); |
| 63 | 66 | // Restore graphics |
| 64 | 67 | g.setColor(oldColor); |
| 65 | 68 | if (g instanceof Graphics2D) { |
| 66 | 69 | ((Graphics2D) g).setStroke(oldStroke); |
| 67 | 70 | } |
| 68 | | int width = bottomRight.x-topLeft.x; |
| 69 | | int height = bottomRight.y-topLeft.y; |
| 70 | 71 | Point p = new Point(topLeft.x+(width/2), topLeft.y+(height/2)); |
| 71 | 72 | if (getLayer() == null || getLayer().isVisibleTexts()) paintText(g, p); |
| 72 | 73 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java
index 97106fa..e32df67 100644
|
|
|
|
| 1 | 1 | // License: GPL. For details, see Readme.txt file. |
| 2 | 2 | package org.openstreetmap.gui.jmapviewer; |
| 3 | 3 | |
| 4 | | import java.util.Collection; |
| 5 | 4 | import java.util.HashMap; |
| | 5 | import java.util.List; |
| 6 | 6 | import java.util.Map; |
| 7 | | import java.util.logging.Level; |
| 8 | | import java.util.logging.Logger; |
| 9 | 7 | import java.util.stream.Collectors; |
| 10 | 8 | |
| 11 | 9 | import org.openstreetmap.gui.jmapviewer.interfaces.TileCache; |
| … |
… |
import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
|
| 20 | 18 | */ |
| 21 | 19 | public class MemoryTileCache implements TileCache { |
| 22 | 20 | |
| 23 | | private static final Logger LOGGER = Logger.getLogger(MemoryTileCache.class.getName()); |
| 24 | 21 | /** |
| 25 | | * @deprecated since 2.20 (create a class specific logger) |
| 26 | | */ |
| 27 | | @Deprecated |
| 28 | | protected static final Logger log = LOGGER; |
| 29 | | |
| 30 | | /** |
| 31 | | * Default cache size |
| | 22 | * Maximum number of tiles in the cache |
| 32 | 23 | */ |
| 33 | 24 | protected int cacheSize; |
| 34 | 25 | |
| … |
… |
public class MemoryTileCache implements TileCache {
|
| 59 | 50 | @Override |
| 60 | 51 | public synchronized void addTile(Tile tile) { |
| 61 | 52 | CacheEntry entry = createCacheEntry(tile); |
| 62 | | if (hash.put(tile.getKey(), entry) == null) { |
| 63 | | // only if hash hadn't had the element, add it to LRU |
| 64 | | lruTiles.addFirst(entry); |
| 65 | | if (hash.size() > cacheSize || lruTiles.getElementCount() > cacheSize) { |
| 66 | | removeOldEntries(); |
| 67 | | } |
| | 53 | CacheEntry replaced = hash.put(tile.getKey(), entry); |
| | 54 | if (replaced != null) { |
| | 55 | // the replaced entry must leave the LRU list too, or the list keeps it (and its image) forever |
| | 56 | lruTiles.removeEntry(replaced); |
| 68 | 57 | } |
| | 58 | lruTiles.addFirst(entry); |
| | 59 | removeOldEntries(); |
| 69 | 60 | } |
| 70 | 61 | |
| 71 | 62 | @Override |
| … |
… |
public class MemoryTileCache implements TileCache {
|
| 81 | 72 | * Removes the least recently used tiles |
| 82 | 73 | */ |
| 83 | 74 | protected synchronized void removeOldEntries() { |
| 84 | | try { |
| 85 | | while (lruTiles.getElementCount() > cacheSize) { |
| 86 | | removeEntry(lruTiles.getLastElement()); |
| 87 | | } |
| 88 | | } catch (NullPointerException e) { |
| 89 | | LOGGER.log(Level.WARNING, e.getMessage(), e); |
| | 75 | // with a negative cache size, the loop would go on with an empty list and fail on its null last element |
| | 76 | while (lruTiles.getElementCount() > Math.max(cacheSize, 0)) { |
| | 77 | removeEntry(lruTiles.getLastElement()); |
| 90 | 78 | } |
| 91 | 79 | } |
| 92 | 80 | |
| … |
… |
public class MemoryTileCache implements TileCache {
|
| 107 | 95 | |
| 108 | 96 | @Override |
| 109 | 97 | public synchronized void clearErrorTiles() { |
| 110 | | Collection<CacheEntry> toRemove = hash.values().stream().filter(cacheEntry -> cacheEntry.tile.hasError()).collect(Collectors.toList()); |
| 111 | | hash.values().removeAll(toRemove); |
| 112 | | toRemove.forEach(lruTiles::removeEntry); |
| | 98 | // Java 16: use Stream.toList() |
| | 99 | List<CacheEntry> toRemove = hash.values().stream().filter(cacheEntry -> cacheEntry.tile.hasError()).collect(Collectors.toList()); |
| | 100 | toRemove.forEach(this::removeEntry); |
| 113 | 101 | } |
| 114 | 102 | |
| 115 | 103 | @Override |
| … |
… |
public class MemoryTileCache implements TileCache {
|
| 125 | 113 | /** |
| 126 | 114 | * Changes the maximum number of {@link Tile} objects that this cache holds. |
| 127 | 115 | * |
| 128 | | * @param cacheSize |
| 129 | | * new maximum number of tiles |
| | 116 | * @param cacheSize new maximum number of tiles |
| 130 | 117 | */ |
| 131 | 118 | public synchronized void setCacheSize(int cacheSize) { |
| 132 | 119 | this.cacheSize = cacheSize; |
| 133 | | if (hash.size() > cacheSize) |
| 134 | | removeOldEntries(); |
| | 120 | removeOldEntries(); |
| 135 | 121 | } |
| 136 | 122 | |
| 137 | 123 | /** |
| … |
… |
public class MemoryTileCache implements TileCache {
|
| 155 | 141 | |
| 156 | 142 | /** |
| 157 | 143 | * Special implementation of a double linked list for {@link CacheEntry} |
| 158 | | * elements. It supports element removal in constant time - in difference to |
| 159 | | * the Java implementation which needs O(n). |
| | 144 | * elements. It supports element removal in constant time - unlike |
| | 145 | * {@link java.util.LinkedList}, which needs O(n). |
| 160 | 146 | * |
| 161 | 147 | * @author Jan Peter Stotz |
| 162 | 148 | */ |
-
diff --git src/org/openstreetmap/gui/jmapviewer/OsmMercator.java src/org/openstreetmap/gui/jmapviewer/OsmMercator.java
index b5354a0..3476381 100644
|
|
|
public class OsmMercator {
|
| 15 | 15 | /** |
| 16 | 16 | * default tile size |
| 17 | 17 | */ |
| 18 | | public static final int DEFAUL_TILE_SIZE = 256; |
| | 18 | public static final int DEFAULT_TILE_SIZE = 256; |
| | 19 | /** |
| | 20 | * default tile size |
| | 21 | * @deprecated use {@link #DEFAULT_TILE_SIZE}, this is the misspelled name |
| | 22 | */ |
| | 23 | @Deprecated |
| | 24 | public static final int DEFAUL_TILE_SIZE = DEFAULT_TILE_SIZE; |
| 19 | 25 | /** maximum latitude (north) for mercator display */ |
| 20 | 26 | public static final double MAX_LAT = 85.05112877980659; |
| 21 | 27 | /** minimum latitude (south) for mercator display */ |
| 22 | | public static final double MIN_LAT = -85.05112877980659; |
| | 28 | public static final double MIN_LAT = -MAX_LAT; |
| 23 | 29 | /** equatorial earth radius for EPSG:3857 (Mercator) */ |
| 24 | 30 | public static final double EARTH_RADIUS = 6_378_137; |
| 25 | 31 | |
| … |
… |
public class OsmMercator {
|
| 29 | 35 | public static final OsmMercator MERCATOR_256 = new OsmMercator(); |
| 30 | 36 | |
| 31 | 37 | /** tile size of the displayed tiles. Use long so all calculations will be in 64bit to properly handle zooms above 22 for 256 tile size */ |
| 32 | | private long tileSize = DEFAUL_TILE_SIZE; |
| | 38 | private long tileSize = DEFAULT_TILE_SIZE; |
| 33 | 39 | |
| 34 | 40 | /** |
| 35 | 41 | * Creates instance with default tile size of 256 |
| … |
… |
public class OsmMercator {
|
| 45 | 51 | this.tileSize = tileSize; |
| 46 | 52 | } |
| 47 | 53 | |
| | 54 | /** |
| | 55 | * Returns the radius of the earth in pixels at the given zoom level. |
| | 56 | * @param aZoomlevel zoom level |
| | 57 | * @return radius in pixels |
| | 58 | */ |
| 48 | 59 | public double radius(int aZoomlevel) { |
| 49 | | return (tileSize * (1 << aZoomlevel)) / (2.0 * Math.PI); |
| | 60 | return getMaxPixels(aZoomlevel) / (2.0 * Math.PI); |
| 50 | 61 | } |
| 51 | 62 | |
| 52 | 63 | /** |
| 53 | | * Returns the absolut number of pixels in y or x, defined as: 2^Zoomlevel * |
| | 64 | * Returns the absolute number of pixels in y or x, defined as: 2^Zoomlevel * |
| 54 | 65 | * tileSize where tileSize is the width of a tile in pixels |
| 55 | 66 | * |
| 56 | 67 | * @param aZoomlevel zoom level to request pixel data |
| … |
… |
public class OsmMercator {
|
| 60 | 71 | return tileSize * (1L << aZoomlevel); |
| 61 | 72 | } |
| 62 | 73 | |
| | 74 | /** |
| | 75 | * Returns the x offset of the map space origin from longitude 0, in pixels. |
| | 76 | * @param aZoomlevel zoom level |
| | 77 | * @return false easting in pixels |
| | 78 | */ |
| 63 | 79 | public long falseEasting(int aZoomlevel) { |
| 64 | 80 | return getMaxPixels(aZoomlevel) / 2; |
| 65 | 81 | } |
| 66 | 82 | |
| | 83 | /** |
| | 84 | * Returns the y offset of the map space origin from the equator, in pixels. |
| | 85 | * @param aZoomlevel zoom level |
| | 86 | * @return false northing in pixels (negative) |
| | 87 | */ |
| 67 | 88 | public long falseNorthing(int aZoomlevel) { |
| 68 | | return -1 * getMaxPixels(aZoomlevel) / 2; |
| | 89 | return -getMaxPixels(aZoomlevel) / 2; |
| 69 | 90 | } |
| 70 | 91 | |
| 71 | 92 | /** |
| … |
… |
public class OsmMercator {
|
| 75 | 96 | * @param y1 the first y coordinate |
| 76 | 97 | * @param x2 the second x coordinate |
| 77 | 98 | * @param y2 the second y coordinate |
| 78 | | * |
| 79 | 99 | * @param zoomLevel the zoom level |
| 80 | 100 | * @return the distance |
| 81 | 101 | */ |
| … |
… |
public class OsmMercator {
|
| 130 | 150 | */ |
| 131 | 151 | public double lonToX(double aLongitude, int aZoomlevel) { |
| 132 | 152 | long mp = getMaxPixels(aZoomlevel); |
| 133 | | double x = (mp * (aLongitude + 180L)) / 360L; |
| | 153 | double x = mp * (aLongitude + 180) / 360; |
| 134 | 154 | return Math.min(x, mp); |
| 135 | 155 | } |
| 136 | 156 | |
| … |
… |
public class OsmMercator {
|
| 139 | 159 | * <p> |
| 140 | 160 | * Mathematical optimization<br> |
| 141 | 161 | * <code> |
| 142 | | * log(u) := log((1.0 + sin(toRadians(aLat))) / (1.0 - sin(toRadians(aLat))<br> |
| 143 | | * |
| 144 | | * y = -1 * (radius(aZoomlevel) / 2 * log(u)))) - falseNorthing(aZoomlevel))<br> |
| 145 | | * y = -1 * (getMaxPixel(aZoomlevel) / 2 * PI / 2 * log(u)) - -1 * getMaxPixel(aZoomLevel) / 2<br> |
| 146 | | * y = getMaxPixel(aZoomlevel) / (-4 * PI) * log(u)) + getMaxPixel(aZoomLevel) / 2<br> |
| 147 | | * y = getMaxPixel(aZoomlevel) * ((log(u) / (-4 * PI)) + 1/2)<br> |
| | 162 | * log(u) := log((1.0 + sin(toRadians(aLat))) / (1.0 - sin(toRadians(aLat))))<br> |
| | 163 | * y = -1 * (radius(aZoomlevel) / 2 * log(u)) - falseNorthing(aZoomlevel)<br> |
| | 164 | * y = -1 * (getMaxPixels(aZoomlevel) / (2 * PI) / 2 * log(u)) - -1 * getMaxPixels(aZoomLevel) / 2<br> |
| | 165 | * y = getMaxPixels(aZoomlevel) / (-4 * PI) * log(u) + getMaxPixels(aZoomLevel) / 2<br> |
| | 166 | * y = getMaxPixels(aZoomlevel) * ((log(u) / (-4 * PI)) + 1/2)<br> |
| 148 | 167 | * </code> |
| 149 | 168 | * </p> |
| 150 | 169 | * @param aLat |
| … |
… |
public class OsmMercator {
|
| 195 | 214 | * @return [MIN_LAT..MAX_LAT] is about [-85..85] |
| 196 | 215 | */ |
| 197 | 216 | public double yToLat(long aY, int aZoomlevel) { |
| 198 | | double latitude = (Math.PI / 2) - (2 * Math.atan(Math.exp(-1.0 * (aY + falseNorthing(aZoomlevel)) / radius(aZoomlevel)))); |
| 199 | | return -1 * Math.toDegrees(latitude); |
| | 217 | double latitude = (Math.PI / 2) - (2 * Math.atan(Math.exp(-(aY + falseNorthing(aZoomlevel)) / radius(aZoomlevel)))); |
| | 218 | return -Math.toDegrees(latitude); |
| 200 | 219 | } |
| 201 | | |
| 202 | 220 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java
index e872e16..17fd6a2 100644
|
|
|
import java.net.URLConnection;
|
| 11 | 11 | import java.util.HashMap; |
| 12 | 12 | import java.util.Map; |
| 13 | 13 | import java.util.Map.Entry; |
| 14 | | import java.util.concurrent.Executors; |
| | 14 | import java.util.concurrent.LinkedBlockingQueue; |
| 15 | 15 | import java.util.concurrent.ThreadPoolExecutor; |
| | 16 | import java.util.concurrent.TimeUnit; |
| 16 | 17 | import java.util.logging.Level; |
| 17 | 18 | import java.util.logging.Logger; |
| 18 | 19 | |
| … |
… |
public class OsmTileLoader implements TileLoader {
|
| 32 | 33 | /** Setting key for number of threads */ |
| 33 | 34 | public static final String THREADS_SETTING = "jmapviewer.osm-tile-loader.threads"; |
| 34 | 35 | private static final int DEFAULT_THREADS_NUMBER = 8; |
| 35 | | private static int nThreads = DEFAULT_THREADS_NUMBER; |
| 36 | | static { |
| | 36 | |
| | 37 | /** Fixed size pool, shared by all instances */ |
| | 38 | private static final ThreadPoolExecutor JOB_DISPATCHER = createFixedPool(threadCount()); |
| | 39 | |
| | 40 | /** Guards resizing {@link #JOB_DISPATCHER}, which takes two steps */ |
| | 41 | private static final Object POOL_SIZE_LOCK = new Object(); |
| | 42 | |
| | 43 | private static ThreadPoolExecutor createFixedPool(int threads) { |
| | 44 | return new ThreadPoolExecutor(threads, threads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); |
| | 45 | } |
| | 46 | |
| | 47 | private static int threadCount() { |
| | 48 | // a failure here would fail the class initialization, so that no tile could be loaded at all |
| 37 | 49 | try { |
| 38 | | nThreads = FeatureAdapter.getIntSetting(THREADS_SETTING, DEFAULT_THREADS_NUMBER); |
| 39 | | } catch (Exception e) { |
| | 50 | int threads = FeatureAdapter.getIntSetting(THREADS_SETTING, DEFAULT_THREADS_NUMBER); |
| | 51 | if (threads >= 1) { |
| | 52 | return threads; |
| | 53 | } |
| | 54 | LOG.log(Level.SEVERE, "Invalid {0}: {1}", new Object[] {THREADS_SETTING, threads}); |
| | 55 | } catch (RuntimeException e) { |
| 40 | 56 | LOG.log(Level.SEVERE, e.getMessage(), e); |
| 41 | 57 | } |
| | 58 | return DEFAULT_THREADS_NUMBER; |
| 42 | 59 | } |
| 43 | 60 | |
| 44 | | private static final ThreadPoolExecutor jobDispatcher = (ThreadPoolExecutor) Executors.newFixedThreadPool(nThreads); |
| 45 | | |
| 46 | 61 | private final class OsmTileJob implements TileJob { |
| 47 | 62 | private final Tile tile; |
| 48 | | private InputStream input; |
| 49 | 63 | private boolean force; |
| 50 | 64 | |
| 51 | 65 | private OsmTileJob(Tile tile) { |
| … |
… |
public class OsmTileLoader implements TileLoader {
|
| 70 | 84 | if ("no-tile".equals(tile.getValue("tile-info"))) { |
| 71 | 85 | tile.setError(tr("No tiles at this zoom level")); |
| 72 | 86 | } else { |
| 73 | | input = conn.getInputStream(); |
| 74 | | try { |
| | 87 | try (InputStream input = conn.getInputStream()) { |
| 75 | 88 | tile.loadImage(input); |
| 76 | | } finally { |
| 77 | | input.close(); |
| 78 | | input = null; |
| 79 | 89 | } |
| 80 | 90 | } |
| 81 | 91 | tile.setLoaded(true); |
| … |
… |
public class OsmTileLoader implements TileLoader {
|
| 83 | 93 | } catch (IOException e) { |
| 84 | 94 | tile.setError(e.getMessage()); |
| 85 | 95 | listener.tileLoadingFinished(tile, false); |
| 86 | | if (input == null) { |
| 87 | | try { |
| 88 | | LOG.log(Level.SEVERE, "Failed loading " + tile.getUrl() +": " |
| 89 | | +e.getClass() + ": " + e.getMessage()); |
| 90 | | } catch (IOException ioe) { |
| 91 | | LOG.log(Level.SEVERE, ioe.getMessage(), ioe); |
| 92 | | } |
| | 96 | try { |
| | 97 | LOG.log(Level.SEVERE, "Failed loading " + tile.getUrl() + ": " + e.getClass() + ": " + e.getMessage()); |
| | 98 | } catch (IOException ioe) { |
| | 99 | LOG.log(Level.SEVERE, ioe.getMessage(), ioe); |
| 93 | 100 | } |
| 94 | 101 | } finally { |
| 95 | 102 | tile.loading = false; |
| … |
… |
public class OsmTileLoader implements TileLoader {
|
| 105 | 112 | @Override |
| 106 | 113 | public void submit(boolean force) { |
| 107 | 114 | this.force = force; |
| 108 | | jobDispatcher.execute(this); |
| | 115 | JOB_DISPATCHER.execute(this); |
| 109 | 116 | } |
| 110 | 117 | } |
| 111 | 118 | |
| … |
… |
public class OsmTileLoader implements TileLoader {
|
| 127 | 134 | this(listener, null); |
| 128 | 135 | } |
| 129 | 136 | |
| | 137 | /** |
| | 138 | * Constructs a new {@code OsmTileLoader}. |
| | 139 | * @param listener tile loader listener |
| | 140 | * @param headers HTTP headers to send in addition to (or instead of) the default ones, can be null |
| | 141 | */ |
| 130 | 142 | public OsmTileLoader(TileLoaderListener listener, Map<String, String> headers) { |
| 131 | 143 | this.headers.put("Accept", "text/html, image/png, image/jpeg, image/gif, */*"); |
| 132 | | this.headers.put("User-Agent", "JMapViewer Java/"+System.getProperty("java.version")); |
| | 144 | this.headers.put("User-Agent", "JMapViewer Java/" + System.getProperty("java.version")); |
| 133 | 145 | if (headers != null) { |
| 134 | 146 | this.headers.putAll(headers); |
| 135 | 147 | } |
| … |
… |
public class OsmTileLoader implements TileLoader {
|
| 142 | 154 | } |
| 143 | 155 | |
| 144 | 156 | protected URLConnection loadTileFromOsm(Tile tile) throws IOException { |
| 145 | | URL url; |
| 146 | | url = new URL(tile.getUrl()); |
| 147 | | URLConnection urlConn = url.openConnection(); |
| | 157 | // Java 20: URL(String) is deprecated, use new URI(...).toURL() (it rejects some URLs that are accepted now) |
| | 158 | URLConnection urlConn = new URL(tile.getUrl()).openConnection(); |
| | 159 | // Java 16: use instanceof pattern matching instead of the casts |
| 148 | 160 | if (urlConn instanceof HttpURLConnection) { |
| 149 | 161 | prepareHttpUrlConnection((HttpURLConnection) urlConn); |
| 150 | 162 | } |
| … |
… |
public class OsmTileLoader implements TileLoader {
|
| 161 | 173 | tile.putValue("tile-info", str); |
| 162 | 174 | } |
| 163 | 175 | |
| 164 | | Long lng = urlConn.getExpiration(); |
| 165 | | if (lng.equals(0L)) { |
| | 176 | long expires = urlConn.getExpiration(); |
| | 177 | if (expires == 0) { |
| 166 | 178 | try { |
| 167 | 179 | str = urlConn.getHeaderField("Cache-Control"); |
| 168 | 180 | if (str != null) { |
| 169 | 181 | for (String token: str.split(",", -1)) { |
| | 182 | // the directives are usually separated by ", " |
| | 183 | token = token.strip(); |
| 170 | 184 | if (token.startsWith("max-age=")) { |
| 171 | | lng = Long.parseLong(token.substring(8)) * 1000 + |
| | 185 | expires = Long.parseLong(token.substring(8)) * 1000 + |
| 172 | 186 | System.currentTimeMillis(); |
| 173 | 187 | } |
| 174 | 188 | } |
| 175 | 189 | } |
| 176 | 190 | } catch (NumberFormatException e) { |
| 177 | 191 | // ignore malformed Cache-Control headers |
| 178 | | if (JMapViewer.debug) { |
| 179 | | LOG.log(Level.FINE, e.getMessage(), e); |
| 180 | | } |
| | 192 | LOG.log(Level.FINE, e.getMessage(), e); |
| 181 | 193 | } |
| 182 | 194 | } |
| 183 | | if (!lng.equals(0L)) { |
| 184 | | tile.putValue("expires", lng.toString()); |
| | 195 | if (expires != 0) { |
| | 196 | tile.putValue("expires", Long.toString(expires)); |
| 185 | 197 | } |
| 186 | 198 | } |
| 187 | 199 | |
| … |
… |
public class OsmTileLoader implements TileLoader {
|
| 202 | 214 | |
| 203 | 215 | @Override |
| 204 | 216 | public boolean hasOutstandingTasks() { |
| 205 | | return jobDispatcher.getTaskCount() > jobDispatcher.getCompletedTaskCount(); |
| | 217 | return JOB_DISPATCHER.getTaskCount() > JOB_DISPATCHER.getCompletedTaskCount(); |
| 206 | 218 | } |
| 207 | 219 | |
| 208 | 220 | @Override |
| 209 | 221 | public void cancelOutstandingTasks() { |
| 210 | | jobDispatcher.getQueue().clear(); |
| | 222 | JOB_DISPATCHER.getQueue().clear(); |
| 211 | 223 | } |
| 212 | 224 | |
| 213 | 225 | /** |
| 214 | 226 | * Sets the maximum number of concurrent connections the tile loader will do |
| 215 | 227 | * @param num number of concurrent connections |
| | 228 | * @throws IllegalArgumentException if {@code num} is less than 1 |
| 216 | 229 | */ |
| 217 | 230 | public static void setConcurrentConnections(int num) { |
| 218 | | jobDispatcher.setMaximumPoolSize(num); |
| | 231 | // checked first, setCorePoolSize(0) would succeed and leave the pool half resized |
| | 232 | if (num < 1) { |
| | 233 | throw new IllegalArgumentException("At least one connection is needed: " + num); |
| | 234 | } |
| | 235 | // The pool has a fixed size, so both sizes have to change. The maximum may never be below the core size. |
| | 236 | synchronized (POOL_SIZE_LOCK) { |
| | 237 | if (num > JOB_DISPATCHER.getMaximumPoolSize()) { |
| | 238 | JOB_DISPATCHER.setMaximumPoolSize(num); |
| | 239 | JOB_DISPATCHER.setCorePoolSize(num); |
| | 240 | } else { |
| | 241 | JOB_DISPATCHER.setCorePoolSize(num); |
| | 242 | JOB_DISPATCHER.setMaximumPoolSize(num); |
| | 243 | } |
| | 244 | } |
| 219 | 245 | } |
| 220 | 246 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/Projected.java src/org/openstreetmap/gui/jmapviewer/Projected.java
index e861c50..bb8c8b3 100644
|
|
|
import java.util.Objects;
|
| 11 | 11 | import org.openstreetmap.gui.jmapviewer.interfaces.IProjected; |
| 12 | 12 | |
| 13 | 13 | /** |
| 14 | | * Projected coordinates represented by an encapsulates a Point2D.Double value. |
| | 14 | * Projected coordinates, stored as a {@link Point2D.Double}. |
| 15 | 15 | */ |
| 16 | 16 | public class Projected implements IProjected, Serializable { |
| | 17 | // Java 14: annotate with @Serial |
| 17 | 18 | private static final long serialVersionUID = 1L; |
| 18 | 19 | private transient Point2D.Double data; |
| 19 | 20 | |
| … |
… |
public class Projected implements IProjected, Serializable {
|
| 36 | 37 | return data.y; |
| 37 | 38 | } |
| 38 | 39 | |
| | 40 | // Java 14: annotate with @Serial |
| 39 | 41 | private void writeObject(ObjectOutputStream out) throws IOException { |
| 40 | 42 | out.writeObject(data.x); |
| 41 | 43 | out.writeObject(data.y); |
| 42 | 44 | } |
| 43 | 45 | |
| | 46 | // Java 14: annotate with @Serial |
| 44 | 47 | private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { |
| 45 | 48 | data = new Point2D.Double(); |
| 46 | 49 | data.x = (Double) in.readObject(); |
| … |
… |
public class Projected implements IProjected, Serializable {
|
| 61 | 64 | public boolean equals(Object obj) { |
| 62 | 65 | if (this == obj) |
| 63 | 66 | return true; |
| 64 | | if (obj == null || !this.getClass().equals(obj.getClass())) |
| | 67 | if (obj == null || !getClass().equals(obj.getClass())) |
| 65 | 68 | return false; |
| 66 | 69 | final Projected other = (Projected) obj; |
| 67 | 70 | return Objects.equals(data, other.data); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/Style.java src/org/openstreetmap/gui/jmapviewer/Style.java
index dc7b647..6b4e9b8 100644
|
|
|
|
| 1 | 1 | // License: GPL. For details, see Readme.txt file. |
| 2 | 2 | package org.openstreetmap.gui.jmapviewer; |
| 3 | 3 | |
| 4 | | import java.awt.AlphaComposite; |
| 5 | 4 | import java.awt.Color; |
| 6 | 5 | import java.awt.Font; |
| 7 | 6 | import java.awt.Stroke; |
| 8 | 7 | |
| 9 | 8 | public class Style { |
| 10 | | private static final AlphaComposite TRANSPARENCY = AlphaComposite.getInstance(AlphaComposite.SRC_OVER); |
| 11 | | private static final AlphaComposite OPAQUE = AlphaComposite.getInstance(AlphaComposite.SRC); |
| 12 | | |
| 13 | 9 | private Color color; |
| 14 | 10 | private Color backColor; |
| 15 | 11 | private Stroke stroke; |
| 16 | 12 | private Font font; |
| 17 | 13 | |
| 18 | 14 | public Style() { |
| 19 | | super(); |
| 20 | 15 | } |
| 21 | 16 | |
| 22 | 17 | public Style(Color color, Color backColor, Stroke stroke, Font font) { |
| 23 | | super(); |
| 24 | 18 | this.color = color; |
| 25 | 19 | this.backColor = backColor; |
| 26 | 20 | this.stroke = stroke; |
| … |
… |
public class Style {
|
| 58 | 52 | public void setFont(Font font) { |
| 59 | 53 | this.font = font; |
| 60 | 54 | } |
| 61 | | |
| 62 | | private static AlphaComposite getAlphaComposite(Color color) { |
| 63 | | return color.getAlpha() == 255 ? OPAQUE : TRANSPARENCY; |
| 64 | | } |
| 65 | | |
| 66 | | public AlphaComposite getAlphaComposite() { |
| 67 | | return getAlphaComposite(color); |
| 68 | | } |
| 69 | | |
| 70 | | public AlphaComposite getBackAlphaComposite() { |
| 71 | | return getAlphaComposite(backColor); |
| 72 | | } |
| 73 | 55 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/Tile.java src/org/openstreetmap/gui/jmapviewer/Tile.java
index 3c2502b..11b8cfd 100644
|
|
|
import java.io.InputStream;
|
| 10 | 10 | import java.util.HashMap; |
| 11 | 11 | import java.util.Map; |
| 12 | 12 | import java.util.Objects; |
| 13 | | import java.util.concurrent.Callable; |
| | 13 | import java.util.function.Supplier; |
| 14 | 14 | import java.util.logging.Level; |
| 15 | 15 | |
| 16 | 16 | import javax.imageio.ImageIO; |
| … |
… |
public class Tile {
|
| 89 | 89 | } |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | | private static class CachedCallable<V> implements Callable<V> { |
| | 92 | /** |
| | 93 | * A supplier that asks the wrapped supplier only once, on first use. |
| | 94 | * @param <V> the type of the supplied value |
| | 95 | */ |
| | 96 | private static final class Lazy<V> implements Supplier<V> { |
| 93 | 97 | private V result; |
| 94 | | private final Callable<V> callable; |
| 95 | | |
| 96 | | /** |
| 97 | | * Wraps callable so it is evaluated only once |
| 98 | | * @param callable to cache |
| 99 | | */ |
| 100 | | CachedCallable(Callable<V> callable) { |
| 101 | | this.callable = callable; |
| | 98 | private final Supplier<V> supplier; |
| | 99 | |
| | 100 | Lazy(Supplier<V> supplier) { |
| | 101 | this.supplier = supplier; |
| 102 | 102 | } |
| 103 | 103 | |
| 104 | 104 | @Override |
| 105 | | public synchronized V call() { |
| 106 | | try { |
| 107 | | if (result == null) { |
| 108 | | result = callable.call(); |
| 109 | | } |
| 110 | | return result; |
| 111 | | } catch (Exception e) { |
| 112 | | // this should not happen here |
| 113 | | throw new JMapViewerRuntimeException(e); |
| | 105 | public V get() { |
| | 106 | if (result == null) { |
| | 107 | result = supplier.get(); |
| 114 | 108 | } |
| | 109 | return result; |
| 115 | 110 | } |
| 116 | 111 | } |
| 117 | 112 | |
| … |
… |
public class Tile {
|
| 121 | 116 | * @param cache Tile cache |
| 122 | 117 | */ |
| 123 | 118 | public void loadPlaceholderFromCache(TileCache cache) { |
| 124 | | /* |
| 125 | | * use LazyTask as creation of BufferedImage is very expensive |
| 126 | | * this way we can avoid object creation until we're sure it's needed |
| 127 | | */ |
| 128 | | final CachedCallable<BufferedImage> tmpImage = new CachedCallable<>(() -> |
| | 119 | // creation of BufferedImage is very expensive, so it is avoided until we're sure it's needed |
| | 120 | Lazy<BufferedImage> tmpImage = new Lazy<>(() -> |
| 129 | 121 | new BufferedImage(source.getTileSize(), source.getTileSize(), BufferedImage.TYPE_INT_ARGB)); |
| 130 | 122 | |
| 131 | 123 | for (int zoomDiff = 1; zoomDiff < 5; zoomDiff++) { |
| … |
… |
public class Tile {
|
| 136 | 128 | int factor = 1 << zoomDiff; |
| 137 | 129 | int xtileHigh = xtile << zoomDiff; |
| 138 | 130 | int ytileHigh = ytile << zoomDiff; |
| 139 | | final double scale = 1.0 / factor; |
| 140 | | |
| 141 | | /* |
| 142 | | * use LazyTask for graphics to avoid evaluation of tmpImage, until we have |
| 143 | | * something to draw |
| 144 | | */ |
| 145 | | CachedCallable<Graphics2D> graphics = new CachedCallable<>(() -> { |
| 146 | | Graphics2D g = (Graphics2D) tmpImage.call().getGraphics(); |
| | 131 | double scale = 1.0 / factor; |
| | 132 | |
| | 133 | // lazy, to avoid the evaluation of tmpImage until we have something to draw |
| | 134 | Lazy<Graphics2D> graphics = new Lazy<>(() -> { |
| | 135 | Graphics2D g = (Graphics2D) tmpImage.get().getGraphics(); |
| 147 | 136 | g.setTransform(AffineTransform.getScaleInstance(scale, scale)); |
| 148 | 137 | return g; |
| 149 | 138 | }); |
| … |
… |
public class Tile {
|
| 154 | 143 | Tile tile = cache.getTile(source, xtileHigh + x, ytileHigh + y, zoomHigh); |
| 155 | 144 | if (tile != null && tile.isLoaded()) { |
| 156 | 145 | paintedTileCount++; |
| 157 | | tile.paint(graphics.call(), x * source.getTileSize(), y * source.getTileSize()); |
| | 146 | tile.paint(graphics.get(), x * source.getTileSize(), y * source.getTileSize()); |
| 158 | 147 | } |
| 159 | 148 | } |
| 160 | 149 | } |
| 161 | 150 | if (paintedTileCount == factor * factor) { |
| 162 | | image = tmpImage.call(); |
| | 151 | image = tmpImage.get(); |
| 163 | 152 | return; |
| 164 | 153 | } |
| 165 | 154 | } |
| … |
… |
public class Tile {
|
| 168 | 157 | if (zoomLow >= JMapViewer.MIN_ZOOM) { |
| 169 | 158 | int xtileLow = xtile >> zoomDiff; |
| 170 | 159 | int ytileLow = ytile >> zoomDiff; |
| 171 | | final int factor = 1 << zoomDiff; |
| 172 | | final double scale = factor; |
| 173 | | CachedCallable<Graphics2D> graphics = new CachedCallable<>(() -> { |
| 174 | | Graphics2D g = (Graphics2D) tmpImage.call().getGraphics(); |
| | 160 | int factor = 1 << zoomDiff; |
| | 161 | Lazy<Graphics2D> graphics = new Lazy<>(() -> { |
| | 162 | Graphics2D g = (Graphics2D) tmpImage.get().getGraphics(); |
| 175 | 163 | AffineTransform at = new AffineTransform(); |
| 176 | 164 | int translateX = (xtile % factor) * source.getTileSize(); |
| 177 | 165 | int translateY = (ytile % factor) * source.getTileSize(); |
| 178 | | at.setTransform(scale, 0, 0, scale, -translateX, -translateY); |
| | 166 | at.setTransform(factor, 0, 0, factor, -translateX, -translateY); |
| 179 | 167 | g.setTransform(at); |
| 180 | 168 | return g; |
| 181 | 169 | }); |
| 182 | 170 | |
| 183 | 171 | Tile tile = cache.getTile(source, xtileLow, ytileLow, zoomLow); |
| 184 | 172 | if (tile != null && tile.isLoaded()) { |
| 185 | | tile.paint(graphics.call(), 0, 0); |
| 186 | | image = tmpImage.call(); |
| | 173 | tile.paint(graphics.get(), 0, 0); |
| | 174 | image = tmpImage.get(); |
| 187 | 175 | return; |
| 188 | 176 | } |
| 189 | 177 | } |
| … |
… |
public class Tile {
|
| 322 | 310 | |
| 323 | 311 | /** |
| 324 | 312 | * Compares this object with <code>obj</code> based on |
| 325 | | * the fields {@link #xtile}, {@link #ytile} and |
| 326 | | * {@link #zoom}. |
| 327 | | * The {@link #source} field is ignored. |
| | 313 | * the fields {@link #xtile}, {@link #ytile}, {@link #zoom} |
| | 314 | * and {@link #source}. |
| 328 | 315 | */ |
| 329 | 316 | @Override |
| 330 | 317 | public boolean equals(Object obj) { |
| 331 | 318 | if (this == obj) |
| 332 | 319 | return true; |
| 333 | | if (obj == null || !this.getClass().equals(obj.getClass())) |
| | 320 | if (obj == null || !getClass().equals(obj.getClass())) |
| 334 | 321 | return false; |
| 335 | 322 | final Tile other = (Tile) obj; |
| 336 | 323 | return xtile == other.xtile |
| … |
… |
public class Tile {
|
| 344 | 331 | } |
| 345 | 332 | |
| 346 | 333 | public String getStatus() { |
| 347 | | if (this.error) |
| | 334 | if (error) |
| 348 | 335 | return "error"; |
| 349 | | if (this.loaded) |
| | 336 | if (loaded) |
| 350 | 337 | return "loaded"; |
| 351 | | if (this.loading) |
| | 338 | if (loading) |
| 352 | 339 | return "loading"; |
| 353 | 340 | return "new"; |
| 354 | 341 | } |
| … |
… |
public class Tile {
|
| 393 | 380 | } |
| 394 | 381 | |
| 395 | 382 | /** |
| 396 | | * returns the metadata of the Tile |
| | 383 | * Returns the metadata of the Tile |
| 397 | 384 | * |
| 398 | 385 | * @param key metadata key that should be returned |
| 399 | 386 | * @return null if no such metadata exists, or the value of the metadata |
| … |
… |
public class Tile {
|
| 404 | 391 | } |
| 405 | 392 | |
| 406 | 393 | /** |
| 407 | | * |
| 408 | 394 | * @return metadata of the tile |
| 409 | 395 | */ |
| 410 | 396 | public Map<String, String> getMetadata() { |
| … |
… |
public class Tile {
|
| 415 | 401 | } |
| 416 | 402 | |
| 417 | 403 | /** |
| 418 | | * indicate that loading process for this tile has started |
| | 404 | * Indicates that loading process for this tile has started |
| 419 | 405 | */ |
| 420 | 406 | public void initLoading() { |
| 421 | 407 | error = false; |
| … |
… |
public class Tile {
|
| 423 | 409 | } |
| 424 | 410 | |
| 425 | 411 | /** |
| 426 | | * indicate that loading process for this tile has ended |
| | 412 | * Indicates that loading process for this tile has ended |
| 427 | 413 | */ |
| 428 | 414 | public void finishLoading() { |
| 429 | 415 | loading = false; |
| … |
… |
public class Tile {
|
| 431 | 417 | } |
| 432 | 418 | |
| 433 | 419 | /** |
| 434 | | * |
| 435 | 420 | * @return TileSource from which this tile comes |
| 436 | 421 | */ |
| 437 | 422 | public TileSource getTileSource() { |
| … |
… |
public class Tile {
|
| 439 | 424 | } |
| 440 | 425 | |
| 441 | 426 | /** |
| 442 | | * indicate that loading process for this tile has been canceled |
| | 427 | * Indicates that loading process for this tile has been canceled |
| 443 | 428 | */ |
| 444 | 429 | public void loadingCanceled() { |
| 445 | 430 | loading = false; |
-
diff --git src/org/openstreetmap/gui/jmapviewer/TileController.java src/org/openstreetmap/gui/jmapviewer/TileController.java
index 136f11b..46f2a4d 100644
|
|
|
import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
|
| 6 | 6 | import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener; |
| 7 | 7 | import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; |
| 8 | 8 | |
| | 9 | /** |
| | 10 | * Wires a {@link TileSource}, a {@link TileCache} and a {@link TileLoader} together, to get the tiles that a map shows. |
| | 11 | */ |
| 9 | 12 | public class TileController { |
| 10 | 13 | protected TileLoader tileLoader; |
| 11 | 14 | protected TileCache tileCache; |
| 12 | 15 | protected TileSource tileSource; |
| 13 | 16 | |
| | 17 | /** |
| | 18 | * Constructs a new {@code TileController}, which loads the tiles with an {@link OsmTileLoader}. |
| | 19 | * @param source the tile source |
| | 20 | * @param tileCache the tile cache |
| | 21 | * @param listener the listener notified when a tile has been loaded |
| | 22 | */ |
| 14 | 23 | public TileController(TileSource source, TileCache tileCache, TileLoaderListener listener) { |
| 15 | 24 | this.tileSource = source; |
| 16 | 25 | this.tileLoader = new OsmTileLoader(listener); |
| … |
… |
public class TileController {
|
| 18 | 27 | } |
| 19 | 28 | |
| 20 | 29 | /** |
| 21 | | * retrieves a tile from the cache. If the tile is not present in the cache |
| 22 | | * a load job is added to the working queue of {@link TileLoader}. |
| | 30 | * Retrieves a tile from the cache. If the tile is not present in the cache, a new tile is added |
| | 31 | * to the cache. If the tile is not loaded yet, a load job is added to the working queue of {@link TileLoader}. |
| 23 | 32 | * |
| 24 | 33 | * @param tilex the X position of the tile |
| 25 | 34 | * @param tiley the Y position of the tile |
| 26 | 35 | * @param zoom the zoom level of the tile |
| 27 | | * @return specified tile from the cache or <code>null</code> if the tile |
| 28 | | * was not found in the cache. |
| | 36 | * @return the specified tile, or <code>null</code> if the position is outside of the map |
| 29 | 37 | */ |
| 30 | 38 | public Tile getTile(int tilex, int tiley, int zoom) { |
| 31 | 39 | int max = 1 << zoom; |
| … |
… |
public class TileController {
|
| 37 | 45 | tileCache.addTile(tile); |
| 38 | 46 | tile.loadPlaceholderFromCache(tileCache); |
| 39 | 47 | } |
| 40 | | if (tile.error) { |
| | 48 | if (tile.hasError()) { |
| 41 | 49 | tile.loadPlaceholderFromCache(tileCache); |
| 42 | 50 | } |
| 43 | 51 | if (!tile.isLoaded()) { |
| … |
… |
public class TileController {
|
| 76 | 84 | |
| 77 | 85 | /** |
| 78 | 86 | * Removes all jobs from the queue that are currently not being processed. |
| 79 | | * |
| 80 | 87 | */ |
| 81 | 88 | public void cancelOutstandingJobs() { |
| 82 | 89 | tileLoader.cancelOutstandingTasks(); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/TileRange.java src/org/openstreetmap/gui/jmapviewer/TileRange.java
index 61c5f29..25b2eca 100644
|
|
|
public class TileRange {
|
| 41 | 41 | } |
| 42 | 42 | |
| 43 | 43 | protected double tilesSpanned() { |
| 44 | | return Math.sqrt(1.0 * this.size()); |
| | 44 | return Math.sqrt(size()); |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | 47 | /** |
| 48 | | * Returns size |
| 49 | | * @return size |
| 50 | | * @throws ArithmeticException – if the result overflows an int (see {@link Math#multiplyExact(int, int)}) |
| | 48 | * Returns the number of tiles in this range. |
| | 49 | * @return the number of tiles |
| | 50 | * @throws ArithmeticException if the result overflows an int (see {@link Math#multiplyExact(int, int)}) |
| 51 | 51 | */ |
| 52 | | public int size() throws ArithmeticException { |
| | 52 | public int size() { |
| 53 | 53 | int xSpan = maxX - minX + 1; |
| 54 | 54 | int ySpan = maxY - minY + 1; |
| 55 | 55 | return Math.multiplyExact(xSpan, ySpan); |
| 56 | 56 | } |
| 57 | 57 | } |
| 58 | | |
-
diff --git src/org/openstreetmap/gui/jmapviewer/TileXY.java src/org/openstreetmap/gui/jmapviewer/TileXY.java
index ca671cc..733d125 100644
|
|
|
|
| 2 | 2 | package org.openstreetmap.gui.jmapviewer; |
| 3 | 3 | |
| 4 | 4 | /** |
| 5 | | * @author w |
| | 5 | * Tile coordinates at a zoom level. They are fractional for points inside a tile. |
| 6 | 6 | * |
| | 7 | * @author w |
| 7 | 8 | */ |
| 8 | 9 | public class TileXY { |
| 9 | 10 | /** |
| … |
… |
public class TileXY {
|
| 17 | 18 | private final double y; |
| 18 | 19 | |
| 19 | 20 | /** |
| 20 | | * Returns an instance of coordinates. |
| | 21 | * Constructs a new {@code TileXY}. |
| 21 | 22 | * |
| 22 | 23 | * @param x number of the tile |
| 23 | 24 | * @param y number of the tile |
| … |
… |
public class TileXY {
|
| 28 | 29 | } |
| 29 | 30 | |
| 30 | 31 | /** |
| 31 | | * @return x index of the tile as integer |
| | 32 | * @return x index of the tile as integer, rounded towards zero |
| 32 | 33 | */ |
| 33 | 34 | public int getXIndex() { |
| 34 | | return x < 0 ? (int) Math.ceil(x) : (int) Math.floor(x); |
| | 35 | return (int) x; |
| 35 | 36 | } |
| 36 | 37 | |
| 37 | 38 | /** |
| 38 | | * @return y index of the tile as integer |
| | 39 | * @return y index of the tile as integer, rounded towards zero |
| 39 | 40 | */ |
| 40 | 41 | public int getYIndex() { |
| 41 | | return y < 0 ? (int) Math.ceil(y) : (int) Math.floor(y); |
| | 42 | return (int) y; |
| 42 | 43 | } |
| 43 | 44 | |
| 44 | 45 | /** |
-
diff --git src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java
index c12645a..f2d908f 100644
|
|
|
import javax.swing.tree.TreePath;
|
| 19 | 19 | * @author galo |
| 20 | 20 | */ |
| 21 | 21 | public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor { |
| 22 | | /** SerialVersionUID */ |
| | 22 | // Java 14: annotate with @Serial |
| 23 | 23 | private static final long serialVersionUID = -8921320784224636657L; |
| 24 | 24 | |
| 25 | 25 | private final CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer(); |
| … |
… |
public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEd
|
| 32 | 32 | |
| 33 | 33 | @Override |
| 34 | 34 | public Object getCellEditorValue() { |
| 35 | | final CheckBoxNodePanel panel = renderer.getPanel(); |
| 36 | | /*final CheckBoxNodeData checkBoxNode = |
| 37 | | new CheckBoxNodeData(panel.label.getText(), panel.check.isSelected()); |
| 38 | | return checkBoxNode; |
| 39 | | CheckBoxNodeData data = search(theTree.rootNode(), panel.label.getText()); |
| 40 | | data.setSelected(panel.check.isSelected());*/ |
| 41 | | return panel.getData(); |
| | 35 | return renderer.getPanel().getData(); |
| 42 | 36 | } |
| 43 | | /*public CheckBoxNodeData search(DefaultMutableTreeNode node, String name){ |
| 44 | | CheckBoxNodeData data = CheckBoxTree.data(node); |
| 45 | | if(data.getText().equals(name)) return data; |
| 46 | | else{ |
| 47 | | data = null; |
| 48 | | for(int i=0; i<node.getChildCount() && data==null; i++){ |
| 49 | | data = search((DefaultMutableTreeNode)node.getChildAt(i), name); |
| 50 | | } |
| 51 | | return data; |
| 52 | | } |
| 53 | | }*/ |
| 54 | 37 | |
| 55 | 38 | public void addNodeListener(MouseAdapter listener) { |
| 56 | 39 | renderer.addNodeListener(listener); |
| … |
… |
public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEd
|
| 58 | 41 | |
| 59 | 42 | @Override |
| 60 | 43 | public boolean isCellEditable(final EventObject event) { |
| | 44 | // Java 16: use instanceof pattern matching instead of the casts |
| 61 | 45 | if (!(event instanceof MouseEvent)) return false; |
| 62 | 46 | final MouseEvent mouseEvent = (MouseEvent) event; |
| 63 | 47 | |
| … |
… |
public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEd
|
| 88 | 72 | fireEditingStopped(); |
| 89 | 73 | } |
| 90 | 74 | }; |
| | 75 | // Java 16: use instanceof pattern matching instead of the casts |
| 91 | 76 | if (editor instanceof CheckBoxNodePanel) { |
| 92 | 77 | final CheckBoxNodePanel panel = (CheckBoxNodePanel) editor; |
| 93 | 78 | panel.check.addItemListener(itemListener); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodePanel.java src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodePanel.java
index b55363e..b0e2378 100644
|
|
|
import javax.swing.JPanel;
|
| 14 | 14 | * @author galo |
| 15 | 15 | */ |
| 16 | 16 | public class CheckBoxNodePanel extends JPanel { |
| 17 | | /** Serial Version UID */ |
| | 17 | // Java 14: annotate with @Serial |
| 18 | 18 | private static final long serialVersionUID = -7236481597785619029L; |
| 19 | 19 | private final JLabel label = new JLabel(); |
| 20 | 20 | private CheckBoxNodeData data; |
| 21 | 21 | public final JCheckBox check = new JCheckBox(); |
| 22 | 22 | |
| | 23 | @SuppressWarnings("this-escape") |
| 23 | 24 | public CheckBoxNodePanel() { |
| 24 | | this.check.setMargin(new Insets(0, 0, 0, 0)); |
| | 25 | check.setMargin(new Insets(0, 0, 0, 0)); |
| 25 | 26 | setLayout(new BorderLayout()); |
| 26 | 27 | add(check, BorderLayout.WEST); |
| 27 | 28 | add(label, BorderLayout.CENTER); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeRenderer.java src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeRenderer.java
index 54e2642..817ec9c 100644
|
|
|
public class CheckBoxNodeRenderer implements TreeCellRenderer {
|
| 58 | 58 | final Object value, final boolean selected, final boolean expanded, |
| 59 | 59 | final boolean leaf, final int row, final boolean hasFocus) { |
| 60 | 60 | CheckBoxNodeData data = null; |
| | 61 | // Java 16: use instanceof pattern matching instead of the casts |
| 61 | 62 | if (value instanceof DefaultMutableTreeNode) { |
| 62 | 63 | final DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; |
| 63 | 64 | final Object userObject = node.getUserObject(); |
| … |
… |
public class CheckBoxNodeRenderer implements TreeCellRenderer {
|
| 66 | 67 | } |
| 67 | 68 | } |
| 68 | 69 | |
| 69 | | //final String stringValue = |
| 70 | | // tree.convertValueToText(value, selected, expanded, leaf, row, false); |
| 71 | | //panel.label.setText(stringValue); |
| 72 | | |
| 73 | 70 | panel.setSelected(Boolean.FALSE); |
| 74 | 71 | |
| 75 | 72 | panel.setEnabled(tree.isEnabled()); |
| … |
… |
public class CheckBoxNodeRenderer implements TreeCellRenderer {
|
| 92 | 89 | selected, expanded, leaf, row, hasFocus); |
| 93 | 90 | } |
| 94 | 91 | |
| 95 | | //panel.label.setText(data.getText()); |
| 96 | 92 | panel.setData(data); |
| 97 | 93 | panel.setSelected(data.isSelected()); |
| 98 | 94 | |
| 99 | 95 | return panel; |
| 100 | 96 | } |
| 101 | | /* |
| 102 | | private JPopupMenu createPopupMenu(final AbstractLayer layer) { |
| 103 | | JMenuItem menuItem; |
| 104 | | |
| 105 | | //Create the popup menu. |
| 106 | | if (layer.isVisibleTexts()) menuItem = new JMenuItem("hide texts"); |
| 107 | | else menuItem = new JMenuItem("show texts"); |
| 108 | | JPopupMenu popup = new JPopupMenu(); |
| 109 | | popup.add(menuItem); |
| 110 | | menuItem.addActionListener(new ActionListener(){ |
| 111 | | @Override |
| 112 | | public void actionPerformed(ActionEvent arg0) { |
| 113 | | setVisibleTexts(layer, !layer.isVisibleTexts()); |
| 114 | | } |
| 115 | | }); |
| 116 | | |
| 117 | | return popup; |
| 118 | | } |
| 119 | | |
| 120 | | private void setVisibleTexts(AbstractLayer layer, boolean visible) { |
| 121 | | layer.setVisibleTexts(visible); |
| 122 | | if (layer instanceof LayerGroup) { |
| 123 | | LayerGroup group = (LayerGroup) layer; |
| 124 | | if (group.getLayers() != null) |
| 125 | | for (AbstractLayer al : group.getLayers()) { |
| 126 | | setVisibleTexts(al, visible); |
| 127 | | } |
| 128 | | } |
| 129 | | } |
| 130 | | */ |
| 131 | 97 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxTree.java src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxTree.java
index 261a15e..21bd428 100644
|
|
|
|
| 1 | 1 | // License: GPL. For details, see Readme.txt file. |
| 2 | 2 | package org.openstreetmap.gui.jmapviewer.checkBoxTree; |
| 3 | 3 | |
| 4 | | import java.awt.BorderLayout; |
| 5 | 4 | import java.awt.event.MouseAdapter; |
| 6 | 5 | import java.util.Objects; |
| 7 | 6 | |
| 8 | | import javax.swing.JFrame; |
| 9 | | import javax.swing.JScrollPane; |
| 10 | 7 | import javax.swing.JTree; |
| 11 | 8 | import javax.swing.event.TreeModelEvent; |
| 12 | 9 | import javax.swing.event.TreeModelListener; |
| … |
… |
import org.openstreetmap.gui.jmapviewer.LayerGroup;
|
| 23 | 20 | * @author galo |
| 24 | 21 | */ |
| 25 | 22 | public class CheckBoxTree extends JTree { |
| 26 | | /** Serial Version UID */ |
| | 23 | // Java 14: annotate with @Serial |
| 27 | 24 | private static final long serialVersionUID = 6943401106938034256L; |
| 28 | 25 | |
| 29 | 26 | private final CheckBoxNodeEditor editor; |
| … |
… |
public class CheckBoxTree extends JTree {
|
| 40 | 37 | this(new DefaultMutableTreeNode(root)); |
| 41 | 38 | } |
| 42 | 39 | |
| | 40 | @SuppressWarnings("this-escape") |
| 43 | 41 | public CheckBoxTree(DefaultMutableTreeNode node) { |
| 44 | 42 | super(new DefaultTreeModel(node)); |
| 45 | 43 | |
| … |
… |
public class CheckBoxTree extends JTree {
|
| 68 | 66 | |
| 69 | 67 | @Override |
| 70 | 68 | public void treeNodesInserted(final TreeModelEvent e) { |
| 71 | | //System.out.println("nodes inserted"); |
| | 69 | // Nothing to do |
| 72 | 70 | } |
| 73 | 71 | |
| 74 | 72 | @Override |
| 75 | 73 | public void treeNodesRemoved(final TreeModelEvent e) { |
| 76 | | //System.out.println("nodes removed"); |
| | 74 | // Nothing to do |
| 77 | 75 | } |
| 78 | 76 | |
| 79 | 77 | @Override |
| 80 | 78 | public void treeStructureChanged(final TreeModelEvent e) { |
| 81 | | //System.out.println("structure changed"); |
| | 79 | // Nothing to do |
| 82 | 80 | } |
| 83 | 81 | }); |
| 84 | 82 | } |
| … |
… |
public class CheckBoxTree extends JTree {
|
| 87 | 85 | editor.addNodeListener(listener); |
| 88 | 86 | } |
| 89 | 87 | |
| 90 | | public static void main(final String[] args) { |
| 91 | | final DefaultMutableTreeNode root = new DefaultMutableTreeNode(new CheckBoxNodeData("Root", Boolean.TRUE)); |
| 92 | | |
| 93 | | final DefaultMutableTreeNode accessibility = |
| 94 | | add(root, "Accessibility", true); |
| 95 | | add(accessibility, "Move system caret with focus/selection changes", false); |
| 96 | | add(accessibility, "Always expand alt text for images", true); |
| 97 | | root.add(accessibility); |
| 98 | | |
| 99 | | final DefaultMutableTreeNode browsing = |
| 100 | | new DefaultMutableTreeNode(new CheckBoxNodeData("Browsing", null)); |
| 101 | | add(browsing, "Notify when downloads complete", true); |
| 102 | | add(browsing, "Disable script debugging", true); |
| 103 | | add(browsing, "Use AutoComplete", true); |
| 104 | | add(browsing, "Browse in a new process", false); |
| 105 | | root.add(browsing); |
| 106 | | |
| 107 | | final CheckBoxTree tree = new CheckBoxTree(root); |
| 108 | | ((DefaultMutableTreeNode) tree.getModel().getRoot()).add(new DefaultMutableTreeNode(new CheckBoxNodeData("gggg", null))); |
| 109 | | ((DefaultTreeModel) tree.getModel()).reload(); |
| 110 | | // show the tree on screen |
| 111 | | final JFrame frame = new JFrame("CheckBox Tree"); |
| 112 | | final JScrollPane scrollPane = new JScrollPane(tree); |
| 113 | | frame.getContentPane().add(scrollPane, BorderLayout.CENTER); |
| 114 | | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
| 115 | | frame.setSize(300, 150); |
| 116 | | frame.setVisible(true); |
| 117 | | } |
| 118 | | |
| 119 | 88 | private static Boolean childStatus(DefaultMutableTreeNode node) { |
| 120 | 89 | Boolean status = data(node.getChildAt(0)).isSelected(); |
| 121 | 90 | for (int i = 1; i < node.getChildCount() && status != null; i++) { |
| 122 | | if (!status.equals( |
| 123 | | data(node.getChildAt(i)).isSelected() |
| 124 | | )) |
| | 91 | if (!status.equals(data(node.getChildAt(i)).isSelected())) |
| 125 | 92 | return null; |
| 126 | 93 | } |
| 127 | 94 | return status; |
| … |
… |
public class CheckBoxTree extends JTree {
|
| 144 | 111 | private static void nodeChanged(DefaultMutableTreeNode node) { |
| 145 | 112 | if (node != null) { |
| 146 | 113 | changeParents(node); |
| 147 | | setChildrens(node, data(node).isSelected()); |
| | 114 | setChildrens(node); |
| 148 | 115 | } |
| 149 | 116 | } |
| 150 | 117 | |
| 151 | | private static void setChildrens(DefaultMutableTreeNode node, Boolean value) { |
| | 118 | private static void setChildrens(DefaultMutableTreeNode node) { |
| 152 | 119 | for (int i = 0; i < node.getChildCount(); i++) { |
| 153 | 120 | DefaultMutableTreeNode childNode = node(node.getChildAt(i)); |
| 154 | 121 | // Fix NPE from #20557 |
| … |
… |
public class CheckBoxTree extends JTree {
|
| 156 | 123 | final CheckBoxNodeData nodeData = data(node); |
| 157 | 124 | if (childData != null && nodeData != null && |
| 158 | 125 | !Objects.equals(childData.isSelected(), nodeData.isSelected())) { |
| 159 | | data(childNode).setSelected(data(node).isSelected()); |
| 160 | | setChildrens(childNode, value); |
| | 126 | childData.setSelected(nodeData.isSelected()); |
| | 127 | setChildrens(childNode); |
| 161 | 128 | } |
| 162 | 129 | } |
| 163 | 130 | } |
| … |
… |
public class CheckBoxTree extends JTree {
|
| 186 | 153 | return data(node(node)); |
| 187 | 154 | } |
| 188 | 155 | |
| 189 | | private static DefaultMutableTreeNode add(final DefaultMutableTreeNode parent, final String text, final boolean checked) { |
| 190 | | final CheckBoxNodeData data = new CheckBoxNodeData(text, checked); |
| 191 | | final DefaultMutableTreeNode node = new DefaultMutableTreeNode(data); |
| 192 | | parent.add(node); |
| 193 | | return node; |
| 194 | | } |
| 195 | | |
| 196 | 156 | public static CheckBoxNodeData createNodeData(AbstractLayer layer) { |
| 197 | 157 | return new CheckBoxNodeData(layer); |
| 198 | 158 | } |
| … |
… |
public class CheckBoxTree extends JTree {
|
| 201 | 161 | return new DefaultMutableTreeNode(createNodeData(layer)); |
| 202 | 162 | } |
| 203 | 163 | |
| 204 | | /*public DefaultMutableTreeNode addLayerGroup(LayerGroup group) { |
| 205 | | if (group != null){ |
| 206 | | if (group.getParent() == null){ |
| 207 | | return add(rootNode(), group); |
| 208 | | } else { |
| 209 | | DefaultMutableTreeNode parentGroup = searchNode(group.getParent()); |
| 210 | | if(parentGroup==null) parentGroup = addLayerGroup(group.getParent()); |
| 211 | | DefaultMutableTreeNode node = add(parentGroup, group); |
| 212 | | return node; |
| 213 | | } |
| 214 | | }else return null; |
| 215 | | }*/ |
| 216 | | |
| 217 | 164 | public Layer addLayer(String name) { |
| 218 | 165 | Layer layer = new Layer(name); |
| 219 | 166 | addLayer(layer); |
| … |
… |
public class CheckBoxTree extends JTree {
|
| 240 | 187 | DefaultMutableTreeNode node = createNode(layer); |
| 241 | 188 | parent.add(node); |
| 242 | 189 | ((DefaultTreeModel) getModel()).reload(); |
| 243 | | //System.out.println("Created node "+layer+" upper of "+data(parent)); |
| 244 | 190 | return node; |
| 245 | 191 | } |
| 246 | 192 | |
| … |
… |
public class CheckBoxTree extends JTree {
|
| 249 | 195 | } |
| 250 | 196 | |
| 251 | 197 | public DefaultMutableTreeNode searchNode(DefaultMutableTreeNode node, AbstractLayer layer) { |
| 252 | | CheckBoxNodeData data = CheckBoxTree.data(node); |
| | 198 | CheckBoxNodeData data = data(node); |
| 253 | 199 | if (data.getAbstractLayer() == layer) return node; |
| 254 | 200 | else { |
| 255 | 201 | DefaultMutableTreeNode found = null; |
-
diff --git src/org/openstreetmap/gui/jmapviewer/events/JMVCommandEvent.java src/org/openstreetmap/gui/jmapviewer/events/JMVCommandEvent.java
index 271187f..46df730 100644
|
|
|
import java.util.EventObject;
|
| 8 | 8 | * objects that register as a JMapViewerEventListener |
| 9 | 9 | * |
| 10 | 10 | * @author Jason Huntley |
| 11 | | * |
| 12 | 11 | */ |
| 13 | 12 | public class JMVCommandEvent extends EventObject { |
| 14 | 13 | public enum COMMAND { |
| … |
… |
public class JMVCommandEvent extends EventObject {
|
| 16 | 15 | ZOOM |
| 17 | 16 | } |
| 18 | 17 | |
| 19 | | /** |
| 20 | | * |
| 21 | | */ |
| | 18 | // Java 14: annotate with @Serial |
| 22 | 19 | private static final long serialVersionUID = 8701544867914969620L; |
| 23 | 20 | |
| 24 | 21 | private COMMAND command; |
| 25 | 22 | |
| | 23 | /** |
| | 24 | * Constructs a new {@code JMVCommandEvent}. |
| | 25 | * @param cmd the command |
| | 26 | * @param source the object on which the event initially occurred |
| | 27 | */ |
| | 28 | @SuppressWarnings("this-escape") |
| 26 | 29 | public JMVCommandEvent(COMMAND cmd, Object source) { |
| 27 | 30 | super(source); |
| 28 | | |
| 29 | 31 | setCommand(cmd); |
| 30 | 32 | } |
| 31 | 33 | |
-
diff --git src/org/openstreetmap/gui/jmapviewer/interfaces/Attributed.java src/org/openstreetmap/gui/jmapviewer/interfaces/Attributed.java
index eb7e955..9163a46 100644
|
|
|
package org.openstreetmap.gui.jmapviewer.interfaces;
|
| 3 | 3 | |
| 4 | 4 | import java.awt.Image; |
| 5 | 5 | |
| | 6 | /** |
| | 7 | * Attribution information that has to be shown together with the data of a source. |
| | 8 | */ |
| 6 | 9 | public interface Attributed { |
| 7 | 10 | /** |
| 8 | 11 | * @return True if the tile source requires attribution in text or image form. |
| … |
… |
public interface Attributed {
|
| 23 | 26 | String getAttributionLinkURL(); |
| 24 | 27 | |
| 25 | 28 | /** |
| 26 | | * @return The URL for the attribution image. Null if no image should be displayed. |
| | 29 | * @return The attribution image. Null if no image should be displayed. |
| 27 | 30 | */ |
| 28 | 31 | Image getAttributionImage(); |
| 29 | 32 | |
-
diff --git src/org/openstreetmap/gui/jmapviewer/interfaces/MapRectangle.java src/org/openstreetmap/gui/jmapviewer/interfaces/MapRectangle.java
index 45bc5a3..95b28dd 100644
|
|
|
public interface MapRectangle extends MapObject {
|
| 31 | 31 | * <code>bottomRight</code> are specifying the coordinates within <code>g</code> |
| 32 | 32 | * |
| 33 | 33 | * @param g graphics structure for painting |
| 34 | | * @param topLeft lop left edge of painting region |
| | 34 | * @param topLeft top left edge of painting region |
| 35 | 35 | * @param bottomRight bottom right edge of painting region |
| 36 | 36 | */ |
| 37 | 37 | void paint(Graphics g, Point topLeft, Point bottomRight); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/interfaces/TemplatedTileSource.java src/org/openstreetmap/gui/jmapviewer/interfaces/TemplatedTileSource.java
index 1037c9f..b405972 100644
|
|
|
package org.openstreetmap.gui.jmapviewer.interfaces;
|
| 4 | 4 | import java.util.Map; |
| 5 | 5 | |
| 6 | 6 | /** |
| 7 | | * Interface for template tile sources, @see TemplatedTMSTileSource |
| | 7 | * Interface for template tile sources, see {@link org.openstreetmap.gui.jmapviewer.tilesources.TemplatedTMSTileSource}. |
| 8 | 8 | * |
| 9 | 9 | * @author Wiktor Niesiobędzki |
| 10 | 10 | * @since 1.10 |
| 11 | 11 | */ |
| 12 | 12 | public interface TemplatedTileSource extends TileSource { |
| 13 | 13 | /** |
| 14 | | * |
| 15 | 14 | * @return headers to be sent with http requests |
| 16 | 15 | */ |
| 17 | 16 | Map<String, String> getHeaders(); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java
index 7ea76ae..7827b65 100644
|
|
|
public interface TileCache {
|
| 39 | 39 | void addTile(Tile tile); |
| 40 | 40 | |
| 41 | 41 | /** |
| 42 | | * @return the number of tiles hold by the cache |
| | 42 | * @return the number of tiles held by the cache |
| 43 | 43 | */ |
| 44 | 44 | int getTileCount(); |
| 45 | 45 | |
| … |
… |
public interface TileCache {
|
| 53 | 53 | * This is implementation specific; the default calls {@link #clear()}. |
| 54 | 54 | */ |
| 55 | 55 | default void clearErrorTiles() { |
| 56 | | this.clear(); |
| | 56 | clear(); |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | 59 | /** |
-
diff --git src/org/openstreetmap/gui/jmapviewer/interfaces/TileJob.java src/org/openstreetmap/gui/jmapviewer/interfaces/TileJob.java
index 925c5ba..210ad57 100644
|
|
|
package org.openstreetmap.gui.jmapviewer.interfaces;
|
| 10 | 10 | public interface TileJob extends Runnable { |
| 11 | 11 | |
| 12 | 12 | /** |
| 13 | | * submits download job to backend. |
| | 13 | * Submits the download job to the backend. |
| 14 | 14 | */ |
| 15 | 15 | void submit(); |
| 16 | 16 | |
| 17 | 17 | /** |
| 18 | | * submits download job to backend. |
| | 18 | * Submits the download job to the backend. |
| 19 | 19 | * @param force true if the load should skip all the caches (local & remote) |
| 20 | 20 | */ |
| 21 | 21 | void submit(boolean force); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoader.java src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoader.java
index a4a58cb..5e9627e 100644
|
|
|
public interface TileLoader {
|
| 22 | 22 | TileJob createTileLoaderJob(Tile tile); |
| 23 | 23 | |
| 24 | 24 | /** |
| 25 | | * cancels all outstanding tasks in the queue. This should rollback the state of the tiles in the queue |
| | 25 | * Cancels all outstanding tasks in the queue. This should rollback the state of the tiles in the queue |
| 26 | 26 | * to loading = false / loaded = false |
| 27 | 27 | */ |
| 28 | 28 | void cancelOutstandingTasks(); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java
index b88fd91..af53614 100644
|
|
|
public interface TileSource extends Attributed {
|
| 97 | 97 | double getDistance(double la1, double lo1, double la2, double lo2); |
| 98 | 98 | |
| 99 | 99 | /** |
| 100 | | * Transforms longitude and latitude to pixel space (as if all tiles at specified zoom level where joined). |
| 101 | | * @param lon longitude |
| | 100 | * Transforms longitude and latitude to pixel space (as if all tiles at specified zoom level were joined). |
| 102 | 101 | * @param lat latitude |
| | 102 | * @param lon longitude |
| 103 | 103 | * @param zoom zoom level |
| 104 | 104 | * @return the pixel coordinates |
| 105 | 105 | */ |
| 106 | 106 | Point latLonToXY(double lat, double lon, int zoom); |
| 107 | 107 | |
| 108 | 108 | /** |
| 109 | | * Transforms longitude and latitude to pixel space (as if all tiles at specified zoom level where joined). |
| | 109 | * Transforms longitude and latitude to pixel space (as if all tiles at specified zoom level were joined). |
| 110 | 110 | * @param point point |
| 111 | 111 | * @param zoom zoom level |
| 112 | 112 | * @return the pixel coordinates |
| … |
… |
public interface TileSource extends Attributed {
|
| 136 | 136 | |
| 137 | 137 | /** |
| 138 | 138 | * Transforms longitude and latitude to tile indices. |
| 139 | | * @param lon longitude |
| 140 | 139 | * @param lat latitude |
| | 140 | * @param lon longitude |
| 141 | 141 | * @param zoom zoom level |
| 142 | 142 | * @return x and y tile indices |
| 143 | 143 | */ |
| … |
… |
public interface TileSource extends Attributed {
|
| 164 | 164 | } |
| 165 | 165 | |
| 166 | 166 | /** |
| 167 | | * Determines to longitude and latitude of a tile. |
| | 167 | * Determines the longitude and latitude of a tile. |
| 168 | 168 | * (Refers to the tile origin - upper left tile corner) |
| 169 | 169 | * @param tile Tile |
| 170 | 170 | * @return WGS84 coordinates of given tile |
| … |
… |
public interface TileSource extends Attributed {
|
| 204 | 204 | int getTileYMax(int zoom); |
| 205 | 205 | |
| 206 | 206 | /** |
| 207 | | * Get minimum y index of tile for specified zoom level |
| | 207 | * Get minimum y index of tile for specified zoom level. |
| 208 | 208 | * @param zoom zoom level |
| 209 | 209 | * @return minimum y index of tile for specified zoom level |
| 210 | 210 | */ |
| … |
… |
public interface TileSource extends Attributed {
|
| 212 | 212 | |
| 213 | 213 | /** |
| 214 | 214 | * Determines, if the returned data from TileSource represent "no tile at this zoom level" situation. Detection |
| 215 | | * algorithms differ per TileSource, so each TileSource should implement each own specific way. |
| | 215 | * algorithms differ per TileSource, so each TileSource should implement its own specific way. |
| 216 | 216 | * |
| 217 | 217 | * @param headers HTTP headers from response from TileSource server |
| 218 | 218 | * @param statusCode HTTP status code |
| … |
… |
public interface TileSource extends Attributed {
|
| 232 | 232 | /** |
| 233 | 233 | * Convert tile indices (x/y/zoom) into projected coordinates of the tile origin. |
| 234 | 234 | * @param x x tile index |
| 235 | | * @param y z tile index |
| | 235 | * @param y y tile index |
| 236 | 236 | * @param zoom zoom level |
| 237 | 237 | * @return projected coordinates of the tile origin |
| 238 | 238 | */ |
-
diff --git src/org/openstreetmap/gui/jmapviewer/package.html src/org/openstreetmap/gui/jmapviewer/package.html
index 37540a6..420ec87 100644
|
|
|
|
| 1 | 1 | <html> |
| 2 | 2 | <head><title>org.openstreetmap.gui.jmapviewer</title></head> |
| 3 | 3 | <body> |
| 4 | | <p>This package and all sub-packages are belonging to the Java |
| 5 | | component <a href="http://wiki.openstreetmap.org/wiki/JMapViewer">JMapViewer</a> |
| | 4 | <p>This package and all its sub-packages belong to the Java |
| | 5 | component <a href="https://wiki.openstreetmap.org/wiki/JMapViewer">JMapViewer</a>. |
| 6 | 6 | </p> |
| 7 | | <p>JMapViewer is designed to run as stand-alone component without |
| | 7 | <p>JMapViewer is designed to run as a stand-alone component without |
| 8 | 8 | any further requirements. Therefore <b>please do not add any code that |
| 9 | | depends on other libraries or applications</b>. Only functions and methods |
| 10 | | provided by the runtime library of Java 8 should be used.</p> |
| | 9 | depends on other libraries or applications</b>. Only the Java 11 modules |
| | 10 | <code>java.desktop</code> and <code>java.logging</code> should be used.</p> |
| 11 | 11 | </body> |
| 12 | 12 | </html> |
-
diff --git src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java
index 49976f3..9230046 100644
|
|
|
public abstract class AbstractOsmTileSource extends TMSTileSource {
|
| 23 | 23 | * @param id unique id for the tile source; contains only characters that |
| 24 | 24 | * are safe for file names; can be null |
| 25 | 25 | */ |
| 26 | | public AbstractOsmTileSource(String name, String baseUrl, String id) { |
| | 26 | protected AbstractOsmTileSource(String name, String baseUrl, String id) { |
| 27 | 27 | super(new TileSourceInfo(name, baseUrl, id)); |
| 28 | 28 | } |
| 29 | 29 | |
-
diff --git src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java
index 89dd0d8..5626e68 100644
|
|
|
import org.openstreetmap.gui.jmapviewer.OsmMercator;
|
| 19 | 19 | * Class generalizing all tile based tile sources |
| 20 | 20 | * |
| 21 | 21 | * @author Wiktor Niesiobędzki |
| 22 | | * |
| 23 | 22 | */ |
| 24 | 23 | public abstract class AbstractTMSTileSource extends AbstractTileSource { |
| 25 | 24 | |
| … |
… |
public abstract class AbstractTMSTileSource extends AbstractTileSource {
|
| 56 | 55 | */ |
| 57 | 56 | @Override |
| 58 | 57 | public int getDefaultTileSize() { |
| 59 | | return OsmMercator.DEFAUL_TILE_SIZE; |
| | 58 | return OsmMercator.DEFAULT_TILE_SIZE; |
| 60 | 59 | } |
| 61 | 60 | |
| 62 | 61 | @Override |
| … |
… |
public abstract class AbstractTMSTileSource extends AbstractTileSource {
|
| 92 | 91 | * @param tilex tile number in x axis |
| 93 | 92 | * @param tiley tile number in y axis |
| 94 | 93 | * @return String containing path part of URL of the tile |
| 95 | | * @throws IOException when subclass cannot return the tile URL |
| 96 | 94 | */ |
| 97 | | public String getTilePath(int zoom, int tilex, int tiley) throws IOException { |
| | 95 | public String getTilePath(int zoom, int tilex, int tiley) { |
| 98 | 96 | return "/" + zoom + "/" + tilex + "/" + tiley + "." + getExtension(); |
| 99 | 97 | } |
| 100 | 98 | |
| … |
… |
public abstract class AbstractTMSTileSource extends AbstractTileSource {
|
| 107 | 105 | |
| 108 | 106 | @Override |
| 109 | 107 | public String getTileUrl(int zoom, int tilex, int tiley) throws IOException { |
| 110 | | return this.getBaseUrl() + getTilePath(zoom, tilex, tiley); |
| | 108 | return getBaseUrl() + getTilePath(zoom, tilex, tiley); |
| 111 | 109 | } |
| 112 | 110 | |
| 113 | 111 | @Override |
| … |
… |
public abstract class AbstractTMSTileSource extends AbstractTileSource {
|
| 115 | 113 | return getName(); |
| 116 | 114 | } |
| 117 | 115 | |
| 118 | | /* |
| 119 | | * Most tilesources use OsmMercator projection. |
| 120 | | */ |
| 121 | 116 | @Override |
| 122 | 117 | public int getTileSize() { |
| 123 | 118 | if (tileSize <= 0) { |
| … |
… |
public abstract class AbstractTMSTileSource extends AbstractTileSource {
|
| 168 | 163 | try { |
| 169 | 164 | md = MessageDigest.getInstance(searchEntry.getKey()); |
| 170 | 165 | } catch (NoSuchAlgorithmException e) { |
| 171 | | FeatureAdapter.getLogger(this.getClass()).log(Level.FINER, searchEntry.getKey() + " algorithm was not found", e); |
| 172 | | break; |
| 173 | | } |
| 174 | | byte[] byteDigest = md.digest(content); |
| 175 | | final int len = byteDigest.length; |
| 176 | | |
| 177 | | char[] hexChars = new char[len * 2]; |
| 178 | | int j = 0; |
| 179 | | for (final int v : byteDigest) { |
| 180 | | int vn = (v & 0xf0) >> 4; |
| 181 | | hexChars[j++] = (char) (vn + (vn >= 10 ? ('a' - 10) : '0')); |
| 182 | | vn = (v & 0xf); |
| 183 | | hexChars[j++] = (char) (vn + (vn >= 10 ? ('a' - 10) : '0')); |
| | 166 | FeatureAdapter.getLogger(getClass()).log(Level.FINER, searchEntry.getKey() + " algorithm was not found", e); |
| | 167 | // the checksums of the other algorithms can still match |
| | 168 | continue; |
| 184 | 169 | } |
| | 170 | String digest = toHex(md.digest(content)); |
| 185 | 171 | for (String val: searchEntry.getValue()) { |
| 186 | | if (new String(hexChars).equalsIgnoreCase(val)) { |
| | 172 | if (digest.equalsIgnoreCase(val)) { |
| 187 | 173 | return true; |
| 188 | 174 | } |
| 189 | 175 | } |
| … |
… |
public abstract class AbstractTMSTileSource extends AbstractTileSource {
|
| 210 | 196 | |
| 211 | 197 | @Override |
| 212 | 198 | public String getTileId(int zoom, int tilex, int tiley) { |
| 213 | | return this.baseUrl + "/" + zoom + "/" + tilex + "/" + tiley; |
| | 199 | return baseUrl + "/" + zoom + "/" + tilex + "/" + tiley; |
| 214 | 200 | } |
| 215 | 201 | |
| 216 | 202 | @Override |
| … |
… |
public abstract class AbstractTMSTileSource extends AbstractTileSource {
|
| 218 | 204 | return modTileFeatures; |
| 219 | 205 | } |
| 220 | 206 | |
| | 207 | /** |
| | 208 | * Encodes bytes as lower case hexadecimal digits. |
| | 209 | * @param bytes the bytes to encode |
| | 210 | * @return two hexadecimal digits per byte |
| | 211 | */ |
| | 212 | // Java 17: replace with java.util.HexFormat.of().formatHex(bytes) |
| | 213 | private static String toHex(byte[] bytes) { |
| | 214 | char[] hexChars = new char[bytes.length * 2]; |
| | 215 | int j = 0; |
| | 216 | for (byte b : bytes) { |
| | 217 | hexChars[j++] = Character.forDigit((b >> 4) & 0xf, 16); |
| | 218 | hexChars[j++] = Character.forDigit(b & 0xf, 16); |
| | 219 | } |
| | 220 | return new String(hexChars); |
| | 221 | } |
| | 222 | |
| 221 | 223 | private static int getTileMax(int zoom) { |
| 222 | 224 | return (int) Math.pow(2.0, zoom) - 1; |
| 223 | 225 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java
index 6a93554..d9502c2 100644
|
|
|
import java.util.Map;
|
| 8 | 8 | import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; |
| 9 | 9 | import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; |
| 10 | 10 | |
| | 11 | /** |
| | 12 | * Base class for tile sources, which holds the attribution. |
| | 13 | */ |
| 11 | 14 | public abstract class AbstractTileSource implements TileSource { |
| 12 | 15 | |
| 13 | 16 | protected String attributionText; |
| … |
… |
public abstract class AbstractTileSource implements TileSource {
|
| 17 | 20 | protected String termsOfUseText; |
| 18 | 21 | protected String termsOfUseURL; |
| 19 | 22 | |
| | 23 | /** |
| | 24 | * Constructs a new {@code AbstractTileSource}. |
| | 25 | */ |
| | 26 | protected AbstractTileSource() { |
| | 27 | // Nothing to do |
| | 28 | } |
| | 29 | |
| 20 | 30 | @Override |
| 21 | 31 | public boolean requiresAttribution() { |
| 22 | 32 | return attributionText != null || attributionLinkURL != null || attributionImage != null |
-
diff --git src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
index 21ba10f..a89eb79 100644
|
|
|
package org.openstreetmap.gui.jmapviewer.tilesources;
|
| 3 | 3 | |
| 4 | 4 | import java.awt.Image; |
| 5 | 5 | import java.io.IOException; |
| | 6 | import java.io.InputStream; |
| 6 | 7 | import java.net.MalformedURLException; |
| 7 | 8 | import java.net.URI; |
| 8 | 9 | import java.net.URISyntaxException; |
| … |
… |
import java.util.concurrent.FutureTask;
|
| 17 | 18 | import java.util.concurrent.TimeUnit; |
| 18 | 19 | import java.util.logging.Level; |
| 19 | 20 | import java.util.logging.Logger; |
| 20 | | import java.util.regex.Pattern; |
| 21 | 21 | import java.util.stream.Collectors; |
| 22 | 22 | |
| 23 | 23 | import javax.xml.XMLConstants; |
| … |
… |
public class BingAerialTileSource extends TMSTileSource {
|
| 65 | 65 | /** Original Bing API key created by Potlatch2 developers in 2010 */ |
| 66 | 66 | private static final String API_KEY = "Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU"; |
| 67 | 67 | |
| 68 | | private static final Pattern PATTERN_SUBDOMAIN = Pattern.compile("\\{subdomain}"); |
| 69 | | private static final Pattern PATTERN_QUADKEY = Pattern.compile("\\{quadkey}"); |
| 70 | | private static final Pattern PATTERN_CULTURE = Pattern.compile("\\{culture}"); |
| 71 | | |
| 72 | 68 | private volatile Future<List<Attribution>> attributions; // volatile is required for getAttribution(), see below. |
| 73 | 69 | private String imageUrlTemplate; |
| 74 | 70 | private int imageryZoomMax = Integer.MIN_VALUE; |
| … |
… |
public class BingAerialTileSource extends TMSTileSource {
|
| 92 | 88 | super(info); |
| 93 | 89 | } |
| 94 | 90 | |
| | 91 | /** |
| | 92 | * The attribution of an imagery provider in an area, for a range of zoom levels. |
| | 93 | */ |
| 95 | 94 | protected static class Attribution { |
| 96 | 95 | private String attributionText; |
| 97 | 96 | private int minZoom; |
| 98 | 97 | private int maxZoom; |
| 99 | 98 | private Coordinate min; |
| 100 | 99 | private Coordinate max; |
| | 100 | |
| | 101 | /** |
| | 102 | * Constructs a new {@code Attribution}. |
| | 103 | */ |
| | 104 | protected Attribution() { |
| | 105 | // Filled in by the parser |
| | 106 | } |
| 101 | 107 | } |
| 102 | 108 | |
| 103 | 109 | @Override |
| … |
… |
public class BingAerialTileSource extends TMSTileSource {
|
| 106 | 112 | if (getAttribution() == null) |
| 107 | 113 | throw new IOException("Attribution is not loaded yet"); |
| 108 | 114 | |
| 109 | | int t = (zoom + tilex + tiley) % subdomains.length; |
| 110 | | String subdomain = subdomains[t]; |
| 111 | | |
| 112 | | String url = imageUrlTemplate; |
| 113 | | url = PATTERN_SUBDOMAIN.matcher(url).replaceAll(subdomain); |
| 114 | | url = PATTERN_QUADKEY.matcher(url).replaceAll(computeQuadTree(zoom, tilex, tiley)); |
| 115 | | |
| 116 | | return url; |
| | 115 | String subdomain = subdomains[(zoom + tilex + tiley) % subdomains.length]; |
| | 116 | return imageUrlTemplate |
| | 117 | .replace("{subdomain}", subdomain) |
| | 118 | .replace("{quadkey}", TemplatedTMSTileSource.xyzToQuadKey(tilex, tiley, zoom)); |
| 117 | 119 | } |
| 118 | 120 | |
| 119 | 121 | /** |
| … |
… |
public class BingAerialTileSource extends TMSTileSource {
|
| 132 | 134 | try { |
| 133 | 135 | return new URI(FeatureAdapter.getSetting(METADATA_API_SETTING, METADATA_API_URL) |
| 134 | 136 | .replace(API_KEY_PLACEHOLDER, getKey()) |
| 135 | | .replace(API_KEY_LAYER, this.layer)).toURL(); |
| | 137 | .replace(API_KEY_LAYER, layer)).toURL(); |
| 136 | 138 | } catch (URISyntaxException e) { |
| 137 | 139 | MalformedURLException malformedURLException = new MalformedURLException(e.getMessage()); |
| 138 | 140 | malformedURLException.initCause(e); |
| … |
… |
public class BingAerialTileSource extends TMSTileSource {
|
| 158 | 160 | String key = FeatureAdapter.getSetting(API_KEY_SETTING, API_KEY); |
| 159 | 161 | if (API_KEY.equals(key)) { // If the API key has not been customized, we try to retrieve the API key |
| 160 | 162 | try { |
| 161 | | String rkey = FeatureAdapter.retrieveApiKey(this.getId()); |
| | 163 | String rkey = FeatureAdapter.retrieveApiKey(getId()); |
| 162 | 164 | if (rkey != null) |
| 163 | 165 | key = rkey; |
| 164 | 166 | } catch (IOException ioException) { |
| 165 | | FeatureAdapter.getLogger(this.getClass()).log(Level.WARNING, "Failed to retrieve api key", ioException); |
| | 167 | LOG.log(Level.WARNING, "Failed to retrieve api key", ioException); |
| 166 | 168 | } |
| 167 | 169 | } |
| 168 | 170 | return key; |
| … |
… |
public class BingAerialTileSource extends TMSTileSource {
|
| 259 | 261 | if (imageResource != null) { |
| 260 | 262 | return FeatureAdapter.readImage(imageResource); |
| 261 | 263 | } else { |
| 262 | | // Some Linux distributions (like Debian) will remove Bing logo from sources, so get it at runtime |
| 263 | | for (int i = 0; i < 5 && (getAttribution() == null || getAttribution().isEmpty()); i++) { |
| 264 | | // Makes sure attribution is loaded |
| 265 | | if (JMapViewer.debug) { |
| 266 | | LOG.log(Level.FINE, "Bing attribution attempt {0}", (i + 1)); |
| 267 | | } |
| 268 | | } |
| | 264 | // Some Linux distributions (like Debian) will remove Bing logo from sources, so get it at runtime. |
| | 265 | // The logo URI is part of the attribution data, which this starts loading if it is not loaded yet. |
| | 266 | getAttribution(); |
| 269 | 267 | if (brandLogoUri != null && !brandLogoUri.isEmpty()) { |
| 270 | 268 | LOG.log(Level.FINE, "Reading Bing logo from {0}", brandLogoUri); |
| 271 | 269 | return FeatureAdapter.readImage(new URI(brandLogoUri)); |
| 272 | 270 | } |
| 273 | 271 | } |
| 274 | 272 | } catch (URISyntaxException | IOException e) { |
| 275 | | LOG.log(Level.SEVERE, String.format("Error while retrieving Bing logo: %s", e.getMessage())); |
| | 273 | LOG.log(Level.SEVERE, "Error while retrieving Bing logo: {0}", e.getMessage()); |
| 276 | 274 | } |
| 277 | 275 | return null; |
| 278 | 276 | } |
| … |
… |
public class BingAerialTileSource extends TMSTileSource {
|
| 296 | 294 | return () -> { |
| 297 | 295 | int waitTimeSec = 1; |
| 298 | 296 | while (true) { |
| 299 | | try { |
| 300 | | InputSource xml = new InputSource(getAttributionUrl().openStream()); |
| 301 | | List<Attribution> r = parseAttributionText(xml); |
| | 297 | try (InputStream in = getAttributionUrl().openStream()) { |
| | 298 | List<Attribution> r = parseAttributionText(new InputSource(in)); |
| 302 | 299 | LOG.log(Level.FINE, "Successfully loaded Bing attribution data."); |
| 303 | 300 | return r; |
| 304 | 301 | } catch (IllegalArgumentException | IOException ex) { |
| … |
… |
public class BingAerialTileSource extends TMSTileSource {
|
| 320 | 317 | // see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html |
| 321 | 318 | synchronized (BingAerialTileSource.class) { |
| 322 | 319 | if (attributions == null) { |
| 323 | | final FutureTask<List<Attribution>> loader = new FutureTask<>(getAttributionLoaderCallable()); |
| 324 | | new Thread(loader, "bing-attribution-loader").start(); |
| 325 | | attributions = loader; |
| | 320 | final FutureTask<List<Attribution>> loader = new FutureTask<>(getAttributionLoaderCallable()); |
| | 321 | new Thread(loader, "bing-attribution-loader").start(); |
| | 322 | attributions = loader; |
| 326 | 323 | } |
| 327 | 324 | } |
| 328 | 325 | } |
| … |
… |
public class BingAerialTileSource extends TMSTileSource {
|
| 361 | 358 | private void setImageUrlTemplate(String template) { |
| 362 | 359 | String noHttpTemplate = template.replace("http://ecn.{subdomain}.tiles.virtualearth.net/", |
| 363 | 360 | "https://ecn.{subdomain}.tiles.virtualearth.net/"); |
| 364 | | this.imageUrlTemplate = PATTERN_CULTURE.matcher(noHttpTemplate).replaceAll(Locale.getDefault().toString()); |
| | 361 | imageUrlTemplate = noHttpTemplate.replace("{culture}", Locale.getDefault().toString()); |
| 365 | 362 | } |
| 366 | 363 | |
| 367 | 364 | private void setImageryZoomMax(int maxZoom) { |
| … |
… |
public class BingAerialTileSource extends TMSTileSource {
|
| 374 | 371 | subdomains[i] = subdomainTxt.item(i).getNodeValue(); |
| 375 | 372 | } |
| 376 | 373 | } |
| 377 | | |
| 378 | | private static String computeQuadTree(int zoom, int tilex, int tiley) { |
| 379 | | StringBuilder k = new StringBuilder(); |
| 380 | | for (int i = zoom; i > 0; i--) { |
| 381 | | char digit = 48; |
| 382 | | int mask = 1 << (i - 1); |
| 383 | | if ((tilex & mask) != 0) { |
| 384 | | digit += (char) 1; |
| 385 | | } |
| 386 | | if ((tiley & mask) != 0) { |
| 387 | | digit += (char) 2; |
| 388 | | } |
| 389 | | k.append(digit); |
| 390 | | } |
| 391 | | return k.toString(); |
| 392 | | } |
| 393 | 374 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java
index 352e1d0..ed7cfc3 100644
|
|
|
import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
|
| 8 | 8 | /** |
| 9 | 9 | * OSM Tile source. |
| 10 | 10 | */ |
| 11 | | public class OsmTileSource { |
| | 11 | public final class OsmTileSource { |
| | 12 | |
| | 13 | private OsmTileSource() { |
| | 14 | // Hide default constructor for the holder of the tile source classes |
| | 15 | } |
| 12 | 16 | |
| 13 | 17 | /** |
| 14 | 18 | * The default "Mapnik" OSM tile source. |
| … |
… |
public class OsmTileSource {
|
| 31 | 35 | |
| 32 | 36 | @Override |
| 33 | 37 | public String getBaseUrl() { |
| 34 | | String url = String.format(this.baseUrl, SERVER[serverNum]); |
| | 38 | String url = String.format(baseUrl, SERVER[serverNum]); |
| 35 | 39 | serverNum = (serverNum + 1) % SERVER.length; |
| 36 | 40 | return url; |
| 37 | 41 | } |
| … |
… |
public class OsmTileSource {
|
| 57 | 61 | |
| 58 | 62 | @Override |
| 59 | 63 | public String getBaseUrl() { |
| 60 | | String url = String.format(this.baseUrl, SERVER[serverNum]); |
| | 64 | String url = String.format(baseUrl, SERVER[serverNum]); |
| 61 | 65 | serverNum = (serverNum + 1) % SERVER.length; |
| 62 | 66 | return url; |
| 63 | 67 | } |
| … |
… |
public class OsmTileSource {
|
| 77 | 81 | |
| 78 | 82 | @Override |
| 79 | 83 | public String getTileUrl(int zoom, int tilex, int tiley) throws IOException { |
| 80 | | return this.getBaseUrl() + getTilePath(zoom, tilex, tiley) + "?apikey=" + getApiKey(); |
| | 84 | return getBaseUrl() + getTilePath(zoom, tilex, tiley) + "?apikey=" + getApiKey(); |
| 81 | 85 | } |
| 82 | 86 | |
| 83 | 87 | @Override |
| … |
… |
public class OsmTileSource {
|
| 115 | 119 | |
| 116 | 120 | @Override |
| 117 | 121 | public String getAttributionLinkURL() { |
| 118 | | return "https://öpnvkarte.de/<"; |
| | 122 | return "https://öpnvkarte.de/"; |
| 119 | 123 | } |
| 120 | 124 | } |
| 121 | 125 | } |
-
diff --git src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java
index 49b573d..cddb8e2 100644
|
|
|
|
| 4 | 4 | package org.openstreetmap.gui.jmapviewer.tilesources; |
| 5 | 5 | |
| 6 | 6 | import java.awt.Point; |
| 7 | | import java.util.Random; |
| | 7 | import java.util.concurrent.ThreadLocalRandom; |
| 8 | 8 | |
| 9 | 9 | import org.openstreetmap.gui.jmapviewer.Coordinate; |
| 10 | 10 | import org.openstreetmap.gui.jmapviewer.OsmMercator; |
| … |
… |
import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
|
| 18 | 18 | * sphere in OsmMercator, so latitude calculation differs a lot. |
| 19 | 19 | * <p> |
| 20 | 20 | * The longitude calculation is the same as in OsmMercator, |
| 21 | | * we inherit it from AbstractTMSTileSource. |
| 22 | | * |
| 23 | | * TODO: correct getDistance() method. |
| | 21 | * we inherit it from TMSTileSource. |
| | 22 | * <p> |
| | 23 | * Note that {@link #getDistance(double, double, double, double)} is inherited as well, so it still |
| | 24 | * assumes a sphere. |
| 24 | 25 | */ |
| 25 | 26 | public class ScanexTileSource extends TMSTileSource { |
| 26 | 27 | private static final String DEFAULT_URL = "https://maps.kosmosnimki.ru"; |
| … |
… |
public class ScanexTileSource extends TMSTileSource {
|
| 28 | 29 | private static final String API_KEY = "4018C5A9AECAD8868ED5DEB2E41D09F7"; |
| 29 | 30 | |
| 30 | 31 | // Latitude to Y and back calculations. |
| 31 | | private static final double RADIUS_E = 6_378_137; /* radius of Earth at equator, m */ |
| 32 | | private static final double EQUATOR = 40075016.68557849; /* equator length, m */ |
| 33 | | private static final double E = 0.0818191908426; /* eccentricity of Earth's ellipsoid */ |
| | 32 | /** radius of Earth at equator, m */ |
| | 33 | private static final double RADIUS_E = 6_378_137; |
| | 34 | /** equator length, m */ |
| | 35 | private static final double EQUATOR = 40075016.68557849; |
| | 36 | /** eccentricity of Earth's ellipsoid */ |
| | 37 | private static final double E = 0.0818191908426; |
| 34 | 38 | |
| 35 | 39 | private enum ScanexLayer { |
| 36 | 40 | IRS("irs", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=BAC78D764F0443BD9AF93E7A998C9F5B"); |
| … |
… |
public class ScanexTileSource extends TMSTileSource {
|
| 74 | 78 | * thus is extraneous. But let it be there just in case if |
| 75 | 79 | * OsmMercator changes. |
| 76 | 80 | */ |
| 77 | | this.tileSize = 256; |
| | 81 | tileSize = 256; |
| 78 | 82 | |
| 79 | 83 | for (ScanexLayer slayer : ScanexLayer.values()) { |
| 80 | 84 | if (url.equalsIgnoreCase(slayer.getName())) { |
| 81 | | this.layer = slayer; |
| | 85 | layer = slayer; |
| 82 | 86 | // Override baseUrl and maxZoom in base class. |
| 83 | | this.baseUrl = DEFAULT_URL; |
| | 87 | baseUrl = DEFAULT_URL; |
| 84 | 88 | if (maxZoom == 0) |
| 85 | | this.maxZoom = DEFAULT_MAXZOOM; |
| | 89 | maxZoom = DEFAULT_MAXZOOM; |
| 86 | 90 | return; |
| 87 | 91 | } |
| 88 | 92 | } |
| 89 | | /* If not "irs" or "spot" keyword, then a custom URL. */ |
| 90 | | TemplatedTMSTileSource.checkUrl(info.getUrl()); |
| 91 | | this.templateSource = new TemplatedTMSTileSource(info); |
| | 93 | // If not the "irs" keyword, then a custom URL. |
| | 94 | TemplatedTMSTileSource.checkUrl(url); |
| | 95 | templateSource = new TemplatedTMSTileSource(info); |
| 92 | 96 | } |
| 93 | 97 | |
| 94 | 98 | @Override |
| … |
… |
public class ScanexTileSource extends TMSTileSource {
|
| 96 | 100 | return "jpeg"; |
| 97 | 101 | } |
| 98 | 102 | |
| 99 | | @Override |
| | 103 | @Override |
| 100 | 104 | public String getTileUrl(int zoom, int tilex, int tiley) { |
| 101 | | if (this.templateSource != null) |
| 102 | | return this.templateSource.getTileUrl(zoom, tilex, tiley); |
| | 105 | if (templateSource != null) |
| | 106 | return templateSource.getTileUrl(zoom, tilex, tiley); |
| 103 | 107 | else |
| 104 | | return this.getBaseUrl() + getTilePath(zoom, tilex, tiley); |
| | 108 | return getBaseUrl() + getTilePath(zoom, tilex, tiley); |
| 105 | 109 | } |
| 106 | 110 | |
| 107 | 111 | @Override |
| … |
… |
public class ScanexTileSource extends TMSTileSource {
|
| 111 | 115 | tilex = tilex - tmp; |
| 112 | 116 | tiley = tmp - tiley - 1; |
| 113 | 117 | |
| 114 | | return this.layer.getUri() + "&apikey=" + API_KEY + "&x=" + tilex + "&y=" + tiley + "&z=" + zoom; |
| | 118 | return layer.getUri() + "&apikey=" + API_KEY + "&x=" + tilex + "&y=" + tiley + "&z=" + zoom; |
| 115 | 119 | } |
| 116 | 120 | |
| 117 | 121 | @Override |
| … |
… |
public class ScanexTileSource extends TMSTileSource {
|
| 153 | 157 | return (EQUATOR/2 - (RADIUS_E * Math.log(tmp/pow))) * Math.pow(2.0, zoom) / EQUATOR; |
| 154 | 158 | } |
| 155 | 159 | |
| 156 | | /* |
| | 160 | /** |
| 157 | 161 | * To solve inverse formula latitude = f(y) we use |
| 158 | 162 | * Newton's method. We cache previous calculated latitude, |
| 159 | 163 | * because new one is usually close to the old one. In case |
| … |
… |
public class ScanexTileSource extends TMSTileSource {
|
| 166 | 170 | lat0 = lat; |
| 167 | 171 | lat = lat - Math.toDegrees(nextTerm(Math.toRadians(lat), y, zoom)); |
| 168 | 172 | if (lat > OsmMercator.MAX_LAT || lat < OsmMercator.MIN_LAT) { |
| 169 | | Random r = new Random(); |
| 170 | 173 | lat = OsmMercator.MIN_LAT + |
| 171 | | r.nextInt((int) (OsmMercator.MAX_LAT - OsmMercator.MIN_LAT)); |
| | 174 | ThreadLocalRandom.current().nextInt((int) (OsmMercator.MAX_LAT - OsmMercator.MIN_LAT)); |
| 172 | 175 | } |
| 173 | 176 | } while (Math.abs(lat0 - lat) > 0.000001); |
| 174 | 177 | |
| … |
… |
public class ScanexTileSource extends TMSTileSource {
|
| 177 | 180 | return lat; |
| 178 | 181 | } |
| 179 | 182 | |
| 180 | | /* Next term in Newton's polynomial */ |
| | 183 | /** Next term in Newton's polynomial */ |
| 181 | 184 | private static double nextTerm(double lat, double y, int zoom) { |
| 182 | 185 | double sinl = Math.sin(lat); |
| 183 | 186 | double cosl = Math.cos(lat); |
| 184 | 187 | |
| 185 | | zoom = (int) Math.pow(2.0, zoom - 1d); |
| 186 | | double ec = Math.exp((1 - y/zoom)*Math.PI); |
| | 188 | int halfTiles = (int) Math.pow(2.0, zoom - 1d); |
| | 189 | double ec = Math.exp((1 - y/halfTiles)*Math.PI); |
| 187 | 190 | |
| 188 | 191 | double f = Math.tan(Math.PI/4+lat/2) - |
| 189 | 192 | ec * Math.pow(Math.tan(Math.PI/4 + Math.asin(E * sinl)/2), E); |
-
diff --git src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java
index 09645d7..eb7fa99 100644
|
|
|
import org.openstreetmap.gui.jmapviewer.interfaces.IProjected;
|
| 17 | 17 | */ |
| 18 | 18 | public class TMSTileSource extends AbstractTMSTileSource { |
| 19 | 19 | |
| | 20 | /** Length of the equator in the projected coordinates, in meters */ |
| | 21 | private static final double MERCATOR_WIDTH = 2 * Math.PI * OsmMercator.EARTH_RADIUS; |
| | 22 | |
| 20 | 23 | protected int maxZoom; |
| 21 | 24 | protected int minZoom; |
| 22 | 25 | protected OsmMercator osmMercator; |
| … |
… |
public class TMSTileSource extends AbstractTMSTileSource {
|
| 25 | 28 | * Constructs a new {@code TMSTileSource}. |
| 26 | 29 | * @param info tile source information |
| 27 | 30 | */ |
| | 31 | @SuppressWarnings("this-escape") |
| 28 | 32 | public TMSTileSource(TileSourceInfo info) { |
| 29 | 33 | super(info); |
| 30 | 34 | minZoom = info.getMinZoom(); |
| 31 | 35 | maxZoom = info.getMaxZoom(); |
| 32 | | this.osmMercator = new OsmMercator(this.getTileSize()); |
| | 36 | osmMercator = new OsmMercator(getTileSize()); |
| 33 | 37 | } |
| 34 | 38 | |
| 35 | 39 | @Override |
| … |
… |
public class TMSTileSource extends AbstractTMSTileSource {
|
| 81 | 85 | |
| 82 | 86 | @Override |
| 83 | 87 | public IProjected tileXYtoProjected(int x, int y, int zoom) { |
| 84 | | double mercatorWidth = 2 * Math.PI * OsmMercator.EARTH_RADIUS; |
| 85 | | double f = mercatorWidth * getTileSize() / osmMercator.getMaxPixels(zoom); |
| 86 | | return new Projected(f * x - mercatorWidth / 2, -(f * y - mercatorWidth / 2)); |
| | 88 | double f = MERCATOR_WIDTH * getTileSize() / osmMercator.getMaxPixels(zoom); |
| | 89 | return new Projected(f * x - MERCATOR_WIDTH / 2, -(f * y - MERCATOR_WIDTH / 2)); |
| 87 | 90 | } |
| 88 | 91 | |
| 89 | 92 | @Override |
| 90 | 93 | public TileXY projectedToTileXY(IProjected p, int zoom) { |
| 91 | | double mercatorWidth = 2 * Math.PI * OsmMercator.EARTH_RADIUS; |
| 92 | | double f = mercatorWidth * getTileSize() / osmMercator.getMaxPixels(zoom); |
| 93 | | return new TileXY((p.getEast() + mercatorWidth / 2) / f, (-p.getNorth() + mercatorWidth / 2) / f); |
| | 94 | double f = MERCATOR_WIDTH * getTileSize() / osmMercator.getMaxPixels(zoom); |
| | 95 | return new TileXY((p.getEast() + MERCATOR_WIDTH / 2) / f, (-p.getNorth() + MERCATOR_WIDTH / 2) / f); |
| 94 | 96 | } |
| 95 | 97 | |
| 96 | 98 | @Override |
-
diff --git src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java
index b64f131..b8337c4 100644
|
|
|
|
| 2 | 2 | package org.openstreetmap.gui.jmapviewer.tilesources; |
| 3 | 3 | |
| 4 | 4 | import java.io.IOException; |
| 5 | | import java.util.Arrays; |
| 6 | 5 | import java.util.HashMap; |
| | 6 | import java.util.List; |
| 7 | 7 | import java.util.Map; |
| 8 | | import java.util.Random; |
| | 8 | import java.util.concurrent.ThreadLocalRandom; |
| 9 | 9 | import java.util.function.BiConsumer; |
| 10 | 10 | import java.util.regex.Matcher; |
| 11 | 11 | import java.util.regex.Pattern; |
| … |
… |
public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
|
| 49 | 49 | private static final Pattern PATTERN_SWITCH = Pattern.compile("\\{switch:([^}]+)}"); |
| 50 | 50 | private static final Pattern PATTERN_HEADER = Pattern.compile("\\{header\\(([^,]+),([^}]+)\\)}"); |
| 51 | 51 | private static final Pattern PATTERN_API_KEY = Pattern.compile("\\{apikey}"); |
| 52 | | private static final Pattern PATTERN_PARAM = Pattern.compile("\\{((?:\\d+-)?z(?:oom)?(:?[+-]\\d+)?|x|y|!y|-y|quad|switch:([^}]+))}"); |
| 53 | | |
| | 52 | private static final Pattern PATTERN_PARAM = Pattern.compile("\\{((?:\\d+-)?z(?:oom)?(?:[+-]\\d+)?|x|y|!y|-y|quad|switch:([^}]+))}"); |
| | 53 | private static final Pattern PATTERN_ANY = Pattern.compile("\\{[^}]*}"); |
| 54 | 54 | // CHECKSTYLE.ON: SingleSpaceSeparator |
| 55 | 55 | |
| 56 | | private static final Pattern[] ALL_PATTERNS = { |
| | 56 | private static final List<Pattern> ALL_PATTERNS = List.of( |
| 57 | 57 | PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y, PATTERN_SWITCH, PATTERN_API_KEY, |
| 58 | | PATTERN_QUAD |
| 59 | | }; |
| | 58 | PATTERN_QUAD); |
| 60 | 59 | |
| 61 | | private Random rand; |
| 62 | 60 | private String[] randomParts; |
| 63 | 61 | private final Map<String, String> headers = new HashMap<>(); |
| 64 | | private boolean inverse_zoom; |
| 65 | | private int zoom_offset; |
| | 62 | private boolean inverseZoom; |
| | 63 | private int zoomOffset; |
| 66 | 64 | |
| 67 | 65 | /** |
| 68 | 66 | * Creates Templated TMS Tile Source based on ImageryInfo |
| … |
… |
public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
|
| 77 | 75 | handleTemplate(info.getId()); |
| 78 | 76 | } |
| 79 | 77 | |
| 80 | | private void replacePattern(BiConsumer<Matcher, StringBuffer> replaceAction, Pattern... patterns) { |
| 81 | | for (Pattern p : patterns) { |
| 82 | | StringBuffer output = new StringBuffer(); |
| 83 | | Matcher m = p.matcher(baseUrl); |
| 84 | | while (m.find()) { |
| 85 | | replaceAction.accept(m, output); |
| 86 | | } |
| 87 | | m.appendTail(output); |
| 88 | | baseUrl = output.toString(); |
| | 78 | private void replacePattern(BiConsumer<Matcher, StringBuilder> replaceAction, Pattern pattern) { |
| | 79 | StringBuilder output = new StringBuilder(); |
| | 80 | Matcher m = pattern.matcher(baseUrl); |
| | 81 | while (m.find()) { |
| | 82 | replaceAction.accept(m, output); |
| 89 | 83 | } |
| | 84 | m.appendTail(output); |
| | 85 | baseUrl = output.toString(); |
| 90 | 86 | } |
| 91 | 87 | |
| 92 | 88 | private void handleTemplate(String imageryId) { |
| 93 | 89 | // Capturing group pattern on switch values |
| 94 | 90 | Matcher m = PATTERN_SWITCH.matcher(baseUrl); |
| 95 | 91 | if (m.find()) { |
| 96 | | rand = new Random(); |
| 97 | 92 | randomParts = m.group(1).split(",", -1); |
| 98 | 93 | } |
| 99 | 94 | // Capturing group pattern on header values |
| … |
… |
public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
|
| 105 | 100 | if (imageryId != null) { |
| 106 | 101 | replacePattern((matcher, output) -> { |
| 107 | 102 | try { |
| 108 | | matcher.appendReplacement(output, FeatureAdapter.retrieveApiKey(imageryId)); |
| | 103 | // the key is literal text, '$' and '\' in it are no group references |
| | 104 | matcher.appendReplacement(output, Matcher.quoteReplacement(FeatureAdapter.retrieveApiKey(imageryId))); |
| 109 | 105 | } catch (IOException | RuntimeException e) { |
| 110 | 106 | throw new IllegalArgumentException(e); |
| 111 | 107 | } |
| … |
… |
public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
|
| 115 | 111 | m = PATTERN_ZOOM.matcher(baseUrl); |
| 116 | 112 | if (m.find()) { |
| 117 | 113 | if (m.group(1) != null) { |
| 118 | | inverse_zoom = true; |
| 119 | | zoom_offset = Integer.parseInt(m.group(1)); |
| | 114 | inverseZoom = true; |
| | 115 | zoomOffset = Integer.parseInt(m.group(1)); |
| 120 | 116 | } |
| 121 | 117 | if (m.group(2) != null) { |
| 122 | | String ofs = m.group(2); |
| 123 | | if (ofs.startsWith("+")) |
| 124 | | ofs = ofs.substring(1); |
| 125 | | zoom_offset += Integer.parseInt(ofs); |
| | 118 | zoomOffset += Integer.parseInt(m.group(2)); |
| 126 | 119 | } |
| 127 | 120 | } |
| 128 | 121 | } |
| … |
… |
public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
|
| 134 | 127 | |
| 135 | 128 | @Override |
| 136 | 129 | public String getTileUrl(int zoom, int tilex, int tiley) { |
| 137 | | StringBuffer url = new StringBuffer(baseUrl.length()); |
| | 130 | StringBuilder url = new StringBuilder(baseUrl.length()); |
| 138 | 131 | Matcher matcher = PATTERN_PARAM.matcher(baseUrl); |
| 139 | 132 | while (matcher.find()) { |
| 140 | 133 | final String replacement; |
| | 134 | // Java 14: use a switch expression, "case "z", "zoom" ->" replaces the fall through |
| 141 | 135 | switch (matcher.group(1)) { |
| 142 | 136 | case "z": // PATTERN_ZOOM |
| 143 | 137 | case "zoom": |
| 144 | | replacement = Integer.toString((inverse_zoom ? -zoom : zoom) + zoom_offset); |
| | 138 | replacement = zoomParameter(zoom); |
| 145 | 139 | break; |
| 146 | 140 | case "x": // PATTERN_X |
| 147 | 141 | replacement = Integer.toString(tilex); |
| … |
… |
public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
|
| 155 | 149 | case "-y": // PATTERN_NEG_Y |
| 156 | 150 | replacement = Integer.toString((int) Math.pow(2, zoom)-1-tiley); |
| 157 | 151 | break; |
| 158 | | case "switch:": |
| 159 | | replacement = getRandomPart(randomParts); |
| 160 | | break; |
| 161 | 152 | case "quad": // PATTERN_QUAD |
| 162 | 153 | replacement = xyzToQuadKey(tilex, tiley, zoom); |
| 163 | 154 | break; |
| 164 | 155 | default: |
| 165 | | // handle switch/zoom here, as group will contain parameters and switch will not work |
| 166 | | if (PATTERN_ZOOM.matcher("{" + matcher.group(1) + "}").matches()) { |
| 167 | | replacement = Integer.toString((inverse_zoom ? -zoom : zoom) + zoom_offset); |
| 168 | | } else if (PATTERN_SWITCH.matcher("{" + matcher.group(1) + "}").matches()) { |
| 169 | | replacement = getRandomPart(randomParts); |
| 170 | | } else { |
| 171 | | replacement = '{' + matcher.group(1) + '}'; |
| 172 | | } |
| | 156 | // the zoom with an offset, or the switch, whose values are in group 2: their parameters defeat the switch labels |
| | 157 | replacement = matcher.group(2) != null ? getRandomPart(randomParts) : zoomParameter(zoom); |
| 173 | 158 | } |
| 174 | | matcher.appendReplacement(url, replacement); |
| | 159 | // the switch values are literal text, '$' and '\' in them are no group references |
| | 160 | matcher.appendReplacement(url, Matcher.quoteReplacement(replacement)); |
| 175 | 161 | } |
| 176 | 162 | matcher.appendTail(url); |
| 177 | 163 | return url.toString().replace(" ", "%20"); |
| 178 | 164 | } |
| 179 | 165 | |
| | 166 | private String zoomParameter(int zoom) { |
| | 167 | return Integer.toString((inverseZoom ? -zoom : zoom) + zoomOffset); |
| | 168 | } |
| | 169 | |
| 180 | 170 | /** |
| 181 | 171 | * Convert an x y z coordinate to a quadkey |
| 182 | 172 | * @param x The x coordinate |
| … |
… |
public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
|
| 184 | 174 | * @param z The z coordinate |
| 185 | 175 | * @return The quadkey |
| 186 | 176 | */ |
| 187 | | private static String xyzToQuadKey(int x, int y, int z) { |
| | 177 | static String xyzToQuadKey(int x, int y, int z) { |
| 188 | 178 | final char[] string = new char[z]; |
| 189 | 179 | for (int i = z; i > 0; i--) { |
| 190 | 180 | char digit = '0'; |
| … |
… |
public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
|
| 200 | 190 | return String.valueOf(string); |
| 201 | 191 | } |
| 202 | 192 | |
| | 193 | /** |
| | 194 | * Picks one of the values of a {switch:...} parameter. |
| | 195 | * @param parts the values to choose from |
| | 196 | * @return a randomly chosen value |
| | 197 | */ |
| 203 | 198 | protected String getRandomPart(final String[] parts) { |
| 204 | | return parts[rand.nextInt(parts.length)]; |
| | 199 | return parts[ThreadLocalRandom.current().nextInt(parts.length)]; |
| 205 | 200 | } |
| 206 | 201 | |
| 207 | 202 | /** |
| … |
… |
public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTi
|
| 209 | 204 | * @param url URL to check |
| 210 | 205 | */ |
| 211 | 206 | public static void checkUrl(String url) { |
| 212 | | assert url != null && !"".equals(url) : "URL cannot be null or empty"; |
| 213 | | Matcher m = Pattern.compile("\\{[^}]*}").matcher(url); |
| | 207 | assert url != null && !url.isEmpty() : "URL cannot be null or empty"; |
| | 208 | Matcher m = PATTERN_ANY.matcher(url); |
| 214 | 209 | while (m.find()) { |
| 215 | | boolean isSupportedPattern = Arrays.stream(ALL_PATTERNS).anyMatch(pattern -> pattern.matcher(m.group()).matches()); |
| | 210 | boolean isSupportedPattern = ALL_PATTERNS.stream().anyMatch(pattern -> pattern.matcher(m.group()).matches()); |
| 216 | 211 | if (!isSupportedPattern) { |
| 217 | 212 | throw new IllegalArgumentException( |
| 218 | 213 | m.group() + " is not a valid TMS argument. Please check this server URL:\n" + url); |
-
diff --git test/org/openstreetmap/gui/jmapviewer/TileRangeTest.java test/org/openstreetmap/gui/jmapviewer/TileRangeTest.java
index b91faff..2426b5a 100644
|
|
|
|
| 1 | 1 | // License: GPL. For details, see Readme.txt file. |
| 2 | 2 | package org.openstreetmap.gui.jmapviewer; |
| 3 | 3 | |
| 4 | | |
| 5 | 4 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 6 | 5 | import static org.junit.jupiter.api.Assertions.assertThrows; |
| 7 | 6 | |
| … |
… |
class TileRangeTest {
|
| 18 | 17 | @Test |
| 19 | 18 | void testSize() { |
| 20 | 19 | assertEquals(16, new TileRange( |
| 21 | | new TileXY(3, 3), |
| | 20 | new TileXY(3, 3), |
| 22 | 21 | new TileXY(6, 6), 10).size()); |
| 23 | 22 | } |
| 24 | 23 | |
| | 24 | /** |
| | 25 | * Fractional tile coordinates widen the range to whole tiles, both ends included. |
| | 26 | */ |
| | 27 | @Test |
| | 28 | void testFractionalCorners() { |
| | 29 | assertEquals(9, new TileRange(new TileXY(0.5, 0.5), new TileXY(1.5, 1.5), 3).size()); |
| | 30 | } |
| | 31 | |
| 25 | 32 | /** |
| 26 | 33 | * Ensure that something exceptional happens when an integer overflow happens |
| 27 | 34 | */ |
-
diff --git test/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSourceTest.java test/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSourceTest.java
index 8e625b3..77e7919 100644
|
|
|
|
| 2 | 2 | package org.openstreetmap.gui.jmapviewer.tilesources; |
| 3 | 3 | |
| 4 | 4 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | 5 | import static org.junit.jupiter.api.Assertions.assertThrows; |
| 5 | 6 | import static org.junit.jupiter.api.Assertions.assertTrue; |
| 6 | 7 | |
| 7 | | import java.text.MessageFormat; |
| 8 | | import java.util.Arrays; |
| 9 | | import java.util.Collection; |
| 10 | | import java.util.Collections; |
| 11 | | import java.util.function.Predicate; |
| 12 | | import java.util.stream.Stream; |
| | 8 | import java.util.List; |
| | 9 | import java.util.Map; |
| | 10 | import java.util.Set; |
| 13 | 11 | |
| 14 | 12 | import org.junit.jupiter.api.Test; |
| 15 | 13 | |
| 16 | 14 | /** |
| 17 | 15 | * Tests for TemplatedTMSTileSource |
| 18 | 16 | */ |
| 19 | | public class TemplatedTMSTileSourceTest { |
| 20 | | |
| 21 | | private static final Collection<String> TMS_IMAGERIES = Collections.singleton("http://imagico.de/map/osmim_tiles.php?layer=S2A_R136_N41_20150831T093006&z={zoom}&x={x}&y={-y}" |
| 22 | | /* |
| 23 | | * generate for example with: |
| 24 | | * $ curl https://josm.openstreetmap.de/maps | \ |
| 25 | | * xmlstarlet sel -N 'josm=http://josm.openstreetmap.de/maps-1.0' -t -v "//josm:entry[josm:type='tms']/josm:url" -n | \ |
| 26 | | * sed -e 's/\&/\&/g' -e 's/^/"/' -e 's/$/",/' |
| 27 | | */); |
| | 17 | class TemplatedTMSTileSourceTest { |
| 28 | 18 | |
| 29 | 19 | /** |
| 30 | 20 | * triple of: |
| … |
… |
public class TemplatedTMSTileSourceTest {
|
| 32 | 22 | * * expected tile url for zoom=4, x=5, y=6 |
| 33 | 23 | * * expected tile url for zoom=3, x=2, y=1 |
| 34 | 24 | */ |
| 35 | | private final Collection<String[]> TEST_DATA = Arrays.asList(new String[][] { |
| 36 | | /* |
| 37 | | * generate with main method below once TMS_IMAGERIES is filled in |
| 38 | | */ |
| | 25 | private static final List<String[]> TEST_DATA = List.<String[]>of( |
| 39 | 26 | new String[] { |
| 40 | | "http://imagico.de/map/osmim_tiles.php?layer=S2A_R136_N41_20150831T093006&z={zoom}&x={x}&y={-y}", |
| 41 | | "http://imagico.de/map/osmim_tiles.php?layer=S2A_R136_N41_20150831T093006&z=4&x=5&y=9", |
| 42 | | "http://imagico.de/map/osmim_tiles.php?layer=S2A_R136_N41_20150831T093006&z=3&x=2&y=6" |
| 43 | | } |
| 44 | | }); |
| | 27 | "http://imagico.de/map/osmim_tiles.php?layer=S2A_R136_N41_20150831T093006&z={zoom}&x={x}&y={-y}", |
| | 28 | "http://imagico.de/map/osmim_tiles.php?layer=S2A_R136_N41_20150831T093006&z=4&x=5&y=9", |
| | 29 | "http://imagico.de/map/osmim_tiles.php?layer=S2A_R136_N41_20150831T093006&z=3&x=2&y=6" |
| | 30 | }); |
| 45 | 31 | |
| 46 | 32 | /** |
| 47 | 33 | * Check standard template |
| … |
… |
public class TemplatedTMSTileSourceTest {
|
| 104 | 90 | } |
| 105 | 91 | |
| 106 | 92 | /** |
| 107 | | * Test template with switch |
| | 93 | * Test template with API key |
| 108 | 94 | */ |
| 109 | 95 | @Test |
| 110 | 96 | void testGetTileUrl_apiKey() { |
| 111 | 97 | System.setProperty("id1.api-key", "wololo"); |
| 112 | | TileSourceInfo testImageryTMS = new TileSourceInfo("test imagery", "http://localhost/{zoom}/{x}/{y}?token={apikey}&foo=bar", "id1"); |
| 113 | | TemplatedTMSTileSource ts = new TemplatedTMSTileSource(testImageryTMS); |
| 114 | | assertEquals("http://localhost/4/5/6?token=wololo&foo=bar", ts.getTileUrl(4, 5, 6)); |
| | 98 | try { |
| | 99 | TileSourceInfo testImageryTMS = new TileSourceInfo("test imagery", "http://localhost/{zoom}/{x}/{y}?token={apikey}&foo=bar", "id1"); |
| | 100 | TemplatedTMSTileSource ts = new TemplatedTMSTileSource(testImageryTMS); |
| | 101 | assertEquals("http://localhost/4/5/6?token=wololo&foo=bar", ts.getTileUrl(4, 5, 6)); |
| | 102 | } finally { |
| | 103 | System.clearProperty("id1.api-key"); |
| | 104 | } |
| 115 | 105 | } |
| 116 | 106 | |
| 117 | 107 | /** |
| … |
… |
public class TemplatedTMSTileSourceTest {
|
| 121 | 111 | void testGetTileUrl_switch() { |
| 122 | 112 | TileSourceInfo testImageryTMS = new TileSourceInfo("test imagery", "http://{switch:a,b,c}.localhost/{10-zoom-5}/{x}/{y}", "id1"); |
| 123 | 113 | TemplatedTMSTileSource ts = new TemplatedTMSTileSource(testImageryTMS); |
| 124 | | assertTrue( |
| 125 | | Stream.of( |
| 126 | | "http://a.localhost/4/2/3", |
| 127 | | "http://b.localhost/4/2/3", |
| 128 | | "http://c.localhost/4/2/3" |
| 129 | | ) |
| 130 | | .anyMatch(Predicate.isEqual(ts.getTileUrl(1, 2, 3))) |
| 131 | | ); |
| | 114 | assertOneOfServers("/4/2/3", ts.getTileUrl(1, 2, 3)); |
| | 115 | assertOneOfServers("/3/3/4", ts.getTileUrl(2, 3, 4)); |
| | 116 | assertOneOfServers("/2/4/5", ts.getTileUrl(3, 4, 5)); |
| | 117 | assertOneOfServers("/1/5/6", ts.getTileUrl(4, 5, 6)); |
| | 118 | } |
| 132 | 119 | |
| 133 | | assertTrue( |
| 134 | | Stream.of( |
| 135 | | "http://a.localhost/3/3/4", |
| 136 | | "http://b.localhost/3/3/4", |
| 137 | | "http://c.localhost/3/3/4" |
| 138 | | ) |
| 139 | | .anyMatch(Predicate.isEqual(ts.getTileUrl(2, 3, 4))) |
| 140 | | ); |
| 141 | | assertTrue( |
| 142 | | Stream.of( |
| 143 | | "http://a.localhost/2/4/5", |
| 144 | | "http://b.localhost/2/4/5", |
| 145 | | "http://c.localhost/2/4/5" |
| 146 | | ) |
| 147 | | .anyMatch(Predicate.isEqual(ts.getTileUrl(3, 4, 5))) |
| 148 | | ); |
| 149 | | assertTrue( |
| 150 | | Stream.of( |
| 151 | | "http://a.localhost/1/5/6", |
| 152 | | "http://b.localhost/1/5/6", |
| 153 | | "http://c.localhost/1/5/6" |
| 154 | | ) |
| 155 | | .anyMatch(Predicate.isEqual(ts.getTileUrl(4, 5, 6))) |
| 156 | | ); |
| | 120 | private static void assertOneOfServers(String path, String url) { |
| | 121 | Set<String> expected = Set.of("http://a.localhost" + path, "http://b.localhost" + path, "http://c.localhost" + path); |
| | 122 | assertTrue(expected.contains(url), url); |
| 157 | 123 | } |
| 158 | 124 | |
| | 125 | /** |
| | 126 | * Test template with Yahoo style y index |
| | 127 | */ |
| 159 | 128 | @Test |
| 160 | 129 | void testGetTileUrl_yahoo() { |
| 161 | 130 | checkGetTileUrl( |
| … |
… |
public class TemplatedTMSTileSourceTest {
|
| 163 | 132 | "http://localhost/4/5/1", |
| 164 | 133 | "http://localhost/3/1/1" |
| 165 | 134 | ); |
| 166 | | |
| 167 | 135 | } |
| 168 | 136 | |
| | 137 | /** |
| | 138 | * Test template with reversed (TMS) y index |
| | 139 | */ |
| 169 | 140 | @Test |
| 170 | 141 | void testGetTileUrl_negative_y() { |
| 171 | 142 | checkGetTileUrl( |
| … |
… |
public class TemplatedTMSTileSourceTest {
|
| 173 | 144 | "http://localhost/4/5/9", |
| 174 | 145 | "http://localhost/3/1/5" |
| 175 | 146 | ); |
| 176 | | |
| 177 | 147 | } |
| 178 | 148 | |
| | 149 | /** |
| | 150 | * Test template with quadkey |
| | 151 | */ |
| 179 | 152 | @Test |
| 180 | 153 | void testGetTileUrl_quad() { |
| 181 | 154 | checkGetTileUrl( |
| … |
… |
public class TemplatedTMSTileSourceTest {
|
| 183 | 156 | "http://localhost/0321", |
| 184 | 157 | "http://localhost/021" |
| 185 | 158 | ); |
| | 159 | } |
| | 160 | |
| | 161 | /** |
| | 162 | * Test that the header placeholders become headers and leave the URL |
| | 163 | */ |
| | 164 | @Test |
| | 165 | void testHeaders() { |
| | 166 | TileSourceInfo info = new TileSourceInfo("test imagery", "http://localhost/{header(X-Test,value)}{z}/{x}/{y}", "id1"); |
| | 167 | info.setCookies("a=b"); |
| | 168 | TemplatedTMSTileSource ts = new TemplatedTMSTileSource(info); |
| | 169 | assertEquals(Map.of("X-Test", "value", "Cookie", "a=b"), ts.getHeaders()); |
| | 170 | assertEquals("http://localhost/4/5/6", ts.getTileUrl(4, 5, 6)); |
| | 171 | } |
| | 172 | |
| | 173 | /** |
| | 174 | * Test that spaces are encoded |
| | 175 | */ |
| | 176 | @Test |
| | 177 | void testSpacesAreEncoded() { |
| | 178 | checkGetTileUrl( |
| | 179 | "http://localhost/my layer/{z}/{x}/{y}", |
| | 180 | "http://localhost/my%20layer/4/5/6", |
| | 181 | "http://localhost/my%20layer/3/1/2" |
| | 182 | ); |
| | 183 | } |
| 186 | 184 | |
| | 185 | /** |
| | 186 | * Test the URL validation |
| | 187 | */ |
| | 188 | @Test |
| | 189 | void testCheckUrl() { |
| | 190 | TemplatedTMSTileSource.checkUrl("http://{switch:a,b}.localhost/{zoom}/{x}/{-y}.png?{quad}"); |
| | 191 | assertThrows(IllegalArgumentException.class, () -> TemplatedTMSTileSource.checkUrl("http://localhost/{unknown}/{x}/{y}")); |
| 187 | 192 | } |
| 188 | 193 | |
| 189 | | private void checkGetTileUrl(String url, String expected123, String expected312) { |
| | 194 | private static void checkGetTileUrl(String url, String expected456, String expected312) { |
| 190 | 195 | TileSourceInfo testImageryTMS = new TileSourceInfo("test imagery", url, "id1"); |
| 191 | 196 | TemplatedTMSTileSource ts = new TemplatedTMSTileSource(testImageryTMS); |
| 192 | | assertEquals(expected123, ts.getTileUrl(4, 5, 6)); |
| | 197 | assertEquals(expected456, ts.getTileUrl(4, 5, 6)); |
| 193 | 198 | assertEquals(expected312, ts.getTileUrl(3, 1, 2)); |
| 194 | 199 | } |
| 195 | 200 | |
| … |
… |
public class TemplatedTMSTileSourceTest {
|
| 205 | 210 | assertEquals(test[2], ts.getTileUrl(3, 2, 1)); |
| 206 | 211 | } |
| 207 | 212 | } |
| 208 | | |
| 209 | | public static void main(String[] args) { |
| 210 | | for (String url: TMS_IMAGERIES) { |
| 211 | | TileSourceInfo testImageryTMS = new TileSourceInfo("test imagery", url, "id1"); |
| 212 | | TemplatedTMSTileSource ts = new TemplatedTMSTileSource(testImageryTMS); |
| 213 | | System.out.println(MessageFormat.format("new String[]{\"{0}\", \"{1}\", \"{2}\"},", |
| 214 | | url, ts.getTileUrl(4, 5, 6), ts.getTileUrl(3, 2, 1))); |
| 215 | | } |
| 216 | | } |
| 217 | 213 | } |
-
diff --git tools/assembly/release.xml tools/assembly/release.xml
new file mode 100644
index 0000000..62fc8ab
|
-
|
+
|
|
| | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| | 2 | <!-- Binary release zip, equivalent to the Ant "create_release_zip" target. |
| | 3 | The JOSM Jenkins release job expects JMapViewer.jar and JMapViewer_src.jar inside. --> |
| | 4 | <assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0" |
| | 5 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | 6 | xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0 http://maven.apache.org/xsd/assembly-2.2.0.xsd"> |
| | 7 | <id>release</id> |
| | 8 | <formats> |
| | 9 | <format>zip</format> |
| | 10 | </formats> |
| | 11 | <includeBaseDirectory>false</includeBaseDirectory> |
| | 12 | <files> |
| | 13 | <file> |
| | 14 | <source>${project.build.directory}/${project.build.finalName}.jar</source> |
| | 15 | <destName>JMapViewer.jar</destName> |
| | 16 | </file> |
| | 17 | <file> |
| | 18 | <source>${project.build.directory}/${project.build.finalName}-sources.jar</source> |
| | 19 | <destName>JMapViewer_src.jar</destName> |
| | 20 | </file> |
| | 21 | <file> |
| | 22 | <source>${project.basedir}/Readme.txt</source> |
| | 23 | </file> |
| | 24 | <file> |
| | 25 | <source>${project.basedir}/Gpl.txt</source> |
| | 26 | </file> |
| | 27 | </files> |
| | 28 | </assembly> |
-
diff --git tools/assembly/source-release.xml tools/assembly/source-release.xml
new file mode 100644
index 0000000..cc009b8
|
-
|
+
|
|
| | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| | 2 | <!-- Source release zip, equivalent to the Ant "create_source_release_zip" target. |
| | 3 | It ships pom.xml, the tests and the tools/ directory as well, so that the unpacked zip |
| | 4 | can be built with Maven as well as with Ant. --> |
| | 5 | <assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0" |
| | 6 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | 7 | xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0 http://maven.apache.org/xsd/assembly-2.2.0.xsd"> |
| | 8 | <id>Source</id> |
| | 9 | <formats> |
| | 10 | <format>zip</format> |
| | 11 | </formats> |
| | 12 | <baseDirectory>jmapviewer-${project.version}</baseDirectory> |
| | 13 | <files> |
| | 14 | <file> |
| | 15 | <source>${project.basedir}/Readme.txt</source> |
| | 16 | </file> |
| | 17 | <file> |
| | 18 | <source>${project.basedir}/Gpl.txt</source> |
| | 19 | </file> |
| | 20 | <file> |
| | 21 | <source>${project.basedir}/build.xml</source> |
| | 22 | </file> |
| | 23 | <file> |
| | 24 | <source>${project.basedir}/pom.xml</source> |
| | 25 | </file> |
| | 26 | </files> |
| | 27 | <fileSets> |
| | 28 | <fileSet> |
| | 29 | <directory>${project.basedir}/src</directory> |
| | 30 | <outputDirectory>src</outputDirectory> |
| | 31 | </fileSet> |
| | 32 | <fileSet> |
| | 33 | <directory>${project.basedir}/test</directory> |
| | 34 | <outputDirectory>test</outputDirectory> |
| | 35 | </fileSet> |
| | 36 | <fileSet> |
| | 37 | <directory>${project.basedir}/tools</directory> |
| | 38 | <outputDirectory>tools</outputDirectory> |
| | 39 | </fileSet> |
| | 40 | </fileSets> |
| | 41 | </assembly> |
-
diff --git tools/checkstyle/jmapviewer_checks.xml tools/checkstyle/jmapviewer_checks.xml
index 10e401a..bc6bf54 100644
|
|
|
|
| 1 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | | <!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> |
| 3 | | |
| 4 | | <!-- |
| 5 | | This configuration file was written by the eclipse-cs plugin configuration editor |
| 6 | | --> |
| 7 | | <!-- |
| 8 | | Checkstyle-Configuration: JMapViewer |
| 9 | | Description: |
| 10 | | JMapViewer Checkstyle rules |
| 11 | | --> |
| | 2 | <!DOCTYPE module PUBLIC "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration_1_3.dtd"> |
| | 3 | <!-- JMapViewer checkstyle rules, used by Maven, Ant and eclipse-cs (.checkstyle) --> |
| 12 | 4 | <module name="Checker"> |
| 13 | 5 | <property name="severity" value="warning"/> |
| 14 | 6 | <property name="charset" value="UTF-8"/> |
| | 7 | <!-- Checkstyle 10 cannot parse module declarations; drop this filter once the build needs JDK 21 (Checkstyle 14+) --> |
| | 8 | <module name="BeforeExecutionExclusionFileFilter"> |
| | 9 | <property name="fileNamePattern" value="module\-info\.java$"/> |
| | 10 | </module> |
| 15 | 11 | <module name="TreeWalker"> |
| 16 | 12 | <module name="MissingDeprecated"/> |
| 17 | 13 | <module name="MissingOverride"/> |
| … |
… |
JMapViewer Checkstyle rules
|
| 20 | 16 | <property name="allowSamelineMultipleAnnotations" value="true"/> |
| 21 | 17 | </module> |
| 22 | 18 | <module name="AnnotationUseStyle"/> |
| 23 | | <module name="JavadocStyle"> |
| 24 | | <property name="checkFirstSentence" value="false"/> |
| 25 | | <property name="checkHtml" value="false"/> |
| 26 | | </module> |
| 27 | 19 | <module name="NonEmptyAtclauseDescription"/> |
| 28 | 20 | <module name="AtclauseOrder"/> |
| 29 | 21 | <module name="AvoidStarImport"/> |
| … |
… |
JMapViewer Checkstyle rules
|
| 104 | 96 | </module> |
| 105 | 97 | <module name="FileTabCharacter"/> |
| 106 | 98 | <module name="LineLength"> |
| 107 | | <property name="fileExtensions" value="java" /> |
| | 99 | <property name="fileExtensions" value=".java"/> |
| 108 | 100 | <property name="max" value="145"/> |
| 109 | 101 | <property name="tabWidth" value="4"/> |
| 110 | 102 | </module> |
| … |
… |
JMapViewer Checkstyle rules
|
| 112 | 104 | <property name="lineSeparator" value="lf"/> |
| 113 | 105 | </module> |
| 114 | 106 | <module name="SuppressionFilter"> |
| 115 | | <property name="file" value="tools/checkstyle/jmapviewer_filters.xml"/> |
| 116 | | <property name="optional" value="true"/> |
| | 107 | <property name="file" value="${config_loc}/jmapviewer_filters.xml"/> |
| 117 | 108 | </module> |
| 118 | 109 | <module name="SuppressWithPlainTextCommentFilter"> |
| 119 | 110 | <property name="offCommentFormat" value="CHECKSTYLE\.OFF\: ([\w\|]+)"/> |
-
diff --git tools/checkstyle/jmapviewer_filters.xml tools/checkstyle/jmapviewer_filters.xml
index 14abc8d..be622b7 100644
|
|
|
|
| 1 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | 2 | <!DOCTYPE suppressions PUBLIC |
| 3 | | "-//Puppy Crawl//DTD Suppressions 1.0//EN" |
| 4 | | "http://www.puppycrawl.com/dtds/suppressions_1_0.dtd"> |
| | 3 | "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" |
| | 4 | "https://checkstyle.org/dtds/suppressions_1_2.dtd"> |
| 5 | 5 | <suppressions> |
| 6 | | <suppress checks="." files="\.classpath" /> |
| 7 | | <suppress checks="." files="\.project" /> |
| 8 | | <suppress checks="HeaderCheck" files="ScanexTileSource\.java" /> |
| 9 | | </suppressions> |
| 10 | | No newline at end of file |
| | 6 | <!-- ScanexTileSource is dual licensed (BSD or GPL) --> |
| | 7 | <suppress checks="HeaderCheck" files="ScanexTileSource\.java"/> |
| | 8 | </suppressions> |