From b2ef17504d7dfd7cfe652c7097e4679df3fd3386 Mon Sep 17 00:00:00 2001
From: Ian Dees <ian.dees@gmail.com>
Date: Mon, 15 Jul 2013 21:48:26 -0500
Subject: [PATCH] Initial commit of plugin based on walking papers plugin.

---
 .classpath                                    |   7 +
 .gitignore                                    |   3 +
 .project                                      |  17 +
 README                                        |   6 +
 build.xml                                     |  30 ++
 data/bg.lang                                  | Bin 0 -> 48 bytes
 data/ca.lang                                  | Bin 0 -> 331 bytes
 data/cs.lang                                  | Bin 0 -> 277 bytes
 data/da.lang                                  | Bin 0 -> 102 bytes
 data/de.lang                                  | Bin 0 -> 323 bytes
 data/el.lang                                  | Bin 0 -> 131 bytes
 data/en.lang                                  | Bin 0 -> 312 bytes
 data/en_AU.lang                               |   1 +
 data/en_GB.lang                               |   1 +
 data/es.lang                                  | Bin 0 -> 297 bytes
 data/et.lang                                  | Bin 0 -> 166 bytes
 data/eu.lang                                  | Bin 0 -> 297 bytes
 data/fr.lang                                  | Bin 0 -> 371 bytes
 data/gl.lang                                  | Bin 0 -> 212 bytes
 data/id.lang                                  | Bin 0 -> 301 bytes
 data/it.lang                                  | Bin 0 -> 345 bytes
 data/ja.lang                                  | Bin 0 -> 341 bytes
 data/nl.lang                                  | Bin 0 -> 302 bytes
 data/pl.lang                                  | Bin 0 -> 275 bytes
 data/pt.lang                                  | Bin 0 -> 392 bytes
 data/pt_BR.lang                               | Bin 0 -> 293 bytes
 data/ru.lang                                  | Bin 0 -> 433 bytes
 data/sk.lang                                  | Bin 0 -> 296 bytes
 data/uk.lang                                  | Bin 0 -> 440 bytes
 data/zh_CN.lang                               | Bin 0 -> 284 bytes
 data/zh_TW.lang                               | Bin 0 -> 284 bytes
 images/preferences/walkingpapers.png          | Bin 0 -> 1910 bytes
 images/walkingpapers.png                      | Bin 0 -> 361 bytes
 .../FieldPapersAddLayerAction.java            | 105 +++++
 .../plugins/fieldpapers/FieldPapersKey.java   |  78 ++++
 .../plugins/fieldpapers/FieldPapersLayer.java | 427 ++++++++++++++++++
 .../fieldpapers/FieldPapersPlugin.java        |  33 ++
 .../plugins/fieldpapers/FieldPapersTile.java  |  67 +++
 38 files changed, 775 insertions(+)
 create mode 100644 .classpath
 create mode 100644 .gitignore
 create mode 100644 .project
 create mode 100644 README
 create mode 100644 build.xml
 create mode 100644 data/bg.lang
 create mode 100644 data/ca.lang
 create mode 100644 data/cs.lang
 create mode 100644 data/da.lang
 create mode 100644 data/de.lang
 create mode 100644 data/el.lang
 create mode 100644 data/en.lang
 create mode 100644 data/en_AU.lang
 create mode 100644 data/en_GB.lang
 create mode 100644 data/es.lang
 create mode 100644 data/et.lang
 create mode 100644 data/eu.lang
 create mode 100644 data/fr.lang
 create mode 100644 data/gl.lang
 create mode 100644 data/id.lang
 create mode 100644 data/it.lang
 create mode 100644 data/ja.lang
 create mode 100644 data/nl.lang
 create mode 100644 data/pl.lang
 create mode 100644 data/pt.lang
 create mode 100644 data/pt_BR.lang
 create mode 100644 data/ru.lang
 create mode 100644 data/sk.lang
 create mode 100644 data/uk.lang
 create mode 100644 data/zh_CN.lang
 create mode 100644 data/zh_TW.lang
 create mode 100644 images/preferences/walkingpapers.png
 create mode 100644 images/walkingpapers.png
 create mode 100644 src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersAddLayerAction.java
 create mode 100644 src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersKey.java
 create mode 100644 src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersLayer.java
 create mode 100644 src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersPlugin.java
 create mode 100644 src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersTile.java

diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..663bc1b
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/JOSM"/>
+	<classpathentry kind="output" path="build"/>
+</classpath>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..98217d6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+build
+.settings
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..8a6fe0e
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>JOSM-walkingpapers</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/README b/README
new file mode 100644
index 0000000..52fa214
--- /dev/null
+++ b/README
@@ -0,0 +1,6 @@
+A plugin for displaying tiled, scanned maps from walking-papers.org.
+
+Written by Frederik Ramm <frederik@remote.org>, based on SlippyMap 
+plugin work by Lubomir Varga <lubomir.varga@freemap.sk> or <luvar@plaintext.sk>.
+
+Public Domain.
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..34ac7d5
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** This is a template build file for a JOSM  plugin.
+**
+** Maintaining versions
+** ====================
+** See README.template
+**
+** Usage
+** =====
+** Call "ant help" to get possible build targets.
+**
+-->
+<project name="walkingpapers" default="dist" basedir=".">
+
+    <!-- enter the SVN commit message -->
+    <property name="commit.message" value="Changed the constructor signature of the plugin main class"/>
+    <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
+    <property name="plugin.main.version" value="4549"/>
+
+    <property name="plugin.author" value="Frederik Ram"/>
+    <property name="plugin.class" value="org.openstreetmap.josm.plugins.walkingpapers.WalkingPapersPlugin"/>
+    <property name="plugin.description" value="Supports downloading tiled, scanned maps from walking-papers.org. This plugin is still under early development and may be buggy."/>
+    <property name="plugin.icon" value="images/preferences/walkingpapers.png"/>
+    <property name="plugin.link" value="http://wiki.openstreetmap.org/index.php/JOSM/Plugins/WalkingPapers"/>
+
+    <!-- ** include targets that all plugins have in common ** -->
+    <import file="../build-common.xml"/>
+
+</project>
diff --git a/data/bg.lang b/data/bg.lang
new file mode 100644
index 0000000000000000000000000000000000000000..b30d90fcf8001b62ab5cf415b89d10e9f45a0bbb
GIT binary patch
literal 48
ucmZQz00V^!3oq=tu;Ieq3p*}0fawhiAc2bw7n?3@(9_ccsrvu#|9=2BiWy=6

literal 0
HcmV?d00001

diff --git a/data/ca.lang b/data/ca.lang
new file mode 100644
index 0000000000000000000000000000000000000000..1e75f2920f82c85580a984f8452120b99e793aa1
GIT binary patch
literal 331
zcmZvYF;2rk5Ji0kPVkk+Nr43gB~U;Ui2y=E)D!QpSs3pwvvyKMIS-<u;0V4~%$ih4
z>AprY|Nl3|!+pStz^SDcF{I>{!Y~XGwoc*vYtV*j*Z+X9A$fP+o<@qSsS0Y51*9zJ
zx0r0tc9Y_25mKw9=sX&VqjgQ5-?F_!O{#3OB*BK4NBjyq_pJug_1|5#Adpe+KXY_m
z&$W&;2xC;vpR!<05)>aDW93FJ!zpV2mB!O+XD%~?5T2jzX2r?kf4i!xhJA5yGfrO)
goOt}>#59x5z#iVMSp=pmsfpqaZ`q#jhW#-70^Ry}mH+?%

