[josm-plugins] 208/369: Imported Upstream version 0.0.svn24632

Bas Couwenberg sebastic at xs4all.nl
Sat Oct 18 12:03:43 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 2d3e40973c8d066ce908852bdf92201b4a845413
Author: David Paleino <dapal at debian.org>
Date:   Wed Dec 8 19:45:03 2010 +0100

    Imported Upstream version 0.0.svn24632
---
 editgpx/build.xml                                  |   8 +-
 imagery/sources.cfg                                |  69 -----
 .../josm/plugins/imagery/ImageryLayer.java         | 134 +++++++-
 .../josm/plugins/imagery/ImageryLayerInfo.java     |   5 +
 .../josm/plugins/imagery/ImageryPlugin.java        |   7 +-
 .../plugins/imagery/ImageryPreferenceEditor.java   | 337 +++------------------
 .../josm/plugins/imagery/ImageryPreferences.java   |   6 +-
 .../plugins/imagery/ImageryProvidersPanel.java     | 218 ++++---------
 .../josm/plugins/imagery/OffsetBookmark.java       |  75 +++++
 .../josm/plugins/imagery/OffsetBookmarksPanel.java | 155 ++++++++++
 .../josm/plugins/imagery/tms/TMSLayer.java         |  24 +-
 .../josm/plugins/imagery/tms/TMSPreferences.java   |  17 ++
 .../josm/plugins/imagery/tms/TMSTileSource.java    |   2 +-
 .../plugins/imagery/tms/TMSTileSourceProvider.java |  41 +++
 .../josm/plugins/imagery/wms/GeorefImage.java      |   1 +
 .../josm/plugins/imagery/wms/HTMLGrabber.java      |   4 +-
 .../josm/plugins/imagery/wms/WMSAdapter.java       |  10 +-
 .../josm/plugins/imagery/wms/WMSGrabber.java       |  12 +-
 .../josm/plugins/imagery/wms/WMSLayer.java         |  11 +-
 svn-info.xml                                       |   8 +-
 wmsplugin/src/wmsplugin/WMSPreferenceEditor.java   |   2 +
 wmsplugin/webkit-image.cpp                         |   6 +-
 22 files changed, 579 insertions(+), 573 deletions(-)

diff --git a/editgpx/build.xml b/editgpx/build.xml
index 2801816..0810b6a 100644
--- a/editgpx/build.xml
+++ b/editgpx/build.xml
@@ -31,10 +31,8 @@
 	<property name="plugin.main.version" value="3408" />
 
 
-	<!-- <property name="josm"                   location="../../core/dist/josm-custom.jar"/> -->
-	<property name="josm"                   location="../JOSM/dist/josm-custom.jar"/>
-	<!-- <property name="plugin.dist.dir"        value="../../dist"/>-->
-	<property name="plugin.dist.dir"        value=".."/>
+	<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"/>
@@ -58,7 +56,7 @@
 				<attribute name="Plugin-Class" value="org.openstreetmap.josm.plugins.editgpx.EditGpxPlugin" />
 				<attribute name="Plugin-Date" value="${version.entry.commit.date}"/>
 				<attribute name="Plugin-Description" value="Allows the user to anonymize timestamps and delete parts of huge GPX tracks very fast." />
-				<attribute name="Plugin-Icon" value="images/mapmode/editgpx_mode.png"/>
+				<attribute name="Plugin-Icon" value="images/mapmode/editgpx_mode.png"/>
 				<attribute name="Plugin-Link" value="http://wiki.openstreetmap.org/wiki/JOSM/Plugins/EditGpx" />
 				<attribute name="Plugin-Mainversion" value="${plugin.main.version}" />
 				<attribute name="Plugin-Version" value="${version.entry.commit.revision}"/>
diff --git a/imagery/sources.cfg b/imagery/sources.cfg
deleted file mode 100644
index 3fd66c2..0000000
--- a/imagery/sources.cfg
+++ /dev/null
@@ -1,69 +0,0 @@
-# OUTDATED - only for old plugins
-# See http://josm.openstreetmap.de/wiki/Maps for newer data.
-#
-# FORMAT
-# default(true or false);Name;URL
-# NOTE: default items should be common and worldwide
-#
-true;Landsat;wms:http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&layers=global_mosaic&styles=&format=image/jpeg&
-true;Landsat (mirror);wms:http://irs.gis-lab.info/?layers=landsat&
-false;Open Aerial Map;wms:http://openaerialmap.org/wms/?VERSION=1.0&request=GetMap&layers=world&styles=&format=image/jpeg&
-#
-# different forms of imagery
-true;Bing sat;bing:bing
-true;Yahoo Sat;html:http://josm.openstreetmap.de/wmsplugin/YahooDirect.html?
-true;OpenStreetMap;tms:http://tile.openstreetmap.org/
-false;OpenCycleMap;tms:http://tile.opencyclemap.org/cycle/
-false;TilesAtHome;tms:http://tah.openstreetmap.org/Tiles/tile/
-#
-#
-# only for Germany
-false;Streets NRW Geofabrik.de;wms:http://tools.geofabrik.de/osmi/view/strassennrw/josmwms?
-#
-#
-# only for North America
-# Terraserver USCG - High resolution maps
-false;Terraserver Topo;wms:http://terraservice.net/ogcmap.ashx?version=1.1.1&request=GetMap&Layers=drg&styles=&format=image/jpeg&
-false;Terraserver Urban;wms:http://terraservice.net/ogcmap.ashx?version=1.1.1&request=GetMap&Layers=urbanarea&styles=&format=image/jpeg&
-#
-#
-# only for Czech Republic
-false;Czech CUZK:KM;wms: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;wms: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&
-#
-#
-# only for GB
-# fails with division by zero error
-false;NPE Maps;wms:http://nick.dev.openstreetmap.org/openpaths/freemap.php?layers=npe&
-false;NPE Maps (Tim);wms:http://dev.openstreetmap.org/~timsc/wms2/map.php?
-false;7th Series (OS7);wms:http://ooc.openstreetmap.org/wms/map.php?source=os7&
-#
-#
-# only for Japan
-false;MLIT Japan (ORTHO);wms:http://orthophoto.mlit.go.jp:8888/wms/service/wmsRasterTileMap?VERSION=1.3.0&REQUEST=GetMap&LAYERS=ORTHO&STYLES=Default&CRS=EPSG:4612&BBOX={s},{w},{n},{e}&WIDTH={width}&HEIGHT={height}&FORMAT=image/png&BGCOLOR=OxFFFFFF
-false;MLIT Japan (ORTHO01);wms:http://orthophoto.mlit.go.jp:8888/wms/service/wmsRasterTileMap?VERSION=1.3.0&REQUEST=GetMap&LAYERS=ORTHO01&STYLES=Default&CRS=EPSG:4612&BBOX={s},{w},{n},{e}&WIDTH={width}&HEIGHT={height}&FORMAT=image/png&BGCOLOR=OxFFFFFF
-false;MLIT Japan (ORTHO02);wms:http://orthophoto.mlit.go.jp:8888/wms/service/wmsRasterTileMap?VERSION=1.3.0&REQUEST=GetMap&LAYERS=ORTHO02&STYLES=Default&CRS=EPSG:4612&BBOX={s},{w},{n},{e}&WIDTH={width}&HEIGHT={height}&FORMAT=image/png&BGCOLOR=OxFFFFFF
-false;MLIT Japan (ORTHO03);wms:http://orthophoto.mlit.go.jp:8888/wms/service/wmsRasterTileMap?VERSION=1.3.0&REQUEST=GetMap&LAYERS=ORTHO03&STYLES=Default&CRS=EPSG:4612&BBOX={s},{w},{n},{e}&WIDTH={width}&HEIGHT={height}&FORMAT=image/png&BGCOLOR=OxFFFFFF
-#
-#
-# only for Italy
-false;Lodi - Italy;wms: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;wms: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;wms: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&
-#
-# only for France
-false;SPOTMaps (France);wms:http://spotmaps.youmapps.org/cgi-bin/mapserv?map=/home/ortho/ortho.map&service=wms&version=1.1.1&srs=EPSG:4326&request=GetMap&layers=spotmaps4osm&format=image/jpeg&FORMAT=image/jpeg&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&Layers=demo&;http://www.youmapps.org/licenses/EULA-OSM-J-{lang}.html
-#
-#
-# URLS must be designed to append arguments directly behind. So the URLS should either end with '?' or '&'
-# Following arguments are added: width, height, bbox, srs (projection method)
-# srs is only added when no srs is given already (In this case the projection is checked
-# and an error is issued when they mismatch).
-#
-# If more specific URL design is needed, then patterns are supported as well. If
-# patterns are found no other arguments are added:
-# {proj} is replaced by projection
-# {bbox} is replaced by bounding box using projected coordinates
-# {width} is requested display width
-# {height} is requested display height
-# {w},{s},{n},{e} are replaced by corresponding coordinates
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryLayer.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryLayer.java
index 3187256..39a6241 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryLayer.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryLayer.java
@@ -1,9 +1,28 @@
 package org.openstreetmap.josm.plugins.imagery;
 
-import java.awt.Toolkit;
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trc;
 
+import java.awt.Component;
+import java.awt.GridBagLayout;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
 import javax.swing.Icon;
 import javax.swing.ImageIcon;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.ProjectionBounds;
