[josm-plugins] 155/369: Imported Upstream version 0.0.svn23040
Bas Couwenberg
sebastic at xs4all.nl
Sat Oct 18 12:03:37 UTC 2014
This is an automated email from the git hooks/post-receive script.
sebastic-guest pushed a commit to branch master
in repository josm-plugins.
commit 9776afb71cc8fe8bcbeb67015c4b8fe7c310d556
Author: David Paleino <dapal at debian.org>
Date: Tue Sep 7 11:05:52 2010 +0200
Imported Upstream version 0.0.svn23040
---
cadastre-fr/.settings/org.eclipse.jdt.core.prefs | 12 +
cadastre-fr/build.xml | 42 +-
cadastre-fr/src/cadastre_fr/Address.java | 17 +-
cadastre-fr/src/cadastre_fr/CadastreInterface.java | 13 +
cadastre-fr/src/cadastre_fr/CadastrePlugin.java | 5 +-
.../src/cadastre_fr/CadastrePreferenceSetting.java | 9 +-
cadastre-fr/src/cadastre_fr/WMSLayer.java | 50 +-
editgpx/build.xml | 16 +-
.../josm/plugins/editgpx/EditGpxLayer.java | 24 +-
.../josm/plugins/editgpx/EditGpxPlugin.java | 1 -
measurement/build.xml | 16 +-
.../josm/plugins/measurement/MeasurementLayer.java | 19 +-
{wmsplugin => remotecontrol}/.classpath | 14 +-
remotecontrol/.project | 18 +
remotecontrol/CONTRIBUTION | 6 +
remotecontrol/README | 9 +
{cadastre-fr => remotecontrol}/build.xml | 36 +-
remotecontrol/images/preferences/remotecontrol.gif | Bin 0 -> 472 bytes
.../josm/plugins/remotecontrol/HttpServer.java | 75 ++
.../josm/plugins/remotecontrol/PermissionPref.java | 24 +
.../remotecontrol/PermissionPrefWithDefault.java | 22 +
.../plugins/remotecontrol/RemoteControlPlugin.java | 106 ++
.../remotecontrol/RemoteControlPreferences.java | 80 ++
.../josm/plugins/remotecontrol/RequestHandler.java | 207 ++++
.../RequestHandlerBadRequestException.java | 4 +
.../RequestHandlerErrorException.java | 4 +
.../remotecontrol/RequestHandlerException.java | 4 +
.../RequestHandlerForbiddenException.java | 5 +
.../plugins/remotecontrol/RequestProcessor.java | 308 +++++
.../remotecontrol/handler/AddNodeHandler.java | 68 ++
.../remotecontrol/handler/ImportHandler.java | 52 +
.../remotecontrol/handler/LoadAndZoomHandler.java | 167 +++
.../remotecontrol/handler/VersionHandler.java | 41 +
routing/build.xml | 16 +-
.../innovant/josm/plugin/routing/RoutingLayer.java | 22 +-
slippymap/build.xml | 18 +-
.../josm-slippymap.launch | 4 +-
.../josm/plugins/slippymap/SlippyMapLayer.java | 58 +-
.../josm/plugins/slippymap/SlippyMapPlugin.java | 48 +-
.../slippymap/SlippyMapPreferenceSetting.java | 34 +-
.../plugins/slippymap/SlippyMapPreferences.java | 57 +-
.../josm/plugins/slippymap/SlippyMapTile.java | 0
svn-info.xml | 8 +-
wmsplugin/.classpath | 4 +-
wmsplugin/.settings/org.eclipse.jdt.core.prefs | 12 +
wmsplugin/build.xml | 19 +-
wmsplugin/josm-wmsplugin.launch | 2 +-
wmsplugin/sources.cfg | 6 +-
wmsplugin/src/wmsplugin/AddWMSLayerPanel.java | 507 ++++++++
wmsplugin/src/wmsplugin/GeorefImage.java | 208 ++--
wmsplugin/src/wmsplugin/Grabber.java | 212 ++--
wmsplugin/src/wmsplugin/HTMLGrabber.java | 61 +-
.../src/wmsplugin/Map_Rectifier_WMSmenuAction.java | 432 +++----
wmsplugin/src/wmsplugin/WMSAdjustAction.java | 368 +++---
wmsplugin/src/wmsplugin/WMSDownloadAction.java | 42 +-
wmsplugin/src/wmsplugin/WMSGrabber.java | 354 +++---
wmsplugin/src/wmsplugin/WMSLayer.java | 1228 ++++++++++++--------
wmsplugin/src/wmsplugin/WMSPlugin.java | 578 +++++----
wmsplugin/src/wmsplugin/WMSPreferenceEditor.java | 66 +-
wmsplugin/src/wmsplugin/WMSRemoteHandler.java | 110 ++
wmsplugin/src/wmsplugin/WMSRequest.java | 101 ++
61 files changed, 4282 insertions(+), 1767 deletions(-)
diff --git a/cadastre-fr/.settings/org.eclipse.jdt.core.prefs b/cadastre-fr/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..0b5c6c4
--- /dev/null
+++ b/cadastre-fr/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Thu Mar 04 08:24:37 CET 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/cadastre-fr/build.xml b/cadastre-fr/build.xml
index fd5d8da..f8d743f 100644
--- a/cadastre-fr/build.xml
+++ b/cadastre-fr/build.xml
@@ -16,7 +16,7 @@
** > ant install
**
** To build against the core in ../../core, create a correct manifest and deploy to
-** SVN,
+** SVN,
** set the properties commit.message and plugin.main.version
** and run
** > ant publish
@@ -29,12 +29,12 @@
<property name="plugin.build.dir" value="build"/>
<property name="plugin.jar" value="${plugin.dist.dir}/${ant.project.name}.jar"/>
<property name="ant.build.javac.target" value="1.5"/>
-
-
+
+
<property name="commit.message" value="Changed constructor for Plugin" />
- <property name="plugin.main.version" value="3174" />
-
+ <property name="plugin.main.version" value="3408" />
+
<target name="init">
<mkdir dir="${plugin.build.dir}"/>
</target>
@@ -86,12 +86,12 @@
</condition>
<copy file="${plugin.jar}" todir="${josm.plugins.dir}"/>
</target>
-
+
<!--
- ************************** Publishing the plugin ***********************************
+ ************************** Publishing the plugin ***********************************
-->
<!--
- ** extracts the JOSM release for the JOSM version in ../core and saves it in the
+ ** extracts the JOSM release for the JOSM version in ../core and saves it in the
** property ${coreversion.info.entry.revision}
**
-->
@@ -103,7 +103,7 @@
<arg value="../../core"/>
</exec>
<xmlproperty file="core.info.xml" prefix="coreversion" keepRoot="true" collapseAttributes="true"/>
- <echo>Building against core revision ${coreversion.info.entry.revision}.</echo>
+ <echo>Building against core revision ${coreversion.info.entry.revision}.</echo>
<echo>Plugin-Mainversion is set to ${plugin.main.version}.</echo>
<delete file="core.info.xml" />
</target>
@@ -118,7 +118,7 @@
<arg value="commit"/>
<arg value="-m '${commit.message}'"/>
<arg value="."/>
- </exec>
+ </exec>
</target>
<!--
@@ -130,37 +130,37 @@
<env key="LANG" value="C"/>
<arg value="up"/>
<arg value="."/>
- </exec>
+ </exec>
<echo>Updating ${plugin.jar} ...</echo>
<exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
<env key="LANG" value="C"/>
<arg value="up"/>
<arg value="../dist/${plugin.jar}"/>
- </exec>
+ </exec>
</target>
-
+
<!--
- ** commits the plugin.jar
+ ** commits the plugin.jar
-->
<target name="commit-dist">
<echo>
***** Properties of published ${plugin.jar} *****
- Commit message : '${commit.message}'
+ Commit message : '${commit.message}'
Plugin-Mainversion: ${plugin.main.version}
JOSM build version: ${coreversion.info.entry.revision}
Plugin-Version : ${version.entry.commit.revision}
- ***** / Properties of published ${plugin.jar} *****
-
+ ***** / Properties of published ${plugin.jar} *****
+
Now commiting ${plugin.jar} ...
- </echo>
+ </echo>
<exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
<env key="LANG" value="C"/>
<arg value="-m '${commit.message}'"/>
- <arg value="commit"/>
+ <arg value="commit"/>
<arg value="${plugin.jar}"/>
- </exec>
+ </exec>
</target>
-
+
<target name="publish" depends="core-info,commit-current,update-current,clean,dist,commit-dist">
</target>
</project>
diff --git a/cadastre-fr/src/cadastre_fr/Address.java b/cadastre-fr/src/cadastre_fr/Address.java
index 8d398f9..d0cff1d 100644
--- a/cadastre-fr/src/cadastre_fr/Address.java
+++ b/cadastre-fr/src/cadastre_fr/Address.java
@@ -88,8 +88,8 @@ public class Address extends MapMode implements MouseListener, MouseMotionListen
final JTextField inputStreet = new JTextField();
JLabel link = new JLabel();
private Way selectedWay;
- //private Relation selectedRelation;
private boolean shift;
+ private boolean ctrl;
public Address(MapFrame mapFrame) {
super(tr("Add address"), "buildings",
@@ -120,6 +120,7 @@ public class Address extends MapMode implements MouseListener, MouseMotionListen
if (e.getButton() != MouseEvent.BUTTON1)
return;
shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+ ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
MapView mv = Main.map.mapView;
Point mousePos = e.getPoint();
List<Way> mouseOnExistingWays = new ArrayList<Way>();
@@ -142,12 +143,21 @@ public class Address extends MapMode implements MouseListener, MouseMotionListen
}
if (currentMouseNode.get(tagHouseStreet) != null) {
inputStreet.setText(currentMouseNode.get(tagHouseStreet));
+ if (ctrl) {
+ Collection<Command> cmds = new LinkedList<Command>();
+ addAddrToPrimitive(currentMouseNode, cmds);
+ if (num == null)
+ applyInputNumberChange();
+ }
setSelectedWay((Way)null);
} else {
// check if the node belongs to an associatedStreet relation
Way wayInRelationAddr = findWayInRelationAddr(currentMouseNode);
if (wayInRelationAddr == null) {
// node exists but doesn't carry address information : add tags like a new node
+ if (ctrl) {
+ applyInputNumberChange();
+ }
Collection<Command> cmds = new LinkedList<Command>();
addAddrToPrimitive(currentMouseNode, cmds);
} else {
@@ -175,6 +185,9 @@ public class Address extends MapMode implements MouseListener, MouseMotionListen
Toolkit.getDefaultToolkit().beep();
} else {
Collection<Command> cmds = new LinkedList<Command>();
+ if (ctrl) {
+ applyInputNumberChange();
+ }
if (tagPolygon.isSelected()) {
addAddrToPolygon(mouseOnExistingBuildingWays, cmds);
} else {
@@ -211,7 +224,7 @@ public class Address extends MapMode implements MouseListener, MouseMotionListen
}
private void addAddrToPrimitive(OsmPrimitive osm, Collection<Command> cmds) {
- // add the current tag addr:housenumber in node and member in relation
+ // add the current tag addr:housenumber in node and member in relation (if so configured)
if (shift) {
try {
revertInputNumberChange();
diff --git a/cadastre-fr/src/cadastre_fr/CadastreInterface.java b/cadastre-fr/src/cadastre_fr/CadastreInterface.java
index 0169279..be0d168 100644
--- a/cadastre-fr/src/cadastre_fr/CadastreInterface.java
+++ b/cadastre-fr/src/cadastre_fr/CadastreInterface.java
@@ -58,7 +58,9 @@ public class CadastreInterface {
final String cInterfaceRasterTA = "afficherCarteTa.do";
final String cInterfaceRasterFeuille = "afficherCarteFeuille.do";
final String cImageLinkStart = "title=\"image\"><a href=\"#\" onClick=\"popup('afficherCarteFeuille.do?f=";
+ final String cTAImageLinkStart = "title=\"image\"><a href=\"#\" onClick=\"popup('afficherCarteTa.do?f=";
final String cImageNameStart = ">Feuille ";
+ final String cTAImageNameStart = "Tableau d'assemblage <strong>";
final static long cCookieExpiration = 30 * 60 * 1000; // 30 minutes expressed in milliseconds
@@ -379,6 +381,17 @@ public class CadastreInterface {
private void parseFeuillesList(String input) {
listOfFeuilles.clear();
+ // get "Tableau d'assemblage"
+ if (Main.pref.getBoolean("cadastrewms.useTA", false)) {
+ while (input.indexOf(cTAImageLinkStart) != -1) {
+ input = input.substring(input.indexOf(cTAImageLinkStart) + cTAImageLinkStart.length());
+ String refTA = input.substring(0, input.indexOf("'"));
+ String nameTA = input.substring(input.indexOf(cTAImageNameStart) + cTAImageNameStart.length());
+ nameTA = nameTA.substring(0, nameTA.indexOf("<"));
+ listOfFeuilles.add(new PlanImage(nameTA, refTA));
+ }
+ }
+ // get "Feuilles"
while (input.indexOf(cImageLinkStart) != -1) {
input = input.substring(input.indexOf(cImageLinkStart)+cImageLinkStart.length());
String refFeuille = input.substring(0, input.indexOf("'"));
diff --git a/cadastre-fr/src/cadastre_fr/CadastrePlugin.java b/cadastre-fr/src/cadastre_fr/CadastrePlugin.java
index 3443cf3..7f993e0 100644
--- a/cadastre-fr/src/cadastre_fr/CadastrePlugin.java
+++ b/cadastre-fr/src/cadastre_fr/CadastrePlugin.java
@@ -104,7 +104,7 @@ import org.openstreetmap.josm.data.projection.*;
* - improved download cancellation
* - from Erik Amzallag:
* - possibility to modify the auto-sourcing text just before upload
- * - from Cl�ment M�nier:
+ * - from Clément Ménier:
* - new option allowing an auto-selection of the first cadastre layer for grab
* - non-modal JDialog in MenuActionGrabPlanImage
* - new options in the image filter (bilinear, bicubic)
@@ -114,6 +114,9 @@ import org.openstreetmap.josm.data.projection.*;
* 2.0 xx-xxx-xxxx - update projection for "La Reunion" departement to RGR92, UTM40S.
* - add 'departement' as option in the municipality selection
* - fixed bug in cache directory size control (and disabled by default)
+ * - add map mode for addressing
+ * - from Nicolas Dumoulin:
+ * - add "tableau d'assemblage" in raster images for georeferencing (as option)
*/
public class CadastrePlugin extends Plugin {
static String VERSION = "2.0";
diff --git a/cadastre-fr/src/cadastre_fr/CadastrePreferenceSetting.java b/cadastre-fr/src/cadastre_fr/CadastrePreferenceSetting.java
index b4ab592..d641c79 100644
--- a/cadastre-fr/src/cadastre_fr/CadastrePreferenceSetting.java
+++ b/cadastre-fr/src/cadastre_fr/CadastrePreferenceSetting.java
@@ -40,6 +40,8 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
private JCheckBox disableImageCropping = new JCheckBox(tr("Disable image cropping during georeferencing."));
+ private JCheckBox enableTableauAssemblage = new JCheckBox(tr("Use \"Tableau d''assemblage\""));
+
private JCheckBox autoFirstLayer = new JCheckBox(tr("Select first WMS layer in list."));
private JCheckBox dontUseRelation = new JCheckBox(tr("Don't use relation for addresses (but \"addr:street\" on elements)."));
@@ -286,7 +288,11 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
// option to disable image cropping during raster image georeferencing
disableImageCropping.setSelected(Main.pref.getBoolean("cadastrewms.noImageCropping", false));
disableImageCropping.setToolTipText(tr("Disable image cropping during georeferencing."));
- cadastrewms.add(disableImageCropping, GBC.eop().insets(0, 0, 0, 0));
+ cadastrewms.add(disableImageCropping, GBC.std().insets(0, 0, 10, 0));
+ // option to add the "Tableau d'assemblage" in list of sheets to grab
+ enableTableauAssemblage.setSelected(Main.pref.getBoolean("cadastrewms.useTA", false));
+ enableTableauAssemblage.setToolTipText(tr("Add the \"Tableau(x) d'assemblage\" in the list of cadastre sheets to grab."));
+ cadastrewms.add(enableTableauAssemblage, GBC.eop().insets(0, 0, 0, 0));
// the crosspiece display
JLabel jLabelCrosspieces = new JLabel(tr("Display crosspieces:"));
cadastrewms.add(jLabelCrosspieces, GBC.std().insets(0, 0, 10, 0));
@@ -400,6 +406,7 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
} catch (NumberFormatException e) { // ignore the last input
}
Main.pref.put("cadastrewms.noImageCropping", disableImageCropping.isSelected());
+ Main.pref.put("cadastrewms.useTA", enableTableauAssemblage.isSelected());
if (crosspiece1.isSelected()) Main.pref.put("cadastrewms.crosspieces", "0");
else if (crosspiece2.isSelected()) Main.pref.put("cadastrewms.crosspieces", "1");
else if (crosspiece3.isSelected()) Main.pref.put("cadastrewms.crosspieces", "2");
diff --git a/cadastre-fr/src/cadastre_fr/WMSLayer.java b/cadastre-fr/src/cadastre_fr/WMSLayer.java
index dd2f804..bfc4650 100644
--- a/cadastre-fr/src/cadastre_fr/WMSLayer.java
+++ b/cadastre-fr/src/cadastre_fr/WMSLayer.java
@@ -4,7 +4,6 @@ package cadastre_fr;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Color;
-import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
@@ -21,9 +20,9 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.Vector;
+import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
-import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import org.openstreetmap.josm.Main;
@@ -43,8 +42,6 @@ import org.openstreetmap.josm.io.OsmTransferException;
*/
public class WMSLayer extends Layer implements ImageObserver {
- Component[] component = null;
-
private int lambertZone = -1;
protected static final Icon icon = new ImageIcon(Toolkit.getDefaultToolkit().createImage(
@@ -58,9 +55,9 @@ public class WMSLayer extends Layer implements ImageObserver {
* v3 to v4 = add original raster image width and height
*/
protected final int serializeFormatVersion = 4;
-
+
public static int currentFormat;
-
+
private static final int cBBoxForBuildings = 50; // hard coded size of grabbed boxes for building layers
private ArrayList<EastNorthBound> dividedBbox = new ArrayList<EastNorthBound>();
@@ -68,7 +65,7 @@ public class WMSLayer extends Layer implements ImageObserver {
private CacheControl cacheControl = null;
private String location = "";
-
+
private String departement = "";
private String codeCommune = "";
@@ -87,8 +84,8 @@ public class WMSLayer extends Layer implements ImageObserver {
private EastNorth rasterMax;
private double rasterRatio;
- private JMenuItem saveAsPng;
-
+ private Action saveAsPng;
+
public boolean adjustModeEnabled;
@@ -105,7 +102,8 @@ public class WMSLayer extends Layer implements ImageObserver {
CadastrePlugin.pluginUsed = true;
}
- public void destroy() {
+ @Override
+ public void destroy() {
// if the layer is currently saving the images in the cache, wait until it's finished
if (cacheControl != null) {
while (!cacheControl.isCachePipeEmpty()) {
@@ -118,9 +116,9 @@ public class WMSLayer extends Layer implements ImageObserver {
dividedBbox = null;
System.out.println("Layer "+location+" destroyed");
}
-
+
private static String buildName(String location, String codeCommune, boolean buildingOnly) {
- String ret = new String(location.toUpperCase());
+ String ret = location.toUpperCase();
if (codeCommune != null && !codeCommune.equals(""))
ret += "(" + codeCommune + ")";
if (buildingOnly)
@@ -135,7 +133,7 @@ public class WMSLayer extends Layer implements ImageObserver {
public void grab(CadastreGrabber grabber, Bounds b) throws IOException {
grab(grabber, b, true);
}
-
+
public void grab(CadastreGrabber grabber, Bounds b, boolean useFactor) throws IOException {
cancelled = false;
if (useFactor) {
@@ -224,7 +222,7 @@ public class WMSLayer extends Layer implements ImageObserver {
}
} else {
// divide to fixed size squares
- int cSquare = factor == 4 ? Integer.parseInt(Main.pref.get("cadastrewms.squareSize", "100")) : optionalSize;
+ int cSquare = factor == 4 ? Integer.parseInt(Main.pref.get("cadastrewms.squareSize", "100")) : optionalSize;
minEast = minEast - minEast % cSquare;
minNorth = minNorth - minNorth % cSquare;
for (int xEast = (int)minEast; xEast < lambertMax.east(); xEast+=cSquare)
@@ -285,7 +283,7 @@ public class WMSLayer extends Layer implements ImageObserver {
}
if (this.adjustModeEnabled) {
WMSAdjustAction.paintAdjustFrames(g, mv);
- }
+ }
}
@Override
@@ -302,17 +300,17 @@ public class WMSLayer extends Layer implements ImageObserver {
}
@Override
- public Component[] getMenuEntries() {
- saveAsPng = new JMenuItem(new MenuActionSaveRasterAs(this));
+ public Action[] getMenuEntries() {
+ saveAsPng = new MenuActionSaveRasterAs(this);
saveAsPng.setEnabled(isRaster);
- component = new Component[] { new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
- new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)),
- new JMenuItem(new MenuActionLoadFromCache()),
+ return new Action[] {
+ LayerListDialog.getInstance().createShowHideLayerAction(),
+ LayerListDialog.getInstance().createDeleteLayerAction(),
+ new MenuActionLoadFromCache(),
saveAsPng,
- new JMenuItem(new LayerListPopup.InfoAction(this)),
+ new LayerListPopup.InfoAction(this),
};
- return component;
}
public GeorefImage findImage(EastNorth eastNorth) {
@@ -442,8 +440,8 @@ public class WMSLayer extends Layer implements ImageObserver {
double rasterSizeY = communeBBox.max.getY() - communeBBox.min.getY();
double ratio = rasterSizeY/rasterSizeX;
// keep same ratio on screen as WMS bbox (stored in communeBBox)
- rasterMin = new EastNorth(eaMin.getX(), rasterCenter.getY()-(eaMax.getX()-eaMin.getX())*ratio/2);
- rasterMax = new EastNorth(eaMax.getX(), rasterCenter.getY()+(eaMax.getX()-eaMin.getX())*ratio/2);
+ rasterMin = new EastNorth(eaMin.getX(), rasterCenter.getY()-(eaMax.getX()-eaMin.getX())*ratio/2);
+ rasterMax = new EastNorth(eaMax.getX(), rasterCenter.getY()+(eaMax.getX()-eaMin.getX())*ratio/2);
rasterRatio = (rasterMax.getX()-rasterMin.getX())/rasterSizeX;
}
@@ -597,7 +595,7 @@ public class WMSLayer extends Layer implements ImageObserver {
setCommuneBBox(new EastNorthBound(new EastNorth(0,0), new EastNorth(images.get(0).image.getWidth()-1,images.get(0).image.getHeight()-1)));
rasterRatio = (rasterMax.getX()-rasterMin.getX())/(communeBBox.max.getX() - communeBBox.min.getX());
}
-
+
public EastNorthBound getCommuneBBox() {
return communeBBox;
}
@@ -639,7 +637,7 @@ public class WMSLayer extends Layer implements ImageObserver {
this.rasterMax = rasterMax.rotate(rasterCenter, angle);
// double proportion = dst1.distance(dst2)/org1.distance(org2);
images.get(0).rotate(rasterCenter, angle);
- this.angle += angle;
+ this.angle += angle;
}
private void paintCrosspieces(Graphics g, MapView mv) {
diff --git a/editgpx/build.xml b/editgpx/build.xml
index 598213d..326bed0 100644
--- a/editgpx/build.xml
+++ b/editgpx/build.xml
@@ -17,7 +17,7 @@
** > ant install
**
** To build against the core in ../../core, create a correct manifest and deploy to
-** SVN,
+** SVN,
** set the properties commit.message and plugin.main.version
** and run
** > ant publish
@@ -28,7 +28,7 @@
<property name="commit.message" value="Changed constructor signature of plugin main class" />
- <property name="plugin.main.version" value="2907" />
+ <property name="plugin.main.version" value="3408" />
<property name="josm" location="../../core/dist/josm-custom.jar"/>
@@ -88,10 +88,10 @@
</target>
<!--
- ************************** Publishing the plugin ***********************************
+ ************************** Publishing the plugin ***********************************
-->
<!--
- ** extracts the JOSM release for the JOSM version in ../core and saves it in the
+ ** extracts the JOSM release for the JOSM version in ../core and saves it in the
** property ${coreversion.info.entry.revision}
**
-->
@@ -140,17 +140,17 @@
</target>
<!--
- ** commits the plugin.jar
+ ** commits the plugin.jar
-->
<target name="commit-dist">
<echo>
***** Properties of published ${plugin.jar} *****
-Commit message : '${commit.message}'
+Commit message : '${commit.message}'
Plugin-Mainversion: ${plugin.main.version}
JOSM build version: ${coreversion.info.entry.revision}
Plugin-Version : ${version.entry.commit.revision}
-***** / Properties of published ${plugin.jar} *****
-
+***** / Properties of published ${plugin.jar} *****
+
Now commiting ${plugin.jar} ...
</echo>
<exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
diff --git a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxLayer.java b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxLayer.java
index 6f49c7c..12d1fd3 100644
--- a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxLayer.java
+++ b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxLayer.java
@@ -6,17 +6,15 @@ package org.openstreetmap.josm.plugins.editgpx;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Color;
-import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
+import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
-import javax.swing.JMenuItem;
-import javax.swing.JSeparator;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.Bounds;
@@ -72,16 +70,16 @@ public class EditGpxLayer extends Layer {
}
@Override
- public Component[] getMenuEntries() {
- return new Component[] {
- new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
- new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)),
- new JSeparator(),
- new JMenuItem(layerImport),
- new JMenuItem(new ConvertToGpxLayerAction()),
- new JMenuItem(new ConvertToAnonTimeGpxLayerAction()),
- new JSeparator(),
- new JMenuItem(new LayerListPopup.InfoAction(this))};
+ public Action[] getMenuEntries() {
+ return new Action[] {
+ LayerListDialog.getInstance().createShowHideLayerAction(),
+ LayerListDialog.getInstance().createDeleteLayerAction(),
+ SeparatorLayerAction.INSTANCE,
+ layerImport,
+ new ConvertToGpxLayerAction(),
+ new ConvertToAnonTimeGpxLayerAction(),
+ SeparatorLayerAction.INSTANCE,
+ new LayerListPopup.InfoAction(this)};
}
@Override
diff --git a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxPlugin.java b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxPlugin.java
index 6699953..b33f5f5 100644
--- a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxPlugin.java
+++ b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxPlugin.java
@@ -24,7 +24,6 @@ import org.openstreetmap.josm.plugins.PluginInformation;
*
* TODO:
* - BUG: when importing eGpxLayer is shown as RawGpxLayer??
- * - BUG: after deletion of layer not all data is deleted (eg dataset)
* - implement reset if user made mistake while marking
*
*
diff --git a/measurement/build.xml b/measurement/build.xml
index 087f340..47ef8c2 100644
--- a/measurement/build.xml
+++ b/measurement/build.xml
@@ -17,7 +17,7 @@
** > ant install
**
** To build against the core in ../../core, create a correct manifest and deploy to
-** SVN,
+** SVN,
** set the properties commit.message and plugin.main.version
** and run
** > ant publish
@@ -27,7 +27,7 @@
<project name="measurement" default="dist" basedir=".">
<property name="commit.message" value="Changed the constructor signature of the plugin main class" />
- <property name="plugin.main.version" value="2907" />
+ <property name="plugin.main.version" value="3408" />
<property name="josm" location="../../core/dist/josm-custom.jar"/>
@@ -86,10 +86,10 @@
</target>
<!--
- ************************** Publishing the plugin ***********************************
+ ************************** Publishing the plugin ***********************************
-->
<!--
- ** extracts the JOSM release for the JOSM version in ../core and saves it in the
+ ** extracts the JOSM release for the JOSM version in ../core and saves it in the
** property ${coreversion.info.entry.revision}
**
-->
@@ -138,17 +138,17 @@
</target>
<!--
- ** commits the plugin.jar
+ ** commits the plugin.jar
-->
<target name="commit-dist">
<echo>
***** Properties of published ${plugin.jar} *****
- Commit message : '${commit.message}'
+ Commit message : '${commit.message}'
Plugin-Mainversion: ${plugin.main.version}
JOSM build version: ${coreversion.info.entry.revision}
Plugin-Version : ${version.entry.commit.revision}
- ***** / Properties of published ${plugin.jar} *****
-
+ ***** / Properties of published ${plugin.jar} *****
+
Now commiting ${plugin.jar} ...
</echo>
<exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
diff --git a/measurement/src/org/openstreetmap/josm/plugins/measurement/MeasurementLayer.java b/measurement/src/org/openstreetmap/josm/plugins/measurement/MeasurementLayer.java
index a34fd33..087a52a 100644
--- a/measurement/src/org/openstreetmap/josm/plugins/measurement/MeasurementLayer.java
+++ b/measurement/src/org/openstreetmap/josm/plugins/measurement/MeasurementLayer.java
@@ -14,6 +14,7 @@ import java.util.ArrayList;
import java.util.Collection;
import javax.swing.AbstractAction;
+import javax.swing.Action;
import javax.swing.Box;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
@@ -23,9 +24,7 @@ import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
-import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
-import javax.swing.JSeparator;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.Bounds;
@@ -93,14 +92,14 @@ public class MeasurementLayer extends Layer {
return getToolTipText();
}
- @Override public Component[] getMenuEntries() {
- return new Component[]{
- new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
+ @Override public Action[] getMenuEntries() {
+ return new Action[]{
+ LayerListDialog.getInstance().createShowHideLayerAction(),
// TODO: implement new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
- new JSeparator(),
- new JMenuItem(new GPXLayerImportAction(this)),
- new JSeparator(),
- new JMenuItem(new LayerListPopup.InfoAction(this))};
+ SeparatorLayerAction.INSTANCE,
+ new GPXLayerImportAction(this),
+ SeparatorLayerAction.INSTANCE,
+ new LayerListPopup.InfoAction(this)};
}
public void removeLastPoint(){
@@ -221,7 +220,7 @@ public class MeasurementLayer extends Layer {
Math.sin(lat1) * coslat2 * Math.cos(dlon)))) / Math.PI;
}
- public static double OldangleBetween(LatLon p1, LatLon p2){
+ public static double oldAngleBetween(LatLon p1, LatLon p2){
double lat1, lon1, lat2, lon2;
double dlon, dlat;
double heading;
diff --git a/wmsplugin/.classpath b/remotecontrol/.classpath
similarity index 83%
copy from wmsplugin/.classpath
copy to remotecontrol/.classpath
index 663bc1b..11208d5 100644
--- a/wmsplugin/.classpath
+++ b/remotecontrol/.classpath
@@ -1,7 +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>
+<?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="bin"/>
+</classpath>
diff --git a/remotecontrol/.project b/remotecontrol/.project
new file mode 100644
index 0000000..9b0c9ee
--- /dev/null
+++ b/remotecontrol/.project
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>remotecontrol</name>
+ <comment></comment>
+ <projects>
+ <project>JOSM</project>
+ </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/remotecontrol/CONTRIBUTION b/remotecontrol/CONTRIBUTION
new file mode 100644
index 0000000..06f8465
--- /dev/null
+++ b/remotecontrol/CONTRIBUTION
@@ -0,0 +1,6 @@
+Originally developed by Frederik Ramm <frederik at remote.org>. Add yourself
+if you contribute.
+
+Stephan Knauss <osm at stephans-server.de>:
+ added /version command to return protocol version
+ added CORS headers for modern browsers, legacy browsers can use jsonp
diff --git a/remotecontrol/README b/remotecontrol/README
new file mode 100644
index 0000000..26828d4
--- /dev/null
+++ b/remotecontrol/README
@@ -0,0 +1,9 @@
+A plugin for JOSM that listens for commands on a TCP port (8111).
+It can be used to tell JOSM to zoom to an area and download data.
+Details are found on the Wiki page,
+
+http://wiki.openstreetmap.org/index.php/JOSM/Plugins/RemoteControl
+
+Initially written by Frederik Ramm <frederik at remote.org>. License:
+GPL V2 or later. Incorporates code taken from YWMS plugin by frsantos.
+
diff --git a/cadastre-fr/build.xml b/remotecontrol/build.xml
similarity index 84%
copy from cadastre-fr/build.xml
copy to remotecontrol/build.xml
index fd5d8da..f9fe76a 100644
--- a/cadastre-fr/build.xml
+++ b/remotecontrol/build.xml
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
<!--
-** This is a template build file for the cadastre-fr plugin.
+** This is the build file for the remotecontrol plugin
**
** Maintaining versions
** ====================
@@ -23,25 +24,24 @@
**
**
-->
-<project name="cadastre-fr" default="dist" basedir=".">
+<project name="remotecontrol" default="dist" basedir=".">
+
+ <!-- set before publising -->
+ <property name="commit.message" value="permissen checkbox for new object creation" />
+ <property name="plugin.main.version" value="2830" />
+
<property name="josm" location="../../core/dist/josm-custom.jar"/>
<property name="plugin.dist.dir" value="../../dist"/>
<property name="plugin.build.dir" value="build"/>
<property name="plugin.jar" value="${plugin.dist.dir}/${ant.project.name}.jar"/>
- <property name="ant.build.javac.target" value="1.5"/>
-
-
-
- <property name="commit.message" value="Changed constructor for Plugin" />
- <property name="plugin.main.version" value="3174" />
-
<target name="init">
<mkdir dir="${plugin.build.dir}"/>
</target>
<target name="compile" depends="init">
<echo message="creating ${plugin.jar}"/>
- <javac srcdir="src" classpath="${josm}" debug="true" destdir="${plugin.build.dir}">
- <compilerarg value="-Xlint:deprecation"/>
+ <javac srcdir="src" classpath="${josm}" debug="true" destdir="${plugin.build.dir}"
+ target="1.5" source="1.5" encoding="UTF-8">
+ <compilerarg value="-Xlint:deprecation"/>
<compilerarg value="-Xlint:unchecked"/>
</javac>
</target>
@@ -51,15 +51,17 @@
</copy>
<jar destfile="${plugin.jar}" basedir="${plugin.build.dir}">
<manifest>
- <attribute name="Author" value="Pieren"/>
- <attribute name="Plugin-Class" value="cadastre_fr.CadastrePlugin"/>
+ <attribute name="Author" value="Frederik Ramm, Bodo Meissner"/>
+ <attribute name="Plugin-Class" value="org.openstreetmap.josm.plugins.remotecontrol.RemoteControlPlugin"/>
<attribute name="Plugin-Date" value="${version.entry.commit.date}"/>
- <attribute name="Plugin-Description" value="A special handler for the French land registry WMS server."/>
- <attribute name="Plugin-Icon" value="images/preferences/cadastrewms.gif"/>
- <attribute name="Plugin-Link" value="http://wiki.openstreetmap.org/wiki/FR:JOSM/Fr:Plugin/Cadastre"/>
+ <attribute name="Plugin-Description" value="Let other applications send commands to JOSM."/>
+ <attribute name="Plugin-Icon" value="images/preferences/remotecontrol.gif"/>
+ <attribute name="Plugin-Link" value="http://wiki.openstreetmap.org/index.php/JOSM/Plugins/RemoteControl"/>
<attribute name="Plugin-Mainversion" value="${plugin.main.version}"/>
- <attribute name="Plugin-Stage" value="60"/>
<attribute name="Plugin-Version" value="${version.entry.commit.revision}"/>
+ <!-- This plugin must be loaded before any plugin that may want to register
+ handlers for additional remote commands.-->
+ <attribute name="Plugin-Stage" value="20"/>
</manifest>
</jar>
</target>
diff --git a/remotecontrol/images/preferences/remotecontrol.gif b/remotecontrol/images/preferences/remotecontrol.gif
new file mode 100644
index 0000000..f82493b
Binary files /dev/null and b/remotecontrol/images/preferences/remotecontrol.gif differ
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/HttpServer.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/HttpServer.java
new file mode 100644
index 0000000..d2ea82c
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/HttpServer.java
@@ -0,0 +1,75 @@
+package org.openstreetmap.josm.plugins.remotecontrol;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.InetAddress;
+
+/**
+ * Simple HTTP server that spawns a {@link RequestProcessor} for every
+ * connection.
+ *
+ * Taken from YWMS plugin by frsantos.
+ */
+
+public class HttpServer extends Thread {
+
+ /** Default port for the HTTP server */
+ public static final int DEFAULT_PORT = 8111;
+
+ /** The server socket */
+ private ServerSocket server;
+
+ /**
+ * Constructor
+ * @param port The port this server will listen on
+ * @throws IOException when connection errors
+ */
+ public HttpServer(int port)
+ throws IOException
+ {
+ super("RemoteControl HTTP Server");
+ this.setDaemon(true);
+ // Start the server socket with only 1 connection.
+ // Also make sure we only listen
+ // on the local interface so nobody from the outside can connect!
+ this.server = new ServerSocket(port, 1,
+ InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 }));
+ }
+
+ /**
+ * The main loop, spawns a {@link RequestProcessor} for each connection
+ */
+ public void run()
+ {
+ System.out.println("RemoteControl::Accepting connections on port " + server.getLocalPort());
+ while (true)
+ {
+ try
+ {
+ Socket request = server.accept();
+ RequestProcessor.processRequest(request);
+ }
+ catch( SocketException se)
+ {
+ if( !server.isClosed() )
+ se.printStackTrace();
+ }
+ catch (IOException ioe)
+ {
+ ioe.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Stops the HTTP server
+ *
+ * @throws IOException
+ */
+ public void stopServer() throws IOException
+ {
+ server.close();
+ }
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPref.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPref.java
new file mode 100644
index 0000000..b1d8eb0
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPref.java
@@ -0,0 +1,24 @@
+package org.openstreetmap.josm.plugins.remotecontrol;
+
+/**
+ * Contains a preference name to control permission for the operation
+ * implemented by the RequestHandler, and an error message to be displayed
+ * if not permitted.
+ *
+ * Use @see PermissionPrefWithDefault instead of this class.
+ *
+ * @author Bodo Meissner
+ */
+ @Deprecated
+public class PermissionPref {
+ /** name of the preference setting to permit the remote operation */
+ String pref;
+ /** message to be displayed if operation is not permitted */
+ String message;
+
+ public PermissionPref(String pref, String message)
+ {
+ this.pref = pref;
+ this.message = message;
+ }
+}
\ No newline at end of file
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPrefWithDefault.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPrefWithDefault.java
new file mode 100644
index 0000000..83a2f3d
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPrefWithDefault.java
@@ -0,0 +1,22 @@
+package org.openstreetmap.josm.plugins.remotecontrol;
+
+/**
+ * This class should replace PermissionPref because it allows explicit
+ * specification of the permission's default value.
+ *
+ * @author Bodo Meissner
+ */
+ at SuppressWarnings("deprecation")
+public class PermissionPrefWithDefault extends PermissionPref {
+
+ boolean defaultVal = true;
+
+ public PermissionPrefWithDefault(String pref, boolean defaultVal, String message) {
+ super(pref, message);
+ this.defaultVal = defaultVal;
+ }
+
+ public PermissionPrefWithDefault(PermissionPref prefWithoutDefault) {
+ super(prefWithoutDefault.pref, prefWithoutDefault.message);
+ }
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RemoteControlPlugin.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RemoteControlPlugin.java
new file mode 100644
index 0000000..fe90e82
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RemoteControlPlugin.java
@@ -0,0 +1,106 @@
+package org.openstreetmap.josm.plugins.remotecontrol;
+
+import java.io.IOException;
+
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginInformation;
+
+/**
+ * Base plugin for remote control operations.
+ * This plugin contains operations that use JOSM core only.
+ *
+ * Other plugins can register additional operations by calling
+ * @see addRequestHandler().
+ * To allow API changes this plugin contains a @see getVersion() method.
+ *
+ * IMPORTANT! increment the minor version on compatible API extensions
+ * and increment the major version and set minor to 0 on incompatible changes.
+ */
+public class RemoteControlPlugin extends Plugin
+{
+ /** API version
+ * IMPORTANT! update the version number on API changes.
+ */
+ static final int apiMajorVersion = 1;
+ static final int apiMinorVersion = 0;
+
+ /**
+ * RemoteControl HTTP protocol version. Change minor number for compatible
+ * interface extensions. Change major number in case of incompatible
+ * changes.
+ */
+ static final int protocolMajorVersion = 1;
+ static final int protocolMinorVersion = 2;
+
+ /** The HTTP server this plugin launches */
+ static HttpServer server;
+
+ /**
+ * Returns an array of int values with major and minor API version
+ * and major and minor HTTP protocol version.
+ *
+ * The function returns an int[4] instead of an object with fields
+ * to avoid ClassNotFound errors with old versions of remotecontrol.
+ *
+ * @return array of integer version numbers:
+ * apiMajorVersion, apiMinorVersion, protocolMajorVersion, protocolMajorVersion
+ */
+ public int[] getVersion()
+ {
+ int versions[] = {apiMajorVersion, apiMinorVersion, protocolMajorVersion, protocolMajorVersion};
+ return versions;
+ }
+
+ /**
+ * Creates the plugin, and starts the HTTP server
+ */
+ public RemoteControlPlugin(PluginInformation info)
+ {
+ super(info);
+ /*
+ System.out.println("constructor " + this.getClass().getName() + " (" + info.name +
+ " v " + info.version + " stage " + info.stage + ")");
+ */
+ restartServer();
+ }
+
+ @Override
+ public PreferenceSetting getPreferenceSetting()
+ {
+ return new RemoteControlPreferences();
+ }
+
+ /**
+ * Starts or restarts the HTTP server
+ *
+ */
+ public void restartServer()
+ {
+ try
+ {
+ if (server != null)
+ server.stopServer();
+
+ int port = HttpServer.DEFAULT_PORT;
+ server = new HttpServer(port);
+ server.start();
+ }
+ catch(IOException ioe)
+ {
+ ioe.printStackTrace();
+ }
+ }
+
+ /**
+ * Add external external request handler.
+ * Can be used by other plug-ins that want to use remote control.
+ *
+ * @param handler The additional request handler.
+ */
+ public void addRequestHandler(String command, Class<? extends RequestHandler> handlerClass)
+ {
+ RequestProcessor.addRequestHandlerClass(command, handlerClass);
+ }
+
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RemoteControlPreferences.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RemoteControlPreferences.java
new file mode 100644
index 0000000..40d7424
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RemoteControlPreferences.java
@@ -0,0 +1,80 @@
+package org.openstreetmap.josm.plugins.remotecontrol;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+import java.awt.GridBagLayout;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.plugins.remotecontrol.handler.AddNodeHandler;
+import org.openstreetmap.josm.plugins.remotecontrol.handler.ImportHandler;
+import org.openstreetmap.josm.plugins.remotecontrol.handler.LoadAndZoomHandler;
+import org.openstreetmap.josm.plugins.remotecontrol.handler.VersionHandler;
+import org.openstreetmap.josm.tools.GBC;
+
+/**
+ * Preference settings for the Remote Control plugin
+ *
+ * @author Frederik Ramm
+ */
+public class RemoteControlPreferences implements PreferenceSetting
+{
+ private JCheckBox permissionLoadData = new JCheckBox(tr("load data from API"));
+ private JCheckBox permissionImportData = new JCheckBox(tr("import data from URL"));
+ private JCheckBox permissionCreateObjects = new JCheckBox(tr("create new objects"));
+ private JCheckBox permissionChangeSelection = new JCheckBox(tr("change the selection"));
+ private JCheckBox permissionChangeViewport = new JCheckBox(tr("change the viewport"));
+ private JCheckBox permissionReadProtocolversion = new JCheckBox(tr("read protocol version"));
+ private JCheckBox alwaysAskUserConfirm = new JCheckBox(tr("confirm all Remote Control actions manually"));
+
+ public void addGui(final PreferenceTabbedPane gui)
+ {
+ String description = tr("A plugin that allows JOSM to be controlled from other applications.");
+ JPanel remote = gui.createPreferenceTab("remotecontrol.gif", tr("Remote Control"), tr("Settings for the Remote Control plugin."));
+ remote.add(new JLabel("<html>"+tr("The Remote Control plugin will always listen on port 8111 on localhost." +
+ "The port is not variable because it is referenced by external applications talking to the plugin.") + "</html>"), GBC.eol().insets(0,5,0,10).fill(GBC.HORIZONTAL));
+
+ JPanel perms = new JPanel();
+ perms.setLayout(new GridBagLayout());
+ perms.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray), tr("Permitted actions")));
+ perms.add(permissionLoadData, GBC.eol().insets(0,5,0,0).fill(GBC.HORIZONTAL));
+ perms.add(permissionImportData, GBC.eol().insets(0,5,0,0).fill(GBC.HORIZONTAL));
+ perms.add(permissionChangeSelection, GBC.eol().insets(0,5,0,0).fill(GBC.HORIZONTAL));
+ perms.add(permissionChangeViewport, GBC.eol().insets(0,5,0,0).fill(GBC.HORIZONTAL));
+ perms.add(permissionCreateObjects, GBC.eol().insets(0,5,0,0).fill(GBC.HORIZONTAL));
+ perms.add(permissionReadProtocolversion, GBC.eol().insets(0,5,0,0).fill(GBC.HORIZONTAL));
+ remote.add(perms, GBC.eol().fill(GBC.HORIZONTAL));
+
+ remote.add(alwaysAskUserConfirm, GBC.eol().insets(0,5,0,0).fill(GBC.HORIZONTAL));
+ remote.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
+
+ permissionLoadData.setSelected(Main.pref.getBoolean(LoadAndZoomHandler.loadDataPermissionKey, LoadAndZoomHandler.loadDataPermissionDefault));
+ permissionImportData.setSelected(Main.pref.getBoolean(ImportHandler.permissionKey, ImportHandler.permissionDefault));
+ permissionChangeSelection.setSelected(Main.pref.getBoolean(LoadAndZoomHandler.changeSelectionPermissionKey, LoadAndZoomHandler.changeSelectionPermissionDefault));
+ permissionChangeViewport.setSelected(Main.pref.getBoolean(LoadAndZoomHandler.changeViewportPermissionKey, LoadAndZoomHandler.changeViewportPermissionDefault));
+ permissionCreateObjects.setSelected(Main.pref.getBoolean(AddNodeHandler.permissionKey, AddNodeHandler.permissionDefault));
+ permissionReadProtocolversion.setSelected(Main.pref.getBoolean(VersionHandler.permissionKey, VersionHandler.permissionDefault));
+ alwaysAskUserConfirm.setSelected(Main.pref.getBoolean(RequestHandler.globalConfirmationKey, RequestHandler.globalConfirmationDefault));
+
+ }
+
+ public boolean ok() {
+ Main.pref.put(LoadAndZoomHandler.loadDataPermissionKey, permissionLoadData.isSelected());
+ Main.pref.put(ImportHandler.permissionKey, permissionImportData.isSelected());
+ Main.pref.put(LoadAndZoomHandler.changeSelectionPermissionKey, permissionChangeSelection.isSelected());
+ Main.pref.put(LoadAndZoomHandler.changeViewportPermissionKey, permissionChangeViewport.isSelected());
+ Main.pref.put(AddNodeHandler.permissionKey, permissionCreateObjects.isSelected());
+ Main.pref.put(VersionHandler.permissionKey, permissionReadProtocolversion.isSelected());
+ Main.pref.put(RequestHandler.globalConfirmationKey, alwaysAskUserConfirm.isSelected());
+ // FIXME confirm return value - really no restart needed?
+ return false /* no restart needed */;
+ }
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandler.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandler.java
new file mode 100644
index 0000000..2a2175d
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandler.java
@@ -0,0 +1,207 @@
+package org.openstreetmap.josm.plugins.remotecontrol;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+
+/**
+ * This is the parent of all classes that handle a specific command
+ * in remote control plug-in.
+ *
+ * @author Bodo Meissner
+ */
+public abstract class RequestHandler
+{
+ public static final String globalConfirmationKey = "remotecontrol.always-confirm";
+ public static final boolean globalConfirmationDefault = false;
+
+ /** The GET request arguments */
+ protected HashMap<String,String> args;
+
+ /** The request URL without "GET". */
+ protected String request;
+
+ /** default response */
+ protected String content = "OK\r\n";
+ /** default content type */
+ protected String contentType = "text/plain";
+
+ /** will be filled with the command assigned to the subclass */
+ protected String myCommand;
+
+ /**
+ * Check permission and parameters and handle request.
+ *
+ * @throws RequestHandlerForbiddenException
+ * @throws RequestHandlerBadRequestException
+ * @throws RequestHandlerErrorException
+ */
+ final void handle() throws RequestHandlerForbiddenException, RequestHandlerBadRequestException, RequestHandlerErrorException
+ {
+ checkPermission();
+ checkMandatoryParams();
+ handleRequest();
+ }
+
+ /**
+ * Handle a specific command sent as remote control.
+ *
+ * This method of the subclass will do the real work.
+ *
+ * @throws RequestHandlerErrorException
+ * @throws RequestHandlerBadRequestException
+ */
+ protected abstract void handleRequest() throws RequestHandlerErrorException, RequestHandlerBadRequestException;
+
+ /**
+ * Get a specific message to ask the user for permission for the operation
+ * requested via remote control.
+ *
+ * This message will be displayed to the user if the preference
+ * remotecontrol.always-confirm is true.
+ *
+ * @return the message
+ */
+ abstract public String getPermissionMessage();
+
+ /**
+ * Get a PermissionPref object containing the name of a special permission
+ * preference to individually allow the requested operation and an error
+ * message to be displayed when a disabled operation is requested.
+ *
+ * Default is not to check any special preference. Override this in a
+ * subclass to define permission preference and error message.
+ *
+ * @return the preference name and error message or null
+ */
+ @SuppressWarnings("deprecation")
+ public PermissionPref getPermissionPref()
+ {
+ /* Example:
+ return new PermissionPrefWithDefault("fooobar.remotecontrol",
+ true
+ "RemoteControl: foobar forbidden by preferences");
+ */
+ return null;
+ }
+
+ protected String[] getMandatoryParams()
+ {
+ return null;
+ }
+
+ /**
+ * Check permissions in preferences and display error message
+ * or ask for permission.
+ *
+ * @throws RequestHandlerForbiddenException
+ */
+ @SuppressWarnings("deprecation")
+ final public void checkPermission() throws RequestHandlerForbiddenException
+ {
+ /*
+ * If the subclass defines a specific preference and if this is set
+ * to false, abort with an error message.
+ *
+ * Note: we use the deprecated class here for compatibility with
+ * older versions of WMSPlugin.
+ */
+ PermissionPref permissionPref = getPermissionPref();
+ if((permissionPref != null) && (permissionPref.pref != null))
+ {
+ PermissionPrefWithDefault permissionPrefWithDefault;
+ if(permissionPref instanceof PermissionPrefWithDefault)
+ {
+ permissionPrefWithDefault = (PermissionPrefWithDefault) permissionPref;
+ }
+ else
+ {
+ permissionPrefWithDefault = new PermissionPrefWithDefault(permissionPref);
+ }
+ if (!Main.pref.getBoolean(permissionPrefWithDefault.pref,
+ permissionPrefWithDefault.defaultVal)) {
+ System.out.println(permissionPrefWithDefault.message);
+ throw new RequestHandlerForbiddenException();
+ }
+ }
+
+ /* Does the user want to confirm everything?
+ * If yes, display specific confirmation message.
+ */
+ if (Main.pref.getBoolean(globalConfirmationKey, globalConfirmationDefault)) {
+ if (JOptionPane.showConfirmDialog(Main.parent,
+ "<html>" + getPermissionMessage() +
+ "<br>" + tr("Do you want to allow this?"),
+ tr("Confirm Remote Control action"),
+ JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
+ throw new RequestHandlerForbiddenException();
+ }
+ }
+ }
+
+ /**
+ * Set request URL and parse args.
+ *
+ * @param url The request URL.
+ */
+ public void setUrl(String url) {
+ this.request = url;
+ parseArgs();
+ }
+
+ /**
+ * Parse the request parameters as key=value pairs.
+ * The result will be stored in this.args.
+ *
+ * Can be overridden by subclass.
+ */
+ protected void parseArgs() {
+ StringTokenizer st = new StringTokenizer(this.request, "&?");
+ HashMap<String, String> args = new HashMap<String, String>();
+ // ignore first token which is the command
+ if(st.hasMoreTokens()) st.nextToken();
+ while (st.hasMoreTokens()) {
+ String param = st.nextToken();
+ int eq = param.indexOf("=");
+ if (eq > -1)
+ args.put(param.substring(0, eq),
+ param.substring(eq + 1));
+ }
+ this.args = args;
+ }
+
+ void checkMandatoryParams() throws RequestHandlerBadRequestException
+ {
+ String[] mandatory = getMandatoryParams();
+ if(mandatory == null) return;
+
+ boolean error = false;
+ for(int i = 0; i < mandatory.length; ++i)
+ {
+ String key = mandatory[i];
+ String value = args.get(key);
+ if((value == null) || (value.length() == 0))
+ {
+ error = true;
+ System.out.println("'" + myCommand + "' remote control request must have '" + key + "' parameter");
+ }
+ }
+ if(error) throw new RequestHandlerBadRequestException();
+ }
+
+ /**
+ * Save command associated with this handler.
+ *
+ * @param command The command.
+ */
+ public void setCommand(String command)
+ {
+ if(command.charAt(0) == '/') command = command.substring(1);
+ myCommand = command;
+ }
+}
\ No newline at end of file
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerBadRequestException.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerBadRequestException.java
new file mode 100644
index 0000000..55d30e3
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerBadRequestException.java
@@ -0,0 +1,4 @@
+package org.openstreetmap.josm.plugins.remotecontrol;
+
+public class RequestHandlerBadRequestException extends RequestHandlerException {
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerErrorException.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerErrorException.java
new file mode 100644
index 0000000..5f6753d
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerErrorException.java
@@ -0,0 +1,4 @@
+package org.openstreetmap.josm.plugins.remotecontrol;
+
+public class RequestHandlerErrorException extends RequestHandlerException {
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerException.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerException.java
new file mode 100644
index 0000000..9ff10a3
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerException.java
@@ -0,0 +1,4 @@
+package org.openstreetmap.josm.plugins.remotecontrol;
+
+public class RequestHandlerException extends Exception {
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerForbiddenException.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerForbiddenException.java
new file mode 100644
index 0000000..38d9fe4
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerForbiddenException.java
@@ -0,0 +1,5 @@
+package org.openstreetmap.josm.plugins.remotecontrol;
+
+public class RequestHandlerForbiddenException extends RequestHandlerException {
+ private static final long serialVersionUID = 2263904699747115423L;
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestProcessor.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestProcessor.java
new file mode 100644
index 0000000..5fcc818
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestProcessor.java
@@ -0,0 +1,308 @@
+package org.openstreetmap.josm.plugins.remotecontrol;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.Socket;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+import org.openstreetmap.josm.plugins.remotecontrol.handler.AddNodeHandler;
+import org.openstreetmap.josm.plugins.remotecontrol.handler.ImportHandler;
+import org.openstreetmap.josm.plugins.remotecontrol.handler.LoadAndZoomHandler;
+import org.openstreetmap.josm.plugins.remotecontrol.handler.VersionHandler;
+
+/**
+ * Processes HTTP "remote control" requests.
+ */
+public class RequestProcessor extends Thread {
+ /**
+ * RemoteControl protocol version. Change minor number for compatible
+ * interface extensions. Change major number in case of incompatible
+ * changes.
+ */
+ public static final String PROTOCOLVERSION = "{\"protocolversion\": {\"major\": " +
+ RemoteControlPlugin.protocolMajorVersion + ", \"minor\": " +
+ RemoteControlPlugin.protocolMinorVersion +
+ "}, \"application\": \"JOSM RemoteControl\"}";
+
+ /** The socket this processor listens on */
+ private Socket request;
+
+ /**
+ * Collection of request handlers.
+ * Will be initialized with default handlers here. Other plug-ins
+ * can extend this list by using @see addRequestHandler
+ */
+ private static HashMap<String, Class<? extends RequestHandler>> handlers = new HashMap<String, Class<? extends RequestHandler>>();
+
+ /**
+ * Constructor
+ *
+ * @param request A socket to read the request.
+ */
+ public RequestProcessor(Socket request) {
+ super("RemoteControl request processor");
+ this.setDaemon(true);
+ this.request = request;
+ }
+
+ /**
+ * Spawns a new thread for the request
+ *
+ * @param request
+ * The WMS request
+ */
+ public static void processRequest(Socket request) {
+ RequestProcessor processor = new RequestProcessor(request);
+ processor.start();
+ }
+
+ /**
+ * Add external request handler. Can be used by other plug-ins that
+ * want to use remote control.
+ * @param command The command to handle.
+ * @param handler The additional request handler.
+ */
+ static void addRequestHandlerClass(String command,
+ Class<? extends RequestHandler> handler) {
+ addRequestHandlerClass(command, handler, false);
+ }
+
+ /**
+ * Add external request handler. Message can be suppressed.
+ * (for internal use)
+ * @param command The command to handle.
+ * @param handler The additional request handler.
+ * @param silent Don't show message if true.
+ */
+ private static void addRequestHandlerClass(String command,
+ Class<? extends RequestHandler> handler, boolean silent) {
+ if(command.charAt(0) == '/')
+ {
+ command = command.substring(1);
+ }
+ String commandWithSlash = "/" + command;
+ if (handlers.get(commandWithSlash) != null) {
+ System.out.println("RemoteControl: ignoring duplicate command " + command
+ + " with handler " + handler.getName());
+ } else {
+ if(!silent) System.out.println("RemoteControl: adding command \"" +
+ command + "\" (handled by " + handler.getSimpleName() + ")");
+ handlers.put(commandWithSlash, handler);
+ }
+ }
+
+ /** Add default request handlers */
+ static {
+ addRequestHandlerClass(LoadAndZoomHandler.command,
+ LoadAndZoomHandler.class, true);
+ addRequestHandlerClass(LoadAndZoomHandler.command2,
+ LoadAndZoomHandler.class, true);
+ addRequestHandlerClass(AddNodeHandler.command, AddNodeHandler.class, true);
+ addRequestHandlerClass(ImportHandler.command, ImportHandler.class, true);
+ addRequestHandlerClass(VersionHandler.command, VersionHandler.class, true);
+ }
+
+ /**
+ * The work is done here.
+ */
+ public void run() {
+ Writer out = null;
+ try {
+ OutputStream raw = new BufferedOutputStream(
+ request.getOutputStream());
+ out = new OutputStreamWriter(raw);
+ Reader in = new InputStreamReader(new BufferedInputStream(
+ request.getInputStream()), "ASCII");
+
+ StringBuffer requestLine = new StringBuffer();
+ while (requestLine.length() < 1024) {
+ int c = in.read();
+ if (c == '\r' || c == '\n')
+ break;
+ requestLine.append((char) c);
+ }
+
+ System.out.println("RemoteControl received: " + requestLine);
+ String get = requestLine.toString();
+ StringTokenizer st = new StringTokenizer(get);
+ if (!st.hasMoreTokens()) {
+ sendError(out);
+ return;
+ }
+ String method = st.nextToken();
+ if (!st.hasMoreTokens()) {
+ sendError(out);
+ return;
+ }
+ String url = st.nextToken();
+
+ if (!method.equals("GET")) {
+ sendNotImplemented(out);
+ return;
+ }
+
+ String command = null;
+ int questionPos = url.indexOf('?');
+ if(questionPos < 0)
+ {
+ command = url;
+ }
+ else
+ {
+ command = url.substring(0, questionPos);
+ }
+
+ // find a handler for this command
+ Class<? extends RequestHandler> handlerClass = handlers
+ .get(command);
+ if (handlerClass == null) {
+ // no handler found
+ sendBadRequest(out);
+ } else {
+ // create handler object
+ RequestHandler handler = handlerClass.newInstance();
+ try {
+ handler.setCommand(command);
+ handler.setUrl(url);
+ handler.checkPermission();
+ handler.handle();
+ sendHeader(out, "200 OK", handler.contentType, false);
+ out.write("Content-length: " + handler.content.length()
+ + "\r\n");
+ out.write("\r\n");
+ out.write(handler.content);
+ out.flush();
+ } catch (RequestHandlerErrorException ex) {
+ sendError(out);
+ } catch (RequestHandlerBadRequestException ex) {
+ sendBadRequest(out);
+ } catch (RequestHandlerForbiddenException ex) {
+ sendForbidden(out);
+ }
+ }
+
+ } catch (IOException ioe) {
+ } catch (Exception e) {
+ e.printStackTrace();
+ try {
+ sendError(out);
+ } catch (IOException e1) {
+ }
+ } finally {
+ try {
+ request.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ /**
+ * Sends a 500 error: server error
+ *
+ * @param out
+ * The writer where the error is written
+ * @throws IOException
+ * If the error can not be written
+ */
+ private void sendError(Writer out) throws IOException {
+ sendHeader(out, "500 Internal Server Error", "text/html", true);
+ out.write("<HTML>\r\n");
+ out.write("<HEAD><TITLE>Internal Error</TITLE>\r\n");
+ out.write("</HEAD>\r\n");
+ out.write("<BODY>");
+ out.write("<H1>HTTP Error 500: Internal Server Error</h2>\r\n");
+ out.write("</BODY></HTML>\r\n");
+ out.flush();
+ }
+
+ /**
+ * Sends a 501 error: not implemented
+ *
+ * @param out
+ * The writer where the error is written
+ * @throws IOException
+ * If the error can not be written
+ */
+ private void sendNotImplemented(Writer out) throws IOException {
+ sendHeader(out, "501 Not Implemented", "text/html", true);
+ out.write("<HTML>\r\n");
+ out.write("<HEAD><TITLE>Not Implemented</TITLE>\r\n");
+ out.write("</HEAD>\r\n");
+ out.write("<BODY>");
+ out.write("<H1>HTTP Error 501: Not Implemented</h2>\r\n");
+ out.write("</BODY></HTML>\r\n");
+ out.flush();
+ }
+
+ /**
+ * Sends a 403 error: forbidden
+ *
+ * @param out
+ * The writer where the error is written
+ * @throws IOException
+ * If the error can not be written
+ */
+ private void sendForbidden(Writer out) throws IOException {
+ sendHeader(out, "403 Forbidden", "text/html", true);
+ out.write("<HTML>\r\n");
+ out.write("<HEAD><TITLE>Forbidden</TITLE>\r\n");
+ out.write("</HEAD>\r\n");
+ out.write("<BODY>");
+ out.write("<H1>HTTP Error 403: Forbidden</h2>\r\n");
+ out.write("</BODY></HTML>\r\n");
+ out.flush();
+ }
+
+ /**
+ * Sends a 403 error: forbidden
+ *
+ * @param out
+ * The writer where the error is written
+ * @throws IOException
+ * If the error can not be written
+ */
+ private void sendBadRequest(Writer out) throws IOException {
+ sendHeader(out, "400 Bad Request", "text/html", true);
+ out.write("<HTML>\r\n");
+ out.write("<HEAD><TITLE>Bad Request</TITLE>\r\n");
+ out.write("</HEAD>\r\n");
+ out.write("<BODY>");
+ out.write("<H1>HTTP Error 400: Bad Request</h2>\r\n");
+ out.write("</BODY></HTML>\r\n");
+ out.flush();
+ }
+
+ /**
+ * Send common HTTP headers to the client.
+ *
+ * @param out
+ * The Writer
+ * @param status
+ * The status string ("200 OK", "500", etc)
+ * @param contentType
+ * The content type of the data sent
+ * @param endHeaders
+ * If true, adds a new line, ending the headers.
+ * @throws IOException
+ * When error
+ */
+ private void sendHeader(Writer out, String status, String contentType,
+ boolean endHeaders) throws IOException {
+ out.write("HTTP/1.1 " + status + "\r\n");
+ Date now = new Date();
+ out.write("Date: " + now + "\r\n");
+ out.write("Server: JOSM RemoteControl\r\n");
+ out.write("Content-type: " + contentType + "\r\n");
+ out.write("Access-Control-Allow-Origin: *\r\n");
+ if (endHeaders)
+ out.write("\r\n");
+ }
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/AddNodeHandler.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/AddNodeHandler.java
new file mode 100644
index 0000000..2d5b9bd
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/AddNodeHandler.java
@@ -0,0 +1,68 @@
+package org.openstreetmap.josm.plugins.remotecontrol.handler;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.HashMap;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.plugins.remotecontrol.PermissionPrefWithDefault;
+import org.openstreetmap.josm.plugins.remotecontrol.RequestHandler;
+
+/**
+ * Handler for add_node request.
+ */
+public class AddNodeHandler extends RequestHandler {
+
+ public static final String command = "add_node";
+ public static final String permissionKey = "remotecontrol.permission.create-objects";
+ public static final boolean permissionDefault = false;
+
+ @Override
+ protected void handleRequest() {
+ addNode(args);
+ }
+
+ @Override
+ protected String[] getMandatoryParams()
+ {
+ return new String[] { "lat", "lon" };
+ }
+
+ @Override
+ public String getPermissionMessage() {
+ return tr("Remote Control has been asked to create a new node.");
+ }
+
+ @Override
+ public PermissionPrefWithDefault getPermissionPref()
+ {
+ return new PermissionPrefWithDefault(permissionKey, permissionDefault,
+ "RemoteControl: creating objects forbidden by preferences");
+ }
+
+ /**
+ * Adds a node, implements the GET /add_node?lon=...&lat=... request.
+ * @param args
+ */
+ private void addNode(HashMap<String, String> args){
+
+ // Parse the arguments
+ double lat = Double.parseDouble(args.get("lat"));
+ double lon = Double.parseDouble(args.get("lon"));
+ System.out.println("Adding node at (" + lat + ", " + lon + ")");
+
+ // Create a new node
+ LatLon ll = new LatLon(lat, lon);
+ Node nnew = new Node(ll);
+
+ // Now execute the commands to add this node.
+ Main.main.undoRedo.add(new AddCommand(nnew));
+ Main.main.getCurrentDataSet().setSelected(nnew);
+ Main.map.mapView.repaint();
+
+ }
+
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/ImportHandler.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/ImportHandler.java
new file mode 100644
index 0000000..398dd92
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/ImportHandler.java
@@ -0,0 +1,52 @@
+package org.openstreetmap.josm.plugins.remotecontrol.handler;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.net.URLDecoder;
+
+import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadTask;
+import org.openstreetmap.josm.plugins.remotecontrol.PermissionPrefWithDefault;
+import org.openstreetmap.josm.plugins.remotecontrol.RequestHandler;
+import org.openstreetmap.josm.plugins.remotecontrol.RequestHandlerErrorException;
+
+/**
+ * Handler for import request
+ */
+public class ImportHandler extends RequestHandler {
+
+ public static final String command = "import";
+ public static final String permissionKey = "remotecontrol.permission.import";
+ public static final boolean permissionDefault = true;
+
+ @Override
+ protected void handleRequest() throws RequestHandlerErrorException {
+ try {
+ DownloadTask osmTask = new DownloadOsmTask();
+ osmTask.loadUrl(false, URLDecoder.decode(args.get("url"), "UTF-8"), null);
+ } catch (Exception ex) {
+ System.out.println("RemoteControl: Error parsing import remote control request:");
+ ex.printStackTrace();
+ throw new RequestHandlerErrorException();
+ }
+ }
+
+ @Override
+ protected String[] getMandatoryParams()
+ {
+ return new String[] { "url" };
+ }
+
+ @Override
+ public String getPermissionMessage() {
+ return tr("Remote Control has been asked to import data from the following URL:") +
+ "<br>" + request;
+ }
+
+ @Override
+ public PermissionPrefWithDefault getPermissionPref()
+ {
+ return new PermissionPrefWithDefault(permissionKey, permissionDefault,
+ "RemoteControl: import forbidden by preferences");
+ }
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/LoadAndZoomHandler.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/LoadAndZoomHandler.java
new file mode 100644
index 0000000..0b7b8a9
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/LoadAndZoomHandler.java
@@ -0,0 +1,167 @@
+package org.openstreetmap.josm.plugins.remotecontrol.handler;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.geom.Area;
+import java.awt.geom.Rectangle2D;
+import java.util.HashSet;
+import java.util.concurrent.Future;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.AutoScaleAction;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadTask;
+import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
+import org.openstreetmap.josm.plugins.remotecontrol.RequestHandler;
+import org.openstreetmap.josm.plugins.remotecontrol.RequestHandlerErrorException;
+
+/**
+ * Handler for load_and_zoom request.
+ */
+public class LoadAndZoomHandler extends RequestHandler
+{
+ public static final String command = "load_and_zoom";
+ public static final String command2 = "zoom";
+
+ public static final String loadDataPermissionKey = "remotecontrol.permission.load-data";
+ public static final boolean loadDataPermissionDefault = true;
+ public static final String changeSelectionPermissionKey = "remotecontrol.permission.change-selection";
+ public static final boolean changeSelectionPermissionDefault = true;
+ public static final String changeViewportPermissionKey = "remotecontrol.permission.change-viewport";
+ public static final boolean changeViewportPermissionDefault = true;
+
+ @Override
+ public String getPermissionMessage()
+ {
+ return tr("Remote Control has been asked to load data from the API.") +
+ "<br>" + tr("Request details: {0}", request);
+ }
+
+ @Override
+ protected String[] getMandatoryParams()
+ {
+ return new String[] { "bottom", "top", "left", "right" };
+ }
+
+ @Override
+ protected void handleRequest() throws RequestHandlerErrorException
+ {
+ DownloadTask osmTask = new DownloadOsmTask();
+ double minlat = 0;
+ double maxlat = 0;
+ double minlon = 0;
+ double maxlon = 0;
+ try {
+ minlat = Double.parseDouble(args.get("bottom"));
+ maxlat = Double.parseDouble(args.get("top"));
+ minlon = Double.parseDouble(args.get("left"));
+ maxlon = Double.parseDouble(args.get("right"));
+
+ if(command.equals(myCommand))
+ {
+ if (!Main.pref.getBoolean(loadDataPermissionKey, loadDataPermissionDefault))
+ {
+ System.out.println("RemoteControl: download forbidden by preferences");
+ }
+ else
+ {
+
+ // find out whether some data has already been downloaded
+ Area present = null;
+ Area toDownload = null;
+ DataSet ds = Main.main.getCurrentDataSet();
+ if (ds != null)
+ present = ds.getDataSourceArea();
+ if (present != null && !present.isEmpty()) {
+ toDownload = new Area(new Rectangle2D.Double(minlon,minlat,maxlon-minlon,maxlat-minlat));
+ toDownload.subtract(present);
+ if (!toDownload.isEmpty())
+ {
+ // the result might not be a rectangle (L shaped etc)
+ Rectangle2D downloadBounds = toDownload.getBounds2D();
+ minlat = downloadBounds.getMinY();
+ minlon = downloadBounds.getMinX();
+ maxlat = downloadBounds.getMaxY();
+ maxlon = downloadBounds.getMaxX();
+ }
+ }
+ if((toDownload != null) && toDownload.isEmpty())
+ {
+ System.out.println("RemoteControl: no download necessary");
+ }
+ else
+ {
+ Future<?> future = osmTask.download(false /*no new layer*/, new Bounds(minlat,minlon,maxlat,maxlon), null /* let the task manage the progress monitor */);
+ Main.worker.submit(new PostDownloadHandler(osmTask, future));
+ }
+ }
+ }
+ } catch (Exception ex) {
+ System.out.println("RemoteControl: Error parsing load_and_zoom remote control request:");
+ ex.printStackTrace();
+ throw new RequestHandlerErrorException();
+ }
+ if (args.containsKey("select") && Main.pref.getBoolean(changeSelectionPermissionKey, changeSelectionPermissionDefault)) {
+ // select objects after downloading, zoom to selection.
+ final String selection = args.get("select");
+ Main.worker.execute(new Runnable() {
+ public void run() {
+ HashSet<Long> ways = new HashSet<Long>();
+ HashSet<Long> nodes = new HashSet<Long>();
+ HashSet<Long> relations = new HashSet<Long>();
+ HashSet<OsmPrimitive> newSel = new HashSet<OsmPrimitive>();
+ for (String item : selection.split(",")) {
+ if (item.startsWith("way")) {
+ ways.add(Long.parseLong(item.substring(3)));
+ } else if (item.startsWith("node")) {
+ nodes.add(Long.parseLong(item.substring(4)));
+ } else if (item.startsWith("relation")) {
+ relations.add(Long.parseLong(item.substring(8)));
+ } else if (item.startsWith("rel")) {
+ relations.add(Long.parseLong(item.substring(3)));
+ } else {
+ System.out.println("RemoteControl: invalid selection '"+item+"' ignored");
+ }
+ }
+ DataSet ds = Main.main.getCurrentDataSet();
+ if(ds == null) // e.g. download failed
+ return;
+ for (Way w : ds.getWays()) if (ways.contains(w.getId())) newSel.add(w);
+ for (Node n : ds.getNodes()) if (nodes.contains(n.getId())) newSel.add(n);
+ for (Relation r : ds.getRelations()) if (relations.contains(r.getId())) newSel.add(r);
+ ds.setSelected(newSel);
+ if (Main.pref.getBoolean(changeViewportPermissionKey, changeViewportPermissionDefault))
+ new AutoScaleAction("selection").actionPerformed(null);
+ }
+ });
+ } else if (Main.pref.getBoolean(changeViewportPermissionKey, changeViewportPermissionDefault)) {
+ // after downloading, zoom to downloaded area.
+ zoom(minlat, maxlat, minlon, maxlon);
+ }
+ }
+
+ protected void zoom(double minlat, double maxlat, double minlon, double maxlon) {
+ final Bounds bounds = new Bounds(new LatLon(minlat, minlon),
+ new LatLon(maxlat, maxlon));
+
+ // make sure this isn't called unless there *is* a MapView
+ //
+ if (Main.map != null && Main.map.mapView != null) {
+ Main.worker.execute(new Runnable() {
+ public void run() {
+ BoundingXYVisitor bbox = new BoundingXYVisitor();
+ bbox.visit(bounds);
+ Main.map.mapView.recalculateCenterScale(bbox);
+ }
+ });
+ }
+ }
+}
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/VersionHandler.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/VersionHandler.java
new file mode 100644
index 0000000..e96690c
--- /dev/null
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/VersionHandler.java
@@ -0,0 +1,41 @@
+package org.openstreetmap.josm.plugins.remotecontrol.handler;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import org.openstreetmap.josm.plugins.remotecontrol.PermissionPrefWithDefault;
+import org.openstreetmap.josm.plugins.remotecontrol.RequestHandler;
+import org.openstreetmap.josm.plugins.remotecontrol.RequestHandlerBadRequestException;
+import org.openstreetmap.josm.plugins.remotecontrol.RequestHandlerErrorException;
+import org.openstreetmap.josm.plugins.remotecontrol.RequestProcessor;
+
+/**
+ * Handler for version request.
+ */
+public class VersionHandler extends RequestHandler {
+
+ public static final String command = "version";
+ public static final String permissionKey = "remotecontrol.permission.read-protocolversion";
+ public static final boolean permissionDefault = true;
+
+ @Override
+ protected void handleRequest() throws RequestHandlerErrorException,
+ RequestHandlerBadRequestException {
+ content = RequestProcessor.PROTOCOLVERSION;
+ contentType = "application/json";
+ if (args.containsKey("jsonp")) {
+ content = args.get("jsonp")+ " && " + args.get("jsonp") + "(" + content + ")";
+ }
+ }
+
+ @Override
+ public String getPermissionMessage() {
+ return tr("Remote Control has been asked to report its protocol version. This enables web sites to detect a running JOSM.");
+ }
+
+ @Override
+ public PermissionPrefWithDefault getPermissionPref()
+ {
+ return new PermissionPrefWithDefault(permissionKey, permissionDefault,
+ "RemoteControl: /version forbidden by preferences");
+ }
+}
diff --git a/routing/build.xml b/routing/build.xml
index c21112c..ecc98b4 100644
--- a/routing/build.xml
+++ b/routing/build.xml
@@ -17,7 +17,7 @@
** > ant install
**
** To build against the core in ../../core, create a correct manifest and deploy to
-** SVN,
+** SVN,
** set the properties commit.message and plugin.main.version
** and run
** > ant publish
@@ -27,7 +27,7 @@
<project name="routing" default="dist" basedir=".">
<property name="commit.message" value="Changed the constructor signature of the plugin main class" />
- <property name="plugin.main.version" value="2830" />
+ <property name="plugin.main.version" value="3408" />
<!-- Define some properties -->
<property name="josm" location="../../core/dist/josm-custom.jar"/>
@@ -105,10 +105,10 @@
</target>
<!--
- ************************** Publishing the plugin ***********************************
+ ************************** Publishing the plugin ***********************************
-->
<!--
- ** extracts the JOSM release for the JOSM version in ../core and saves it in the
+ ** extracts the JOSM release for the JOSM version in ../core and saves it in the
** property ${coreversion.info.entry.revision}
**
-->
@@ -157,17 +157,17 @@
</target>
<!--
- ** commits the plugin.jar
+ ** commits the plugin.jar
-->
<target name="commit-dist">
<echo>
***** Properties of published ${plugin.jar} *****
- Commit message : '${commit.message}'
+ Commit message : '${commit.message}'
Plugin-Mainversion: ${plugin.main.version}
JOSM build version: ${coreversion.info.entry.revision}
Plugin-Version : ${version.entry.commit.revision}
- ***** / Properties of published ${plugin.jar} *****
-
+ ***** / Properties of published ${plugin.jar} *****
+
Now commiting ${plugin.jar} ...
</echo>
<exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
diff --git a/routing/src/com/innovant/josm/plugin/routing/RoutingLayer.java b/routing/src/com/innovant/josm/plugin/routing/RoutingLayer.java
index 7f42c37..6cd0eab 100644
--- a/routing/src/com/innovant/josm/plugin/routing/RoutingLayer.java
+++ b/routing/src/com/innovant/josm/plugin/routing/RoutingLayer.java
@@ -29,7 +29,6 @@ package com.innovant.josm.plugin.routing;
import java.awt.BasicStroke;
import java.awt.Color;
-import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
@@ -38,9 +37,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import javax.swing.Action;
import javax.swing.Icon;
-import javax.swing.JMenuItem;
-import javax.swing.JSeparator;
import org.apache.log4j.Logger;
import org.openstreetmap.josm.Main;
@@ -181,16 +179,16 @@ public class RoutingLayer extends Layer {
* @see org.openstreetmap.josm.gui.layer.Layer#getMenuEntries()
*/
@Override
- public Component[] getMenuEntries() {
- Collection<Component> components = new ArrayList<Component>();
- components.add(new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)));
+ public Action[] getMenuEntries() {
+ Collection<Action> components = new ArrayList<Action>();
+ components.add(LayerListDialog.getInstance().createShowHideLayerAction());
// components.add(new JMenuItem(new LayerListDialog.ShowHideMarkerText(this)));
- components.add(new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)));
- components.add(new JSeparator());
- components.add(new JMenuItem(new RenameLayerAction(getAssociatedFile(), this)));
- components.add(new JSeparator());
- components.add(new JMenuItem(new LayerListPopup.InfoAction(this)));
- return components.toArray(new Component[0]);
+ components.add(LayerListDialog.getInstance().createDeleteLayerAction());
+ components.add(SeparatorLayerAction.INSTANCE);
+ components.add(new RenameLayerAction(getAssociatedFile(), this));
+ components.add(SeparatorLayerAction.INSTANCE);
+ components.add(new LayerListPopup.InfoAction(this));
+ return components.toArray(new Action[0]);
}
/*
diff --git a/slippymap/build.xml b/slippymap/build.xml
index 4440051..3151356 100644
--- a/slippymap/build.xml
+++ b/slippymap/build.xml
@@ -17,7 +17,7 @@
** > ant install
**
** To build against the core in ../../core, create a correct manifest and deploy to
-** SVN,
+** SVN,
** set the properties commit.message and plugin.main.version
** and run
** > ant publish
@@ -27,7 +27,7 @@
<project name="slippymap" default="dist" basedir=".">
<property name="commit.message" value="Added haiti imagery tile source" />
- <property name="plugin.main.version" value="2830" />
+ <property name="plugin.main.version" value="3408" />
<property name="josm" location="../../core/dist/josm-custom.jar"/>
<property name="plugin.dist.dir" value="../../dist"/>
@@ -86,10 +86,10 @@
</target>
<!--
- ************************** Publishing the plugin ***********************************
+ ************************** Publishing the plugin ***********************************
-->
<!--
- ** extracts the JOSM release for the JOSM version in ../core and saves it in the
+ ** extracts the JOSM release for the JOSM version in ../core and saves it in the
** property ${coreversion.info.entry.revision}
**
-->
@@ -138,17 +138,17 @@
</target>
<!--
- ** commits the plugin.jar
+ ** commits the plugin.jar
-->
<target name="commit-dist">
<echo>
***** Properties of published ${plugin.jar} *****
- Commit message : '${commit.message}'
+ Commit message : '${commit.message}'
Plugin-Mainversion: ${plugin.main.version}
JOSM build version: ${coreversion.info.entry.revision}
Plugin-Version : ${version.entry.commit.revision}
- ***** / Properties of published ${plugin.jar} *****
-
+ ***** / Properties of published ${plugin.jar} *****
+
Now commiting ${plugin.jar} ...
</echo>
<exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
@@ -183,7 +183,7 @@
<target name="publish" depends="ensure-svn-present,core-info,commit-current,update-current,clean,dist,commit-dist">
</target>
-
+
<target name="dev-install">
<copy file="${plugin.jar}" todir="c:/data/projekte/osm/josm-dev/plugins" />
</target>
diff --git a/wmsplugin/josm-wmsplugin.launch b/slippymap/josm-slippymap.launch
similarity index 91%
copy from wmsplugin/josm-wmsplugin.launch
copy to slippymap/josm-slippymap.launch
index 0b4de4c..4dc2cd4 100644
--- a/wmsplugin/josm-wmsplugin.launch
+++ b/slippymap/josm-slippymap.launch
@@ -6,7 +6,7 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JDK 5"/>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JDK 6"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.openstreetmap.josm.gui.MainApplication"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="wmsplugin"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="slippymap"/>
</launchConfiguration>
diff --git a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapLayer.java b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapLayer.java
index fc59189..2874f65 100644
--- a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapLayer.java
+++ b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapLayer.java
@@ -3,7 +3,6 @@ package org.openstreetmap.josm.plugins.slippymap;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Color;
-import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
@@ -20,11 +19,11 @@ import java.util.LinkedList;
import java.util.List;
import javax.swing.AbstractAction;
+import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
-import javax.swing.JSeparator;
import javax.swing.SwingUtilities;
import org.openstreetmap.gui.jmapviewer.JobDispatcher;
@@ -38,16 +37,14 @@ import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.RenameLayerAction;
import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
-import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
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;
-import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
/**
* Class that displays a slippy map layer.
@@ -57,7 +54,7 @@ import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
* @author Dave Hansen <dave at sr71.net>
*
*/
-public class SlippyMapLayer extends Layer implements PreferenceChangedListener, ImageObserver,
+public class SlippyMapLayer extends Layer implements ImageObserver,
TileLoaderListener {
boolean debug = false;
void out(String s)
@@ -263,13 +260,10 @@ public class SlippyMapLayer extends Layer implements PreferenceChangedListener,
public void layerRemoved(Layer oldLayer) {
MapView.removeLayerChangeListener(this);
- Main.pref.removePreferenceChangeListener(SlippyMapLayer.this);
}
});
}
});
-
- Main.pref.addPreferenceChangeListener(this);
}
void zoomChanged()
@@ -879,8 +873,6 @@ public class SlippyMapLayer extends Layer implements PreferenceChangedListener,
ts.loadAllTiles(false);
}
- int fontHeight = g.getFontMetrics().getHeight();
-
g.setColor(Color.DARK_GRAY);
List<Tile> missedTiles = this.paintTileImages(g, ts, currentZoomLevel, null);
@@ -962,7 +954,6 @@ public class SlippyMapLayer extends Layer implements PreferenceChangedListener,
if (!ts.tooLarge())
ts.loadAllTiles(false); // make sure there are tile objects for all tiles
Tile clickedTile = null;
- Point p1 = null, p2 = null;
for (Tile t1 : ts.allTiles()) {
Tile t2 = tempCornerTile(t1);
Rectangle r = new Rectangle(pixelPos(t1));
@@ -992,15 +983,15 @@ public class SlippyMapLayer extends Layer implements PreferenceChangedListener,
}
@Override
- public Component[] getMenuEntries() {
- return new Component[] {
- new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
- new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)),
- new JSeparator(),
+ public Action[] getMenuEntries() {
+ return new Action[] {
+ LayerListDialog.getInstance().createShowHideLayerAction(),
+ LayerListDialog.getInstance().createDeleteLayerAction(),
+ SeparatorLayerAction.INSTANCE,
// color,
- new JMenuItem(new RenameLayerAction(this.getAssociatedFile(), this)),
- new JSeparator(),
- new JMenuItem(new LayerListPopup.InfoAction(this)) };
+ new RenameLayerAction(this.getAssociatedFile(), this),
+ SeparatorLayerAction.INSTANCE,
+ new LayerListPopup.InfoAction(this) };
}
@Override
@@ -1040,31 +1031,4 @@ public class SlippyMapLayer extends Layer implements PreferenceChangedListener,
private double tileXToLon(int x, int zoom) {
return x * 45.0 / Math.pow(2.0, zoom - 3) - 180.0;
}
-
- /*
- * (non-Javadoc)
- *
- * @seeorg.openstreetmap.josm.data.Preferences.PreferenceChangedListener#
- * preferenceChanged(java.lang.String, java.lang.String)
- */
- public void preferenceChanged(PreferenceChangeEvent event) {
- if (event.getKey().startsWith(SlippyMapPreferences.PREFERENCE_PREFIX)) {
- // System.err.println(this + ".preferenceChanged('" + key + "', '"
- // + newValue + "') called");
- // when fade background changed, no need to clear tile storage
- // TODO move this code to SlippyMapPreferences class.
- if (!event.getKey().equals(SlippyMapPreferences.PREFERENCE_FADE_BACKGROUND)) {
- autoZoomPopup.setSelected(SlippyMapPreferences.getAutozoom());
- }
- if (event.getKey().equals(SlippyMapPreferences.PREFERENCE_TILE_SOURCE)) {
- newTileStorage();
- }
- redraw();
- }
- }
-
- @Override
- public void destroy() {
- Main.pref.removePreferenceChangeListener(SlippyMapLayer.this);
- }
}
diff --git a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPlugin.java b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPlugin.java
index 3b84be4..1f1cb7e 100644
--- a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPlugin.java
+++ b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPlugin.java
@@ -1,6 +1,10 @@
package org.openstreetmap.josm.plugins.slippymap;
+import java.util.List;
+
import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
+import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
import org.openstreetmap.josm.gui.MapFrame;
import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
import org.openstreetmap.josm.plugins.Plugin;
@@ -12,16 +16,18 @@ import org.openstreetmap.josm.plugins.PluginInformation;
* @author Frederik Ramm <frederik at remote.org>
*
*/
-public class SlippyMapPlugin extends Plugin
+public class SlippyMapPlugin extends Plugin implements PreferenceChangedListener
{
public SlippyMapPlugin(PluginInformation info)
{
super(info);
+ Main.pref.addPreferenceChangeListener(this);
}
- public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame)
+ @Override
+ public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame)
{
- if (newFrame != null){
+ if (newFrame != null && SlippyMapPreferences.getMapSource() != SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE) {
SlippyMapLayer smlayer;
smlayer = new SlippyMapLayer();
Main.main.addLayer(smlayer);
@@ -39,4 +45,40 @@ public class SlippyMapPlugin extends Plugin
return new SlippyMapPreferenceSetting();
}
+ /*
+ * (non-Javadoc)
+ *
+ * @seeorg.openstreetmap.josm.data.Preferences.PreferenceChangedListener#
+ * preferenceChanged(java.lang.String, java.lang.String)
+ */
+ public void preferenceChanged(PreferenceChangeEvent event) {
+ if (!Main.isDisplayingMapView()) {
+ return;
+ }
+ List<SlippyMapLayer> layes = Main.map.mapView.getLayersOfType(SlippyMapLayer.class);
+ assert layes.size() <= 1;
+ SlippyMapLayer layer = layes.isEmpty()?null:layes.get(0);
+
+ if (event.getKey().equals(SlippyMapPreferences.PREFERENCE_TILE_SOURCE)) {
+ if (layer == null && SlippyMapPreferences.getMapSource() != SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE) {
+ Main.map.mapView.addLayer(new SlippyMapLayer());
+ } else if (layer != null && SlippyMapPreferences.getMapSource() == SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE) {
+ Main.map.mapView.removeLayer(layer);
+ } else if (layer == null && SlippyMapPreferences.getMapSource() == SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE) {
+ // Do nothing
+ } else {
+ layer.newTileStorage();
+ }
+ } else if (event.getKey().startsWith(SlippyMapPreferences.PREFERENCE_PREFIX) && layer != null) {
+ // System.err.println(this + ".preferenceChanged('" + key + "', '"
+ // + newValue + "') called");
+ // when fade background changed, no need to clear tile storage
+ // TODO move this code to SlippyMapPreferences class.
+ if (!event.getKey().equals(SlippyMapPreferences.PREFERENCE_FADE_BACKGROUND)) {
+ layer.autoZoomPopup.setSelected(SlippyMapPreferences.getAutozoom());
+ }
+ layer.redraw();
+ }
+ }
+
}
diff --git a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferenceSetting.java b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferenceSetting.java
index 3b13dd4..4cfc0a4 100644
--- a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferenceSetting.java
+++ b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferenceSetting.java
@@ -2,6 +2,11 @@ package org.openstreetmap.josm.plugins.slippymap;
import static org.openstreetmap.josm.tools.I18n.tr;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.swing.Box;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
@@ -10,14 +15,8 @@ import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
-import java.awt.event.ActionListener;
-import java.awt.event.ActionEvent;
-import java.util.Collection;
-
-import org.openstreetmap.gui.jmapviewer.*;
-import org.openstreetmap.gui.jmapviewer.interfaces.*;
-import org.openstreetmap.josm.gui.preferences.PreferenceDialog;
+import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
import org.openstreetmap.josm.tools.GBC;
@@ -33,20 +32,21 @@ public class SlippyMapPreferenceSetting implements PreferenceSetting {
* ComboBox with all known tile sources.
*/
private JComboBox tileSourceCombo;
-
+
private JCheckBox autozoomActive = new JCheckBox(tr("autozoom"));
private JCheckBox autoloadTiles = new JCheckBox(tr("autoload tiles"));
private JSpinner maxZoomLvl;
private JSpinner minZoomLvl = new JSpinner();
private JSlider fadeBackground = new JSlider(0, 100);
-
+
public void addGui(PreferenceTabbedPane gui)
{
minZoomLvl = new JSpinner(new SpinnerNumberModel(SlippyMapPreferences.DEFAULT_MIN_ZOOM, SlippyMapPreferences.MIN_ZOOM, SlippyMapPreferences.MAX_ZOOM, 1));
maxZoomLvl = new JSpinner(new SpinnerNumberModel(SlippyMapPreferences.DEFAULT_MAX_ZOOM, SlippyMapPreferences.MIN_ZOOM, SlippyMapPreferences.MAX_ZOOM, 1));
//String description = tr("A plugin that adds to JOSM new layer. This layer could render external tiles.");
JPanel slippymapTab = gui.createPreferenceTab("slippymap.png", tr("SlippyMap"), tr("Settings for the SlippyMap plugin."));
- Collection<TileSource> allSources = SlippyMapPreferences.getAllMapSources();
+ List<TileSource> allSources = new ArrayList<TileSource>(SlippyMapPreferences.getAllMapSources());
+ allSources.add(0, SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE);
//Collection<String> allSources = SlippyMapPreferences.getAllMapNames();
tileSourceCombo = new JComboBox(allSources.toArray());
//tileSourceCombo.setEditable(true);
@@ -54,19 +54,19 @@ public class SlippyMapPreferenceSetting implements PreferenceSetting {
slippymapTab.add(new JLabel(tr("Tile Sources")), GBC.std());
slippymapTab.add(GBC.glue(5, 0), GBC.std());
slippymapTab.add(tileSourceCombo, GBC.eol().fill(GBC.HORIZONTAL));
-
+
slippymapTab.add(new JLabel(tr("Auto zoom: ")), GBC.std());
slippymapTab.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
slippymapTab.add(autozoomActive, GBC.eol().fill(GBC.HORIZONTAL));
-
+
slippymapTab.add(new JLabel(tr("Autoload Tiles: ")), GBC.std());
slippymapTab.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
slippymapTab.add(autoloadTiles, GBC.eol().fill(GBC.HORIZONTAL));
-
+
slippymapTab.add(new JLabel(tr("Min zoom lvl: ")), GBC.std());
slippymapTab.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
slippymapTab.add(this.minZoomLvl, GBC.eol().fill(GBC.HORIZONTAL));
-
+
slippymapTab.add(new JLabel(tr("Max zoom lvl: ")), GBC.std());
slippymapTab.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
slippymapTab.add(this.maxZoomLvl, GBC.eol().fill(GBC.HORIZONTAL));
@@ -74,7 +74,7 @@ public class SlippyMapPreferenceSetting implements PreferenceSetting {
slippymapTab.add(new JLabel(tr("Fade background: ")), GBC.std());
slippymapTab.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
slippymapTab.add(this.fadeBackground, GBC.eol().fill(GBC.HORIZONTAL));
-
+
slippymapTab.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
tileSourceCombo.addActionListener(new ActionListener() {
@@ -127,7 +127,7 @@ public class SlippyMapPreferenceSetting implements PreferenceSetting {
this.minZoomLvl.setValue(SlippyMapPreferences.getMinZoomLvl());
this.fadeBackground.setValue(Math.round(SlippyMapPreferences.getFadeBackground()*100f));
}
-
+
/**
* <p>
* Someone pressed the "ok" button
@@ -138,7 +138,7 @@ public class SlippyMapPreferenceSetting implements PreferenceSetting {
*/
public boolean ok()
{
- SlippyMapPreferences.setMapSource((TileSource)this.tileSourceCombo.getSelectedItem());
+ SlippyMapPreferences.setMapSource((TileSource)this.tileSourceCombo.getSelectedItem());
SlippyMapPreferences.setAutozoom(this.autozoomActive.isSelected());
SlippyMapPreferences.setAutoloadTiles(this.autoloadTiles.isSelected());
SlippyMapPreferences.setMaxZoomLvl((Integer)this.maxZoomLvl.getValue());
diff --git a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferences.java b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferences.java
index 90aad6a..680726f 100644
--- a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferences.java
+++ b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferences.java
@@ -1,12 +1,15 @@
package org.openstreetmap.josm.plugins.slippymap;
-import org.openstreetmap.josm.Main;
-import java.util.List;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
import java.util.ArrayList;
-import java.util.Collection;
+import java.util.List;
import java.util.Map;
-import org.openstreetmap.gui.jmapviewer.*;
-import org.openstreetmap.gui.jmapviewer.interfaces.*;
+
+import org.openstreetmap.gui.jmapviewer.OsmTileSource;
+import org.openstreetmap.gui.jmapviewer.OsmTileSource.AbstractOsmTileSource;
+import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
+import org.openstreetmap.josm.Main;
/**
* Preferences for Slippy Map Tiles
@@ -17,6 +20,7 @@ import org.openstreetmap.gui.jmapviewer.interfaces.*;
*/
public class SlippyMapPreferences
{
+ public static final String NO_DEFAULT_TILE_SOURCE_NAME = "{%no_default%}";
public static final String PREFERENCE_PREFIX = "slippymap";
public static final String PREFERENCE_TILE_CUSTOM_SOURCE = PREFERENCE_PREFIX + ".custom_tile_source_";
@@ -34,6 +38,7 @@ public class SlippyMapPreferences
public static final int DEFAULT_MAX_ZOOM = 20;
public static final int DEFAULT_MIN_ZOOM = 2;
+
public static TileSource getMapSource()
{
String name = Main.pref.get(PREFERENCE_TILE_SOURCE);
@@ -41,23 +46,27 @@ public class SlippyMapPreferences
}
public static TileSource getMapSource(String name)
{
+ if (NO_DEFAULT_TILE_SOURCE_NAME.equals(name)) {
+ return NO_DEFAULT_TILE_SOURCE; // User don't want to load slippy layer on startup
+ }
+
List<TileSource> sources = SlippyMapPreferences.getAllMapSources();
- TileSource source = sources.get(0);
+
if (name == null || "".equals(name)) {
- name = source.getName();
- Main.pref.put(PREFERENCE_TILE_SOURCE, name);
+ Main.pref.put(PREFERENCE_TILE_SOURCE, sources.get(0).getName());
+ return sources.get(0);
}
+
for (TileSource s : sources) {
- if (!name.equals(s.getName()))
- continue;
- source = s;
- break;
+ if (name.equals(s.getName()))
+ return s;
}
- return source;
+
+ return sources.get(0);
}
public static void setMapSource(TileSource source) {
- Main.pref.put(SlippyMapPreferences.PREFERENCE_TILE_SOURCE, source.getName());
+ Main.pref.put(SlippyMapPreferences.PREFERENCE_TILE_SOURCE, source == NO_DEFAULT_TILE_SOURCE?NO_DEFAULT_TILE_SOURCE_NAME:source.getName());
}
public static boolean getAutozoom()
@@ -235,6 +244,12 @@ public class SlippyMapPreferences
Main.pref.put(SlippyMapPreferences.PREFERENCE_MIN_ZOOM_LVL, "" + minZoomLvl);
}
+ public static TileSource NO_DEFAULT_TILE_SOURCE = new AbstractOsmTileSource(tr("(none)"), "") {
+ public TileUpdate getTileUpdate() {
+ return null;
+ }
+ };
+
public static class Coastline extends OsmTileSource.AbstractOsmTileSource {
public Coastline() {
super("Coastline", "http://hypercube.telascience.org/tiles/1.0.0/coastline");
@@ -265,11 +280,13 @@ public class SlippyMapPreferences
super("NearMap Australia", "http://www.nearmap.com/maps/hl=en&nml=Vert&");
}
- public int getMaxZoom() {
+ @Override
+ public int getMaxZoom() {
return 21;
}
- public String getTilePath(int zoom, int tilex, int tiley) {
+ @Override
+ public String getTilePath(int zoom, int tilex, int tiley) {
return "z=" + zoom + "&x=" + tilex + "&y=" + tiley;
}
@@ -277,18 +294,20 @@ public class SlippyMapPreferences
return TileUpdate.IfNoneMatch;
}
}
-
+
public static class HaitiImagery extends OsmTileSource.AbstractOsmTileSource {
public HaitiImagery() {
super("HaitiImagery", "http://gravitystorm.dev.openstreetmap.org/imagery/haiti");
}
- public int getMaxZoom() {
+ @Override
+ public int getMaxZoom() {
return 21;
}
- public String getTilePath(int zoom, int tilex, int tiley) {
+ @Override
+ public String getTilePath(int zoom, int tilex, int tiley) {
return "/" + zoom + "/" + tilex + "/" + tiley + ".png";
}
diff --git a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapTile.java b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapTile.java
deleted file mode 100644
index e69de29..0000000
diff --git a/svn-info.xml b/svn-info.xml
index 5016e5a..40df43d 100644
--- a/svn-info.xml
+++ b/svn-info.xml
@@ -3,16 +3,16 @@
<entry
kind="dir"
path="plugins"
- revision="22363">
+ revision="23040">
<url>http://svn.openstreetmap.org/applications/editors/josm/plugins</url>
<repository>
<root>http://svn.openstreetmap.org</root>
<uuid>b9d5c4c9-76e1-0310-9c85-f3177eceb1e4</uuid>
</repository>
<commit
- revision="22295">
-<author>nakor</author>
-<date>2010-07-13T00:34:51.532356Z</date>
+ revision="23039">
+<author>postfix</author>
+<date>2010-09-06T21:06:40.259986Z</date>
</commit>
</entry>
</info>
diff --git a/wmsplugin/.classpath b/wmsplugin/.classpath
index 663bc1b..1ae9f2f 100644
--- a/wmsplugin/.classpath
+++ b/wmsplugin/.classpath
@@ -1,7 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry including="images/" kind="src" path=""/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JDK 6"/>
<classpathentry combineaccessrules="false" kind="src" path="/JOSM"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/remotecontrol"/>
<classpathentry kind="output" path="build"/>
</classpath>
diff --git a/wmsplugin/.settings/org.eclipse.jdt.core.prefs b/wmsplugin/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..d8aed90
--- /dev/null
+++ b/wmsplugin/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Thu Aug 12 20:39:44 CEST 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/wmsplugin/build.xml b/wmsplugin/build.xml
index 7b811ba..c36ce4b 100644
--- a/wmsplugin/build.xml
+++ b/wmsplugin/build.xml
@@ -27,11 +27,12 @@
<project name="wmsplugin" default="dist" basedir=".">
- <property name="commit.message" value="add commit message" />
- <property name="plugin.main.version" value="2830" />
+ <property name="commit.message" value="fixed josm bug 4671 - wms url for sicily has changed" />
+ <property name="plugin.main.version" value="3451" />
<property name="josm" location="../../core/dist/josm-custom.jar" />
+ <property name="remotecontrol" location="../../dist/remotecontrol.jar" />
<property name="plugin.dist.dir" value="../../dist" />
<property name="plugin.build.dir" value="build" />
<property name="plugin.jar" value="${plugin.dist.dir}/${ant.project.name}.jar" />
@@ -42,7 +43,7 @@
</target>
<target name="compile" depends="init">
<echo message="creating ${plugin.jar}" />
- <javac srcdir="src" classpath="${josm}" debug="true" destdir="${plugin.build.dir}">
+ <javac srcdir="src" classpath="${josm};${remotecontrol}" debug="true" destdir="${plugin.build.dir}">
<compilerarg value="-Xlint:deprecation" />
<compilerarg value="-Xlint:unchecked" />
</javac>
@@ -92,10 +93,10 @@
</target>
<!--
- ************************** Publishing the plugin ***********************************
+ ************************** Publishing the plugin ***********************************
-->
<!--
- ** extracts the JOSM release for the JOSM version in ../core and saves it in the
+ ** extracts the JOSM release for the JOSM version in ../core and saves it in the
** property ${coreversion.info.entry.revision}
**
-->
@@ -144,17 +145,17 @@
</target>
<!--
- ** commits the plugin.jar
+ ** commits the plugin.jar
-->
<target name="commit-dist">
<echo>
***** Properties of published ${plugin.jar} *****
- Commit message : '${commit.message}'
+ Commit message : '${commit.message}'
Plugin-Mainversion: ${plugin.main.version}
JOSM build version: ${coreversion.info.entry.revision}
Plugin-Version : ${version.entry.commit.revision}
- ***** / Properties of published ${plugin.jar} *****
-
+ ***** / Properties of published ${plugin.jar} *****
+
Now commiting ${plugin.jar} ...
</echo>
<exec append="true" output="svn.log" executable="svn" failifexecutionfails="true" failonerror="true">
diff --git a/wmsplugin/josm-wmsplugin.launch b/wmsplugin/josm-wmsplugin.launch
index 0b4de4c..4d10a6f 100644
--- a/wmsplugin/josm-wmsplugin.launch
+++ b/wmsplugin/josm-wmsplugin.launch
@@ -6,7 +6,7 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
</listAttribute>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JDK 5"/>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JDK 6"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.openstreetmap.josm.gui.MainApplication"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="wmsplugin"/>
</launchConfiguration>
diff --git a/wmsplugin/sources.cfg b/wmsplugin/sources.cfg
index 89837de..c64ff0a 100644
--- a/wmsplugin/sources.cfg
+++ b/wmsplugin/sources.cfg
@@ -3,6 +3,7 @@
# NOTE: default items should be common and worldwide
#
true;Landsat;http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&layers=global_mosaic&styles=&format=image/jpeg&
+true;Landsat (mirror);http://irs.gis-lab.info/?layers=landsat&
false;Open Aerial Map;http://openaerialmap.org/wms/?VERSION=1.0&request=GetMap&layers=world&styles=&format=image/jpeg&
#
# different forms for web access
@@ -24,7 +25,7 @@ false;Terraserver Urban;http://terraservice.net/ogcmap.ashx?version=1.1.1&reques
#
#
# only for Czech Republic
-false;Czech CUZK:KM;http://wms.cuzk.cz/wms.asp?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&LAYERS=kn,def_budovy,prehledky&FORMAT=image/png&TRANSPARENT=TRUE&
+false;Czech CUZK:KM;http://wms.cuzk.cz/wms.asp?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&LAYERS=parcelni_cisla_i,obrazy_parcel_i,RST_KMD_I,hranice_parcel_i,DEF_BUDOVY,RST_KN_I,dalsi_p_mapy_i,prehledka_kat_prac,prehledka_kat_uz,prehledka_kraju-linie&FORMAT=image/png&transparent=TRUE&
false;Czech UHUL:ORTOFOTO;http://geoportal2.uhul.cz/cgi-bin/oprl.asp?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&LAYERS=Ortofoto_cb&STYLES=default&FORMAT=image/jpeg&TRANSPARENT=TRUE&
#
#
@@ -44,7 +45,8 @@ false;MLIT Japan (ORTHO03);http://orthophoto.mlit.go.jp:8888/wms/service/wmsRast
#
# only for Italy
false;Lodi - Italy;http://sit.provincia.lodi.it/mapserver/mapserv.exe?map=ortofoto_wgs84.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&LAYERS=Terraitaly%20Ortofoto%202007&STYLES=%2C%2C&FORMAT=image/png&TRANSPARENT=TRUE&
-false;Sicily - Italy;http://88.53.214.52/arcgis/services/WGS84_F33/OrtofotoATA_20072008_f33/MapServer/WMSServer?LAYERS=0&REQUEST=GetMap&VERSION=1.1.1&FORMAT=image%2Fpng&STYLES=&
+false;Sicily - Italy;http://88.53.214.52/sitr/services/WGS84_F33/Ortofoto_ATA20072008_f33/MapServer/WMSServer?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=CRS:84&LAYERS=0&STYLES=default&FORMAT=image/jpeg&
+false;PCN 2006 - Italy;http://wms.pcn.minambiente.it/cgi-bin/mapserv.exe?map=/ms_ogc/service/ortofoto_colore_06.map&LAYERS=ortofoto_colore_06_32,ortofoto_colore_06_33&REQUEST=GetMap&VERSION=1.1.1&FORMAT=image%2Fjpeg&
#
#
# URLS must be designed to append arguments directly behind. So the URLS should either end with '?' or '&'
diff --git a/wmsplugin/src/wmsplugin/AddWMSLayerPanel.java b/wmsplugin/src/wmsplugin/AddWMSLayerPanel.java
new file mode 100644
index 0000000..9355b10
--- /dev/null
+++ b/wmsplugin/src/wmsplugin/AddWMSLayerPanel.java
@@ -0,0 +1,507 @@
+package wmsplugin;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.HeadlessException;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.JTree;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.MutableTreeNode;
+import javax.swing.tree.TreePath;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.data.projection.ProjectionSubPrefs;
+import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
+import org.openstreetmap.josm.tools.GBC;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+public class AddWMSLayerPanel extends JPanel {
+ private List<LayerDetails> selectedLayers;
+ private URL serviceUrl;
+ private LayerDetails selectedLayer;
+
+ private JTextField menuName;
+ private JTextArea resultingLayerField;
+ private MutableTreeNode treeRootNode;
+ private DefaultTreeModel treeData;
+ private JTree layerTree;
+ private JButton showBoundsButton;
+
+ private boolean previouslyShownUnsupportedCrsError = false;
+
+ public AddWMSLayerPanel() {
+ JPanel wmsFetchPanel = new JPanel(new GridBagLayout());
+ menuName = new JTextField(40);
+ menuName.setText(tr("Unnamed WMS Layer"));
+ final JTextArea serviceUrl = new JTextArea(3, 40);
+ serviceUrl.setLineWrap(true);
+ serviceUrl.setText("http://sample.com/wms?");
+ wmsFetchPanel.add(new JLabel(tr("Menu Name")), GBC.std().insets(0,0,5,0));
+ wmsFetchPanel.add(menuName, GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+ wmsFetchPanel.add(new JLabel(tr("Service URL")), GBC.std().insets(0,0,5,0));
+ JScrollPane scrollPane = new JScrollPane(serviceUrl,
+ JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+ JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ wmsFetchPanel.add(scrollPane, GBC.eop().insets(5,0,0,0));
+ JButton getLayersButton = new JButton(tr("Get Layers"));
+ getLayersButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Cursor beforeCursor = getCursor();
+ try {
+ setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ attemptGetCapabilities(serviceUrl.getText());
+ } finally {
+ setCursor(beforeCursor);
+ }
+ }
+ });
+ wmsFetchPanel.add(getLayersButton, GBC.eop().anchor(GridBagConstraints.EAST));
+
+ treeRootNode = new DefaultMutableTreeNode();
+ treeData = new DefaultTreeModel(treeRootNode);
+ layerTree = new JTree(treeData);
+ layerTree.setCellRenderer(new LayerTreeCellRenderer());
+ layerTree.addTreeSelectionListener(new TreeSelectionListener() {
+
+ public void valueChanged(TreeSelectionEvent e) {
+ TreePath[] selectionRows = layerTree.getSelectionPaths();
+ if(selectionRows == null) {
+ showBoundsButton.setEnabled(false);
+ selectedLayer = null;
+ return;
+ }
+
+ selectedLayers = new LinkedList<LayerDetails>();
+ for (TreePath i : selectionRows) {
+ Object userObject = ((DefaultMutableTreeNode) i.getLastPathComponent()).getUserObject();
+ if(userObject instanceof LayerDetails) {
+ LayerDetails detail = (LayerDetails) userObject;
+ if(!detail.isSupported()) {
+ layerTree.removeSelectionPath(i);
+ if(!previouslyShownUnsupportedCrsError) {
+ JOptionPane.showMessageDialog(null, tr("That layer does not support any of JOSM's projections,\n" +
+ "so you can not use it. This message will not show again."),
+ tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+ previouslyShownUnsupportedCrsError = true;
+ }
+ } else if(detail.ident != null) {
+ selectedLayers.add(detail);
+ }
+ }
+ }
+
+ if (!selectedLayers.isEmpty()) {
+ resultingLayerField.setText(buildGetMapUrl());
+
+ if(selectedLayers.size() == 1) {
+ showBoundsButton.setEnabled(true);
+ selectedLayer = selectedLayers.get(0);
+ }
+ } else {
+ showBoundsButton.setEnabled(false);
+ selectedLayer = null;
+ }
+ }
+ });
+ wmsFetchPanel.add(new JScrollPane(layerTree), GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+
+ JPanel layerManipulationButtons = new JPanel();
+ showBoundsButton = new JButton(tr("Show Bounds"));
+ showBoundsButton.setEnabled(false);
+ showBoundsButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if(selectedLayer.bounds != null) {
+ SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser();
+ mapPanel.setBoundingBox(selectedLayer.bounds);
+ JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE);
+ } else {
+ JOptionPane.showMessageDialog(null, tr("No bounding box was found for this layer."),
+ tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ });
+ layerManipulationButtons.add(showBoundsButton);
+
+ wmsFetchPanel.add(layerManipulationButtons, GBC.eol().insets(0,0,5,0));
+ wmsFetchPanel.add(new JLabel(tr("WMS URL")), GBC.std().insets(0,0,5,0));
+ resultingLayerField = new JTextArea(3, 40);
+ resultingLayerField.setLineWrap(true);
+ wmsFetchPanel.add(new JScrollPane(resultingLayerField, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+
+ add(wmsFetchPanel);
+ }
+
+ private String buildRootUrl() {
+ StringBuilder a = new StringBuilder(serviceUrl.getProtocol());
+ a.append("://");
+ a.append(serviceUrl.getHost());
+ if(serviceUrl.getPort() != -1) {
+ a.append(":");
+ a.append(serviceUrl.getPort());
+ }
+ a.append(serviceUrl.getPath());
+ a.append("?");
+ if(serviceUrl.getQuery() != null) {
+ a.append(serviceUrl.getQuery());
+ if (!serviceUrl.getQuery().isEmpty() && !serviceUrl.getQuery().endsWith("&")) {
+ a.append("&");
+ }
+ }
+ return a.toString();
+ }
+
+ private String buildGetMapUrl() {
+ StringBuilder a = new StringBuilder();
+ a.append(buildRootUrl());
+ a.append("FORMAT=image/jpeg&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&Layers=");
+ a.append(commaSepLayerList());
+ a.append("&");
+
+ return a.toString();
+ }
+
+ private String commaSepLayerList() {
+ StringBuilder b = new StringBuilder();
+
+ Iterator<LayerDetails> iterator = selectedLayers.iterator();
+ while (iterator.hasNext()) {
+ LayerDetails layerDetails = iterator.next();
+ b.append(layerDetails.ident);
+ if(iterator.hasNext()) {
+ b.append(",");
+ }
+ }
+
+ return b.toString();
+ }
+
+ private void attemptGetCapabilities(String serviceUrlStr) {
+ URL getCapabilitiesUrl = null;
+ try {
+ if (!serviceUrlStr.trim().contains("capabilities")) {
+ // If the url doesn't already have GetCapabilities, add it in
+ getCapabilitiesUrl = new URL(serviceUrlStr + "VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities");
+ } else {
+ // Otherwise assume it's a good URL and let the subsequent error
+ // handling systems deal with problems
+ getCapabilitiesUrl = new URL(serviceUrlStr);
+ }
+ serviceUrl = new URL(serviceUrlStr);
+ } catch (HeadlessException e) {
+ return;
+ } catch (MalformedURLException e) {
+ JOptionPane.showMessageDialog(this, tr("Invalid service URL."),
+ tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ System.out.println("Connecting to: " + getCapabilitiesUrl);
+
+ String incomingData;
+ try {
+ URLConnection openConnection = getCapabilitiesUrl.openConnection();
+ InputStream inputStream = openConnection.getInputStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
+ String line;
+ StringBuilder ba = new StringBuilder();
+ while((line = br.readLine()) != null) {
+ ba.append(line);
+ ba.append("\n");
+ }
+ incomingData = ba.toString();
+ } catch (IOException e) {
+ JOptionPane.showMessageDialog(this, tr("Could not retrieve WMS layer list."),
+ tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ System.out.println(incomingData);
+
+ Document document;
+ try {
+ DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+ builderFactory.setValidating(false);
+ builderFactory.setNamespaceAware(true);
+ DocumentBuilder builder = builderFactory.newDocumentBuilder();
+ builder.setEntityResolver(new EntityResolver() {
+ public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
+ System.out.println("Ignoring DTD " + publicId + ", " + systemId);
+ return new InputSource(new StringReader(""));
+ }
+ });
+ document = builder.parse(new InputSource(new StringReader(incomingData)));
+ } catch (ParserConfigurationException e) {
+ JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."),
+ tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+ return;
+ } catch (SAXException e) {
+ JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."),
+ tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+ return;
+ } catch (IOException e) {
+ JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."),
+ tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ try {
+ treeRootNode.setUserObject(getCapabilitiesUrl.getHost());
+ Element capabilityElem = getChild(document.getDocumentElement(), "Capability");
+ List<Element> children = getChildren(capabilityElem, "Layer");
+ List<LayerDetails> layers = parseLayers(children, new HashSet<String>());
+ updateTreeList(layers);
+ } catch(Exception e) {
+ JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."),
+ tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+ e.printStackTrace();
+ return;
+ }
+ }
+
+ private void updateTreeList(List<LayerDetails> layers) {
+ addLayersToTreeData(treeRootNode, layers);
+ layerTree.expandRow(0);
+ }
+
+ private void addLayersToTreeData(MutableTreeNode parent, List<LayerDetails> layers) {
+ for (LayerDetails layerDetails : layers) {
+ DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(layerDetails);
+ addLayersToTreeData(treeNode, layerDetails.children);
+ treeData.insertNodeInto(treeNode, parent, 0);
+ }
+ }
+
+ private List<LayerDetails> parseLayers(List<Element> children, Set<String> parentCrs) {
+ List<LayerDetails> details = new LinkedList<LayerDetails>();
+ for (Element element : children) {
+ details.add(parseLayer(element, parentCrs));
+ }
+ return details;
+ }
+
+ private LayerDetails parseLayer(Element element, Set<String> parentCrs) {
+ String name = getChildContent(element, "Title", null, null);
+ String ident = getChildContent(element, "Name", null, null);
+
+ // The set of supported CRS/SRS for this layer
+ Set<String> crsList = new HashSet<String>();
+ // ...including this layer's already-parsed parent projections
+ crsList.addAll(parentCrs);
+
+ // Parse the CRS/SRS pulled out of this layer's XML element
+ // I think CRS and SRS are the same at this point
+ List<Element> crsChildren = getChildren(element, "CRS");
+ crsChildren.addAll(getChildren(element, "SRS"));
+ for (Element child : crsChildren) {
+ String crs = (String) getContent(child);
+ if(crs != null) {
+ String upperCase = crs.trim().toUpperCase();
+ crsList.add(upperCase);
+ }
+ }
+
+ // Check to see if any of the specified projections are supported by JOSM
+ boolean josmSupportsThisLayer = false;
+ for (String crs : crsList) {
+ josmSupportsThisLayer |= isProjSupported(crs);
+ }
+
+ Bounds bounds = null;
+ Element bboxElem = getChild(element, "EX_GeographicBoundingBox");
+ if(bboxElem != null) {
+ // Attempt to use EX_GeographicBoundingBox for bounding box
+ double left = Double.parseDouble(getChildContent(bboxElem, "westBoundLongitude", null, null));
+ double top = Double.parseDouble(getChildContent(bboxElem, "northBoundLatitude", null, null));
+ double right = Double.parseDouble(getChildContent(bboxElem, "eastBoundLongitude", null, null));
+ double bot = Double.parseDouble(getChildContent(bboxElem, "southBoundLatitude", null, null));
+ bounds = new Bounds(bot, left, top, right);
+ } else {
+ // If that's not available, try LatLonBoundingBox
+ bboxElem = getChild(element, "LatLonBoundingBox");
+ if(bboxElem != null) {
+ double left = Double.parseDouble(bboxElem.getAttribute("minx"));
+ double top = Double.parseDouble(bboxElem.getAttribute("maxy"));
+ double right = Double.parseDouble(bboxElem.getAttribute("maxx"));
+ double bot = Double.parseDouble(bboxElem.getAttribute("miny"));
+ bounds = new Bounds(bot, left, top, right);
+ }
+ }
+
+ List<Element> layerChildren = getChildren(element, "Layer");
+ List<LayerDetails> childLayers = parseLayers(layerChildren, crsList);
+
+ return new LayerDetails(name, ident, crsList, josmSupportsThisLayer, bounds, childLayers);
+ }
+
+ private boolean isProjSupported(String crs) {
+ for (Projection proj : Projection.allProjections) {
+ if (proj instanceof ProjectionSubPrefs) {
+ if (((ProjectionSubPrefs) proj).getPreferencesFromCode(crs) == null) {
+ return true;
+ }
+ } else {
+ if (proj.toCode().equals(crs)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public String getUrlName() {
+ return menuName.getText();
+ }
+
+ public String getUrl() {
+ return resultingLayerField.getText();
+ }
+
+ public static void main(String[] args) {
+ JFrame f = new JFrame("Test");
+ f.setContentPane(new AddWMSLayerPanel());
+ f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ f.pack();
+ f.setVisible(true);
+ }
+
+ private static String getChildContent(Element parent, String name, String missing, String empty) {
+ Element child = getChild(parent, name);
+ if (child == null) {
+ return missing;
+ } else {
+ String content = (String) getContent(child);
+ return (content != null) ? content : empty;
+ }
+ }
+
+ private static Object getContent(Element element) {
+ NodeList nl = element.getChildNodes();
+ StringBuffer content = new StringBuffer();
+ for (int i = 0; i < nl.getLength(); i++) {
+ Node node = nl.item(i);
+ switch (node.getNodeType()) {
+ case Node.ELEMENT_NODE:
+ return node;
+ case Node.CDATA_SECTION_NODE:
+ case Node.TEXT_NODE:
+ content.append(node.getNodeValue());
+ break;
+ }
+ }
+ return content.toString().trim();
+ }
+
+ private static List<Element> getChildren(Element parent, String name) {
+ List<Element> retVal = new LinkedList<Element>();
+ for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
+ if (child instanceof Element && name.equals(child.getNodeName())) {
+ retVal.add((Element) child);
+ }
+ }
+ return retVal;
+ }
+
+ private static Element getChild(Element parent, String name) {
+ for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
+ if (child instanceof Element && name.equals(child.getNodeName())) {
+ return (Element) child;
+ }
+ }
+ return null;
+ }
+
+ class LayerDetails {
+
+ private String name;
+ private String ident;
+ private Set<String> crsList;
+ private List<LayerDetails> children;
+ private Bounds bounds;
+ private boolean supported;
+
+ public LayerDetails(String name, String ident, Set<String> crsList,
+ boolean supportedLayer, Bounds bounds,
+ List<LayerDetails> childLayers) {
+ this.name = name;
+ this.ident = ident;
+ this.crsList = crsList;
+ this.supported = supportedLayer;
+ this.children = childLayers;
+ this.bounds = bounds;
+ }
+
+ public boolean isSupported() {
+ return this.supported;
+ }
+
+ @Override
+ public String toString() {
+ if(this.name == null || this.name.isEmpty()) {
+ return this.ident;
+ } else {
+ return this.name;
+ }
+ }
+
+ }
+
+ class LayerTreeCellRenderer extends DefaultTreeCellRenderer {
+ @Override
+ public Component getTreeCellRendererComponent(JTree tree, Object value,
+ boolean sel, boolean expanded, boolean leaf, int row,
+ boolean hasFocus) {
+ super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
+ row, hasFocus);
+ DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
+ Object userObject = treeNode.getUserObject();
+ if (userObject instanceof LayerDetails) {
+ LayerDetails layer = (LayerDetails) userObject;
+ setEnabled(layer.isSupported());
+ }
+ return this;
+ }
+ }
+
+}
diff --git a/wmsplugin/src/wmsplugin/GeorefImage.java b/wmsplugin/src/wmsplugin/GeorefImage.java
index 7a41243..1245ff0 100644
--- a/wmsplugin/src/wmsplugin/GeorefImage.java
+++ b/wmsplugin/src/wmsplugin/GeorefImage.java
@@ -1,87 +1,136 @@
package wmsplugin;
-import java.awt.Dimension;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
-import java.awt.Point;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.lang.ref.SoftReference;
import javax.imageio.ImageIO;
-import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.coor.EastNorth;
import org.openstreetmap.josm.gui.NavigatableComponent;
public class GeorefImage implements Serializable {
- public BufferedImage image = null;
- private Image reImg = null;
- private Dimension reImgHash = new Dimension(0, 0);
- public EastNorth min, max;
- public boolean downloadingStarted;
- public boolean failed = false;
- public boolean infotext = false;
+ private static final long serialVersionUID = 1L;
+
+ public enum State { IMAGE, NOT_IN_CACHE, FAILED};
+
+ private WMSLayer layer;
+ private State state;
+
+ private BufferedImage image;
+ private SoftReference<BufferedImage> reImg;
+ private int xIndex;
+ private int yIndex;
+
- public GeorefImage(boolean downloadingStarted) {
- this.downloadingStarted = downloadingStarted;
+ public EastNorth getMin() {
+ return layer.getEastNorth(xIndex, yIndex);
}
- public boolean contains(EastNorth en, double dx, double dy) {
- return min.east()+dx <= en.east() && en.east() <= max.east()+dx
- && min.north()+dy <= en.north() && en.north() <= max.north()+dy;
+ public EastNorth getMax() {
+ return layer.getEastNorth(xIndex+1, yIndex+1);
}
- public boolean isVisible(NavigatableComponent nc, double dx, double dy) {
- EastNorth mi = new EastNorth(min.east()+dx, min.north()+dy);
- EastNorth ma = new EastNorth(max.east()+dx, max.north()+dy);
- Point minPt = nc.getPoint(mi), maxPt = nc.getPoint(ma);
- Graphics g = nc.getGraphics();
- return (g.hitClip(minPt.x, maxPt.y,
- maxPt.x - minPt.x, minPt.y - maxPt.y));
+ public GeorefImage(WMSLayer layer) {
+ this.layer = layer;
}
- public boolean paint(Graphics g, NavigatableComponent nc, double dx, double dy) {
- if (image == null || min == null || max == null) return false;
+ public void changePosition(int xIndex, int yIndex) {
+ if (!equalPosition(xIndex, yIndex)) {
+ this.xIndex = xIndex;
+ this.yIndex = yIndex;
+ this.image = null;
+ flushedResizedCachedInstance();
+ }
+ }
+
+ public boolean equalPosition(int xIndex, int yIndex) {
+ return this.xIndex == xIndex && this.yIndex == yIndex;
+ }
- EastNorth mi = new EastNorth(min.east()+dx, min.north()+dy);
- EastNorth ma = new EastNorth(max.east()+dx, max.north()+dy);
- Point minPt = nc.getPoint(mi), maxPt = nc.getPoint(ma);
+ public void changeImage(State state, BufferedImage image) {
+ flushedResizedCachedInstance();
+ this.image = image;
+ this.state = state;
+
+ switch (state) {
+ case FAILED:
+ {
+ BufferedImage img = createImage();
+ Graphics g = img.getGraphics();
+ g.setColor(Color.RED);
+ g.fillRect(0, 0, img.getWidth(), img.getHeight());
+ g.setFont(g.getFont().deriveFont(Font.PLAIN).deriveFont(36.0f));
+ g.setColor(Color.BLACK);
+ g.drawString(tr("Exception occurred"), 10, img.getHeight()/2);
+ this.image = img;
+ break;
+ }
+ case NOT_IN_CACHE:
+ {
+ BufferedImage img = createImage();
+ Graphics g = img.getGraphics();
+ g.setColor(Color.GRAY);
+ g.fillRect(0, 0, img.getWidth(), img.getHeight());
+ Font font = g.getFont();
+ Font tempFont = font.deriveFont(Font.PLAIN).deriveFont(36.0f);
+ g.setFont(tempFont);
+ g.setColor(Color.BLACK);
+ g.drawString(tr("Not in cache"), 10, img.getHeight()/2);
+ g.setFont(font);
+ this.image = img;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ private BufferedImage createImage() {
+ return new BufferedImage(layer.getBaseImageWidth(), layer.getBaseImageHeight(), BufferedImage.TYPE_INT_RGB);
+ }
+
+ public boolean paint(Graphics g, NavigatableComponent nc, int xIndex, int yIndex, int leftEdge, int bottomEdge) {
+ if (image == null)
+ return false;
- if(!isVisible(nc, dx, dy)){
+ if(!(this.xIndex == xIndex && this.yIndex == yIndex)){
return false;
}
- // Width and height flicker about 2 pixels due to rounding errors, typically only 1
- int width = Math.abs(maxPt.x-minPt.x);
- int height = Math.abs(minPt.y-maxPt.y);
- int diffx, diffy;
+ int left = layer.getImageX(xIndex);
+ int bottom = layer.getImageY(yIndex);
+ int width = layer.getImageWidth(xIndex);
+ int height = layer.getImageHeight(yIndex);
+
+ int x = left - leftEdge;
+ int y = nc.getHeight() - (bottom - bottomEdge) - height;
- diffx = reImgHash.width - width;
- diffy = reImgHash.height - height;
// This happens if you zoom outside the world
if(width == 0 || height == 0)
return false;
- // We still need to re-render if the requested size is larger (otherwise we'll have black lines)
- // If it's only up to two pixels smaller, just draw the old image, the errors are minimal
- // but the performance improvements when moving are huge
- // Zooming is still slow because the images need to be resized
- if(diffx >= 0 && diffx <= 2 && diffy >= 0 && diffy <= 2 && reImg != null) {
- /*g.setColor(Color.RED);
- g.drawRect(minPt.x, minPt.y-height, width, height);*/
- g.drawImage(reImg, minPt.x, maxPt.y, null);
+ BufferedImage img = reImg == null?null:reImg.get();
+ if(img != null && img.getWidth() == width && img.getHeight() == height) {
+ g.drawImage(img, x, y, null);
return true;
}
- boolean alphaChannel = Main.pref.getBoolean("wmsplugin.alpha_channel") && image.getTransparency() != Transparency.OPAQUE;
+ boolean alphaChannel = WMSLayer.PROP_ALPHA_CHANNEL.get() && getImage().getTransparency() != Transparency.OPAQUE;
try {
- if(reImg != null) reImg.flush();
+ if(img != null) img.flush();
long freeMem = Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory();
//System.out.println("Free Memory: "+ (freeMem/1024/1024) +" MB");
// Notice that this value can get negative due to integer overflows
@@ -93,44 +142,37 @@ public class GeorefImage implements Serializable {
// traditional rendering is as fast at these zoom levels, so it's no loss.
// Also prevent caching if we're out of memory soon
if(width > 2000 || height > 2000 || width*height*multipl > freeMem) {
- fallbackDraw(g, image, minPt, maxPt);
+ fallbackDraw(g, getImage(), x, y, width, height);
} else {
// We haven't got a saved resized copy, so resize and cache it
- reImg = new BufferedImage(width, height, alphaChannel?BufferedImage.TYPE_INT_ARGB:BufferedImage.TYPE_3BYTE_BGR);
- reImg.getGraphics().drawImage(image,
+ img = new BufferedImage(width, height, alphaChannel?BufferedImage.TYPE_INT_ARGB:BufferedImage.TYPE_3BYTE_BGR);
+ img.getGraphics().drawImage(getImage(),
0, 0, width, height, // dest
- 0, 0, image.getWidth(null), image.getHeight(null), // src
+ 0, 0, getImage().getWidth(null), getImage().getHeight(null), // src
null);
- reImg.getGraphics().dispose();
-
- reImgHash.setSize(width, height);
- /*g.setColor(Color.RED);
- g.drawRect(minPt.x, minPt.y-height, width, height);*/
- g.drawImage(reImg, minPt.x, maxPt.y, null);
+ img.getGraphics().dispose();
+ g.drawImage(img, x, y, null);
+ reImg = new SoftReference<BufferedImage>(img);
}
} catch(Exception e) {
- fallbackDraw(g, image, minPt, maxPt);
+ fallbackDraw(g, getImage(), x, y, width, height);
}
return true;
}
- private void fallbackDraw(Graphics g, Image img, Point min, Point max) {
- if(reImg != null) {
- reImg.flush();
- reImg = null;
- }
- g.drawImage(img,
- min.x, max.y, max.x, min.y, // dest
- 0, 0, img.getWidth(null), img.getHeight(null), // src
+ private void fallbackDraw(Graphics g, Image img, int x, int y, int width, int height) {
+ flushedResizedCachedInstance();
+ g.drawImage(
+ img, x, y, x + width, y + height,
+ 0, 0, img.getWidth(null), img.getHeight(null),
null);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
- max = (EastNorth) in.readObject();
- min = (EastNorth) in.readObject();
+ state = (State) in.readObject();
boolean hasImage = in.readBoolean();
if (hasImage)
- image = ImageIO.read(ImageIO.createImageInputStream(in));
+ image = (ImageIO.read(ImageIO.createImageInputStream(in)));
else {
in.readObject(); // read null from input stream
image = null;
@@ -138,18 +180,44 @@ public class GeorefImage implements Serializable {
}
private void writeObject(ObjectOutputStream out) throws IOException {
- out.writeObject(max);
- out.writeObject(min);
- if(image == null) {
+ out.writeObject(state);
+ if(getImage() == null) {
out.writeBoolean(false);
out.writeObject(null);
} else {
out.writeBoolean(true);
- ImageIO.write(image, "png", ImageIO.createImageOutputStream(out));
+ ImageIO.write(getImage(), "png", ImageIO.createImageOutputStream(out));
}
}
public void flushedResizedCachedInstance() {
+ if (reImg != null) {
+ BufferedImage img = reImg.get();
+ if (img != null) {
+ img.flush();
+ }
+ }
reImg = null;
}
+
+
+ public BufferedImage getImage() {
+ return image;
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public int getXIndex() {
+ return xIndex;
+ }
+
+ public int getYIndex() {
+ return yIndex;
+ }
+
+ public void setLayer(WMSLayer layer) {
+ this.layer = layer;
+ }
}
diff --git a/wmsplugin/src/wmsplugin/Grabber.java b/wmsplugin/src/wmsplugin/Grabber.java
index 54a30c8..c225370 100644
--- a/wmsplugin/src/wmsplugin/Grabber.java
+++ b/wmsplugin/src/wmsplugin/Grabber.java
@@ -1,12 +1,5 @@
package wmsplugin;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics;
-import java.awt.image.BufferedImage;
-
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.ProjectionBounds;
import org.openstreetmap.josm.data.coor.EastNorth;
@@ -14,104 +7,109 @@ import org.openstreetmap.josm.data.projection.Projection;
import org.openstreetmap.josm.gui.MapView;
import org.openstreetmap.josm.io.CacheFiles;
-abstract public class Grabber extends Thread {
- protected ProjectionBounds b;
- protected Projection proj;
- protected double pixelPerDegree;
- protected MapView mv;
- protected WMSLayer layer;
- protected GeorefImage image;
- protected CacheFiles cache;
-
- Grabber(ProjectionBounds b, GeorefImage image, MapView mv, WMSLayer layer, CacheFiles cache)
- {
- if (b.min != null && b.max != null && WMSPlugin.doOverlap) {
- double eastSize = b.max.east() - b.min.east();
- double northSize = b.max.north() - b.min.north();
-
- double eastCoef = WMSPlugin.overlapEast / 100.0;
- double northCoef = WMSPlugin.overlapNorth / 100.0;
-
- this.b = new ProjectionBounds( new EastNorth(b.min.east(),
- b.min.north()),
- new EastNorth(b.max.east() + eastCoef * eastSize,
- b.max.north() + northCoef * northSize));
- } else
- this.b = b;
-
- this.proj = Main.proj;
- this.pixelPerDegree = layer.pixelPerDegree;
- this.image = image;
- this.mv = mv;
- this.layer = layer;
- this.cache = cache;
-
- }
-
- abstract void fetch() throws Exception; // the image fetch code
-
- int width(){
- return (int) ((b.max.north() - b.min.north()) * pixelPerDegree);
- }
- int height(){
- return (int) ((b.max.east() - b.min.east()) * pixelPerDegree);
- }
-
- protected void grabError(Exception e){ // report error when grabing image
- e.printStackTrace();
-
- BufferedImage img = new BufferedImage(width(), height(), BufferedImage.TYPE_INT_ARGB);
- Graphics g = img.getGraphics();
- g.setColor(Color.RED);
- g.fillRect(0, 0, width(), height());
- Font font = g.getFont();
- Font tempFont = font.deriveFont(Font.PLAIN).deriveFont(36.0f);
- g.setFont(tempFont);
- g.setColor(Color.BLACK);
- g.drawString(tr("Exception occurred"), 10, height()/2);
- image.image = img;
- image.flushedResizedCachedInstance();
- image.failed = true;
- image.downloadingStarted = false;
- g.setFont(font);
- }
-
- protected void grabNotInCache(){ // report not in cache
- BufferedImage img = new BufferedImage(width(), height(), BufferedImage.TYPE_INT_ARGB);
- Graphics g = img.getGraphics();
- g.setColor(Color.GRAY);
- g.fillRect(0, 0, width(), height());
- Font font = g.getFont();
- Font tempFont = font.deriveFont(Font.PLAIN).deriveFont(36.0f);
- g.setFont(tempFont);
- g.setColor(Color.BLACK);
- g.drawString(tr("Not in cache"), 10, height()/2);
- image.image = img;
- image.flushedResizedCachedInstance();
- image.infotext = true;
- image.downloadingStarted = false;
- g.setFont(font);
- }
-
- protected void attempt(){ // try to fetch the image
- int maxTries = 5; // n tries for every image
- for (int i = 1; i <= maxTries; i++) {
- try {
- fetch();
- break; // break out of the retry loop
- } catch (Exception e) {
- try { // sleep some time and then ask the server again
- Thread.sleep(random(1000, 2000));
- } catch (InterruptedException e1) {}
-
- if(i == maxTries) grabError(e);
- }
- }
- }
-
- public static int random(int min, int max) {
- return (int)(Math.random() * ((max+1)-min) ) + min;
- }
-
- abstract public boolean loadFromCache(boolean real);
+import wmsplugin.GeorefImage.State;
+
+abstract public class Grabber implements Runnable {
+ protected final MapView mv;
+ protected final WMSLayer layer;
+ protected final CacheFiles cache;
+
+ protected ProjectionBounds b;
+ protected Projection proj;
+ protected double pixelPerDegree;
+ protected WMSRequest request;
+ protected volatile boolean canceled;
+
+ Grabber(MapView mv, WMSLayer layer, CacheFiles cache) {
+ this.mv = mv;
+ this.layer = layer;
+ this.cache = cache;
+ }
+
+ private void updateState(WMSRequest request) {
+ b = new ProjectionBounds(
+ layer.getEastNorth(request.getXIndex(), request.getYIndex()),
+ layer.getEastNorth(request.getXIndex() + 1, request.getYIndex() + 1));
+ if (b.min != null && b.max != null && WMSPlugin.PROP_OVERLAP.get()) {
+ double eastSize = b.max.east() - b.min.east();
+ double northSize = b.max.north() - b.min.north();
+
+ double eastCoef = WMSPlugin.PROP_OVERLAP_EAST.get() / 100.0;
+ double northCoef = WMSPlugin.PROP_OVERLAP_NORTH.get() / 100.0;
+
+ this.b = new ProjectionBounds( new EastNorth(b.min.east(),
+ b.min.north()),
+ new EastNorth(b.max.east() + eastCoef * eastSize,
+ b.max.north() + northCoef * northSize));
+ }
+
+ this.proj = Main.proj;
+ this.pixelPerDegree = request.getPixelPerDegree();
+ this.request = request;
+ }
+
+ abstract void fetch(WMSRequest request) throws Exception; // the image fetch code
+
+ int width(){
+ return layer.getBaseImageWidth();
+ }
+ int height(){
+ return layer.getBaseImageHeight();
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ if (canceled) {
+ return;
+ }
+ WMSRequest request = layer.getRequest();
+ if (request == null) {
+ return;
+ }
+ updateState(request);
+ if(!loadFromCache(request)){
+ attempt(request);
+ }
+ if (request.getState() != null) {
+ layer.finishRequest(request);
+ mv.repaint();
+ }
+ }
+ }
+
+ protected void attempt(WMSRequest request){ // try to fetch the image
+ int maxTries = 5; // n tries for every image
+ for (int i = 1; i <= maxTries; i++) {
+ if (canceled) {
+ return;
+ }
+ try {
+ if (!layer.requestIsValid(request)) {
+ return;
+ }
+ fetch(request);
+ break; // break out of the retry loop
+ } catch (Exception e) {
+ try { // sleep some time and then ask the server again
+ Thread.sleep(random(1000, 2000));
+ } catch (InterruptedException e1) {}
+
+ if(i == maxTries) {
+ e.printStackTrace();
+ request.finish(State.FAILED, null);
+ }
+ }
+ }
+ }
+
+ public static int random(int min, int max) {
+ return (int)(Math.random() * ((max+1)-min) ) + min;
+ }
+
+ abstract public boolean loadFromCache(WMSRequest request);
+
+ public void cancel() {
+ canceled = true;
+ }
}
diff --git a/wmsplugin/src/wmsplugin/HTMLGrabber.java b/wmsplugin/src/wmsplugin/HTMLGrabber.java
index 5cc5789..ec5e8d5 100644
--- a/wmsplugin/src/wmsplugin/HTMLGrabber.java
+++ b/wmsplugin/src/wmsplugin/HTMLGrabber.java
@@ -10,39 +10,38 @@ import java.util.StringTokenizer;
import javax.imageio.ImageIO;
import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.ProjectionBounds;
import org.openstreetmap.josm.gui.MapView;
import org.openstreetmap.josm.io.CacheFiles;
public class HTMLGrabber extends WMSGrabber {
- HTMLGrabber(ProjectionBounds b, GeorefImage image, MapView mv, WMSLayer layer, CacheFiles cache) {
- super(b, image, mv, layer, cache);
- this.baseURL = layer.baseURL.replaceFirst("html:", "");
- }
-
- @Override
- protected BufferedImage grab(URL url) throws IOException {
- String urlstring = url.toExternalForm();
-
- System.out.println("Grabbing HTML " + url);
-
- ArrayList<String> cmdParams = new ArrayList<String>();
- StringTokenizer st = new StringTokenizer(MessageFormat.format(
- Main.pref.get("wmsplugin.browser", "webkit-image {0}"), urlstring));
- while( st.hasMoreTokens() )
- cmdParams.add(st.nextToken());
-
- ProcessBuilder builder = new ProcessBuilder( cmdParams);
-
- Process browser;
- try {
- browser = builder.start();
- } catch(IOException ioe) {
- throw new IOException( "Could not start browser. Please check that the executable path is correct.\n" + ioe.getMessage() );
- }
-
- BufferedImage img = ImageIO.read(browser.getInputStream());
- cache.saveImg(urlstring, img);
- return img;
- }
+ HTMLGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
+ super(mv, layer, cache);
+ this.baseURL = layer.baseURL.replaceFirst("html:", "");
+ }
+
+ @Override
+ protected BufferedImage grab(URL url) throws IOException {
+ String urlstring = url.toExternalForm();
+
+ System.out.println("Grabbing HTML " + url);
+
+ ArrayList<String> cmdParams = new ArrayList<String>();
+ StringTokenizer st = new StringTokenizer(MessageFormat.format(
+ Main.pref.get("wmsplugin.browser", "webkit-image {0}"), urlstring));
+ while( st.hasMoreTokens() )
+ cmdParams.add(st.nextToken());
+
+ ProcessBuilder builder = new ProcessBuilder( cmdParams);
+
+ Process browser;
+ try {
+ browser = builder.start();
+ } catch(IOException ioe) {
+ throw new IOException( "Could not start browser. Please check that the executable path is correct.\n" + ioe.getMessage() );
+ }
+
+ BufferedImage img = ImageIO.read(browser.getInputStream());
+ cache.saveImg(urlstring, img);
+ return img;
+ }
}
diff --git a/wmsplugin/src/wmsplugin/Map_Rectifier_WMSmenuAction.java b/wmsplugin/src/wmsplugin/Map_Rectifier_WMSmenuAction.java
index a034a90..b3cf66d 100644
--- a/wmsplugin/src/wmsplugin/Map_Rectifier_WMSmenuAction.java
+++ b/wmsplugin/src/wmsplugin/Map_Rectifier_WMSmenuAction.java
@@ -28,220 +28,220 @@ import org.openstreetmap.josm.tools.Shortcut;
import org.openstreetmap.josm.tools.UrlLabel;
public class Map_Rectifier_WMSmenuAction extends JosmAction {
- /**
- * Class that bundles all required information of a rectifier service
- */
- public static class RectifierService {
- private final String name;
- private final String url;
- private final String wmsUrl;
- private final Pattern urlRegEx;
- private final Pattern idValidator;
- public JRadioButton btn;
- /**
- * @param name: Name of the rectifing service
- * @param url: URL to the service where users can register, upload, etc.
- * @param wmsUrl: URL to the WMS server where JOSM will grab the images. Insert __s__ where the ID should be placed
- * @param urlRegEx: a regular expression that determines if a given URL is one of the service and returns the WMS id if so
- * @param idValidator: regular expression that checks if a given ID is syntactically valid
- */
- public RectifierService(String name, String url, String wmsUrl, String urlRegEx, String idValidator) {
- this.name = name;
- this.url = url;
- this.wmsUrl = wmsUrl;
- this.urlRegEx = Pattern.compile(urlRegEx);
- this.idValidator = Pattern.compile(idValidator);
- }
-
- public boolean isSelected() {
- return btn.isSelected();
- }
- }
-
- /**
- * List of available rectifier services. May be extended from the outside
- */
- public ArrayList<RectifierService> services = new ArrayList<RectifierService>();
-
- public Map_Rectifier_WMSmenuAction() {
- super(tr("Rectified Image..."),
- "OLmarker",
- tr("Download Rectified Images From Various Services"),
- Shortcut.registerShortcut("wms:rectimg",
- tr("WMS: {0}", tr("Rectified Image...")),
- KeyEvent.VK_R,
- Shortcut.GROUP_NONE),
- true
- );
-
- // Add default services
- services.add(
- new RectifierService("Metacarta Map Rectifier",
- "http://labs.metacarta.com/rectifier/",
- "http://labs.metacarta.com/rectifier/wms.cgi?id=__s__&srs=EPSG:4326"
- + "&Service=WMS&Version=1.1.0&Request=GetMap&format=image/png&",
- // This matches more than the "classic" WMS link, so users can pretty much
- // copy any link as long as it includes the ID
- "labs\\.metacarta\\.com/(?:.*?)(?:/|=)([0-9]+)(?:\\?|/|\\.|$)",
- "^[0-9]+$")
- );
- services.add(
- // TODO: Change all links to mapwarper.net once the project has moved.
- // The RegEx already matches the new URL and old URLs will be forwarded
- // to make the transition as smooth as possible for the users
- new RectifierService("Geothings Map Warper",
- "http://warper.geothings.net/",
- "http://warper.geothings.net/maps/wms/__s__?request=GetMap&version=1.1.1"
- + "&styles=&format=image/png&srs=epsg:4326&exceptions=application/vnd.ogc.se_inimage&",
- // This matches more than the "classic" WMS link, so users can pretty much
- // copy any link as long as it includes the ID
- "(?:mapwarper\\.net|warper\\.geothings\\.net)/(?:.*?)/([0-9]+)(?:\\?|/|\\.|$)",
- "^[0-9]+$")
- );
-
- // This service serves the purpose of "just this once" without forcing the user
- // to commit the link to the preferences
-
- // Clipboard content gets trimmed, so matching whitespace only ensures that this
- // service will never be selected automatically.
- services.add(new RectifierService(tr("Custom WMS Link"), "", "", "^\\s+$", ""));
- }
-
- public void actionPerformed(ActionEvent e) {
- JPanel panel = new JPanel(new GridBagLayout());
- panel.add(new JLabel(tr("Supported Rectifier Services:")), GBC.eol());
-
- JTextField tfWmsUrl = new JTextField(30);
-
- String clip = getClipboardContents();
- ButtonGroup group = new ButtonGroup();
-
- JRadioButton firstBtn = null;
- for(RectifierService s : services) {
- JRadioButton serviceBtn = new JRadioButton(s.name);
- if(firstBtn == null)
- firstBtn = serviceBtn;
- // Checks clipboard contents against current service if no match has been found yet.
- // If the contents match, they will be inserted into the text field and the corresponding
- // service will be pre-selected.
- if(!clip.equals("") && tfWmsUrl.getText().equals("")
- && (s.urlRegEx.matcher(clip).find() || s.idValidator.matcher(clip).matches())) {
- serviceBtn.setSelected(true);
- tfWmsUrl.setText(clip);
- }
- s.btn = serviceBtn;
- group.add(serviceBtn);
- if(!s.url.equals("")) {
- panel.add(serviceBtn, GBC.std());
- panel.add(new UrlLabel(s.url, tr("Visit Homepage")), GBC.eol().anchor(GridBagConstraints.EAST));
- } else
- panel.add(serviceBtn, GBC.eol().anchor(GridBagConstraints.WEST));
- }
-
- // Fallback in case no match was found
- if(tfWmsUrl.getText().equals("") && firstBtn != null)
- firstBtn.setSelected(true);
-
- panel.add(new JLabel(tr("WMS URL or Image ID:")), GBC.eol());
- panel.add(tfWmsUrl, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
-
- ExtendedDialog diag = new ExtendedDialog(Main.parent,
- tr("Add Rectified Image"),
-
- new String[] {tr("Add Rectified Image"), tr("Cancel")});
- diag.setContent(panel);
- diag.setButtonIcons(new String[] {"OLmarker.png", "cancel.png"});
-
- // This repeatedly shows the dialog in case there has been an error.
- // The loop is break;-ed if the users cancels
- outer: while(true) {
- diag.showDialog();
- int answer = diag.getValue();
- // Break loop when the user cancels
- if(answer != 1)
- break;
-
- String text = tfWmsUrl.getText().trim();
- // Loop all services until we find the selected one
- for(RectifierService s : services) {
- if(!s.isSelected())
- continue;
-
- // We've reached the custom WMS URL service
- // Just set the URL and hope everything works out
- if(s.wmsUrl.equals("")) {
- addWMSLayer(s.name + " (" + text + ")", text);
- break outer;
- }
-
- // First try to match if the entered string as an URL
- Matcher m = s.urlRegEx.matcher(text);
- if(m.find()) {
- String id = m.group(1);
- String newURL = s.wmsUrl.replaceAll("__s__", id);
- String title = s.name + " (" + id + ")";
- addWMSLayer(title, newURL);
- break outer;
- }
- // If not, look if it's a valid ID for the selected service
- if(s.idValidator.matcher(text).matches()) {
- String newURL = s.wmsUrl.replaceAll("__s__", text);
- String title = s.name + " (" + text + ")";
- addWMSLayer(title, newURL);
- break outer;
- }
-
- // We've found the selected service, but the entered string isn't suitable for
- // it. So quit checking the other radio buttons
- break;
- }
-
- // and display an error message. The while(true) ensures that the dialog pops up again
- JOptionPane.showMessageDialog(Main.parent,
- tr("Couldn't match the entered link or id to the selected service. Please try again."),
- tr("No valid WMS URL or id"),
- JOptionPane.ERROR_MESSAGE);
- diag.setVisible(true);
- }
- }
-
- /**
- * Adds a WMS Layer with given title and URL
- * @param title: Name of the layer as it will shop up in the layer manager
- * @param url: URL to the WMS server
- * @param cookies: Cookies to send with each image request (Format: josm=is; very=cool)
- */
- private void addWMSLayer(String title, String url, String cookies) {
- WMSLayer wmsLayer = new WMSLayer(title, url, cookies);
- Main.main.addLayer(wmsLayer);
- }
-
- /**
- * Adds a WMS Layer with given title and URL
- * @param title: Name of the layer as it will shop up in the layer manager
- * @param url: URL to the WMS server
- */
- private void addWMSLayer(String title, String url) {
- addWMSLayer(title, url, "");
- }
-
- /**
- * Helper function that extracts a String from the Clipboard if available.
- * Returns an empty String otherwise
- * @return String Clipboard contents if available
- */
- private String getClipboardContents() {
- String result = "";
- Transferable contents = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
-
- if(contents == null || !contents.isDataFlavorSupported(DataFlavor.stringFlavor))
- return "";
-
- try {
- result = (String)contents.getTransferData(DataFlavor.stringFlavor);
- } catch(Exception ex) {
- return "";
- }
- return result.trim();
- }
+ /**
+ * Class that bundles all required information of a rectifier service
+ */
+ public static class RectifierService {
+ private final String name;
+ private final String url;
+ private final String wmsUrl;
+ private final Pattern urlRegEx;
+ private final Pattern idValidator;
+ public JRadioButton btn;
+ /**
+ * @param name: Name of the rectifing service
+ * @param url: URL to the service where users can register, upload, etc.
+ * @param wmsUrl: URL to the WMS server where JOSM will grab the images. Insert __s__ where the ID should be placed
+ * @param urlRegEx: a regular expression that determines if a given URL is one of the service and returns the WMS id if so
+ * @param idValidator: regular expression that checks if a given ID is syntactically valid
+ */
+ public RectifierService(String name, String url, String wmsUrl, String urlRegEx, String idValidator) {
+ this.name = name;
+ this.url = url;
+ this.wmsUrl = wmsUrl;
+ this.urlRegEx = Pattern.compile(urlRegEx);
+ this.idValidator = Pattern.compile(idValidator);
+ }
+
+ public boolean isSelected() {
+ return btn.isSelected();
+ }
+ }
+
+ /**
+ * List of available rectifier services. May be extended from the outside
+ */
+ public ArrayList<RectifierService> services = new ArrayList<RectifierService>();
+
+ public Map_Rectifier_WMSmenuAction() {
+ super(tr("Rectified Image..."),
+ "OLmarker",
+ tr("Download Rectified Images From Various Services"),
+ Shortcut.registerShortcut("wms:rectimg",
+ tr("WMS: {0}", tr("Rectified Image...")),
+ KeyEvent.VK_R,
+ Shortcut.GROUP_NONE),
+ true
+ );
+
+ // Add default services
+ services.add(
+ new RectifierService("Metacarta Map Rectifier",
+ "http://labs.metacarta.com/rectifier/",
+ "http://labs.metacarta.com/rectifier/wms.cgi?id=__s__&srs=EPSG:4326"
+ + "&Service=WMS&Version=1.1.0&Request=GetMap&format=image/png&",
+ // This matches more than the "classic" WMS link, so users can pretty much
+ // copy any link as long as it includes the ID
+ "labs\\.metacarta\\.com/(?:.*?)(?:/|=)([0-9]+)(?:\\?|/|\\.|$)",
+ "^[0-9]+$")
+ );
+ services.add(
+ // TODO: Change all links to mapwarper.net once the project has moved.
+ // The RegEx already matches the new URL and old URLs will be forwarded
+ // to make the transition as smooth as possible for the users
+ new RectifierService("Geothings Map Warper",
+ "http://warper.geothings.net/",
+ "http://warper.geothings.net/maps/wms/__s__?request=GetMap&version=1.1.1"
+ + "&styles=&format=image/png&srs=epsg:4326&exceptions=application/vnd.ogc.se_inimage&",
+ // This matches more than the "classic" WMS link, so users can pretty much
+ // copy any link as long as it includes the ID
+ "(?:mapwarper\\.net|warper\\.geothings\\.net)/(?:.*?)/([0-9]+)(?:\\?|/|\\.|$)",
+ "^[0-9]+$")
+ );
+
+ // This service serves the purpose of "just this once" without forcing the user
+ // to commit the link to the preferences
+
+ // Clipboard content gets trimmed, so matching whitespace only ensures that this
+ // service will never be selected automatically.
+ services.add(new RectifierService(tr("Custom WMS Link"), "", "", "^\\s+$", ""));
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ JPanel panel = new JPanel(new GridBagLayout());
+ panel.add(new JLabel(tr("Supported Rectifier Services:")), GBC.eol());
+
+ JTextField tfWmsUrl = new JTextField(30);
+
+ String clip = getClipboardContents();
+ ButtonGroup group = new ButtonGroup();
+
+ JRadioButton firstBtn = null;
+ for(RectifierService s : services) {
+ JRadioButton serviceBtn = new JRadioButton(s.name);
+ if(firstBtn == null)
+ firstBtn = serviceBtn;
+ // Checks clipboard contents against current service if no match has been found yet.
+ // If the contents match, they will be inserted into the text field and the corresponding
+ // service will be pre-selected.
+ if(!clip.equals("") && tfWmsUrl.getText().equals("")
+ && (s.urlRegEx.matcher(clip).find() || s.idValidator.matcher(clip).matches())) {
+ serviceBtn.setSelected(true);
+ tfWmsUrl.setText(clip);
+ }
+ s.btn = serviceBtn;
+ group.add(serviceBtn);
+ if(!s.url.equals("")) {
+ panel.add(serviceBtn, GBC.std());
+ panel.add(new UrlLabel(s.url, tr("Visit Homepage")), GBC.eol().anchor(GridBagConstraints.EAST));
+ } else
+ panel.add(serviceBtn, GBC.eol().anchor(GridBagConstraints.WEST));
+ }
+
+ // Fallback in case no match was found
+ if(tfWmsUrl.getText().equals("") && firstBtn != null)
+ firstBtn.setSelected(true);
+
+ panel.add(new JLabel(tr("WMS URL or Image ID:")), GBC.eol());
+ panel.add(tfWmsUrl, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
+
+ ExtendedDialog diag = new ExtendedDialog(Main.parent,
+ tr("Add Rectified Image"),
+
+ new String[] {tr("Add Rectified Image"), tr("Cancel")});
+ diag.setContent(panel);
+ diag.setButtonIcons(new String[] {"OLmarker.png", "cancel.png"});
+
+ // This repeatedly shows the dialog in case there has been an error.
+ // The loop is break;-ed if the users cancels
+ outer: while(true) {
+ diag.showDialog();
+ int answer = diag.getValue();
+ // Break loop when the user cancels
+ if(answer != 1)
+ break;
+
+ String text = tfWmsUrl.getText().trim();
+ // Loop all services until we find the selected one
+ for(RectifierService s : services) {
+ if(!s.isSelected())
+ continue;
+
+ // We've reached the custom WMS URL service
+ // Just set the URL and hope everything works out
+ if(s.wmsUrl.equals("")) {
+ addWMSLayer(s.name + " (" + text + ")", text);
+ break outer;
+ }
+
+ // First try to match if the entered string as an URL
+ Matcher m = s.urlRegEx.matcher(text);
+ if(m.find()) {
+ String id = m.group(1);
+ String newURL = s.wmsUrl.replaceAll("__s__", id);
+ String title = s.name + " (" + id + ")";
+ addWMSLayer(title, newURL);
+ break outer;
+ }
+ // If not, look if it's a valid ID for the selected service
+ if(s.idValidator.matcher(text).matches()) {
+ String newURL = s.wmsUrl.replaceAll("__s__", text);
+ String title = s.name + " (" + text + ")";
+ addWMSLayer(title, newURL);
+ break outer;
+ }
+
+ // We've found the selected service, but the entered string isn't suitable for
+ // it. So quit checking the other radio buttons
+ break;
+ }
+
+ // and display an error message. The while(true) ensures that the dialog pops up again
+ JOptionPane.showMessageDialog(Main.parent,
+ tr("Couldn't match the entered link or id to the selected service. Please try again."),
+ tr("No valid WMS URL or id"),
+ JOptionPane.ERROR_MESSAGE);
+ diag.setVisible(true);
+ }
+ }
+
+ /**
+ * Adds a WMS Layer with given title and URL
+ * @param title: Name of the layer as it will shop up in the layer manager
+ * @param url: URL to the WMS server
+ * @param cookies: Cookies to send with each image request (Format: josm=is; very=cool)
+ */
+ private void addWMSLayer(String title, String url, String cookies) {
+ WMSLayer wmsLayer = new WMSLayer(title, url, cookies);
+ Main.main.addLayer(wmsLayer);
+ }
+
+ /**
+ * Adds a WMS Layer with given title and URL
+ * @param title: Name of the layer as it will shop up in the layer manager
+ * @param url: URL to the WMS server
+ */
+ private void addWMSLayer(String title, String url) {
+ addWMSLayer(title, url, "");
+ }
+
+ /**
+ * Helper function that extracts a String from the Clipboard if available.
+ * Returns an empty String otherwise
+ * @return String Clipboard contents if available
+ */
+ private String getClipboardContents() {
+ String result = "";
+ Transferable contents = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
+
+ if(contents == null || !contents.isDataFlavorSupported(DataFlavor.stringFlavor))
+ return "";
+
+ try {
+ result = (String)contents.getTransferData(DataFlavor.stringFlavor);
+ } catch(Exception ex) {
+ return "";
+ }
+ return result.trim();
+ }
}
diff --git a/wmsplugin/src/wmsplugin/WMSAdjustAction.java b/wmsplugin/src/wmsplugin/WMSAdjustAction.java
index 7a6576c..4ed12d9 100644
--- a/wmsplugin/src/wmsplugin/WMSAdjustAction.java
+++ b/wmsplugin/src/wmsplugin/WMSAdjustAction.java
@@ -30,189 +30,187 @@ import org.openstreetmap.josm.tools.ImageProvider;
public class WMSAdjustAction extends MapMode implements MouseListener, MouseMotionListener{
- //static private final Logger logger = Logger.getLogger(WMSAdjustAction.class.getName());
-
- GeorefImage selectedImage;
- boolean mouseDown;
- EastNorth prevEastNorth;
- private WMSLayer adjustingLayer;
-
- public WMSAdjustAction(MapFrame mapFrame) {
- super(tr("Adjust WMS"), "adjustwms",
- tr("Adjust the position of the selected WMS layer"), mapFrame,
- ImageProvider.getCursor("normal", "move"));
- }
-
-
-
- @Override public void enterMode() {
- super.enterMode();
- if (!hasWMSLayersToAdjust()) {
- warnNoWMSLayers();
- return;
- }
- List<WMSLayer> wmsLayers = Main.map.mapView.getLayersOfType(WMSLayer.class);
- if (wmsLayers.size() == 1) {
- adjustingLayer = wmsLayers.get(0);
- } else {
- adjustingLayer = (WMSLayer)askAdjustLayer(Main.map.mapView.getLayersOfType(WMSLayer.class));
- }
- if (adjustingLayer == null)
- return;
- if (!adjustingLayer.isVisible()) {
- adjustingLayer.setVisible(true);
- }
- Main.map.mapView.addMouseListener(this);
- Main.map.mapView.addMouseMotionListener(this);
- }
-
- @Override public void exitMode() {
- super.exitMode();
- Main.map.mapView.removeMouseListener(this);
- Main.map.mapView.removeMouseMotionListener(this);
- adjustingLayer = null;
- }
-
- @Override public void mousePressed(MouseEvent e) {
- if (e.getButton() != MouseEvent.BUTTON1)
- return;
-
- if (adjustingLayer.isVisible()) {
- prevEastNorth=Main.map.mapView.getEastNorth(e.getX(),e.getY());
- selectedImage = adjustingLayer.findImage(prevEastNorth);
- if(selectedImage!=null) {
- Main.map.mapView.setCursor
- (Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
- }
- }
- }
-
- @Override public void mouseDragged(MouseEvent e) {
- if(selectedImage!=null) {
- EastNorth eastNorth=
- Main.map.mapView.getEastNorth(e.getX(),e.getY());
- adjustingLayer.displace(
- eastNorth.east()-prevEastNorth.east(),
- eastNorth.north()-prevEastNorth.north()
- );
- prevEastNorth = eastNorth;
- Main.map.mapView.repaint();
- }
- }
-
- @Override public void mouseReleased(MouseEvent e) {
- Main.map.mapView.repaint();
- Main.map.mapView.setCursor(Cursor.getDefaultCursor());
- selectedImage = null;
- prevEastNorth = null;
- }
-
- @Override
- public void mouseEntered(MouseEvent e) {
- }
-
- @Override
- public void mouseExited(MouseEvent e) {
- }
-
- @Override
- public void mouseMoved(MouseEvent e) {
- }
-
- @Override public void mouseClicked(MouseEvent e) {
- }
-
- // This only makes the buttons look disabled, but since no keyboard shortcut is
- // provided there aren't any other means to activate this tool
- @Override public boolean layerIsSupported(Layer l) {
- return (l instanceof WMSLayer) && l.isVisible();
- }
-
- /**
- * the list cell renderer used to render layer list entries
- *
- */
- static public class LayerListCellRenderer extends DefaultListCellRenderer {
-
- protected boolean isActiveLayer(Layer layer) {
- if (Main.map == null)
- return false;
- if (Main.map.mapView == null)
- return false;
- return Main.map.mapView.getActiveLayer() == layer;
- }
-
- @Override
- public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
- boolean cellHasFocus) {
- Layer layer = (Layer) value;
- JLabel label = (JLabel) super.getListCellRendererComponent(list, layer.getName(), index, isSelected,
- cellHasFocus);
- Icon icon = layer.getIcon();
- label.setIcon(icon);
- label.setToolTipText(layer.getToolTipText());
- return label;
- }
- }
-
- /**
- * Prompts the user with a list of WMS layers which can be adjusted
- *
- * @param adjustableLayers the list of adjustable layers
- * @return the selected layer; null, if no layer was selected
- */
- protected Layer askAdjustLayer(List<? extends Layer> adjustableLayers) {
- JComboBox layerList = new JComboBox();
- layerList.setRenderer(new LayerListCellRenderer());
- layerList.setModel(new DefaultComboBoxModel(adjustableLayers.toArray()));
- layerList.setSelectedIndex(0);
-
- JPanel pnl = new JPanel();
- pnl.setLayout(new GridBagLayout());
- pnl.add(new JLabel(tr("Please select the WMS layer to adjust.")), GBC.eol());
- pnl.add(layerList, GBC.eol());
-
- ExtendedDialog diag = new ExtendedDialog(
- Main.parent,
- tr("Select WMS layer"),
- new String[] { tr("Start adjusting"),tr("Cancel") }
- );
- diag.setContent(pnl);
- diag.setButtonIcons(new String[] { "mapmode/adjustwms", "cancel" });
- diag.showDialog();
- int decision = diag.getValue();
- if (decision != 1)
- return null;
- Layer adjustLayer = (Layer) layerList.getSelectedItem();
- return adjustLayer;
- }
-
- /**
- * Displays a warning message if there are no WMS layers to adjust
- *
- */
- protected void warnNoWMSLayers() {
- JOptionPane.showMessageDialog(
- Main.parent,
- tr("There are currently no WMS layer to adjust."),
- tr("No layers to adjust"),
- JOptionPane.WARNING_MESSAGE
- );
- }
-
- /**
- * Replies true if there is at least one WMS layer
- *
- * @return true if there is at least one WMS layer
- */
- protected boolean hasWMSLayersToAdjust() {
- if (Main.map == null) return false;
- if (Main.map.mapView == null) return false;
- return ! Main.map.mapView.getLayersOfType(WMSLayer.class).isEmpty();
- }
-
- @Override
- protected void updateEnabledState() {
- setEnabled(hasWMSLayersToAdjust());
- }
+ //static private final Logger logger = Logger.getLogger(WMSAdjustAction.class.getName());
+
+ GeorefImage selectedImage;
+ boolean mouseDown;
+ EastNorth prevEastNorth;
+ private WMSLayer adjustingLayer;
+
+ public WMSAdjustAction(MapFrame mapFrame) {
+ super(tr("Adjust WMS"), "adjustwms",
+ tr("Adjust the position of the selected WMS layer"), mapFrame,
+ ImageProvider.getCursor("normal", "move"));
+ }
+
+
+
+ @Override public void enterMode() {
+ super.enterMode();
+ if (!hasWMSLayersToAdjust()) {
+ warnNoWMSLayers();
+ return;
+ }
+ List<WMSLayer> wmsLayers = Main.map.mapView.getLayersOfType(WMSLayer.class);
+ if (wmsLayers.size() == 1) {
+ adjustingLayer = wmsLayers.get(0);
+ } else {
+ adjustingLayer = (WMSLayer)askAdjustLayer(Main.map.mapView.getLayersOfType(WMSLayer.class));
+ }
+ if (adjustingLayer == null)
+ return;
+ if (!adjustingLayer.isVisible()) {
+ adjustingLayer.setVisible(true);
+ }
+ Main.map.mapView.addMouseListener(this);
+ Main.map.mapView.addMouseMotionListener(this);
+ }
+
+ @Override public void exitMode() {
+ super.exitMode();
+ Main.map.mapView.removeMouseListener(this);
+ Main.map.mapView.removeMouseMotionListener(this);
+ adjustingLayer = null;
+ }
+
+ @Override public void mousePressed(MouseEvent e) {
+ if (e.getButton() != MouseEvent.BUTTON1)
+ return;
+
+ if (adjustingLayer.isVisible()) {
+ prevEastNorth=Main.map.mapView.getEastNorth(e.getX(),e.getY());
+ selectedImage = adjustingLayer.findImage(prevEastNorth);
+ if(selectedImage!=null) {
+ Main.map.mapView.setCursor
+ (Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+ }
+ }
+ }
+
+ @Override public void mouseDragged(MouseEvent e) {
+ if(selectedImage!=null) {
+ EastNorth eastNorth=
+ Main.map.mapView.getEastNorth(e.getX(),e.getY());
+ adjustingLayer.displace(
+ eastNorth.east()-prevEastNorth.east(),
+ eastNorth.north()-prevEastNorth.north()
+ );
+ prevEastNorth = eastNorth;
+ Main.map.mapView.repaint();
+ }
+ }
+
+ @Override public void mouseReleased(MouseEvent e) {
+ Main.map.mapView.repaint();
+ Main.map.mapView.setCursor(Cursor.getDefaultCursor());
+ selectedImage = null;
+ prevEastNorth = null;
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseMoved(MouseEvent e) {
+ }
+
+ @Override public void mouseClicked(MouseEvent e) {
+ }
+
+ @Override public boolean layerIsSupported(Layer l) {
+ return hasWMSLayersToAdjust();
+ }
+
+ /**
+ * the list cell renderer used to render layer list entries
+ *
+ */
+ static public class LayerListCellRenderer extends DefaultListCellRenderer {
+
+ protected boolean isActiveLayer(Layer layer) {
+ if (Main.map == null)
+ return false;
+ if (Main.map.mapView == null)
+ return false;
+ return Main.map.mapView.getActiveLayer() == layer;
+ }
+
+ @Override
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+ boolean cellHasFocus) {
+ Layer layer = (Layer) value;
+ JLabel label = (JLabel) super.getListCellRendererComponent(list, layer.getName(), index, isSelected,
+ cellHasFocus);
+ Icon icon = layer.getIcon();
+ label.setIcon(icon);
+ label.setToolTipText(layer.getToolTipText());
+ return label;
+ }
+ }
+
+ /**
+ * Prompts the user with a list of WMS layers which can be adjusted
+ *
+ * @param adjustableLayers the list of adjustable layers
+ * @return the selected layer; null, if no layer was selected
+ */
+ protected Layer askAdjustLayer(List<? extends Layer> adjustableLayers) {
+ JComboBox layerList = new JComboBox();
+ layerList.setRenderer(new LayerListCellRenderer());
+ layerList.setModel(new DefaultComboBoxModel(adjustableLayers.toArray()));
+ layerList.setSelectedIndex(0);
+
+ JPanel pnl = new JPanel();
+ pnl.setLayout(new GridBagLayout());
+ pnl.add(new JLabel(tr("Please select the WMS layer to adjust.")), GBC.eol());
+ pnl.add(layerList, GBC.eol());
+
+ ExtendedDialog diag = new ExtendedDialog(
+ Main.parent,
+ tr("Select WMS layer"),
+ new String[] { tr("Start adjusting"),tr("Cancel") }
+ );
+ diag.setContent(pnl);
+ diag.setButtonIcons(new String[] { "mapmode/adjustwms", "cancel" });
+ diag.showDialog();
+ int decision = diag.getValue();
+ if (decision != 1)
+ return null;
+ Layer adjustLayer = (Layer) layerList.getSelectedItem();
+ return adjustLayer;
+ }
+
+ /**
+ * Displays a warning message if there are no WMS layers to adjust
+ *
+ */
+ protected void warnNoWMSLayers() {
+ JOptionPane.showMessageDialog(
+ Main.parent,
+ tr("There are currently no WMS layer to adjust."),
+ tr("No layers to adjust"),
+ JOptionPane.WARNING_MESSAGE
+ );
+ }
+
+ /**
+ * Replies true if there is at least one WMS layer
+ *
+ * @return true if there is at least one WMS layer
+ */
+ protected boolean hasWMSLayersToAdjust() {
+ if (Main.map == null) return false;
+ if (Main.map.mapView == null) return false;
+ return ! Main.map.mapView.getLayersOfType(WMSLayer.class).isEmpty();
+ }
+
+ @Override
+ protected void updateEnabledState() {
+ setEnabled(hasWMSLayersToAdjust());
+ }
}
diff --git a/wmsplugin/src/wmsplugin/WMSDownloadAction.java b/wmsplugin/src/wmsplugin/WMSDownloadAction.java
index f7eff50..e1f807d 100644
--- a/wmsplugin/src/wmsplugin/WMSDownloadAction.java
+++ b/wmsplugin/src/wmsplugin/WMSDownloadAction.java
@@ -9,25 +9,25 @@ import org.openstreetmap.josm.actions.JosmAction;
public class WMSDownloadAction extends JosmAction {
- private final WMSInfo info;
-
- public WMSDownloadAction(WMSInfo info) {
- super(info.name, "wmsmenu", tr("Download WMS tile from {0}",info.name), null, false);
- putValue("toolbar", "wms_" + info.name);
- this.info = info;
- }
-
- public void actionPerformed(ActionEvent e) {
- //System.out.println(info.url);
-
- WMSLayer wmsLayer = new WMSLayer(info.name, info.url, info.cookies);
- Main.main.addLayer(wmsLayer);
- }
-
- public static WMSLayer getLayer(WMSInfo info) {
- // FIXME: move this to WMSPlugin/WMSInfo/preferences.
- WMSLayer wmsLayer = new WMSLayer(info.name, info.url, info.cookies);
- Main.main.addLayer(wmsLayer);
- return wmsLayer;
- }
+ private final WMSInfo info;
+
+ public WMSDownloadAction(WMSInfo info) {
+ super(info.name, "wmsmenu", tr("Download WMS tile from {0}",info.name), null, false);
+ putValue("toolbar", "wms_" + info.name);
+ this.info = info;
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ //System.out.println(info.url);
+
+ WMSLayer wmsLayer = new WMSLayer(info.name, info.url, info.cookies);
+ Main.main.addLayer(wmsLayer);
+ }
+
+ public static WMSLayer getLayer(WMSInfo info) {
+ // FIXME: move this to WMSPlugin/WMSInfo/preferences.
+ WMSLayer wmsLayer = new WMSLayer(info.name, info.url, info.cookies);
+ Main.main.addLayer(wmsLayer);
+ return wmsLayer;
+ }
};
diff --git a/wmsplugin/src/wmsplugin/WMSGrabber.java b/wmsplugin/src/wmsplugin/WMSGrabber.java
index 098f494..4ef6f40 100644
--- a/wmsplugin/src/wmsplugin/WMSGrabber.java
+++ b/wmsplugin/src/wmsplugin/WMSGrabber.java
@@ -22,199 +22,183 @@ import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.ProjectionBounds;
+import org.openstreetmap.josm.data.Version;
import org.openstreetmap.josm.data.coor.EastNorth;
import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.projection.Mercator;
-import org.openstreetmap.josm.data.Version;
import org.openstreetmap.josm.gui.MapView;
import org.openstreetmap.josm.io.CacheFiles;
import org.openstreetmap.josm.io.OsmTransferException;
import org.openstreetmap.josm.io.ProgressInputStream;
+import wmsplugin.GeorefImage.State;
+
public class WMSGrabber extends Grabber {
- public static boolean isUrlWithPatterns(String url) {
- return url != null && url.contains("{") && url.contains("}");
- }
-
- protected String baseURL;
- private final boolean urlWithPatterns;
-
- WMSGrabber(ProjectionBounds b, GeorefImage image, MapView mv, WMSLayer layer, CacheFiles cache) {
- super(b, image, mv, layer, cache);
- this.baseURL = layer.baseURL;
- /* URL containing placeholders? */
- urlWithPatterns = isUrlWithPatterns(baseURL);
- }
-
- @Override
- public void run() {
- attempt();
- mv.repaint();
- }
-
- @Override
- void fetch() throws Exception{
- URL url = null;
- try {
- url = getURL(
- b.min.east(), b.min.north(),
- b.max.east(), b.max.north(),
- width(), height());
-
- image.min = b.min;
- image.max = b.max;
-
- if(image.isVisible(mv, layer.getDx(), layer.getDy())) { //don't download, if the image isn't visible already
- image.image = grab(url);
- image.flushedResizedCachedInstance();
- }
- image.downloadingStarted = false;
- } catch(Exception e) {
- e.printStackTrace();
- throw new Exception(e.getMessage() + "\nImage couldn't be fetched: " + (url != null ? url.toString() : ""));
- }
- }
-
- public static final NumberFormat latLonFormat = new DecimalFormat("###0.0000000",
- new DecimalFormatSymbols(Locale.US));
-
- protected URL getURL(double w, double s,double e,double n,
- int wi, int ht) throws MalformedURLException {
- String myProj = Main.proj.toCode();
- if(Main.proj instanceof Mercator) // don't use mercator code directly
- {
- LatLon sw = Main.proj.eastNorth2latlon(new EastNorth(w, s));
- LatLon ne = Main.proj.eastNorth2latlon(new EastNorth(e, n));
- myProj = "EPSG:4326";
- s = sw.lat();
- w = sw.lon();
- n = ne.lat();
- e = ne.lon();
- }
-
- String str = baseURL;
- String bbox = latLonFormat.format(w) + ","
- + latLonFormat.format(s) + ","
- + latLonFormat.format(e) + ","
- + latLonFormat.format(n);
-
- if (urlWithPatterns) {
- str = str.replaceAll("\\{proj\\}", myProj)
- .replaceAll("\\{bbox\\}", bbox)
- .replaceAll("\\{w\\}", latLonFormat.format(w))
- .replaceAll("\\{s\\}", latLonFormat.format(s))
- .replaceAll("\\{e\\}", latLonFormat.format(e))
- .replaceAll("\\{n\\}", latLonFormat.format(n))
- .replaceAll("\\{width\\}", String.valueOf(wi))
- .replaceAll("\\{height\\}", String.valueOf(ht));
- } else {
- str += "bbox=" + bbox
- + getProjection(baseURL, false)
- + "&width=" + wi + "&height=" + ht;
- if (!(baseURL.endsWith("&") || baseURL.endsWith("?"))) {
- System.out.println(tr("Warning: The base URL ''{0}'' for a WMS service doesn't have a trailing '&' or a trailing '?'.", baseURL));
- System.out.println(tr("Warning: Fetching WMS tiles is likely to fail. Please check you preference settings."));
- System.out.println(tr("Warning: The complete URL is ''{0}''.", str));
- }
- }
- return new URL(str.replace(" ", "%20"));
- }
-
- static public String getProjection(String baseURL, Boolean warn)
- {
- String projname = Main.proj.toCode();
- if(Main.proj instanceof Mercator) // don't use mercator code
- projname = "EPSG:4326";
- String res = "";
- try
- {
- Matcher m = Pattern.compile(".*srs=([a-z0-9:]+).*").matcher(baseURL.toLowerCase());
- if(m.matches())
- {
- projname = projname.toLowerCase();
- if(!projname.equals(m.group(1)) && warn)
- {
- JOptionPane.showMessageDialog(Main.parent,
- tr("The projection ''{0}'' in URL and current projection ''{1}'' mismatch.\n"
- + "This may lead to wrong coordinates.",
- m.group(1), projname),
- tr("Warning"),
- JOptionPane.WARNING_MESSAGE);
- }
- }
- else
- res ="&srs="+projname;
- }
- catch(Exception e)
- {
- }
- return res;
- }
-
- @Override
- public boolean loadFromCache(boolean real){
- URL url = null;
- try{
- url = getURL(
- b.min.east(), b.min.north(),
- b.max.east(), b.max.north(),
- width(), height());
- } catch(Exception e) {
- return false;
- }
- BufferedImage cached = cache.getImg(url.toString());
- if((!real && !layer.hasAutoDownload()) || cached != null){
- image.min = b.min;
- image.max = b.max;
- if(cached == null){
- grabNotInCache();
- return true;
- }
- image.image = cached;
- image.flushedResizedCachedInstance();
- image.downloadingStarted = false;
- return true;
- }
- return false;
- }
-
- protected BufferedImage grab(URL url) throws IOException, OsmTransferException {
- System.out.println("Grabbing WMS " + url);
-
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- if(layer.cookies != null && !layer.cookies.equals(""))
- conn.setRequestProperty("Cookie", layer.cookies);
- conn.setRequestProperty("User-Agent", Main.pref.get("wmsplugin.user_agent", Version.getInstance().getAgentString()));
- conn.setConnectTimeout(Main.pref.getInteger("wmsplugin.timeout.connect", 30) * 1000);
- conn.setReadTimeout(Main.pref.getInteger("wmsplugin.timeout.read", 30) * 1000);
-
- String contentType = conn.getHeaderField("Content-Type");
- if( conn.getResponseCode() != 200
- || contentType != null && !contentType.startsWith("image") ) {
- throw new IOException(readException(conn));
- }
-
- InputStream is = new ProgressInputStream(conn, null);
- BufferedImage img = ImageIO.read(is);
- is.close();
-
- cache.saveImg(url.toString(), img);
- return img;
- }
-
- protected String readException(URLConnection conn) throws IOException {
- StringBuilder exception = new StringBuilder();
- InputStream in = conn.getInputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(in));
-
- String line = null;
- while( (line = br.readLine()) != null) {
- // filter non-ASCII characters and control characters
- exception.append(line.replaceAll("[^\\p{Print}]", ""));
- exception.append('\n');
- }
- return exception.toString();
- }
+ public static boolean isUrlWithPatterns(String url) {
+ return url != null && url.contains("{") && url.contains("}");
+ }
+
+ protected String baseURL;
+ private final boolean urlWithPatterns;
+
+ WMSGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
+ super(mv, layer, cache);
+ this.baseURL = layer.baseURL;
+ /* URL containing placeholders? */
+ urlWithPatterns = isUrlWithPatterns(baseURL);
+ }
+
+ @Override
+ void fetch(WMSRequest request) throws Exception{
+ URL url = null;
+ try {
+ url = getURL(
+ b.min.east(), b.min.north(),
+ b.max.east(), b.max.north(),
+ width(), height());
+ request.finish(State.IMAGE, grab(url));
+
+ } catch(Exception e) {
+ e.printStackTrace();
+ throw new Exception(e.getMessage() + "\nImage couldn't be fetched: " + (url != null ? url.toString() : ""));
+ }
+ }
+
+ public static final NumberFormat latLonFormat = new DecimalFormat("###0.0000000",
+ new DecimalFormatSymbols(Locale.US));
+
+ protected URL getURL(double w, double s,double e,double n,
+ int wi, int ht) throws MalformedURLException {
+ String myProj = Main.proj.toCode();
+ if(Main.proj instanceof Mercator) // don't use mercator code directly
+ {
+ LatLon sw = Main.proj.eastNorth2latlon(new EastNorth(w, s));
+ LatLon ne = Main.proj.eastNorth2latlon(new EastNorth(e, n));
+ myProj = "EPSG:4326";
+ s = sw.lat();
+ w = sw.lon();
+ n = ne.lat();
+ e = ne.lon();
+ }
+
+ String str = baseURL;
+ String bbox = latLonFormat.format(w) + ","
+ + latLonFormat.format(s) + ","
+ + latLonFormat.format(e) + ","
+ + latLonFormat.format(n);
+
+ if (urlWithPatterns) {
+ str = str.replaceAll("\\{proj\\}", myProj)
+ .replaceAll("\\{bbox\\}", bbox)
+ .replaceAll("\\{w\\}", latLonFormat.format(w))
+ .replaceAll("\\{s\\}", latLonFormat.format(s))
+ .replaceAll("\\{e\\}", latLonFormat.format(e))
+ .replaceAll("\\{n\\}", latLonFormat.format(n))
+ .replaceAll("\\{width\\}", String.valueOf(wi))
+ .replaceAll("\\{height\\}", String.valueOf(ht));
+ } else {
+ str += "bbox=" + bbox
+ + getProjection(baseURL, false)
+ + "&width=" + wi + "&height=" + ht;
+ if (!(baseURL.endsWith("&") || baseURL.endsWith("?"))) {
+ System.out.println(tr("Warning: The base URL ''{0}'' for a WMS service doesn't have a trailing '&' or a trailing '?'.", baseURL));
+ System.out.println(tr("Warning: Fetching WMS tiles is likely to fail. Please check you preference settings."));
+ System.out.println(tr("Warning: The complete URL is ''{0}''.", str));
+ }
+ }
+ return new URL(str.replace(" ", "%20"));
+ }
+
+ static public String getProjection(String baseURL, Boolean warn)
+ {
+ String projname = Main.proj.toCode();
+ if(Main.proj instanceof Mercator) // don't use mercator code
+ projname = "EPSG:4326";
+ String res = "";
+ try
+ {
+ Matcher m = Pattern.compile(".*srs=([a-z0-9:]+).*").matcher(baseURL.toLowerCase());
+ if(m.matches())
+ {
+ projname = projname.toLowerCase();
+ if(!projname.equals(m.group(1)) && warn)
+ {
+ JOptionPane.showMessageDialog(Main.parent,
+ tr("The projection ''{0}'' in URL and current projection ''{1}'' mismatch.\n"
+ + "This may lead to wrong coordinates.",
+ m.group(1), projname),
+ tr("Warning"),
+ JOptionPane.WARNING_MESSAGE);
+ }
+ }
+ else
+ res ="&srs="+projname;
+ }
+ catch(Exception e)
+ {
+ }
+ return res;
+ }
+
+ @Override
+ public boolean loadFromCache(WMSRequest request) {
+ URL url = null;
+ try{
+ url = getURL(
+ b.min.east(), b.min.north(),
+ b.max.east(), b.max.north(),
+ width(), height());
+ } catch(Exception e) {
+ return false;
+ }
+ BufferedImage cached = cache.getImg(url.toString());
+ if((!request.isReal() && !layer.hasAutoDownload()) || cached != null){
+ if(cached == null){
+ request.finish(State.NOT_IN_CACHE, null);
+ return true;
+ }
+ request.finish(State.IMAGE, cached);
+ return true;
+ }
+ return false;
+ }
+
+ protected BufferedImage grab(URL url) throws IOException, OsmTransferException {
+ System.out.println("Grabbing WMS " + url);
+
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ if(layer.cookies != null && !layer.cookies.equals(""))
+ conn.setRequestProperty("Cookie", layer.cookies);
+ conn.setRequestProperty("User-Agent", Main.pref.get("wmsplugin.user_agent", Version.getInstance().getAgentString()));
+ conn.setConnectTimeout(Main.pref.getInteger("wmsplugin.timeout.connect", 30) * 1000);
+ conn.setReadTimeout(Main.pref.getInteger("wmsplugin.timeout.read", 30) * 1000);
+
+ String contentType = conn.getHeaderField("Content-Type");
+ if( conn.getResponseCode() != 200
+ || contentType != null && !contentType.startsWith("image") ) {
+ throw new IOException(readException(conn));
+ }
+
+ InputStream is = new ProgressInputStream(conn, null);
+ BufferedImage img = ImageIO.read(is);
+ is.close();
+
+ cache.saveImg(url.toString(), img);
+ return img;
+ }
+
+ protected String readException(URLConnection conn) throws IOException {
+ StringBuilder exception = new StringBuilder();
+ InputStream in = conn.getInputStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
+
+ String line = null;
+ while( (line = br.readLine()) != null) {
+ // filter non-ASCII characters and control characters
+ exception.append(line.replaceAll("[^\\p{Print}]", ""));
+ exception.append('\n');
+ }
+ return exception.toString();
+ }
}
diff --git a/wmsplugin/src/wmsplugin/WMSLayer.java b/wmsplugin/src/wmsplugin/WMSLayer.java
index 1e67263..2d1cf9e 100644
--- a/wmsplugin/src/wmsplugin/WMSLayer.java
+++ b/wmsplugin/src/wmsplugin/WMSLayer.java
@@ -12,484 +12,806 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import javax.swing.AbstractAction;
+import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
-import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
-import javax.swing.JSeparator;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.DiskAccessAction;
import org.openstreetmap.josm.actions.SaveActionBase;
import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
+import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
import org.openstreetmap.josm.data.ProjectionBounds;
import org.openstreetmap.josm.data.coor.EastNorth;
import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
+import org.openstreetmap.josm.data.preferences.BooleanProperty;
import org.openstreetmap.josm.gui.MapView;
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.io.CacheFiles;
import org.openstreetmap.josm.tools.ImageProvider;
-import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
-import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
+
+import wmsplugin.GeorefImage.State;
/**
* This is a layer that grabs the current screen from an WMS server. The data
* fetched this way is tiled and managed to the disc to reduce server load.
*/
public class WMSLayer extends Layer implements PreferenceChangedListener {
- protected static final Icon icon =
- new ImageIcon(Toolkit.getDefaultToolkit().createImage(WMSPlugin.class.getResource("/images/wms_small.png")));
-
- public int messageNum = 5; //limit for messages per layer
- protected MapView mv;
- protected String resolution;
- protected boolean stopAfterPaint = false;
- protected int imageSize = 500;
- protected int dax = 10;
- protected int day = 10;
- protected int minZoom = 3;
- protected double dx = 0.0;
- protected double dy = 0.0;
- protected double pixelPerDegree;
- protected GeorefImage[][] images = new GeorefImage[dax][day];
- JCheckBoxMenuItem startstop = new JCheckBoxMenuItem(tr("Automatic downloading"), true);
- protected JCheckBoxMenuItem alphaChannel = new JCheckBoxMenuItem(new ToggleAlphaAction());
- protected String baseURL;
- protected String cookies;
- protected final int serializeFormatVersion = 5;
-
- private ExecutorService executor = null;
-
- /** set to true if this layer uses an invalid base url */
- private boolean usesInvalidUrl = false;
- /** set to true if the user confirmed to use an potentially invalid WMS base url */
- private boolean isInvalidUrlConfirmed = false;
-
- public WMSLayer() {
- this(tr("Blank Layer"), null, null);
- initializeImages();
- mv = Main.map.mapView;
- }
-
- public WMSLayer(String name, String baseURL, String cookies) {
- super(name);
- alphaChannel.setSelected(Main.pref.getBoolean("wmsplugin.alpha_channel"));
- setBackgroundLayer(true); /* set global background variable */
- initializeImages();
- this.baseURL = baseURL;
- this.cookies = cookies;
- WMSGrabber.getProjection(baseURL, true);
- mv = Main.map.mapView;
-
- // quick hack to predefine the PixelDensity to reuse the cache
- int codeIndex = getName().indexOf("#PPD=");
- if (codeIndex != -1) {
- pixelPerDegree = Double.valueOf(getName().substring(codeIndex+5));
- } else {
- pixelPerDegree = getPPD();
- }
- resolution = mv.getDist100PixelText();
-
- executor = Executors.newFixedThreadPool(
- Main.pref.getInteger("wmsplugin.numThreads",
- WMSPlugin.simultaneousConnections));
- if (baseURL != null && !baseURL.startsWith("html:") && !WMSGrabber.isUrlWithPatterns(baseURL)) {
- if (!(baseURL.endsWith("&") || baseURL.endsWith("?"))) {
- if (!confirmMalformedUrl(baseURL)) {
- System.out.println(tr("Warning: WMS layer deactivated because of malformed base url ''{0}''", baseURL));
- usesInvalidUrl = true;
- setName(getName() + tr("(deactivated)"));
- return;
- } else {
- isInvalidUrlConfirmed = true;
- }
- }
- }
-
- Main.pref.addPreferenceChangeListener(this);
- }
-
- public boolean hasAutoDownload(){
- return startstop.isSelected();
- }
-
- public double getDx(){
- return dx;
- }
-
- public double getDy(){
- return dy;
- }
-
- @Override
- public void destroy() {
- try {
- executor.shutdownNow();
- // Might not be initialized, so catch NullPointer as well
- } catch(Exception x) {
- x.printStackTrace();
- }
- }
-
- public double getPPD(){
- ProjectionBounds bounds = mv.getProjectionBounds();
- return mv.getWidth() / (bounds.max.east() - bounds.min.east());
- }
-
- public void initializeImages() {
- images = new GeorefImage[dax][day];
- for(int x = 0; x<dax; ++x) {
- for(int y = 0; y<day; ++y) {
- images[x][y]= new GeorefImage(false);
- }
- }
- }
-
- @Override public Icon getIcon() {
- return icon;
- }
-
- @Override public String getToolTipText() {
- if(startstop.isSelected())
- return tr("WMS layer ({0}), automatically downloading in zoom {1}", getName(), resolution);
- else
- return tr("WMS layer ({0}), downloading in zoom {1}", getName(), resolution);
- }
-
- @Override public boolean isMergable(Layer other) {
- return false;
- }
-
- @Override public void mergeFrom(Layer from) {
- }
-
- private ProjectionBounds XYtoBounds (int x, int y) {
- return new ProjectionBounds(
- new EastNorth( x * imageSize / pixelPerDegree, y * imageSize / pixelPerDegree),
- new EastNorth((x + 1) * imageSize / pixelPerDegree, (y + 1) * imageSize / pixelPerDegree));
- }
-
- private int modulo (int a, int b) {
- return a % b >= 0 ? a%b : a%b+b;
- }
-
- private boolean zoomIsTooBig() {
- //don't download when it's too outzoomed
- return pixelPerDegree / getPPD() > minZoom;
- }
-
- @Override public void paint(Graphics2D g, final MapView mv, Bounds bounds) {
- if(baseURL == null) return;
- if (usesInvalidUrl && !isInvalidUrlConfirmed) return;
-
- if (zoomIsTooBig()) {
- for(int x = 0; x<dax; ++x) {
- for(int y = 0; y<day; ++y) {
- images[modulo(x,dax)][modulo(y,day)].paint(g, mv, dx, dy);
- }
- }
- } else {
- downloadAndPaintVisible(g, mv, false);
- }
- }
-
- public void displace(double dx, double dy) {
- this.dx += dx;
- this.dy += dy;
- }
-
- protected boolean confirmMalformedUrl(String url) {
- if (isInvalidUrlConfirmed)
- return true;
- String msg = tr("<html>The base URL<br>"
- + "''{0}''<br>"
- + "for this WMS layer does neither end with a ''&'' nor with a ''?''.<br>"
- + "This is likely to lead to invalid WMS request. You should check your<br>"
- + "preference settings.<br>"
- + "Do you want to fetch WMS tiles anyway?",
- url);
- String [] options = new String[] {
- tr("Yes, fetch images"),
- tr("No, abort")
- };
- int ret = JOptionPane.showOptionDialog(
- Main.parent,
- msg,
- tr("Invalid URL?"),
- JOptionPane.YES_NO_OPTION,
- JOptionPane.WARNING_MESSAGE,
- null,
- options, options[1]
- );
- switch(ret) {
- case JOptionPane.YES_OPTION: return true;
- default: return false;
- }
- }
-
- protected void downloadAndPaintVisible(Graphics g, final MapView mv,
- boolean real){
- if (usesInvalidUrl)
- return;
-
- ProjectionBounds bounds = mv.getProjectionBounds();
- int bminx= (int)Math.floor (((bounds.min.east() - dx) * pixelPerDegree) / imageSize );
- int bminy= (int)Math.floor (((bounds.min.north() - dy) * pixelPerDegree) / imageSize );
- int bmaxx= (int)Math.ceil (((bounds.max.east() - dx) * pixelPerDegree) / imageSize );
- int bmaxy= (int)Math.ceil (((bounds.max.north() - dy) * pixelPerDegree) / imageSize );
-
- for(int x = bminx; x<bmaxx; ++x) {
- for(int y = bminy; y<bmaxy; ++y){
- GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
- if((!img.paint(g, mv, dx, dy) || img.infotext) && !img.downloadingStarted){
- img.downloadingStarted = true;
- img.image = null;
- img.flushedResizedCachedInstance();
- Grabber gr = WMSPlugin.getGrabber(XYtoBounds(x,y), img, mv, this);
- if(!gr.loadFromCache(real)){
- gr.setPriority(1);
- executor.submit(gr);
- }
- }
- }
- }
- }
-
- @Override public void visitBoundingBox(BoundingXYVisitor v) {
- for(int x = 0; x<dax; ++x) {
- for(int y = 0; y<day; ++y)
- if(images[x][y].image!=null){
- v.visit(images[x][y].min);
- v.visit(images[x][y].max);
- }
- }
- }
-
- @Override public Object getInfoComponent() {
- return getToolTipText();
- }
-
- @Override public Component[] getMenuEntries() {
- return new Component[]{
- new JMenuItem(LayerListDialog.getInstance().createActivateLayerAction(this)),
- new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
- new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)),
- new JSeparator(),
- new JMenuItem(new LoadWmsAction()),
- new JMenuItem(new SaveWmsAction()),
- new JMenuItem(new BookmarkWmsAction()),
- new JSeparator(),
- startstop,
- alphaChannel,
- new JMenuItem(new ChangeResolutionAction()),
- new JMenuItem(new ReloadErrorTilesAction()),
- new JMenuItem(new DownloadAction()),
- new JSeparator(),
- new JMenuItem(new LayerListPopup.InfoAction(this))
- };
- }
-
- public GeorefImage findImage(EastNorth eastNorth) {
- for(int x = 0; x<dax; ++x) {
- for(int y = 0; y<day; ++y)
- if(images[x][y].image!=null && images[x][y].min!=null && images[x][y].max!=null)
- if(images[x][y].contains(eastNorth, dx, dy))
- return images[x][y];
- }
- return null;
- }
-
- public class DownloadAction extends AbstractAction {
- public DownloadAction() {
- super(tr("Download visible tiles"));
- }
- public void actionPerformed(ActionEvent ev) {
- if (zoomIsTooBig()) {
- JOptionPane.showMessageDialog(
- Main.parent,
- tr("The requested area is too big. Please zoom in a little, or change resolution"),
- tr("Error"),
- JOptionPane.ERROR_MESSAGE
- );
- } else {
- downloadAndPaintVisible(mv.getGraphics(), mv, true);
- }
- }
- }
-
- public class ChangeResolutionAction extends AbstractAction {
- public ChangeResolutionAction() {
- super(tr("Change resolution"));
- }
- public void actionPerformed(ActionEvent ev) {
- initializeImages();
- resolution = mv.getDist100PixelText();
- pixelPerDegree = getPPD();
- mv.repaint();
- }
- }
-
- public class ReloadErrorTilesAction extends AbstractAction {
- public ReloadErrorTilesAction() {
- super(tr("Reload erroneous tiles"));
- }
- public void actionPerformed(ActionEvent ev) {
- // Delete small files, because they're probably blank tiles.
- // See https://josm.openstreetmap.de/ticket/2307
- WMSPlugin.cache.customCleanUp(CacheFiles.CLEAN_SMALL_FILES, 4096);
-
- for (int x = 0; x < dax; ++x) {
- for (int y = 0; y < day; ++y) {
- GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
- if(img.failed){
- img.image = null;
- img.flushedResizedCachedInstance();
- img.downloadingStarted = false;
- img.failed = false;
- mv.repaint();
- }
- }
- }
- }
- }
-
- public class ToggleAlphaAction extends AbstractAction {
- public ToggleAlphaAction() {
- super(tr("Alpha channel"));
- }
- public void actionPerformed(ActionEvent ev) {
- JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) ev.getSource();
- boolean alphaChannel = checkbox.isSelected();
- Main.pref.put("wmsplugin.alpha_channel", alphaChannel);
-
- // clear all resized cached instances and repaint the layer
- for (int x = 0; x < dax; ++x) {
- for (int y = 0; y < day; ++y) {
- GeorefImage img = images[modulo(x, dax)][modulo(y, day)];
- img.flushedResizedCachedInstance();
- }
- }
- mv.repaint();
- }
- }
-
- public class SaveWmsAction extends AbstractAction {
- public SaveWmsAction() {
- super(tr("Save WMS layer to file"), ImageProvider.get("save"));
- }
- public void actionPerformed(ActionEvent ev) {
- File f = SaveActionBase.createAndOpenSaveFileChooser(
- tr("Save WMS layer"), ".wms");
- try {
- if (f != null) {
- ObjectOutputStream oos = new ObjectOutputStream(
- new FileOutputStream(f)
- );
- oos.writeInt(serializeFormatVersion);
- oos.writeInt(dax);
- oos.writeInt(day);
- oos.writeInt(imageSize);
- oos.writeDouble(pixelPerDegree);
- oos.writeObject(getName());
- oos.writeObject(baseURL);
- oos.writeObject(images);
- oos.close();
- }
- } catch (Exception ex) {
- ex.printStackTrace(System.out);
- }
- }
- }
-
- public class LoadWmsAction extends AbstractAction {
- public LoadWmsAction() {
- super(tr("Load WMS layer from file"), ImageProvider.get("load"));
- }
- public void actionPerformed(ActionEvent ev) {
- JFileChooser fc = DiskAccessAction.createAndOpenFileChooser(true,
- false, tr("Load WMS layer"), "wms");
- if(fc == null) return;
- File f = fc.getSelectedFile();
- if (f == null) return;
- try
- {
- FileInputStream fis = new FileInputStream(f);
- ObjectInputStream ois = new ObjectInputStream(fis);
- int sfv = ois.readInt();
- if (sfv != serializeFormatVersion) {
- JOptionPane.showMessageDialog(Main.parent,
- tr("Unsupported WMS file version; found {0}, expected {1}", sfv, serializeFormatVersion),
- tr("File Format Error"),
- JOptionPane.ERROR_MESSAGE);
- return;
- }
- startstop.setSelected(false);
- dax = ois.readInt();
- day = ois.readInt();
- imageSize = ois.readInt();
- pixelPerDegree = ois.readDouble();
- setName((String)ois.readObject());
- baseURL = (String) ois.readObject();
- images = (GeorefImage[][])ois.readObject();
- ois.close();
- fis.close();
- mv.repaint();
- }
- catch (Exception ex) {
- // FIXME be more specific
- ex.printStackTrace(System.out);
- JOptionPane.showMessageDialog(Main.parent,
- tr("Error loading file"),
- tr("Error"),
- JOptionPane.ERROR_MESSAGE);
- return;
- }
- }
- }
- /**
- * This action will add a WMS layer menu entry with the current WMS layer
- * URL and name extended by the current resolution.
- * When using the menu entry again, the WMS cache will be used properly.
- */
- public class BookmarkWmsAction extends AbstractAction {
- public BookmarkWmsAction() {
- super(tr("Set WMS Bookmark"));
- }
- public void actionPerformed(ActionEvent ev) {
- int i = 0;
- while (Main.pref.hasKey("wmsplugin.url."+i+".url")) {
- i++;
- }
- String baseName;
- // cut old parameter
- int parameterIndex = getName().indexOf("#PPD=");
- if (parameterIndex != -1) {
- baseName = getName().substring(0,parameterIndex);
- }
- else {
- baseName = getName();
- }
- Main.pref.put("wmsplugin.url."+ i +".url",baseURL );
- Main.pref.put("wmsplugin.url."+String.valueOf(i)+".name",
- baseName + "#PPD=" + pixelPerDegree );
- WMSPlugin.refreshMenu();
- }
- }
-
- public void preferenceChanged(PreferenceChangeEvent event) {
- if (event.getKey().equals("wmsplugin.simultaneousConnections")) {
- executor.shutdownNow();
- executor = Executors.newFixedThreadPool(
- Main.pref.getInteger("wmsplugin.numThreads",
- WMSPlugin.simultaneousConnections));
- }
- }
+
+ protected static final Icon icon =
+ new ImageIcon(Toolkit.getDefaultToolkit().createImage(WMSPlugin.class.getResource("/images/wms_small.png")));
+
+ public static final BooleanProperty PROP_ALPHA_CHANNEL = new BooleanProperty("wmsplugin.alpha_channel", true);
+
+ public int messageNum = 5; //limit for messages per layer
+ protected MapView mv;
+ protected String resolution;
+ protected int imageSize = 500;
+ protected int dax = 10;
+ protected int day = 10;
+ protected int daStep = 5;
+ protected int minZoom = 3;
+
+ protected double dx = 0.0;
+ protected double dy = 0.0;
+
+ protected double pixelPerDegree;
+ protected GeorefImage[][] images;
+ protected String baseURL;
+ protected String cookies;
+ protected final int serializeFormatVersion = 5;
+ protected boolean autoDownloadEnabled = true;
+ protected boolean settingsChanged;
+
+ // Image index boundary for current view
+ private volatile int bminx;
+ private volatile int bminy;
+ private volatile int bmaxx;
+ private volatile int bmaxy;
+ private volatile int leftEdge;
+ private volatile int bottomEdge;
+
+ // Request queue
+ private final List<WMSRequest> requestQueue = new ArrayList<WMSRequest>();
+ private final List<WMSRequest> finishedRequests = new ArrayList<WMSRequest>();
+ private final Lock requestQueueLock = new ReentrantLock();
+ private final Condition queueEmpty = requestQueueLock.newCondition();
+ private final List<Grabber> grabbers = new ArrayList<Grabber>();
+ private final List<Thread> grabberThreads = new ArrayList<Thread>();
+ private int threadCount;
+ private int workingThreadCount;
+ private boolean canceled;
+
+
+ /** set to true if this layer uses an invalid base url */
+ private boolean usesInvalidUrl = false;
+ /** set to true if the user confirmed to use an potentially invalid WMS base url */
+ private boolean isInvalidUrlConfirmed = false;
+
+ public WMSLayer() {
+ this(tr("Blank Layer"), null, null);
+ initializeImages();
+ mv = Main.map.mapView;
+ }
+
+ public WMSLayer(String name, String baseURL, String cookies) {
+ super(name);
+ setBackgroundLayer(true); /* set global background variable */
+ initializeImages();
+ this.baseURL = baseURL;
+ this.cookies = cookies;
+ WMSGrabber.getProjection(baseURL, true);
+ mv = Main.map.mapView;
+
+ // quick hack to predefine the PixelDensity to reuse the cache
+ int codeIndex = getName().indexOf("#PPD=");
+ if (codeIndex != -1) {
+ pixelPerDegree = Double.valueOf(getName().substring(codeIndex+5));
+ } else {
+ pixelPerDegree = getPPD();
+ }
+ resolution = mv.getDist100PixelText();
+
+ if(baseURL != null)
+ {
+ startGrabberThreads();
+ }
+ if (baseURL != null && !baseURL.startsWith("html:") && !WMSGrabber.isUrlWithPatterns(baseURL)) {
+ if (!(baseURL.endsWith("&") || baseURL.endsWith("?"))) {
+ if (!confirmMalformedUrl(baseURL)) {
+ System.out.println(tr("Warning: WMS layer deactivated because of malformed base url ''{0}''", baseURL));
+ usesInvalidUrl = true;
+ setName(getName() + tr("(deactivated)"));
+ return;
+ } else {
+ isInvalidUrlConfirmed = true;
+ }
+ }
+ }
+
+ Main.pref.addPreferenceChangeListener(this);
+ }
+
+ public boolean hasAutoDownload(){
+ return autoDownloadEnabled;
+ }
+
+
+ @Override
+ public void destroy() {
+ cancelGrabberThreads(false);
+ Main.pref.removePreferenceChangeListener(this);
+ }
+
+ public void initializeImages() {
+ GeorefImage[][] old = images;
+ images = new GeorefImage[dax][day];
+ if (old != null) {
+ for (int i=0; i<old.length; i++) {
+ for (int k=0; k<old[i].length; k++) {
+ GeorefImage o = old[i][k];
+ images[modulo(o.getXIndex(),dax)][modulo(o.getYIndex(),day)] = old[i][k];
+ }
+ }
+ }
+ for(int x = 0; x<dax; ++x) {
+ for(int y = 0; y<day; ++y) {
+ if (images[x][y] == null) {
+ images[x][y]= new GeorefImage(this);
+ }
+ }
+ }
+ }
+
+ @Override public Icon getIcon() {
+ return icon;
+ }
+
+ @Override public String getToolTipText() {
+ if(autoDownloadEnabled)
+ return tr("WMS layer ({0}), automatically downloading in zoom {1}", getName(), resolution);
+ else
+ return tr("WMS layer ({0}), downloading in zoom {1}", getName(), resolution);
+ }
+
+ @Override public boolean isMergable(Layer other) {
+ return false;
+ }
+
+ @Override public void mergeFrom(Layer from) {
+ }
+
+ private int modulo (int a, int b) {
+ return a % b >= 0 ? a%b : a%b+b;
+ }
+
+ private boolean zoomIsTooBig() {
+ //don't download when it's too outzoomed
+ return pixelPerDegree / getPPD() > minZoom;
+ }
+
+ @Override public void paint(Graphics2D g, final MapView mv, Bounds b) {
+ if(baseURL == null) return;
+ if (usesInvalidUrl && !isInvalidUrlConfirmed) return;
+
+ settingsChanged = false;
+
+ ProjectionBounds bounds = mv.getProjectionBounds();
+ bminx= getImageXIndex(bounds.min.east());
+ bminy= getImageYIndex(bounds.min.north());
+ bmaxx= getImageXIndex(bounds.max.east());
+ bmaxy= getImageYIndex(bounds.max.north());
+
+ leftEdge = (int)(bounds.min.east() * getPPD());
+ bottomEdge = (int)(bounds.min.north() * getPPD());
+
+ if (zoomIsTooBig()) {
+ for(int x = bminx; x<=bmaxx; ++x) {
+ for(int y = bminy; y<=bmaxy; ++y) {
+ images[modulo(x,dax)][modulo(y,day)].paint(g, mv, x, y, leftEdge, bottomEdge);
+ }
+ }
+ } else {
+ downloadAndPaintVisible(g, mv, false);
+ }
+ }
+
+ protected boolean confirmMalformedUrl(String url) {
+ if (isInvalidUrlConfirmed)
+ return true;
+ String msg = tr("<html>The base URL<br>"
+ + "''{0}''<br>"
+ + "for this WMS layer does neither end with a ''&'' nor with a ''?''.<br>"
+ + "This is likely to lead to invalid WMS request. You should check your<br>"
+ + "preference settings.<br>"
+ + "Do you want to fetch WMS tiles anyway?",
+ url);
+ String [] options = new String[] {
+ tr("Yes, fetch images"),
+ tr("No, abort")
+ };
+ int ret = JOptionPane.showOptionDialog(
+ Main.parent,
+ msg,
+ tr("Invalid URL?"),
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.WARNING_MESSAGE,
+ null,
+ options, options[1]
+ );
+ switch(ret) {
+ case JOptionPane.YES_OPTION: return true;
+ default: return false;
+ }
+ }
+
+ public double getPPD(){
+ ProjectionBounds bounds = mv.getProjectionBounds();
+ return mv.getWidth() / (bounds.max.east() - bounds.min.east());
+ }
+
+ public void displace(double dx, double dy) {
+ settingsChanged = true;
+ this.dx += dx;
+ this.dy += dy;
+ }
+
+ public int getImageXIndex(double coord) {
+ return (int)Math.floor( ((coord - dx) * pixelPerDegree) / imageSize);
+ }
+
+ public int getImageYIndex(double coord) {
+ return (int)Math.floor( ((coord - dy) * pixelPerDegree) / imageSize);
+ }
+
+ public int getImageX(int imageIndex) {
+ return (int)(imageIndex * imageSize * (getPPD() / pixelPerDegree) + dx * getPPD());
+ }
+
+ public int getImageY(int imageIndex) {
+ return (int)(imageIndex * imageSize * (getPPD() / pixelPerDegree) + dy * getPPD());
+ }
+
+ public int getImageWidth(int xIndex) {
+ int overlap = (int)(WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_EAST.get() * imageSize * getPPD() / pixelPerDegree / 100:0);
+ return getImageX(xIndex + 1) - getImageX(xIndex) + overlap;
+ }
+
+ public int getImageHeight(int yIndex) {
+ int overlap = (int)(WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_NORTH.get() * imageSize * getPPD() / pixelPerDegree / 100:0);
+ return getImageY(yIndex + 1) - getImageY(yIndex) + overlap;
+ }
+
+ /**
+ *
+ * @return Size of image in original zoom
+ */
+ public int getBaseImageWidth() {
+ int overlap = (WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_EAST.get() * imageSize / 100:0);
+ return imageSize + overlap;
+ }
+
+ /**
+ *
+ * @return Size of image in original zoom
+ */
+ public int getBaseImageHeight() {
+ int overlap = (WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_NORTH.get() * imageSize / 100:0);
+ return imageSize + overlap;
+ }
+
+
+ /**
+ *
+ * @param xIndex
+ * @param yIndex
+ * @return Real EastNorth of given tile. dx/dy is not counted in
+ */
+ public EastNorth getEastNorth(int xIndex, int yIndex) {
+ return new EastNorth((xIndex * imageSize) / pixelPerDegree, (yIndex * imageSize) / pixelPerDegree);
+ }
+
+
+ protected void downloadAndPaintVisible(Graphics g, final MapView mv, boolean real){
+
+ int newDax = dax;
+ int newDay = day;
+
+ if (bmaxx - bminx >= dax || bmaxx - bminx < dax - 2 * daStep) {
+ newDax = ((bmaxx - bminx) / daStep + 1) * daStep;
+ }
+
+ if (bmaxy - bminy >= day || bmaxy - bminx < day - 2 * daStep) {
+ newDay = ((bmaxy - bminy) / daStep + 1) * daStep;
+ }
+
+ if (newDax != dax || newDay != day) {
+ dax = newDax;
+ day = newDay;
+ initializeImages();
+ }
+
+ for(int x = bminx; x<=bmaxx; ++x) {
+ for(int y = bminy; y<=bmaxy; ++y){
+ images[modulo(x,dax)][modulo(y,day)].changePosition(x, y);
+ }
+ }
+
+ gatherFinishedRequests();
+
+ for(int x = bminx; x<=bmaxx; ++x) {
+ for(int y = bminy; y<=bmaxy; ++y){
+ GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
+ if (!img.paint(g, mv, x, y, leftEdge, bottomEdge)) {
+ WMSRequest request = new WMSRequest(x, y, pixelPerDegree, real);
+ addRequest(request);
+ }
+ }
+ }
+ }
+
+ @Override public void visitBoundingBox(BoundingXYVisitor v) {
+ for(int x = 0; x<dax; ++x) {
+ for(int y = 0; y<day; ++y)
+ if(images[x][y].getImage() != null){
+ v.visit(images[x][y].getMin());
+ v.visit(images[x][y].getMax());
+ }
+ }
+ }
+
+ @Override public Object getInfoComponent() {
+ return getToolTipText();
+ }
+
+ @Override public Action[] getMenuEntries() {
+ return new Action[]{
+ LayerListDialog.getInstance().createActivateLayerAction(this),
+ LayerListDialog.getInstance().createShowHideLayerAction(),
+ LayerListDialog.getInstance().createDeleteLayerAction(),
+ SeparatorLayerAction.INSTANCE,
+ new LoadWmsAction(),
+ new SaveWmsAction(),
+ new BookmarkWmsAction(),
+ SeparatorLayerAction.INSTANCE,
+ new StartStopAction(),
+ new ToggleAlphaAction(),
+ new ChangeResolutionAction(),
+ new ReloadErrorTilesAction(),
+ new DownloadAction(),
+ SeparatorLayerAction.INSTANCE,
+ new LayerListPopup.InfoAction(this)
+ };
+ }
+
+ public GeorefImage findImage(EastNorth eastNorth) {
+ int xIndex = getImageXIndex(eastNorth.east());
+ int yIndex = getImageYIndex(eastNorth.north());
+ GeorefImage result = images[modulo(xIndex, dax)][modulo(yIndex, day)];
+ if (result.getXIndex() == xIndex && result.getYIndex() == yIndex) {
+ return result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ *
+ * @param request
+ * @return -1 if request is no longer needed, otherwise priority of request (lower number <=> more important request)
+ */
+ private int getRequestPriority(WMSRequest request) {
+ if (request.getPixelPerDegree() != pixelPerDegree) {
+ return -1;
+ }
+ if (bminx > request.getXIndex()
+ || bmaxx < request.getXIndex()
+ || bminy > request.getYIndex()
+ || bmaxy < request.getYIndex()) {
+ return -1;
+ }
+
+ EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
+ int mouseX = getImageXIndex(cursorEastNorth.east());
+ int mouseY = getImageYIndex(cursorEastNorth.north());
+ int dx = request.getXIndex() - mouseX;
+ int dy = request.getYIndex() - mouseY;
+
+ return dx * dx + dy * dy;
+ }
+
+ public WMSRequest getRequest() {
+ requestQueueLock.lock();
+ try {
+ workingThreadCount--;
+ Iterator<WMSRequest> it = requestQueue.iterator();
+ while (it.hasNext()) {
+ WMSRequest item = it.next();
+ int priority = getRequestPriority(item);
+ if (priority == -1) {
+ it.remove();
+ } else {
+ item.setPriority(priority);
+ }
+ }
+ Collections.sort(requestQueue);
+
+ EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
+ int mouseX = getImageXIndex(cursorEastNorth.east());
+ int mouseY = getImageYIndex(cursorEastNorth.north());
+ boolean isOnMouse = requestQueue.size() > 0 && requestQueue.get(0).getXIndex() == mouseX && requestQueue.get(0).getYIndex() == mouseY;
+
+ // If there is only one thread left then keep it in case we need to download other tile urgently
+ while (!canceled &&
+ (requestQueue.isEmpty() || (!isOnMouse && threadCount - workingThreadCount == 0 && threadCount > 1))) {
+ try {
+ queueEmpty.await();
+ } catch (InterruptedException e) {
+ // Shouldn't happen
+ }
+ }
+
+ workingThreadCount++;
+ if (canceled) {
+ return null;
+ } else {
+ return requestQueue.remove(0);
+ }
+
+ } finally {
+ requestQueueLock.unlock();
+ }
+ }
+
+ public void finishRequest(WMSRequest request) {
+ if (request.getState() == null) {
+ throw new IllegalArgumentException("Finished request without state");
+ }
+ requestQueueLock.lock();
+ try {
+ finishedRequests.add(request);
+ } finally {
+ requestQueueLock.unlock();
+ }
+ }
+
+ public void addRequest(WMSRequest request) {
+ requestQueueLock.lock();
+ try {
+ if (!requestQueue.contains(request)) {
+ requestQueue.add(request);
+ queueEmpty.signalAll();
+ }
+ } finally {
+ requestQueueLock.unlock();
+ }
+ }
+
+ public boolean requestIsValid(WMSRequest request) {
+ return bminx <= request.getXIndex() && bmaxx >= request.getXIndex() && bminy <= request.getYIndex() && bmaxy >= request.getYIndex();
+ }
+
+ private void gatherFinishedRequests() {
+ requestQueueLock.lock();
+ try {
+ for (WMSRequest request: finishedRequests) {
+ GeorefImage img = images[modulo(request.getXIndex(),dax)][modulo(request.getYIndex(),day)];
+ if (img.equalPosition(request.getXIndex(), request.getYIndex())) {
+ img.changeImage(request.getState(), request.getImage());
+ }
+ }
+ } finally {
+ finishedRequests.clear();
+ requestQueueLock.unlock();
+ }
+ }
+
+ public class DownloadAction extends AbstractAction {
+ private static final long serialVersionUID = -7183852461015284020L;
+ public DownloadAction() {
+ super(tr("Download visible tiles"));
+ }
+ public void actionPerformed(ActionEvent ev) {
+ if (zoomIsTooBig()) {
+ JOptionPane.showMessageDialog(
+ Main.parent,
+ tr("The requested area is too big. Please zoom in a little, or change resolution"),
+ tr("Error"),
+ JOptionPane.ERROR_MESSAGE
+ );
+ } else {
+ downloadAndPaintVisible(mv.getGraphics(), mv, true);
+ }
+ }
+ }
+
+ public class ChangeResolutionAction extends AbstractAction {
+ public ChangeResolutionAction() {
+ super(tr("Change resolution"));
+ }
+ public void actionPerformed(ActionEvent ev) {
+ initializeImages();
+ resolution = mv.getDist100PixelText();
+ pixelPerDegree = getPPD();
+ settingsChanged = true;
+ mv.repaint();
+ }
+ }
+
+ public class ReloadErrorTilesAction extends AbstractAction {
+ public ReloadErrorTilesAction() {
+ super(tr("Reload erroneous tiles"));
+ }
+ public void actionPerformed(ActionEvent ev) {
+ // Delete small files, because they're probably blank tiles.
+ // See https://josm.openstreetmap.de/ticket/2307
+ WMSPlugin.cache.customCleanUp(CacheFiles.CLEAN_SMALL_FILES, 4096);
+
+ for (int x = 0; x < dax; ++x) {
+ for (int y = 0; y < day; ++y) {
+ GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
+ if(img.getState() == State.FAILED){
+ addRequest(new WMSRequest(img.getXIndex(), img.getYIndex(), pixelPerDegree, true));
+ mv.repaint();
+ }
+ }
+ }
+ }
+ }
+
+ public class ToggleAlphaAction extends AbstractAction implements LayerAction {
+ public ToggleAlphaAction() {
+ super(tr("Alpha channel"));
+ }
+ public void actionPerformed(ActionEvent ev) {
+ JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) ev.getSource();
+ boolean alphaChannel = checkbox.isSelected();
+ PROP_ALPHA_CHANNEL.put(alphaChannel);
+
+ // clear all resized cached instances and repaint the layer
+ for (int x = 0; x < dax; ++x) {
+ for (int y = 0; y < day; ++y) {
+ GeorefImage img = images[modulo(x, dax)][modulo(y, day)];
+ img.flushedResizedCachedInstance();
+ }
+ }
+ mv.repaint();
+ }
+ public Component createMenuComponent() {
+ JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
+ item.setSelected(PROP_ALPHA_CHANNEL.get());
+ return item;
+ }
+ public boolean supportLayers(List<Layer> layers) {
+ return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
+ }
+ }
+
+ public class SaveWmsAction extends AbstractAction {
+ public SaveWmsAction() {
+ super(tr("Save WMS layer to file"), ImageProvider.get("save"));
+ }
+ public void actionPerformed(ActionEvent ev) {
+ File f = SaveActionBase.createAndOpenSaveFileChooser(
+ tr("Save WMS layer"), ".wms");
+ try {
+ if (f != null) {
+ ObjectOutputStream oos = new ObjectOutputStream(
+ new FileOutputStream(f)
+ );
+ oos.writeInt(serializeFormatVersion);
+ oos.writeInt(dax);
+ oos.writeInt(day);
+ oos.writeInt(imageSize);
+ oos.writeDouble(pixelPerDegree);
+ oos.writeObject(getName());
+ oos.writeObject(baseURL);
+ oos.writeObject(images);
+ oos.close();
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace(System.out);
+ }
+ }
+ }
+
+ public class LoadWmsAction extends AbstractAction {
+ public LoadWmsAction() {
+ super(tr("Load WMS layer from file"), ImageProvider.get("load"));
+ }
+ public void actionPerformed(ActionEvent ev) {
+ JFileChooser fc = DiskAccessAction.createAndOpenFileChooser(true,
+ false, tr("Load WMS layer"), "wms");
+ if(fc == null) return;
+ File f = fc.getSelectedFile();
+ if (f == null) return;
+ try
+ {
+ FileInputStream fis = new FileInputStream(f);
+ ObjectInputStream ois = new ObjectInputStream(fis);
+ int sfv = ois.readInt();
+ if (sfv != serializeFormatVersion) {
+ JOptionPane.showMessageDialog(Main.parent,
+ tr("Unsupported WMS file version; found {0}, expected {1}", sfv, serializeFormatVersion),
+ tr("File Format Error"),
+ JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ autoDownloadEnabled = false;
+ dax = ois.readInt();
+ day = ois.readInt();
+ imageSize = ois.readInt();
+ pixelPerDegree = ois.readDouble();
+ setName((String)ois.readObject());
+ baseURL = (String) ois.readObject();
+ images = (GeorefImage[][])ois.readObject();
+ ois.close();
+ fis.close();
+ for (GeorefImage[] imgs : images) {
+ for (GeorefImage img : imgs) {
+ if (img != null) {
+ img.setLayer(WMSLayer.this);
+ }
+ }
+ }
+ settingsChanged = true;
+ mv.repaint();
+ if(baseURL != null)
+ {
+ startGrabberThreads();
+ }
+ }
+ catch (Exception ex) {
+ // FIXME be more specific
+ ex.printStackTrace(System.out);
+ JOptionPane.showMessageDialog(Main.parent,
+ tr("Error loading file"),
+ tr("Error"),
+ JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ }
+ }
+ /**
+ * This action will add a WMS layer menu entry with the current WMS layer
+ * URL and name extended by the current resolution.
+ * When using the menu entry again, the WMS cache will be used properly.
+ */
+ public class BookmarkWmsAction extends AbstractAction {
+ public BookmarkWmsAction() {
+ super(tr("Set WMS Bookmark"));
+ }
+ public void actionPerformed(ActionEvent ev) {
+ int i = 0;
+ while (Main.pref.hasKey("wmsplugin.url."+i+".url")) {
+ i++;
+ }
+ String baseName;
+ // cut old parameter
+ int parameterIndex = getName().indexOf("#PPD=");
+ if (parameterIndex != -1) {
+ baseName = getName().substring(0,parameterIndex);
+ }
+ else {
+ baseName = getName();
+ }
+ Main.pref.put("wmsplugin.url."+ i +".url",baseURL );
+ Main.pref.put("wmsplugin.url."+String.valueOf(i)+".name",
+ baseName + "#PPD=" + pixelPerDegree );
+ WMSPlugin.refreshMenu();
+ }
+ }
+
+ private class StartStopAction extends AbstractAction implements LayerAction {
+
+ public StartStopAction() {
+ super(tr("Automatic downloading"));
+ }
+
+ public Component createMenuComponent() {
+ JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
+ item.setSelected(autoDownloadEnabled);
+ return item;
+ }
+
+ public boolean supportLayers(List<Layer> layers) {
+ return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ autoDownloadEnabled = !autoDownloadEnabled;
+ if (autoDownloadEnabled) {
+ mv.repaint();
+ }
+ }
+ }
+
+ private void cancelGrabberThreads(boolean wait) {
+ requestQueueLock.lock();
+ try {
+ canceled = true;
+ for (Grabber grabber: grabbers) {
+ grabber.cancel();
+ }
+ queueEmpty.signalAll();
+ } finally {
+ requestQueueLock.unlock();
+ }
+ if (wait) {
+ for (Thread t: grabberThreads) {
+ try {
+ t.join();
+ } catch (InterruptedException e) {
+ // Shouldn't happen
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ private void startGrabberThreads() {
+ int threadCount = WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.get();
+ requestQueueLock.lock();
+ try {
+ canceled = false;
+ grabbers.clear();
+ grabberThreads.clear();
+ for (int i=0; i<threadCount; i++) {
+ Grabber grabber = WMSPlugin.getGrabber(mv, this);
+ grabbers.add(grabber);
+ Thread t = new Thread(grabber, "WMS " + getName() + " " + i);
+ t.setDaemon(true);
+ t.start();
+ grabberThreads.add(t);
+ }
+ this.workingThreadCount = grabbers.size();
+ this.threadCount = grabbers.size();
+ } finally {
+ requestQueueLock.unlock();
+ }
+ }
+
+ @Override
+ public boolean isChanged() {
+ requestQueueLock.lock();
+ try {
+ return !finishedRequests.isEmpty() || settingsChanged;
+ } finally {
+ requestQueueLock.unlock();
+ }
+ }
+
+ public void preferenceChanged(PreferenceChangeEvent event) {
+ if (event.getKey().equals(WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.getKey())) {
+ cancelGrabberThreads(true);
+ startGrabberThreads();
+ } else if (
+ event.getKey().equals(WMSPlugin.PROP_OVERLAP.getKey())
+ || event.getKey().equals(WMSPlugin.PROP_OVERLAP_EAST.getKey())
+ || event.getKey().equals(WMSPlugin.PROP_OVERLAP_NORTH.getKey())) {
+ for (int i=0; i<images.length; i++) {
+ for (int k=0; k<images[i].length; k++) {
+ images[i][k] = new GeorefImage(this);
+ }
+ }
+
+ settingsChanged = true;
+ }
+ }
+
}
diff --git a/wmsplugin/src/wmsplugin/WMSPlugin.java b/wmsplugin/src/wmsplugin/WMSPlugin.java
index 9672bad..7e62f42 100644
--- a/wmsplugin/src/wmsplugin/WMSPlugin.java
+++ b/wmsplugin/src/wmsplugin/WMSPlugin.java
@@ -14,6 +14,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
@@ -22,11 +24,13 @@ import java.util.TreeSet;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.ExtensionFileFilter;
import org.openstreetmap.josm.actions.JosmAction;
-import org.openstreetmap.josm.data.ProjectionBounds;
+import org.openstreetmap.josm.data.preferences.BooleanProperty;
+import org.openstreetmap.josm.data.preferences.IntegerProperty;
import org.openstreetmap.josm.gui.IconToggleButton;
import org.openstreetmap.josm.gui.MainMenu;
import org.openstreetmap.josm.gui.MapFrame;
@@ -35,226 +39,366 @@ import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
import org.openstreetmap.josm.io.CacheFiles;
import org.openstreetmap.josm.io.MirroredInputStream;
import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginHandler;
import org.openstreetmap.josm.plugins.PluginInformation;
+import org.openstreetmap.josm.plugins.PluginProxy;
import wmsplugin.io.WMSLayerExporter;
import wmsplugin.io.WMSLayerImporter;
public class WMSPlugin extends Plugin {
- static CacheFiles cache = new CacheFiles("wmsplugin");
-
- WMSLayer wmsLayer;
- static JMenu wmsJMenu;
-
- static ArrayList<WMSInfo> wmsList = new ArrayList<WMSInfo>();
- static TreeMap<String,String> wmsListDefault = new TreeMap<String,String>();
-
- static boolean doOverlap = false;
- static int overlapEast = 14;
- static int overlapNorth = 4;
- static int simultaneousConnections = 3;
-
- // remember state of menu item to restore on changed preferences
- static private boolean menuEnabled = false;
-
- protected void initExporterAndImporter() {
- ExtensionFileFilter.exporters.add(new WMSLayerExporter());
- ExtensionFileFilter.importers.add(new WMSLayerImporter());
- }
-
- public WMSPlugin(PluginInformation info) {
- super(info);
- refreshMenu();
- cache.setExpire(CacheFiles.EXPIRE_MONTHLY, false);
- cache.setMaxSize(70, false);
- initExporterAndImporter();
- }
-
- // this parses the preferences settings. preferences for the wms plugin have to
- // look like this:
- // wmsplugin.1.name=Landsat
- // wmsplugin.1.url=http://and.so.on/
-
- @Override
- public void copy(String from, String to) throws FileNotFoundException, IOException
- {
- File pluginDir = new File(getPrefsPath());
- if (!pluginDir.exists())
- pluginDir.mkdirs();
- FileOutputStream out = new FileOutputStream(getPrefsPath() + to);
- InputStream in = WMSPlugin.class.getResourceAsStream(from);
- byte[] buffer = new byte[8192];
- for(int len = in.read(buffer); len > 0; len = in.read(buffer))
- out.write(buffer, 0, len);
- in.close();
- out.close();
- }
-
-
- public static void refreshMenu() {
- wmsList.clear();
- Map<String,String> prefs = Main.pref.getAllPrefix("wmsplugin.url.");
-
- TreeSet<String> keys = new TreeSet<String>(prefs.keySet());
-
- // Here we load the settings for "overlap" checkbox and spinboxes.
-
- try {
- doOverlap = Boolean.valueOf(prefs.get("wmsplugin.url.overlap"));
- } catch (Exception e) {} // If sth fails, we drop to default settings.
-
- try {
- overlapEast = Integer.valueOf(prefs.get("wmsplugin.url.overlapEast"));
- } catch (Exception e) {} // If sth fails, we drop to default settings.
-
- try {
- overlapNorth = Integer.valueOf(prefs.get("wmsplugin.url.overlapNorth"));
- } catch (Exception e) {} // If sth fails, we drop to default settings.
-
- // Load the settings for number of simultaneous connections
- try {
- simultaneousConnections = Integer.valueOf(prefs.get("wmsplugin.simultanousConnections"));
- } catch (Exception e) {} // If sth fails, we drop to default settings.
-
- // And then the names+urls of WMS servers
- int prefid = 0;
- String name = null;
- String url = null;
- String cookies = "";
- int lastid = -1;
- for (String key : keys) {
- String[] elements = key.split("\\.");
- if (elements.length != 4) continue;
- try {
- prefid = Integer.parseInt(elements[2]);
- } catch(NumberFormatException e) {
- continue;
- }
- if (prefid != lastid) {
- name = url = null; lastid = prefid;
- }
- if (elements[3].equals("name"))
- name = prefs.get(key);
- else if (elements[3].equals("url"))
- {
- /* FIXME: Remove the if clause after some time */
- if(!prefs.get(key).startsWith("yahoo:")) /* legacy stuff */
- url = prefs.get(key);
- }
- else if (elements[3].equals("cookies"))
- cookies = prefs.get(key);
- if (name != null && url != null)
- wmsList.add(new WMSInfo(name, url, cookies, prefid));
- }
- String source = "http://svn.openstreetmap.org/applications/editors/josm/plugins/wmsplugin/sources.cfg";
- try
- {
- MirroredInputStream s = new MirroredInputStream(source,
- Main.pref.getPreferencesDir() + "plugins/wmsplugin/", -1);
- InputStreamReader r;
- try
- {
- r = new InputStreamReader(s, "UTF-8");
- }
- catch (UnsupportedEncodingException e)
- {
- r = new InputStreamReader(s);
- }
- BufferedReader reader = new BufferedReader(r);
- String line;
- while((line = reader.readLine()) != null)
- {
- String val[] = line.split(";");
- if(!line.startsWith("#") && val.length == 3)
- setDefault("true".equals(val[0]), tr(val[1]), val[2]);
- }
- }
- catch (IOException e)
- {
- }
-
- Collections.sort(wmsList);
- MainMenu menu = Main.main.menu;
-
- if (wmsJMenu == null)
- wmsJMenu = menu.addMenu(marktr("WMS"), KeyEvent.VK_W, menu.defaultMenuPos, ht("/Plugin/WMS"));
- else
- wmsJMenu.removeAll();
-
- // for each configured WMSInfo, add a menu entry.
- for (final WMSInfo u : wmsList) {
- wmsJMenu.add(new JMenuItem(new WMSDownloadAction(u)));
- }
- wmsJMenu.addSeparator();
- wmsJMenu.add(new JMenuItem(new Map_Rectifier_WMSmenuAction()));
-
- wmsJMenu.addSeparator();
- wmsJMenu.add(new JMenuItem(new
- JosmAction(tr("Blank Layer"), "blankmenu", tr("Open a blank WMS layer to load data from a file"), null, false) {
- public void actionPerformed(ActionEvent ev) {
- Main.main.addLayer(new WMSLayer());
- }
- }));
- setEnabledAll(menuEnabled);
- }
-
- /* add a default entry in case the URL does not yet exist */
- private static void setDefault(Boolean force, String name, String url)
- {
- String testurl = url.replaceAll("=", "_");
- wmsListDefault.put(name, url);
-
- if(force && !Main.pref.getBoolean("wmsplugin.default."+testurl))
- {
- Main.pref.put("wmsplugin.default."+testurl, true);
- int id = -1;
- for(WMSInfo i : wmsList)
- {
- if(url.equals(i.url))
- return;
- if(i.prefid > id)
- id = i.prefid;
- }
- WMSInfo newinfo = new WMSInfo(name, url, id+1);
- newinfo.save();
- wmsList.add(newinfo);
- }
- }
-
- public static Grabber getGrabber(ProjectionBounds bounds, GeorefImage img, MapView mv, WMSLayer layer){
- if(layer.baseURL.startsWith("html:"))
- return new HTMLGrabber(bounds, img, mv, layer, cache);
- else
- return new WMSGrabber(bounds, img, mv, layer, cache);
- }
-
- private static void setEnabledAll(boolean isEnabled) {
- for(int i=0; i < wmsJMenu.getItemCount(); i++) {
- JMenuItem item = wmsJMenu.getItem(i);
-
- if(item != null) item.setEnabled(isEnabled);
- }
- menuEnabled = isEnabled;
- }
-
- @Override
- public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
- if (oldFrame==null && newFrame!=null) {
- setEnabledAll(true);
- Main.map.addMapMode(new IconToggleButton
- (new WMSAdjustAction(Main.map)));
- } else if (oldFrame!=null && newFrame==null ) {
- setEnabledAll(false);
- }
- }
-
- @Override
- public PreferenceSetting getPreferenceSetting() {
- return new WMSPreferenceEditor();
- }
-
- static public String getPrefsPath()
- {
- return Main.pref.getPluginsDirectory().getPath() + "/wmsplugin/";
- }
+ static CacheFiles cache = new CacheFiles("wmsplugin");
+
+ public static final IntegerProperty PROP_SIMULTANEOUS_CONNECTIONS = new IntegerProperty("wmsplugin.simultaneousConnections", 3);
+ public static final BooleanProperty PROP_OVERLAP = new BooleanProperty("wmsplugin.url.overlap", false);
+ public static final IntegerProperty PROP_OVERLAP_EAST = new IntegerProperty("wmsplugin.url.overlapEast", 14);
+ public static final IntegerProperty PROP_OVERLAP_NORTH = new IntegerProperty("wmsplugin.url.overlapNorth", 4);
+
+ WMSLayer wmsLayer;
+ static JMenu wmsJMenu;
+
+ static ArrayList<WMSInfo> wmsList = new ArrayList<WMSInfo>();
+ static TreeMap<String,String> wmsListDefault = new TreeMap<String,String>();
+
+ // remember state of menu item to restore on changed preferences
+ static private boolean menuEnabled = false;
+
+ /***************************************************************
+ * Remote control initialization:
+ * If you need remote control in some other plug-in
+ * copy this stuff and the call to initRemoteControl below
+ * and replace the RequestHandler subclass in initRemoteControl
+ ***************************************************************/
+
+ /** name of remote control plugin */
+ private static final String REMOTECONTROL_NAME = "remotecontrol";
+
+ /* if necessary change these version numbers to ensure compatibility */
+
+ /** RemoteControlPlugin older than this SVN revision is not compatible */
+ static final int REMOTECONTROL_MIN_REVISION = 22734;
+ /** WMSPlugin needs this specific API major version of RemoteControlPlugin */
+ static final int REMOTECONTROL_NEED_API_MAJOR = 1;
+ /** All API minor versions starting from this should be compatible */
+ static final int REMOTECONTROL_MIN_API_MINOR = 0;
+
+ /* these fields will contain state and version of remote control plug-in */
+ boolean remoteControlAvailable = false;
+ boolean remoteControlCompatible = true;
+ boolean remoteControlInitialized = false;
+ int remoteControlRevision = 0;
+ int remoteControlApiMajor = 0;
+ int remoteControlApiMinor = 0;
+ int remoteControlProtocolMajor = 0;
+ int remoteControlProtocolMinor = 0;
+
+ /**
+ * Check if remote control plug-in is available and if its version is
+ * high enough and register remote control command for this plug-in.
+ */
+ private void initRemoteControl() {
+ for(PluginProxy pp: PluginHandler.pluginList)
+ {
+ PluginInformation info = pp.getPluginInformation();
+ if(REMOTECONTROL_NAME.equals(info.name))
+ {
+ remoteControlAvailable = true;
+ remoteControlRevision = Integer.parseInt(info.version);
+ if(REMOTECONTROL_MIN_REVISION > remoteControlRevision)
+ {
+ remoteControlCompatible = false;
+ }
+ }
+ }
+
+ if(remoteControlAvailable && remoteControlCompatible)
+ {
+ Plugin plugin =
+ (Plugin) PluginHandler.getPlugin(REMOTECONTROL_NAME);
+ try {
+ Method method;
+ method = plugin.getClass().getMethod("getVersion");
+ Object obj = method.invoke(plugin);
+ if((obj != null ) && (obj instanceof int[]))
+ {
+ int[] versions = (int[]) obj;
+ if(versions.length >= 4)
+ {
+ remoteControlApiMajor = versions[0];
+ remoteControlApiMinor = versions[1];
+ remoteControlProtocolMajor = versions[2];
+ remoteControlProtocolMinor = versions[3];
+ }
+ }
+
+ if((remoteControlApiMajor != REMOTECONTROL_NEED_API_MAJOR) ||
+ (remoteControlApiMinor < REMOTECONTROL_MIN_API_MINOR))
+ {
+ remoteControlCompatible = false;
+ }
+ if(remoteControlCompatible)
+ {
+ System.out.println(this.getClass().getSimpleName() + ": initializing remote control");
+ method = plugin.getClass().getMethod("addRequestHandler", String.class, Class.class);
+ // replace command and class when you copy this to some other plug-in
+ // for compatibility with old remotecontrol add leading "/"
+ method.invoke(plugin, "/" + WMSRemoteHandler.command, WMSRemoteHandler.class);
+ remoteControlInitialized = true;
+ }
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ }
+ }
+ if(remoteControlAvailable)
+ {
+ String msg = null;
+
+ if(remoteControlCompatible)
+ {
+ if(!remoteControlInitialized)
+ {
+ msg = tr("Could not initialize remote control.");
+ }
+ }
+ else
+ {
+ msg = tr("Remote control plugin is not compatible with {0}.",
+ this.getClass().getSimpleName());
+ }
+
+ if(msg != null)
+ {
+ String additionalMessage = tr("{0} will work but remote control for this plugin is disabled.\n"
+ + "You should update the plugins.",
+ this.getClass().getSimpleName());
+ String versionMessage = tr("Current version of \"{1}\": {2}, internal version {3}. "
+ + "Need version {4}, internal version {5}.\n"
+ + "If updating the plugins does not help report a bug for \"{0}\".",
+ this.getClass().getSimpleName(),
+ REMOTECONTROL_NAME,
+ ""+remoteControlRevision,
+ (remoteControlApiMajor != 0) ?
+ ""+remoteControlApiMajor+"."+remoteControlApiMinor :
+ tr("unknown"),
+ ""+REMOTECONTROL_MIN_REVISION,
+ ""+REMOTECONTROL_NEED_API_MAJOR+"."+REMOTECONTROL_MIN_API_MINOR );
+
+ String title = tr("{0}: Problem with remote control",
+ this.getClass().getSimpleName());
+
+ System.out.println(this.getClass().getSimpleName() + ": " +
+ msg + "\n" + versionMessage);
+
+ JOptionPane.showMessageDialog(
+ Main.parent,
+ msg + "\n" + additionalMessage,
+ title,
+ JOptionPane.WARNING_MESSAGE
+ );
+ }
+ }
+
+ if(!remoteControlAvailable) {
+ System.out.println(this.getClass().getSimpleName() + ": remote control not available");
+ }
+ }
+
+ /***************************************
+ * end of remote control initialization
+ ***************************************/
+
+ protected void initExporterAndImporter() {
+ ExtensionFileFilter.exporters.add(new WMSLayerExporter());
+ ExtensionFileFilter.importers.add(new WMSLayerImporter());
+ }
+
+ public WMSPlugin(PluginInformation info) {
+ super(info);
+ /*
+ System.out.println("constructor " + this.getClass().getName() + " (" + info.name +
+ " v " + info.version + " stage " + info.stage + ")");
+ */
+ refreshMenu();
+ cache.setExpire(CacheFiles.EXPIRE_MONTHLY, false);
+ cache.setMaxSize(70, false);
+ initExporterAndImporter();
+ initRemoteControl();
+ }
+
+ // this parses the preferences settings. preferences for the wms plugin have to
+ // look like this:
+ // wmsplugin.1.name=Landsat
+ // wmsplugin.1.url=http://and.so.on/
+
+ @Override
+ public void copy(String from, String to) throws FileNotFoundException, IOException
+ {
+ File pluginDir = new File(getPrefsPath());
+ if (!pluginDir.exists())
+ pluginDir.mkdirs();
+ FileOutputStream out = new FileOutputStream(getPrefsPath() + to);
+ InputStream in = WMSPlugin.class.getResourceAsStream(from);
+ byte[] buffer = new byte[8192];
+ for(int len = in.read(buffer); len > 0; len = in.read(buffer))
+ out.write(buffer, 0, len);
+ in.close();
+ out.close();
+ }
+
+
+ public static void refreshMenu() {
+ wmsList.clear();
+ Map<String,String> prefs = Main.pref.getAllPrefix("wmsplugin.url.");
+
+ TreeSet<String> keys = new TreeSet<String>(prefs.keySet());
+
+ // And then the names+urls of WMS servers
+ int prefid = 0;
+ String name = null;
+ String url = null;
+ String cookies = "";
+ int lastid = -1;
+ for (String key : keys) {
+ String[] elements = key.split("\\.");
+ if (elements.length != 4) continue;
+ try {
+ prefid = Integer.parseInt(elements[2]);
+ } catch(NumberFormatException e) {
+ continue;
+ }
+ if (prefid != lastid) {
+ name = url = null; lastid = prefid;
+ }
+ if (elements[3].equals("name"))
+ name = prefs.get(key);
+ else if (elements[3].equals("url"))
+ {
+ /* FIXME: Remove the if clause after some time */
+ if(!prefs.get(key).startsWith("yahoo:")) /* legacy stuff */
+ url = prefs.get(key);
+ }
+ else if (elements[3].equals("cookies"))
+ cookies = prefs.get(key);
+ if (name != null && url != null)
+ wmsList.add(new WMSInfo(name, url, cookies, prefid));
+ }
+ String source = "http://svn.openstreetmap.org/applications/editors/josm/plugins/wmsplugin/sources.cfg";
+ try
+ {
+ MirroredInputStream s = new MirroredInputStream(source,
+ Main.pref.getPreferencesDir() + "plugins/wmsplugin/", -1);
+ InputStreamReader r;
+ try
+ {
+ r = new InputStreamReader(s, "UTF-8");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ r = new InputStreamReader(s);
+ }
+ BufferedReader reader = new BufferedReader(r);
+ String line;
+ while((line = reader.readLine()) != null)
+ {
+ String val[] = line.split(";");
+ if(!line.startsWith("#") && val.length == 3)
+ setDefault("true".equals(val[0]), tr(val[1]), val[2]);
+ }
+ }
+ catch (IOException e)
+ {
+ }
+
+ Collections.sort(wmsList);
+ MainMenu menu = Main.main.menu;
+
+ if (wmsJMenu == null)
+ wmsJMenu = menu.addMenu(marktr("WMS"), KeyEvent.VK_W, menu.defaultMenuPos, ht("/Plugin/WMS"));
+ else
+ wmsJMenu.removeAll();
+
+ // for each configured WMSInfo, add a menu entry.
+ for (final WMSInfo u : wmsList) {
+ wmsJMenu.add(new JMenuItem(new WMSDownloadAction(u)));
+ }
+ wmsJMenu.addSeparator();
+ wmsJMenu.add(new JMenuItem(new Map_Rectifier_WMSmenuAction()));
+
+ wmsJMenu.addSeparator();
+ wmsJMenu.add(new JMenuItem(new
+ JosmAction(tr("Blank Layer"), "blankmenu", tr("Open a blank WMS layer to load data from a file"), null, false) {
+ public void actionPerformed(ActionEvent ev) {
+ Main.main.addLayer(new WMSLayer());
+ }
+ }));
+ setEnabledAll(menuEnabled);
+ }
+
+ /* add a default entry in case the URL does not yet exist */
+ private static void setDefault(Boolean force, String name, String url)
+ {
+ String testurl = url.replaceAll("=", "_");
+ wmsListDefault.put(name, url);
+
+ if(force && !Main.pref.getBoolean("wmsplugin.default."+testurl))
+ {
+ Main.pref.put("wmsplugin.default."+testurl, true);
+ int id = -1;
+ for(WMSInfo i : wmsList)
+ {
+ if(url.equals(i.url))
+ return;
+ if(i.prefid > id)
+ id = i.prefid;
+ }
+ WMSInfo newinfo = new WMSInfo(name, url, id+1);
+ newinfo.save();
+ wmsList.add(newinfo);
+ }
+ }
+
+ public static Grabber getGrabber(MapView mv, WMSLayer layer){
+ if(layer.baseURL.startsWith("html:"))
+ return new HTMLGrabber(mv, layer, cache);
+ else
+ return new WMSGrabber(mv, layer, cache);
+ }
+
+ private static void setEnabledAll(boolean isEnabled) {
+ for(int i=0; i < wmsJMenu.getItemCount(); i++) {
+ JMenuItem item = wmsJMenu.getItem(i);
+
+ if(item != null) item.setEnabled(isEnabled);
+ }
+ menuEnabled = isEnabled;
+ }
+
+ @Override
+ public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
+ if (oldFrame==null && newFrame!=null) {
+ setEnabledAll(true);
+ Main.map.addMapMode(new IconToggleButton
+ (new WMSAdjustAction(Main.map)));
+ } else if (oldFrame!=null && newFrame==null ) {
+ setEnabledAll(false);
+ }
+ }
+
+ @Override
+ public PreferenceSetting getPreferenceSetting() {
+ return new WMSPreferenceEditor();
+ }
+
+ static public String getPrefsPath()
+ {
+ return Main.pref.getPluginsDirectory().getPath() + "/wmsplugin/";
+ }
}
diff --git a/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java b/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java
index 2541c17..aa73c29 100644
--- a/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java
+++ b/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java
@@ -5,7 +5,6 @@ import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
@@ -21,7 +20,6 @@ import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
-import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.table.DefaultTableModel;
@@ -39,6 +37,8 @@ public class WMSPreferenceEditor implements PreferenceSetting {
JSpinner spinEast;
JSpinner spinNorth;
JSpinner spinSimConn;
+ JCheckBox remoteCheckBox;
+ boolean allowRemoteControl = true;
public void addGui(final PreferenceTabbedPane gui) {
JPanel p = gui.createPreferenceTab("wms", tr("WMS Plugin Preferences"), tr("Modify list of WMS servers displayed in the WMS plugin menu"));
@@ -55,7 +55,7 @@ public class WMSPreferenceEditor implements PreferenceSetting {
}
final DefaultTableModel modeldef = new DefaultTableModel(
- new String[]{tr("Menu Name (Default)"), tr("WMS URL (Default)")}, 0);
+ new String[]{tr("Menu Name (Default)"), tr("WMS URL (Default)")}, 0);
final JTable listdef = new JTable(modeldef){
@Override
public boolean isCellEditable(int row,int column){return false;}
@@ -75,20 +75,13 @@ public class WMSPreferenceEditor implements PreferenceSetting {
buttonPanel.add(add, GBC.std().insets(0,5,0,0));
add.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
- JPanel p = new JPanel(new GridBagLayout());
- p.add(new JLabel(tr("Menu Name")), GBC.std().insets(0,0,5,0));
- JTextField key = new JTextField(40);
- JTextField value = new JTextField(40);
- p.add(key, GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
- p.add(new JLabel(tr("WMS URL")), GBC.std().insets(0,0,5,0));
- p.add(value, GBC.eol().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+ AddWMSLayerPanel p = new AddWMSLayerPanel();
int answer = JOptionPane.showConfirmDialog(
gui, p,
- tr("Enter a menu name and WMS URL"),
- JOptionPane.OK_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE);
+ tr("Add WMS URL"),
+ JOptionPane.OK_CANCEL_OPTION);
if (answer == JOptionPane.OK_OPTION) {
- model.addRow(new String[]{key.getText(), value.getText()});
+ model.addRow(new String[]{p.getUrlName(), p.getUrl()});
}
}
});
@@ -119,7 +112,7 @@ public class WMSPreferenceEditor implements PreferenceSetting {
tr("Please select at least one row to copy."),
tr("Information"),
JOptionPane.INFORMATION_MESSAGE
- );
+ );
return;
}
@@ -154,9 +147,9 @@ public class WMSPreferenceEditor implements PreferenceSetting {
p.add(scrolldef, GBC.eol().insets(0,5,0,0).fill(GridBagConstraints.BOTH));
browser = new JComboBox(new String[]{
- "webkit-image {0}",
- "gnome-web-photo --mode=photo --format=png {0} /dev/stdout",
- "gnome-web-photo-fixed {0}",
+ "webkit-image {0}",
+ "gnome-web-photo --mode=photo --format=png {0} /dev/stdout",
+ "gnome-web-photo-fixed {0}",
"webkit-image-gtk {0}"});
browser.setEditable(true);
browser.setSelectedItem(Main.pref.get("wmsplugin.browser", "webkit-image {0}"));
@@ -166,11 +159,11 @@ public class WMSPreferenceEditor implements PreferenceSetting {
//Overlap
p.add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
- overlapCheckBox = new JCheckBox(tr("Overlap tiles"), WMSPlugin.doOverlap );
+ overlapCheckBox = new JCheckBox(tr("Overlap tiles"), WMSPlugin.PROP_OVERLAP.get() );
JLabel labelEast = new JLabel(tr("% of east:"));
JLabel labelNorth = new JLabel(tr("% of north:"));
- spinEast = new JSpinner(new SpinnerNumberModel(WMSPlugin.overlapEast, 1, 50, 1));
- spinNorth = new JSpinner(new SpinnerNumberModel(WMSPlugin.overlapNorth, 1, 50, 1));
+ spinEast = new JSpinner(new SpinnerNumberModel(WMSPlugin.PROP_OVERLAP_EAST.get(), 1, 50, 1));
+ spinNorth = new JSpinner(new SpinnerNumberModel(WMSPlugin.PROP_OVERLAP_NORTH.get(), 1, 50, 1));
JPanel overlapPanel = new JPanel(new FlowLayout());
overlapPanel.add(overlapCheckBox);
@@ -180,15 +173,24 @@ public class WMSPreferenceEditor implements PreferenceSetting {
overlapPanel.add(spinNorth);
p.add(overlapPanel);
-
+
// Simultaneous connections
p.add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
JLabel labelSimConn = new JLabel(tr("Simultaneous connections"));
- spinSimConn = new JSpinner(new SpinnerNumberModel(WMSPlugin.simultaneousConnections, 1, 30, 1));
+ spinSimConn = new JSpinner(new SpinnerNumberModel(WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.get(), 1, 30, 1));
JPanel overlapPanelSimConn = new JPanel(new FlowLayout());
overlapPanelSimConn.add(labelSimConn);
overlapPanelSimConn.add(spinSimConn);
- p.add(overlapPanelSimConn);
+ p.add(overlapPanelSimConn, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
+
+
+ allowRemoteControl = Main.pref.getBoolean("wmsplugin.remotecontrol", true);
+ remoteCheckBox = new JCheckBox(tr("Allow remote control (reqires remotecontrol plugin)"), allowRemoteControl );
+ JPanel remotePanel = new JPanel(new FlowLayout());
+ remotePanel.add(remoteCheckBox);
+
+ p.add(remotePanel);
+
}
public boolean ok() {
@@ -228,17 +230,15 @@ public class WMSPreferenceEditor implements PreferenceSetting {
if (change) WMSPlugin.refreshMenu();
- WMSPlugin.doOverlap = overlapCheckBox.getModel().isSelected();
- WMSPlugin.overlapEast = (Integer) spinEast.getModel().getValue();
- WMSPlugin.overlapNorth = (Integer) spinNorth.getModel().getValue();
- WMSPlugin.simultaneousConnections = (Integer) spinSimConn.getModel().getValue();
+ WMSPlugin.PROP_OVERLAP.put(overlapCheckBox.getModel().isSelected());
+ WMSPlugin.PROP_OVERLAP_EAST.put((Integer) spinEast.getModel().getValue());
+ WMSPlugin.PROP_OVERLAP_NORTH.put((Integer) spinNorth.getModel().getValue());
+ WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.put((Integer) spinSimConn.getModel().getValue());
+ allowRemoteControl = remoteCheckBox.getModel().isSelected();
- Main.pref.put("wmsplugin.url.overlap", String.valueOf(WMSPlugin.doOverlap));
- Main.pref.put("wmsplugin.url.overlapEast", String.valueOf(WMSPlugin.overlapEast));
- Main.pref.put("wmsplugin.url.overlapNorth", String.valueOf(WMSPlugin.overlapNorth));
+ Main.pref.put("wmsplugin.browser", browser.getEditor().getItem().toString());
- Main.pref.put("wmsplugin.browser", browser.getEditor().getItem().toString());
- Main.pref.put("wmsplugin.simultaneousConnections", String.valueOf(WMSPlugin.simultaneousConnections));
+ Main.pref.put("wmsplugin.remotecontrol", String.valueOf(allowRemoteControl));
return false;
}
diff --git a/wmsplugin/src/wmsplugin/WMSRemoteHandler.java b/wmsplugin/src/wmsplugin/WMSRemoteHandler.java
new file mode 100644
index 0000000..772eca5
--- /dev/null
+++ b/wmsplugin/src/wmsplugin/WMSRemoteHandler.java
@@ -0,0 +1,110 @@
+package wmsplugin;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.plugins.remotecontrol.PermissionPrefWithDefault;
+import org.openstreetmap.josm.plugins.remotecontrol.RequestHandler;
+import org.openstreetmap.josm.plugins.remotecontrol.RequestHandlerErrorException;
+
+public class WMSRemoteHandler extends RequestHandler {
+
+ public static final String command = "wms";
+
+ @Override
+ public String getPermissionMessage() {
+ return tr("Remote Control has been asked to load a WMS layer from the following URL:") +
+ "<br>" + args.get("url");
+ }
+
+ @Override
+ public PermissionPrefWithDefault getPermissionPref()
+ {
+ return new PermissionPrefWithDefault(
+ "wmsplugin.remotecontrol",
+ true,
+ "RemoteControl: WMS forbidden by preferences");
+ }
+
+ @Override
+ protected String[] getMandatoryParams()
+ {
+ return new String[] { "url" };
+ }
+
+ @Override
+ protected void handleRequest() throws RequestHandlerErrorException {
+ String url = args.get("url");
+ String title = args.get("title");
+ if((title == null) || (title.length() == 0))
+ {
+ title = "remote WMS";
+ }
+ String cookies = args.get("cookies");
+ if(cookies == null)
+ {
+ cookies = "";
+ }
+ WMSLayer wmsLayer = new WMSLayer(title, url, cookies);
+ Main.main.addLayer(wmsLayer);
+
+ }
+
+ @Override
+ public void parseArgs() {
+ StringTokenizer st = new StringTokenizer(request, "&?");
+ HashMap<String, String> args = new HashMap<String, String>();
+ // skip first element which is the command
+ if(st.hasMoreTokens()) st.nextToken();
+ while (st.hasMoreTokens()) {
+ String param = st.nextToken();
+ int eq = param.indexOf("=");
+ if (eq > -1)
+ {
+ String key = param.substring(0, eq);
+ /* "url=" terminates normal parameters
+ * and will be handled separately
+ */
+ if("url".equals(key)) break;
+
+ String value = param.substring(eq + 1);
+ // urldecode all normal values
+ try {
+ value = URLDecoder.decode(value, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ args.put(key,
+ value);
+ }
+ }
+ // url as second or later parameter
+ int urlpos = request.indexOf("&url=");
+ // url as first (and only) parameter
+ if(urlpos < 0) urlpos = request.indexOf("?url=");
+ // url found?
+ if(urlpos >= 0) {
+ // URL value
+ String value = request.substring(urlpos + 5);
+ // allow skipping URL decoding with urldecode=false
+ String urldecode = args.get("urldecode");
+ if((urldecode == null) || (Boolean.valueOf(urldecode) == true))
+ {
+ try {
+ value = URLDecoder.decode(value, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ args.put("url", value);
+ }
+ this.args = args;
+ }
+}
diff --git a/wmsplugin/src/wmsplugin/WMSRequest.java b/wmsplugin/src/wmsplugin/WMSRequest.java
new file mode 100644
index 0000000..8a5bcda
--- /dev/null
+++ b/wmsplugin/src/wmsplugin/WMSRequest.java
@@ -0,0 +1,101 @@
+package wmsplugin;
+
+import java.awt.image.BufferedImage;
+
+import wmsplugin.GeorefImage.State;
+
+public class WMSRequest implements Comparable<WMSRequest> {
+ private final int xIndex;
+ private final int yIndex;
+ private final double pixelPerDegree;
+ private final boolean real; // Download even if autodownloading is disabled
+ private int priority;
+ // Result
+ private State state;
+ private BufferedImage image;
+
+ public WMSRequest(int xIndex, int yIndex, double pixelPerDegree, boolean real) {
+ this.xIndex = xIndex;
+ this.yIndex = yIndex;
+ this.pixelPerDegree = pixelPerDegree;
+ this.real = real;
+ }
+
+ public void finish(State state, BufferedImage image) {
+ this.state = state;
+ this.image = image;
+ }
+
+ public int getXIndex() {
+ return xIndex;
+ }
+
+ public int getYIndex() {
+ return yIndex;
+ }
+
+ public double getPixelPerDegree() {
+ return pixelPerDegree;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(pixelPerDegree);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ result = prime * result + xIndex;
+ result = prime * result + yIndex;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ WMSRequest other = (WMSRequest) obj;
+ if (Double.doubleToLongBits(pixelPerDegree) != Double
+ .doubleToLongBits(other.pixelPerDegree))
+ return false;
+ if (xIndex != other.xIndex)
+ return false;
+ if (yIndex != other.yIndex)
+ return false;
+ return true;
+ }
+
+ public void setPriority(int priority) {
+ this.priority = priority;
+ }
+
+ public int getPriority() {
+ return priority;
+ }
+
+ public int compareTo(WMSRequest o) {
+ return priority - o.priority;
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public BufferedImage getImage() {
+ return image;
+ }
+
+ @Override
+ public String toString() {
+ return "WMSRequest [xIndex=" + xIndex + ", yIndex=" + yIndex
+ + ", pixelPerDegree=" + pixelPerDegree + "]";
+ }
+
+ public boolean isReal() {
+ return real;
+ }
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/josm-plugins.git
More information about the Pkg-grass-devel
mailing list