literal 0
HcmV?d00001

diff --git a/data/cs.lang b/data/cs.lang
new file mode 100644
index 0000000000000000000000000000000000000000..cff2b09d0c5f1fdf3b31e1a15177d8023759d42c
GIT binary patch
literal 277
zcmZvXQA)#55Jle}+`y$2Qo#mYfE2+WK}xZx;NQedYe@3u@m`FW(j~Zner5q~!Jn9I
zHBRfN!hFnJhI`L7S95lfQoqXzL10+={^&kKh0LzRm-NhN@J2<R+4a<sV;^GiYusET
ziZ<ulC^GXWNjx<u$-SN-uh@4jlJ|n(`W>fSs%gmCO5L@VKzhFDi>^9<t<CJAkp8P;
z+~3{8aw3PYiDI>ib<i5ZXqKgyqtk!c%*pbYMpii#iV(-~us7q!-x^pPYoPX_stFTq
Op++JlHW%ArKMX(l)@jB7

literal 0
HcmV?d00001

diff --git a/data/da.lang b/data/da.lang
new file mode 100644
index 0000000000000000000000000000000000000000..e682717308f5db0c93b811f20ac0b7435700252c
GIT binary patch
literal 102
zcmXAh(FuSs3<a}+D`Ww)h64!x2OCOgXiHjgduzqNciiy+U^}#-bWFuN265~fOryBq
qgm!Yy)0T)=wZdWUu7)>T(j3>yRlHI02ms5T{`&hOqVWKXXN(v6za{4Y

literal 0
HcmV?d00001

diff --git a/data/de.lang b/data/de.lang
new file mode 100644
index 0000000000000000000000000000000000000000..76868a2967122a444a77f3c803236dcde4e9d8c1
GIT binary patch
literal 323
zcmZwDv2MaJ5C&ks085|X7efUD7JY!KOA$gaAlj-Dn;ReYsmUF35*QG#-qfU7Dlwkq
z`~CfAHft4W2%ZTmIcTa}!zv^=so?C&Z<a7Sx+A69Y6_^hfu{ua7+>bsF@%fQpro3_
z?DoWgKrDo{OGEBSQ_LHI>cZvE(29p^5BJie7BNuid<LA`<jI=tlD_ivmVtfl9n;5d
z1HGYEubA9c--%0zD<WRlKZB(w=VwzmF%Qc@G9azBX7u@2b=x;JkN?KmA`1wU+;`d^
OV6R%?@^tNfy6zVMd~!(u

literal 0
HcmV?d00001

diff --git a/data/el.lang b/data/el.lang
new file mode 100644
index 0000000000000000000000000000000000000000..9c9af41ac13eaf58eb57d76d745e19143efddba0
GIT binary patch
literal 131
zcmZQz00X6Si_dL5-*~?B+@5o5&+R?8|9q3ex#j290EJr4Z9m_nr>DoD1{46PX*sv^
n+!}@R4M0V$AZja6tN|#~a&8S!=T@M3+Qg}}Qm8hl{r?{T4H-?c

literal 0
HcmV?d00001

diff --git a/data/en.lang b/data/en.lang
new file mode 100644
index 0000000000000000000000000000000000000000..a4c40e86ecbeea890f646e394475edeb8fb2c6a0
GIT binary patch
literal 312
zcmZvXL2Cjr5QXy#yz~z|JQO_`^jau;P(eXKTBPS`leMAQOh~d8EB<ynYkOJnHjjDp
z=6$M~bL$NP7bHstF4UYFDvkr{#0|d5f4Oj&M2a?L&FO&hY2gfp=jmmrHVc=drxOSb
zMcGl2n~a$3(Q%vo3HgIUum%(i+US{#h{AWG)oK}vO_Fuz?fzv0PFOE6>KeSe0;)TA
zrz&TjrTlFc<5&$||G#c2YOU4a?GFUI8;E-BYY2iwjf833<@~U)pJx~K(Dyw-9M|hF
D)EsPN

literal 0
HcmV?d00001

diff --git a/data/en_AU.lang b/data/en_AU.lang
new file mode 100644
index 0000000..30b6b2b
--- /dev/null
+++ b/data/en_AU.lang
@@ -0,0 +1 @@
+ÿþÿþÿþÿþÿþÿþÿþÿÿ
\ No newline at end of file
diff --git a/data/en_GB.lang b/data/en_GB.lang
new file mode 100644
index 0000000..30b6b2b
--- /dev/null
+++ b/data/en_GB.lang
@@ -0,0 +1 @@
+ÿþÿþÿþÿþÿþÿþÿþÿÿ
\ No newline at end of file
diff --git a/data/es.lang b/data/es.lang
new file mode 100644
index 0000000000000000000000000000000000000000..20ff18a58861da1bb165766d7d47bcc2ae04c570
GIT binary patch
literal 297
zcmZ`!OG*Pl6znT_gCZa#3kP!m5iy&9kq`*3U#6d-lbL>Pe-I5hkZX^Sdu4pB;7WHz
zQD1ZSC`gP@te|6#=m^d~OYEt2r%w;dc%^Rd{PrqP;FubTTW|+wF*;lyM`pQ@lp{qH
zkDdbIr7$>U+7QTRj!x59fs!qGCaroyDjTPO{zx~gxzAB-X<0J~>(#?QGo*ITXBh8F
z%A%qa%IPCj^{ulvU|;{Je_}2cb=vQOrfG(=xxBCB)6YLFzyD#ZuO`*{F4E&LJr3t#
F_yWqOYoh=F

literal 0
HcmV?d00001

diff --git a/data/et.lang b/data/et.lang
new file mode 100644
index 0000000000000000000000000000000000000000..64329c7764ed59e549aa29e83a6a45d35a76d377
GIT binary patch
literal 166
zcmZvVu?@m75JhhY2DlOmya7r94T6e@0Z#HMy7=ToKF3*z6__A<#h_Falwa@ZeE?`~
zQz2y5$b~ec1&Yi`^5n56oJoVk?l{uO$=r}SR3g9OK$J3^TQRo$SA9P2SeCco^@98F
g5W`0N3H#-hSaDD;I2avZ*Z$mYUFTd~0qR=o2U4&;CIA2c

literal 0
HcmV?d00001

diff --git a/data/eu.lang b/data/eu.lang
new file mode 100644
index 0000000000000000000000000000000000000000..f6bb522748851decd99d24315637a7b03ddf0a57
GIT binary patch
literal 297
zcmZvX!D_-#5JlflbU(OKN`n1>QYdC2xG0Laz9rK*#JmZU7Ya}Ob<;^pcW#G!&zu{o
zDoZ5Eh*X2VacLzsMUS3sDAk&xRa#uvw*_rC1&lo#ztlQpQIHtg(M-boj?Wy?DDluD
zGSWz#9s<p4o~s?zp$GBINP~p^0p_*G4#)kDxK>AQH}r`_OTV}@8aA0>pf{;s>8v(O
z>W~<56`rbpodjPpKP<~~x`*e}-&Feeok~mJxFUy*8FYQQQC97W4st=9?$h)GL0fD2

literal 0
HcmV?d00001

diff --git a/data/fr.lang b/data/fr.lang
new file mode 100644
index 0000000000000000000000000000000000000000..96d09143979f744b8ff720757aee8816fff2cc75
GIT binary patch
literal 371
zcmZutOG*Pl5bYDV@&IpVvQTs@h)8geMZlfwn(3O@q^G;>PlASk*YF0;Ip!uF#Icen
z1S1qh74_=Xd!?#r8+=NpvJB0zCQ9N2;~F1Z%Er4SgHTMuitNI;`FWtgF<tmLNAM-W
ze!jgM%`Th9kjs!(Vtu*U7ixCbG^T#yh~gME#moq?@9MtO+_tiaRFiXk$KVWhOaHR1
zlW-s3REv9;;}03>$SE;aT>S%uFLDxx+D4YJB+EigqTwTnTihCb15M&|Yvq7*tWG97
qxxe~`FLgE{`&<~0`)}Z3_YI81?-*3@>V1p#)kdBEL0m&1!|)B6F_BCF

literal 0
HcmV?d00001

diff --git a/data/gl.lang b/data/gl.lang
new file mode 100644
index 0000000000000000000000000000000000000000..d2e3f733f2b6dee9f011298a8e7c0eeeda8b7e9b
GIT binary patch
literal 212
zcmZvWF$%&!5JmS2-r!fFg^M0R(g}*4^_Wb;qPw&18U;g6WNB#^@0FM+SlNC)?>&`l
z#33?#X)?i)0|>_D5-g?W^>D}-S2`YyD`uWNho~hKNChTCbFb!g^Hi&)l}G`lgC$Qm
zm5f{reBg^A%kIqJn37}aC5%|^2OIq%E2T#3f${rmt-Dr@lVRL_OR)Wv0F&N7?R#+(
Lv8Wbx*LK|-TiZ_M

literal 0
HcmV?d00001

diff --git a/data/id.lang b/data/id.lang
new file mode 100644
index 0000000000000000000000000000000000000000..e161a7ced01bcdef2828e27d5e24e0688f055340
GIT binary patch
literal 301
zcmZvXyH3ME6h!?M)T2~M!RrHnh6V(Zg@UNZ*^9aC!`7}>$cpmoF>4G|DQ-9S%$(|W
ztA-YaJqLL44R?fw_bz%Sg&M5(SBF&zM8y}K)zF^z>?Nj)F1A&@&EYd!%Ya@6Vq|EM
zq!E{W7>Pj~KVTGTS0ZLUMebck11qP9kIzgC@b%>h9GLNNk9EUV%XgB6c&FxOMj1MK
vl;q|V>#Y9Y^fzSQF&(SRx5WkZj|&_}iC7oc%`dYkHj)@i>HhjK9jECV#D{HM

literal 0
HcmV?d00001

diff --git a/data/it.lang b/data/it.lang
new file mode 100644
index 0000000000000000000000000000000000000000..3f8e5d41e69c2a2cf4c23e8c8ce5713556d56aac
GIT binary patch
literal 345
zcmZvYK~BRk5Jhte)?eMUT@V3##D)ctiiD5=vFl(DVT9wc>;$A#y$|=`UQO+=Lh8o0
zX6FBS-_>2y1x-ob#4#MVEyr?0{JX}EMo}-Y?A&rG7K`1*egRAPCif}6Jr5K(rdnfL
zZJ#9#<YXKPgC}$p0>OMRet(d9>IosTVavYft{g~)yysXXxyvvV#gu0nPHlK?e9F@q
zaPS$>N>M7F9yicZYHqP|c?-qtZ8a#w;YRE={2U+;u3_br_1XPQ`wytD>*-KkZR9Jf
f6)%60@i0fmDu2ZqMhi(BDbtipirwXYI!x0Md?<ej

literal 0
HcmV?d00001

diff --git a/data/ja.lang b/data/ja.lang
new file mode 100644
index 0000000000000000000000000000000000000000..0874920336a773ca075de91c4ed173851e52ff43
GIT binary patch
literal 341
zcmZvY&q_j35Qoo`#KBcTUFrd%O`D)a2~k_YkV{cwixwhuW)QMJ1WCEL!L?G0%2VN{
zOzdHPp6V&QO{bM0%xY%%ecy~)-Op@qg*&;Kd?vqH*b8<GISq3Rs=(MUF1z|G==|rQ
z4fE;FE<q<SeV7PTg}H;N!NfSAFbngnQ^na*N^J~2nyzvRdIz<^x8RQ7YmG%cf^NVJ
zu7PE{2Nv>$=fv*n#YLSz{`LKLqpQ+m6YN@gS)9cx7Kx=rJt>XBn;2WY5N79PW?f&r
zEx77Yhf|X2%1w6^sfkg~5poa&$xuy$x?ZeaoGVGn`v1rDivJk+3Df{f_2m3ym?XbO
CHNqGG

literal 0
HcmV?d00001

diff --git a/data/nl.lang b/data/nl.lang
new file mode 100644
index 0000000000000000000000000000000000000000..8c957181167d48de3e169097ddcdd2f82eb4d136
GIT binary patch
literal 302
zcmZvX!D<3Q5Jcw}@&|<w(1VNl0LdYOh&f2W<lH#D<Fe!QGCR1S_-EeoU#>m7$K*7{
zP+j%Pd~7AaF$Ywklz5_4F+5-N<4l1{bmZ$QxOqbj$F`8@a2AQMjLiy@>*6*syESu}
zkW*@+n9wn+LzDEiDm!Ymq&-luP?O`|d*g*Hg4+M7F#B)OvmChp`h=9ZYkK6Qr<U0#
z1|5zmmoVNdyHxrt)jZ2`ApA>iUe+T7kDNtO^bhm;Gfu>Am^k-D4pSXAL|sHqxW3)`
HN8djI*lui7

literal 0
HcmV?d00001

diff --git a/data/pl.lang b/data/pl.lang
new file mode 100644
index 0000000000000000000000000000000000000000..768900c3f357ae56e0b0db28d3a16b1c43aacba0
GIT binary patch
literal 275
zcmZvWF;2rk6h!w9Tws(6B(TB_DALd%7f48SAA7OBH{QS6wYADdX=rkWD950s!@gFW
z1sWufrkG+h@2R^7*65@e4{$!|Ds6fi_h9=fzN4yTBt%*pw#|(rr+p~IHxO`*#df({
zsK-(aO&{pU<rC9?zI#HF(9`rrh*i?l(XwulbTDKkk|i*rPeUcS=KKYy>r!fJLABQb
z>){3Wt1rUlUmbPv{Odc<s3?m0q?S)V<|x0-GslNM5-zj&6(XEO9uFoYZF#`<b~m5q
F`3w$3YbF2y

literal 0
HcmV?d00001

diff --git a/data/pt.lang b/data/pt.lang
new file mode 100644
index 0000000000000000000000000000000000000000..023ba19fe2a3b42d214a2c909aa33ba8260fbd8d
GIT binary patch
literal 392
zcmZutJ5B>J5Zyy?fKjTXzzPRI6wsttKth5NP4Hwj%G%@gCy^56G!#@^fOhYd#olc|
z&^_7nzEyYMzYA=H!AS`H=Z;#CbtDf01|5PG2pkFa*lyW2mku5Ipu{)uCMI94?qGIY
zo@NT3$@7N0MERAhCQtoGMi9wn0ZmzJC#rg_B}9*q%;fO!RF6_tA_ge*F^;DlqnW7O
zaKx4msEZ!i{F9NxtnxQkrB^n3(dmG{g6wHsd|XRWAk)WslBNoC0o#8W@&X8fn#4YX
z8`js0lKdZ+i@MCCe?(JC4d-fkiv~5q%QP4~j)TEGZ?q_DlI;>|KUNbsUY&;XFnj~B
C(U89Y

literal 0
HcmV?d00001

diff --git a/data/pt_BR.lang b/data/pt_BR.lang
new file mode 100644
index 0000000000000000000000000000000000000000..8f1965fea3b92bcf42b71f5d5389f2f48ece2cdb
GIT binary patch
literal 293
zcmZvXF-`+95Ji0jZt#_cq+kUHKokU_NCBZph<b=8k;U5M*la*VISmD(pyUL;SC(-i
zsObI_^Zxs0d|TcH<r7hIE?;YI(Q<+d3rU{JNBQOqD|n&y$%W-fq{t~_E*=7BG1#1L
z2WEEl>K+-Lho?wbb&Q2LP<ZC#6vP_9c}{^zVVc9*)f6d_f_~|GS9~LBX|5-Ghe{>f
z&!&(Llkq<;L#h}pupGsyE#t!3bA<id$Q<2Nr@!{5Y5JWxz9dhU@Nn3LyTh)b&KV&H
O-b5E}&bIxo?|%S(CTpbt

literal 0
HcmV?d00001

diff --git a/data/ru.lang b/data/ru.lang
new file mode 100644
index 0000000000000000000000000000000000000000..3de0c373f93b29b4a82b06cf44ca4b0ac7ad42d6
GIT binary patch
literal 433
zcmZvY!AiqW5JmGTLslth(1lBJ<3?~Hg6OsoDM8Uv7cNR6X+;Z)f_oAF;I$eXO%s3N
z&JQ)-N!{7ad%T%>=iWPBgcoF(qQVSwo}VaD34Sy|rFY162&Y4R5acNJhQ)+)PH)+I
zwBk(s>-PCse9>9&w!5djtMIbd@kt;ij>PY8418~lSF*q1sPc#7LlcrmYr;lF9YZ^P
z61(UkLnfH$JqkFn0Zki1NoAU&XPaUx7o*~xxDowl%c`~h8}m-^%%2%PnrN9E9qwC-
zf|R{o2^iUFx(v(&lq_gtCyurSQyXqcgI_@o@V3GqZ7`BGEG=9ZhV{bR;%vbTUlMRX
dEjeCpP!5_6npCsoRLAxQ6ME=x4(df+{{o$E|J?up

literal 0
HcmV?d00001

diff --git a/data/sk.lang b/data/sk.lang
new file mode 100644
index 0000000000000000000000000000000000000000..0c7dc14ac5ac57220306cc07e607800c82ce0748
GIT binary patch
literal 296
zcmZvXF;2rk5JmS6T;MBJQefZ!2nrga2q6$4(T(vY+1R^dt(Qe|lq2L2mY_^WOPY<Z
z6=yL8O{y8`f6crnuJ5D{-|bdv?ABr9sQrR6Q?@!ZZ%U%Z2Nk(8v(u7FX{&_o3~nx=
zG7OgItAQB5a%!oDrt%%RV;dTzTo6htGZ%g|s$3fOWMV)tG`F;f<H%t#c`mr!s>qP>
zksMDC6R^eY4TirAsdAvHleQ<iQrTr>@Ap_7iId0w$B~YZBuTdyXD@$7xbKbNZRI>+
Y7;Q%IjM|6K-MVe02^%agR^7hq4!`zwBLDyZ

literal 0
HcmV?d00001

diff --git a/data/uk.lang b/data/uk.lang
new file mode 100644
index 0000000000000000000000000000000000000000..62b22a1860cd8d6701b74ca32da53c032680cc83
GIT binary patch
literal 440
zcmZ`#yGjE=6x}b8+ie0WinZ9-2o@rUjZHuaLD3Kki?Fhfpee+F#dab#V!0bO8ceeJ
zg>!$w56OD&qzo1_%zd249528tMuH&<WSF4TNC$$shI~F^tT8g4v1p2!_Sg(DW$Qsx
zeHMJnUE}Jqb=}-(H`*7S+s&I!lU-!CUtmNG!P;Z><A@AjVk*Ah-3ol)yT==A&J5&)
z++wJ)ChMXDtAv=0OsV$GYOV>5vKu+vjQF9=ov0IE)@B`F=7AG;t$Ov&@WSm83bM!g
zBqzs*LRgMc4)&$S2r?$ZKTtohTvEzT7|~wqe3!8qp#CrW8s1ktT6~xz`wc&;g|~xG
hDuhyF9CbNehABrbOrv*UN7{Fv$u*Vkc2F&<>JQ>x1+xGE

literal 0
HcmV?d00001

diff --git a/data/zh_CN.lang b/data/zh_CN.lang
new file mode 100644
index 0000000000000000000000000000000000000000..d0cabe27b2fe1f45c626ca1408097e40c670e841
GIT binary patch
literal 284
zcmZRucs6~(v&~bV?Cw)2Pt3{A%uClTNGwP#D%Q&{N>_NXe)rS<X$qMsj~eDw8`M5(
znEQNI%ai>JpEa&$uzogU-}5EAp0;*8?d*Nlx%ydu|I?k@p6uv)vS-25jt$t118ROc
zXT#Ik`xx9_?3?_wbtyJQp+P<h&pM_lc)DmjowGs##C@`3t%7}Kimk$vo!w6-^Z|`|
z*}URuN1G;t5X54*!Fqan|Nk-QhC{rf5CHay0?@{%8=EwMKG1x>r|0>emCvT^d%kP=
X(~i{&)rPeUBB;vW@0kTu`TsuvUJ{do

literal 0
HcmV?d00001

diff --git a/data/zh_TW.lang b/data/zh_TW.lang
new file mode 100644
index 0000000000000000000000000000000000000000..6685442b5f889a403a5962d5e0361c7e51390b1a
GIT binary patch
literal 284
zcmZRuc;2$`+2*NF_svr%Pt3{A%uClTNGwP#D%Q&{N>_NXuHk9_G=<ER#|=Hz2DOhH
zdY{i~d9k_u#fmNl>z51HKVP!zX=}&R&faHz&CmM#pX^xnWJlN2rp-?~HefRjsQKxf
z4NvDxWAJ#fXUEglrPvgO2KgvF>zJnC>7t<Vbj}I|5dX=JwF(OMnJKmkPj+@c-PZ#&
z=w<VYryXsY3_=jA;YRD}>HYu5pdAkJj6wj|GYUXEpKe^DpaJxR=KDQ8&!+8pzGL09
WDf<+v4Qm-hP!+%5GYhEf|9=1x%#gwW

literal 0
HcmV?d00001

diff --git a/images/preferences/walkingpapers.png b/images/preferences/walkingpapers.png
new file mode 100644
index 0000000000000000000000000000000000000000..ea185998e011bd3852b7e292b73a46c4f09231e0
GIT binary patch
literal 1910
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

literal 0
HcmV?d00001

diff --git a/images/walkingpapers.png b/images/walkingpapers.png
new file mode 100644
index 0000000000000000000000000000000000000000..054bafc4a103d3b8e7d3287d3bb9965e1cabdc32
GIT binary patch
literal 361
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@
z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPggac77f;%eM5Jo<O0Oo-U3d7N>iI
z4^BK{z%e<0o4!Ztj8hY|AKP^wzj>qj_;IC^Cp<KG-v?a{37ylWa^}shb=|l5tKLfr
z&YanAY#bbFtYoB=xBbtW-c^V0GBUj53uQgod0+UL*QZ;)#>X0F`ffUObutgb+tn?v
zxYM7#{S(~Ok<h~!+S)Ot^Yh<n4NtE9z4ZQ_!Di!w5|1A`+bVMk{<L%Kjk<AHQEBo9
zkA9Zb;?_B7{4@DEmwqjts+v6YXGC(ETEom;rBkzw`m;;QzuZ%g`#S&CG#6v%Y+gab
z$=jbTSX8T`(Alwrb;XCQS5|?)-@pG;DR`2NVgGrTpEDf19`6Twn!(f6&t;ucLK6T7
Cbd>V|

literal 0
HcmV?d00001

diff --git a/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersAddLayerAction.java b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersAddLayerAction.java
new file mode 100644
index 0000000..ac3eb9b
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersAddLayerAction.java
@@ -0,0 +1,105 @@
+package org.openstreetmap.josm.plugins.fieldpapers;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.LatLon;
+
+@SuppressWarnings("serial")
+public class FieldPapersAddLayerAction extends JosmAction {
+
+    public FieldPapersAddLayerAction() {
+        super(tr("Scanned Map..."), "walkingpapers",
+            tr("Display a map that was previously scanned and uploaded to walking-papers.org"), null, false);
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        String wpid = JOptionPane.showInputDialog(Main.parent,
+            tr("Enter a walking-papers.org URL or ID (the bit after the ?id= in the URL)"),
+                Main.pref.get("walkingpapers.last-used-id"));
+
+        if (wpid == null || wpid.equals("")) return;
+
+        // Grab id= from the URL if we need to, otherwise get an ID
+        String mungedWpId = this.getWalkingPapersId(wpid);
+
+        if (mungedWpId == null || mungedWpId.equals("")) return;
+
+        // screen-scrape details about this id from walking-papers.org
+        String wpUrl = Main.pref.get("walkingpapers.base-url", "http://walking-papers.org/") + "scan.php?id=" + mungedWpId;
+
+        Pattern spanPattern = Pattern.compile("<span class=\"(\\S+)\">(\\S+)</span>");
+        Matcher m;
+
+        double north = 0;
+        double south = 0;
+        double east = 0;
+        double west = 0;
+        int minz = -1;
+        int maxz = -1;
+        String tile = null;
+
+        try {
+            BufferedReader r = new BufferedReader(new InputStreamReader(new URL(wpUrl).openStream(), "utf-8"));
+            for (String line = r.readLine(); line != null; line = r.readLine()) {
+                m = spanPattern.matcher(line);
+                if (m.find()) {
+                    if ("tile".equals(m.group(1))) tile = m.group(2);
+                    else if ("north".equals(m.group(1))) north = Double.parseDouble(m.group(2));
+                    else if ("south".equals(m.group(1))) south = Double.parseDouble(m.group(2));
+                    else if ("east".equals(m.group(1))) east = Double.parseDouble(m.group(2));
+                    else if ("west".equals(m.group(1))) west = Double.parseDouble(m.group(2));
+                    else if ("minzoom".equals(m.group(1))) minz = Integer.parseInt(m.group(2));
+                    else if ("maxzoom".equals(m.group(1))) maxz = Integer.parseInt(m.group(2));
+                }
+            }
+            r.close();
+            if ((tile == null) || (north == 0 && south == 0) || (east == 0 && west == 0)) throw new Exception();
+        } catch (Exception ex) {
+            JOptionPane.showMessageDialog(Main.parent,tr("Could not read information from walking-papers.org the id \"{0}\"", mungedWpId));
+            return;
+        }
+
+
+        //http://walking-papers.org/scan.php?id=rmvdr3lq
+        // The server is apparently broken and returning the WpId in the URL twice
+        // which makes it return errors when we fetch it.  So, strip out one of
+        // the dups.  This is a hack and needs to get removed when the server
+        // is fixed.
+        tile = tile.replaceFirst(mungedWpId+"/"+mungedWpId, mungedWpId);
+        Main.pref.put("walkingpapers.last-used-id", mungedWpId);
+
+        Bounds b = new Bounds(new LatLon(south, west), new LatLon(north, east));
+
+        FieldPapersLayer wpl = new FieldPapersLayer(mungedWpId, tile, b, minz, maxz);
+        Main.main.addLayer(wpl);
+
+    }
+
+    private static String getWalkingPapersId(String wpid) {
+        if (!wpid.contains("id=")) {
+            return wpid;
+        } else {
+            // To match e.g. http://walking-papers.org/scan.php?id=53h78bbx
+            final Pattern pattern = Pattern.compile("\\?id=(\\S+)");
+            final Matcher matcher = pattern.matcher(wpid);
+            final boolean found   = matcher.find();
+
+            if (found) {
+                return matcher.group(1);
+            }
+        }
+        return null;
+    }
+}
diff --git a/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersKey.java b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersKey.java
new file mode 100644
index 0000000..8d5f759
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersKey.java
@@ -0,0 +1,78 @@
+/**
+ *
+ */
+package org.openstreetmap.josm.plugins.fieldpapers;
+
+/**
+ * <p>
+ * Key for map tile. Key have just X and Y value. It have overriden {@link #hashCode()},
+ * {@link #equals(Object)} and also {@link #toString()}.
+ * </p>
+ *
+ * @author LuVar <lubomir.varga@freemap.sk>
+ * @author Dave Hansen <dave@sr71.net>
+ *
+ */
+public class FieldPapersKey {
+    private final int x;
+    private final int y;
+    private final int level;
+
+    /**
+     * <p>
+     * Constructs key for hashmaps for some tile describedy by X and Y position. X and Y are tiles
+     * positions on discrete map.
+     * </p>
+     *
+     * @param x x position in tiles table
+     * @param y y position in tiles table
+     */
+    public final boolean valid;
+    public FieldPapersKey(int level, int x, int y) {
+        this.x = x;
+        this.y = y;
+        this.level = level;
+        if (level <= 0 || x < 0 || y < 0) {
+            this.valid = false;
+            System.err.println("invalid WalkingPapersKey("+level+", "+x+", "+y+")");
+        } else {
+            this.valid = true;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns true ONLY if x and y are equals.
+     * </p>
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof FieldPapersKey) {
+            FieldPapersKey smk = (FieldPapersKey) obj;
+            if((smk.x == this.x) && (smk.y == this.y) && (smk.level == this.level)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @return  return new Integer(this.x + this.y * 10000).hashCode();
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return new Integer(this.x + this.y * 10000 + this.level * 100000).hashCode();
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "WalkingPapersKey(x=" + this.x + ",y=" + this.y + ",level=" + level + ")";
+    }
+
+}
diff --git a/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersLayer.java b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersLayer.java
new file mode 100644
index 0000000..421dec5
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersLayer.java
@@ -0,0 +1,427 @@
+package org.openstreetmap.josm.plugins.fieldpapers;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.image.ImageObserver;
+import java.net.URL;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.TreeSet;
+
+import javax.swing.Action;
+import javax.swing.Icon;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
+import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
+import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * Class that displays a slippy map layer. Adapted from SlippyMap plugin for Walking Papers use.
+ *
+ * @author Frederik Ramm <frederik@remote.org>
+ * @author LuVar <lubomir.varga@freemap.sk>
+ * @author Dave Hansen <dave@sr71.net>
+ *
+ */
+public class FieldPapersLayer extends Layer implements ImageObserver {
+    /**
+     * Actual zoom lvl. Initial zoom lvl is set to
+     * {@link WalkingPapersPreferences#getMinZoomLvl()}.
+     */
+    private int currentZoomLevel;
+    private HashMap<FieldPapersKey, FieldPapersTile> tileStorage = null;
+
+    private Point[][] pixelpos = new Point[21][21];
+    private LatLon lastTopLeft;
+    private LatLon lastBotRight;
+    private int viewportMinX, viewportMaxX, viewportMinY, viewportMaxY;
+    private Image bufferImage;
+    private boolean needRedraw;
+
+    private int minzoom, maxzoom;
+    private Bounds printBounds;
+    private String tileUrlTemplate;
+    private String walkingPapersId;
+
+    @SuppressWarnings("serial")
+    public FieldPapersLayer(String id, String tile, Bounds b, int minz, int maxz) {
+        super(tr("Walking Papers: {0}", id));
+        setBackgroundLayer(true);
+        walkingPapersId = id;
+
+        tileUrlTemplate = tile;
+        this.printBounds = b;
+        this.minzoom = minz; this.maxzoom = maxz;
+        currentZoomLevel = minz;
+
+        clearTileStorage();
+
+        MapView.addLayerChangeListener(new LayerChangeListener() {
+            public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+                // if user changes to a walking papers layer, zoom there just as if
+                // it was newly added
+                layerAdded(newLayer);
+            }
+
+            public void layerAdded(Layer newLayer) {
+                // only do something if we are affected
+                if (newLayer != FieldPapersLayer.this) return;
+                BoundingXYVisitor bbox = new BoundingXYVisitor();
+                bbox.visit(printBounds);
+                Main.map.mapView.recalculateCenterScale(bbox);
+                needRedraw = true;
+            }
+
+            public void layerRemoved(Layer oldLayer) {
+                if (oldLayer == FieldPapersLayer.this) {
+                    MapView.removeLayerChangeListener(this);
+                }
+            }
+        });
+    }
+
+    /**
+     * Zoom in, go closer to map.
+     */
+    public void increaseZoomLevel() {
+        if (currentZoomLevel < maxzoom) {
+            currentZoomLevel++;
+            needRedraw = true;
+        }
+    }
+
+    /**
+     * Zoom out from map.
+     */
+    public void decreaseZoomLevel() {
+        if (currentZoomLevel > minzoom) {
+            currentZoomLevel--;
+            needRedraw = true;
+        }
+    }
+
+    public void clearTileStorage() {
+        tileStorage = new HashMap<FieldPapersKey, FieldPapersTile>();
+        checkTileStorage();
+    }
+
+    static class TileTimeComp implements Comparator<FieldPapersTile> {
+        public int compare(FieldPapersTile s1, FieldPapersTile s2) {
+            long t1 = s1.access_time();
+            long t2 = s2.access_time();
+            if (s1 == s2) return 0;
+            if (t1 == t2) {
+                t1 = s1.hashCode();
+                t2 = s2.hashCode();
+            }
+            if (t1 < t2) return -1;
+            return 1;
+        }
+    }
+
+    long lastCheck = 0;
+    /**
+     * <p>
+     * Check if tiles.size() is not more than max_nr_tiles. If yes, oldest tiles by timestamp
+     * are fired out from cache.
+     * </p>
+     */
+    public void checkTileStorage() {
+        long now = System.currentTimeMillis();
+        if (now - lastCheck < 1000) return;
+        lastCheck = now;
+        TreeSet<FieldPapersTile> tiles = new TreeSet<FieldPapersTile>(new TileTimeComp());
+        tiles.addAll(tileStorage.values());
+        int max_nr_tiles = 100;
+        if (tiles.size() < max_nr_tiles) {
+            return;
+        }
+        int dropCount = tiles.size() - max_nr_tiles;;
+        for (FieldPapersTile t : tiles) {
+            if (dropCount <= 0)
+                break;
+            t.dropImage();
+            dropCount--;
+        }
+    }
+
+    void loadSingleTile(FieldPapersTile tile) {
+        tile.loadImage();
+        this.checkTileStorage();
+    }
+
+    /*
+     * Attempt to approximate how much the image is
+     * being scaled.  For instance, a 100x100 image
+     * being scaled to 50x50 would return 0.25.
+     */
+    Double getImageScaling(Image img, Point p0, Point p1) {
+        int realWidth = img.getWidth(this);
+        int realHeight = img.getHeight(this);
+        if (realWidth == -1 || realHeight == -1)
+                return null;
+        int drawWidth = p1.x - p0.x;
+        int drawHeight = p1.x - p0.x;
+
+        double drawArea = drawWidth * drawHeight;
+        double realArea = realWidth * realHeight;
+
+        return drawArea / realArea;
+    }
+
+    /**
+     */
+    @Override
+    public void paint(Graphics2D g, MapView mv, Bounds bounds) {
+        LatLon topLeft = mv.getLatLon(0, 0);
+        LatLon botRight = mv.getLatLon(mv.getWidth(), mv.getHeight());
+        Graphics2D oldg = g;
+
+        if (botRight.lon() == 0.0 || botRight.lat() == 0) {
+                // probably still initializing
+                return;
+        }
+        if (lastTopLeft != null && lastBotRight != null
+                && topLeft.equalsEpsilon(lastTopLeft)
+                && botRight.equalsEpsilon(lastBotRight) && bufferImage != null
+                && mv.getWidth() == bufferImage.getWidth(null)
+                && mv.getHeight() == bufferImage.getHeight(null) && !needRedraw) {
+
+            g.drawImage(bufferImage, 0, 0, null);
+            return;
+        }
+
+        needRedraw = false;
+        lastTopLeft = topLeft;
+        lastBotRight = botRight;
+        bufferImage = mv.createImage(mv.getWidth(), mv.getHeight());
+        g = (Graphics2D) bufferImage.getGraphics();
+
+        if (!LatLon.isValidLat(topLeft.lat())  ||
+            !LatLon.isValidLat(botRight.lat()) ||
+            !LatLon.isValidLon(topLeft.lon())  ||
+            !LatLon.isValidLon(botRight.lon()))
+            return;
+
+        viewportMinX = lonToTileX(topLeft.lon());
+        viewportMaxX = lonToTileX(botRight.lon());
+        viewportMinY = latToTileY(topLeft.lat());
+        viewportMaxY = latToTileY(botRight.lat());
+
+        if (viewportMinX > viewportMaxX) {
+            int tmp = viewportMinX;
+            viewportMinX = viewportMaxX;
+            viewportMaxX = tmp;
+        }
+        if (viewportMinY > viewportMaxY) {
+            int tmp = viewportMinY;
+            viewportMinY = viewportMaxY;
+            viewportMaxY = tmp;
+        }
+
+        if (viewportMaxX-viewportMinX > 18) return;
+        if (viewportMaxY-viewportMinY > 18) return;
+
+        for (int x = viewportMinX - 1; x <= viewportMaxX + 1; x++) {
+            double lon = tileXToLon(x);
+            for (int y = viewportMinY - 1; y <= viewportMaxY + 1; y++) {
+                LatLon tmpLL = new LatLon(tileYToLat(y), lon);
+                pixelpos[x - viewportMinX + 1][y - viewportMinY + 1] = mv.getPoint(Main.getProjection()
+                        .latlon2eastNorth(tmpLL));
+            }
+        }
+
+        g.setColor(Color.DARK_GRAY);
+
+        Double imageScale = null;
+        int count = 0;
+
+        for (int x = viewportMinX-1; x <= viewportMaxX; x++) {
+
+            for (int y = viewportMinY-1; y <= viewportMaxY; y++) {
+                FieldPapersKey key = new FieldPapersKey(currentZoomLevel, x, y);
+                FieldPapersTile tile;
+                tile = tileStorage.get(key);
+                if (!key.valid) continue;
+                if (tile == null) {
+                    // check if tile is in range
+                    Bounds tileBounds = new Bounds(new LatLon(tileYToLat(y+1), tileXToLon(x)),
+                        new LatLon(tileYToLat(y), tileXToLon(x+1)));
+                    if (!tileBounds.asRect().intersects(printBounds.asRect())) continue;
+                    tile = new FieldPapersTile(x, y, currentZoomLevel, this);
+                    tileStorage.put(key, tile);
+                    loadSingleTile(tile);
+                    checkTileStorage();
+                }
+                Image img = tile.getImage();
+
+                if (img != null) {
+                    Point p = pixelpos[x - viewportMinX + 1][y - viewportMinY + 1];
+                    Point p2 = pixelpos[x - viewportMinX + 2][y - viewportMinY + 2];
+                    g.drawImage(img, p.x, p.y, p2.x - p.x, p2.y - p.y, this);
+                    if (imageScale == null)
+                        imageScale = getImageScaling(img, p, p2);
+                    count++;
+                }
+            }
+        }
+
+        if (count == 0)
+        {
+            //System.out.println("no images on " + walkingPapersId + ", return");
+            return;
+        }
+
+        oldg.drawImage(bufferImage, 0, 0, null);
+
+        if (imageScale != null) {
+            // If each source image pixel is being stretched into > 3
+            // drawn pixels, zoom in... getting too pixelated
+            if (imageScale > 3) {
+                increaseZoomLevel();
+                this.paint(oldg, mv, bounds);
+            }
+
+            // If each source image pixel is being squished into > 0.32
+            // of a drawn pixels, zoom out.
+            else if (imageScale < 0.32) {
+                decreaseZoomLevel();
+                this.paint(oldg, mv, bounds);
+            }
+        }
+    }// end of paint metod
+
+    FieldPapersTile getTileForPixelpos(int px, int py) {
+        int tilex = viewportMaxX;
+        int tiley = viewportMaxY;
+        for (int x = viewportMinX; x <= viewportMaxX; x++) {
+            if (pixelpos[x - viewportMinX + 1][0].x > px) {
+                tilex = x - 1;
+                break;
+            }
+        }
+
+        if (tilex == -1) return null;
+
+        for (int y = viewportMinY; y <= viewportMaxY; y++) {
+            if (pixelpos[0][y - viewportMinY + 1].y > py) {
+                tiley = y - 1;
+                break;
+            }
+        }
+
+        if (tiley == -1) return null;
+
+        FieldPapersKey key = new FieldPapersKey(currentZoomLevel, tilex, tiley);
+        if (!key.valid) {
+            System.err.println("getTileForPixelpos("+px+","+py+") made invalid key");
+            return null;
+        }
+        FieldPapersTile tile = tileStorage.get(key);
+        if (tile == null)
+            tileStorage.put(key, tile = new FieldPapersTile(tilex, tiley, currentZoomLevel, this));
+        checkTileStorage();
+        return tile;
+    }
+
+    @Override
+    public Icon getIcon() {
+        return ImageProvider.get("walkingpapers");
+    }
+
+    @Override
+    public Object getInfoComponent() {
+        return getToolTipText();
+    }
+
+    @Override
+    public Action[] getMenuEntries() {
+        return new Action[] {
+                LayerListDialog.getInstance().createShowHideLayerAction(),
+                LayerListDialog.getInstance().createDeleteLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                // color,
+                // new JMenuItem(new RenameLayerAction(associatedFile, this)),
+                SeparatorLayerAction.INSTANCE,
+                new LayerListPopup.InfoAction(this) };
+    }
+
+    @Override
+    public String getToolTipText() {
+        return tr("Walking Papers layer ({0}) in zoom {1}", this.getWalkingPapersId(), currentZoomLevel);
+    }
+
+    @Override
+    public boolean isMergable(Layer other) {
+        return false;
+    }
+
+    @Override
+    public void mergeFrom(Layer from) {
+    }
+
+    @Override
+    public void visitBoundingBox(BoundingXYVisitor v) {
+        if (printBounds != null)
+            v.visit(printBounds);
+    }
+
+    private int latToTileY(double lat) {
+        double l = lat / 180 * Math.PI;
+        double pf = Math.log(Math.tan(l) + (1 / Math.cos(l)));
+        return (int) (Math.pow(2.0, currentZoomLevel - 1) * (Math.PI - pf) / Math.PI);
+    }
+
+    private int lonToTileX(double lon) {
+        return (int) (Math.pow(2.0, currentZoomLevel - 3) * (lon + 180.0) / 45.0);
+    }
+
+    private double tileYToLat(int y) {
+        return Math.atan(Math.sinh(Math.PI
+                - (Math.PI * y / Math.pow(2.0, currentZoomLevel - 1))))
+                * 180 / Math.PI;
+    }
+
+    private double tileXToLon(int x) {
+        return x * 45.0 / Math.pow(2.0, currentZoomLevel - 3) - 180.0;
+    }
+
+    public boolean imageUpdate(Image img, int infoflags, int x, int y,
+            int width, int height) {
+        boolean done = ((infoflags & (ERROR | FRAMEBITS | ALLBITS)) != 0);
+        if ((infoflags & ERROR) != 0) return false;
+        // Repaint immediately if we are done, otherwise batch up
+        // repaint requests every 100 milliseconds
+        needRedraw = true;
+        Main.map.repaint(done ? 0 : 100);
+        return !done;
+    }
+
+    public String getWalkingPapersId() {
+        return walkingPapersId;
+    }
+
+    public URL formatImageUrl(int x, int y, int z) {
+        String urlstr = tileUrlTemplate.
+            replace("{x}", String.valueOf(x)).
+            replace("{y}", String.valueOf(y)).
+            replace("{z}", String.valueOf(z));
+        try {
+            return new URL(urlstr);
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+}
diff --git a/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersPlugin.java b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersPlugin.java
new file mode 100644
index 0000000..bfbf7b9
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersPlugin.java
@@ -0,0 +1,33 @@
+package org.openstreetmap.josm.plugins.fieldpapers;
+
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
+import static org.openstreetmap.josm.tools.I18n.marktr;
+
+import java.awt.event.KeyEvent;
+
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.MainMenu;
+import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginInformation;
+
+/**
+ * Main class for the walking papers plugin.
+ *
+ * @author Frederik Ramm <frederik@remote.org>
+ *
+ */
+public class FieldPapersPlugin extends Plugin
+{
+    static JMenu walkingPapersMenu;
+
+    public FieldPapersPlugin(PluginInformation info)
+    {
+        super(info);
+        MainMenu menu = Main.main.menu;
+        walkingPapersMenu = menu.addMenu(marktr("Walking Papers"), KeyEvent.VK_K, menu.defaultMenuPos, ht("/Plugin/WalkingPapers"));
+        walkingPapersMenu.add(new JMenuItem(new FieldPapersAddLayerAction()));
+    }
+}
diff --git a/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersTile.java b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersTile.java
new file mode 100644
index 0000000..9679e03
--- /dev/null
+++ b/src/org/openstreetmap/josm/plugins/fieldpapers/FieldPapersTile.java
@@ -0,0 +1,67 @@
+package org.openstreetmap.josm.plugins.fieldpapers;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.net.URL;
+
+/**
+ * Class that contains information about one single slippy map tile.
+ *
+ * @author Frederik Ramm <frederik@remote.org>
+ * @author LuVar <lubomir.varga@freemap.sk>
+ * @author Dave Hansen <dave@sr71.net>
+ *
+ */
+public class FieldPapersTile {
+    private Image tileImage;
+    long timestamp;
+
+    int x;
+    int y;
+    int z;
+
+    FieldPapersLayer parentLayer;
+
+
+    public FieldPapersTile(int x, int y, int z, FieldPapersLayer parent) {
+        this.x = x;
+        this.y = y;
+        this.z = z;
+        parentLayer = parent;
+        timestamp = System.currentTimeMillis();
+    }
+
+    public URL getImageUrl() {
+        return parentLayer.formatImageUrl(x, y, z);
+    }
+
+    public void loadImage() {
+        URL imageUrl = this.getImageUrl();
+        tileImage = Toolkit.getDefaultToolkit().createImage(imageUrl);
+        Toolkit.getDefaultToolkit().sync();
+        timestamp = System.currentTimeMillis();
+    }
+
+    public Image getImage() {
+        timestamp = System.currentTimeMillis();
+        return tileImage;
+    }
+
+    public void dropImage() {
+        tileImage = null;
+        //  This should work in theory but doesn't seem to actually
+        //  reduce the X server memory usage
+        //tileImage.flush();
+    }
+
+    public long access_time() {
+        return timestamp;
+    }
+
+    public boolean equals(Object o) {
+        if (!(o instanceof FieldPapersTile))
+            return false;
+        FieldPapersTile other = (FieldPapersTile) o;
+        return (this.x == other.x && this.y == other.y && this.z == other.z);
+    }
+}