@@ -12,34 +31,33 @@ import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.plugins.imagery.ImageryInfo.ImageryType;
 import org.openstreetmap.josm.plugins.imagery.tms.TMSLayer;
 import org.openstreetmap.josm.plugins.imagery.wms.WMSLayer;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
 
 public abstract class ImageryLayer extends Layer {
     protected static final Icon icon =
         new ImageIcon(Toolkit.getDefaultToolkit().createImage(ImageryPlugin.class.getResource("/images/imagery_small.png")));
 
-    protected ImageryInfo info;
+    protected final ImageryInfo info;
     protected MapView mv;
 
     protected double dx = 0.0;
     protected double dy = 0.0;
 
+    protected int sharpenLevel;
+
     public ImageryLayer(ImageryInfo info) {
         super(info.getName());
         this.info = info;
         this.mv = Main.map.mapView;
+        this.sharpenLevel = ImageryPreferences.PROP_SHARPEN_LEVEL.get();
     }
 
-
     public double getPPD(){
         ProjectionBounds bounds = mv.getProjectionBounds();
         return mv.getWidth() / (bounds.max.east() - bounds.min.east());
     }
 
-    public void displace(double dx, double dy) {
-        this.dx += dx;
-        this.dy += dy;
-    }
-
     public double getDx() {
         return dx;
     }
@@ -48,6 +66,15 @@ public abstract class ImageryLayer extends Layer {
         return dy;
     }
 
+    public void setOffset(double dx, double dy) {
+        this.dx = dx;
+        this.dy = dy;
+    }
+
+    public void displace(double dx, double dy) {
+        setOffset(this.dx += dx, this.dy += dy);
+    }
+
     public ImageryInfo getInfo() {
         return info;
     }
@@ -78,4 +105,95 @@ public abstract class ImageryLayer extends Layer {
             return new TMSLayer(info);
         } else throw new AssertionError();
     }
+
+    class ApplyOffsetAction extends AbstractAction {
+        private OffsetBookmark b;
+        ApplyOffsetAction(OffsetBookmark b) {
+            super(b.name);
+            this.b = b;
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent arg0) {
+            setOffset(b.dx, b.dy);
+            Main.map.repaint();
+        }
+    }
+
+    class NewBookmarkAction extends AbstractAction {
+        private class BookmarkNamePanel extends JPanel {
+            public JTextField text = new JTextField();
+            public BookmarkNamePanel() {
+                super(new GridBagLayout());
+                add(new JLabel(tr("Bookmark name: ")),GBC.eol());
+                add(text,GBC.eol().fill(GBC.HORIZONTAL));
+            }
+        }
+        public NewBookmarkAction() {
+            super(tr("(save current)"));
+        }
+        @Override
+        public void actionPerformed(ActionEvent arg0) {
+            BookmarkNamePanel p = new BookmarkNamePanel();
+            int answer = JOptionPane.showConfirmDialog(
+                    Main.parent, p,
+                    tr("Add offset bookmark"),
+                    JOptionPane.OK_CANCEL_OPTION);
+            if (answer == JOptionPane.OK_OPTION) {
+                OffsetBookmark b =
+                    new OffsetBookmark(Main.proj,info.getName(),p.text.getText(),getDx(),getDy());
+                OffsetBookmark.allBookmarks.add(b);
+                OffsetBookmark.saveBookmarks();
+            }
+        }
+    }
+
+    class OffsetAction extends AbstractAction implements LayerAction {
+        @Override
+        public void actionPerformed(ActionEvent e) {
+        }
+        @Override
+        public Component createMenuComponent() {
+            JMenu menu = new JMenu(trc("layer", "Offset"));
+            menu.setIcon(ImageProvider.get("mapmode", "adjustimg"));
+            boolean haveCurrent = false;
+            for (OffsetBookmark b : OffsetBookmark.allBookmarks) {
+                if (!b.isUsable(ImageryLayer.this)) continue;
+                JCheckBoxMenuItem item = new JCheckBoxMenuItem(new ApplyOffsetAction(b));
+                if (b.dx == dx && b.dy == dy) {
+                    item.setSelected(true);
+                    haveCurrent = true;
+                }
+                menu.add(item);
+            }
+            if (!haveCurrent) {
+                menu.insert(new NewBookmarkAction(), 0);
+            }
+            return menu;
+        }
+        @Override
+        public boolean supportLayers(List<Layer> layers) {
+            return false;
+        }
+    }
+
+    public Action getOffsetAction() {
+        return new OffsetAction();
+    }
+
+    public BufferedImage sharpenImage(BufferedImage img) {
+        if (sharpenLevel <= 0) return img;
+        int width = img.getWidth(null);
+        int height = img.getHeight(null);
+        BufferedImage tmp = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        tmp.getGraphics().drawImage(img, 0, 0, null);
+        Kernel kernel;
+        if (sharpenLevel == 1) {
+            kernel = new Kernel(2, 2, new float[] { 4, -1, -1, -1});
+        } else {
+            kernel = new Kernel(3, 3, new float[] { -1, -1, -1, -1, 9, -1, -1, -1, -1});
+        }
+        BufferedImageOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
+        return op.filter(tmp, null);
+    }
 }
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryLayerInfo.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryLayerInfo.java
index a648566..83147d4 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryLayerInfo.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryLayerInfo.java
@@ -11,6 +11,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedList;
+import java.util.List;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.io.MirroredInputStream;
@@ -101,4 +102,8 @@ public class ImageryLayerInfo {
         }
         Main.pref.putArray("imagery.layers", coll);
     }
+
+    public List<ImageryInfo> getLayers() {
+        return Collections.unmodifiableList(layers);
+    }
 }
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPlugin.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPlugin.java
index 393a8be..8204b13 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPlugin.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPlugin.java
@@ -20,11 +20,13 @@ import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.gui.IconToggleButton;
 import org.openstreetmap.josm.gui.MainMenu;
 import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
 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 org.openstreetmap.josm.plugins.imagery.tms.TMSTileSourceProvider;
 import org.openstreetmap.josm.plugins.imagery.wms.Map_Rectifier_WMSmenuAction;
 import org.openstreetmap.josm.plugins.imagery.wms.WMSAdapter;
 import org.openstreetmap.josm.plugins.imagery.wms.WMSLayer;
@@ -39,7 +41,6 @@ public class ImageryPlugin extends Plugin {
     public static WMSAdapter wmsAdapter = new WMSAdapter();
 
     public ImageryLayerInfo info = new ImageryLayerInfo();
-
     // remember state of menu item to restore on changed preferences
     private boolean menuEnabled = false;
 
@@ -57,7 +58,7 @@ public class ImageryPlugin extends Plugin {
 
     /** RemoteControlPlugin older than this SVN revision is not compatible */
     final int REMOTECONTROL_MIN_REVISION = 22734;
-    /** WMSPlugin needs this specific API major version of RemoteControlPlugin */
+    /** Imagery Plugin needs this specific API major version of RemoteControlPlugin */
     final int REMOTECONTROL_NEED_API_MAJOR = 1;
     /** All API minor versions starting from this should be compatible */
     final int REMOTECONTROL_MIN_API_MINOR = 0;
@@ -204,8 +205,10 @@ public class ImageryPlugin extends Plugin {
         super(info);
         instance = this;
         this.info.load();
+        OffsetBookmark.loadBookmarks();
         refreshMenu();
         initRemoteControl();
+        SlippyMapBBoxChooser.addTileSourceProvider(new TMSTileSourceProvider());
     }
 
     public void addLayer(ImageryInfo info) {
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPreferenceEditor.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPreferenceEditor.java
index 92e1a43..2c99c48 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPreferenceEditor.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPreferenceEditor.java
@@ -1,22 +1,14 @@
 package org.openstreetmap.josm.plugins.imagery;
 
 import static org.openstreetmap.josm.tools.I18n.tr;
-import static org.openstreetmap.josm.tools.I18n.trc;
 
 import java.awt.Color;
 import java.awt.Component;
-import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.Font;
-import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.awt.event.MouseEvent;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Locale;
 
 import javax.swing.BorderFactory;
 import javax.swing.Box;
@@ -24,7 +16,6 @@ import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JColorChooser;
 import javax.swing.JComboBox;
-import javax.swing.JEditorPane;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
@@ -33,165 +24,43 @@ import javax.swing.JSeparator;
 import javax.swing.JSlider;
 import javax.swing.JSpinner;
 import javax.swing.JTabbedPane;
-import javax.swing.JTable;
 import javax.swing.SpinnerNumberModel;
-import javax.swing.table.DefaultTableModel;
-import javax.swing.table.TableColumnModel;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
-import org.openstreetmap.josm.plugins.imagery.ImageryInfo.ImageryType;
 import org.openstreetmap.josm.plugins.imagery.tms.TMSPreferences;
-import org.openstreetmap.josm.plugins.imagery.wms.AddWMSLayerPanel;
 import org.openstreetmap.josm.plugins.imagery.wms.WMSAdapter;
 import org.openstreetmap.josm.tools.ColorHelper;
 import org.openstreetmap.josm.tools.GBC;
 
 public class ImageryPreferenceEditor implements PreferenceSetting {
-    private ImageryLayerTableModel model;
-    private JComboBox browser;
+    ImageryProvidersPanel imageryProviders;
+
+    WMSAdapter wmsAdapter = ImageryPlugin.wmsAdapter;
+    ImageryPlugin plugin = ImageryPlugin.instance;
 
     // Common settings
     private Color colFadeColor;
     private JButton btnFadeColor;
     private JSlider fadeAmount = new JSlider(0, 100);
     private JCheckBox remoteCheckBox;
-    boolean allowRemoteControl = true;
+    private JComboBox sharpen;
+    private boolean allowRemoteControl = true;
 
     // WMS Settings
+    private JComboBox browser;
     JCheckBox overlapCheckBox;
     JSpinner spinEast;
     JSpinner spinNorth;
     JSpinner spinSimConn;
-    WMSAdapter wmsAdapter = ImageryPlugin.wmsAdapter;
-    ImageryPlugin plugin = ImageryPlugin.instance;
 
     //TMS settings controls
     private JCheckBox autozoomActive = new JCheckBox();
     private JCheckBox autoloadTiles = new JCheckBox();
     private JSpinner minZoomLvl;
     private JSpinner maxZoomLvl;
-
-
-    private JPanel buildImageryProvidersPanel(final PreferenceTabbedPane gui) {
-        final JPanel p = new JPanel(new GridBagLayout());
-        model = new ImageryLayerTableModel();
-        final JTable list = new JTable(model) {
-            @Override
-            public String getToolTipText(MouseEvent e) {
-                java.awt.Point p = e.getPoint();
-                return model.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
-            }
-        };
-        JScrollPane scroll = new JScrollPane(list);
-        p.add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
-        scroll.setPreferredSize(new Dimension(200, 200));
-
-        final ImageryDefaultLayerTableModel modeldef = new ImageryDefaultLayerTableModel();
-        final JTable listdef = new JTable(modeldef) {
-            @Override
-            public String getToolTipText(MouseEvent e) {
-                java.awt.Point p = e.getPoint();
-                return (String) modeldef.getValueAt(rowAtPoint(p), columnAtPoint(p));
-            }
-        };
-        JScrollPane scrolldef = new JScrollPane(listdef);
-        // scrolldef is added after the buttons so it's clearer the buttons
-        // control the top list and not the default one
-        scrolldef.setPreferredSize(new Dimension(200, 200));
-
-        TableColumnModel mod = listdef.getColumnModel();
-        mod.getColumn(1).setPreferredWidth(800);
-        mod.getColumn(0).setPreferredWidth(200);
-        mod = list.getColumnModel();
-        mod.getColumn(2).setPreferredWidth(50);
-        mod.getColumn(1).setPreferredWidth(800);
-        mod.getColumn(0).setPreferredWidth(200);
-
-        JPanel buttonPanel = new JPanel(new FlowLayout());
-
-        JButton add = new JButton(tr("Add"));
-        buttonPanel.add(add, GBC.std().insets(0, 5, 0, 0));
-        add.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                AddWMSLayerPanel p = new AddWMSLayerPanel();
-                int answer = JOptionPane.showConfirmDialog(
-                        gui, p,
-                        tr("Add Imagery URL"),
-                        JOptionPane.OK_CANCEL_OPTION);
-                if (answer == JOptionPane.OK_OPTION) {
-                    model.addRow(new ImageryInfo(p.getUrlName(), p.getUrl()));
-                }
-            }
-        });
-
-        JButton delete = new JButton(tr("Delete"));
-        buttonPanel.add(delete, GBC.std().insets(0, 5, 0, 0));
-        delete.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                if (list.getSelectedRow() == -1)
-                    JOptionPane.showMessageDialog(gui, tr("Please select the row to delete."));
-                else {
-                    Integer i;
-                    while ((i = list.getSelectedRow()) != -1)
-                        model.removeRow(i);
-                }
-            }
-        });
-
-        JButton copy = new JButton(tr("Copy Selected Default(s)"));
-        buttonPanel.add(copy, GBC.std().insets(0, 5, 0, 0));
-        copy.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                int[] lines = listdef.getSelectedRows();
-                if (lines.length == 0) {
-                    JOptionPane.showMessageDialog(
-                            gui,
-                            tr("Please select at least one row to copy."),
-                            tr("Information"),
-                            JOptionPane.INFORMATION_MESSAGE);
-                    return;
-                }
-
-                outer: for (int i = 0; i < lines.length; i++) {
-                    ImageryInfo info = modeldef.getRow(lines[i]);
-
-                    // Check if an entry with exactly the same values already
-                    // exists
-                    for (int j = 0; j < model.getRowCount(); j++) {
-                        if (info.equalsBaseValues(model.getRow(j))) {
-                            // Select the already existing row so the user has
-                            // some feedback in case an entry exists
-                            list.getSelectionModel().setSelectionInterval(j, j);
-                            list.scrollRectToVisible(list.getCellRect(j, 0, true));
-                            continue outer;
-                        }
-                    }
-
-                    if (info.eulaAcceptanceRequired != null) {
-                        if (!confirmeEulaAcceptance(gui, info.eulaAcceptanceRequired))
-                            continue outer;
-                    }
-
-                    model.addRow(new ImageryInfo(info));
-                    int lastLine = model.getRowCount() - 1;
-                    list.getSelectionModel().setSelectionInterval(lastLine, lastLine);
-                    list.scrollRectToVisible(list.getCellRect(lastLine, 0, true));
-                }
-            }
-        });
-
-        p.add(buttonPanel);
-        p.add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
-        // Add default item list
-        p.add(scrolldef, GBC.eol().insets(0, 5, 0, 0).fill(GridBagConstraints.BOTH));
-
-        return p;
-    }
+    private JCheckBox addToSlippyMapChosser = new JCheckBox();
 
     private JPanel buildCommonSettingsPanel(final PreferenceTabbedPane gui) {
         final JPanel p = new JPanel(new GridBagLayout());
@@ -231,6 +100,15 @@ public class ImageryPreferenceEditor implements PreferenceSetting {
         remoteCheckBox = new JCheckBox(tr("Allow remote control (reqires remotecontrol plugin)"), allowRemoteControl);
         p.add(remoteCheckBox,GBC.eol().fill(GBC.HORIZONTAL));
 
+        this.sharpen = new JComboBox(new String[] {
+                tr("None"),
+                tr("Soft"),
+                tr("Strong")});
+        p.add(new JLabel(tr("Sharpen (requires layer re-add): ")));
+        p.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
+        p.add(this.sharpen, GBC.std().fill(GBC.HORIZONTAL));
+        this.sharpen.setSelectedIndex(ImageryPreferences.PROP_SHARPEN_LEVEL.get());
+
         return p;
     }
 
@@ -242,7 +120,7 @@ public class ImageryPreferenceEditor implements PreferenceSetting {
                 "gnome-web-photo-fixed {0}",
                 "webkit-image-gtk {0}"});
         browser.setEditable(true);
-        browser.setSelectedItem(Main.pref.get("wmsplugin.browser", "webkit-image {0}"));
+        browser.setSelectedItem(wmsAdapter.PROP_BROWSER.get());
         p.add(new JLabel(tr("Downloader:")), GBC.eol().fill(GBC.HORIZONTAL));
         p.add(browser);
 
@@ -278,6 +156,7 @@ public class ImageryPreferenceEditor implements PreferenceSetting {
 
     private JPanel buildTMSSettingsPanel() {
         JPanel tmsTab = new JPanel(new GridBagLayout());
+
         minZoomLvl = new JSpinner(new SpinnerNumberModel(TMSPreferences.DEFAULT_MIN_ZOOM, TMSPreferences.MIN_ZOOM, TMSPreferences.MAX_ZOOM, 1));
         maxZoomLvl = new JSpinner(new SpinnerNumberModel(TMSPreferences.DEFAULT_MAX_ZOOM, TMSPreferences.MIN_ZOOM, TMSPreferences.MAX_ZOOM, 1));
 
@@ -297,10 +176,13 @@ public class ImageryPreferenceEditor implements PreferenceSetting {
         tmsTab.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
         tmsTab.add(this.maxZoomLvl, GBC.eol().fill(GBC.HORIZONTAL));
 
-        tmsTab.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
+        tmsTab.add(new JLabel(tr("Add to slippymap chooser: ")), GBC.std());
+        tmsTab.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
+        tmsTab.add(addToSlippyMapChosser, GBC.eol().fill(GBC.HORIZONTAL));
 
         this.autozoomActive.setSelected(TMSPreferences.PROP_DEFAULT_AUTOZOOM.get());
         this.autoloadTiles.setSelected(TMSPreferences.PROP_DEFAULT_AUTOLOAD.get());
+        this.addToSlippyMapChosser.setSelected(TMSPreferences.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get());
         this.maxZoomLvl.setValue(TMSPreferences.getMaxZoomLvl(null));
         this.minZoomLvl.setValue(TMSPreferences.getMinZoomLvl(null));
         return tmsTab;
@@ -330,17 +212,22 @@ public class ImageryPreferenceEditor implements PreferenceSetting {
     public void addGui(final PreferenceTabbedPane gui) {
         JPanel p = gui.createPreferenceTab("imagery", tr("Imagery Preferences"), tr("Modify list of imagery layers displayed in the Imagery menu"));
         JTabbedPane pane = new JTabbedPane();
-        pane.add(buildImageryProvidersPanel(gui));
+        imageryProviders = new ImageryProvidersPanel(gui, plugin.info);
+        pane.add(imageryProviders);
         pane.add(buildSettingsPanel(gui));
+        pane.add(new OffsetBookmarksPanel(gui));
         pane.setTitleAt(0, tr("Imagery providers"));
         pane.setTitleAt(1, tr("Settings"));
+        pane.setTitleAt(2, tr("Offset bookmarks"));
         p.add(pane,GBC.std().fill(GBC.BOTH));
     }
 
     @Override
     public boolean ok() {
+        boolean restartRequired = false;
         plugin.info.save();
         plugin.refreshMenu();
+        OffsetBookmark.saveBookmarks();
 
         wmsAdapter.PROP_OVERLAP.put(overlapCheckBox.getModel().isSelected());
         wmsAdapter.PROP_OVERLAP_EAST.put((Integer) spinEast.getModel().getValue());
@@ -348,19 +235,22 @@ public class ImageryPreferenceEditor implements PreferenceSetting {
         wmsAdapter.PROP_SIMULTANEOUS_CONNECTIONS.put((Integer) spinSimConn.getModel().getValue());
         allowRemoteControl = remoteCheckBox.getModel().isSelected();
 
-        Main.pref.put("wmsplugin.browser", browser.getEditor().getItem().toString());
-
+        Main.pref.put("imagery.wms.browser", browser.getEditor().getItem().toString());
 
+        if (TMSPreferences.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get() != this.addToSlippyMapChosser.isSelected())
+            restartRequired = true;
+        TMSPreferences.PROP_ADD_TO_SLIPPYMAP_CHOOSER.put(this.addToSlippyMapChosser.isSelected());
         TMSPreferences.PROP_DEFAULT_AUTOZOOM.put(this.autozoomActive.isSelected());
         TMSPreferences.PROP_DEFAULT_AUTOLOAD.put(this.autoloadTiles.isSelected());
         TMSPreferences.setMaxZoomLvl((Integer)this.maxZoomLvl.getValue());
         TMSPreferences.setMinZoomLvl((Integer)this.minZoomLvl.getValue());
 
-        ImageryPreferences.PROP_REMOTE_CONTROL.put(allowRemoteControl);
         ImageryPreferences.PROP_FADE_AMOUNT.put(this.fadeAmount.getValue());
         ImageryPreferences.setFadeColor(this.colFadeColor);
+        ImageryPreferences.PROP_REMOTE_CONTROL.put(allowRemoteControl);
+        ImageryPreferences.PROP_SHARPEN_LEVEL.put(sharpen.getSelectedIndex());
 
-        return false;
+        return restartRequired;
     }
 
     /**
@@ -372,13 +262,13 @@ public class ImageryPreferenceEditor implements PreferenceSetting {
      *            The server URL
      */
     public void setServerUrl(String server, String url) {
-        for (int i = 0; i < model.getRowCount(); i++) {
-            if (server.equals(model.getValueAt(i, 0).toString())) {
-                model.setValueAt(url, i, 1);
+        for (int i = 0; i < imageryProviders.model.getRowCount(); i++) {
+            if (server.equals(imageryProviders.model.getValueAt(i, 0).toString())) {
+                imageryProviders.model.setValueAt(url, i, 1);
                 return;
             }
         }
-        model.addRow(new String[] { server, url });
+        imageryProviders.model.addRow(new String[] { server, url });
     }
 
     /**
@@ -389,152 +279,11 @@ public class ImageryPreferenceEditor implements PreferenceSetting {
      * @return The server URL
      */
     public String getServerUrl(String server) {
-        for (int i = 0; i < model.getRowCount(); i++) {
-            if (server.equals(model.getValueAt(i, 0).toString())) {
-                return model.getValueAt(i, 1).toString();
+        for (int i = 0; i < imageryProviders.model.getRowCount(); i++) {
+            if (server.equals(imageryProviders.model.getValueAt(i, 0).toString())) {
+                return imageryProviders.model.getValueAt(i, 1).toString();
             }
         }
         return null;
     }
-
-    /**
-     * The table model for the WMS layer
-     *
-     */
-    class ImageryLayerTableModel extends DefaultTableModel {
-        public ImageryLayerTableModel() {
-            setColumnIdentifiers(new String[] { tr("Menu Name"), tr("Imagery URL"), trc("layer", "Zoom") });
-        }
-
-        public ImageryInfo getRow(int row) {
-            return plugin.info.layers.get(row);
-        }
-
-        public void addRow(ImageryInfo i) {
-            plugin.info.add(i);
-            int p = getRowCount() - 1;
-            fireTableRowsInserted(p, p);
-        }
-
-        @Override
-        public void removeRow(int i) {
-            plugin.info.remove(getRow(i));
-            fireTableRowsDeleted(i, i);
-        }
-
-        @Override
-        public int getRowCount() {
-            return plugin.info.layers.size();
-        }
-
-        @Override
-        public Object getValueAt(int row, int column) {
-            ImageryInfo info = plugin.info.layers.get(row);
-            switch (column) {
-            case 0:
-                return info.name;
-            case 1:
-                return info.getFullURL();
-            case 2:
-                return (info.imageryType == ImageryType.WMS) ? (info.pixelPerDegree == 0.0 ? "" : info.pixelPerDegree)
-                                                             : (info.maxZoom == 0 ? "" : info.maxZoom);
-            }
-            return null;
-        }
-
-        @Override
-        public void setValueAt(Object o, int row, int column) {
-            ImageryInfo info = plugin.info.layers.get(row);
-            switch (column) {
-            case 0:
-                info.name = (String) o;
-            case 1:
-                info.setURL((String)o);
-            case 2:
-                info.pixelPerDegree = 0;
-                info.maxZoom = 0;
-                try {
-                    if(info.imageryType == ImageryType.WMS)
-                        info.pixelPerDegree = Double.parseDouble((String) o);
-                    else
-                        info.maxZoom = Integer.parseInt((String) o);
-                } catch (NumberFormatException e) {
-                }
-            }
-        }
-
-        @Override
-        public boolean isCellEditable(int row, int column) {
-            return true;
-        }
-    }
-
-    /**
-     * The table model for the WMS layer
-     *
-     */
-    class ImageryDefaultLayerTableModel extends DefaultTableModel {
-        public ImageryDefaultLayerTableModel() {
-            setColumnIdentifiers(new String[] { tr("Menu Name (Default)"), tr("Imagery URL (Default)") });
-        }
-
-        public ImageryInfo getRow(int row) {
-            return plugin.info.defaultLayers.get(row);
-        }
-
-        @Override
-        public int getRowCount() {
-            return plugin.info.defaultLayers.size();
-        }
-
-        @Override
-        public Object getValueAt(int row, int column) {
-            ImageryInfo info = plugin.info.defaultLayers.get(row);
-            switch (column) {
-            case 0:
-                return info.name;
-            case 1:
-                return info.getFullURL();
-            }
-            return null;
-        }
-
-        @Override
-        public boolean isCellEditable(int row, int column) {
-            return false;
-        }
-    }
-
-    private boolean confirmeEulaAcceptance(PreferenceTabbedPane gui, String eulaUrl) {
-        URL url = null;
-        try {
-            url = new URL(eulaUrl.replaceAll("\\{lang\\}", Locale.getDefault().toString()));
-            JEditorPane htmlPane = null;
-            try {
-                htmlPane = new JEditorPane(url);
-            } catch (IOException e1) {
-                // give a second chance with a default Locale 'en'
-                try {
-                    url = new URL(eulaUrl.replaceAll("\\{lang\\}", "en"));
-                    htmlPane = new JEditorPane(url);
-                } catch (IOException e2) {
-                    JOptionPane.showMessageDialog(gui ,tr("EULA license URL not available: {0}", eulaUrl));
-                    return false;
-                }
-            }
-            Box box = Box.createVerticalBox();
-            htmlPane.setEditable(false);
-            JScrollPane scrollPane = new JScrollPane(htmlPane);
-            scrollPane.setPreferredSize(new Dimension(400, 400));
-            box.add(scrollPane);
-            int option = JOptionPane.showConfirmDialog(Main.parent, box, tr("Please abort if you are not sure"), JOptionPane.YES_NO_OPTION,
-                    JOptionPane.WARNING_MESSAGE);
-            if (option == JOptionPane.YES_OPTION) {
-                return true;
-            }
-        } catch (MalformedURLException e2) {
-            JOptionPane.showMessageDialog(gui ,tr("Malformed URL for the EULA licence: {0}", eulaUrl));
-        }
-        return false;
-    }
 }
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPreferences.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPreferences.java
index c55505d..39620a1 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPreferences.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryPreferences.java
@@ -7,9 +7,9 @@ import org.openstreetmap.josm.data.preferences.BooleanProperty;
 import org.openstreetmap.josm.data.preferences.IntegerProperty;
 
 public class ImageryPreferences {
-
     public static final BooleanProperty PROP_REMOTE_CONTROL = new BooleanProperty("imagery.remotecontrol", true);
     public static final IntegerProperty PROP_FADE_AMOUNT = new IntegerProperty("imagery.fade_amount", 0);
+    public static final IntegerProperty PROP_SHARPEN_LEVEL = new IntegerProperty("imagery.sharpen_level", 0);
 
     public static Color getFadeColor() {
         return Main.pref.getColor("imagery.fade", Color.white);
@@ -24,5 +24,7 @@ public class ImageryPreferences {
         Main.pref.putColor("imagery.fade", color);
     }
 
-
+    public static boolean isUrlWithPatterns(String url) {
+        return url != null && url.contains("{") && url.contains("}");
+    }
 }
diff --git a/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryProvidersPanel.java
similarity index 54%
copy from wmsplugin/src/wmsplugin/WMSPreferenceEditor.java
copy to imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryProvidersPanel.java
index 7e2af13..f9744d6 100644
--- a/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/ImageryProvidersPanel.java
@@ -1,4 +1,4 @@
-package wmsplugin;
+package org.openstreetmap.josm.plugins.imagery;
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 import static org.openstreetmap.josm.tools.I18n.trc;
@@ -6,6 +6,7 @@ import static org.openstreetmap.josm.tools.I18n.trc;
 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.awt.event.MouseEvent;
@@ -16,52 +17,41 @@ import java.util.Locale;
 
 import javax.swing.Box;
 import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
 import javax.swing.JEditorPane;
-import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
-import javax.swing.JSpinner;
 import javax.swing.JTable;
-import javax.swing.SpinnerNumberModel;
 import javax.swing.table.DefaultTableModel;
 import javax.swing.table.TableColumnModel;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.plugins.imagery.ImageryInfo.ImageryType;
+import org.openstreetmap.josm.plugins.imagery.wms.AddWMSLayerPanel;
 import org.openstreetmap.josm.tools.GBC;
 
-public class WMSPreferenceEditor implements PreferenceSetting {
-    private WMSLayerTableModel model;
-    private JComboBox browser;
+public class ImageryProvidersPanel extends JPanel {
+    final ImageryLayerTableModel model;
+    private final ImageryLayerInfo layerInfo;
 
-    JCheckBox overlapCheckBox;
-    JSpinner spinEast;
-    JSpinner spinNorth;
-    JSpinner spinSimConn;
-    JCheckBox remoteCheckBox;
-    boolean allowRemoteControl = true;
-    WMSPlugin plugin = WMSPlugin.instance;
+    public ImageryProvidersPanel(final PreferenceTabbedPane gui, ImageryLayerInfo layerInfo) {
+        super(new GridBagLayout());
+        this.layerInfo = layerInfo;
+        this.model = new ImageryLayerTableModel();
 
-    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"));
-
-        model = new WMSLayerTableModel();
         final JTable list = new JTable(model) {
             @Override
             public String getToolTipText(MouseEvent e) {
                 java.awt.Point p = e.getPoint();
-                return (String) model.getValueAt(rowAtPoint(p), columnAtPoint(p));
+                return model.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
             }
         };
         JScrollPane scroll = new JScrollPane(list);
-        p.add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
+        add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
         scroll.setPreferredSize(new Dimension(200, 200));
 
-        final WMSDefaultLayerTableModel modeldef = new WMSDefaultLayerTableModel();
+        final ImageryDefaultLayerTableModel modeldef = new ImageryDefaultLayerTableModel();
         final JTable listdef = new JTable(modeldef) {
             @Override
             public String getToolTipText(MouseEvent e) {
@@ -87,14 +77,15 @@ public class WMSPreferenceEditor implements PreferenceSetting {
         JButton add = new JButton(tr("Add"));
         buttonPanel.add(add, GBC.std().insets(0, 5, 0, 0));
         add.addActionListener(new ActionListener() {
+            @Override
             public void actionPerformed(ActionEvent e) {
                 AddWMSLayerPanel p = new AddWMSLayerPanel();
                 int answer = JOptionPane.showConfirmDialog(
                         gui, p,
-                        tr("Add WMS URL"),
+                        tr("Add Imagery URL"),
                         JOptionPane.OK_CANCEL_OPTION);
                 if (answer == JOptionPane.OK_OPTION) {
-                    model.addRow(new WMSInfo(p.getUrlName(), p.getUrl()));
+                    model.addRow(new ImageryInfo(p.getUrlName(), p.getUrl()));
                 }
             }
         });
@@ -102,6 +93,7 @@ public class WMSPreferenceEditor implements PreferenceSetting {
         JButton delete = new JButton(tr("Delete"));
         buttonPanel.add(delete, GBC.std().insets(0, 5, 0, 0));
         delete.addActionListener(new ActionListener() {
+            @Override
             public void actionPerformed(ActionEvent e) {
                 if (list.getSelectedRow() == -1)
                     JOptionPane.showMessageDialog(gui, tr("Please select the row to delete."));
@@ -116,6 +108,7 @@ public class WMSPreferenceEditor implements PreferenceSetting {
         JButton copy = new JButton(tr("Copy Selected Default(s)"));
         buttonPanel.add(copy, GBC.std().insets(0, 5, 0, 0));
         copy.addActionListener(new ActionListener() {
+            @Override
             public void actionPerformed(ActionEvent e) {
                 int[] lines = listdef.getSelectedRows();
                 if (lines.length == 0) {
@@ -128,7 +121,7 @@ public class WMSPreferenceEditor implements PreferenceSetting {
                 }
 
                 outer: for (int i = 0; i < lines.length; i++) {
-                    WMSInfo info = modeldef.getRow(lines[i]);
+                    ImageryInfo info = modeldef.getRow(lines[i]);
 
                     // Check if an entry with exactly the same values already
                     // exists
@@ -143,11 +136,11 @@ public class WMSPreferenceEditor implements PreferenceSetting {
                     }
 
                     if (info.eulaAcceptanceRequired != null) {
-                        if (!confirmeEulaAcceptance(gui, info.eulaAcceptanceRequired))
+                        if (!confirmEulaAcceptance(gui, info.eulaAcceptanceRequired))
                             continue outer;
                     }
 
-                    model.addRow(new WMSInfo(info));
+                    model.addRow(new ImageryInfo(info));
                     int lastLine = model.getRowCount() - 1;
                     list.getSelectionModel().setSelectionInterval(lastLine, lastLine);
                     list.scrollRectToVisible(list.getCellRect(lastLine, 0, true));
@@ -155,188 +148,109 @@ public class WMSPreferenceEditor implements PreferenceSetting {
             }
         });
 
-        p.add(buttonPanel);
-        p.add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
+        add(buttonPanel);
+        add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
         // Add default item list
-        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-gtk {0}"});
-        browser.setEditable(true);
-        browser.setSelectedItem(Main.pref.get("wmsplugin.browser", "webkit-image {0}"));
-        p.add(new JLabel(tr("Downloader:")), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
-        p.add(browser);
-
-        // Overlap
-        p.add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
-
-        overlapCheckBox = new JCheckBox(tr("Overlap tiles"), plugin.PROP_OVERLAP.get());
-        JLabel labelEast = new JLabel(tr("% of east:"));
-        JLabel labelNorth = new JLabel(tr("% of north:"));
-        spinEast = new JSpinner(new SpinnerNumberModel(plugin.PROP_OVERLAP_EAST.get(), 1, 50, 1));
-        spinNorth = new JSpinner(new SpinnerNumberModel(plugin.PROP_OVERLAP_NORTH.get(), 1, 50, 1));
-
-        JPanel overlapPanel = new JPanel(new FlowLayout());
-        overlapPanel.add(overlapCheckBox);
-        overlapPanel.add(labelEast);
-        overlapPanel.add(spinEast);
-        overlapPanel.add(labelNorth);
-        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(plugin.PROP_SIMULTANEOUS_CONNECTIONS.get(), 1, 30, 1));
-        JPanel overlapPanelSimConn = new JPanel(new FlowLayout());
-        overlapPanelSimConn.add(labelSimConn);
-        overlapPanelSimConn.add(spinSimConn);
-        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() {
-        plugin.info.save();
-        plugin.refreshMenu();
-
-        plugin.PROP_OVERLAP.put(overlapCheckBox.getModel().isSelected());
-        plugin.PROP_OVERLAP_EAST.put((Integer) spinEast.getModel().getValue());
-        plugin.PROP_OVERLAP_NORTH.put((Integer) spinNorth.getModel().getValue());
-        plugin.PROP_SIMULTANEOUS_CONNECTIONS.put((Integer) spinSimConn.getModel().getValue());
-        allowRemoteControl = remoteCheckBox.getModel().isSelected();
-
-        Main.pref.put("wmsplugin.browser", browser.getEditor().getItem().toString());
-
-        Main.pref.put("wmsplugin.remotecontrol", String.valueOf(allowRemoteControl));
-        return false;
-    }
-
-    /**
-     * Updates a server URL in the preferences dialog. Used by other plugins.
-     *
-     * @param server
-     *            The server name
-     * @param url
-     *            The server URL
-     */
-    public void setServerUrl(String server, String url) {
-        for (int i = 0; i < model.getRowCount(); i++) {
-            if (server.equals(model.getValueAt(i, 0).toString())) {
-                model.setValueAt(url, i, 1);
-                return;
-            }
-        }
-        model.addRow(new String[] { server, url });
+        add(scrolldef, GBC.eol().insets(0, 5, 0, 0).fill(GridBagConstraints.BOTH));
     }
 
     /**
-     * Gets a server URL in the preferences dialog. Used by other plugins.
-     *
-     * @param server
-     *            The server name
-     * @return The server URL
+     * The table model for imagery layer list
      */
-    public String getServerUrl(String server) {
-        for (int i = 0; i < model.getRowCount(); i++) {
-            if (server.equals(model.getValueAt(i, 0).toString())) {
-                return model.getValueAt(i, 1).toString();
-            }
+    class ImageryLayerTableModel extends DefaultTableModel {
+        public ImageryLayerTableModel() {
+            setColumnIdentifiers(new String[] { tr("Menu Name"), tr("Imagery URL"), trc("layer", "Zoom") });
         }
-        return null;
-    }
 
-    /**
-     * The table model for the WMS layer
-     *
-     */
-    class WMSLayerTableModel extends DefaultTableModel {
-        public WMSLayerTableModel() {
-            setColumnIdentifiers(new String[] { tr("Menu Name"), tr("WMS URL"), trc("layer", "Zoom") });
+        public ImageryInfo getRow(int row) {
+            return layerInfo.layers.get(row);
         }
 
-        public WMSInfo getRow(int row) {
-            return plugin.info.layers.get(row);
-        }
-
-        public void addRow(WMSInfo i) {
-            plugin.info.add(i);
+        public void addRow(ImageryInfo i) {
+            layerInfo.add(i);
             int p = getRowCount() - 1;
             fireTableRowsInserted(p, p);
         }
 
         @Override
         public void removeRow(int i) {
-            plugin.info.remove(getRow(i));
+            layerInfo.remove(getRow(i));
             fireTableRowsDeleted(i, i);
         }
 
         @Override
         public int getRowCount() {
-            return plugin.info.layers.size();
+            return layerInfo.layers.size();
         }
 
         @Override
         public Object getValueAt(int row, int column) {
-            WMSInfo info = plugin.info.layers.get(row);
+            ImageryInfo info = layerInfo.layers.get(row);
             switch (column) {
             case 0:
                 return info.name;
             case 1:
                 return info.getFullURL();
             case 2:
-                return info.pixelPerDegree == 0.0 ? "" : info.pixelPerDegree;
+                return (info.imageryType == ImageryType.WMS) ? (info.pixelPerDegree == 0.0 ? "" : info.pixelPerDegree)
+                                                             : (info.maxZoom == 0 ? "" : info.maxZoom);
+            default:
+                throw new ArrayIndexOutOfBoundsException();
             }
-            return null;
         }
 
         @Override
         public void setValueAt(Object o, int row, int column) {
-            WMSInfo info = plugin.info.layers.get(row);
+            ImageryInfo info = layerInfo.layers.get(row);
             switch (column) {
             case 0:
                 info.name = (String) o;
+                break;
             case 1:
                 info.setURL((String)o);
+                break;
+            case 2:
+                info.pixelPerDegree = 0;
+                info.maxZoom = 0;
+                try {
+                    if(info.imageryType == ImageryType.WMS)
+                        info.pixelPerDegree = Double.parseDouble((String) o);
+                    else
+                        info.maxZoom = Integer.parseInt((String) o);
+                } catch (NumberFormatException e) {
+                }
+                break;
+            default:
+                throw new ArrayIndexOutOfBoundsException();
             }
         }
 
         @Override
         public boolean isCellEditable(int row, int column) {
-            return (column != 2);
+            return true;
         }
     }
 
     /**
-     * The table model for the WMS layer
-     *
+     * The table model for the default imagery layer list
      */
-    class WMSDefaultLayerTableModel extends DefaultTableModel {
-        public WMSDefaultLayerTableModel() {
-            setColumnIdentifiers(new String[] { tr("Menu Name (Default)"), tr("WMS URL (Default)") });
+    class ImageryDefaultLayerTableModel extends DefaultTableModel {
+        public ImageryDefaultLayerTableModel() {
+            setColumnIdentifiers(new String[] { tr("Menu Name (Default)"), tr("Imagery URL (Default)") });
         }
 
-        public WMSInfo getRow(int row) {
-            return plugin.info.defaultLayers.get(row);
+        public ImageryInfo getRow(int row) {
+            return layerInfo.defaultLayers.get(row);
         }
 
         @Override
         public int getRowCount() {
-            return plugin.info.defaultLayers.size();
+            return layerInfo.defaultLayers.size();
         }
 
         @Override
         public Object getValueAt(int row, int column) {
-            WMSInfo info = plugin.info.defaultLayers.get(row);
+            ImageryInfo info = layerInfo.defaultLayers.get(row);
             switch (column) {
             case 0:
                 return info.name;
@@ -352,7 +266,7 @@ public class WMSPreferenceEditor implements PreferenceSetting {
         }
     }
 
-    private boolean confirmeEulaAcceptance(PreferenceTabbedPane gui, String eulaUrl) {
+    private boolean confirmEulaAcceptance(PreferenceTabbedPane gui, String eulaUrl) {
         URL url = null;
         try {
             url = new URL(eulaUrl.replaceAll("\\{lang\\}", Locale.getDefault().toString()));
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/OffsetBookmark.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/OffsetBookmark.java
new file mode 100644
index 0000000..a1a4cca
--- /dev/null
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/OffsetBookmark.java
@@ -0,0 +1,75 @@
+package org.openstreetmap.josm.plugins.imagery;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.projection.Projection;
+
+public class OffsetBookmark {
+    public static List<OffsetBookmark> allBookmarks = new ArrayList<OffsetBookmark>();
+
+    public Projection proj;
+    public String layerName;
+    public String name;
+    public double dx, dy;
+
+    public boolean isUsable(ImageryLayer layer) {
+        return Main.proj.getClass() == proj.getClass() &&
+                layer.getInfo().getName().equals(layerName);
+    }
+    public OffsetBookmark(Projection proj, String layerName, String name, double dx, double dy) {
+        this.proj = proj;
+        this.layerName = layerName;
+        this.name = name;
+        this.dx = dx;
+        this.dy = dy;
+    }
+
+    public OffsetBookmark(Collection<String> list) {
+        ArrayList<String> array = new ArrayList<String>(list);
+        String projectionName = array.get(0);
+        for (Projection proj : Projection.allProjections) {
+            if (proj.getCacheDirectoryName().equals(projectionName)) {
+                this.proj = proj;
+                break;
+            }
+        }
+        if (this.proj == null)
+            throw new IllegalStateException(tr("Projection ''{0}'' not found", projectionName));
+        this.layerName = array.get(1);
+        this.name = array.get(2);
+        this.dx = Double.valueOf(array.get(3));
+        this.dy = Double.valueOf(array.get(4));
+    }
+
+    public ArrayList<String> getInfoArray() {
+        ArrayList<String> res = new ArrayList<String>(5);
+        res.add(proj.getCacheDirectoryName()); // we should use non-localized projection name
+        res.add(layerName);
+        res.add(name);
+        res.add(String.valueOf(dx));
+        res.add(String.valueOf(dy));
+        return res;
+    }
+
+    public static void loadBookmarks() {
+        for(Collection<String> c : Main.pref.getArray("imagery.offsets",
+                Collections.<Collection<String>>emptySet())) {
+                    allBookmarks.add(new OffsetBookmark(c));
+                }
+    }
+
+    public static void saveBookmarks() {
+        LinkedList<Collection<String>> coll = new LinkedList<Collection<String>>();
+        for (OffsetBookmark b : allBookmarks) {
+            coll.add(b.getInfoArray());
+        }
+        Main.pref.putArray("imagery.offsets", coll);
+    }
+}
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/OffsetBookmarksPanel.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/OffsetBookmarksPanel.java
new file mode 100644
index 0000000..c261058
--- /dev/null
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/OffsetBookmarksPanel.java
@@ -0,0 +1,155 @@
+package org.openstreetmap.josm.plugins.imagery;
+
+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.awt.event.MouseEvent;
+import java.util.List;
+
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableColumnModel;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.tools.GBC;
+
+
+public class OffsetBookmarksPanel extends JPanel {
+    List<OffsetBookmark> bookmarks = OffsetBookmark.allBookmarks;
+    OffsetsBookmarksModel model = new OffsetsBookmarksModel();
+
+    public OffsetBookmarksPanel(final PreferenceTabbedPane gui) {
+        super(new GridBagLayout());
+        final JTable list = new JTable(model) {
+            @Override
+            public String getToolTipText(MouseEvent e) {
+                java.awt.Point p = e.getPoint();
+                return model.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
+            }
+        };
+        JScrollPane scroll = new JScrollPane(list);
+        add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
+        scroll.setPreferredSize(new Dimension(200, 200));
+
+        TableColumnModel mod = list.getColumnModel();
+        mod.getColumn(0).setPreferredWidth(150);
+        mod.getColumn(1).setPreferredWidth(200);
+        mod.getColumn(2).setPreferredWidth(300);
+        mod.getColumn(3).setPreferredWidth(150);
+        mod.getColumn(4).setPreferredWidth(150);
+
+        JPanel buttonPanel = new JPanel(new FlowLayout());
+
+        JButton add = new JButton(tr("Add"));
+        buttonPanel.add(add, GBC.std().insets(0, 5, 0, 0));
+        add.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                OffsetBookmark b = new OffsetBookmark(Main.proj,"","",0,0);
+                model.addRow(b);
+            }
+        });
+
+        JButton delete = new JButton(tr("Delete"));
+        buttonPanel.add(delete, GBC.std().insets(0, 5, 0, 0));
+        delete.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                if (list.getSelectedRow() == -1)
+                    JOptionPane.showMessageDialog(gui, tr("Please select the row to delete."));
+                else {
+                    Integer i;
+                    while ((i = list.getSelectedRow()) != -1)
+                        model.removeRow(i);
+                }
+            }
+        });
+
+        add(buttonPanel,GBC.eol());
+    }
+
+    /**
+     * The table model for imagery offsets list
+     */
+    class OffsetsBookmarksModel extends DefaultTableModel {
+        public OffsetsBookmarksModel() {
+            setColumnIdentifiers(new String[] { tr("Projection"),  tr("Layer"), tr("Name"), tr("Easting"), tr("Northing"),});
+        }
+
+        public OffsetBookmark getRow(int row) {
+            return bookmarks.get(row);
+        }
+
+        public void addRow(OffsetBookmark i) {
+            bookmarks.add(i);
+            int p = getRowCount() - 1;
+            fireTableRowsInserted(p, p);
+        }
+
+        @Override
+        public void removeRow(int i) {
+            bookmarks.remove(getRow(i));
+            fireTableRowsDeleted(i, i);
+        }
+
+        @Override
+        public int getRowCount() {
+            return bookmarks.size();
+        }
+
+        @Override
+        public Object getValueAt(int row, int column) {
+            OffsetBookmark info = bookmarks.get(row);
+            switch (column) {
+            case 0:
+                return info.proj.toString();
+            case 1:
+                return info.layerName;
+            case 2:
+                return info.name;
+            case 3:
+                return info.dx;
+            case 4:
+                return info.dy;
+            default:
+                throw new ArrayIndexOutOfBoundsException();
+            }
+        }
+
+        @Override
+        public void setValueAt(Object o, int row, int column) {
+            OffsetBookmark info = bookmarks.get(row);
+            switch (column) {
+            case 1:
+                info.layerName = o.toString();
+                break;
+            case 2:
+                info.name = o.toString();
+                break;
+            case 3:
+                info.dx = Double.parseDouble((String) o);;
+                break;
+            case 4:
+                info.dy = Double.parseDouble((String) o);;
+                break;
+            default:
+                throw new ArrayIndexOutOfBoundsException();
+            }
+        }
+
+        @Override
+        public boolean isCellEditable(int row, int column) {
+            return column >= 1;
+        }
+    }
+}
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSLayer.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSLayer.java
index 173a8da..4de7f35 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSLayer.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSLayer.java
@@ -54,7 +54,6 @@ import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.plugins.imagery.ImageryInfo;
 import org.openstreetmap.josm.plugins.imagery.ImageryLayer;
 import org.openstreetmap.josm.plugins.imagery.ImageryPreferences;
-import org.openstreetmap.josm.plugins.imagery.ImageryInfo.ImageryType;
 
 /**
  * Class that displays a slippy map layer.
@@ -84,6 +83,7 @@ public class TMSLayer extends ImageryLayer implements ImageObserver, TileLoaderL
         needRedraw = true;
         Main.map.repaint(100);
         tileRequestsOutstanding.remove(tile);
+        if (sharpenLevel != 0) tile.setImage(sharpenImage(tile.getImage()));
         if (debug)
             out("tileLoadingFinished() tile: " + tile + " success: " + success);
     }
@@ -160,8 +160,8 @@ public class TMSLayer extends ImageryLayer implements ImageObserver, TileLoaderL
     }
 
     @Override
-    public void displace(double dx, double dy) {
-        super.displace(dx, dy);
+    public void setOffset(double dx, double dy) {
+        super.setOffset(dx, dy);
         needRedraw = true;
     }
 
@@ -182,15 +182,10 @@ public class TMSLayer extends ImageryLayer implements ImageObserver, TileLoaderL
         setBackgroundLayer(true);
         this.setVisible(true);
 
-        if (info.getImageryType() == ImageryType.TMS) {
-            if(isUrlWithPatterns(info.getURL())) {
-                initTileSource(new TemplatedTMSTileSource(info.getName(), info.getURL(), info.getMaxZoom()));
-            } else {
-                initTileSource(new TMSTileSource(info.getName(),info.getURL(), info.getMaxZoom()));
-            }
-        } else if (info.getImageryType() == ImageryType.BING) {
-            initTileSource(new BingAerialTileSource());
-        } else throw new IllegalStateException("cannot create TMSLayer with non-TMS ImageryInfo");
+        TileSource source = TMSPreferences.getTileSource(info);
+        if (source == null)
+            throw new IllegalStateException("cannot create TMSLayer with non-TMS ImageryInfo");
+        initTileSource(source);
 
         tileOptionMenu = new JPopupMenu();
 
@@ -364,10 +359,6 @@ public class TMSLayer extends ImageryLayer implements ImageObserver, TileLoaderL
         });
     }
 
-    public static boolean isUrlWithPatterns(String url) {
-        return url != null && url.contains("{") && url.contains("}");
-    }
-
     void zoomChanged()
     {
         if (debug)
@@ -1137,6 +1128,7 @@ public class TMSLayer extends ImageryLayer implements ImageObserver, TileLoaderL
                 LayerListDialog.getInstance().createDeleteLayerAction(),
                 SeparatorLayerAction.INSTANCE,
                 // color,
+                getOffsetAction(),
                 new RenameLayerAction(this.getAssociatedFile(), this),
                 SeparatorLayerAction.INSTANCE,
                 new LayerListPopup.InfoAction(this) };
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSPreferences.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSPreferences.java
index b2d62a3..abca2b8 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSPreferences.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSPreferences.java
@@ -3,6 +3,9 @@ package org.openstreetmap.josm.plugins.imagery.tms;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
 import org.openstreetmap.josm.data.preferences.BooleanProperty;
 import org.openstreetmap.josm.data.preferences.IntegerProperty;
+import org.openstreetmap.josm.plugins.imagery.ImageryInfo;
+import org.openstreetmap.josm.plugins.imagery.ImageryInfo.ImageryType;
+import org.openstreetmap.josm.plugins.imagery.ImageryPreferences;
 
 /**
  * Preferences for Slippy Map Tiles
@@ -26,6 +29,7 @@ public class TMSPreferences
     public static final IntegerProperty PROP_MIN_ZOOM_LVL = new IntegerProperty(PREFERENCE_PREFIX + ".min_zoom_lvl", DEFAULT_MIN_ZOOM);
     public static final IntegerProperty PROP_MAX_ZOOM_LVL = new IntegerProperty(PREFERENCE_PREFIX + ".max_zoom_lvl", DEFAULT_MAX_ZOOM);
     public static final BooleanProperty PROP_DRAW_DEBUG = new BooleanProperty(PREFERENCE_PREFIX + ".draw_debug", false);
+    public static final BooleanProperty PROP_ADD_TO_SLIPPYMAP_CHOOSER = new BooleanProperty(PREFERENCE_PREFIX + ".add_to_slippymap_chooser", true);
 
     static int checkMaxZoomLvl(int maxZoomLvl, TileSource ts)
     {
@@ -79,4 +83,17 @@ public class TMSPreferences
         minZoomLvl = checkMinZoomLvl(minZoomLvl, null);
         PROP_MIN_ZOOM_LVL.put(minZoomLvl);
     }
+
+    public static TileSource getTileSource(ImageryInfo info) {
+        if (info.getImageryType() == ImageryType.TMS) {
+            if(ImageryPreferences.isUrlWithPatterns(info.getURL())) {
+                return new TemplatedTMSTileSource(info.getName(), info.getURL(), info.getMaxZoom());
+            } else {
+                return new TMSTileSource(info.getName(),info.getURL(), info.getMaxZoom());
+            }
+        } else if (info.getImageryType() == ImageryType.BING) {
+            return new BingAerialTileSource();
+        }
+        return null;
+    }
 }
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSTileSource.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSTileSource.java
index fcd2878..3e5b81a 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSTileSource.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSTileSource.java
@@ -19,4 +19,4 @@ public class TMSTileSource extends OsmTileSource.AbstractOsmTileSource {
     public TileUpdate getTileUpdate() {
         return TileUpdate.IfNoneMatch;
     }
-}
\ No newline at end of file
+}
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSTileSourceProvider.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSTileSourceProvider.java
new file mode 100644
index 0000000..29d21f2
--- /dev/null
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/tms/TMSTileSourceProvider.java
@@ -0,0 +1,41 @@
+package org.openstreetmap.josm.plugins.imagery.tms;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
+import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser.TileSourceProvider;
+import org.openstreetmap.josm.plugins.imagery.ImageryInfo;
+import org.openstreetmap.josm.plugins.imagery.ImageryPlugin;
+
+/**
+ * TMS TileSource provider for the slippymap chooser
+ * @author Upliner
+ */
+public class TMSTileSourceProvider implements TileSourceProvider {
+    static final HashSet<String> existingSlippyMapUrls = new HashSet<String>();
+    static {
+        // Urls that already exist in the slippymap chooser
+        existingSlippyMapUrls.add("http://tile.openstreetmap.org");
+        existingSlippyMapUrls.add("http://tah.openstreetmap.org/Tiles");
+        existingSlippyMapUrls.add("http://tile.opencyclemap.org/cycle");
+    }
+
+    @Override
+    public List<TileSource> getTileSources() {
+        if (!TMSPreferences.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get()) return Collections.<TileSource>emptyList();
+        List<TileSource> sources = new ArrayList<TileSource>();
+        for (ImageryInfo info : ImageryPlugin.instance.info.getLayers()) {
+            if (existingSlippyMapUrls.contains(info.getURL())) continue;
+            TileSource source = TMSPreferences.getTileSource(info);
+            if (source != null) sources.add(source);
+        }
+        return sources;
+    }
+
+    public static void addExistingSlippyMapUrl(String url) {
+        existingSlippyMapUrls.add(url);
+    }
+}
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/GeorefImage.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/GeorefImage.java
index a18639b..9cddc61 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/GeorefImage.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/GeorefImage.java
@@ -96,6 +96,7 @@ public class GeorefImage implements Serializable {
             break;
         }
         default:
+            this.image = layer.sharpenImage(this.image);
             break;
         }
     }
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/HTMLGrabber.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/HTMLGrabber.java
index 16c9bcb..b66cab9 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/HTMLGrabber.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/HTMLGrabber.java
@@ -9,9 +9,9 @@ import java.util.StringTokenizer;
 
 import javax.imageio.ImageIO;
 
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.io.CacheFiles;
+import org.openstreetmap.josm.plugins.imagery.ImageryPlugin;
 
 public class HTMLGrabber extends WMSGrabber {
     HTMLGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
@@ -26,7 +26,7 @@ public class HTMLGrabber extends WMSGrabber {
 
         ArrayList<String> cmdParams = new ArrayList<String>();
         StringTokenizer st = new StringTokenizer(MessageFormat.format(
-                Main.pref.get("wmsplugin.browser", "webkit-image {0}"), urlstring));
+                ImageryPlugin.wmsAdapter.PROP_BROWSER.get(), urlstring));
         while( st.hasMoreTokens() )
             cmdParams.add(st.nextToken());
 
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSAdapter.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSAdapter.java
index cebf2ef..c6c3c9f 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSAdapter.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSAdapter.java
@@ -3,6 +3,7 @@ package org.openstreetmap.josm.plugins.imagery.wms;
 import org.openstreetmap.josm.actions.ExtensionFileFilter;
 import org.openstreetmap.josm.data.preferences.BooleanProperty;
 import org.openstreetmap.josm.data.preferences.IntegerProperty;
+import org.openstreetmap.josm.data.preferences.StringProperty;
 import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.io.CacheFiles;
 import org.openstreetmap.josm.plugins.imagery.ImageryInfo.ImageryType;
@@ -13,10 +14,11 @@ import org.openstreetmap.josm.plugins.imagery.wms.io.WMSLayerImporter;
 public class WMSAdapter {
     CacheFiles cache = new CacheFiles("wmsplugin");
 
-    public final IntegerProperty PROP_SIMULTANEOUS_CONNECTIONS = new IntegerProperty("wmsplugin.simultaneousConnections", 3);
-    public final BooleanProperty PROP_OVERLAP = new BooleanProperty("wmsplugin.url.overlap", false);
-    public final IntegerProperty PROP_OVERLAP_EAST = new IntegerProperty("wmsplugin.url.overlapEast", 14);
-    public final IntegerProperty PROP_OVERLAP_NORTH = new IntegerProperty("wmsplugin.url.overlapNorth", 4);
+    public final StringProperty PROP_BROWSER = new StringProperty("imagery.wms.browser", "webkit-image {0}");
+    public final IntegerProperty PROP_SIMULTANEOUS_CONNECTIONS = new IntegerProperty("imagery.wms.simultaneousConnections", 3);
+    public final BooleanProperty PROP_OVERLAP = new BooleanProperty("imagery.wms.overlap", false);
+    public final IntegerProperty PROP_OVERLAP_EAST = new IntegerProperty("imagery.wms.overlapEast", 14);
+    public final IntegerProperty PROP_OVERLAP_NORTH = new IntegerProperty("imagery.wms.overlapNorth", 4);
 
     protected void initExporterAndImporter() {
         ExtensionFileFilter.exporters.add(new WMSLayerExporter());
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSGrabber.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSGrabber.java
index d0d199c..661f159 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSGrabber.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSGrabber.java
@@ -30,13 +30,11 @@ 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 org.openstreetmap.josm.plugins.imagery.ImageryPreferences;
 import org.openstreetmap.josm.plugins.imagery.wms.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;
@@ -45,7 +43,7 @@ public class WMSGrabber extends Grabber {
         super(mv, layer, cache);
         this.baseURL = layer.getInfo().getURL();
         /* URL containing placeholders? */
-        urlWithPatterns = isUrlWithPatterns(baseURL);
+        urlWithPatterns = ImageryPreferences.isUrlWithPatterns(baseURL);
     }
 
     @Override
@@ -169,9 +167,9 @@ public class WMSGrabber extends Grabber {
         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
         if(layer.getInfo().getCookies() != null && !layer.getInfo().getCookies().equals(""))
             conn.setRequestProperty("Cookie", layer.getInfo().getCookies());
-        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);
+        conn.setRequestProperty("User-Agent", Main.pref.get("imagery.wms.user_agent", Version.getInstance().getAgentString()));
+        conn.setConnectTimeout(Main.pref.getInteger("imagery.wms.timeout.connect", 30) * 1000);
+        conn.setReadTimeout(Main.pref.getInteger("imagery.wms.timeout.read", 30) * 1000);
 
         String contentType = conn.getHeaderField("Content-Type");
         if( conn.getResponseCode() != 200
diff --git a/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSLayer.java b/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSLayer.java
index de20cbc..f751f2a 100644
--- a/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSLayer.java
+++ b/imagery/src/org/openstreetmap/josm/plugins/imagery/wms/WMSLayer.java
@@ -44,6 +44,7 @@ import org.openstreetmap.josm.plugins.imagery.ImageryInfo;
 import org.openstreetmap.josm.plugins.imagery.ImageryInfo.ImageryType;
 import org.openstreetmap.josm.plugins.imagery.ImageryLayer;
 import org.openstreetmap.josm.plugins.imagery.ImageryPlugin;
+import org.openstreetmap.josm.plugins.imagery.ImageryPreferences;
 import org.openstreetmap.josm.plugins.imagery.wms.GeorefImage.State;
 import org.openstreetmap.josm.tools.ImageProvider;
 
@@ -53,7 +54,7 @@ import org.openstreetmap.josm.tools.ImageProvider;
  */
 public class WMSLayer extends ImageryLayer implements PreferenceChangedListener {
 
-    public static final BooleanProperty PROP_ALPHA_CHANNEL = new BooleanProperty("wmsplugin.alpha_channel", true);
+    public static final BooleanProperty PROP_ALPHA_CHANNEL = new BooleanProperty("imagery.wms.alpha_channel", true);
     WMSAdapter plugin = ImageryPlugin.wmsAdapter;
 
     public int messageNum = 5; //limit for messages per layer
@@ -68,6 +69,7 @@ public class WMSLayer extends ImageryLayer implements PreferenceChangedListener
     protected final int serializeFormatVersion = 5;
     protected boolean autoDownloadEnabled = true;
     protected boolean settingsChanged;
+    protected ImageryInfo info;
 
     // Image index boundary for current view
     private volatile int bminx;
@@ -110,7 +112,7 @@ public class WMSLayer extends ImageryLayer implements PreferenceChangedListener
         if(info.getURL() != null) {
             WMSGrabber.getProjection(info.getURL(), true);
             startGrabberThreads();
-            if(info.getImageryType() == ImageryType.WMS && !WMSGrabber.isUrlWithPatterns(info.getURL())) {
+            if(info.getImageryType() == ImageryType.WMS && !ImageryPreferences.isUrlWithPatterns(info.getURL())) {
                 if (!(info.getURL().endsWith("&") || info.getURL().endsWith("?"))) {
                     if (!confirmMalformedUrl(info.getURL())) {
                         System.out.println(tr("Warning: WMS layer deactivated because of malformed base url ''{0}''", info.getURL()));
@@ -241,8 +243,8 @@ public class WMSLayer extends ImageryLayer implements PreferenceChangedListener
     }
 
     @Override
-    public void displace(double dx, double dy) {
-        super.displace(dx, dy);
+    public void setOffset(double dx, double dy) {
+        super.setOffset(dx, dy);
         settingsChanged = true;
     }
 
@@ -356,6 +358,7 @@ public class WMSLayer extends ImageryLayer implements PreferenceChangedListener
                 LayerListDialog.getInstance().createShowHideLayerAction(),
                 LayerListDialog.getInstance().createDeleteLayerAction(),
                 SeparatorLayerAction.INSTANCE,
+                getOffsetAction(),
                 new LoadWmsAction(),
                 new SaveWmsAction(),
                 new BookmarkWmsAction(),
diff --git a/svn-info.xml b/svn-info.xml
index bb78072..7b483a4 100644
--- a/svn-info.xml
+++ b/svn-info.xml
@@ -3,16 +3,16 @@
 <entry
    kind="dir"
    path="plugins"
-   revision="24608">
+   revision="24657">
 <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="24602">
-<author>malcolmh</author>
-<date>2010-12-05T20:42:28.719021Z</date>
+   revision="24654">
+<author>extropy</author>
+<date>2010-12-08T14:53:35.122571Z</date>
 </commit>
 </entry>
 </info>
diff --git a/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java b/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java
index 7e2af13..98d09e7 100644
--- a/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java
+++ b/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java
@@ -305,8 +305,10 @@ public class WMSPreferenceEditor implements PreferenceSetting {
             switch (column) {
             case 0:
                 info.name = (String) o;
+                break;
             case 1:
                 info.setURL((String)o);
+                break;
             }
         }
 
diff --git a/wmsplugin/webkit-image.cpp b/wmsplugin/webkit-image.cpp
index fddb51c..10ab76a 100644
--- a/wmsplugin/webkit-image.cpp
+++ b/wmsplugin/webkit-image.cpp
@@ -151,9 +151,9 @@ int main(int argc, char **argv)
   QObject::connect(page, SIGNAL(loadFinished(bool)), s, SLOT(loaded(bool)));
   QObject::connect(s, SIGNAL(finish(void)), &a, SLOT(quit()));
   /* set some useful defaults for a webpage */
-//  page->setViewportSize(QSize(1280,1024));
-//  page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
-//  page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
+  page->setViewportSize(QSize(1280,1024));
+  page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
+  page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
   page->mainFrame()->load (QUrl(url));
   return a.exec();
 }

-- 
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