Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/Address.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/Address.java	(revision 33637)
+++ 	(revision )
@@ -1,540 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.Cursor;
-import java.awt.GridBagLayout;
-import java.awt.Point;
-import java.awt.Rectangle;
-import java.awt.Toolkit;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ComponentAdapter;
-import java.awt.event.ComponentEvent;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.swing.ButtonGroup;
-import javax.swing.ImageIcon;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JTextField;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.mapmode.MapMode;
-import org.openstreetmap.josm.command.AddCommand;
-import org.openstreetmap.josm.command.ChangeCommand;
-import org.openstreetmap.josm.command.ChangePropertyCommand;
-import org.openstreetmap.josm.command.Command;
-import org.openstreetmap.josm.command.SequenceCommand;
-import org.openstreetmap.josm.data.coor.EastNorth;
-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.RelationMember;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.data.osm.WaySegment;
-import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.ImageProvider;
-import org.openstreetmap.josm.tools.Pair;
-import org.openstreetmap.josm.tools.Shortcut;
-
-public class Address extends MapMode {
-
-    // perhaps make all these tags configurable in the future
-    private String tagHighway = "highway";
-    private String tagHighwayName = "name";
-    private String tagHouseNumber = "addr:housenumber";
-    private String tagHouseStreet = "addr:street";
-    private String tagBuilding = "building";
-    private String relationAddrType = "associatedStreet";
-    private String relationAddrName = "name";
-    private String relationAddrStreetRole = "street";
-    private String relationMemberHouse = "house";
-
-    private JRadioButton plusOne = new JRadioButton("+1", false);
-    private JRadioButton plusTwo = new JRadioButton("+2", true); // enable this by default
-    private JRadioButton minusOne = new JRadioButton("-1", false);
-    private JRadioButton minusTwo = new JRadioButton("-2", false);
-    final JCheckBox tagPolygon = new JCheckBox(tr("on polygon"));
-
-    JDialog dialog;
-    JButton clearButton;
-    final JTextField inputNumber = new JTextField();
-    final JTextField inputStreet = new JTextField();
-    JLabel link = new JLabel();
-    private transient Way selectedWay;
-    private boolean shift;
-    private boolean ctrl;
-
-    /**
-     * Constructs a new {@code Address} map mode.
-     */
-    public Address() {
-        super(tr("Add address"), "buildings",
-                tr("Helping tool for tag address"),
-                // CHECKSTYLE.OFF: LineLength
-                Shortcut.registerShortcut("mapmode:cadastre-fr-buildings", tr("Mode: {0}", tr("CadastreFR - Buildings")), KeyEvent.VK_E, Shortcut.DIRECT),
-                // CHECKSTYLE.ON: LineLength
-                getCursor());
-    }
-
-    @Override public void enterMode() {
-        super.enterMode();
-        if (dialog == null) {
-            createDialog();
-        }
-        dialog.setVisible(true);
-        Main.map.mapView.addMouseListener(this);
-    }
-
-    @Override public void exitMode() {
-        if (Main.map.mapView != null) {
-            super.exitMode();
-            Main.map.mapView.removeMouseListener(this);
-        }
-        // kill the window completely to fix an issue on some linux distro and full screen mode.
-        if (dialog != null) {
-            dialog.dispose();
-            dialog = null;
-        }
-    }
-
-    @Override
-    public void mousePressed(MouseEvent e) {
-        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<>();
-        List<Way> mouseOnExistingBuildingWays = new ArrayList<>();
-        Node currentMouseNode = mv.getNearestNode(mousePos, OsmPrimitive::isSelectable);
-        if (currentMouseNode != null) {
-            // click on existing node
-            setNewSelection(currentMouseNode);
-            String num = currentMouseNode.get(tagHouseNumber);
-            if (num != null
-                    && currentMouseNode.get(tagHouseStreet) == null
-                    && findWayInRelationAddr(currentMouseNode) == null
-                    && !inputStreet.getText().isEmpty()) {
-                // house number already present but not linked to a street
-                Collection<Command> cmds = new LinkedList<>();
-                addStreetNameOrRelation(currentMouseNode, cmds);
-                Command c = new SequenceCommand("Add node address", cmds);
-                Main.main.undoRedo.add(c);
-                setNewSelection(currentMouseNode);
-            } else {
-                if (num != null) {
-                    try {
-                        // add new address
-                        Integer.parseInt(num);
-                        inputNumber.setText(num);
-                        applyInputNumberChange();
-                    } catch (NumberFormatException en) {
-                        Main.warn("Unable to parse house number \"" + num + "\"");
-                    }
-                }
-                if (currentMouseNode.get(tagHouseStreet) != null) {
-                    if (Main.pref.getBoolean("cadastrewms.addr.dontUseRelation", false)) {
-                        inputStreet.setText(currentMouseNode.get(tagHouseStreet));
-                        if (ctrl) {
-                            Collection<Command> cmds = new LinkedList<>();
-                            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<>();
-                        addAddrToPrimitive(currentMouseNode, cmds);
-                    } else {
-                        inputStreet.setText(wayInRelationAddr.get(tagHighwayName));
-                        setSelectedWay(wayInRelationAddr);
-                    }
-                }
-            }
-        } else {
-            List<WaySegment> wss = mv.getNearestWaySegments(mousePos, OsmPrimitive::isSelectable);
-            for (WaySegment ws : wss) {
-                if (ws.way.get(tagHighway) != null && ws.way.get(tagHighwayName) != null)
-                    mouseOnExistingWays.add(ws.way);
-                else if (ws.way.get(tagBuilding) != null && ws.way.get(tagHouseNumber) == null)
-                    mouseOnExistingBuildingWays.add(ws.way);
-            }
-            if (mouseOnExistingWays.size() == 1) {
-                // clicked on existing highway => set new street name
-                inputStreet.setText(mouseOnExistingWays.get(0).get(tagHighwayName));
-                setSelectedWay(mouseOnExistingWays.get(0));
-                inputNumber.setText("");
-                setNewSelection(mouseOnExistingWays.get(0));
-            } else if (mouseOnExistingWays.isEmpty()) {
-                // clicked a non highway and not a node => add the new address
-                if (inputStreet.getText().isEmpty() || inputNumber.getText().isEmpty()) {
-                    Toolkit.getDefaultToolkit().beep();
-                } else {
-                    Collection<Command> cmds = new LinkedList<>();
-                    if (ctrl) {
-                        applyInputNumberChange();
-                    }
-                    if (tagPolygon.isSelected()) {
-                        addAddrToPolygon(mouseOnExistingBuildingWays, cmds);
-                    } else {
-                        Node n = createNewNode(e, cmds);
-                        addAddrToPrimitive(n, cmds);
-                    }
-                }
-            }
-        }
-    }
-
-    private Way findWayInRelationAddr(Node n) {
-        List<OsmPrimitive> l = n.getReferrers();
-        for (OsmPrimitive osm : l) {
-            if (osm instanceof Relation && osm.hasKey("type") && osm.get("type").equals(relationAddrType)) {
-                for (RelationMember rm : ((Relation) osm).getMembers()) {
-                    if (rm.getRole().equals(relationAddrStreetRole)) {
-                        OsmPrimitive osp = rm.getMember();
-                        if (osp instanceof Way && osp.hasKey(tagHighwayName)) {
-                            return (Way) osp;
-                        }
-                    }
-                }
-            }
-        }
-        return null;
-    }
-
-    private void addAddrToPolygon(List<Way> mouseOnExistingBuildingWays, Collection<Command> cmds) {
-        for (Way w:mouseOnExistingBuildingWays) {
-            addAddrToPrimitive(w, cmds);
-        }
-    }
-
-    private void addAddrToPrimitive(OsmPrimitive osm, Collection<Command> cmds) {
-        // add the current tag addr:housenumber in node and member in relation (if so configured)
-        if (shift) {
-            try {
-                revertInputNumberChange();
-            } catch (NumberFormatException en) {
-                Main.warn("Unable to parse house number \"" + inputNumber.getText() + "\"");
-            }
-        }
-        cmds.add(new ChangePropertyCommand(osm, tagHouseNumber, inputNumber.getText()));
-        addStreetNameOrRelation(osm, cmds);
-        try {
-            applyInputNumberChange();
-            Command c = new SequenceCommand("Add node address", cmds);
-            Main.main.undoRedo.add(c);
-            setNewSelection(osm);
-        } catch (NumberFormatException en) {
-            Main.warn("Unable to parse house number \"" + inputNumber.getText() + "\"");
-        }
-    }
-
-    private Relation findRelationAddr(Way w) {
-        List<OsmPrimitive> l = w.getReferrers();
-        for (OsmPrimitive osm : l) {
-            if (osm instanceof Relation && osm.hasKey("type") && osm.get("type").equals(relationAddrType)) {
-                return (Relation) osm;
-            }
-        }
-        return null;
-    }
-
-    private void addStreetNameOrRelation(OsmPrimitive osm, Collection<Command> cmds) {
-        if (Main.pref.getBoolean("cadastrewms.addr.dontUseRelation", false)) {
-            cmds.add(new ChangePropertyCommand(osm, tagHouseStreet, inputStreet.getText()));
-        } else if (selectedWay != null) {
-            Relation selectedRelation = findRelationAddr(selectedWay);
-            // add the node to its relation
-            if (selectedRelation != null) {
-                RelationMember rm = new RelationMember(relationMemberHouse, osm);
-                Relation newRel = new Relation(selectedRelation);
-                newRel.addMember(rm);
-                cmds.add(new ChangeCommand(selectedRelation, newRel));
-            } else {
-                // create new relation
-                Relation newRel = new Relation();
-                newRel.put("type", relationAddrType);
-                newRel.put(relationAddrName, selectedWay.get(tagHighwayName));
-                newRel.addMember(new RelationMember(relationAddrStreetRole, selectedWay));
-                newRel.addMember(new RelationMember(relationMemberHouse, osm));
-                cmds.add(new AddCommand(newRel));
-            }
-        }
-    }
-
-    private static Node createNewNode(MouseEvent e, Collection<Command> cmds) {
-        // DrawAction.mouseReleased() but without key modifiers
-        Node n = new Node(Main.map.mapView.getLatLon(e.getX(), e.getY()));
-        cmds.add(new AddCommand(n));
-        List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(e.getPoint(), OsmPrimitive::isSelectable);
-        Map<Way, List<Integer>> insertPoints = new HashMap<>();
-        for (WaySegment ws : wss) {
-            List<Integer> is;
-            if (insertPoints.containsKey(ws.way)) {
-                is = insertPoints.get(ws.way);
-            } else {
-                is = new ArrayList<>();
-                insertPoints.put(ws.way, is);
-            }
-
-            is.add(ws.lowerIndex);
-        }
-        Set<Pair<Node, Node>> segSet = new HashSet<>();
-        ArrayList<Way> replacedWays = new ArrayList<>();
-        ArrayList<Way> reuseWays = new ArrayList<>();
-        for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
-            Way w = insertPoint.getKey();
-            List<Integer> is = insertPoint.getValue();
-            Way wnew = new Way(w);
-            pruneSuccsAndReverse(is);
-            for (int i : is) {
-                segSet.add(Pair.sort(new Pair<>(w.getNode(i), w.getNode(i+1))));
-            }
-            for (int i : is) {
-                wnew.addNode(i + 1, n);
-            }
-            cmds.add(new ChangeCommand(insertPoint.getKey(), wnew));
-            replacedWays.add(insertPoint.getKey());
-            reuseWays.add(wnew);
-        }
-        adjustNode(segSet, n);
-
-        return n;
-    }
-
-    private static void adjustNode(Collection<Pair<Node, Node>> segs, Node n) {
-
-        switch (segs.size()) {
-        case 0:
-            return;
-        case 2:
-            // This computes the intersection between
-            // the two segments and adjusts the node position.
-            Iterator<Pair<Node, Node>> i = segs.iterator();
-            Pair<Node, Node> seg = i.next();
-            EastNorth A = seg.a.getEastNorth();
-            EastNorth B = seg.b.getEastNorth();
-            seg = i.next();
-            EastNorth C = seg.a.getEastNorth();
-            EastNorth D = seg.b.getEastNorth();
-
-            double u = det(B.east() - A.east(), B.north() - A.north(), C.east() - D.east(), C.north() - D.north());
-
-            // Check for parallel segments and do nothing if they are
-            // In practice this will probably only happen when a way has been duplicated
-
-            if (u == 0) return;
-
-            // q is a number between 0 and 1
-            // It is the point in the segment where the intersection occurs
-            // if the segment is scaled to lenght 1
-
-            double q = det(B.north() - C.north(), B.east() - C.east(), D.north() - C.north(), D.east() - C.east()) / u;
-            EastNorth intersection = new EastNorth(
-                    B.east() + q * (A.east() - B.east()),
-                    B.north() + q * (A.north() - B.north()));
-
-            int snapToIntersectionThreshold
-            = Main.pref.getInteger("edit.snap-intersection-threshold", 10);
-
-            // only adjust to intersection if within snapToIntersectionThreshold pixel of mouse click; otherwise
-            // fall through to default action.
-            // (for semi-parallel lines, intersection might be miles away!)
-            if (Main.map.mapView.getPoint(n).distance(Main.map.mapView.getPoint(intersection)) < snapToIntersectionThreshold) {
-                n.setEastNorth(intersection);
-                return;
-            }
-
-        default:
-            EastNorth P = n.getEastNorth();
-            seg = segs.iterator().next();
-            A = seg.a.getEastNorth();
-            B = seg.b.getEastNorth();
-            double a = P.distanceSq(B);
-            double b = P.distanceSq(A);
-            double c = A.distanceSq(B);
-            q = (a - b + c) / (2*c);
-            n.setEastNorth(new EastNorth(B.east() + q * (A.east() - B.east()), B.north() + q * (A.north() - B.north())));
-        }
-    }
-
-    static double det(double a, double b, double c, double d) {
-        return a * d - b * c;
-    }
-
-    private static void pruneSuccsAndReverse(List<Integer> is) {
-        HashSet<Integer> is2 = new HashSet<>();
-        for (int i : is) {
-            if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
-                is2.add(i);
-            }
-        }
-        is.clear();
-        is.addAll(is2);
-        Collections.sort(is);
-        Collections.reverse(is);
-    }
-
-    private static Cursor getCursor() {
-        try {
-            return ImageProvider.getCursor("crosshair", null);
-        } catch (RuntimeException e) {
-            Main.warn(e);
-        }
-        return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
-    }
-
-    private void applyInputNumberChange() {
-        Integer num = Integer.parseInt(inputNumber.getText());
-        if (plusOne.isSelected())
-            num = num + 1;
-        if (plusTwo.isSelected())
-            num = num + 2;
-        if (minusOne.isSelected() && num > 1)
-            num = num - 1;
-        if (minusTwo.isSelected() && num > 2)
-            num = num - 2;
-        inputNumber.setText(num.toString());
-    }
-
-    private void revertInputNumberChange() {
-        Integer num = Integer.parseInt(inputNumber.getText());
-        if (plusOne.isSelected())
-            num = num - 1;
-        if (plusTwo.isSelected())
-            num = num - 2;
-        if (minusOne.isSelected() && num > 1)
-            num = num + 1;
-        if (minusTwo.isSelected() && num > 2)
-            num = num + 2;
-        inputNumber.setText(num.toString());
-    }
-
-    private void createDialog() {
-        ImageIcon iconLink = ImageProvider.get(null, "Mf_relation");
-        link.setIcon(iconLink);
-        link.setEnabled(false);
-        JPanel p = new JPanel(new GridBagLayout());
-        JLabel number = new JLabel(tr("Next no"));
-        JLabel street = new JLabel(tr("Street"));
-        p.add(number, GBC.std().insets(0, 0, 0, 0));
-        p.add(inputNumber, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 0, 5));
-        p.add(street, GBC.std().insets(0, 0, 0, 0));
-        JPanel p2 = new JPanel(new GridBagLayout());
-        inputStreet.setEditable(false);
-        p2.add(inputStreet, GBC.std().fill(GBC.HORIZONTAL).insets(5, 0, 0, 0));
-        p2.add(link, GBC.eol().insets(10, 0, 0, 0));
-        p.add(p2, GBC.eol().fill(GBC.HORIZONTAL));
-        clearButton = new JButton("Clear");
-        clearButton.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                inputNumber.setText("");
-                inputStreet.setText("");
-                setSelectedWay((Way) null);
-            }
-        });
-        ButtonGroup bgIncremental = new ButtonGroup();
-        bgIncremental.add(plusOne);
-        bgIncremental.add(plusTwo);
-        bgIncremental.add(minusOne);
-        bgIncremental.add(minusTwo);
-        p.add(minusOne, GBC.std().insets(10, 0, 10, 0));
-        p.add(plusOne, GBC.std().insets(0, 0, 10, 0));
-        tagPolygon.setSelected(Main.pref.getBoolean("cadastrewms.addr.onBuilding", false));
-        tagPolygon.addChangeListener(new ChangeListener() {
-            @Override
-            public void stateChanged(ChangeEvent arg0) {
-                Main.pref.put("cadastrewms.addr.onBuilding", tagPolygon.isSelected());
-            }
-        });
-        p.add(tagPolygon, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 0, 0));
-        p.add(minusTwo, GBC.std().insets(10, 0, 10, 0));
-        p.add(plusTwo, GBC.std().insets(0, 0, 10, 0));
-        p.add(clearButton, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 0, 0));
-
-        final Object[] options = {};
-        final JOptionPane pane = new JOptionPane(p,
-                JOptionPane.PLAIN_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION,
-                null, options, null);
-        dialog = pane.createDialog(Main.parent, tr("Enter addresses"));
-        dialog.setModal(false);
-        dialog.setAlwaysOnTop(true);
-        dialog.addComponentListener(new ComponentAdapter() {
-            protected void rememberGeometry() {
-                Main.pref.put("cadastrewms.addr.bounds", dialog.getX()+","+dialog.getY()+","+dialog.getWidth()+","+dialog.getHeight());
-            }
-
-            @Override public void componentMoved(ComponentEvent e) {
-                rememberGeometry();
-            }
-
-            @Override public void componentResized(ComponentEvent e) {
-                rememberGeometry();
-            }
-        });
-        dialog.addWindowListener(new WindowAdapter() {
-            @Override
-            public void windowClosing(WindowEvent arg) {
-                Main.map.selectMapMode((MapMode) Main.map.getDefaultButtonAction());
-            }
-        });
-        String bounds = Main.pref.get("cadastrewms.addr.bounds", null);
-        if (bounds != null) {
-            String[] b = bounds.split(",");
-            dialog.setBounds(new Rectangle(
-                    Integer.parseInt(b[0]), Integer.parseInt(b[1]), Integer.parseInt(b[2]), Integer.parseInt(b[3])));
-        }
-    }
-
-    private void setSelectedWay(Way w) {
-        this.selectedWay = w;
-        if (w == null) {
-            link.setEnabled(false);
-        } else
-            link.setEnabled(true);
-        link.repaint();
-    }
-
-    private static void setNewSelection(OsmPrimitive osm) {
-        DataSet ds = Main.getLayerManager().getEditDataSet();
-        Collection<OsmPrimitive> newSelection = new LinkedList<>(ds.getSelected());
-        newSelection.clear();
-        newSelection.add(osm);
-        ds.setSelected(osm);
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CacheControl.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CacheControl.java	(revision 33637)
+++ 	(revision )
@@ -1,235 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.concurrent.Callable;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import javax.swing.JDialog;
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.util.GuiHelper;
-
-/**
- * This class handles the WMS layer cache mechanism. The design is oriented for a good performance (no
- * wait status on GUI, fast saving even in big file). A separate thread is created for each WMS
- * layer to not suspend the GUI until disk I/O is terminated (a file for the cache can take
- * several MB's). If the cache file already exists, new images are just appended to the file
- * (performance). Since we use the ObjectStream methods, it is required to modify the standard
- * ObjectOutputStream in order to have objects appended readable (otherwise a stream header
- * is inserted before each append and an exception is raised at objects read).
- */
-public class CacheControl implements Runnable {
-
-    public static final String C_LAMBERT_CC_9Z = "CC";
-
-    public static final String C_UTM20N = "UTM";
-
-    public static class ObjectOutputStreamAppend extends ObjectOutputStream {
-        public ObjectOutputStreamAppend(OutputStream out) throws IOException {
-            super(out);
-        }
-
-        @Override
-        protected void writeStreamHeader() throws IOException {
-            reset();
-        }
-    }
-
-    public static boolean cacheEnabled = true;
-
-    public static int cacheSize = 500;
-
-    public WMSLayer wmsLayer;
-
-    private ArrayList<GeorefImage> imagesToSave = new ArrayList<>();
-    private Lock imagesLock = new ReentrantLock();
-
-    public boolean isCachePipeEmpty() {
-        imagesLock.lock();
-        boolean ret = imagesToSave.isEmpty();
-        imagesLock.unlock();
-        return ret;
-    }
-
-    public CacheControl(WMSLayer wmsLayer) {
-        cacheEnabled = Main.pref.getBoolean("cadastrewms.enableCaching", true);
-        this.wmsLayer = wmsLayer;
-        try {
-            cacheSize = Integer.parseInt(Main.pref.get("cadastrewms.cacheSize", String.valueOf(CadastrePreferenceSetting.DEFAULT_CACHE_SIZE)));
-        } catch (NumberFormatException e) {
-            cacheSize = CadastrePreferenceSetting.DEFAULT_CACHE_SIZE;
-        }
-        File path = new File(CadastrePlugin.cacheDir);
-        if (!path.exists())
-            path.mkdirs();
-        else // check directory capacity
-            checkDirSize(path);
-        new Thread(this).start();
-    }
-
-    private static void checkDirSize(File path) {
-        if (cacheSize != 0) {
-            long size = 0;
-            long oldestFileDate = Long.MAX_VALUE;
-            int oldestFile = 0;
-            File[] files = path.listFiles();
-            for (int i = 0; i < files.length; i++) {
-                size += files[i].length();
-                if (files[i].lastModified() < oldestFileDate) {
-                    oldestFile = i;
-                    oldestFileDate = files[i].lastModified();
-                }
-            }
-            if (size > (long) cacheSize*1024*1024) {
-                Main.info("Delete oldest file  \""+ files[oldestFile].getName()
-                        + "\" in cache dir to stay under the limit of " + cacheSize + " MB.");
-                files[oldestFile].delete();
-                checkDirSize(path);
-            }
-        }
-    }
-
-    public boolean loadCacheIfExist() {
-        if (!CadastrePlugin.isCadastreProjection()) {
-            CadastrePlugin.askToChangeProjection();
-        }
-        File file = new File(CadastrePlugin.cacheDir + wmsLayer.getName() + "." + WMSFileExtension());
-        if (file.exists()) {
-            int reply = GuiHelper.runInEDTAndWaitAndReturn(new Callable<Integer>() {
-                @Override
-                public Integer call() throws Exception {
-                    JOptionPane pane = new JOptionPane(
-                            tr("Location \"{0}\" found in cache.\n"+
-                            "Load cache first ?\n"+
-                            "(No = new cache)", wmsLayer.getName()),
-                            JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION, null);
-                    // this below is a temporary workaround to fix the "always on top" issue
-                    JDialog dialog = pane.createDialog(Main.parent, tr("Select Feuille"));
-                    CadastrePlugin.prepareDialog(dialog);
-                    dialog.setVisible(true);
-                    return (Integer) pane.getValue();
-                    // till here
-                }
-            });
-
-            if (reply == JOptionPane.OK_OPTION && loadCache(file, wmsLayer.getLambertZone())) {
-                return true;
-            } else {
-                delete(file);
-            }
-        }
-        return false;
-    }
-
-    public void deleteCacheFile() {
-        delete(new File(CadastrePlugin.cacheDir + wmsLayer.getName() + "." + WMSFileExtension()));
-    }
-
-    private static void delete(File file) {
-        Main.info("Delete file "+file);
-        if (file.exists())
-            file.delete();
-        while (file.exists()) { // wait until file is really gone (otherwise appends to existing one)
-            CadastrePlugin.safeSleep(500);
-        }
-    }
-
-    public boolean loadCache(File file, int currentLambertZone) {
-        boolean successfulRead = false;
-        try (
-            FileInputStream fis = new FileInputStream(file);
-            ObjectInputStream ois = new ObjectInputStream(fis);
-        ) {
-            successfulRead = wmsLayer.read(file, ois, currentLambertZone);
-        } catch (IOException | ClassNotFoundException ex) {
-            Main.error(ex);
-            GuiHelper.runInEDTAndWait(new Runnable() {
-                @Override
-                public void run() {
-                    JOptionPane.showMessageDialog(Main.parent, tr("Error loading file.\nProbably an old version of the cache file."),
-                            tr("Error"), JOptionPane.ERROR_MESSAGE);
-                }
-            });
-            return false;
-        }
-        if (successfulRead && wmsLayer.isRaster()) {
-            // serialized raster bufferedImage hangs-up on Java6. Recreate them here
-            wmsLayer.getImage(0).image = RasterImageModifier.fixRasterImage(wmsLayer.getImage(0).image);
-        }
-        return successfulRead;
-    }
-
-    public synchronized void saveCache(GeorefImage image) {
-        imagesLock.lock();
-        this.imagesToSave.add(image);
-        this.notifyAll();
-        imagesLock.unlock();
-    }
-
-    /**
-     * Thread saving the grabbed images in background.
-     */
-    @Override
-    public synchronized void run() {
-        for (;;) {
-            imagesLock.lock();
-            int size = imagesToSave.size();
-            imagesLock.unlock();
-            if (size > 0) {
-                File file = new File(CadastrePlugin.cacheDir + wmsLayer.getName() + "." + WMSFileExtension());
-                try {
-                    if (file.exists()) {
-                        try (ObjectOutputStreamAppend oos = new ObjectOutputStreamAppend(
-                                new BufferedOutputStream(new FileOutputStream(file, true)))) {
-                            for (int i = 0; i < size; i++) {
-                                oos.writeObject(imagesToSave.get(i));
-                            }
-                        }
-                    } else {
-                        try (ObjectOutputStream oos = new ObjectOutputStream(
-                                new BufferedOutputStream(new FileOutputStream(file)))) {
-                            wmsLayer.write(file, oos);
-                            for (int i = 0; i < size; i++) {
-                                oos.writeObject(imagesToSave.get(i));
-                            }
-                        }
-                    }
-                } catch (IOException e) {
-                    Main.error(e);
-                }
-                imagesLock.lock();
-                for (int i = 0; i < size; i++) {
-                    imagesToSave.remove(0);
-                }
-                imagesLock.unlock();
-            }
-            try {
-                wait();
-            } catch (InterruptedException e) {
-                Main.error(e);
-            }
-        }
-    }
-
-    private String WMSFileExtension() {
-        String ext = String.valueOf(wmsLayer.getLambertZone() + 1);
-        if (CadastrePlugin.isLambert_cc9())
-            ext = C_LAMBERT_CC_9Z + ext;
-        else if (CadastrePlugin.isUtm_france_dom())
-            ext = C_UTM20N + ext;
-        return ext;
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CacheFileLambert4ZoneFilter.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CacheFileLambert4ZoneFilter.java	(revision 33637)
+++ 	(revision )
@@ -1,55 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.File;
-import java.util.Locale;
-
-import javax.swing.filechooser.FileFilter;
-
-public final class CacheFileLambert4ZoneFilter extends FileFilter {
-
-    /**
-     * Derived from ExtensionFileFilter writen by imi
-     */
-    private final String extension;
-    private final String description;
-
-    static final CacheFileLambert4ZoneFilter[] filters = {
-        new CacheFileLambert4ZoneFilter("1", tr("Lambert Zone {0} cache file (.{0})", 1)),
-        new CacheFileLambert4ZoneFilter("2", tr("Lambert Zone {0} cache file (.{0})", 2)),
-        new CacheFileLambert4ZoneFilter("3", tr("Lambert Zone {0} cache file (.{0})", 3)),
-        new CacheFileLambert4ZoneFilter("4", tr("Lambert Zone {0} cache file (.{0})", 4))
-        };
-
-    /**
-     * Construct an extension file filter by giving the extension to check after.
-     *
-     */
-    private CacheFileLambert4ZoneFilter(String extension, String description) {
-        this.extension = extension;
-        this.description = description;
-    }
-
-    public boolean acceptName(String filename) {
-        String name = filename.toLowerCase(Locale.FRANCE);
-        for (String ext : extension.split(",")) {
-            if (name.endsWith("." + ext))
-                return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean accept(File pathname) {
-        if (pathname.isDirectory())
-            return true;
-        return acceptName(pathname.getName());
-    }
-
-    @Override
-    public String getDescription() {
-        return description;
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CacheFileLambert9ZoneFilter.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CacheFileLambert9ZoneFilter.java	(revision 33637)
+++ 	(revision )
@@ -1,60 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.File;
-
-import javax.swing.filechooser.FileFilter;
-
-public final class CacheFileLambert9ZoneFilter extends FileFilter {
-
-    /**
-     * Derived from ExtensionFileFilter writen by imi
-     */
-    private final String extension;
-    private final String description;
-
-    public static CacheFileLambert9ZoneFilter[] filters = {
-        new CacheFileLambert9ZoneFilter("cc1", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 1)),
-        new CacheFileLambert9ZoneFilter("cc2", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 2)),
-        new CacheFileLambert9ZoneFilter("cc3", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 3)),
-        new CacheFileLambert9ZoneFilter("cc4", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 4)),
-        new CacheFileLambert9ZoneFilter("cc5", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 5)),
-        new CacheFileLambert9ZoneFilter("cc6", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 6)),
-        new CacheFileLambert9ZoneFilter("cc7", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 7)),
-        new CacheFileLambert9ZoneFilter("cc8", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 8)),
-        new CacheFileLambert9ZoneFilter("cc9", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 9))
-        };
-
-    /**
-     * Construct an extension file filter by giving the extension to check after.
-     *
-     */
-    private CacheFileLambert9ZoneFilter(String extension, String description) {
-        this.extension = extension;
-        this.description = description;
-    }
-
-    public boolean acceptName(String filename) {
-        String name = filename.toLowerCase();
-        for (String ext : extension.split(",")) {
-            if (name.endsWith("." + ext))
-                return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean accept(File pathname) {
-        if (pathname.isDirectory())
-            return true;
-        return acceptName(pathname.getName());
-    }
-
-    @Override
-    public String getDescription() {
-        return description;
-    }
-
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CacheFileUTM20NFilter.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CacheFileUTM20NFilter.java	(revision 33637)
+++ 	(revision )
@@ -1,55 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.File;
-
-import javax.swing.filechooser.FileFilter;
-
-public final class CacheFileUTM20NFilter extends FileFilter {
-
-    /**
-     * Derived from ExtensionFileFilter writen by imi
-     */
-    private final String extension;
-    private final String description;
-
-    public static CacheFileUTM20NFilter[] filters = {
-        new CacheFileUTM20NFilter("utm1", tr("Guadeloupe Fort-Marigot cache file (.UTM1)")),
-        new CacheFileUTM20NFilter("utm2", tr("Guadeloupe Ste-Anne cache file (.UTM2)")),
-        new CacheFileUTM20NFilter("utm3", tr("Martinique Fort Desaix cache file (.UTM3)")),
-        new CacheFileUTM20NFilter("utm4", tr("Reunion RGR92 cache file (.UTM4)"))
-        };
-
-    /**
-     * Construct an extension file filter by giving the extension to check after.
-     *
-     */
-    private CacheFileUTM20NFilter(String extension, String description) {
-        this.extension = extension;
-        this.description = description;
-    }
-
-    public boolean acceptName(String filename) {
-        String name = filename.toLowerCase();
-        for (String ext : extension.split(",")) {
-            if (name.endsWith("." + ext))
-                return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean accept(File pathname) {
-        if (pathname.isDirectory())
-            return true;
-        return acceptName(pathname.getName());
-    }
-
-    @Override
-    public String getDescription() {
-        return description;
-    }
-
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastreGrabber.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastreGrabber.java	(revision 33637)
+++ 	(revision )
@@ -1,93 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import javax.imageio.ImageIO;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.io.OsmTransferException;
-
-public class CadastreGrabber {
-
-    private CadastreInterface wmsInterface = new CadastreInterface();
-
-    public GeorefImage grab(WMSLayer wmsLayer, EastNorth lambertMin, EastNorth lambertMax)
-            throws IOException, OsmTransferException {
-        try {
-            URL url = null;
-            if (wmsLayer.isRaster())
-                url = getURLRaster(wmsLayer, lambertMin, lambertMax);
-            else
-                url = getURLVector(lambertMin, lambertMax);
-            BufferedImage img = grab(url);
-            if (img == null)
-                throw new OsmTransferException(url.toString());
-            ImageModifier imageModified;
-            if (wmsLayer.isRaster())
-                imageModified = new RasterImageModifier(img);
-            else
-                imageModified = new VectorImageModifier(img, false);
-            return new GeorefImage(imageModified.getBufferedImage(), lambertMin, lambertMax, wmsLayer);
-        } catch (MalformedURLException e) {
-            throw (IOException) new IOException(tr("CadastreGrabber: Illegal url.")).initCause(e);
-        }
-    }
-
-    private static URL getURLRaster(WMSLayer wmsLayer, EastNorth lambertMin, EastNorth lambertMax) throws MalformedURLException {
-        // GET /scpc/wms?version=1.1&request=GetMap&layers=CDIF:PMC@QH4480001701&format=image/png&bbox=-1186,0,13555,8830&width=576&height=345&exception=application/vnd.ogc.se_inimage&styles= HTTP/1.1
-        final int cRasterX = CadastrePlugin.imageWidth; // keep width constant and adjust width to original image proportions
-        String str = CadastreInterface.BASE_URL+"/scpc/wms?version=1.1&request=GetMap";
-        str += "&layers=CDIF:PMC@";
-        str += wmsLayer.getCodeCommune();
-        str += "&format=image/png";
-        //str += "&format=image/jpeg";
-        str += "&bbox=";
-        str += wmsLayer.eastNorth2raster(lambertMin, lambertMax);
-        str += "&width="+cRasterX+"&height="; // maximum allowed by wms server (576/345, 800/378, 1000/634)
-        str += (int) (cRasterX*(wmsLayer.communeBBox.max.getY() - wmsLayer.communeBBox.min.getY())/(wmsLayer.communeBBox.max.getX() - wmsLayer.communeBBox.min.getX()));
-        str += "&exception=application/vnd.ogc.se_inimage&styles="; // required for raster images
-        Main.info("URL="+str);
-        return new URL(str.replace(" ", "%20"));
-    }
-
-    private static URL buildURLVector(String layers, String styles,
-            int width, int height,
-            EastNorth lambertMin, EastNorth lambertMax) throws MalformedURLException {
-        String str = CadastreInterface.BASE_URL+"/scpc/wms?version=1.1&request=GetMap";
-        str += "&layers="+ layers;
-        str += "&format=image/png";
-        str += "&bbox="+lambertMin.east()+",";
-        str += lambertMin.north() + ",";
-        str += lambertMax.east() + ",";
-        str += lambertMax.north();
-        str += "&width="+width+"&height="+height;
-        str += "&exception=application/vnd.ogc.se_inimage"; // works also without (but slower ?)
-        str += "&styles=" + styles;
-        Main.info("URL="+str);
-        return new URL(str.replace(" ", "%20"));
-    }
-
-    private static URL getURLVector(EastNorth lambertMin, EastNorth lambertMax) throws MalformedURLException {
-        return buildURLVector(CadastrePlugin.grabLayers, CadastrePlugin.grabStyles,
-                CadastrePlugin.imageWidth, CadastrePlugin.imageHeight,
-                lambertMin, lambertMax);
-    }
-
-    private BufferedImage grab(URL url) throws IOException, OsmTransferException {
-        try (InputStream is = wmsInterface.getContent(url)) {
-            return ImageIO.read(is);
-        }
-    }
-
-    public CadastreInterface getWmsInterface() {
-        return wmsInterface;
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastreInterface.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastreInterface.java	(revision 33637)
+++ 	(revision )
@@ -1,607 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.GridBagLayout;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.CookieHandler;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-
-import javax.swing.JComboBox;
-import javax.swing.JDialog;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.data.validation.util.Entities;
-import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
-import org.openstreetmap.josm.gui.util.GuiHelper;
-import org.openstreetmap.josm.io.OsmTransferException;
-import org.openstreetmap.josm.io.ProgressInputStream;
-import org.openstreetmap.josm.tools.GBC;
-
-public class CadastreInterface {
-    public boolean downloadCanceled;
-    private HttpURLConnection urlConn;
-
-    private String cookie;
-    private String interfaceRef;
-    private String lastWMSLayerName;
-    private URL searchFormURL;
-    private List<String> listOfCommunes = new ArrayList<>();
-    private List<String> listOfTA = new ArrayList<>();
-    static class PlanImage {
-        String name;
-        String ref;
-        PlanImage(String name, String ref) {
-            this.name = name;
-            this.ref = ref;
-        }
-    }
-
-    private List<PlanImage> listOfFeuilles = new ArrayList<>();
-    private long cookieTimestamp;
-
-    static final String BASE_URL = "https://www.cadastre.gouv.fr";
-    static final String C_IMAGE_FORMAT = "Cette commune est au format ";
-    static final String C_COMMUNE_LIST_START = "<select name=\"codeCommune\"";
-    static final String C_COMMUNE_LIST_END = "</select>";
-    static final String C_OPTION_LIST_START = "<option value=\"";
-    static final String C_OPTION_LIST_END = "</option>";
-    static final String C_BBOX_COMMUN_START = "new GeoBox(";
-    static final String C_BBOX_COMMUN_END = ")";
-
-    static final String C_INTERFACE_VECTOR = "afficherCarteCommune.do";
-    static final String C_INTERFACE_RASTER_TA = "afficherCarteTa.do";
-    static final String C_INTERFACE_RASTER_FEUILLE = "afficherCarteFeuille.do";
-    static final String C_IMAGE_LINK_START = "<a href=\"#\" class=\"raster\" onClick=\"popup('afficherCarteFeuille.do?f=";
-    static final String C_TA_IMAGE_LINK_START = "<a href=\"#\" class=\"raster\" onClick=\"popup('afficherCarteTa.do?f=";
-    static final String C_IMAGE_NAME_START = ">Feuille ";
-    static final String C_TA_IMAGE_NAME_START = "Tableau d'assemblage <strong>";
-
-    static final long COOKIE_EXPIRATION = 30 * 60 * 1000L; // 30 minutes expressed in milliseconds
-
-    static final int RETRIES_GET_COOKIE = 10; // 10 times every 3 seconds means 30 seconds trying to get a cookie
-
-    public boolean retrieveInterface(WMSLayer wmsLayer) throws DuplicateLayerException, WMSException {
-        if (wmsLayer.getName().isEmpty())
-            return false;
-        boolean isCookieExpired = isCookieExpired();
-        if (wmsLayer.getName().equals(lastWMSLayerName) && !isCookieExpired)
-            return true;
-        if (!wmsLayer.getName().equals(lastWMSLayerName))
-            interfaceRef = null;
-        // open the session with the French Cadastre web front end
-        downloadCanceled = false;
-        try {
-            if (cookie == null || isCookieExpired) {
-                getCookie();
-                interfaceRef = null;
-            }
-            if (cookie == null)
-                throw new WMSException(tr("Cannot open a new client session.\nServer in maintenance or temporary overloaded."));
-            if (interfaceRef == null) {
-                    getInterface(wmsLayer);
-                    this.lastWMSLayerName = wmsLayer.getName();
-            }
-            openInterface();
-        } catch (IOException e) {
-            Main.error(e);
-            GuiHelper.runInEDT(() ->
-                JOptionPane.showMessageDialog(Main.parent,
-                    tr("Town/city {0} not found or not available\n" +
-                            "or action canceled", wmsLayer.getLocation())));
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     *
-     * @return true if a cookie is delivered by WMS and false is WMS is not opening a client session
-     *         (too many clients or in maintenance)
-     */
-    private void getCookie() throws IOException {
-        boolean success = false;
-        int retries = RETRIES_GET_COOKIE;
-        try {
-            searchFormURL = new URL(BASE_URL + "/scpc/accueil.do");
-            while (!success && retries > 0) {
-                urlConn = (HttpURLConnection) searchFormURL.openConnection();
-                urlConn.setRequestProperty("Connection", "close");
-                urlConn.setRequestMethod("GET");
-                urlConn.connect();
-                if (urlConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
-                    Main.info("GET "+searchFormURL);
-                    BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), StandardCharsets.UTF_8));
-                    while (in.readLine() != null) {
-                        // read the buffer otherwise we sent POST too early
-                    }
-                    success = true;
-                    // See https://bugs.openjdk.java.net/browse/JDK-8036017
-                    // When a cookie handler is setup, "Set-Cookie" header returns empty values
-                    CookieHandler cookieHandler = CookieHandler.getDefault();
-                    if (cookieHandler != null) {
-                        if (handleCookie(cookieHandler.get(searchFormURL.toURI(), new HashMap<String, List<String>>()).get("Cookie").get(0))) {
-                            break;
-                        }
-                    } else {
-                        String headerName;
-                        for (int i = 1; (headerName = urlConn.getHeaderFieldKey(i)) != null; i++) {
-                            if ("Set-Cookie".equals(headerName) && handleCookie(urlConn.getHeaderField(i))) {
-                                break;
-                            }
-                        }
-                    }
-                } else {
-                    Main.warn("Request to home page failed. Http error:"+urlConn.getResponseCode()+". Try again "+retries+" times");
-                    CadastrePlugin.safeSleep(3000);
-                    retries--;
-                }
-            }
-        } catch (MalformedURLException | URISyntaxException e) {
-            throw new IOException("Illegal url.", e);
-        }
-    }
-
-    private boolean handleCookie(String pCookie) {
-        cookie = pCookie;
-        if (cookie == null || cookie.isEmpty()) {
-            Main.warn("received empty cookie");
-            cookie = null;
-        } else {
-            int index = cookie.indexOf(';');
-            if (index > -1) {
-                cookie = cookie.substring(0, index);
-            }
-            cookieTimestamp = new Date().getTime();
-            Main.info("received cookie=" + cookie + " at " + new Date(cookieTimestamp));
-        }
-        return cookie != null;
-    }
-
-    public void resetCookie() {
-        lastWMSLayerName = null;
-        cookie = null;
-    }
-
-    public boolean isCookieExpired() {
-        long now = new Date().getTime();
-        if ((now - cookieTimestamp) > COOKIE_EXPIRATION) {
-            Main.info("cookie received at "+new Date(cookieTimestamp)+" expired (now is "+new Date(now)+")");
-            return true;
-        }
-        return false;
-    }
-
-    public void resetInterfaceRefIfNewLayer(String newWMSLayerName) {
-        if (!newWMSLayerName.equals(lastWMSLayerName)) {
-            interfaceRef = null;
-            cookie = null; // new since WMS server requires that we come back to the main form
-        }
-    }
-
-    private void setCookie() {
-        this.urlConn.setRequestProperty("Cookie", this.cookie);
-    }
-
-    public void setCookie(HttpURLConnection urlConn) {
-        urlConn.setRequestProperty("Cookie", this.cookie);
-    }
-
-    private void getInterface(WMSLayer wmsLayer) throws IOException, DuplicateLayerException {
-        // first attempt : search for given name without codeCommune
-        interfaceRef = postForm(wmsLayer, "");
-        // second attempt either from known codeCommune (e.g. from cache) or from ComboBox
-        if (interfaceRef == null) {
-            if (!wmsLayer.getCodeCommune().isEmpty()) {
-                // codeCommune is already known (from previous request or from cache on disk)
-                interfaceRef = postForm(wmsLayer, wmsLayer.getCodeCommune());
-            } else {
-                if (listOfCommunes.size() > 1) {
-                    // commune unknown, prompt the list of communes from server and try with codeCommune
-                    String selected = selectMunicipalityDialog();
-                    if (selected != null) {
-                        String newCodeCommune = selected.substring(1, selected.indexOf('>') - 2);
-                        String newLocation = selected.substring(selected.indexOf('>') + 1, selected.lastIndexOf(" - "));
-                        wmsLayer.setCodeCommune(newCodeCommune);
-                        wmsLayer.setLocation(newLocation);
-                        Main.pref.put("cadastrewms.codeCommune", newCodeCommune);
-                        Main.pref.put("cadastrewms.location", newLocation);
-                    }
-                    checkLayerDuplicates(wmsLayer);
-                    interfaceRef = postForm(wmsLayer, wmsLayer.getCodeCommune());
-                }
-                if (listOfCommunes.size() == 1 && wmsLayer.isRaster()) {
-                    // commune known but raster format. Select "Feuille" (non-georeferenced image) from list.
-                    int res = selectFeuilleDialog();
-                    if (res != -1) {
-                        wmsLayer.setCodeCommune(listOfFeuilles.get(res).name);
-                        checkLayerDuplicates(wmsLayer);
-                        interfaceRef = buildRasterFeuilleInterfaceRef(wmsLayer.getCodeCommune());
-                    }
-                }
-            }
-        }
-
-        if (interfaceRef == null)
-            throw new IOException("Town/city " + wmsLayer.getLocation() + " not found.");
-    }
-
-    private void openInterface() throws IOException {
-        try {
-            // finally, open the interface on server side giving access to the wms server
-            URL interfaceURL = new URL(BASE_URL + "/scpc/"+interfaceRef);
-            urlConn = (HttpURLConnection) interfaceURL.openConnection();
-            urlConn.setRequestMethod("GET");
-            setCookie();
-            urlConn.connect();
-            if (urlConn.getResponseCode() != HttpURLConnection.HTTP_OK) {
-                throw new IOException("Cannot open Cadastre interface. GET response:"+urlConn.getResponseCode());
-            }
-            Main.info("GET "+interfaceURL);
-            BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), StandardCharsets.UTF_8));
-            // read the buffer otherwise we sent POST too early
-            StringBuilder lines = new StringBuilder();
-            String ln;
-            while ((ln = in.readLine()) != null) {
-                if (Main.isDebugEnabled()) {
-                    lines.append(ln);
-                }
-            }
-            if (Main.isDebugEnabled()) {
-                Main.debug(lines.toString());
-            }
-        } catch (MalformedURLException e) {
-            throw (IOException) new IOException(
-                "CadastreGrabber: Illegal url.").initCause(e);
-        }
-    }
-
-    /**
-     * Post the form with the commune name and check the returned answer which is embedded
-     * in HTTP XML packets. This function doesn't use an XML parser yet but that would be a good idea
-     * for the next releases.
-     * Two possibilities :
-     * - either the commune name matches and we receive an URL starting with "afficherCarteCommune.do" or
-     * - we don't receive a single answer but a list of possible values. This answer looks like:
-     *   <select name="codeCommune" class="long erreur" id="codeCommune">
-     *   <option value="">Choisir</option>
-     *   <option value="50061" >COLMARS - 04370</option>
-     *   <option value="QK066" >COLMAR - 68000</option>
-     *   </select>
-     * The returned string is the interface name used in further requests, e.g. "afficherCarteCommune.do?c=QP224"
-     * where QP224 is the code commune known by the WMS (or "afficherCarteTa.do?c=..." for raster images).
-     *
-     * @return retURL url to available code commune in the cadastre; "" if not found
-     */
-    private String postForm(WMSLayer wmsLayer, String codeCommune) throws IOException {
-        try {
-            listOfCommunes.clear();
-            listOfTA.clear();
-            // send a POST request with a city/town/village name
-            String content = "numerovoie=";
-            content += "&indiceRepetition=";
-            content += "&nomvoie=";
-            content += "&lieuDit=";
-            if (codeCommune.isEmpty()) {
-                content += "&ville=" + java.net.URLEncoder.encode(wmsLayer.getLocation(), "UTF-8");
-                content += "&codePostal=";
-            } else {
-                content += "&codeCommune=" + codeCommune;
-            }
-            content += "&codeDepartement=";
-            content += wmsLayer.getDepartement();
-            content += "&nbResultatParPage=10";
-            content += "&x=0&y=0";
-            searchFormURL = new URL(BASE_URL + "/scpc/rechercherPlan.do");
-            urlConn = (HttpURLConnection) searchFormURL.openConnection();
-            urlConn.setRequestMethod("POST");
-            urlConn.setDoOutput(true);
-            urlConn.setDoInput(true);
-            setCookie();
-            try (OutputStream wr = urlConn.getOutputStream()) {
-                wr.write(content.getBytes(StandardCharsets.UTF_8));
-                Main.info("POST "+content);
-                wr.flush();
-            }
-            String ln;
-            StringBuilder sb = new StringBuilder();
-            try (BufferedReader rd = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), StandardCharsets.UTF_8))) {
-                while ((ln = rd.readLine()) != null) {
-                    sb.append(ln);
-                }
-            }
-            String lines = sb.toString();
-            urlConn.disconnect();
-            if (lines != null) {
-                if (lines.indexOf(C_IMAGE_FORMAT) != -1) {
-                    int i = lines.indexOf(C_IMAGE_FORMAT);
-                    int j = lines.indexOf('.', i);
-                    wmsLayer.setRaster("image".equals(lines.substring(i+C_IMAGE_FORMAT.length(), j)));
-                }
-                if (!wmsLayer.isRaster() && lines.indexOf(C_INTERFACE_VECTOR) != -1) {  // "afficherCarteCommune.do"
-                    // shall be something like: interfaceRef = "afficherCarteCommune.do?c=X2269";
-                    lines = lines.substring(lines.indexOf(C_INTERFACE_VECTOR), lines.length());
-                    lines = lines.substring(0, lines.indexOf('\''));
-                    lines = Entities.unescape(lines);
-                    Main.info("interface ref.:"+lines);
-                    return lines;
-                } else if (wmsLayer.isRaster() && lines.indexOf(C_INTERFACE_RASTER_TA) != -1) { // "afficherCarteTa.do"
-                    // list of values parsed in listOfFeuilles (list all non-georeferenced images)
-                    lines = getFeuillesList();
-                    if (!downloadCanceled) {
-                        parseFeuillesList(lines);
-                        if (!listOfFeuilles.isEmpty()) {
-                            int res = selectFeuilleDialog();
-                            if (res != -1) {
-                                wmsLayer.setCodeCommune(listOfFeuilles.get(res).name);
-                                checkLayerDuplicates(wmsLayer);
-                                interfaceRef = buildRasterFeuilleInterfaceRef(wmsLayer.getCodeCommune());
-                                wmsLayer.setCodeCommune(listOfFeuilles.get(res).ref);
-                                lines = buildRasterFeuilleInterfaceRef(listOfFeuilles.get(res).ref);
-                                lines = Entities.unescape(lines);
-                                Main.info("interface ref.:"+lines);
-                                return lines;
-                            }
-                        }
-                    }
-                    return null;
-                } else if (lines.indexOf(C_COMMUNE_LIST_START) != -1 && lines.indexOf(C_COMMUNE_LIST_END) != -1) {
-                    // list of values parsed in listOfCommunes
-                    int i = lines.indexOf(C_COMMUNE_LIST_START);
-                    int j = lines.indexOf(C_COMMUNE_LIST_END, i);
-                    parseCommuneList(lines.substring(i, j));
-                }
-            }
-        } catch (MalformedURLException e) {
-            throw (IOException) new IOException("Illegal url.").initCause(e);
-        } catch (DuplicateLayerException e) {
-            Main.error(e);
-        }
-        return null;
-    }
-
-    private void parseCommuneList(String input) {
-        if (input.indexOf(C_OPTION_LIST_START) != -1) {
-            while (input.indexOf("<option value=\"") != -1) {
-                int i = input.indexOf(C_OPTION_LIST_START);
-                int j = input.indexOf(C_OPTION_LIST_END, i+C_OPTION_LIST_START.length());
-                int k = input.indexOf('"', i+C_OPTION_LIST_START.length());
-                if (j != -1 && k > (i + C_OPTION_LIST_START.length())) {
-                    String lov = input.substring(i+C_OPTION_LIST_START.length()-1, j);
-                    if (lov.indexOf('>') != -1) {
-                        Main.info("parse "+lov);
-                        listOfCommunes.add(lov);
-                    } else
-                        Main.error("unable to parse commune string:"+lov);
-                }
-                input = input.substring(j+C_OPTION_LIST_END.length());
-            }
-        }
-    }
-
-    private String getFeuillesList() {
-        // get all images in one html page
-        String ln = null;
-        StringBuilder lines = new StringBuilder();
-        HttpURLConnection urlConn2 = null;
-        try {
-            URL getAllImagesURL = new URL(BASE_URL + "/scpc/listerFeuillesParcommune.do?keepVolatileSession=&offset=2000");
-            urlConn2 = (HttpURLConnection) getAllImagesURL.openConnection();
-            setCookie(urlConn2);
-            urlConn2.connect();
-            Main.info("GET "+getAllImagesURL);
-            try (BufferedReader rd = new BufferedReader(new InputStreamReader(urlConn2.getInputStream(), StandardCharsets.UTF_8))) {
-                while ((ln = rd.readLine()) != null) {
-                    lines.append(ln);
-                }
-            }
-            urlConn2.disconnect();
-        } catch (IOException e) {
-            listOfFeuilles.clear();
-            Main.error(e);
-        }
-        return lines.toString();
-    }
-
-    private void parseFeuillesList(String input) {
-        listOfFeuilles.clear();
-        // get "Tableau d'assemblage"
-        String inputTA = input;
-        if (Main.pref.getBoolean("cadastrewms.useTA", false)) {
-            while (inputTA.indexOf(C_TA_IMAGE_LINK_START) != -1) {
-                inputTA = inputTA.substring(inputTA.indexOf(C_TA_IMAGE_LINK_START) + C_TA_IMAGE_LINK_START.length());
-                String refTA = inputTA.substring(0, inputTA.indexOf('\''));
-                String nameTA = inputTA.substring(inputTA.indexOf(C_TA_IMAGE_NAME_START) + C_TA_IMAGE_NAME_START.length());
-                nameTA = nameTA.substring(0, nameTA.indexOf('<'));
-                listOfFeuilles.add(new PlanImage(nameTA, refTA));
-            }
-        }
-        // get "Feuilles"
-        while (input.indexOf(C_IMAGE_LINK_START) != -1) {
-            input = input.substring(input.indexOf(C_IMAGE_LINK_START)+C_IMAGE_LINK_START.length());
-            String refFeuille = input.substring(0, input.indexOf('\''));
-            String nameFeuille = input.substring(
-                    input.indexOf(C_IMAGE_NAME_START)+C_IMAGE_NAME_START.length(),
-                    input.indexOf(" -"));
-            listOfFeuilles.add(new PlanImage(nameFeuille, refFeuille));
-        }
-    }
-
-    private String selectMunicipalityDialog() {
-        JPanel p = new JPanel(new GridBagLayout());
-        String[] communeList = new String[listOfCommunes.size() + 1];
-        communeList[0] = tr("Choose from...");
-        for (int i = 0; i < listOfCommunes.size(); i++) {
-            communeList[i + 1] = listOfCommunes.get(i).substring(listOfCommunes.get(i).indexOf('>')+1);
-        }
-        JComboBox<String> inputCommuneList = new JComboBox<>(communeList);
-        p.add(inputCommuneList, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 0, 0, 0));
-        JOptionPane pane = new JOptionPane(p, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null);
-        // this below is a temporary workaround to fix the "always on top" issue
-        JDialog dialog = pane.createDialog(Main.parent, tr("Select commune"));
-        CadastrePlugin.prepareDialog(dialog);
-        dialog.setVisible(true);
-        // till here
-        if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
-            return null;
-        return listOfCommunes.get(inputCommuneList.getSelectedIndex()-1);
-    }
-
-    private int selectFeuilleDialog() {
-        JPanel p = new JPanel(new GridBagLayout());
-        List<String> imageNames = new ArrayList<>();
-        for (PlanImage src : listOfFeuilles) {
-            imageNames.add(src.name);
-        }
-        JComboBox<String> inputFeuilleList = new JComboBox<>(imageNames.toArray(new String[]{}));
-        p.add(inputFeuilleList, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 0, 0, 0));
-        JOptionPane pane = new JOptionPane(p, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null);
-        // this below is a temporary workaround to fix the "always on top" issue
-        JDialog dialog = pane.createDialog(Main.parent, tr("Select Feuille"));
-        CadastrePlugin.prepareDialog(dialog);
-        dialog.setVisible(true);
-        // till here
-        if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
-            return -1;
-        return inputFeuilleList.getSelectedIndex();
-    }
-
-    private static String buildRasterFeuilleInterfaceRef(String codeCommune) {
-        return C_INTERFACE_RASTER_FEUILLE + "?f=" + codeCommune;
-    }
-
-    /**
-     * Retrieve the bounding box size in pixels of the whole commune (point 0,0 at top, left corner)
-     * and store it in given wmsLayer
-     * In case of raster image, we also check in the same http request if the image is already georeferenced
-     * and store the result in the wmsLayer as well.
-     * @param wmsLayer the WMSLayer where the commune data and images are stored
-     */
-    public void retrieveCommuneBBox(WMSLayer wmsLayer) throws IOException {
-        if (interfaceRef == null)
-            return;
-        // send GET opening normally the small window with the commune overview
-        String content = BASE_URL + "/scpc/" + interfaceRef;
-        content += "&dontSaveLastForward&keepVolatileSession=";
-        searchFormURL = new URL(content);
-        urlConn = (HttpURLConnection) searchFormURL.openConnection();
-        urlConn.setRequestMethod("GET");
-        setCookie();
-        urlConn.connect();
-        if (urlConn.getResponseCode() != HttpURLConnection.HTTP_OK) {
-            throw new IOException("Cannot get Cadastre response.");
-        }
-        Main.info("GET "+searchFormURL);
-        String ln;
-        StringBuilder sb = new StringBuilder();
-        try (BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), StandardCharsets.UTF_8))) {
-            while ((ln = in.readLine()) != null) {
-                sb.append(ln);
-            }
-        }
-        urlConn.disconnect();
-        String line = sb.toString();
-        parseBBoxCommune(wmsLayer, line);
-        if (wmsLayer.isRaster() && !wmsLayer.isAlreadyGeoreferenced()) {
-            parseGeoreferences(wmsLayer, line);
-        }
-    }
-
-    private static void parseBBoxCommune(WMSLayer wmsLayer, String input) {
-        if (input.indexOf(C_BBOX_COMMUN_START) != -1) {
-            input = input.substring(input.indexOf(C_BBOX_COMMUN_START));
-            int i = input.indexOf(',');
-            double minx = Double.parseDouble(input.substring(C_BBOX_COMMUN_START.length(), i));
-            int j = input.indexOf(',', i+1);
-            double miny = Double.parseDouble(input.substring(i+1, j));
-            int k = input.indexOf(',', j+1);
-            double maxx = Double.parseDouble(input.substring(j+1, k));
-            int l = input.indexOf(C_BBOX_COMMUN_END, k+1);
-            double maxy = Double.parseDouble(input.substring(k+1, l));
-            wmsLayer.setCommuneBBox(new EastNorthBound(new EastNorth(minx, miny), new EastNorth(maxx, maxy)));
-        }
-    }
-
-    private static void parseGeoreferences(WMSLayer wmsLayer, String input) {
-        /* commented since cadastre WMS changes mid july 2013
-         * until new GeoBox coordinates parsing is solved */
-//        if (input.lastIndexOf(cBBoxCommunStart) != -1) {
-//            input = input.substring(input.lastIndexOf(cBBoxCommunStart));
-//            input = input.substring(input.indexOf(cBBoxCommunEnd)+cBBoxCommunEnd.length());
-//            int i = input.indexOf(",");
-//            int j = input.indexOf(",", i+1);
-//            String str = input.substring(i+1, j);
-//            double unknown_yet = tryParseDouble(str);
-//            int j_ = input.indexOf(",", j+1);
-//            double angle = Double.parseDouble(input.substring(j+1, j_));
-//            int k = input.indexOf(",", j_+1);
-//            double scale_origin = Double.parseDouble(input.substring(j_+1, k));
-//            int l = input.indexOf(",", k+1);
-//            double dpi = Double.parseDouble(input.substring(k+1, l));
-//            int m = input.indexOf(",", l+1);
-//            double fX = Double.parseDouble(input.substring(l+1, m));
-//            int n = input.indexOf(",", m+1);
-//            double fY = Double.parseDouble(input.substring(m+1, n));
-//            int o = input.indexOf(",", n+1);
-//            double X0 = Double.parseDouble(input.substring(n+1, o));
-//            int p = input.indexOf(",", o+1);
-//            double Y0 = Double.parseDouble(input.substring(o+1, p));
-//            if (X0 != 0.0 && Y0 != 0) {
-//                wmsLayer.setAlreadyGeoreferenced(true);
-//                wmsLayer.fX = fX;
-//                wmsLayer.fY = fY;
-//                wmsLayer.angle = angle;
-//                wmsLayer.X0 = X0;
-//                wmsLayer.Y0 = Y0;
-//            }
-//            Main.info("parse georef:"+unknown_yet+","+angle+","+scale_origin+","+dpi+","+fX+","+fY+","+X0+","+Y0);
-//        }
-    }
-
-    private static void checkLayerDuplicates(WMSLayer wmsLayer) throws DuplicateLayerException {
-        if (Main.map != null) {
-            for (Layer l : Main.getLayerManager().getLayers()) {
-                if (l instanceof WMSLayer && l.getName().equals(wmsLayer.getName()) && (!l.equals(wmsLayer))) {
-                    Main.info("Try to grab into a new layer when "+wmsLayer.getName()+" is already opened.");
-                    // remove the duplicated layer
-                    Main.getLayerManager().removeLayer(wmsLayer);
-                    throw new DuplicateLayerException();
-                }
-            }
-        }
-    }
-
-    public void cancel() {
-        if (urlConn != null) {
-            urlConn.setConnectTimeout(1);
-            urlConn.setReadTimeout(1);
-        }
-        downloadCanceled = true;
-        lastWMSLayerName = null;
-    }
-
-    public InputStream getContent(URL url) throws IOException, OsmTransferException {
-        urlConn = (HttpURLConnection) url.openConnection();
-        urlConn.setRequestProperty("Connection", "close");
-        urlConn.setRequestMethod("GET");
-        setCookie();
-        return new ProgressInputStream(urlConn, NullProgressMonitor.INSTANCE);
-    }
-}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastrePlugin.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastrePlugin.java	(revision 33637)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastrePlugin.java	(revision 33638)
@@ -38,4 +38,16 @@
 import org.openstreetmap.josm.plugins.Plugin;
 import org.openstreetmap.josm.plugins.PluginInformation;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.MenuActionGrab;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.MenuActionGrabPlanImage;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.MenuActionLoadFromCache;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.MenuActionNewLocation;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.MenuActionOpenPreferences;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.mapmode.Address;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.mapmode.WMSAdjustAction;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.upload.CheckSourceUploadHook;
+import org.openstreetmap.josm.plugins.fr.cadastre.preferences.CadastrePreferenceSetting;
+import org.openstreetmap.josm.plugins.fr.cadastre.session.CadastreSessionExporter;
+import org.openstreetmap.josm.plugins.fr.cadastre.session.CadastreSessionImporter;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
 
 /**
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastrePreferenceSetting.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastrePreferenceSetting.java	(revision 33637)
+++ 	(revision )
@@ -1,466 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.GridBagLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.AbstractButton;
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.ButtonGroup;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JScrollPane;
-import javax.swing.JSeparator;
-import javax.swing.JSlider;
-import javax.swing.JTextField;
-import javax.swing.SwingConstants;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.preferences.DefaultTabPreferenceSetting;
-import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.I18n;
-import org.openstreetmap.josm.tools.ImageProvider;
-
-/**
- * Preference settings for the French Cadastre plugin
- *
- * @author Pieren &lt;pieren3@gmail.com&gt;
- */
-public class CadastrePreferenceSetting extends DefaultTabPreferenceSetting {
-
-    static final int TRANS_MIN = 1;
-    static final int TRANS_MAX = 10;
-    private JSlider sliderTrans = new JSlider(JSlider.HORIZONTAL, TRANS_MIN, TRANS_MAX, TRANS_MAX);
-
-    private JTextField sourcing = new JTextField(20);
-
-    private JCheckBox alterColors = new JCheckBox(tr("Replace original background by JOSM background color."));
-
-    private JCheckBox reversGrey = new JCheckBox(tr("Reverse grey colors (for black backgrounds)."));
-
-    private JCheckBox transparency = new JCheckBox(tr("Set background transparent."));
-
-    private JCheckBox drawBoundaries = new JCheckBox(tr("Draw boundaries of downloaded data."));
-
-    private JComboBox<String> imageInterpolationMethod = new JComboBox<>();
-
-    private JCheckBox disableImageCropping = new JCheckBox(tr("Disable image cropping during georeferencing."));
-
-    private JCheckBox enableTableauAssemblage = new JCheckBox(tr("Use \"Tableau d''assemblage\""));
-
-    private JCheckBox simplify2BitsColors = new JCheckBox(tr("Replace grey shades by white color only"));
-
-    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)."));
-
-    private JRadioButton grabMultiplier1 = new JRadioButton("", true);
-
-    private JRadioButton grabMultiplier2 = new JRadioButton("", true);
-
-    private JRadioButton grabMultiplier3 = new JRadioButton("", true);
-
-    private JRadioButton grabMultiplier4 = new JRadioButton("", true);
-
-    private JRadioButton crosspiece1 = new JRadioButton(tr("off"));
-
-    private JRadioButton crosspiece2 = new JRadioButton(tr("25 m"));
-
-    private JRadioButton crosspiece3 = new JRadioButton(tr("50 m"));
-
-    private JRadioButton crosspiece4 = new JRadioButton(tr("100 m"));
-
-    private JRadioButton grabRes1 = new JRadioButton(tr("high"));
-    private JRadioButton grabRes2 = new JRadioButton(tr("medium"));
-    private JRadioButton grabRes3 = new JRadioButton(tr("low"));
-
-    private JCheckBox layerLS3 = new JCheckBox(tr("water"));
-    private JCheckBox layerLS2 = new JCheckBox(tr("building"));
-    private JCheckBox layerLS1 = new JCheckBox(tr("symbol"));
-    private JCheckBox layerParcel = new JCheckBox(tr("parcel"));
-    private JCheckBox layerLabel = new JCheckBox(tr("parcel number"));
-    private JCheckBox layerNumero = new JCheckBox(tr("address"));
-    private JCheckBox layerLieudit = new JCheckBox(tr("locality"));
-    private JCheckBox layerSection = new JCheckBox(tr("section"));
-    private JCheckBox layerCommune = new JCheckBox(tr("commune"));
-
-    static final int DEFAULT_SQUARE_SIZE = 100;
-    private JTextField grabMultiplier4Size = new JTextField(5);
-
-    private JCheckBox enableCache = new JCheckBox(tr("Enable automatic caching."));
-
-    static final int DEFAULT_CACHE_SIZE = 0; // disabled by default
-    JLabel jLabelCacheSize = new JLabel(tr("Max. cache size (in MB)"));
-    private JTextField cacheSize = new JTextField(20);
-
-    static final String DEFAULT_RASTER_DIVIDER = "7";
-    private JTextField rasterDivider = new JTextField(10);
-
-    static final int DEFAULT_CROSSPIECES = 0;
-
-    static final String DEFAULT_GRAB_MULTIPLIER = Scale.SQUARE_100M.value;
-
-    /**
-     * Constructs a new {@code CadastrePreferenceSetting}.
-     */
-    public CadastrePreferenceSetting() {
-        super("cadastrewms.png", I18n.tr("French cadastre WMS"),
-            tr("A special handler of the French cadastre wms at www.cadastre.gouv.fr" + "<BR><BR>"
-                + "Please read the Terms and Conditions of Use here (in French): <br>"
-                + "<a href=\"http://www.cadastre.gouv.fr/scpc/html/CU_01_ConditionsGenerales_fr.html\"> "
-                + "http://www.cadastre.gouv.fr/scpc/html/CU_01_ConditionsGenerales_fr.html</a> <BR>"
-                + "before any upload of data created by this plugin.")
-        );
-    }
-
-    @Override
-    public void addGui(final PreferenceTabbedPane gui) {
-        JPanel cadastrewmsMast = gui.createPreferenceTab(this);
-
-        JPanel cadastrewms = new JPanel(new GridBagLayout());
-        cadastrewms.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
-
-        // option to automatically set the source tag when uploading
-        sourcing.setText(CadastrePlugin.source);
-        sourcing.setToolTipText(tr("<html>Value of key \"source\" when autosourcing is enabled</html>"));
-        JLabel jLabelSource = new JLabel(tr("Source"));
-        cadastrewms.add(jLabelSource, GBC.eop().insets(0, 0, 0, 0));
-        cadastrewms.add(sourcing, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 5));
-
-        // option to alter the original colors of the wms images
-        alterColors.setSelected(Main.pref.getBoolean("cadastrewms.alterColors", false));
-        alterColors.setToolTipText(tr("Replace the original white background by the background color defined in JOSM preferences."));
-        cadastrewms.add(alterColors, GBC.eop().insets(0, 0, 0, 0));
-
-        // option to reverse the grey colors (to see texts background)
-        reversGrey.setSelected(Main.pref.getBoolean("cadastrewms.invertGrey", false));
-        reversGrey.setToolTipText(
-                tr("Invert the original black and white colors (and all intermediate greys). Useful for texts on dark backgrounds."));
-        cadastrewms.add(reversGrey, GBC.eop().insets(0, 0, 0, 0));
-
-        // option to enable transparency
-        transparency.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                sliderTrans.setEnabled(transparency.isSelected());
-            }
-        });
-        transparency.setSelected(Main.pref.getBoolean("cadastrewms.backgroundTransparent", false));
-        transparency.setToolTipText(tr("Allows multiple layers stacking"));
-        cadastrewms.add(transparency, GBC.eop().insets(0, 0, 0, 0));
-
-        // slider for transparency level
-        sliderTrans.setSnapToTicks(true);
-        sliderTrans.setToolTipText(tr("Set WMS layers transparency. Right is opaque, left is transparent."));
-        sliderTrans.setMajorTickSpacing(10);
-        sliderTrans.setMinorTickSpacing(1);
-        sliderTrans.setValue((int) (Float.parseFloat(Main.pref.get("cadastrewms.brightness", "1.0f"))*10));
-        sliderTrans.setPaintTicks(true);
-        sliderTrans.setPaintLabels(false);
-        sliderTrans.setEnabled(transparency.isSelected());
-        cadastrewms.add(sliderTrans, GBC.eol().fill(GBC.HORIZONTAL).insets(20, 0, 250, 0));
-
-        // option to draw boundaries of downloaded data
-        drawBoundaries.setSelected(Main.pref.getBoolean("cadastrewms.drawBoundaries", false));
-        drawBoundaries.setToolTipText(tr("Draw a rectangle around downloaded data from WMS server."));
-        cadastrewms.add(drawBoundaries, GBC.eop().insets(0, 0, 0, 5));
-
-        // option to select the single grabbed image resolution
-        JLabel jLabelRes = new JLabel(tr("Image resolution:"));
-        cadastrewms.add(jLabelRes, GBC.std().insets(0, 5, 10, 0));
-        ButtonGroup bgResolution = new ButtonGroup();
-        grabRes1.setToolTipText(tr("High resolution (1000x800)"));
-        grabRes2.setToolTipText(tr("Medium resolution (800x600)"));
-        grabRes3.setToolTipText(tr("Low resolution (600x400)"));
-        bgResolution.add(grabRes1);
-        bgResolution.add(grabRes2);
-        bgResolution.add(grabRes3);
-        String currentResolution = Main.pref.get("cadastrewms.resolution", "high");
-        if (currentResolution.equals("high"))
-            grabRes1.setSelected(true);
-        if (currentResolution.equals("medium"))
-            grabRes2.setSelected(true);
-        if (currentResolution.equals("low"))
-            grabRes3.setSelected(true);
-        cadastrewms.add(grabRes1, GBC.std().insets(5, 0, 5, 0));
-        cadastrewms.add(grabRes2, GBC.std().insets(5, 0, 5, 0));
-        cadastrewms.add(grabRes3, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 0, 5));
-
-        // option to select image zooming interpolation method
-        JLabel jLabelImageZoomInterpolation = new JLabel(tr("Image filter interpolation:"));
-        cadastrewms.add(jLabelImageZoomInterpolation, GBC.std().insets(0, 0, 10, 0));
-        imageInterpolationMethod.addItem(tr("Nearest-Neighbor (fastest) [ Default ]"));
-        imageInterpolationMethod.addItem(tr("Bilinear (fast)"));
-        imageInterpolationMethod.addItem(tr("Bicubic (slow)"));
-        String savedImageInterpolationMethod = Main.pref.get("cadastrewms.imageInterpolation", "standard");
-        if (savedImageInterpolationMethod.equals("bilinear"))
-            imageInterpolationMethod.setSelectedIndex(1);
-        else if (savedImageInterpolationMethod.equals("bicubic"))
-            imageInterpolationMethod.setSelectedIndex(2);
-        else
-            imageInterpolationMethod.setSelectedIndex(0);
-        cadastrewms.add(imageInterpolationMethod, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 200, 5));
-
-        // separator
-        cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
-
-        // the vectorized images multiplier
-        JLabel jLabelScale = new JLabel(tr("Vector images grab multiplier:"));
-        cadastrewms.add(jLabelScale, GBC.std().insets(0, 5, 10, 0));
-        ButtonGroup bgGrabMultiplier = new ButtonGroup();
-        ActionListener multiplierActionListener = new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent actionEvent) {
-              AbstractButton button = (AbstractButton) actionEvent.getSource();
-              grabMultiplier4Size.setEnabled(button == grabMultiplier4);
-            }
-          };
-        grabMultiplier1.setIcon(ImageProvider.get("preferences", "unsel_box_1"));
-        grabMultiplier1.setSelectedIcon(ImageProvider.get("preferences", "sel_box_1"));
-        grabMultiplier1.addActionListener(multiplierActionListener);
-        grabMultiplier1.setToolTipText(tr("Grab one image full screen"));
-        grabMultiplier2.setIcon(ImageProvider.get("preferences", "unsel_box_2"));
-        grabMultiplier2.setSelectedIcon(ImageProvider.get("preferences", "sel_box_2"));
-        grabMultiplier2.addActionListener(multiplierActionListener);
-        grabMultiplier2.setToolTipText(tr("Grab smaller images (higher quality but use more memory)"));
-        grabMultiplier3.setIcon(ImageProvider.get("preferences", "unsel_box_3"));
-        grabMultiplier3.setSelectedIcon(ImageProvider.get("preferences", "sel_box_3"));
-        grabMultiplier3.addActionListener(multiplierActionListener);
-        grabMultiplier3.setToolTipText(tr("Grab smaller images (higher quality but use more memory)"));
-        grabMultiplier4.setIcon(ImageProvider.get("preferences", "unsel_box_4"));
-        grabMultiplier4.setSelectedIcon(ImageProvider.get("preferences", "sel_box_4"));
-        grabMultiplier4.addActionListener(multiplierActionListener);
-        grabMultiplier4.setToolTipText(tr("Fixed size square (default is 100m)"));
-        bgGrabMultiplier.add(grabMultiplier1);
-        bgGrabMultiplier.add(grabMultiplier2);
-        bgGrabMultiplier.add(grabMultiplier3);
-        bgGrabMultiplier.add(grabMultiplier4);
-        String currentScale = Main.pref.get("cadastrewms.scale", DEFAULT_GRAB_MULTIPLIER);
-        if (currentScale.equals(Scale.X1.value))
-            grabMultiplier1.setSelected(true);
-        if (currentScale.equals(Scale.X2.value))
-            grabMultiplier2.setSelected(true);
-        if (currentScale.equals(Scale.X3.value))
-            grabMultiplier3.setSelected(true);
-        if (currentScale.equals(Scale.SQUARE_100M.value))
-            grabMultiplier4.setSelected(true);
-        cadastrewms.add(grabMultiplier1, GBC.std().insets(5, 0, 5, 0));
-        cadastrewms.add(grabMultiplier2, GBC.std().insets(5, 0, 5, 0));
-        cadastrewms.add(grabMultiplier3, GBC.std().insets(5, 0, 5, 0));
-        cadastrewms.add(grabMultiplier4, GBC.std().insets(5, 0, 5, 0));
-        int squareSize = getNumber("cadastrewms.squareSize", DEFAULT_SQUARE_SIZE);
-        grabMultiplier4Size.setText(String.valueOf(squareSize));
-        grabMultiplier4Size.setToolTipText(tr("Fixed size (from 25 to 1000 meters)"));
-        grabMultiplier4Size.setEnabled(currentScale.equals(Scale.SQUARE_100M.value));
-        cadastrewms.add(grabMultiplier4Size, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 0, 5));
-
-        // WMS layers selection
-        JLabel jLabelLayers = new JLabel(tr("Layers:"));
-        cadastrewms.add(jLabelLayers, GBC.std().insets(0, 5, 10, 0));
-        layerLS3.setSelected(Main.pref.getBoolean("cadastrewms.layerWater", true));
-        layerLS3.setToolTipText(tr("Sea, rivers, swimming pools."));
-        cadastrewms.add(layerLS3, GBC.std().insets(5, 0, 5, 0));
-        layerLS2.setSelected(Main.pref.getBoolean("cadastrewms.layerBuilding", true));
-        layerLS2.setToolTipText(tr("Buildings, covers, underground constructions."));
-        cadastrewms.add(layerLS2, GBC.std().insets(5, 0, 5, 0));
-        layerLS1.setSelected(Main.pref.getBoolean("cadastrewms.layerSymbol", true));
-        layerLS1.setToolTipText(tr("Symbols like cristian cross."));
-        cadastrewms.add(layerLS1, GBC.std().insets(5, 0, 5, 0));
-        layerParcel.setSelected(Main.pref.getBoolean("cadastrewms.layerParcel", true));
-        layerParcel.setToolTipText(tr("Parcels."));
-        cadastrewms.add(layerParcel, GBC.eop().insets(5, 0, 5, 0));
-        layerLabel.setSelected(Main.pref.getBoolean("cadastrewms.layerLabel", true));
-        layerLabel.setToolTipText(tr("Parcels numbers, street names."));
-        cadastrewms.add(layerLabel, GBC.std().insets(70, 0, 5, 0));
-        layerNumero.setSelected(Main.pref.getBoolean("cadastrewms.layerNumero", true));
-        layerNumero.setToolTipText(tr("Address, houses numbers."));
-        cadastrewms.add(layerNumero, GBC.std().insets(5, 0, 5, 0));
-        layerLieudit.setSelected(Main.pref.getBoolean("cadastrewms.layerLieudit", true));
-        layerLieudit.setToolTipText(tr("Locality, hamlet, place."));
-        cadastrewms.add(layerLieudit, GBC.std().insets(5, 0, 5, 0));
-        layerSection.setSelected(Main.pref.getBoolean("cadastrewms.layerSection", true));
-        layerSection.setToolTipText(tr("Cadastral sections and subsections."));
-        cadastrewms.add(layerSection, GBC.std().insets(5, 0, 5, 0));
-        layerCommune.setSelected(Main.pref.getBoolean("cadastrewms.layerCommune", true));
-        layerCommune.setToolTipText(tr("Municipality administrative borders."));
-        cadastrewms.add(layerCommune, GBC.eop().insets(5, 0, 5, 0));
-
-        // separator
-        cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
-
-        // for raster images (not vectorized), image grab divider (from 1 to 12)
-        String savedRasterDivider = Main.pref.get("cadastrewms.rasterDivider", DEFAULT_RASTER_DIVIDER);
-        JLabel jLabelRasterDivider = new JLabel(tr("Raster images grab multiplier:"));
-        rasterDivider.setText(savedRasterDivider);
-        rasterDivider.setToolTipText("Raster image grab division, from 1 to 12; 12 is very high definition");
-        cadastrewms.add(jLabelRasterDivider, GBC.std().insets(0, 5, 10, 0));
-        cadastrewms.add(rasterDivider, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 200, 5));
-        // 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.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));
-        // option to use 2 bits colors only
-        simplify2BitsColors.setSelected(Main.pref.getBoolean("cadastrewms.raster2bitsColors", false));
-        simplify2BitsColors.setToolTipText(tr("Replace greyscale by white color (smaller files and memory usage)."));
-        cadastrewms.add(simplify2BitsColors, 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));
-        ButtonGroup bgCrosspieces = new ButtonGroup();
-        int crosspieces = getNumber("cadastrewms.crosspieces", DEFAULT_CROSSPIECES);
-        if (crosspieces == 0) crosspiece1.setSelected(true);
-        if (crosspieces == 1) crosspiece2.setSelected(true);
-        if (crosspieces == 2) crosspiece3.setSelected(true);
-        if (crosspieces == 3) crosspiece4.setSelected(true);
-        bgCrosspieces.add(crosspiece1);
-        bgCrosspieces.add(crosspiece2);
-        bgCrosspieces.add(crosspiece3);
-        bgCrosspieces.add(crosspiece4);
-        cadastrewms.add(crosspiece1, GBC.std().insets(5, 0, 5, 0));
-        cadastrewms.add(crosspiece2, GBC.std().insets(5, 0, 5, 0));
-        cadastrewms.add(crosspiece3, GBC.std().insets(5, 0, 5, 0));
-        cadastrewms.add(crosspiece4, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 0, 5));
-
-        // separator
-        cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
-
-        // option to enable automatic caching
-        enableCache.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                jLabelCacheSize.setEnabled(enableCache.isSelected());
-                cacheSize.setEnabled(enableCache.isSelected());
-            }
-        });
-        enableCache.setSelected(Main.pref.getBoolean("cadastrewms.enableCaching", true));
-        enableCache.setToolTipText(tr("Allows an automatic caching"));
-        cadastrewms.add(enableCache, GBC.eop().insets(0, 0, 0, 0));
-
-        // option to fix the cache size(in MB)
-        int size = getNumber("cadastrewms.cacheSize", DEFAULT_CACHE_SIZE);
-        cacheSize.setText(String.valueOf(size));
-        cacheSize.setToolTipText(tr("Oldest files are automatically deleted when this size is exceeded"));
-        cadastrewms.add(jLabelCacheSize, GBC.std().insets(20, 0, 0, 0));
-        cadastrewms.add(cacheSize, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 200, 5));
-
-        // separator
-        cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
-
-        // option to select the first WMS layer
-        autoFirstLayer.setSelected(Main.pref.getBoolean("cadastrewms.autoFirstLayer", false));
-        autoFirstLayer.setToolTipText(tr("Automatically selects the first WMS layer if multiple layers exist when grabbing."));
-        cadastrewms.add(autoFirstLayer, GBC.eop().insets(0, 0, 0, 0));
-
-        // separator
-        cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
-
-        // option to use or not relations in addresses
-        dontUseRelation.setSelected(Main.pref.getBoolean("cadastrewms.addr.dontUseRelation", false));
-        dontUseRelation.setToolTipText(tr("Enable this to use the tag \"add:street\" on nodes."));
-        cadastrewms.add(dontUseRelation, GBC.eop().insets(0, 0, 0, 0));
-
-        // end of dialog, scroll bar
-        cadastrewms.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
-        JScrollPane scrollpane = new JScrollPane(cadastrewms);
-        scrollpane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
-        cadastrewmsMast.add(scrollpane, GBC.eol().fill(GBC.BOTH));
-    }
-
-    @Override
-    public boolean ok() {
-        Main.pref.put("cadastrewms.source", sourcing.getText());
-        CadastrePlugin.source = sourcing.getText();
-        Main.pref.put("cadastrewms.alterColors", alterColors.isSelected());
-        Main.pref.put("cadastrewms.invertGrey", reversGrey.isSelected());
-        Main.pref.put("cadastrewms.backgroundTransparent", transparency.isSelected());
-        Main.pref.put("cadastrewms.brightness", Float.toString((float) sliderTrans.getValue()/10));
-        Main.pref.put("cadastrewms.drawBoundaries", drawBoundaries.isSelected());
-        if (grabRes1.isSelected())
-            Main.pref.put("cadastrewms.resolution", "high");
-        else if (grabRes2.isSelected())
-            Main.pref.put("cadastrewms.resolution", "medium");
-        else if (grabRes3.isSelected())
-            Main.pref.put("cadastrewms.resolution", "low");
-        if (imageInterpolationMethod.getSelectedIndex() == 2)
-            Main.pref.put("cadastrewms.imageInterpolation", "bicubic");
-        else if (imageInterpolationMethod.getSelectedIndex() == 1)
-            Main.pref.put("cadastrewms.imageInterpolation", "bilinear");
-        else
-            Main.pref.put("cadastrewms.imageInterpolation", "standard");
-        if (grabMultiplier1.isSelected())
-            Main.pref.put("cadastrewms.scale", Scale.X1.toString());
-        else if (grabMultiplier2.isSelected())
-            Main.pref.put("cadastrewms.scale", Scale.X2.toString());
-        else if (grabMultiplier3.isSelected())
-            Main.pref.put("cadastrewms.scale", Scale.X3.toString());
-        else {
-            Main.pref.put("cadastrewms.scale", Scale.SQUARE_100M.toString());
-            try {
-                int squareSize = Integer.parseInt(grabMultiplier4Size.getText());
-                if (squareSize >= 25 && squareSize <= 1000)
-                    Main.pref.put("cadastrewms.squareSize", grabMultiplier4Size.getText());
-            } catch (NumberFormatException e) {
-                Main.debug(e);
-            }
-        }
-        Main.pref.put("cadastrewms.layerWater", layerLS3.isSelected());
-        Main.pref.put("cadastrewms.layerBuilding", layerLS2.isSelected());
-        Main.pref.put("cadastrewms.layerSymbol", layerLS1.isSelected());
-        Main.pref.put("cadastrewms.layerParcel", layerParcel.isSelected());
-        Main.pref.put("cadastrewms.layerLabel", layerLabel.isSelected());
-        Main.pref.put("cadastrewms.layerNumero", layerNumero.isSelected());
-        Main.pref.put("cadastrewms.layerLieudit", layerLieudit.isSelected());
-        Main.pref.put("cadastrewms.layerSection", layerSection.isSelected());
-        Main.pref.put("cadastrewms.layerCommune", layerCommune.isSelected());
-        try {
-            int i = Integer.parseInt(rasterDivider.getText());
-            if (i > 0 && i < 13)
-                Main.pref.put("cadastrewms.rasterDivider", String.valueOf(i));
-        } catch (NumberFormatException e) {
-            Main.debug(e);
-        }
-        Main.pref.put("cadastrewms.noImageCropping", disableImageCropping.isSelected());
-        Main.pref.put("cadastrewms.useTA", enableTableauAssemblage.isSelected());
-        Main.pref.put("cadastrewms.raster2bitsColors", simplify2BitsColors.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");
-        else if (crosspiece4.isSelected()) Main.pref.put("cadastrewms.crosspieces", "3");
-        Main.pref.put("cadastrewms.enableCaching", enableCache.isSelected());
-
-        // spread data into objects instead of restarting the application
-        try {
-            CacheControl.cacheSize = Integer.parseInt(cacheSize.getText());
-            Main.pref.put("cadastrewms.cacheSize", String.valueOf(CacheControl.cacheSize));
-        } catch (NumberFormatException e) {
-            Main.debug(e);
-        }
-        Main.pref.put("cadastrewms.autoFirstLayer", autoFirstLayer.isSelected());
-        CacheControl.cacheEnabled = enableCache.isSelected();
-        Main.pref.put("cadastrewms.addr.dontUseRelation", dontUseRelation.isSelected());
-        CadastrePlugin.refreshConfiguration();
-        CadastrePlugin.refreshMenu();
-
-        return false;
-    }
-
-    private int getNumber(String pref_parameter, int def_value) {
-        try {
-            return Integer.parseInt(Main.pref.get(pref_parameter, String.valueOf(def_value)));
-        } catch (NumberFormatException e) {
-            return def_value;
-        }
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastreSessionExporter.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastreSessionExporter.java	(revision 33637)
+++ 	(revision )
@@ -1,81 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import java.awt.Component;
-import java.awt.GridBagLayout;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URL;
-import java.util.Collection;
-import java.util.Collections;
-
-import javax.swing.JCheckBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.SwingConstants;
-
-import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.io.session.SessionLayerExporter;
-import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport;
-import org.openstreetmap.josm.tools.GBC;
-import org.w3c.dom.Element;
-
-public class CadastreSessionExporter implements SessionLayerExporter {
-
-    private WMSLayer layer;
-    private JCheckBox export;
-
-    public CadastreSessionExporter(WMSLayer layer) {
-        this.layer = layer;
-    }
-
-    @Override
-    public Collection<Layer> getDependencies() {
-        return Collections.emptySet();
-    }
-
-    @Override
-    public Component getExportPanel() {
-        final JPanel p = new JPanel(new GridBagLayout());
-        export = new JCheckBox();
-        export.setSelected(true);
-        final JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEFT);
-        lbl.setToolTipText(layer.getToolTipText());
-        p.add(export, GBC.std());
-        p.add(lbl, GBC.std());
-        p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
-        return p;
-    }
-
-    @Override
-    public boolean shallExport() {
-        return export.isSelected();
-    }
-
-    @Override
-    public boolean requiresZip() {
-        return false;
-    }
-
-    @Override
-    public Element export(ExportSupport support) throws IOException {
-        Element layerEl = support.createElement("layer");
-        layerEl.setAttribute("type", "cadastre-fr");
-        layerEl.setAttribute("version", "0.1");
-
-        Element file = support.createElement("file");
-        layerEl.appendChild(file);
-
-        URI uri = layer.getAssociatedFile().toURI();
-        URL url = null;
-        try {
-            url = uri.toURL();
-        } catch (MalformedURLException e) {
-            throw new IOException(e);
-        }
-        file.appendChild(support.createTextNode(url.toString()));
-        return layerEl;
-    }
-
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastreSessionImporter.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CadastreSessionImporter.java	(revision 33637)
+++ 	(revision )
@@ -1,65 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URLDecoder;
-
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-
-import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.io.IllegalDataException;
-import org.openstreetmap.josm.io.session.SessionLayerImporter;
-import org.openstreetmap.josm.io.session.SessionReader.ImportSupport;
-import org.w3c.dom.Element;
-
-public class CadastreSessionImporter implements SessionLayerImporter {
-
-    @Override
-    public Layer load(Element elem, ImportSupport support,
-            ProgressMonitor progressMonitor) throws IOException,
-            IllegalDataException {
-        String version = elem.getAttribute("version");
-        if (!"0.1".equals(version)) {
-            throw new IllegalDataException(tr("Version ''{0}'' of meta data for imagery layer is not supported. Expected: 0.1", version));
-        }
-        try {
-            XPathFactory xPathFactory = XPathFactory.newInstance();
-            XPath xpath = xPathFactory.newXPath();
-            XPathExpression fileExp = xpath.compile("file/text()");
-            String fileStr = (String) fileExp.evaluate(elem, XPathConstants.STRING);
-            if (fileStr == null || fileStr.isEmpty()) {
-                throw new IllegalDataException(tr("File name expected for layer no. {0}", support.getLayerIndex()));
-            }
-
-            fileStr = URLDecoder.decode(fileStr, "UTF-8");
-            fileStr = fileStr.substring(fileStr.indexOf(":/")+2);
-            String filename = fileStr.substring(fileStr.lastIndexOf('/')+1, fileStr.length());
-            String ext = (filename.lastIndexOf('.') == -1) ? "" : filename.substring(filename.lastIndexOf('.')+1, filename.length());
-            // create layer and load cache
-            if (ext.length() == 3 && ext.substring(0, CacheControl.C_LAMBERT_CC_9Z.length()).equals(CacheControl.C_LAMBERT_CC_9Z))
-                ext = ext.substring(2);
-            else if (ext.length() == 4 && ext.substring(0, CacheControl.C_UTM20N.length()).equals(CacheControl.C_UTM20N))
-                ext = ext.substring(3);
-            else if (ext.length() == 2 || ext.length() > 4)
-                throw new IllegalDataException(tr("Unexpected file extension. {0}", ext));
-
-            int layoutZone = Integer.parseInt(ext)-1;
-            WMSLayer wmsLayer = new WMSLayer("", "", layoutZone);
-            File file = new File(fileStr);
-            wmsLayer.grabThread.getCacheControl().loadCache(file, layoutZone);
-            return wmsLayer;
-
-        } catch (XPathExpressionException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CheckSourceUploadHook.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/CheckSourceUploadHook.java	(revision 33637)
+++ 	(revision )
@@ -1,89 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.GridBagLayout;
-import java.util.Collection;
-import java.util.HashSet;
-
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.upload.UploadHook;
-import org.openstreetmap.josm.command.ChangePropertyCommand;
-import org.openstreetmap.josm.data.APIDataSet;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
-import org.openstreetmap.josm.tools.GBC;
-
-/**
- * This hook is called at JOSM upload and will check if new nodes and ways provide
- * a tag "source=". If not and if auto-sourcing is enabled, it will add
- * automatically a tag "source"="Cadastre..." as defined in the plugin preferences.
- */
-public class CheckSourceUploadHook implements UploadHook {
-
-    /**
-     * Add the tag "source" if it doesn't exist for all new Nodes and Ways before uploading
-     */
-    @Override
-    public boolean checkUpload(APIDataSet apiDataSet) {
-        if (CadastrePlugin.autoSourcing && CadastrePlugin.pluginUsed && !apiDataSet.getPrimitivesToAdd().isEmpty()) {
-            Collection<OsmPrimitive> sel = new HashSet<>();
-            for (OsmPrimitive osm : apiDataSet.getPrimitivesToAdd()) {
-                if ((osm instanceof Way && (osm.getKeys().size() == 0 || !tagSourceExist(osm)))
-                 || (osm instanceof Node && osm.getKeys().size() > 0 && !tagSourceExist(osm))) {
-                    sel.add(osm);
-                }
-            }
-            if (!sel.isEmpty()) {
-                displaySource(sel);
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Check whenever one of the keys of the object is "source"
-     * @return true if one of keys is "source"
-     */
-    private boolean tagSourceExist(OsmPrimitive osm) {
-        for (String key : osm.keySet()) {
-            if (key.equals("source")) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Displays a screen with the list of objects which will be tagged with
-     * source="cadastre.." if it is approved.
-     * @param sel the list of elements added without a key "source"
-     */
-    private void displaySource(Collection<OsmPrimitive> sel) {
-        if (!sel.isEmpty()) {
-            JPanel p = new JPanel(new GridBagLayout());
-            OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
-            p.add(new JLabel(tr("Add \"source=...\" to elements?")), GBC.eol());
-            JTextField tf = new JTextField(CadastrePlugin.source);
-            p.add(tf, GBC.eol());
-            JList<OsmPrimitive> l = new JList<>(sel.toArray(new OsmPrimitive[0]));
-            l.setCellRenderer(renderer);
-            l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
-            p.add(new JScrollPane(l), GBC.eol().fill());
-            boolean bContinue = JOptionPane.showConfirmDialog(Main.parent, p, tr("Add \"source=...\" to elements?"),
-                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
-            if (bContinue)
-                Main.main.undoRedo.add(new ChangePropertyCommand(sel, "source", tf.getText()));
-        }
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/DownloadSVGBuilding.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/DownloadSVGBuilding.java	(revision 33637)
+++ 	(revision )
@@ -1,283 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.AddCommand;
-import org.openstreetmap.josm.command.Command;
-import org.openstreetmap.josm.command.SequenceCommand;
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.gui.PleaseWaitRunnable;
-import org.openstreetmap.josm.io.OsmTransferException;
-
-public class DownloadSVGBuilding extends PleaseWaitRunnable {
-
-    private WMSLayer wmsLayer;
-    private CadastreInterface wmsInterface;
-    private String svg;
-    private static EastNorthBound currentView;
-    private EastNorthBound viewBox;
-    private static String errorMessage;
-
-    /**
-     * Constructs a new {@code DownloadSVGBuilding}.
-     */
-    public DownloadSVGBuilding(WMSLayer wmsLayer) {
-        super(tr("Downloading {0}", wmsLayer.getName()));
-
-        this.wmsLayer = wmsLayer;
-        this.wmsInterface = wmsLayer.grabber.getWmsInterface();
-    }
-
-    @Override
-    public void realRun() throws IOException, OsmTransferException {
-        progressMonitor.indeterminateSubTask(tr("Contacting WMS Server..."));
-        errorMessage = null;
-        try {
-            if (wmsInterface.retrieveInterface(wmsLayer)) {
-                svg = grabBoundary(currentView);
-                if (svg == null)
-                    return;
-                getViewBox(svg);
-                if (viewBox == null)
-                    return;
-                createBuildings(svg);
-            }
-        } catch (DuplicateLayerException e) {
-            Main.warn("removed a duplicated layer");
-        } catch (WMSException e) {
-            errorMessage = e.getMessage();
-            wmsLayer.grabber.getWmsInterface().resetCookie();
-        }
-    }
-
-    @Override
-    protected void cancel() {
-        wmsLayer.grabber.getWmsInterface().cancel();
-    }
-
-    @Override
-    protected void finish() {
-        // Do nothing
-    }
-
-    private boolean getViewBox(String svg) {
-        double[] box = new SVGParser().getViewBox(svg);
-        if (box != null) {
-            viewBox = new EastNorthBound(new EastNorth(box[0], box[1]),
-                    new EastNorth(box[0]+box[2], box[1]+box[3]));
-            return true;
-        }
-        Main.warn("Unable to parse SVG data (viewBox)");
-        return false;
-    }
-
-    /**
-     *  The svg contains more than one commune boundary defined by path elements. So detect
-     *  which path element is the best fitting to the viewBox and convert it to OSM objects
-     */
-    private void createBuildings(String svg) {
-        String[] SVGpaths = new SVGParser().getClosedPaths(svg);
-        ArrayList<ArrayList<EastNorth>> eastNorths = new ArrayList<>();
-
-        // convert SVG nodes to eastNorth coordinates
-        for (int i = 0; i < SVGpaths.length; i++) {
-            ArrayList<EastNorth> eastNorth = new ArrayList<>();
-            createNodes(SVGpaths[i], eastNorth);
-            if (eastNorth.size() > 2)
-                eastNorths.add(eastNorth);
-        }
-
-        // create nodes and closed ways
-        DataSet svgDataSet = new DataSet();
-        for (ArrayList<EastNorth> path : eastNorths) {
-            Way wayToAdd = new Way();
-            for (EastNorth eastNorth : path) {
-                Node nodeToAdd = new Node(Main.getProjection().eastNorth2latlon(eastNorth));
-                // check if new node is not already created by another new path
-                Node nearestNewNode = checkNearestNode(nodeToAdd, svgDataSet.getNodes());
-                if (nodeToAdd.equals(nearestNewNode))
-                    svgDataSet.addPrimitive(nearestNewNode);
-                wayToAdd.addNode(nearestNewNode); // either a new node or an existing one
-            }
-            wayToAdd.addNode(wayToAdd.getNode(0)); // close the way
-            svgDataSet.addPrimitive(wayToAdd);
-        }
-
-        // TODO remove small boxes (4 nodes with less than 1 meter distance)
-        /*
-        for (Way w : svgDataSet.ways)
-            if (w.nodes.size() == 5)
-                for (int i = 0; i < w.nodes.size()-2; i++) {
-                    if (w.nodes.get(i).eastNorth.distance(w.nodes.get(i+1).eastNorth))
-                }*/
-
-        // simplify ways and check if we can reuse existing OSM nodes
-//        for (Way wayToAdd : svgDataSet.getWays())
-//            new SimplifyWay().simplifyWay(wayToAdd, svgDataSet, 0.5);
-        // check if the new way or its nodes is already in OSM layer
-        for (Node n : svgDataSet.getNodes()) {
-            Node nearestNewNode = checkNearestNode(n, Main.getLayerManager().getEditDataSet().getNodes());
-            if (nearestNewNode != n) {
-                // replace the SVG node by the OSM node
-                for (Way w : svgDataSet.getWays()) {
-                    int replaced = 0;
-                    for (Node node : w.getNodes()) {
-                        if (node == n) {
-                            node = nearestNewNode;
-                            replaced++;
-                        }
-                    }
-                    if (w.getNodesCount() == replaced)
-                        w.setDeleted(true);
-                }
-                n.setDeleted(true);
-            }
-
-        }
-
-        Collection<Command> cmds = new LinkedList<>();
-        for (Node node : svgDataSet.getNodes()) {
-            if (!node.isDeleted())
-                cmds.add(new AddCommand(node));
-        }
-        for (Way way : svgDataSet.getWays()) {
-            if (!way.isDeleted())
-                cmds.add(new AddCommand(way));
-        }
-        Main.main.undoRedo.add(new SequenceCommand(tr("Create buildings"), cmds));
-        Main.map.repaint();
-    }
-
-    private void createNodes(String SVGpath, ArrayList<EastNorth> eastNorth) {
-        // looks like "M981283.38 368690.15l143.81 72.46 155.86 ..."
-        String[] coor = SVGpath.split("[MlZ ]"); //coor[1] is x, coor[2] is y
-        double dx = Double.parseDouble(coor[1]);
-        double dy = Double.parseDouble(coor[2]);
-        for (int i = 3; i < coor.length; i += 2) {
-            if (coor[i].isEmpty()) {
-                eastNorth.clear(); // some paths are just artifacts
-                return;
-            }
-            double east = dx += Double.parseDouble(coor[i]);
-            double north = dy += Double.parseDouble(coor[i+1]);
-            eastNorth.add(new EastNorth(east, north));
-        }
-        // flip the image (svg using a reversed Y coordinate system)
-        double pivot = viewBox.min.getY() + (viewBox.max.getY() - viewBox.min.getY()) / 2;
-        for (int i = 0; i < eastNorth.size(); i++) {
-            EastNorth en = eastNorth.get(i);
-            eastNorth.set(i, new EastNorth(en.east(), 2 * pivot - en.north()));
-        }
-        return;
-    }
-
-    /**
-     * Check if node can be reused.
-     * @param nodeToAdd the candidate as new node
-     * @return the already existing node (if any), otherwise the new node candidate.
-     */
-    private static Node checkNearestNode(Node nodeToAdd, Collection<Node> nodes) {
-        double epsilon = 0.05; // smallest distance considering duplicate node
-        for (Node n : nodes) {
-            if (!n.isDeleted() && !n.isIncomplete()) {
-                double dist = n.getEastNorth().distance(nodeToAdd.getEastNorth());
-                if (dist < epsilon) {
-                    return n;
-                }
-            }
-        }
-        return nodeToAdd;
-    }
-
-    private String grabBoundary(EastNorthBound bbox) throws IOException, OsmTransferException {
-        try {
-            URL url = null;
-            url = getURLsvg(bbox);
-            return grabSVG(url);
-        } catch (MalformedURLException e) {
-            throw (IOException) new IOException(tr("CadastreGrabber: Illegal url.")).initCause(e);
-        }
-    }
-
-    private static URL getURLsvg(EastNorthBound bbox) throws MalformedURLException {
-        String str = CadastreInterface.BASE_URL+"/scpc/wms?version=1.1&request=GetMap";
-        str += "&layers=";
-        str += "CDIF:LS2";
-        str += "&format=image/svg";
-        str += "&bbox="+bbox.min.east()+",";
-        str += bbox.min.north() + ",";
-        str += bbox.max.east() + ",";
-        str += bbox.max.north();
-        str += "&width="+CadastrePlugin.imageWidth+"&height="+CadastrePlugin.imageHeight;
-        str += "&exception=application/vnd.ogc.se_inimage";
-        str += "&styles=";
-        str += "LS2_90";
-        Main.info("URL="+str);
-        return new URL(str.replace(" ", "%20"));
-    }
-
-    private String grabSVG(URL url) throws IOException, OsmTransferException {
-        File file = new File(CadastrePlugin.cacheDir + "building.svg");
-        String svg = "";
-        try (InputStream is = wmsInterface.getContent(url)) {
-            if (file.exists())
-                file.delete();
-            try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file, true));
-                 InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
-                 BufferedReader br = new BufferedReader(isr)) {
-                String line;
-                while (null != (line = br.readLine())) {
-                    line += "\n";
-                    bos.write(line.getBytes(StandardCharsets.UTF_8));
-                    svg += line;
-                }
-            }
-        } catch (IOException e) {
-            Main.error(e);
-        }
-        return svg;
-    }
-
-    public static void download(WMSLayer wmsLayer) {
-        MapView mv = Main.map.mapView;
-        currentView = new EastNorthBound(mv.getEastNorth(0, mv.getHeight()),
-                mv.getEastNorth(mv.getWidth(), 0));
-        if ((currentView.max.east() - currentView.min.east()) > 1000 ||
-                (currentView.max.north() - currentView.min.north() > 1000)) {
-            JOptionPane.showMessageDialog(Main.parent,
-                    tr("To avoid cadastre WMS overload,\nbuilding import size is limited to 1 km2 max."));
-            return;
-        }
-        if (CadastrePlugin.autoSourcing == false) {
-            JOptionPane.showMessageDialog(Main.parent,
-                    tr("Please, enable auto-sourcing and check cadastre millesime."));
-            return;
-        }
-        Main.worker.execute(new DownloadSVGBuilding(wmsLayer));
-        if (errorMessage != null)
-            JOptionPane.showMessageDialog(Main.parent, errorMessage);
-    }
-
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/DownloadSVGTask.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/DownloadSVGTask.java	(revision 33637)
+++ 	(revision )
@@ -1,224 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.AddCommand;
-import org.openstreetmap.josm.command.Command;
-import org.openstreetmap.josm.command.SequenceCommand;
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.gui.PleaseWaitRunnable;
-import org.openstreetmap.josm.io.OsmTransferException;
-
-/**
- * Grab the SVG administrative boundaries of the active commune layer (cadastre),
- * isolate the SVG path of the concerned commune (other municipalities are also
- * downloaded in the SVG data), convert to OSM nodes and way plus simplify.
- * Thanks to Frederic Rodrigo for his help.
- */
-public class DownloadSVGTask extends PleaseWaitRunnable {
-
-    private WMSLayer wmsLayer;
-    private CadastreInterface wmsInterface;
-    private String svg;
-    private EastNorthBound viewBox;
-    private static String errorMessage;
-
-    /**
-     * Constructs a new {@code DownloadSVGTask}.
-     */
-    public DownloadSVGTask(WMSLayer wmsLayer) {
-        super(tr("Downloading {0}", wmsLayer.getName()));
-
-        this.wmsLayer = wmsLayer;
-        this.wmsInterface = wmsLayer.grabber.getWmsInterface();
-    }
-
-    @Override
-    public void realRun() throws IOException, OsmTransferException {
-        progressMonitor.indeterminateSubTask(tr("Contacting WMS Server..."));
-        errorMessage = null;
-        try {
-            if (wmsInterface.retrieveInterface(wmsLayer)) {
-                svg = grabBoundary(wmsLayer.getCommuneBBox());
-                if (svg == null)
-                    return;
-                progressMonitor.indeterminateSubTask(tr("Extract SVG ViewBox..."));
-                getViewBox(svg);
-                if (viewBox == null)
-                    return;
-                progressMonitor.indeterminateSubTask(tr("Extract best fitting boundary..."));
-                createWay(svg);
-            }
-        } catch (DuplicateLayerException e) {
-            Main.warn("removed a duplicated layer");
-        } catch (WMSException e) {
-            errorMessage = e.getMessage();
-            wmsLayer.grabber.getWmsInterface().resetCookie();
-        }
-    }
-
-    @Override
-    protected void cancel() {
-        wmsLayer.grabber.getWmsInterface().cancel();
-    }
-
-    @Override
-    protected void finish() {
-        // Do nothing
-    }
-
-    private boolean getViewBox(String svg) {
-        double[] box = new SVGParser().getViewBox(svg);
-        if (box != null) {
-            viewBox = new EastNorthBound(new EastNorth(box[0], box[1]),
-                    new EastNorth(box[0]+box[2], box[1]+box[3]));
-            return true;
-        }
-        Main.warn("Unable to parse SVG data (viewBox)");
-        return false;
-    }
-
-    /**
-     *  The svg contains more than one commune boundary defined by path elements. So detect
-     *  which path element is the best fitting to the viewBox and convert it to OSM objects
-     */
-    private void createWay(String svg) {
-        String[] SVGpaths = new SVGParser().getClosedPaths(svg);
-        ArrayList<Double> fitViewBox = new ArrayList<>();
-        ArrayList<ArrayList<EastNorth>> eastNorths = new ArrayList<>();
-        for (int i = 0; i < SVGpaths.length; i++) {
-            ArrayList<EastNorth> eastNorth = new ArrayList<>();
-            fitViewBox.add(createNodes(SVGpaths[i], eastNorth));
-            eastNorths.add(eastNorth);
-        }
-        // the smallest fitViewBox indicates the best fitting path in viewBox
-        Double min = Collections.min(fitViewBox);
-        int bestPath = fitViewBox.indexOf(min);
-        List<Node> nodeList = new ArrayList<>();
-        for (EastNorth eastNorth : eastNorths.get(bestPath)) {
-            nodeList.add(new Node(Main.getProjection().eastNorth2latlon(eastNorth)));
-        }
-        Way wayToAdd = new Way();
-        Collection<Command> cmds = new LinkedList<>();
-        for (Node node : nodeList) {
-            cmds.add(new AddCommand(node));
-            wayToAdd.addNode(node);
-        }
-        wayToAdd.addNode(wayToAdd.getNode(0)); // close the circle
-
-        // simplify the way
-//        double threshold = Double.parseDouble(Main.pref.get("cadastrewms.simplify-way-boundary", "1.0"));
-//        new SimplifyWay().simplifyWay(wayToAdd, Main.main.getCurrentDataSet(), threshold);
-
-        cmds.add(new AddCommand(wayToAdd));
-        Main.main.undoRedo.add(new SequenceCommand(tr("Create boundary"), cmds));
-        Main.map.repaint();
-    }
-
-    private double createNodes(String SVGpath, ArrayList<EastNorth> eastNorth) {
-        // looks like "M981283.38 368690.15l143.81 72.46 155.86 ..."
-        String[] coor = SVGpath.split("[MlZ ]"); //coor[1] is x, coor[2] is y
-        double dx = Double.parseDouble(coor[1]);
-        double dy = Double.parseDouble(coor[2]);
-        double minY = Double.MAX_VALUE;
-        double minX = Double.MAX_VALUE;
-        double maxY = Double.MIN_VALUE;
-        double maxX = Double.MIN_VALUE;
-        for (int i = 3; i < coor.length; i += 2) {
-            double east = dx += Double.parseDouble(coor[i]);
-            double north = dy += Double.parseDouble(coor[i+1]);
-            eastNorth.add(new EastNorth(east, north));
-            minX = minX > east ? east : minX;
-            minY = minY > north ? north : minY;
-            maxX = maxX < east ? east : maxX;
-            maxY = maxY < north ? north : maxY;
-        }
-        // flip the image (svg using a reversed Y coordinate system)
-        double pivot = viewBox.min.getY() + (viewBox.max.getY() - viewBox.min.getY()) / 2;
-        for (int i = 0; i < eastNorth.size(); i++) {
-            EastNorth en = eastNorth.get(i);
-            eastNorth.set(i, new EastNorth(en.east(), 2 * pivot - en.north()));
-        }
-        return Math.abs(minX - viewBox.min.getX())+Math.abs(maxX - viewBox.max.getX())
-        +Math.abs(minY - viewBox.min.getY())+Math.abs(maxY - viewBox.max.getY());
-    }
-
-    private String grabBoundary(EastNorthBound bbox) throws IOException, OsmTransferException {
-        try {
-            return grabSVG(getURLsvg(bbox));
-        } catch (MalformedURLException e) {
-            throw (IOException) new IOException(tr("CadastreGrabber: Illegal url.")).initCause(e);
-        }
-    }
-
-    private static URL getURLsvg(EastNorthBound bbox) throws MalformedURLException {
-        String str = CadastreInterface.BASE_URL+"/scpc/wms?version=1.1&request=GetMap";
-        str += "&layers=";
-        str += "CDIF:COMMUNE";
-        str += "&format=image/svg";
-        str += "&bbox="+bbox.min.east()+",";
-        str += bbox.min.north() + ",";
-        str += bbox.max.east() + ",";
-        str += bbox.max.north();
-        str += "&width="+CadastrePlugin.imageWidth+"&height="+CadastrePlugin.imageHeight;
-        str += "&styles=";
-        str += "COMMUNE_90";
-        Main.info("URL="+str);
-        return new URL(str.replace(" ", "%20"));
-    }
-
-    private String grabSVG(URL url) throws IOException, OsmTransferException {
-        File file = new File(CadastrePlugin.cacheDir + "boundary.svg");
-        String svg = "";
-        try (InputStream is = wmsInterface.getContent(url)) {
-            if (file.exists())
-                file.delete();
-            try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file, true));
-                 InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
-                 BufferedReader br = new BufferedReader(isr)) {
-                String line;
-                while (null != (line = br.readLine())) {
-                    line += "\n";
-                    bos.write(line.getBytes(StandardCharsets.UTF_8));
-                    svg += line;
-                }
-            }
-        } catch (IOException e) {
-            Main.error(e);
-        }
-        return svg;
-    }
-
-    public static void download(WMSLayer wmsLayer) {
-        if (!CadastrePlugin.autoSourcing) {
-            JOptionPane.showMessageDialog(Main.parent,
-                    tr("Please, enable auto-sourcing and check cadastre millesime."));
-            return;
-        }
-        Main.worker.execute(new DownloadSVGTask(wmsLayer));
-        if (errorMessage != null)
-            JOptionPane.showMessageDialog(Main.parent, errorMessage);
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/DownloadWMSPlanImage.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/DownloadWMSPlanImage.java	(revision 33637)
+++ 	(revision )
@@ -1,126 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.IOException;
-import java.util.concurrent.Future;
-
-import javax.swing.JDialog;
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.gui.PleaseWaitRunnable;
-
-public class DownloadWMSPlanImage {
-
-    private Future<Task> task = null;
-    private WMSLayer wmsLayer;
-    private Bounds bounds;
-    private static boolean dontGeoreference = false;
-    private static String errorMessage;
-
-    private class Task extends PleaseWaitRunnable {
-        Task(WMSLayer wmsLayer, Bounds bounds) {
-            super(tr("Downloading {0}", wmsLayer.getName()));
-        }
-
-        @Override
-        public void realRun() throws IOException {
-            progressMonitor.indeterminateSubTask(tr("Contacting cadastre WMS ..."));
-            errorMessage = null;
-            try {
-                if (wmsLayer.grabber.getWmsInterface().retrieveInterface(wmsLayer)) {
-                    if (!wmsLayer.getImages().isEmpty()) {
-                        JOptionPane pane = new JOptionPane(tr("Image already loaded"), JOptionPane.INFORMATION_MESSAGE);
-                        // this below is a temporary workaround to fix the "always on top" issue
-                        JDialog dialog = pane.createDialog(Main.parent, "");
-                        CadastrePlugin.prepareDialog(dialog);
-                        dialog.setVisible(true);
-                        // till here
-                        dontGeoreference = true;
-                    } else if (wmsLayer.grabber.getWmsInterface().downloadCanceled) {
-                        // do nothing
-                    } else {
-                        // first time we grab an image for this layer
-                        if (CacheControl.cacheEnabled) {
-                            if (wmsLayer.grabThread.getCacheControl().loadCacheIfExist()) {
-                                dontGeoreference = true;
-                                wmsLayer.invalidate();
-                                return;
-                            }
-                        }
-                        if (wmsLayer.isRaster()) {
-                            // set raster image commune bounding box based on current view (before adjustment)
-                            wmsLayer.grabber.getWmsInterface().retrieveCommuneBBox(wmsLayer);
-                            wmsLayer.setRasterBounds(bounds);
-                            // grab new images from wms server into active layer
-                            wmsLayer.grab(bounds);
-                            if (wmsLayer.grabber.getWmsInterface().downloadCanceled) {
-                                wmsLayer.clearImages();
-                                wmsLayer.invalidate();
-                            } else {
-                                // next steps follow in method finish() when download is terminated
-                                wmsLayer.joinBufferedImages();
-                            }
-                        } else {
-                            /*JOptionPane.showMessageDialog(Main.parent,tr("Municipality vectorized !\n"+
-                                    "Use the normal Cadastre Grab menu."));*/
-                            JOptionPane pane = new JOptionPane(
-                                    tr("Municipality vectorized !\nUse the normal Cadastre Grab menu."),
-                                    JOptionPane.INFORMATION_MESSAGE);
-                            // this below is a temporary workaround to fix the "always on top" issue
-                            JDialog dialog = pane.createDialog(Main.parent, "");
-                            CadastrePlugin.prepareDialog(dialog);
-                            dialog.setVisible(true);
-                            // till here
-                        }
-                    }
-                }
-            } catch (DuplicateLayerException e) {
-                // we tried to grab onto a duplicated layer (removed)
-                Main.warn("removed a duplicated layer");
-            } catch (WMSException e) {
-                errorMessage = e.getMessage();
-                wmsLayer.grabber.getWmsInterface().resetCookie();
-            }
-        }
-
-        @Override
-        protected void cancel() {
-            wmsLayer.grabber.getWmsInterface().cancel();
-            dontGeoreference = true;
-        }
-
-        @Override
-        protected void finish() {
-        }
-    }
-
-    public void download(WMSLayer wmsLayer) {
-        MapView mv = Main.map.mapView;
-        Bounds bounds = new Bounds(mv.getLatLon(0, mv.getHeight()), mv.getLatLon(mv.getWidth(), 0));
-        dontGeoreference = false;
-
-        //Main.worker.execute(new DownloadWMSPlanImage(wmsLayer, bounds));
-        Task t = new Task(wmsLayer, bounds);
-        this.wmsLayer = wmsLayer;
-        this.bounds = bounds;
-        task = Main.worker.submit(t, t);
-        if (errorMessage != null)
-            JOptionPane.showMessageDialog(Main.parent, errorMessage);
-    }
-
-    public boolean waitFinished() {
-        if (task != null) {
-            try {
-                task.get();
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-        return dontGeoreference;
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/DownloadWMSVectorImage.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/DownloadWMSVectorImage.java	(revision 33637)
+++ 	(revision )
@@ -1,89 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.IOException;
-
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.gui.PleaseWaitRunnable;
-
-public class DownloadWMSVectorImage extends PleaseWaitRunnable {
-
-    private WMSLayer wmsLayer;
-    private Bounds bounds;
-    private static String errorMessage;
-
-    public DownloadWMSVectorImage(WMSLayer wmsLayer, Bounds bounds) {
-        super(tr("Downloading {0}", wmsLayer.getName()));
-
-        this.wmsLayer = wmsLayer;
-        this.bounds = bounds;
-    }
-
-    @Override
-    public void realRun() throws IOException {
-        progressMonitor.indeterminateSubTask(tr("Contacting WMS Server..."));
-        errorMessage = null;
-        try {
-            if (wmsLayer.grabber.getWmsInterface().retrieveInterface(wmsLayer)) {
-                if (!wmsLayer.hasImages()) {
-                    // first time we grab an image for this layer
-                    if (CacheControl.cacheEnabled) {
-                        if (wmsLayer.grabThread.getCacheControl().loadCacheIfExist()) {
-                            Main.map.mapView.zoomTo(wmsLayer.getFirstViewFromCacheBBox().toBounds());
-                            return;
-                        }
-                    }
-                    if (wmsLayer.isRaster()) {
-                        // set raster image commune bounding box based on current view (before adjustment)
-                        JOptionPane.showMessageDialog(Main.parent,
-                                tr("This commune is not vectorized.\nPlease use the other menu entry to georeference a \"Plan image\""));
-                        Main.getLayerManager().removeLayer(wmsLayer);
-                        wmsLayer = null;
-                        return;
-                    } else {
-                        // set vectorized commune bounding box by opening the standard web window
-                        wmsLayer.grabber.getWmsInterface().retrieveCommuneBBox(wmsLayer);
-                    }
-                }
-                // grab new images from wms server into active layer
-                wmsLayer.grab(bounds);
-            } else if (!wmsLayer.hasImages()) {
-              // failed to contact WMS of find this commune. Remove layer if empty.
-              Main.getLayerManager().removeLayer(wmsLayer);
-            }
-        } catch (DuplicateLayerException e) {
-            // we tried to grab onto a duplicated layer (removed)
-            Main.warn("removed a duplicated layer");
-        } catch (WMSException e) {
-            Main.warn(e);
-            errorMessage = e.getMessage();
-            wmsLayer.grabber.getWmsInterface().resetCookie();
-        }
-    }
-
-    @Override
-    protected void cancel() {
-        wmsLayer.grabber.getWmsInterface().cancel();
-        if (wmsLayer != null)
-            wmsLayer.grabThread.setCanceled(true);
-    }
-
-    @Override
-    protected void finish() {
-    }
-
-    public static void download(WMSLayer wmsLayer) {
-        MapView mv = Main.map.mapView;
-        Bounds bounds = new Bounds(mv.getLatLon(0, mv.getHeight()), mv.getLatLon(mv.getWidth(), 0));
-
-        Main.worker.execute(new DownloadWMSVectorImage(wmsLayer, bounds));
-        if (errorMessage != null)
-            JOptionPane.showMessageDialog(Main.parent, errorMessage);
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/DuplicateLayerException.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/DuplicateLayerException.java	(revision 33637)
+++ 	(revision )
@@ -1,6 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-class DuplicateLayerException extends Exception {
-    private static final long serialVersionUID = 1L;
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/EastNorthBound.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/EastNorthBound.java	(revision 33637)
+++ 	(revision )
@@ -1,42 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import java.io.Serializable;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.coor.EastNorth;
-
-public class EastNorthBound implements Serializable {
-
-    private static final long serialVersionUID = 8451650309216472069L;
-
-    public EastNorth min, max;
-    public EastNorthBound(EastNorth min, EastNorth max) {
-        this.min = min;
-        this.max = max;
-    }
-
-    public boolean contains(EastNorth eastNorth) {
-        if (eastNorth.east() < min.east() || eastNorth.north() < min.north())
-            return false;
-        if (eastNorth.east() > max.east() || eastNorth.north() > max.north())
-            return false;
-        return true;
-    }
-
-    public EastNorthBound interpolate(EastNorthBound en2, double proportion) {
-        EastNorthBound enb = new EastNorthBound(this.min.interpolate(en2.min, proportion),
-                this.max.interpolate(en2.max, proportion));
-        return enb;
-    }
-
-    public Bounds toBounds() {
-        return new Bounds(Main.getProjection().eastNorth2latlon(min), Main.getProjection().eastNorth2latlon(max));
-    }
-
-    @Override public String toString() {
-        return "EastNorthBound[" + min.east() + "," + min.north() + "," + max.east() + "," + max.north() + "]";
-    }
-}
-
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/GeorefImage.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/GeorefImage.java	(revision 33637)
+++ 	(revision )
@@ -1,376 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import java.awt.AlphaComposite;
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.GraphicsConfiguration;
-import java.awt.GraphicsDevice;
-import java.awt.GraphicsEnvironment;
-import java.awt.Image;
-import java.awt.Point;
-import java.awt.image.BufferedImage;
-import java.awt.image.ImageObserver;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.util.Objects;
-
-import javax.imageio.ImageIO;
-
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.gui.NavigatableComponent;
-
-public class GeorefImage implements Serializable, ImageObserver, Cloneable {
-    private static final long serialVersionUID = 1L;
-
-    // bbox of the georeferenced image (the nice horizontal and vertical box)
-    public EastNorth min;
-    public EastNorth max;
-    // bbox of the georeferenced original image (raster only) (inclined if rotated and before cropping)
-    // P[0] is bottom,left then next are clockwise.
-    public EastNorth[] orgRaster = new EastNorth[4];
-    // bbox of the georeferenced original image (raster only) after cropping
-    public EastNorth[] orgCroppedRaster = new EastNorth[4];
-    // angle with georeferenced original image after rotation (raster images only)(in radian)
-    public double angle = 0;
-    public int imageOriginalHeight = 0;
-    public int imageOriginalWidth = 0;
-
-    public BufferedImage image;
-    public WMSLayer wmsLayer;
-
-    private double pixelPerEast;
-    private double pixelPerNorth;
-
-    public GeorefImage(BufferedImage img, EastNorth min, EastNorth max, WMSLayer wmsLayer) {
-        image = Objects.requireNonNull(img);
-
-        this.min = Objects.requireNonNull(min);
-        this.max = Objects.requireNonNull(max);
-        this.orgRaster[0] = min;
-        this.orgRaster[1] = new EastNorth(min.east(), max.north());
-        this.orgRaster[2] = max;
-        this.orgRaster[3] = new EastNorth(max.east(), min.north());
-        this.orgCroppedRaster[0] = min;
-        this.orgCroppedRaster[1] = new EastNorth(min.east(), max.north());
-        this.orgCroppedRaster[2] = max;
-        this.orgCroppedRaster[3] = new EastNorth(max.east(), min.north());
-        // img can be null for a hack used in overlapping detection
-        this.imageOriginalHeight = (img == null ? 1 : img.getHeight());
-        this.imageOriginalWidth = (img == null ? 1 : img.getWidth());
-        this.wmsLayer = wmsLayer;
-        updatePixelPer();
-    }
-
-    public static GraphicsConfiguration getDefaultConfiguration() {
-        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
-        GraphicsDevice gd = ge.getDefaultScreenDevice();
-        return gd.getDefaultConfiguration();
-    }
-
-    /**
-     * Recalculate the new bounding box of the image based on the four points provided as parameters.
-     * The new bbox defined in [min.max] will retain the extreme values of both boxes.
-     * @param p1 one of the bounding box corner
-     * @param p2 one of the bounding box corner
-     * @param p3 one of the bounding box corner
-     * @param p4 one of the bounding box corner
-     */
-    private EastNorthBound computeNewBounding(EastNorth p1, EastNorth p2, EastNorth p3, EastNorth p4) {
-        EastNorth[] pt = new EastNorth[4];
-        pt[0] = p1;
-        pt[1] = p2;
-        pt[2] = p3;
-        pt[3] = p4;
-        double smallestEast = Double.MAX_VALUE;
-        double smallestNorth = Double.MAX_VALUE;
-        double highestEast = Double.MIN_VALUE;
-        double highestNorth = Double.MIN_VALUE;
-        for (int i = 0; i <= 3; i++) {
-            smallestEast = Math.min(pt[i].east(), smallestEast);
-            smallestNorth = Math.min(pt[i].north(), smallestNorth);
-            highestEast = Math.max(pt[i].east(), highestEast);
-            highestNorth = Math.max(pt[i].north(), highestNorth);
-        }
-        return new EastNorthBound(new EastNorth(smallestEast, smallestNorth),
-                new EastNorth(highestEast, highestNorth));
-    }
-
-    public boolean contains(EastNorth en) {
-        return min.east() <= en.east() && en.east() <= max.east() && min.north() <= en.north()
-                && en.north() <= max.north();
-    }
-
-    public void paint(Graphics2D g, NavigatableComponent nc, boolean backgroundTransparent, float transparency,
-            boolean drawBoundaries) {
-        if (image == null || min == null || max == null)
-            return;
-
-        // apply offsets defined manually when vector images are translated manually (not saved in cache)
-        double dx = 0, dy = 0;
-        if (wmsLayer != null) {
-            dx = wmsLayer.deltaEast;
-            dy = wmsLayer.deltaNorth;
-        }
-        Point minPt = nc.getPoint(new EastNorth(min.east()+dx, min.north()+dy));
-        Point maxPt = nc.getPoint(new EastNorth(max.east()+dx, max.north()+dy));
-
-        if (!g.hitClip(minPt.x, maxPt.y, maxPt.x - minPt.x, minPt.y - maxPt.y))
-            return;
-
-        if (backgroundTransparent && transparency < 1.0f)
-            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, transparency));
-        if (drawBoundaries) {
-            if (orgCroppedRaster == null) {
-                // this is the old cache format where only [min,max] bbox is stored
-                g.setColor(Color.green);
-                g.drawRect(minPt.x, maxPt.y, maxPt.x - minPt.x, minPt.y - maxPt.y);
-            } else {
-                Point[] croppedPoint = new Point[5];
-                for (int i = 0; i < 4; i++) {
-                    croppedPoint[i] = nc.getPoint(
-                            new EastNorth(orgCroppedRaster[i].east()+dx, orgCroppedRaster[i].north()+dy));
-                }
-                croppedPoint[4] = croppedPoint[0];
-                for (int i = 0; i < 4; i++) {
-                    g.setColor(Color.green);
-                    g.drawLine(croppedPoint[i].x, croppedPoint[i].y, croppedPoint[i+1].x, croppedPoint[i+1].y);
-                }
-                /*
-                //Uncomment this section to display the original image size (before cropping)
-                Point[] orgPoint = new Point[5];
-                for (int i=0; i<4; i++)
-                    orgPoint[i] = nc.getPoint(orgRaster[i]);
-                orgPoint[4] = orgPoint[0];
-                for (int i=0; i<4; i++) {
-                  g.setColor(Color.red);
-                  g.drawLine(orgPoint[i].x, orgPoint[i].y, orgPoint[i+1].x, orgPoint[i+1].y);
-                }
-                */
-            }
-        }
-            g.drawImage(image, minPt.x, maxPt.y, maxPt.x, minPt.y, // dest
-                        0, 0, image.getWidth(), image.getHeight(), // src
-                        null);
-        if (backgroundTransparent && transparency < 1.0f)
-            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
-    }
-
-    /**
-     * Is the given bbox overlapping this image ?
-     */
-    public boolean overlap(GeorefImage georefImage) {
-        if (this.contains(georefImage.min) || this.contains(georefImage.max))
-            return true;
-        if (this.contains(new EastNorth(georefImage.min.east(), georefImage.max.north()))
-                || this.contains(new EastNorth(georefImage.max.east(), georefImage.min.north())))
-            return true;
-        return false;
-    }
-
-    /**
-     * Make all pixels masked by the given georefImage transparent in this image
-     */
-    public void withdraw(GeorefImage georefImage) {
-        double minMaskEast = (georefImage.min.east() > this.min.east()) ? georefImage.min.east() : this.min.east();
-        double maxMaskEast = (georefImage.max.east() < this.max.east()) ? georefImage.max.east() : this.max.east();
-        double minMaskNorth = (georefImage.min.north() > this.min.north()) ? georefImage.min.north() : this.min.north();
-        double maxMaskNorth = (georefImage.max.north() < this.max.north()) ? georefImage.max.north() : this.max.north();
-        if ((maxMaskNorth - minMaskNorth) > 0 && (maxMaskEast - minMaskEast) > 0) {
-            double pxPerEast = (max.east() - min.east()) / image.getWidth();
-            double pxPerNorth = (max.north() - min.north()) / image.getHeight();
-            int minXMaskPixel = (int) ((minMaskEast - min.east()) / pxPerEast);
-            int minYMaskPixel = (int) ((max.north() - maxMaskNorth) / pxPerNorth);
-            int widthXMaskPixel = Math.abs((int) ((maxMaskEast - minMaskEast) / pxPerEast));
-            int heightYMaskPixel = Math.abs((int) ((maxMaskNorth - minMaskNorth) / pxPerNorth));
-            Graphics g = image.getGraphics();
-            for (int x = minXMaskPixel; x < minXMaskPixel + widthXMaskPixel; x++) {
-                for (int y = minYMaskPixel; y < minYMaskPixel + heightYMaskPixel; y++) {
-                    image.setRGB(x, y, VectorImageModifier.cadastreBackgroundTransp);
-                }
-            }
-            g.dispose();
-        }
-    }
-
-    /**
-     * Method required by BufferedImage serialization.
-     * Save only primitives to keep cache independent of software changes.
-     */
-    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
-        if (WMSLayer.currentFormat >= 2) {
-            max = new EastNorth(in.readDouble(), in.readDouble());
-            min = new EastNorth(in.readDouble(), in.readDouble());
-        }
-        orgRaster = null;
-        orgCroppedRaster = null;
-        if (WMSLayer.currentFormat >= 3) {
-            orgRaster = new EastNorth[4];
-            orgCroppedRaster = new EastNorth[4];
-            angle = in.readDouble();
-            orgRaster[0] = new EastNorth(in.readDouble(), in.readDouble());
-            orgRaster[1] = new EastNorth(in.readDouble(), in.readDouble());
-            orgRaster[2] = new EastNorth(in.readDouble(), in.readDouble());
-            orgRaster[3] = new EastNorth(in.readDouble(), in.readDouble());
-            orgCroppedRaster[0] = new EastNorth(in.readDouble(), in.readDouble());
-            orgCroppedRaster[1] = new EastNorth(in.readDouble(), in.readDouble());
-            orgCroppedRaster[2] = new EastNorth(in.readDouble(), in.readDouble());
-            orgCroppedRaster[3] = new EastNorth(in.readDouble(), in.readDouble());
-        }
-        if (WMSLayer.currentFormat >= 4) {
-            imageOriginalHeight = in.readInt();
-            imageOriginalWidth = in.readInt();
-        }
-        image = ImageIO.read(ImageIO.createImageInputStream(in));
-        updatePixelPer();
-    }
-
-    /**
-     * Method required by BufferedImage serialization.
-     * Use only primitives for stability in time (not influenced by josm-core changes).
-     */
-    private void writeObject(ObjectOutputStream out) throws IOException {
-        out.writeDouble(max.getX()); out.writeDouble(max.getY());
-        out.writeDouble(min.getX()); out.writeDouble(min.getY());
-        if (orgRaster == null) { // just in case we save an old format layer already cached
-            orgRaster = new EastNorth[4];
-            orgCroppedRaster = new EastNorth[4];
-        }
-        out.writeDouble(angle);
-        out.writeDouble(orgRaster[0].getX()); out.writeDouble(orgRaster[0].getY());
-        out.writeDouble(orgRaster[1].getX()); out.writeDouble(orgRaster[1].getY());
-        out.writeDouble(orgRaster[2].getX()); out.writeDouble(orgRaster[2].getY());
-        out.writeDouble(orgRaster[3].getX()); out.writeDouble(orgRaster[3].getY());
-        out.writeDouble(orgCroppedRaster[0].getX()); out.writeDouble(orgCroppedRaster[0].getY());
-        out.writeDouble(orgCroppedRaster[1].getX()); out.writeDouble(orgCroppedRaster[1].getY());
-        out.writeDouble(orgCroppedRaster[2].getX()); out.writeDouble(orgCroppedRaster[2].getY());
-        out.writeDouble(orgCroppedRaster[3].getX()); out.writeDouble(orgCroppedRaster[3].getY());
-        // Write image as a format 3 if cache was loaded with this format to avoid incompatibilities.
-        if (WMSLayer.currentFormat >= 4) {
-            out.writeInt(imageOriginalHeight);
-            out.writeInt(imageOriginalWidth);
-        }
-        ImageIO.write(image, "png", ImageIO.createImageOutputStream(out));
-    }
-
-    private void updatePixelPer() {
-        pixelPerEast = image.getWidth()/(max.east()-min.east());
-        pixelPerNorth = image.getHeight()/(max.north()-min.north());
-    }
-
-    public double getPixelPerEast() {
-        return pixelPerEast;
-    }
-
-    public double getPixelPerNorth() {
-        return pixelPerNorth;
-    }
-
-    @Override
-    public String toString() {
-        return "GeorefImage[min=" + min + ", max=" + max + ", image" + image + "]";
-    }
-
-    /*
-     * Following methods are used for affine transformation of two points p1 and p2
-     */
-    /**
-     * Add a translation (dx, dy) to this image min,max coordinates
-     * @param dx delta added to X image coordinate
-     * @param dy delta added to Y image coordinate
-     */
-    public void shear(double dx, double dy) {
-        min = new EastNorth(min.east() + dx, min.north() + dy);
-        max = new EastNorth(max.east() + dx, max.north() + dy);
-        for (int i = 0; i < 4; i++) {
-            orgRaster[i] = new EastNorth(orgRaster[i].east() + dx, orgRaster[i].north() + dy);
-            orgCroppedRaster[i] = new EastNorth(orgCroppedRaster[i].east() + dx, orgCroppedRaster[i].north() + dy);
-        }
-    }
-
-    /**
-     * Change this image scale by moving the min,max coordinates around an anchor
-     */
-    public void scale(EastNorth anchor, double proportion) {
-        min = anchor.interpolate(min, proportion);
-        max = anchor.interpolate(max, proportion);
-        for (int i = 0; i < 4; i++) {
-            orgRaster[i] = anchor.interpolate(orgRaster[i], proportion);
-            orgCroppedRaster[i] = anchor.interpolate(orgCroppedRaster[i], proportion);
-        }
-        updatePixelPer();
-    }
-
-    /**
-     * Rotate this image and its min/max coordinates around anchor point
-     * @param anchor anchor of rotation
-     * @param old_ang previous angle of image before rotation (0 the first time)(in radian)
-     * @param delta_ang angle of rotation (in radian)
-     */
-    public void rotate(EastNorth anchor, double delta_ang) {
-        if (orgRaster == null || orgCroppedRaster == null)
-            return;
-        // rotate the bounding boxes coordinates first
-        for (int i = 0; i < 4; i++) {
-            orgRaster[i] = orgRaster[i].rotate(anchor, delta_ang);
-            orgCroppedRaster[i] = orgCroppedRaster[i].rotate(anchor, delta_ang);
-        }
-        // rotate the image now
-        double sin = Math.abs(Math.sin(angle+delta_ang)), cos = Math.abs(Math.cos(angle+delta_ang));
-        int w = imageOriginalWidth, h = imageOriginalHeight;
-        int neww = (int) Math.floor(w*cos+h*sin);
-        int newh = (int) Math.floor(h*cos+w*sin);
-        GraphicsConfiguration gc = getDefaultConfiguration();
-        BufferedImage result = gc.createCompatibleImage(neww, newh, image.getTransparency());
-        Graphics2D g = result.createGraphics();
-        g.translate((neww-image.getWidth())/2, (newh-image.getHeight())/2);
-        g.rotate(delta_ang, image.getWidth()/2, image.getHeight()/2);
-        g.drawRenderedImage(image, null);
-        g.dispose();
-        image = result;
-        EastNorthBound enb = computeNewBounding(orgCroppedRaster[0], orgCroppedRaster[1], orgCroppedRaster[2], orgCroppedRaster[3]);
-        min = enb.min;
-        max = enb.max;
-        angle += delta_ang;
-    }
-
-    /**
-     * Crop the image based on new bbox coordinates adj1 and adj2 (for raster images only).
-     * @param adj1 is the new corner bottom, left
-     * @param adj2 is the new corner top, right
-     */
-    public void crop(EastNorth adj1, EastNorth adj2) {
-        // s1 and s2 have 0,0 at top, left where all EastNorth coord. have 0,0 at bottom, left
-        int sx1 = (int) ((adj1.getX() - min.getX())*getPixelPerEast());
-        int sy1 = (int) ((max.getY() - adj2.getY())*getPixelPerNorth());
-        int sx2 = (int) ((adj2.getX() - min.getX())*getPixelPerEast());
-        int sy2 = (int) ((max.getY() - adj1.getY())*getPixelPerNorth());
-        int newWidth = Math.abs(sx2 - sx1);
-        int newHeight = Math.abs(sy2 - sy1);
-        BufferedImage new_img = new BufferedImage(newWidth, newHeight, image.getType());
-        Graphics g = new_img.getGraphics();
-        g.drawImage(image, 0, 0, newWidth-1, newHeight-1,
-                sx1, sy1, sx2, sy2,
-                this);
-        image = new_img;
-        this.min = adj1;
-        this.max = adj2;
-        this.orgCroppedRaster[0] = min;
-        this.orgCroppedRaster[1] = new EastNorth(min.east(), max.north());
-        this.orgCroppedRaster[2] = max;
-        this.orgCroppedRaster[3] = new EastNorth(max.east(), min.north());
-        this.imageOriginalWidth = newWidth;
-        this.imageOriginalHeight = newHeight;
-        updatePixelPer();
-    }
-
-    @Override
-    public boolean imageUpdate(Image img, int infoflags, int x, int y,
-            int width, int height) {
-        return false;
-    }
-
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/GrabThread.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/GrabThread.java	(revision 33637)
+++ 	(revision )
@@ -1,235 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.Point;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.io.OsmTransferException;
-
-public class GrabThread extends Thread {
-
-    private boolean canceled;
-
-    private CadastreGrabber grabber;
-
-    private WMSLayer wmsLayer;
-
-    private Lock lockImagesToGrag = new ReentrantLock();
-
-    private ArrayList<EastNorthBound> imagesToGrab = new ArrayList<>();
-
-    private CacheControl cacheControl = null;
-
-    private EastNorthBound currentGrabImage;
-
-    private Lock lockCurrentGrabImage = new ReentrantLock();
-
-    /**
-     * Call directly grabber for raster images or prepare thread for vector images
-     */
-    public void addImages(ArrayList<EastNorthBound> moreImages) {
-        lockImagesToGrag.lock();
-        imagesToGrab.addAll(moreImages);
-        lockImagesToGrag.unlock();
-        synchronized (this) {
-            this.notify();
-        }
-        Main.info("Added " + moreImages.size() + " to the grab thread");
-        if (wmsLayer.isRaster()) {
-            waitNotification();
-        }
-    }
-
-    public int getImagesToGrabSize() {
-        lockImagesToGrag.lock();
-        int size = imagesToGrab.size();
-        lockImagesToGrag.unlock();
-        return size;
-    }
-
-    public ArrayList<EastNorthBound> getImagesToGrabCopy() {
-        ArrayList<EastNorthBound> copyList = new ArrayList<>();
-        lockImagesToGrag.lock();
-        for (EastNorthBound img : imagesToGrab) {
-            EastNorthBound imgCpy = new EastNorthBound(img.min, img.max);
-            copyList.add(imgCpy);
-        }
-        lockImagesToGrag.unlock();
-        return copyList;
-    }
-
-    public void clearImagesToGrab() {
-        lockImagesToGrag.lock();
-        imagesToGrab.clear();
-        lockImagesToGrag.unlock();
-    }
-
-    @Override
-    public void run() {
-        for (;;) {
-            while (getImagesToGrabSize() > 0) {
-                lockImagesToGrag.lock();
-                lockCurrentGrabImage.lock();
-                currentGrabImage = imagesToGrab.get(0);
-                lockCurrentGrabImage.unlock();
-                imagesToGrab.remove(0);
-                lockImagesToGrag.unlock();
-                if (canceled) {
-                    break;
-                } else {
-                    GeorefImage newImage;
-                    try {
-                        Main.map.repaint(); // paint the current grab box
-                        newImage = grabber.grab(wmsLayer, currentGrabImage.min, currentGrabImage.max);
-                    } catch (IOException e) {
-                        Main.warn("Download action canceled by user or server did not respond");
-                        setCanceled(true);
-                        break;
-                    } catch (OsmTransferException e) {
-                        Main.error("OSM transfer failed");
-                        setCanceled(true);
-                        break;
-                    }
-                    if (grabber.getWmsInterface().downloadCanceled) {
-                        Main.info("Download action canceled by user");
-                        setCanceled(true);
-                        break;
-                    }
-                    try {
-                        if (CadastrePlugin.backgroundTransparent) {
-                            wmsLayer.imagesLock.lock();
-                            for (GeorefImage img : wmsLayer.getImages()) {
-                                if (img.overlap(newImage))
-                                    // mask overlapping zone in already grabbed image
-                                    img.withdraw(newImage);
-                                else
-                                    // mask overlapping zone in new image only when new image covers completely the
-                                    // existing image
-                                    newImage.withdraw(img);
-                            }
-                            wmsLayer.imagesLock.unlock();
-                        }
-                        wmsLayer.addImage(newImage);
-                        wmsLayer.invalidate();
-                        saveToCache(newImage);
-                    } catch (NullPointerException e) {
-                        Main.info("Layer destroyed. Cancel grab thread");
-                        setCanceled(true);
-                    }
-                }
-            }
-            Main.info("grab thread list empty");
-            lockCurrentGrabImage.lock();
-            currentGrabImage = null;
-            lockCurrentGrabImage.unlock();
-            if (canceled) {
-                clearImagesToGrab();
-                canceled = false;
-            }
-            if (wmsLayer.isRaster()) {
-                notifyWaiter();
-            }
-            waitNotification();
-        }
-    }
-
-    public void saveToCache(GeorefImage image) {
-        if (CacheControl.cacheEnabled && !wmsLayer.isRaster()) {
-            getCacheControl().saveCache(image);
-        }
-    }
-
-    public void saveNewCache() {
-        if (CacheControl.cacheEnabled) {
-            getCacheControl().deleteCacheFile();
-            wmsLayer.imagesLock.lock();
-            for (GeorefImage image : wmsLayer.getImages()) {
-                getCacheControl().saveCache(image);
-            }
-            wmsLayer.imagesLock.unlock();
-        }
-    }
-
-    public void cancel() {
-        clearImagesToGrab();
-        if (cacheControl != null) {
-            while (!cacheControl.isCachePipeEmpty()) {
-                Main.info("Try to close a WMSLayer which is currently saving in cache : wait 1 sec.");
-                CadastrePlugin.safeSleep(1000);
-            }
-        }
-    }
-
-    public CacheControl getCacheControl() {
-        if (cacheControl == null)
-            cacheControl = new CacheControl(wmsLayer);
-        return cacheControl;
-    }
-
-    public GrabThread(WMSLayer wmsLayer) {
-        this.wmsLayer = wmsLayer;
-    }
-
-    public void paintBoxesToGrab(Graphics g, MapView mv) {
-        if (getImagesToGrabSize() > 0) {
-            ArrayList<EastNorthBound> imagesToGrab = getImagesToGrabCopy();
-            for (EastNorthBound img : imagesToGrab) {
-                paintBox(g, mv, img, Color.red);
-            }
-        }
-        lockCurrentGrabImage.lock();
-        if (currentGrabImage != null) {
-            paintBox(g, mv, currentGrabImage, Color.orange);
-        }
-        lockCurrentGrabImage.unlock();
-    }
-
-    private void paintBox(Graphics g, MapView mv, EastNorthBound img, Color color) {
-        Point[] croppedPoint = new Point[5];
-        croppedPoint[0] = mv.getPoint(img.min);
-        croppedPoint[1] = mv.getPoint(new EastNorth(img.min.east(), img.max.north()));
-        croppedPoint[2] = mv.getPoint(img.max);
-        croppedPoint[3] = mv.getPoint(new EastNorth(img.max.east(), img.min.north()));
-        croppedPoint[4] = croppedPoint[0];
-        for (int i = 0; i < 4; i++) {
-            g.setColor(color);
-            g.drawLine(croppedPoint[i].x, croppedPoint[i].y, croppedPoint[i+1].x, croppedPoint[i+1].y);
-        }
-    }
-
-    public boolean isCanceled() {
-        return canceled;
-    }
-
-    public void setCanceled(boolean canceled) {
-        this.canceled = canceled;
-    }
-
-    public CadastreGrabber getGrabber() {
-        return grabber;
-    }
-
-    public void setGrabber(CadastreGrabber grabber) {
-        this.grabber = grabber;
-    }
-
-    private synchronized void notifyWaiter() {
-        this.notify();
-    }
-
-    private synchronized void waitNotification() {
-        try {
-            wait();
-        } catch (InterruptedException e) {
-            Main.error(e);
-        }
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/ImageModifier.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/ImageModifier.java	(revision 33637)
+++ 	(revision )
@@ -1,178 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import java.awt.Color;
-import java.awt.Transparency;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorConvertOp;
-import java.awt.image.DataBuffer;
-import java.awt.image.IndexColorModel;
-import java.util.Objects;
-
-public abstract class ImageModifier {
-    /**
-     * Current background color used by cadastre.gouv.fr
-     */
-    //public static int cadastreBackgroundTransp = 1; // original white but transparent
-
-    protected int parcelColor = Color.RED.getRGB();
-
-    protected BufferedImage bufferedImage;
-
-    public static int[] cRoofColors = new int[] {-197380, -592138};
-    public static int[] cBuilingFootColors = new int[] {-256};
-
-    protected BufferedImage convert1(BufferedImage src) {
-        IndexColorModel icm = new IndexColorModel(
-            1, 2,
-            new byte[] {(byte) 0, (byte) 0xFF},
-            new byte[] {(byte) 0, (byte) 0xFF},
-            new byte[] {(byte) 0, (byte) 0xFF}
-        );
-
-        BufferedImage dest = new BufferedImage(
-            src.getWidth(), src.getHeight(),
-            BufferedImage.TYPE_BYTE_BINARY,
-            icm
-            );
-
-        ColorConvertOp cco = new ColorConvertOp(
-            src.getColorModel().getColorSpace(),
-            dest.getColorModel().getColorSpace(),
-            null
-            );
-
-        cco.filter(src, dest);
-
-        return dest;
-      }
-
-    /**
-     * Converts the source image to 4-bit colour
-     * using the default 16-colour palette:
-     * <ul>
-     *  <li>black</li><li>dark red</li><li>dark green</li>
-     *  <li>dark yellow</li><li>dark blue</li><li>dark magenta</li>
-     *  <li>dark cyan</li><li>dark grey</li><li>light grey</li>
-     *  <li>red</li><li>green</li><li>yellow</li><li>blue</li>
-     *  <li>magenta</li><li>cyan</li><li>white</li>
-     * </ul>
-     * No transparency.
-     * @param src the source image to convert
-     * @return a copy of the source image with a 4-bit colour depth, with the default colour pallette
-     */
-    protected BufferedImage convert4(BufferedImage src) {
-        int[] cmap = new int[] {
-          0x000000, 0x800000, 0x008000, 0x808000,
-          0x000080, 0x800080, 0x008080, 0x808080,
-          0xC0C0C0, 0xFF0000, 0x00FF00, 0xFFFF00,
-          0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFF
-        };
-        return convert4(src, cmap);
-      }
-
-      /**
-       * Converts the source image to 4-bit colour
-       * using the given colour map.  No transparency.
-       * @param src the source image to convert
-       * @param cmap the colour map, which should contain no more than 16 entries
-       * The entries are in the form RRGGBB (hex).
-       * @return a copy of the source image with a 4-bit colour depth, with the custom colour pallette
-       */
-    protected BufferedImage convert4(BufferedImage src, int[] cmap) {
-        IndexColorModel icm = new IndexColorModel(
-            4, cmap.length, cmap, 0, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE
-            );
-        BufferedImage dest = new BufferedImage(
-            src.getWidth(), src.getHeight(),
-            BufferedImage.TYPE_BYTE_BINARY,
-            icm
-            );
-        ColorConvertOp cco = new ColorConvertOp(
-            src.getColorModel().getColorSpace(),
-            dest.getColorModel().getColorSpace(),
-            null
-            );
-        cco.filter(src, dest);
-
-        return dest;
-      }
-
-    protected BufferedImage convert8(BufferedImage src) {
-        BufferedImage dest = new BufferedImage(
-            src.getWidth(), src.getHeight(),
-            BufferedImage.TYPE_BYTE_INDEXED
-            );
-        ColorConvertOp cco = new ColorConvertOp(
-            src.getColorModel().getColorSpace(),
-            dest.getColorModel().getColorSpace(),
-            null
-            );
-        cco.filter(src, dest);
-        return dest;
-      }
-
-    public boolean isBuildingColor(int rgb, boolean ignoreParcelColor) {
-        for (int i = 0; i < cBuilingFootColors.length; i++) {
-            if (rgb == cBuilingFootColors[i])
-                    return true;
-        }
-        if (ignoreParcelColor && (rgb == parcelColor))
-            return true;
-        return false;
-    }
-
-    public boolean isRoofColor(int rgb, boolean ignoreParcelColor) {
-        for (int i = 0; i < cRoofColors.length; i++) {
-            if (rgb == cRoofColors[i])
-                    return true;
-        }
-        if (ignoreParcelColor && (rgb == parcelColor))
-            return true;
-        return false;
-    }
-
-    public boolean isParcelColor(BufferedImage img, int x, int y) {
-        int rgb = img.getRGB(x, y);
-        return (rgb == parcelColor);
-    }
-
-    public boolean isBuildingOrRoofColor(BufferedImage img, int x, int y, boolean ignoreParcelColor) {
-        int rgb = img.getRGB(x, y);
-        boolean ret = isBuildingColor(rgb, ignoreParcelColor) || isRoofColor(rgb, ignoreParcelColor);
-        return ret;
-    }
-
-    public boolean isBuildingOrRoofColor(BufferedImage img, int x, int y, boolean colorType, boolean ignoreParcelColor) {
-        int rgb = img.getRGB(x, y);
-        boolean ret;
-        if (colorType)
-            ret = isBuildingColor(rgb, ignoreParcelColor);
-        else
-            ret = isRoofColor(rgb, ignoreParcelColor);
-        return ret;
-    }
-
-    /**
-     * Checks if the rgb value is the black background color
-     */
-    public boolean isBackgroundColor(BufferedImage img, int x, int y) {
-        return (img.getRGB(x, y) == -1);
-    }
-
-    /**
-     * Returns the buffered image.
-     * @return the buffered image
-     */
-    public final BufferedImage getBufferedImage() {
-        return bufferedImage;
-    }
-
-    /**
-     * Sets the buffered image.
-     * @param bufferedImage the buffered image
-     */
-    protected final void setBufferedImage(BufferedImage bufferedImage) {
-        this.bufferedImage = Objects.requireNonNull(bufferedImage);
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionBoundaries.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionBoundaries.java	(revision 33637)
+++ 	(revision )
@@ -1,40 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.JosmAction;
-
-public class MenuActionBoundaries extends JosmAction {
-
-    public static final String NAME = "Administrative boundary";
-
-    private static final long serialVersionUID = 1L;
-    private WMSLayer wmsLayer = null;
-
-    /**
-     * Constructs a new {@code MenuActionBoundaries}.
-     */
-    public MenuActionBoundaries() {
-        super(tr(NAME), "cadastre_small", tr("Extract commune boundary"), null, false);
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent arg0) {
-        wmsLayer = WMSDownloadAction.getLayer();
-        if (wmsLayer != null) {
-            if (wmsLayer.isRaster()) {
-                JOptionPane.showMessageDialog(Main.parent,
-                        tr("Only on vectorized layers"), tr("Error"),
-                        JOptionPane.ERROR_MESSAGE);
-                return;
-            }
-            DownloadSVGTask.download(wmsLayer);
-        }
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionCancelGrab.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionCancelGrab.java	(revision 33637)
+++ 	(revision )
@@ -1,33 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.marktr;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-
-import org.openstreetmap.josm.actions.JosmAction;
-
-@SuppressWarnings("serial")
-public class MenuActionCancelGrab extends JosmAction {
-
-    public static final String NAME = marktr("Cancel current grab");
-
-    private WMSLayer wmsLayer;
-
-    /**
-     * Constructs a new {@code MenuActionCancelGrab}.
-     * @param wmsLayer WMS layer
-     */
-    public MenuActionCancelGrab(WMSLayer wmsLayer) {
-        super(tr(NAME), null, tr("Cancel current grab (only vector images)"), null, false);
-        this.wmsLayer = wmsLayer;
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent arg0) {
-        if (wmsLayer.grabThread.getImagesToGrabSize() > 0) {
-            wmsLayer.grabThread.cancel();
-        }
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionGrab.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionGrab.java	(revision 33637)
+++ 	(revision )
@@ -1,43 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.marktr;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-import java.awt.event.KeyEvent;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.JosmAction;
-import org.openstreetmap.josm.tools.Shortcut;
-
-/**
- * Action calling the wms grabber for cadastre.gouv.fr
- */
-public class MenuActionGrab extends JosmAction {
-
-    public static final String NAME = marktr("Cadastre grab");
-
-    /**
-     * Constructs a new {@code MenuActionGrab}.
-     */
-    public MenuActionGrab() {
-        super(tr(NAME), "cadastre_small", tr("Download Image from French Cadastre WMS"),
-                Shortcut.registerShortcut("cadastre:grab", tr("Cadastre: {0}", tr("Download Image from French Cadastre WMS")),
-                KeyEvent.VK_F10, Shortcut.DIRECT), false, "cadastrefr/grab", true);
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        if (Main.map != null) {
-            if (CadastrePlugin.isCadastreProjection()) {
-                WMSLayer wmsLayer = WMSDownloadAction.getLayer();
-                if (wmsLayer != null)
-                    DownloadWMSVectorImage.download(wmsLayer);
-            } else {
-                CadastrePlugin.askToChangeProjection();
-            }
-        } else
-            new MenuActionNewLocation().actionPerformed(e);
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionGrabPlanImage.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionGrabPlanImage.java	(revision 33637)
+++ 	(revision )
@@ -1,91 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.marktr;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-import java.util.ArrayList;
-
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.JosmAction;
-
-public class MenuActionGrabPlanImage extends JosmAction implements Runnable {
-
-    /**
-     * Action calling the wms grabber for non georeferenced images called "plan image"
-     */
-    private static final long serialVersionUID = 1L;
-
-    public static final String NAME = marktr("Georeference an image");
-
-    private DownloadWMSPlanImage downloadWMSPlanImage;
-    private WMSLayer wmsLayer;
-    private RasterImageGeoreferencer rasterImageGeoreferencer;
-
-    /**
-     * Constructs a new {@code MenuActionGrabPlanImage}.
-     */
-    public MenuActionGrabPlanImage() {
-        super(tr(NAME), "cadastre_small", tr("Grab non-georeferenced image"), null, false, "cadastrefr/grabplanimage", true);
-        rasterImageGeoreferencer = new RasterImageGeoreferencer();
-    }
-
-    @Override
-    protected void updateEnabledState() {
-        if (wmsLayer == null || Main.map == null || Main.map.mapView == null) return;
-        if (!rasterImageGeoreferencer.isRunning()) return;
-        if (Main.getLayerManager().containsLayer(wmsLayer))
-            return;
-        JOptionPane.showMessageDialog(Main.parent, tr("Georeferencing interrupted"));
-        rasterImageGeoreferencer.actionInterrupted();
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent ae) {
-        if (Main.map != null) {
-            if (CadastrePlugin.isCadastreProjection()) {
-                wmsLayer = new MenuActionNewLocation().addNewLayer(new ArrayList<WMSLayer>());
-                if (wmsLayer == null) return;
-                downloadWMSPlanImage = new DownloadWMSPlanImage();
-                downloadWMSPlanImage.download(wmsLayer);
-                // download sub-images of the cadastre scan and join them into one single
-                Main.worker.execute(this);
-            } else {
-                CadastrePlugin.askToChangeProjection();
-            }
-        }
-    }
-
-    @Override
-    public void run() {
-        // wait until plan image is fully loaded and joined into one single image
-        boolean loadedFromCache = downloadWMSPlanImage.waitFinished();
-        if (loadedFromCache) {
-            Main.map.repaint();
-        } else if (wmsLayer.getImages().size() == 0) {
-            // action canceled or image loaded from cache (and already georeferenced)
-            rasterImageGeoreferencer.actionInterrupted();
-        } else {
-            int reply = JOptionPane.CANCEL_OPTION;
-            if (wmsLayer.isAlreadyGeoreferenced()) {
-                reply = JOptionPane.showConfirmDialog(null,
-                        tr("This image contains georeference data.\n"+
-                                "Do you want to use them ?"),
-                        null,
-                        JOptionPane.YES_NO_OPTION);
-            }
-            if (reply == JOptionPane.OK_OPTION) {
-                rasterImageGeoreferencer.transformGeoreferencedImg();
-            } else {
-                rasterImageGeoreferencer.addListener();
-                if (Main.pref.getBoolean("cadastrewms.noImageCropping", false) == false)
-                    rasterImageGeoreferencer.startCropping(wmsLayer);
-                else
-                    rasterImageGeoreferencer.startGeoreferencing(wmsLayer);
-            }
-        }
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionLoadFromCache.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionLoadFromCache.java	(revision 33637)
+++ 	(revision )
@@ -1,113 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.marktr;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-
-import javax.swing.JFileChooser;
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.JosmAction;
-import org.openstreetmap.josm.gui.layer.Layer;
-
-public class MenuActionLoadFromCache extends JosmAction {
-    private static final long serialVersionUID = 1L;
-
-    public static final String name = marktr("Load layer from cache");
-
-    /**
-     * Constructs a new {@code MenuActionLoadFromCache}.
-     */
-    public MenuActionLoadFromCache() {
-        super(tr(name), "cadastre_small", tr("Load location from cache (only if cache is enabled)"), null, false, "cadastrefr/loadfromcache", true);
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        JFileChooser fc = createAndOpenFileChooser();
-        if (fc == null)
-            return;
-
-        File[] files = fc.getSelectedFiles();
-        int layoutZone = CadastrePlugin.getCadastreProjectionLayoutZone();
-        nextFile:
-        for (File file : files) {
-            if (file.exists()) {
-                String filename = file.getName();
-                String ext = (filename.lastIndexOf('.') == -1) ? "" : filename.substring(filename.lastIndexOf('.')+1, filename.length());
-                if ((ext.length() == 3 && ext.substring(0, CacheControl.C_LAMBERT_CC_9Z.length()).equals(CacheControl.C_LAMBERT_CC_9Z) &&
-                    !(CadastrePlugin.isLambert_cc9()))
-                    || (ext.length() == 4 && ext.substring(0, CacheControl.C_UTM20N.length()).equals(CacheControl.C_UTM20N) &&
-                            !(CadastrePlugin.isUtm_france_dom()))
-                    || (ext.length() == 1) && !(CadastrePlugin.isLambert())) {
-                        JOptionPane.showMessageDialog(Main.parent, tr("{0} not allowed with the current projection", filename),
-                                tr("Error"), JOptionPane.ERROR_MESSAGE);
-                        continue;
-                } else {
-                    String location = filename.substring(0, filename.lastIndexOf('.'));
-                    if (ext.length() == 3 && ext.substring(0, CacheControl.C_LAMBERT_CC_9Z.length()).equals(CacheControl.C_LAMBERT_CC_9Z))
-                        ext = ext.substring(2);
-                    else if (ext.length() == 4 && ext.substring(0, CacheControl.C_UTM20N.length()).equals(CacheControl.C_UTM20N))
-                        ext = ext.substring(3);
-                    // check the extension and its compatibility with current projection
-                    try {
-                        int cacheZone = Integer.parseInt(ext) - 1;
-                        if (cacheZone >= 0 && cacheZone <= 9) {
-                            if (cacheZone != layoutZone) {
-                                JOptionPane.showMessageDialog(Main.parent,
-                                        tr("Cannot load cache {0} which is not compatible with current projection zone", filename),
-                                        tr("Error"), JOptionPane.ERROR_MESSAGE);
-                                continue nextFile;
-                            } else
-                                Main.info("Load cache " + filename);
-                        }
-                    } catch (NumberFormatException ex) {
-                        JOptionPane.showMessageDialog(Main.parent, tr("Selected file {0} is not a cache file from this plugin (invalid extension)", filename), tr("Error"), JOptionPane.ERROR_MESSAGE);
-                        continue nextFile;
-                    }
-                    // check if the selected cache is not already displayed
-                    if (Main.map != null) {
-                        for (Layer l : Main.getLayerManager().getLayers()) {
-                            if (l instanceof WMSLayer && l.getName().equals(location)) {
-                                JOptionPane.showMessageDialog(Main.parent, tr("The location {0} is already on screen. Cache not loaded.", filename), tr("Error"), JOptionPane.ERROR_MESSAGE);
-                                continue nextFile;
-                            }
-                        }
-                    }
-                    // create layer and load cache
-                    WMSLayer wmsLayer = new WMSLayer("", "", Integer.parseInt(ext)-1);
-                    if (wmsLayer.grabThread.getCacheControl().loadCache(file, layoutZone)) {
-                        CadastrePlugin.addWMSLayer(wmsLayer);
-                    }
-                }
-            }
-        }
-
-    }
-
-    protected static JFileChooser createAndOpenFileChooser() {
-        JFileChooser fc = new JFileChooser(new File(CadastrePlugin.cacheDir));
-        fc.setMultiSelectionEnabled(true);
-        int layoutZone = CadastrePlugin.getCadastreProjectionLayoutZone();
-        if (layoutZone != -1) {
-            if (CadastrePlugin.isLambert())
-                fc.addChoosableFileFilter(CacheFileLambert4ZoneFilter.filters[layoutZone]);
-            else if (CadastrePlugin.isLambert_cc9())
-                fc.addChoosableFileFilter(CacheFileLambert9ZoneFilter.filters[layoutZone]);
-            else if (CadastrePlugin.isUtm_france_dom())
-                fc.addChoosableFileFilter(CacheFileUTM20NFilter.filters[layoutZone]);
-        }
-        fc.setAcceptAllFileFilterUsed(false);
-
-        int answer = fc.showOpenDialog(Main.parent);
-        if (answer != JFileChooser.APPROVE_OPTION)
-            return null;
-
-        return fc;
-    }
-
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionNewLocation.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionNewLocation.java	(revision 33637)
+++ 	(revision )
@@ -1,134 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.GridBagLayout;
-import java.awt.event.ActionEvent;
-import java.util.ArrayList;
-
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JTextField;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.JosmAction;
-import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.tools.GBC;
-
-public class MenuActionNewLocation extends JosmAction {
-
-    private static final long serialVersionUID = 1L;
-
-    // CHECKSTYLE.OFF: LineLength
-    // CHECKSTYLE.OFF: SingleSpaceSeparator
-
-    private static final String[] departements = {
-        "", tr("(optional)"),
-        "001", "01 - Ain",                 "002", "02 - Aisne",              "003", "03 - Allier",                "004", "04 - Alpes de Haute-Provence", "005", "05 - Hautes-Alpes",
-        "006", "06 - Alpes-Maritimes",     "007", "07 - Ard\u00eache",       "008", "08 - Ardennes",              "009", "09 - Ari\u00e8ge",             "010", "10 - Aube",
-        "011", "11 - Aude",                "012", "12 - Aveyron",            "013", "13 - Bouches-du-Rh\u00f4ne", "014", "14 - Calvados",                "015", "15 - Cantal",
-        "016", "16 - Charente",            "017", "17 - Charente-Maritime",  "018", "18 - Cher",                  "019", "19 - Corr\u00e8ze",
-        "02A", "2A - Corse-du-Sud",        "02B", "2B - Haute-Corse",
-        "021", "21 - C\u00f4te-d'Or",      "022", "22 - C\u00f4tes d'Armor", "023", "23 - Creuse",                "024", "24 - Dordogne",                "025", "25 - Doubs",
-        "026", "26 - Dr\u00f4me",          "027", "27 - Eure",               "028", "28 - Eure-et-Loir",          "029", "29 - Finist\u00e8re",          "030", "30 - Gard",
-        "031", "31 - Haute-Garonne",       "032", "32 - Gers",               "033", "33 - Gironde",               "034", "34 - H\u00e9rault",            "035", "35 - Ille-et-Vilaine",
-        "036", "36 - Indre",               "037", "37 - Indre-et-Loire",     "038", "38 - Is\u00e8re",            "039", "39 - Jura",                    "040", "40 - Landes",
-        "041", "41 - Loir-et-Cher",        "042", "42 - Loire",              "043", "43 - Haute-Loire",           "044", "44 - Loire-Atlantique",        "045", "45 - Loiret",
-        "046", "46 - Lot",                 "047", "47 - Lot-et-Garonne",     "048", "48 - Loz\u00e8re",           "049", "49 - Maine-et-Loire",          "050", "50 - Manche",
-        "051", "51 - Marne",               "052", "52 - Haute-Marne",        "053", "53 - Mayenne",               "054", "54 - Meurthe-et-Moselle",      "055", "55 - Meuse",
-        "056", "56 - Morbihan",            "057", "57 - Moselle",            "058", "58 - Ni\u00e8vre",           "059", "59 - Nord",                    "060", "60 - Oise",
-        "061", "61 - Orne",                "062", "62 - Pas-de-Calais",      "063", "63 - Puy-de-D\u00f4me",      "064", "64 - Pyr\u00e9n\u00e9es-Atlantiques", "065", "65 - Hautes-Pyr\u00e9n\u00e9es",
-        "066", "66 - Pyr\u00e9n\u00e9es-Orientales", "067", "67 - Bas-Rhin", "068", "68 - Haut-Rhin",             "069", "69 - Rh\u00f4ne",              "070", "70 - Haute-Sa\u00f4ne",
-        "071", "71 - Sa\u00f4ne-et-Loire", "072", "72 - Sarthe",             "073", "73 - Savoie",                "074", "74 - Haute-Savoie",            "075", "75 - Paris",
-        "076", "76 - Seine-Maritime",      "077", "77 - Seine-et-Marne",     "078", "78 - Yvelines",              "079", "79 - Deux-S\u00e8vres",        "080", "80 - Somme",
-        "081", "81 - Tarn",                "082", "82 - Tarn-et-Garonne",    "083", "83 - Var",                   "084", "84 - Vaucluse",                "085", "85 - Vend\u00e9e",
-        "086", "86 - Vienne",              "087", "87 - Haute-Vienne",       "088", "88 - Vosges",                "089", "89 - Yonne",                   "090", "90 - Territoire de Belfort",
-        "091", "91 - Essonne",             "092", "92 - Hauts-de-Seine",     "093", "93 - Seine-Saint-Denis",     "094", "94 - Val-de-Marne",            "095", "95 - Val-d'Oise",
-        "971", "971 - Guadeloupe",         "972", "972 - Martinique",        "973", "973 - Guyane",               "974", "974 - R\u00e9union"
-    };
-
-    // CHECKSTYLE.ON: SingleSpaceSeparator
-    // CHECKSTYLE.ON: LineLength
-
-    public MenuActionNewLocation() {
-        super(tr("Change location"), "cadastre_small", tr("Set a new location for the next request"), null, false,
-                "cadastrefr/newlocation", true);
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        WMSLayer wmsLayer = addNewLayer(new ArrayList<WMSLayer>());
-        if (wmsLayer != null)
-            DownloadWMSVectorImage.download(wmsLayer);
-    }
-
-    public WMSLayer addNewLayer(ArrayList<WMSLayer> existingLayers) {
-        String location = "";
-        String codeDepartement = "";
-        String codeCommune = "";
-        JLabel labelSectionNewLocation = new JLabel(tr("Add a new municipality layer"));
-        JPanel p = new JPanel(new GridBagLayout());
-        JLabel labelLocation = new JLabel(tr("Commune"));
-        final JTextField inputTown = new JTextField(Main.pref.get("cadastrewms.location"));
-        inputTown.setToolTipText(tr("<html>Enter the town,village or city name.<br>"
-                + "Use the syntax and punctuation known by www.cadastre.gouv.fr .</html>"));
-        JLabel labelDepartement = new JLabel(tr("Departement"));
-        final JComboBox<String> inputDepartement = new JComboBox<>();
-        for (int i = 1; i < departements.length; i += 2) {
-            inputDepartement.addItem(departements[i]);
-        }
-        inputDepartement.setToolTipText(tr("<html>Departement number (optional)</html>"));
-        if (!Main.pref.get("cadastrewms.codeDepartement").equals("")) {
-            for (int i = 0; i < departements.length; i += 2) {
-                if (departements[i].equals(Main.pref.get("cadastrewms.codeDepartement")))
-                    inputDepartement.setSelectedIndex(i/2);
-            }
-        }
-        p.add(labelSectionNewLocation, GBC.eol());
-        p.add(labelLocation, GBC.std().insets(10, 0, 0, 0));
-        p.add(inputTown, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 5));
-        p.add(labelDepartement, GBC.std().insets(10, 0, 0, 0));
-        p.add(inputDepartement, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 5));
-        JOptionPane pane = new JOptionPane(p, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null) {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public void selectInitialValue() {
-                inputTown.requestFocusInWindow();
-                inputTown.selectAll();
-            }
-        };
-        pane.createDialog(Main.parent, tr("Add new layer")).setVisible(true);
-        if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
-            return null;
-
-        WMSLayer wmsLayer = null;
-        if (!inputTown.getText().equals("")) {
-            location = inputTown.getText().toUpperCase();
-            codeDepartement = departements[inputDepartement.getSelectedIndex()*2];
-            Main.pref.put("cadastrewms.location", location);
-            Main.pref.put("cadastrewms.codeCommune", codeCommune);
-            Main.pref.put("cadastrewms.codeDepartement", codeDepartement);
-            if (Main.map != null) {
-                for (Layer l : Main.getLayerManager().getLayers()) {
-                    if (l instanceof WMSLayer && l.getName().equalsIgnoreCase(location)) {
-                        return null;
-                    }
-                }
-            }
-            // add the layer if it doesn't exist
-            int zone = CadastrePlugin.getCadastreProjectionLayoutZone();
-            wmsLayer = new WMSLayer(location, codeCommune, zone);
-            wmsLayer.setDepartement(codeDepartement);
-            CadastrePlugin.addWMSLayer(wmsLayer);
-            Main.info("Add new layer with Location:" + inputTown.getText());
-        } else if (existingLayers != null && existingLayers.size() > 0 && Main.getLayerManager().getActiveLayer() instanceof WMSLayer) {
-            wmsLayer = (WMSLayer) Main.getLayerManager().getActiveLayer();
-        }
-
-        return wmsLayer;
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionOpenPreferences.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionOpenPreferences.java	(revision 33637)
+++ 	(revision )
@@ -1,31 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.marktr;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.JosmAction;
-import org.openstreetmap.josm.gui.preferences.PreferenceDialog;
-
-public class MenuActionOpenPreferences extends JosmAction {
-    private static final long serialVersionUID = 1L;
-
-    public static final String NAME = marktr("Preferences");
-
-    /**
-     * Constructs a new {@code MenuActionOpenPreferences}.
-     */
-    public MenuActionOpenPreferences() {
-        super(tr(NAME), "cadastre_small", tr("Open Cadastre Preferences"), null, false, "cadastrefr/openpreferences", true);
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        PreferenceDialog p = new PreferenceDialog(Main.parent);
-        p.selectPreferencesTabByClass(CadastrePreferenceSetting.class);
-        p.setVisible(true);
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionRefineGeoRef.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionRefineGeoRef.java	(revision 33637)
+++ 	(revision )
@@ -1,43 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.marktr;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.JosmAction;
-
-public class MenuActionRefineGeoRef extends JosmAction {
-
-    public static final String NAME = marktr("Refine georeferencing");
-
-    private WMSLayer wmsLayer;
-    private RasterImageGeoreferencer rasterImageGeoreferencer;
-
-    /**
-     * Constructs a new {@code MenuActionRefineGeoRef}.
-     * @param wmsLayer WMS layer
-     */
-    public MenuActionRefineGeoRef(WMSLayer wmsLayer) {
-        super(tr(NAME), null, tr("Improve georeferencing (only raster images)"), null, false);
-        this.wmsLayer = wmsLayer;
-        rasterImageGeoreferencer = new RasterImageGeoreferencer();
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent arg0) {
-        if (!wmsLayer.isRaster()) {
-            Main.info("MenuActionRefineGeoRef called for unexpected layer type");
-            return;
-        }
-        if (CadastrePlugin.isCadastreProjection()) {
-            //wmsLayer = WMSDownloadAction.getLayer();
-        } else {
-            CadastrePlugin.askToChangeProjection();
-        }
-        rasterImageGeoreferencer.addListener();
-        rasterImageGeoreferencer.startGeoreferencing(wmsLayer);
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionResetCookie.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionResetCookie.java	(revision 33637)
+++ 	(revision )
@@ -1,25 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-
-import org.openstreetmap.josm.actions.JosmAction;
-
-public class MenuActionResetCookie extends JosmAction {
-
-    /**
-     *
-     */
-    private static final long serialVersionUID = 1L;
-
-    public MenuActionResetCookie() {
-        super(tr("Reset cookie"), "cadastre_small", tr("Get a new cookie (session timeout)"), null, false);
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        //CadastrePlugin.cadastreGrabber.getWmsInterface().resetCookie();
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionSaveRasterAs.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/MenuActionSaveRasterAs.java	(revision 33637)
+++ 	(revision )
@@ -1,139 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.marktr;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
-import java.util.Locale;
-
-import javax.imageio.ImageIO;
-import javax.swing.JFileChooser;
-import javax.swing.filechooser.FileFilter;
-
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.coverage.grid.GridCoverageFactory;
-import org.geotools.coverage.grid.io.AbstractGridFormat;
-import org.geotools.gce.geotiff.GeoTiffFormat;
-import org.geotools.gce.geotiff.GeoTiffWriteParams;
-import org.geotools.gce.geotiff.GeoTiffWriter;
-import org.geotools.geometry.Envelope2D;
-import org.geotools.referencing.CRS;
-import org.opengis.parameter.GeneralParameterValue;
-import org.opengis.parameter.ParameterValueGroup;
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.JosmAction;
-
-public class MenuActionSaveRasterAs extends JosmAction {
-
-    public static final String NAME = marktr("Save image as...");
-
-    private static final long serialVersionUID = 1L;
-
-    private WMSLayer wmsLayer;
-
-    public class FiltrePng extends FileFilter {
-        @Override
-        public boolean accept(File file) {
-            if (file.isDirectory()) {
-                return true;
-            }
-            return file.getName().toLowerCase(Locale.ENGLISH).endsWith(".png");
-        }
-
-        @Override
-        public String getDescription() {
-            return tr("PNG files (*.png)");
-        }
-    }
-
-    public class FiltreTiff extends FileFilter {
-        @Override
-        public boolean accept(File file) {
-            if (file.isDirectory()) {
-                return true;
-            }
-            return file.getName().toLowerCase(Locale.ENGLISH).endsWith(".tif");
-        }
-
-        @Override
-        public String getDescription() {
-            return tr("GeoTiff files (*.tif)");
-        }
-    }
-
-    FiltreTiff filtreTiff = new FiltreTiff();
-    FiltrePng filtrePng = new FiltrePng();
-
-    /**
-     * Constructs a new {@code MenuActionSaveRasterAs}.
-     * @param wmsLayer WMS layer
-     */
-    public MenuActionSaveRasterAs(WMSLayer wmsLayer) {
-        super(tr(NAME), "save", tr("Export image (only raster images)"), null, false);
-        this.wmsLayer = wmsLayer;
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent arg0) {
-        File file;
-        JFileChooser fc = new JFileChooser();
-        fc.addChoosableFileFilter(filtreTiff);
-        fc.addChoosableFileFilter(filtrePng);
-        fc.setFileFilter(filtreTiff);
-        int returnVal = fc.showSaveDialog(Main.parent);
-        if (returnVal == JFileChooser.APPROVE_OPTION) {
-            file = fc.getSelectedFile();
-            BufferedImage bi = wmsLayer.getImage(0).image;
-            if (fc.getFileFilter().equals(filtrePng)) {
-                if (!file.getName().endsWith(".png"))
-                    file = new File(file.getParent(), file.getName()+".png");
-                try {
-                    ImageIO.write(bi, "png", file);
-/*
-                    FileOutputStream flux = new FileOutputStream(file);
-                    BufferedOutputStream fluxBuf = new BufferedOutputStream(flux);
-                    JPEGImageEncoder codec = JPEGCodec.createJPEGEncoder(fluxBuf, JPEGCodec.getDefaultJPEGEncodeParam(bi));
-                    codec.encode(bi);
-                    fluxBuf.close();
-*/
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            } else if (fc.getFileFilter().equals(filtreTiff)) {
-                boolean alpha = bi.getColorModel().hasAlpha();
-                Main.info("image with alpha channel : " + alpha);
-                try {
-                    double x = wmsLayer.getImage(0).min.east();
-                    double y = wmsLayer.getImage(0).min.north();
-                    Envelope2D bbox = new Envelope2D(CRS.decode("EPSG:27561"),
-                            x, y,
-                            wmsLayer.getImage(0).max.east()-x, wmsLayer.getImage(0).max.north()-y);
-                    GridCoverageFactory factory = new GridCoverageFactory();
-                    GridCoverage2D coverage = factory.create("tiff", bi, bbox);
-                    final File output = new File(file.getParent(), file.getName()+".tif");
-                    GeoTiffWriter gtwriter = new GeoTiffWriter(output);
-                    GeoTiffWriteParams wp = new GeoTiffWriteParams();
-                    wp.setCompressionMode(GeoTiffWriteParams.MODE_EXPLICIT);
-                    wp.setCompressionType("LZW");
-                    wp.setCompressionQuality(0.75F);
-                    final GeoTiffFormat format = new GeoTiffFormat();
-                    final ParameterValueGroup params = format.getWriteParameters();
-                    params.parameter(
-                                    AbstractGridFormat.GEOTOOLS_WRITE_PARAMS.getName().toString())
-                                    .setValue(wp);
-
-                    gtwriter.write(coverage, params.values().toArray(new GeneralParameterValue[1]));
-                    gtwriter.dispose();
-                    coverage.dispose(true);
-                } catch (Exception e) {
-                    Main.error(e);
-                }
-            }
-        }
-    }
-
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/RasterImageGeoreferencer.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/RasterImageGeoreferencer.java	(revision 33637)
+++ 	(revision )
@@ -1,363 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.GridBagLayout;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JTextField;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.tools.GBC;
-
-public class RasterImageGeoreferencer implements MouseListener {
-
-    private int countMouseClicked = 0;
-    private int mode = 0;
-    private int cGetCorners = 1;
-    private int cGetLambertCrosspieces = 2;
-    private EastNorth ea1;
-    private EastNorth ea2;
-    private long mouseClickedTime = 0;
-    private WMSLayer wmsLayer;
-    private EastNorth georefpoint1;
-    private EastNorth georefpoint2;
-    private boolean ignoreMouseClick = false;
-    private boolean clickOnTheMap = false;
-
-    /**
-     * The time which needs to pass between two clicks during georeferencing, in milliseconds
-     */
-    private int initialClickDelay;
-
-    public void addListener() {
-        Main.map.mapView.addMouseListener(this);
-    }
-
-    /**
-    *
-    * @return false if all operations are canceled
-    */
-   public boolean startCropping(WMSLayer wmsLayer) {
-       this.wmsLayer = wmsLayer;
-       mode = cGetCorners;
-       countMouseClicked = 0;
-       initialClickDelay = Main.pref.getInteger("cadastrewms.georef-click-delay", 200);
-       mouseClickedTime = System.currentTimeMillis();
-       Object[] options = {"OK", "Cancel"};
-       int ret = JOptionPane.showOptionDialog(null,
-               tr("Click first corner for image cropping\n(two points required)"),
-               tr("Image cropping"),
-               JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
-               null, options, options[0]);
-       if (ret == JOptionPane.OK_OPTION) {
-           mouseClickedTime = System.currentTimeMillis();
-       } else
-           if (canceledOrRestartCurrAction("image cropping"))
-               return startCropping(wmsLayer);
-       return true;
-   }
-
-   /**
-    *
-    * @return false if all operations are canceled
-    */
-  public boolean startGeoreferencing(WMSLayer wmsLayer) {
-      this.wmsLayer = wmsLayer;
-      countMouseClicked = 0;
-      mode = cGetLambertCrosspieces;
-      initialClickDelay = Main.pref.getInteger("cadastrewms.georef-click-delay", 200);
-      mouseClickedTime = System.currentTimeMillis();
-      Object[] options = {"OK", "Cancel"};
-      int ret = JOptionPane.showOptionDialog(null,
-              tr("Click first Lambert crosspiece for georeferencing\n(two points required)"),
-              tr("Image georeferencing"),
-              JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
-              null, options, options[0]);
-      if (ret == JOptionPane.OK_OPTION) {
-          mouseClickedTime = System.currentTimeMillis();
-      } else
-          if (canceledOrRestartCurrAction("georeferencing"))
-              return startGeoreferencing(wmsLayer);
-      return true;
-  }
-
-  public boolean isRunning() {
-      return (countMouseClicked != 0 || mode != 0);
-  }
-
-  @Override
-  public void mouseClicked(MouseEvent e) {
-      if (System.currentTimeMillis() - mouseClickedTime < initialClickDelay) {
-          Main.info("mouse click bounce detected");
-          return; // mouse click anti-bounce
-      } else
-          mouseClickedTime = System.currentTimeMillis();
-      if (e.getButton() != MouseEvent.BUTTON1)
-          return;
-      if (ignoreMouseClick) return; // In case we are currently just allowing zooming to read lambert coordinates
-      EastNorth ea = Main.getProjection().latlon2eastNorth(Main.map.mapView.getLatLon(e.getX(), e.getY()));
-      Main.info("click:"+countMouseClicked+" ,"+ea+", mode:"+mode);
-      if (clickOnTheMap) {
-          clickOnTheMap = false;
-          handleNewCoordinates(ea.east(), ea.north());
-      } else {
-          // ignore clicks outside the image
-          if (ea.east() < wmsLayer.getImage(0).min.east() || ea.east() > wmsLayer.getImage(0).max.east()
-                  || ea.north() < wmsLayer.getImage(0).min.north() || ea.north() > wmsLayer.getImage(0).max.north()) {
-              Main.info("ignore click outside the image");
-              return;
-          }
-          countMouseClicked++;
-          if (mode == cGetCorners) {
-              if (countMouseClicked == 1) {
-                  ea1 = ea;
-                  continueCropping();
-              }
-              if (countMouseClicked == 2) {
-                  wmsLayer.cropImage(ea1, ea);
-                  wmsLayer.invalidate();
-                  startGeoreferencing(wmsLayer);
-              }
-          } else if (mode == cGetLambertCrosspieces) {
-              if (countMouseClicked == 1) {
-                  ea1 = ea;
-                  inputLambertPosition(); // This will automatically asks for second point and continue the georeferencing
-              }
-              if (countMouseClicked == 2) {
-                  ea2 = ea;
-                  inputLambertPosition(); // This will automatically ends the georeferencing
-              }
-          }
-      }
-  }
-
-  /**
-   *
-   * @return false if all operations are canceled
-   */
- private boolean canceledOrRestartCurrAction(String action) {
-     Object[] options = {"Cancel", "Retry"};
-     int selectedValue = JOptionPane.showOptionDialog(null,
-             tr("Do you want to cancel completely\n"+
-                     "or just retry "+action+" ?"), "",
-             JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
-             null, options, options[0]);
-     countMouseClicked = 0;
-     if (selectedValue == 0) { // "Cancel"
-         // remove layer
-         Main.getLayerManager().removeLayer(wmsLayer);
-         wmsLayer = null;
-         Main.map.mapView.removeMouseListener(this);
-         return false;
-     }
-     return true;
- }
-
- /**
-  * Use point org1 as anchor for scale, then move org1 to dst1, then rotate org2 on dst2
-  * around org1/dst1 anchor
-  * @param org1 first point at original coordinate system (the grabbed image)
-  * @param org2 second point
-  * @param dst1 first point at final destination coordinate system (the real east/north coordinate system)
-  * @param dst2 second point
-  */
- private void affineTransform(EastNorth org1, EastNorth org2, EastNorth dst1, EastNorth dst2) {
-     // handle an NPE case I'm not able to reproduce
-     if (org1 == null || org2 == null || dst1 == null || dst2 == null) {
-         JOptionPane.showMessageDialog(Main.parent,
-                 tr("Ooops. I failed to catch all coordinates\n"+
-                    "correctly. Retry please."));
-         Main.warn("failed to transform: one coordinate missing:"
-                    +"org1="+org1+", org2="+org2+", dst1="+dst1+", dst2="+dst2);
-         return;
-     }
-     double angle = dst1.heading(dst2) - org1.heading(org2);
-     double proportion = dst1.distance(dst2)/org1.distance(org2);
-     // move
-     double dx = dst1.getX() - org1.getX();
-     double dy = dst1.getY() - org1.getY();
-     wmsLayer.getImage(0).shear(dx, dy);
-     // rotate : dst1 is anchor for rotation and scale
-     wmsLayer.getImage(0).rotate(dst1, angle);
-     // scale image from anchor dst1
-     wmsLayer.getImage(0).scale(dst1, proportion);
- }
-
- /**
-  * Ends the georeferencing by computing the affine transformation
-  */
- private void endGeoreferencing() {
-     Main.map.mapView.removeMouseListener(this);
-     affineTransform(ea1, ea2, georefpoint1, georefpoint2);
-     wmsLayer.grabThread.saveNewCache();
-     wmsLayer.invalidate();
-     actionCompleted();
-     clickOnTheMap = false;
-     ignoreMouseClick = false;
- }
-
- private void inputLambertPosition() {
-     JLabel labelEnterPosition = new JLabel(
-             tr("Enter cadastre east,north position"));
-     JLabel labelWarning = new JLabel(
-             tr("(Warning: verify north with arrow !!)"));
-     JPanel p = new JPanel(new GridBagLayout());
-     JLabel labelEast = new JLabel(tr("East"));
-     JLabel labelNorth = new JLabel(tr("North"));
-     final JTextField inputEast = new JTextField();
-     final JTextField inputNorth = new JTextField();
-     p.add(labelEnterPosition, GBC.eol());
-     p.add(labelWarning, GBC.eol());
-     p.add(labelEast, GBC.std().insets(0, 0, 10, 0));
-     p.add(inputEast, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 5, 0, 5));
-     p.add(labelNorth, GBC.std().insets(0, 0, 10, 0));
-     p.add(inputNorth, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 5, 0, 5));
-     final Object[] options = {tr("OK"),
-             tr("Cancel"),
-             tr("I use the mouse")};
-     final JOptionPane pane = new JOptionPane(p,
-             JOptionPane.INFORMATION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION,
-             null, options, options[0]);
-     String number;
-     if (countMouseClicked == 1)
-         number = "first";
-     else
-         number = "second";
-     JDialog dialog = pane.createDialog(Main.parent, tr(
-             "Set {0} Lambert coordinates", number));
-     dialog.setModal(false);
-     ignoreMouseClick = true; // To avoid mouseClicked from being called
-                              // during coordinates reading
-     dialog.setAlwaysOnTop(true);
-     dialog.setVisible(true);
-     pane.addPropertyChangeListener(new PropertyChangeListener() {
-         @Override
-         public void propertyChange(PropertyChangeEvent evt) {
-             if (JOptionPane.VALUE_PROPERTY.equals(evt.getPropertyName())) {
-                 ignoreMouseClick = false;
-                 // Cancel
-                 if (pane.getValue().equals(options[1])) {
-                     if (canceledOrRestartCurrAction("georeferencing"))
-                         startGeoreferencing(wmsLayer);
-                 }
-                 // Click on the map
-                 if (pane.getValue().equals(options[2])) {
-                     clickOnTheMap = true;
-                 } else {
-                 // OK (coordinates manually entered)
-                     clickOnTheMap = false;
-                     if (inputEast.getText().length() != 0
-                             && inputNorth.getText().length() != 0) {
-                         double e, n;
-                         try {
-                             e = Double.parseDouble(inputEast.getText());
-                             n = Double.parseDouble(inputNorth.getText());
-                         } catch (NumberFormatException ex) {
-                             return;
-                         }
-                         handleNewCoordinates(e, n);
-                     }
-                 }
-             }
-         }
-     });
- }
-
- /**
- *
- * @return false if all operations are canceled
- */
-private boolean continueCropping() {
-    Object[] options = {"OK", "Cancel"};
-    int ret = JOptionPane.showOptionDialog(null,
-            tr("Click second corner for image cropping"),
-            tr("Image cropping"),
-            JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
-            null, options, options[0]);
-    if (ret != JOptionPane.OK_OPTION) {
-        if (canceledOrRestartCurrAction("image cropping"))
-            return startCropping(wmsLayer);
-    }
-    return true;
-}
-
-public void transformGeoreferencedImg() {
-    georefpoint1 = new EastNorth(wmsLayer.X0, wmsLayer.Y0);
-    georefpoint2 = new EastNorth(wmsLayer.X0+wmsLayer.fX*wmsLayer.communeBBox.max.getX(),
-            wmsLayer.Y0+wmsLayer.fY*wmsLayer.communeBBox.max.getX());
-    ea1 = new EastNorth(wmsLayer.getImage(0).min.east(), wmsLayer.getImage(0).max.north());
-    EastNorth ea2 = wmsLayer.getImage(0).max;
-    affineTransform(ea1, ea2, georefpoint1, georefpoint2);
-    wmsLayer.grabThread.saveNewCache();
-    wmsLayer.invalidate();
-}
-
-
- /**
- *
- * @return false if all operations are canceled
- */
-private boolean continueGeoreferencing() {
-    Object[] options = {"OK", "Cancel"};
-    int ret = JOptionPane.showOptionDialog(null,
-            tr("Click second Lambert crosspiece for georeferencing"),
-            tr("Image georeferencing"),
-            JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
-            null, options, options[0]);
-    if (ret != JOptionPane.OK_OPTION) {
-        if (canceledOrRestartCurrAction("georeferencing"))
-            return startGeoreferencing(wmsLayer);
-    }
-    return true;
-}
-
- private void handleNewCoordinates(double e, double n) {
-     if (countMouseClicked == 1) {
-         georefpoint1 = new EastNorth(e, n);
-         continueGeoreferencing();
-     } else {
-         georefpoint2 = new EastNorth(e, n);
-         endGeoreferencing();
-     }
- }
-
- private void actionCompleted() {
-     countMouseClicked = 0;
-     mode = 0;
-     mouseClickedTime = System.currentTimeMillis();
- }
-
- public void actionInterrupted() {
-     actionCompleted();
-     if (wmsLayer != null) {
-         Main.getLayerManager().removeLayer(wmsLayer);
-         wmsLayer = null;
-     }
- }
-
- @Override
- public void mouseEntered(MouseEvent arg0) {
- }
-
- @Override
- public void mouseExited(MouseEvent arg0) {
- }
-
- @Override
- public void mousePressed(MouseEvent arg0) {
- }
-
- @Override
- public void mouseReleased(MouseEvent arg0) {
- }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/RasterImageModifier.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/RasterImageModifier.java	(revision 33637)
+++ 	(revision )
@@ -1,106 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import java.awt.Color;
-import java.awt.image.BufferedImage;
-import java.awt.image.ComponentColorModel;
-import java.awt.image.IndexColorModel;
-
-import org.openstreetmap.josm.Main;
-
-public class RasterImageModifier extends ImageModifier {
-
-    private int cadastreBackground = -1; // white
-
-    public static int cadastreBackgroundTransp = 16777215; // original white but transparent
-
-    private boolean transparencyEnabled = false;
-
-    public RasterImageModifier(BufferedImage bi) {
-        setBufferedImage(bi);
-        transparencyEnabled = Main.pref.getBoolean("cadastrewms.backgroundTransparent");
-        if (transparencyEnabled)
-            makeTransparent();
-        if (Main.pref.getBoolean("cadastrewms.invertGrey"))
-            invertGrey();
-    }
-
-    /**
-     * Invert black/white/grey pixels (to change original black characters to white).
-     */
-    private void invertGrey() {
-        int w = bufferedImage.getWidth();
-        int h = bufferedImage.getHeight();
-        for (int x = 0; x < w; x++) {
-            for (int y = 0; y < h; y++) {
-                int pixel = bufferedImage.getRGB(x, y);
-                if ((!transparencyEnabled && pixel != cadastreBackground)
-                        || (transparencyEnabled && pixel != cadastreBackgroundTransp)) {
-                    bufferedImage.setRGB(x, y, reverseIfGrey(pixel));
-                }
-            }
-        }
-    }
-
-    /**
-     * Reverse the grey value if the pixel is grey (light grey becomes dark grey)
-     * Used for texts.
-     */
-    private int reverseIfGrey(int pixel) {
-        Color col = new Color(pixel);
-        int r = col.getRed();
-        int g = col.getGreen();
-        int b = col.getBlue();
-        if ((b == r) && (b == g)) {
-            pixel = (0x00 << 32) + ((byte) (255 - r) << 16) + ((byte) (255 - r) << 8) + ((byte) (255 - r));
-        }
-        return pixel;
-    }
-
-    private void makeTransparent() {
-        if (bufferedImage.getColorModel() instanceof ComponentColorModel ||
-            bufferedImage.getColorModel() instanceof IndexColorModel) {
-            int width = bufferedImage.getWidth();
-            int height = bufferedImage.getHeight();
-            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-            // converting grey scale colors to black/white is configurable (use less resources but is less readable)
-            boolean simplifyColors = Main.pref.getBoolean("cadastrewms.raster2bitsColors", false);
-            for (int y = 0; y < height; y++) {
-                for (int x = 0; x < width; x++) {
-                    int rgb = bufferedImage.getRGB(x, y);
-                    Color c = new Color(rgb);
-                    int r = c.getRed();
-                    int g = c.getGreen();
-                    int b = c.getBlue();
-                    Color maskedColor;
-                    if (rgb == cadastreBackground) {
-                        maskedColor = simplifyColors ? new Color(0xff, 0xff, 0xff, 0x00) :
-                            new Color(r, g, b, 0x00); // transparent
-                    } else {
-                        maskedColor = simplifyColors ? new Color(0, 0, 0, 0xFF) :
-                            new Color(r, g, b, 0xFF); // opaque
-                    }
-                    bi.setRGB(x, y, maskedColor.getRGB());
-                }
-            }
-            setBufferedImage(bi);
-        }
-        return;
-    }
-
-    /**
-     * Temporary fix for Java6 which doesn't de-serialize correctly cached image on disk.
-     * Recreate a new raster image based on what is loaded/serialized from disk cache.
-     * @return new image
-     */
-    public static BufferedImage fixRasterImage(BufferedImage img) {
-        int width = img.getWidth();
-        int height = img.getHeight();
-        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-        int[] rgbArray = new int[width * height];
-        img.getRGB(0, 0, width, height, rgbArray, 0, width);
-        bi.setRGB(0, 0, width, height, rgbArray, 0, width);
-        return bi;
-    }
-
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/SVGParser.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/SVGParser.java	(revision 33637)
+++ 	(revision )
@@ -1,64 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import java.util.ArrayList;
-
-/**
- * This class is not intended to be a real SVG parser. It's also not using existing
- * xml parsers. It's just extracting the required strings from an SVG file coming
- * from the French land registry cadastre.gouv.fr
- *
- */
-public class SVGParser {
-
-    private String cViewBoxStart = "viewBox=\"";
-    private String cViewBoxEnd = "\"";
-    private String cPathStart = "<path d=\"";
-    private String cClosedPathEnd = "\"/>";
-
-    /**
-     * The SVG viewBox looks like this:
-     *   viewBox="969780.0 320377.11 5466.130000000005 2846.429999999993"
-     * @param svg the SVG XML data
-     * @return double [x,y,dx,dy] of viewBox; null if parsing failed
-     */
-    public double[] getViewBox(String svg) {
-        int s = svg.indexOf(cViewBoxStart)+cViewBoxStart.length();
-        int e = svg.indexOf(cViewBoxEnd, s);
-        if (s != -1 && e != -1) {
-            try {
-                String str = svg.substring(s, e);
-                String[] viewBox = str.split(" ");
-                double[] dbox = new double[4];
-                for (int i = 0; i < 4; i++) {
-                    dbox[i] = Double.parseDouble(viewBox[i]);
-                }
-                return dbox;
-            } catch (Exception ex) {
-                return null;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Closed SVG paths are finishing with a "Z" at the end of the moves list.
-     */
-    public String[] getClosedPaths(String svg) {
-        ArrayList<String> path = new ArrayList<>();
-        int i = 0;
-        while (svg.indexOf(cPathStart, i) != -1) {
-            int s = svg.indexOf(cPathStart, i) + cViewBoxStart.length();
-            int e = svg.indexOf(cClosedPathEnd, s);
-            if (s != -1 && e != -1) {
-                String onePath = svg.substring(s, e);
-                if (onePath.indexOf("Z") != -1) // only closed SVG path
-                    path.add(onePath);
-            } else
-                break;
-            i = e;
-        }
-        return path.toArray(new String[ path.size() ]);
-    }
-
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/Scale.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/Scale.java	(revision 33637)
+++ 	(revision )
@@ -1,31 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-/**
- * List of possible grab factors each time we call the grab action.
- * X1 means that only one bounding box is grabbed where X2 means that the current
- * view is split in 2x2 bounding boxes and X3 is 3x3 boxes.
- * SQUARE_100M is a special value where bounding boxes have a fixed size of 100x100 meters
- * and east,north are rounded to the lowest 100 meter as well, thus none of the bounding boxes
- * are overlapping each others.
- */
-public enum Scale {
-    X1("1"),
-    X2("2"),
-    X3("3"),
-    SQUARE_100M("4");
-
-    /**
-     * value is the string equivalent stored in the preferences file
-     */
-    public final String value;
-
-    Scale(String value) {
-        this.value = value;
-    }
-
-    @Override
-    public String toString() {
-        return value;
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/SimplifyWay.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/SimplifyWay.java	(revision 33637)
+++ 	(revision )
@@ -1,85 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.data.projection.Ellipsoid;
-
-/**
- * Imported from plugin UtilsPlugin
- * @author
- *
- */
-public class SimplifyWay {
-    public void simplifyWay(Way w/*, DataSet dataSet*/, double threshold) {
-        Way wnew = new Way(w);
-
-        simplifyWayRange(wnew, 0, wnew.getNodesCount() - 1, threshold);
-        w.setNodes(wnew.getNodes());
-    }
-
-    public void simplifyWayRange(Way wnew, int from, int to, double thr) {
-        if (to - from >= 2) {
-            ArrayList<Node> ns = new ArrayList<>();
-            simplifyWayRange(wnew, from, to, ns, thr);
-            List<Node> nodes = wnew.getNodes();
-            for (int j = to - 1; j > from; j--) {
-                nodes.remove(j);
-            }
-            nodes.addAll(from+1, ns);
-            wnew.setNodes(nodes);
-        }
-    }
-
-    /**
-     * Takes an interval [from,to] and adds nodes from (from,to) to ns.
-     * (from and to are indices of wnew.nodes.)
-     */
-    public void simplifyWayRange(Way wnew, int from, int to, ArrayList<Node> ns, double thr) {
-        Node fromN = wnew.getNode(from), toN = wnew.getNode(to);
-
-        int imax = -1;
-        double xtemax = 0;
-        for (int i = from + 1; i < to; i++) {
-            Node n = wnew.getNode(i);
-            double xte = Math.abs(Ellipsoid.WGS84.a
-                    * xtd(fromN.getCoor().lat() * Math.PI / 180, fromN.getCoor().lon() * Math.PI / 180, toN.getCoor().lat() * Math.PI
-                            / 180, toN.getCoor().lon() * Math.PI / 180, n.getCoor().lat() * Math.PI / 180, n.getCoor().lon() * Math.PI
-                            / 180));
-            if (xte > xtemax) {
-                xtemax = xte;
-                imax = i;
-            }
-        }
-
-        if (imax != -1 && xtemax >= thr) {
-            simplifyWayRange(wnew, from, imax, ns, thr);
-            ns.add(wnew.getNode(imax));
-            simplifyWayRange(wnew, imax, to, ns, thr);
-        }
-    }
-
-    /* From Aviaton Formulary v1.3
-     * http://www.edwilliams.org/avform.htm
-     */
-    public static double dist(double lat1, double lon1, double lat2, double lon2) {
-        return 2 * Math.asin(Math.sqrt(Math.pow(Math.sin((lat1 - lat2) / 2), 2) + Math.cos(lat1) * Math.cos(lat2)
-                * Math.pow(Math.sin((lon1 - lon2) / 2), 2)));
-    }
-
-    public static double course(double lat1, double lon1, double lat2, double lon2) {
-        return Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
-                * Math.cos(lat2) * Math.cos(lon1 - lon2))
-                % (2 * Math.PI);
-    }
-
-    public static double xtd(double lat1, double lon1, double lat2, double lon2, double lat3, double lon3) {
-        double dist_AD = dist(lat1, lon1, lat3, lon3);
-        double crs_AD = course(lat1, lon1, lat3, lon3);
-        double crs_AB = course(lat1, lon1, lat2, lon2);
-        return Math.asin(Math.sin(dist_AD) * Math.sin(crs_AD - crs_AB));
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/VectorImageModifier.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/VectorImageModifier.java	(revision 33637)
+++ 	(revision )
@@ -1,113 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import java.awt.Color;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.IndexColorModel;
-import java.awt.image.WritableRaster;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.tools.ColorHelper;
-
-public class VectorImageModifier extends ImageModifier {
-
-    private int cadastreBackground = -1; // white
-
-    public static int cadastreBackgroundTransp = 1; // original white but transparent
-
-    private int backgroundPixel = 0;
-
-    public VectorImageModifier() {
-        super();
-    }
-
-    public VectorImageModifier(BufferedImage bi, boolean monocolor) {
-        setBufferedImage(bi);
-        if (Main.pref.getBoolean("cadastrewms.backgroundTransparent"))
-            makeTransparent();
-        else if (Main.pref.getBoolean("cadastrewms.alterColors"))
-            replaceBackground();
-        if (Main.pref.getBoolean("cadastrewms.invertGrey"))
-            invertGrey();
-        if (monocolor)
-            setBufferedImage(convert8(convert4(bufferedImage)));
-    }
-
-    /**
-     * Replace the background color by the josm color.background color.
-     */
-    private void replaceBackground() {
-        int w = bufferedImage.getWidth();
-        int h = bufferedImage.getHeight();
-        int josmBackgroundColor = ColorHelper.html2color(Main.pref.get("color.background", "#000000")).getRGB();
-        for (int x = 0; x < w; x++) {
-            for (int y = 0; y < h; y++) {
-                int pixel = bufferedImage.getRGB(x, y);
-                if (pixel == cadastreBackground) {
-                    bufferedImage.setRGB(x, y, josmBackgroundColor);
-                }
-            }
-        }
-        // The cadastre has now a new background (for invertGrey())
-        cadastreBackground = josmBackgroundColor;
-    }
-
-    /**
-     * Invert black/white/grey pixels (to change original black characters to white).
-     */
-    private void invertGrey() {
-        int w = bufferedImage.getWidth();
-        int h = bufferedImage.getHeight();
-        for (int x = 0; x < w; x++) {
-            for (int y = 0; y < h; y++) {
-                int pixel = bufferedImage.getRGB(x, y);
-                if (pixel != cadastreBackground) {
-                    bufferedImage.setRGB(x, y, reverseIfGrey(pixel));
-                }
-            }
-        }
-    }
-
-    /**
-     * Reverse the grey value if the pixel is grey (light grey becomes dark grey)
-     * Used for texts.
-     */
-    private int reverseIfGrey(int pixel) {
-        Color col = new Color(pixel);
-        int r = col.getRed();
-        int g = col.getGreen();
-        int b = col.getBlue();
-        if ((b == r) && (b == g)) {
-            pixel = ((byte) col.getAlpha() << 24) + ((byte) (255 - r) << 16) + ((byte) (255 - r) << 8) + ((byte) (255 - r));
-        }
-        // Maybe we should try to find a better formula to avoid discontinuity when text is drawn on a colored item
-        // (building, ...). One could use the conversion to and from HSB to only change the brightness not the color.
-        // Note: the color palette does not have the inverse colors so it may be very weird!
-        return pixel;
-    }
-
-    private void makeTransparent() {
-        ColorModel colorModel = bufferedImage.getColorModel();
-        if (bufferedImage.getColorModel() instanceof IndexColorModel) {
-            // vector image (IndexColorModel)
-            IndexColorModel icm = (IndexColorModel) colorModel;
-            WritableRaster raster = bufferedImage.getRaster();
-            // pixel is offset in ICM's palette
-            backgroundPixel = 1; // default Cadastre background sample
-            int size = icm.getMapSize();
-            byte[] reds = new byte[size];
-            byte[] greens = new byte[size];
-            byte[] blues = new byte[size];
-            icm.getReds(reds);
-            icm.getGreens(greens);
-            icm.getBlues(blues);
-            // The cadastre background has now an alpha to 0 (for invertGrey())
-            cadastreBackground = 0x00ffffff;
-            IndexColorModel icm2 = new IndexColorModel(colorModel.getPixelSize(), size, reds, greens, blues,
-                    backgroundPixel);
-            setBufferedImage(new BufferedImage(icm2, raster, bufferedImage.isAlphaPremultiplied(), null));
-        }
-        return;
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/WMSAdjustAction.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/WMSAdjustAction.java	(revision 33637)
+++ 	(revision )
@@ -1,197 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.Color;
-import java.awt.Cursor;
-import java.awt.Graphics2D;
-import java.awt.Toolkit;
-import java.awt.event.ActionEvent;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.event.MouseMotionListener;
-
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.mapmode.MapMode;
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.tools.ImageProvider;
-
-public class WMSAdjustAction extends MapMode implements
-        MouseListener, MouseMotionListener {
-
-    private static final long serialVersionUID = 1L;
-    private WMSLayer modifiedLayer = null;
-    private boolean rasterMoved;
-    private EastNorth prevEastNorth;
-    enum Mode { moveXY, moveZ, rotate }
-
-    private static Mode mode = null;
-    private static EastNorth[] croppedRaster = new EastNorth[5];;
-
-    /**
-     * Constructs a new {@code WMSAdjustAction} map mode.
-     */
-    public WMSAdjustAction() {
-        super(tr("Adjust WMS"), "adjustxywms",
-                        tr("Adjust the position of the WMS layer (saved for raster images only)"),
-                        ImageProvider.getCursor("normal", "move"));
-    }
-
-    @Override public void enterMode() {
-        if (Main.map != null) {
-            if (Main.getLayerManager().getActiveLayer() instanceof WMSLayer) {
-                modifiedLayer = (WMSLayer) Main.getLayerManager().getActiveLayer();
-                super.enterMode();
-                Main.map.mapView.addMouseListener(this);
-                Main.map.mapView.addMouseMotionListener(this);
-                rasterMoved = false;
-                modifiedLayer.adjustModeEnabled = true;
-            } else {
-                // This mode works only if active layer is a cadastre layer
-                if (Boolean.TRUE.equals(getValue("active"))) {
-                    exitMode();
-                }
-                Main.map.selectMapMode((MapMode) Main.map.getDefaultButtonAction());
-            }
-        }
-    }
-
-    @Override public void exitMode() {
-        super.exitMode();
-        Main.map.mapView.removeMouseListener(this);
-        Main.map.mapView.removeMouseMotionListener(this);
-        if (rasterMoved && CacheControl.cacheEnabled && modifiedLayer.isRaster()) {
-            int reply = JOptionPane.showConfirmDialog(null,
-                    "Save the changes in cache ?",
-                    "Update cache",
-                    JOptionPane.YES_NO_OPTION);
-            if (reply == JOptionPane.OK_OPTION) {
-                saveModifiedLayers();
-            }
-        }
-        rasterMoved = false;
-        if (modifiedLayer != null) {
-            modifiedLayer.adjustModeEnabled = false;
-            modifiedLayer = null;
-        }
-    }
-
-    @Override
-    public void mousePressed(MouseEvent e) {
-        if (e.getButton() != MouseEvent.BUTTON1)
-            return;
-        requestFocusInMapView();
-        boolean ctrl = (e.getModifiers() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) != 0;
-        // boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
-        boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
-        if (shift && !ctrl && modifiedLayer.isRaster())
-            mode = Mode.moveZ;
-        else if (shift && ctrl && modifiedLayer.isRaster())
-            mode = Mode.rotate;
-        else
-            mode = Mode.moveXY;
-        rasterMoved = true;
-        prevEastNorth = Main.map.mapView.getEastNorth(e.getX(), e.getY());
-        Main.map.mapView.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
-    }
-
-    @Override public void mouseDragged(MouseEvent e) {
-        EastNorth newEastNorth = Main.map.mapView.getEastNorth(e.getX(), e.getY());
-        if (mode == Mode.rotate) {
-            rotateFrameOnly(prevEastNorth, newEastNorth);
-        } else {
-            if (mode == Mode.moveXY) {
-                displace(prevEastNorth, newEastNorth);
-            } else if (mode == Mode.moveZ) {
-                resize(newEastNorth);
-            }
-            prevEastNorth = newEastNorth;
-        }
-        if (modifiedLayer != null) {
-            modifiedLayer.invalidate();
-        }
-    }
-
-    public static void paintAdjustFrames(Graphics2D g, final MapView mv) {
-        if (mode == Mode.rotate && croppedRaster != null) {
-            g.setColor(Color.red);
-            for (int i = 0; i < 4; i++) {
-                g.drawLine(mv.getPoint(croppedRaster[i]).x,
-                        mv.getPoint(croppedRaster[i]).y,
-                        mv.getPoint(croppedRaster[i+1]).x,
-                        mv.getPoint(croppedRaster[i+1]).y);
-            }
-        }
-    }
-
-    private void displace(EastNorth start, EastNorth end) {
-        modifiedLayer.displace(end.east()-start.east(), end.north()-start.north());
-    }
-
-    private void resize(EastNorth newEastNorth) {
-        EastNorth center = modifiedLayer.getRasterCenter();
-        double dPrev = prevEastNorth.distance(center.east(), center.north());
-        double dNew = newEastNorth.distance(center.east(), center.north());
-        modifiedLayer.resize(center, dNew/dPrev);
-    }
-
-    private void rotate(EastNorth start, EastNorth end) {
-        EastNorth pivot = modifiedLayer.getRasterCenter();
-        double startAngle = Math.atan2(start.east()-pivot.east(), start.north()-pivot.north());
-        double endAngle = Math.atan2(end.east()-pivot.east(), end.north()-pivot.north());
-        double rotationAngle = endAngle - startAngle;
-        modifiedLayer.rotate(pivot, rotationAngle);
-    }
-
-    private void rotateFrameOnly(EastNorth start, EastNorth end) {
-        if (start != null && end != null) {
-            EastNorth pivot = modifiedLayer.getRasterCenter();
-            double startAngle = Math.atan2(start.east()-pivot.east(), start.north()-pivot.north());
-            double endAngle = Math.atan2(end.east()-pivot.east(), end.north()-pivot.north());
-            double rotationAngle = endAngle - startAngle;
-            if (modifiedLayer.getImage(0).orgCroppedRaster != null) {
-                for (int i = 0; i < 4; i++) {
-                    croppedRaster[i] = modifiedLayer.getImage(0).orgCroppedRaster[i].rotate(pivot, rotationAngle);
-                }
-                croppedRaster[4] = croppedRaster[0];
-            }
-        }
-    }
-
-    @Override
-    public void mouseReleased(MouseEvent e) {
-        if (mode == Mode.rotate) {
-            EastNorth newEastNorth = Main.map.mapView.getEastNorth(e.getX(), e.getY());
-            rotate(prevEastNorth, newEastNorth);
-            if (modifiedLayer != null) {
-                modifiedLayer.invalidate();
-            }
-        }
-        Main.map.mapView.setCursor(Cursor.getDefaultCursor());
-        prevEastNorth = null;
-        mode = 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) {
-    }
-
-    private void saveModifiedLayers() {
-        modifiedLayer.grabThread.saveNewCache();
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/WMSDownloadAction.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/WMSDownloadAction.java	(revision 33637)
+++ 	(revision )
@@ -1,52 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-//import java.awt.event.ActionEvent;
-import java.util.ArrayList;
-
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-//import org.openstreetmap.josm.actions.JosmAction;
-import org.openstreetmap.josm.gui.layer.Layer;
-
-public class WMSDownloadAction /*extends JosmAction */ {
-
-//    public WMSDownloadAction(String layerName) {
-//        super(layerName, "wmsmenu", tr("Download WMS tile from {0}",layerName), null, false);
-//    }
-//
-//    public void actionPerformed(ActionEvent e) {
-//        DownloadWMSVectorImage.download(getLayer());
-//    }
-
-    public static WMSLayer getLayer() {
-        // check if we already have a layer created. if not, create; if yes, reuse.
-        ArrayList<WMSLayer> existingWMSlayers = new ArrayList<>();
-        if (Main.map != null) {
-            Layer activeLayer = Main.getLayerManager().getActiveLayer();
-            if (activeLayer instanceof WMSLayer)
-                return (WMSLayer) activeLayer;
-            for (Layer l : Main.getLayerManager().getLayers()) {
-                if (l instanceof WMSLayer) {
-                    existingWMSlayers.add((WMSLayer) l);
-                }
-            }
-            if (existingWMSlayers.size() == 1)
-                return existingWMSlayers.get(0);
-            if (existingWMSlayers.size() == 0)
-                return new MenuActionNewLocation().addNewLayer(existingWMSlayers);
-            if (Main.pref.getBoolean("cadastrewms.autoFirstLayer", false)) {
-                return existingWMSlayers.get(0);
-            } else {
-                JOptionPane.showMessageDialog(Main.parent,
-                        tr("More than one WMS layer present\nSelect one of them first, then retry"));
-            }
-        } else {
-            return new MenuActionNewLocation().addNewLayer(existingWMSlayers);
-        }
-        return null;
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/WMSException.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/WMSException.java	(revision 33637)
+++ 	(revision )
@@ -1,17 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-class WMSException extends Exception {
-    private String message;
-    private static final long serialVersionUID = 1L;
-
-    WMSException(String message) {
-        super();
-        this.message = message;
-    }
-
-    @Override
-    public String getMessage() {
-        return message;
-    }
-}
Index: plications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/WMSLayer.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/WMSLayer.java	(revision 33637)
+++ 	(revision )
@@ -1,729 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.plugins.fr.cadastre;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Image;
-import java.awt.Point;
-import java.awt.RenderingHints;
-import java.awt.Toolkit;
-import java.awt.event.ActionEvent;
-import java.awt.image.BufferedImage;
-import java.awt.image.ImageObserver;
-import java.io.EOFException;
-import java.io.File;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Vector;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import javax.swing.Action;
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.JosmAction;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
-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.gui.util.GuiHelper;
-
-/**
- * This is a layer that grabs the current screen from the French cadastre WMS
- * server. The data fetched this way is tiled and managed to the disc to reduce
- * server load.
- */
-public class WMSLayer extends Layer implements ImageObserver {
-
-    private int lambertZone = -1;
-
-    public CadastreGrabber grabber = new CadastreGrabber();
-
-    protected static final Icon icon = new ImageIcon(Toolkit.getDefaultToolkit().createImage(
-            CadastrePlugin.class.getResource("/images/cadastre_small.png")));
-
-    private Vector<GeorefImage> images = new Vector<>();
-
-    public Lock imagesLock = new ReentrantLock();
-
-    /**
-     * v1 to v2 = not supported
-     * v2 to v3 = add 4 more EastNorth coordinates in GeorefImages
-     * v3 to v4 = add original raster image width and height
-     */
-    protected final int serializeFormatVersion = 4;
-
-    public static int currentFormat;
-
-    private ArrayList<EastNorthBound> dividedBbox = new ArrayList<>();
-
-    private String location = "";
-
-    private String departement = "";
-
-    private String codeCommune = "";
-
-    public EastNorthBound communeBBox = new EastNorthBound(new EastNorth(0, 0), new EastNorth(0, 0));
-
-    private boolean isRaster;
-    private boolean isAlreadyGeoreferenced;
-    public double X0, Y0, angle, fX, fY;
-
-    // bbox of the georeferenced raster image (the nice horizontal and vertical box)
-    private EastNorth rasterMin;
-    private EastNorth rasterMax;
-    private double rasterRatio;
-
-    // offset for vector images temporarily shifted (correcting Cadastre artifacts), in pixels
-    public double deltaEast;
-    public double deltaNorth;
-
-    private Action saveAsPng;
-
-    private Action cancelGrab;
-
-    private Action refineGeoRef;
-
-    class ResetOffsetActionMenu extends JosmAction {
-        ResetOffsetActionMenu() {
-            super(tr("Reset offset"), null, tr("Reset offset (only vector images)"), null, false);
-        }
-
-        @Override
-        public void actionPerformed(ActionEvent arg0) {
-            deltaEast = 0;
-            deltaNorth = 0;
-            invalidate();
-        }
-    }
-
-    public boolean adjustModeEnabled;
-
-    public GrabThread grabThread;
-
-    /**
-     * Constructs a new {@code WMSLayer}.
-     */
-    public WMSLayer() {
-        this(tr("Blank Layer"), "", -1);
-    }
-
-    public WMSLayer(String location, String codeCommune, int lambertZone) {
-        super(buildName(location, codeCommune));
-        this.location = location;
-        this.codeCommune = codeCommune;
-        this.lambertZone = lambertZone;
-        grabThread = new GrabThread(this);
-        grabThread.start();
-        // enable auto-sourcing option
-        CadastrePlugin.pluginUsed = true;
-    }
-
-    @Override
-    public void destroy() {
-        // if the layer is currently saving the images in the cache, wait until it's finished
-        if (grabThread != null)
-                grabThread.cancel();
-        grabThread = null;
-        super.destroy();
-        images = null;
-        dividedBbox = null;
-        Main.info("Layer "+location+" destroyed");
-    }
-
-    private static String buildName(String location, String codeCommune) {
-        String ret = location.toUpperCase(Locale.FRANCE);
-        if (codeCommune != null && !codeCommune.isEmpty())
-            ret += "(" + codeCommune + ")";
-        return ret;
-    }
-
-    private String rebuildName() {
-        return buildName(this.location.toUpperCase(Locale.FRANCE), this.codeCommune);
-    }
-
-    public void grab(Bounds b) throws IOException {
-        grabThread.setCanceled(false);
-        grabThread.setGrabber(grabber);
-        // if it is the first layer, use the communeBBox as grab bbox (and not divided)
-        if (Main.getLayerManager().getLayers().size() == 1) {
-            final Bounds bounds = this.getCommuneBBox().toBounds();
-            GuiHelper.runInEDTAndWait(new Runnable() {
-                @Override
-                public void run() {
-                    Main.map.mapView.zoomTo(bounds);
-                }
-            });
-            divideBbox(bounds, 1);
-        } else {
-            if (isRaster) {
-                divideBbox(new Bounds(Main.getProjection().eastNorth2latlon(rasterMin), Main.getProjection().eastNorth2latlon(rasterMax)),
-                        Integer.parseInt(Main.pref.get("cadastrewms.rasterDivider", CadastrePreferenceSetting.DEFAULT_RASTER_DIVIDER)));
-            } else
-                divideBbox(b,
-                        Integer.parseInt(Main.pref.get("cadastrewms.scale", CadastrePreferenceSetting.DEFAULT_GRAB_MULTIPLIER)));
-        }
-        grabThread.addImages(dividedBbox);
-    }
-
-    /**
-     * Divides the bounding box in smaller squares. Their size (and quantity) is configurable in Preferences.
-     *
-     * @param b      the original bbox, usually the current bbox on screen
-     * @param factor 1 = source bbox 1:1
-     *               2 = source bbox divided by 2x2 smaller boxes
-     *               3 = source bbox divided by 3x3 smaller boxes
-     *               4 = configurable size from preferences (100 meters per default) rounded
-     *                   allowing grabbing of next contiguous zone
-     */
-    private void divideBbox(Bounds b, int factor) {
-        EastNorth lambertMin = Main.getProjection().latlon2eastNorth(b.getMin());
-        EastNorth lambertMax = Main.getProjection().latlon2eastNorth(b.getMax());
-        double minEast = lambertMin.east()+deltaEast;
-        double minNorth = lambertMin.north()+deltaNorth;
-        double dEast = (lambertMax.east() - minEast) / factor;
-        double dNorth = (lambertMax.north() - minNorth) / factor;
-        dividedBbox.clear();
-        if (factor < 4 || isRaster) {
-            for (int xEast = 0; xEast < factor; xEast++) {
-                for (int xNorth = 0; xNorth < factor; xNorth++) {
-                    dividedBbox.add(new EastNorthBound(new EastNorth(minEast + xEast * dEast, minNorth + xNorth * dNorth),
-                                new EastNorth(minEast + (xEast + 1) * dEast, minNorth + (xNorth + 1) * dNorth)));
-                }
-            }
-        } else {
-            // divide to fixed size squares
-            // grab all square in a spiral starting from the center (usually the most interesting place)
-            int c = Integer.parseInt(Main.pref.get("cadastrewms.squareSize", String.valueOf(CadastrePreferenceSetting.DEFAULT_SQUARE_SIZE)));
-            lambertMin = lambertMin.add(-minEast % c, -minNorth % c);
-            lambertMax = lambertMax.add(c - lambertMax.east() % c, c - lambertMax.north() % c);
-            EastNorth mid = lambertMax.getCenter(lambertMin);
-            mid = mid.add(-1, 1); // in case the boxes side is a pair, select the one one top,left to follow the rotation
-            mid = mid.add(-mid.east() % c, -mid.north() % c);
-            int x = (int) (lambertMax.east() -lambertMin.east())/c;
-            int y = (int) (lambertMax.north() -lambertMin.north())/c;
-            int[] dx = {+1, 0, -1, 0};
-            int[] dy = {0, -1, 0, +1};
-            int currDir = -1, lDir = 1, i = 1, j = 0, k = -1;
-            if (x == 1)
-                currDir = 0;
-            dividedBbox.add(new EastNorthBound(mid, new EastNorth(mid.east()+c, mid.north()+c)));
-            while (i < (x*y)) {
-                i++;
-                j++;
-                if (j >= lDir) {
-                    k++;
-                    if (k > 1) {
-                        lDir++;
-                        k = 0;
-                    }
-                    j = 0;
-                    currDir = (currDir+1) % 4;
-                } else if (currDir >= 0 && j >= (currDir == 0 || currDir == 2 ? (x-1) : (y-1))) {
-                    // the overall is a rectangle, not a square. Jump to the other side to grab next square.
-                    k++;
-                    if (k > 1) {
-                        lDir++;
-                        k = 0;
-                    }
-                    j = lDir-1;
-                    currDir = (currDir+1) % 4;
-                    mid = new EastNorth(mid.east() + dx[currDir]*c*(lDir-1), mid.north() + dy[currDir]*c*(lDir-1));
-                }
-                mid = new EastNorth(mid.east() + dx[currDir]*c, mid.north() + dy[currDir]*c);
-                dividedBbox.add(new EastNorthBound(mid, new EastNorth(mid.east()+c, mid.north()+c)));
-            }
-        }
-    }
-
-    @Override
-    public Icon getIcon() {
-        return icon;
-    }
-
-    @Override
-    public String getToolTipText() {
-        String str = tr("WMS layer ({0}), {1} tile(s) loaded", getName(), images.size());
-        if (isRaster) {
-            str += "\n"+tr("Is not vectorized.");
-            str += "\n"+tr("Bounding box: {0}", communeBBox);
-            if (!images.isEmpty())
-                str += "\n"+tr("Image size (px): {0}/{1}", images.get(0).image.getWidth(), images.get(0).image.getHeight());
-        } else {
-            str += "\n"+tr("Is vectorized.");
-            str += "\n"+tr("Commune bbox: {0}", communeBBox);
-        }
-        return str;
-    }
-
-    @Override
-    public boolean isMergable(Layer other) {
-        return false;
-    }
-
-    @Override
-    public void mergeFrom(Layer from) {
-        // Do nothing
-    }
-
-    @Override
-    public void paint(Graphics2D g, final MapView mv, Bounds bounds) {
-        synchronized (this) {
-            Object savedInterpolation = g.getRenderingHint(RenderingHints.KEY_INTERPOLATION);
-            if (savedInterpolation == null) savedInterpolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
-            String interpolation = Main.pref.get("cadastrewms.imageInterpolation", "standard");
-            if (interpolation.equals("bilinear"))
-                g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
-            else if (interpolation.equals("bicubic"))
-                g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
-            else
-                g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
-            imagesLock.lock();
-            for (GeorefImage img : images) {
-                img.paint(g, mv, CadastrePlugin.backgroundTransparent,
-                        CadastrePlugin.transparency, CadastrePlugin.drawBoundaries);
-            }
-            imagesLock.unlock();
-            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, savedInterpolation);
-        }
-        if (this.isRaster) {
-            paintCrosspieces(g, mv);
-        }
-        grabThread.paintBoxesToGrab(g, mv);
-        if (this.adjustModeEnabled) {
-            WMSAdjustAction.paintAdjustFrames(g, mv);
-        }
-    }
-
-    @Override
-    public void visitBoundingBox(BoundingXYVisitor v) {
-        for (GeorefImage img : images) {
-            v.visit(img.min);
-            v.visit(img.max);
-        }
-    }
-
-    @Override
-    public Object getInfoComponent() {
-        return getToolTipText();
-    }
-
-    @Override
-    public Action[] getMenuEntries() {
-        saveAsPng = new MenuActionSaveRasterAs(this);
-        saveAsPng.setEnabled(isRaster);
-        cancelGrab = new MenuActionCancelGrab(this);
-        cancelGrab.setEnabled(!isRaster && grabThread.getImagesToGrabSize() > 0);
-        refineGeoRef = new MenuActionRefineGeoRef(this);
-        refineGeoRef.setEnabled(isRaster && grabThread.getImagesToGrabSize() == 0);
-        Action resetOffset = new ResetOffsetActionMenu();
-        resetOffset.setEnabled(!isRaster && !images.isEmpty() && (deltaEast != 0.0 || deltaNorth != 0.0));
-        return new Action[] {
-                LayerListDialog.getInstance().createShowHideLayerAction(),
-                LayerListDialog.getInstance().createDeleteLayerAction(),
-                new MenuActionLoadFromCache(),
-                saveAsPng,
-                cancelGrab,
-                refineGeoRef,
-                resetOffset,
-                new LayerListPopup.InfoAction(this),
-        };
-    }
-
-    public GeorefImage findImage(EastNorth eastNorth) {
-        // Iterate in reverse, so we return the image which is painted last.
-        // (i.e. the topmost one)
-        for (int i = images.size() - 1; i >= 0; i--) {
-            if (images.get(i).contains(eastNorth)) {
-                return images.get(i);
-            }
-        }
-        return null;
-    }
-
-    public boolean isOverlapping(Bounds bounds) {
-        GeorefImage georefImage =
-            new GeorefImage(null,
-            Main.getProjection().latlon2eastNorth(bounds.getMin()),
-            Main.getProjection().latlon2eastNorth(bounds.getMax()), this);
-        for (GeorefImage img : images) {
-            if (img.overlap(georefImage))
-                return true;
-        }
-        return false;
-    }
-
-    /**
-     * Convert the eastNorth input coordinates to raster coordinates.
-     * The original raster size is [0,0,12286,8730] where 0,0 is the upper left corner and
-     * 12286,8730 is the approx. raster max size.
-     * @return the raster coordinates for the wms server request URL (minX,minY,maxX,maxY)
-     */
-    public String eastNorth2raster(EastNorth min, EastNorth max) {
-        double minX = (min.east() - rasterMin.east()) / rasterRatio;
-        double minY = (min.north() - rasterMin.north()) / rasterRatio;
-        double maxX = (max.east() - rasterMin.east()) / rasterRatio;
-        double maxY = (max.north() - rasterMin.north()) / rasterRatio;
-        return minX+","+minY+","+maxX+","+maxY;
-    }
-
-    public String getLocation() {
-        return location;
-    }
-
-    public void setLocation(String location) {
-        this.location = location;
-        setName(rebuildName());
-    }
-
-    public String getDepartement() {
-        return departement;
-    }
-
-    public void setDepartement(String departement) {
-        this.departement = departement;
-    }
-
-    public String getCodeCommune() {
-        return codeCommune;
-    }
-
-    public void setCodeCommune(String codeCommune) {
-        this.codeCommune = codeCommune;
-        setName(rebuildName());
-    }
-
-    public boolean isRaster() {
-        return isRaster;
-    }
-
-    public void setRaster(boolean isRaster) {
-        this.isRaster = isRaster;
-        if (saveAsPng != null)
-            saveAsPng.setEnabled(isRaster);
-    }
-
-    public boolean isAlreadyGeoreferenced() {
-        return isAlreadyGeoreferenced;
-    }
-
-    public void setAlreadyGeoreferenced(boolean isAlreadyGeoreferenced) {
-        this.isAlreadyGeoreferenced = isAlreadyGeoreferenced;
-    }
-
-    /**
-     * Set raster positions used for grabbing and georeferencing.
-     * rasterMin is the Eaast North of bottom left corner raster image on the screen when image is grabbed.
-     * The bounds width and height are the raster width and height. The image width matches the current view
-     * and the image height is adapted.
-     * Required: the communeBBox must be set (normally it is catched by CadastreInterface and saved by DownloadWMSPlanImage)
-     * @param bounds the current main map view boundaries
-     */
-    public void setRasterBounds(Bounds bounds) {
-        EastNorth rasterCenter = Main.getProjection().latlon2eastNorth(bounds.getCenter());
-        EastNorth eaMin = Main.getProjection().latlon2eastNorth(bounds.getMin());
-        EastNorth eaMax = Main.getProjection().latlon2eastNorth(bounds.getMax());
-        double rasterSizeX = communeBBox.max.getX() - communeBBox.min.getX();
-        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);
-        rasterRatio = (rasterMax.getX()-rasterMin.getX())/rasterSizeX;
-    }
-
-    /**
-     * Called by CacheControl when a new cache file is created on disk.
-     * Save only primitives to keep cache independent of software changes.
-     */
-    public void write(File associatedFile, ObjectOutputStream oos) throws IOException {
-        currentFormat = this.serializeFormatVersion;
-        setAssociatedFile(associatedFile);
-        oos.writeInt(this.serializeFormatVersion);
-        oos.writeObject(this.location);    // String
-        oos.writeObject(this.codeCommune); // String
-        oos.writeInt(this.lambertZone);
-        oos.writeBoolean(this.isRaster);
-        oos.writeBoolean(false); // previously buildingsOnly
-        if (this.isRaster) {
-            oos.writeDouble(this.rasterMin.getX());
-            oos.writeDouble(this.rasterMin.getY());
-            oos.writeDouble(this.rasterMax.getX());
-            oos.writeDouble(this.rasterMax.getY());
-            oos.writeDouble(this.rasterRatio);
-        }
-        oos.writeDouble(this.communeBBox.min.getX());
-        oos.writeDouble(this.communeBBox.min.getY());
-        oos.writeDouble(this.communeBBox.max.getX());
-        oos.writeDouble(this.communeBBox.max.getY());
-    }
-
-    /**
-     * Called by CacheControl when a cache file is read from disk.
-     * Cache uses only primitives to stay independent of software changes.
-     */
-    public boolean read(File associatedFile, ObjectInputStream ois, int currentLambertZone) throws IOException, ClassNotFoundException {
-        currentFormat = ois.readInt();;
-        if (currentFormat < 2) {
-            JOptionPane.showMessageDialog(Main.parent, tr("Unsupported cache file version; found {0}, expected {1}\nCreate a new one.",
-                    currentFormat, this.serializeFormatVersion), tr("Cache Format Error"), JOptionPane.ERROR_MESSAGE);
-            return false;
-        }
-        this.setLocation((String) ois.readObject());
-        this.setCodeCommune((String) ois.readObject());
-        this.lambertZone = ois.readInt();
-        this.setRaster(ois.readBoolean());
-        setAssociatedFile(associatedFile);
-        if (currentFormat >= 4)
-            ois.readBoolean();
-        if (this.isRaster) {
-            double X = ois.readDouble();
-            double Y = ois.readDouble();
-            this.rasterMin = new EastNorth(X, Y);
-            X = ois.readDouble();
-            Y = ois.readDouble();
-            this.rasterMax = new EastNorth(X, Y);
-            this.rasterRatio = ois.readDouble();
-        }
-        double minX = ois.readDouble();
-        double minY = ois.readDouble();
-        double maxX = ois.readDouble();
-        double maxY = ois.readDouble();
-        this.communeBBox = new EastNorthBound(new EastNorth(minX, minY), new EastNorth(maxX, maxY));
-        if (this.lambertZone != currentLambertZone && currentLambertZone != -1) {
-            JOptionPane.showMessageDialog(Main.parent, tr("Lambert zone {0} in cache "+
-                    "incompatible with current Lambert zone {1}",
-                    this.lambertZone+1, currentLambertZone), tr("Cache Lambert Zone Error"), JOptionPane.ERROR_MESSAGE);
-            return false;
-        }
-        synchronized (this) {
-            boolean EOF = false;
-            try {
-                while (!EOF) {
-                    GeorefImage newImage = (GeorefImage) ois.readObject();
-                    for (GeorefImage img : this.images) {
-                        if (CadastrePlugin.backgroundTransparent) {
-                            if (img.overlap(newImage))
-                                // mask overlapping zone in already grabbed image
-                                img.withdraw(newImage);
-                            else
-                                // mask overlapping zone in new image only when
-                                // new image covers completely the existing image
-                                newImage.withdraw(img);
-                        }
-                    }
-                    newImage.wmsLayer = this;
-                    this.images.add(newImage);
-                }
-            } catch (EOFException ex) {
-                // expected exception when all images are read
-                Main.trace(ex);
-            }
-        }
-        Main.info("Cache loaded for location "+location+" with "+images.size()+" images");
-        return true;
-    }
-
-    /**
-     * Join the grabbed images into one single.
-     */
-    public void joinBufferedImages() {
-        if (images.size() > 1) {
-            EastNorth min = images.get(0).min;
-            EastNorth max = images.get(images.size()-1).max;
-            int oldImgWidth = images.get(0).image.getWidth();
-            int oldImgHeight = images.get(0).image.getHeight();
-            HashSet<Double> lx = new HashSet<>();
-            HashSet<Double> ly = new HashSet<>();
-            for (GeorefImage img : images) {
-                lx.add(img.min.east());
-                ly.add(img.min.north());
-            }
-            int newWidth = oldImgWidth*lx.size();
-            int newHeight = oldImgHeight*ly.size();
-            BufferedImage newImg = new BufferedImage(newWidth, newHeight, images.get(0).image.getType()/*BufferedImage.TYPE_INT_ARGB*/);
-            Graphics g = newImg.getGraphics();
-            // Coordinate (0,0) is on top,left corner where images are grabbed from bottom left
-            int rasterDivider = (int) Math.sqrt(images.size());
-            for (int h = 0; h < lx.size(); h++) {
-                for (int v = 0; v < ly.size(); v++) {
-                    int newx = h*oldImgWidth;
-                    int newy = newHeight - oldImgHeight - (v*oldImgHeight);
-                    int j = h*rasterDivider + v;
-                    g.drawImage(images.get(j).image, newx, newy, this);
-                }
-            }
-            synchronized (this) {
-                images.clear();
-                images.add(new GeorefImage(newImg, min, max, this));
-            }
-        }
-    }
-
-    /**
-     * Image cropping based on two EN coordinates pointing to two corners in diagonal
-     * Because it's coming from user mouse clics, we have to sort de positions first.
-     * Works only for raster image layer (only one image in collection).
-     * Updates layer georeferences.
-     */
-    public void cropImage(EastNorth en1, EastNorth en2) {
-        // adj1 is corner bottom, left
-        EastNorth adj1 = new EastNorth(en1.east() <= en2.east() ? en1.east() : en2.east(),
-                en1.north() <= en2.north() ? en1.north() : en2.north());
-        // adj2 is corner top, right
-        EastNorth adj2 = new EastNorth(en1.east() > en2.east() ? en1.east() : en2.east(),
-                en1.north() > en2.north() ? en1.north() : en2.north());
-        images.get(0).crop(adj1, adj2);
-        // update the layer georefs
-        rasterMin = adj1;
-        rasterMax = adj2;
-        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;
-    }
-
-    public EastNorthBound getFirstViewFromCacheBBox() {
-        if (isRaster) {
-            return communeBBox;
-        }
-        double minX = Double.MAX_VALUE;
-        double maxX = Double.MIN_VALUE;
-        double minY = Double.MAX_VALUE;
-        double maxY = Double.MIN_VALUE;
-        for (GeorefImage image:images) {
-            minX = image.min.east() < minX ? image.min.east() : minX;
-            maxX = image.max.east() > maxX ? image.max.east() : maxX;
-            minY = image.min.north() < minY ? image.min.north() : minY;
-            maxY = image.max.north() > maxY ? image.max.north() : maxY;
-        }
-        return new EastNorthBound(new EastNorth(minX, minY), new EastNorth(maxX, maxY));
-    }
-
-    public void setCommuneBBox(EastNorthBound entireCommune) {
-        this.communeBBox = entireCommune;
-    }
-
-    /**
-     * Method required by ImageObserver when drawing an image
-     */
-    @Override
-    public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
-        return false;
-    }
-
-    public int getLambertZone() {
-        return lambertZone;
-    }
-
-    public EastNorth getRasterCenter() {
-        return new EastNorth((images.get(0).max.east()+images.get(0).min.east())/2,
-                (images.get(0).max.north()+images.get(0).min.north())/2);
-    }
-
-    public void displace(double dx, double dy) {
-        if (isRaster) {
-            this.rasterMin = new EastNorth(rasterMin.east() + dx, rasterMin.north() + dy);
-            this.rasterMax = new EastNorth(rasterMax.east() + dx, rasterMax.north() + dy);
-            images.get(0).shear(dx, dy);
-        } else {
-            deltaEast += dx;
-            deltaNorth += dy;
-        }
-    }
-
-    public void resize(EastNorth rasterCenter, double proportion) {
-        this.rasterMin = rasterMin.interpolate(rasterCenter, proportion);
-        this.rasterMax = rasterMax.interpolate(rasterCenter, proportion);
-        images.get(0).scale(rasterCenter, proportion);
-    }
-
-    public void rotate(EastNorth rasterCenter, double angle) {
-        this.rasterMin = rasterMin.rotate(rasterCenter, angle);
-        this.rasterMax = rasterMax.rotate(rasterCenter, angle);
-        images.get(0).rotate(rasterCenter, angle);
-        this.angle += angle;
-    }
-
-    private void paintCrosspieces(Graphics g, MapView mv) {
-        String crosspieces = Main.pref.get("cadastrewms.crosspieces", "0");
-        if (!crosspieces.equals("0")) {
-            int modulo = 25;
-            if (crosspieces.equals("2")) modulo = 50;
-            if (crosspieces.equals("3")) modulo = 100;
-            EastNorthBound currentView = new EastNorthBound(mv.getEastNorth(0, mv.getHeight()),
-                    mv.getEastNorth(mv.getWidth(), 0));
-            int minX = ((int) currentView.min.east()/modulo+1)*modulo;
-            int minY = ((int) currentView.min.north()/modulo+1)*modulo;
-            int maxX = ((int) currentView.max.east()/modulo)*modulo;
-            int maxY = ((int) currentView.max.north()/modulo)*modulo;
-            int size = (maxX-minX)/modulo;
-            if (size < 20) {
-                int px = size > 10 ? 2 : Math.abs(12-size);
-                g.setColor(Color.green);
-                for (int x = minX; x <= maxX; x += modulo) {
-                    for (int y = minY; y <= maxY; y += modulo) {
-                        Point p = mv.getPoint(new EastNorth(x, y));
-                        g.drawLine(p.x-px, p.y, p.x+px, p.y);
-                        g.drawLine(p.x, p.y-px, p.x, p.y+px);
-                    }
-                }
-            }
-        }
-    }
-
-    public GeorefImage getImage(int index) {
-        imagesLock.lock();
-        GeorefImage img = null;
-        try {
-            img = this.images.get(index);
-        } catch (ArrayIndexOutOfBoundsException e) {
-            Main.error(e);
-        }
-        imagesLock.unlock();
-        return img;
-    }
-
-    public Vector<GeorefImage> getImages() {
-        return this.images;
-    }
-
-    public boolean hasImages() {
-        return images != null && !images.isEmpty();
-    }
-
-    public void addImage(GeorefImage img) {
-        imagesLock.lock();
-        this.images.add(img);
-        imagesLock.unlock();
-    }
-
-    public void setImages(Vector<GeorefImage> images) {
-        imagesLock.lock();
-        this.images = images;
-        imagesLock.unlock();
-    }
-
-    public void clearImages() {
-        imagesLock.lock();
-        this.images.clear();
-        imagesLock.unlock();
-    }
-}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionBoundaries.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionBoundaries.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionBoundaries.java	(revision 33638)
@@ -0,0 +1,42 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.DownloadSVGTask;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+
+public class MenuActionBoundaries extends JosmAction {
+
+    public static final String NAME = "Administrative boundary";
+
+    private static final long serialVersionUID = 1L;
+    private WMSLayer wmsLayer = null;
+
+    /**
+     * Constructs a new {@code MenuActionBoundaries}.
+     */
+    public MenuActionBoundaries() {
+        super(tr(NAME), "cadastre_small", tr("Extract commune boundary"), null, false);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent arg0) {
+        wmsLayer = WMSDownloadAction.getLayer();
+        if (wmsLayer != null) {
+            if (wmsLayer.isRaster()) {
+                JOptionPane.showMessageDialog(Main.parent,
+                        tr("Only on vectorized layers"), tr("Error"),
+                        JOptionPane.ERROR_MESSAGE);
+                return;
+            }
+            DownloadSVGTask.download(wmsLayer);
+        }
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionCancelGrab.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionCancelGrab.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionCancelGrab.java	(revision 33638)
@@ -0,0 +1,34 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+
+@SuppressWarnings("serial")
+public class MenuActionCancelGrab extends JosmAction {
+
+    public static final String NAME = marktr("Cancel current grab");
+
+    private WMSLayer wmsLayer;
+
+    /**
+     * Constructs a new {@code MenuActionCancelGrab}.
+     * @param wmsLayer WMS layer
+     */
+    public MenuActionCancelGrab(WMSLayer wmsLayer) {
+        super(tr(NAME), null, tr("Cancel current grab (only vector images)"), null, false);
+        this.wmsLayer = wmsLayer;
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent arg0) {
+        if (wmsLayer.grabThread.getImagesToGrabSize() > 0) {
+            wmsLayer.grabThread.cancel();
+        }
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionGrab.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionGrab.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionGrab.java	(revision 33638)
@@ -0,0 +1,46 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.DownloadWMSVectorImage;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * Action calling the wms grabber for cadastre.gouv.fr
+ */
+public class MenuActionGrab extends JosmAction {
+
+    public static final String NAME = marktr("Cadastre grab");
+
+    /**
+     * Constructs a new {@code MenuActionGrab}.
+     */
+    public MenuActionGrab() {
+        super(tr(NAME), "cadastre_small", tr("Download Image from French Cadastre WMS"),
+                Shortcut.registerShortcut("cadastre:grab", tr("Cadastre: {0}", tr("Download Image from French Cadastre WMS")),
+                KeyEvent.VK_F10, Shortcut.DIRECT), false, "cadastrefr/grab", true);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        if (Main.map != null) {
+            if (CadastrePlugin.isCadastreProjection()) {
+                WMSLayer wmsLayer = WMSDownloadAction.getLayer();
+                if (wmsLayer != null)
+                    DownloadWMSVectorImage.download(wmsLayer);
+            } else {
+                CadastrePlugin.askToChangeProjection();
+            }
+        } else
+            new MenuActionNewLocation().actionPerformed(e);
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionGrabPlanImage.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionGrabPlanImage.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionGrabPlanImage.java	(revision 33638)
@@ -0,0 +1,95 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.DownloadWMSPlanImage;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.RasterImageGeoreferencer;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+
+public class MenuActionGrabPlanImage extends JosmAction implements Runnable {
+
+    /**
+     * Action calling the wms grabber for non georeferenced images called "plan image"
+     */
+    private static final long serialVersionUID = 1L;
+
+    public static final String NAME = marktr("Georeference an image");
+
+    private DownloadWMSPlanImage downloadWMSPlanImage;
+    private WMSLayer wmsLayer;
+    private RasterImageGeoreferencer rasterImageGeoreferencer;
+
+    /**
+     * Constructs a new {@code MenuActionGrabPlanImage}.
+     */
+    public MenuActionGrabPlanImage() {
+        super(tr(NAME), "cadastre_small", tr("Grab non-georeferenced image"), null, false, "cadastrefr/grabplanimage", true);
+        rasterImageGeoreferencer = new RasterImageGeoreferencer();
+    }
+
+    @Override
+    protected void updateEnabledState() {
+        if (wmsLayer == null || Main.map == null || Main.map.mapView == null) return;
+        if (!rasterImageGeoreferencer.isRunning()) return;
+        if (Main.getLayerManager().containsLayer(wmsLayer))
+            return;
+        JOptionPane.showMessageDialog(Main.parent, tr("Georeferencing interrupted"));
+        rasterImageGeoreferencer.actionInterrupted();
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent ae) {
+        if (Main.map != null) {
+            if (CadastrePlugin.isCadastreProjection()) {
+                wmsLayer = new MenuActionNewLocation().addNewLayer(new ArrayList<WMSLayer>());
+                if (wmsLayer == null) return;
+                downloadWMSPlanImage = new DownloadWMSPlanImage();
+                downloadWMSPlanImage.download(wmsLayer);
+                // download sub-images of the cadastre scan and join them into one single
+                Main.worker.execute(this);
+            } else {
+                CadastrePlugin.askToChangeProjection();
+            }
+        }
+    }
+
+    @Override
+    public void run() {
+        // wait until plan image is fully loaded and joined into one single image
+        boolean loadedFromCache = downloadWMSPlanImage.waitFinished();
+        if (loadedFromCache) {
+            Main.map.repaint();
+        } else if (wmsLayer.getImages().size() == 0) {
+            // action canceled or image loaded from cache (and already georeferenced)
+            rasterImageGeoreferencer.actionInterrupted();
+        } else {
+            int reply = JOptionPane.CANCEL_OPTION;
+            if (wmsLayer.isAlreadyGeoreferenced()) {
+                reply = JOptionPane.showConfirmDialog(null,
+                        tr("This image contains georeference data.\n"+
+                                "Do you want to use them ?"),
+                        null,
+                        JOptionPane.YES_NO_OPTION);
+            }
+            if (reply == JOptionPane.OK_OPTION) {
+                rasterImageGeoreferencer.transformGeoreferencedImg();
+            } else {
+                rasterImageGeoreferencer.addListener();
+                if (Main.pref.getBoolean("cadastrewms.noImageCropping", false) == false)
+                    rasterImageGeoreferencer.startCropping(wmsLayer);
+                else
+                    rasterImageGeoreferencer.startGeoreferencing(wmsLayer);
+            }
+        }
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionLoadFromCache.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionLoadFromCache.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionLoadFromCache.java	(revision 33638)
@@ -0,0 +1,119 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.CacheControl;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.CacheFileLambert4ZoneFilter;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.CacheFileLambert9ZoneFilter;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.CacheFileUTM20NFilter;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+
+public class MenuActionLoadFromCache extends JosmAction {
+    private static final long serialVersionUID = 1L;
+
+    public static final String name = marktr("Load layer from cache");
+
+    /**
+     * Constructs a new {@code MenuActionLoadFromCache}.
+     */
+    public MenuActionLoadFromCache() {
+        super(tr(name), "cadastre_small", tr("Load location from cache (only if cache is enabled)"), null, false, "cadastrefr/loadfromcache", true);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        JFileChooser fc = createAndOpenFileChooser();
+        if (fc == null)
+            return;
+
+        File[] files = fc.getSelectedFiles();
+        int layoutZone = CadastrePlugin.getCadastreProjectionLayoutZone();
+        nextFile:
+        for (File file : files) {
+            if (file.exists()) {
+                String filename = file.getName();
+                String ext = (filename.lastIndexOf('.') == -1) ? "" : filename.substring(filename.lastIndexOf('.')+1, filename.length());
+                if ((ext.length() == 3 && ext.substring(0, CacheControl.C_LAMBERT_CC_9Z.length()).equals(CacheControl.C_LAMBERT_CC_9Z) &&
+                    !(CadastrePlugin.isLambert_cc9()))
+                    || (ext.length() == 4 && ext.substring(0, CacheControl.C_UTM20N.length()).equals(CacheControl.C_UTM20N) &&
+                            !(CadastrePlugin.isUtm_france_dom()))
+                    || (ext.length() == 1) && !(CadastrePlugin.isLambert())) {
+                        JOptionPane.showMessageDialog(Main.parent, tr("{0} not allowed with the current projection", filename),
+                                tr("Error"), JOptionPane.ERROR_MESSAGE);
+                        continue;
+                } else {
+                    String location = filename.substring(0, filename.lastIndexOf('.'));
+                    if (ext.length() == 3 && ext.substring(0, CacheControl.C_LAMBERT_CC_9Z.length()).equals(CacheControl.C_LAMBERT_CC_9Z))
+                        ext = ext.substring(2);
+                    else if (ext.length() == 4 && ext.substring(0, CacheControl.C_UTM20N.length()).equals(CacheControl.C_UTM20N))
+                        ext = ext.substring(3);
+                    // check the extension and its compatibility with current projection
+                    try {
+                        int cacheZone = Integer.parseInt(ext) - 1;
+                        if (cacheZone >= 0 && cacheZone <= 9) {
+                            if (cacheZone != layoutZone) {
+                                JOptionPane.showMessageDialog(Main.parent,
+                                        tr("Cannot load cache {0} which is not compatible with current projection zone", filename),
+                                        tr("Error"), JOptionPane.ERROR_MESSAGE);
+                                continue nextFile;
+                            } else
+                                Main.info("Load cache " + filename);
+                        }
+                    } catch (NumberFormatException ex) {
+                        JOptionPane.showMessageDialog(Main.parent, tr("Selected file {0} is not a cache file from this plugin (invalid extension)", filename), tr("Error"), JOptionPane.ERROR_MESSAGE);
+                        continue nextFile;
+                    }
+                    // check if the selected cache is not already displayed
+                    if (Main.map != null) {
+                        for (Layer l : Main.getLayerManager().getLayers()) {
+                            if (l instanceof WMSLayer && l.getName().equals(location)) {
+                                JOptionPane.showMessageDialog(Main.parent, tr("The location {0} is already on screen. Cache not loaded.", filename), tr("Error"), JOptionPane.ERROR_MESSAGE);
+                                continue nextFile;
+                            }
+                        }
+                    }
+                    // create layer and load cache
+                    WMSLayer wmsLayer = new WMSLayer("", "", Integer.parseInt(ext)-1);
+                    if (wmsLayer.grabThread.getCacheControl().loadCache(file, layoutZone)) {
+                        CadastrePlugin.addWMSLayer(wmsLayer);
+                    }
+                }
+            }
+        }
+
+    }
+
+    protected static JFileChooser createAndOpenFileChooser() {
+        JFileChooser fc = new JFileChooser(new File(CadastrePlugin.cacheDir));
+        fc.setMultiSelectionEnabled(true);
+        int layoutZone = CadastrePlugin.getCadastreProjectionLayoutZone();
+        if (layoutZone != -1) {
+            if (CadastrePlugin.isLambert())
+                fc.addChoosableFileFilter(CacheFileLambert4ZoneFilter.filters[layoutZone]);
+            else if (CadastrePlugin.isLambert_cc9())
+                fc.addChoosableFileFilter(CacheFileLambert9ZoneFilter.filters[layoutZone]);
+            else if (CadastrePlugin.isUtm_france_dom())
+                fc.addChoosableFileFilter(CacheFileUTM20NFilter.filters[layoutZone]);
+        }
+        fc.setAcceptAllFileFilterUsed(false);
+
+        int answer = fc.showOpenDialog(Main.parent);
+        if (answer != JFileChooser.APPROVE_OPTION)
+            return null;
+
+        return fc;
+    }
+
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionNewLocation.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionNewLocation.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionNewLocation.java	(revision 33638)
@@ -0,0 +1,137 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.DownloadWMSVectorImage;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+import org.openstreetmap.josm.tools.GBC;
+
+public class MenuActionNewLocation extends JosmAction {
+
+    private static final long serialVersionUID = 1L;
+
+    // CHECKSTYLE.OFF: LineLength
+    // CHECKSTYLE.OFF: SingleSpaceSeparator
+
+    private static final String[] departements = {
+        "", tr("(optional)"),
+        "001", "01 - Ain",                 "002", "02 - Aisne",              "003", "03 - Allier",                "004", "04 - Alpes de Haute-Provence", "005", "05 - Hautes-Alpes",
+        "006", "06 - Alpes-Maritimes",     "007", "07 - Ard\u00eache",       "008", "08 - Ardennes",              "009", "09 - Ari\u00e8ge",             "010", "10 - Aube",
+        "011", "11 - Aude",                "012", "12 - Aveyron",            "013", "13 - Bouches-du-Rh\u00f4ne", "014", "14 - Calvados",                "015", "15 - Cantal",
+        "016", "16 - Charente",            "017", "17 - Charente-Maritime",  "018", "18 - Cher",                  "019", "19 - Corr\u00e8ze",
+        "02A", "2A - Corse-du-Sud",        "02B", "2B - Haute-Corse",
+        "021", "21 - C\u00f4te-d'Or",      "022", "22 - C\u00f4tes d'Armor", "023", "23 - Creuse",                "024", "24 - Dordogne",                "025", "25 - Doubs",
+        "026", "26 - Dr\u00f4me",          "027", "27 - Eure",               "028", "28 - Eure-et-Loir",          "029", "29 - Finist\u00e8re",          "030", "30 - Gard",
+        "031", "31 - Haute-Garonne",       "032", "32 - Gers",               "033", "33 - Gironde",               "034", "34 - H\u00e9rault",            "035", "35 - Ille-et-Vilaine",
+        "036", "36 - Indre",               "037", "37 - Indre-et-Loire",     "038", "38 - Is\u00e8re",            "039", "39 - Jura",                    "040", "40 - Landes",
+        "041", "41 - Loir-et-Cher",        "042", "42 - Loire",              "043", "43 - Haute-Loire",           "044", "44 - Loire-Atlantique",        "045", "45 - Loiret",
+        "046", "46 - Lot",                 "047", "47 - Lot-et-Garonne",     "048", "48 - Loz\u00e8re",           "049", "49 - Maine-et-Loire",          "050", "50 - Manche",
+        "051", "51 - Marne",               "052", "52 - Haute-Marne",        "053", "53 - Mayenne",               "054", "54 - Meurthe-et-Moselle",      "055", "55 - Meuse",
+        "056", "56 - Morbihan",            "057", "57 - Moselle",            "058", "58 - Ni\u00e8vre",           "059", "59 - Nord",                    "060", "60 - Oise",
+        "061", "61 - Orne",                "062", "62 - Pas-de-Calais",      "063", "63 - Puy-de-D\u00f4me",      "064", "64 - Pyr\u00e9n\u00e9es-Atlantiques", "065", "65 - Hautes-Pyr\u00e9n\u00e9es",
+        "066", "66 - Pyr\u00e9n\u00e9es-Orientales", "067", "67 - Bas-Rhin", "068", "68 - Haut-Rhin",             "069", "69 - Rh\u00f4ne",              "070", "70 - Haute-Sa\u00f4ne",
+        "071", "71 - Sa\u00f4ne-et-Loire", "072", "72 - Sarthe",             "073", "73 - Savoie",                "074", "74 - Haute-Savoie",            "075", "75 - Paris",
+        "076", "76 - Seine-Maritime",      "077", "77 - Seine-et-Marne",     "078", "78 - Yvelines",              "079", "79 - Deux-S\u00e8vres",        "080", "80 - Somme",
+        "081", "81 - Tarn",                "082", "82 - Tarn-et-Garonne",    "083", "83 - Var",                   "084", "84 - Vaucluse",                "085", "85 - Vend\u00e9e",
+        "086", "86 - Vienne",              "087", "87 - Haute-Vienne",       "088", "88 - Vosges",                "089", "89 - Yonne",                   "090", "90 - Territoire de Belfort",
+        "091", "91 - Essonne",             "092", "92 - Hauts-de-Seine",     "093", "93 - Seine-Saint-Denis",     "094", "94 - Val-de-Marne",            "095", "95 - Val-d'Oise",
+        "971", "971 - Guadeloupe",         "972", "972 - Martinique",        "973", "973 - Guyane",               "974", "974 - R\u00e9union"
+    };
+
+    // CHECKSTYLE.ON: SingleSpaceSeparator
+    // CHECKSTYLE.ON: LineLength
+
+    public MenuActionNewLocation() {
+        super(tr("Change location"), "cadastre_small", tr("Set a new location for the next request"), null, false,
+                "cadastrefr/newlocation", true);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        WMSLayer wmsLayer = addNewLayer(new ArrayList<WMSLayer>());
+        if (wmsLayer != null)
+            DownloadWMSVectorImage.download(wmsLayer);
+    }
+
+    public WMSLayer addNewLayer(ArrayList<WMSLayer> existingLayers) {
+        String location = "";
+        String codeDepartement = "";
+        String codeCommune = "";
+        JLabel labelSectionNewLocation = new JLabel(tr("Add a new municipality layer"));
+        JPanel p = new JPanel(new GridBagLayout());
+        JLabel labelLocation = new JLabel(tr("Commune"));
+        final JTextField inputTown = new JTextField(Main.pref.get("cadastrewms.location"));
+        inputTown.setToolTipText(tr("<html>Enter the town,village or city name.<br>"
+                + "Use the syntax and punctuation known by www.cadastre.gouv.fr .</html>"));
+        JLabel labelDepartement = new JLabel(tr("Departement"));
+        final JComboBox<String> inputDepartement = new JComboBox<>();
+        for (int i = 1; i < departements.length; i += 2) {
+            inputDepartement.addItem(departements[i]);
+        }
+        inputDepartement.setToolTipText(tr("<html>Departement number (optional)</html>"));
+        if (!Main.pref.get("cadastrewms.codeDepartement").equals("")) {
+            for (int i = 0; i < departements.length; i += 2) {
+                if (departements[i].equals(Main.pref.get("cadastrewms.codeDepartement")))
+                    inputDepartement.setSelectedIndex(i/2);
+            }
+        }
+        p.add(labelSectionNewLocation, GBC.eol());
+        p.add(labelLocation, GBC.std().insets(10, 0, 0, 0));
+        p.add(inputTown, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 5));
+        p.add(labelDepartement, GBC.std().insets(10, 0, 0, 0));
+        p.add(inputDepartement, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 5));
+        JOptionPane pane = new JOptionPane(p, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null) {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public void selectInitialValue() {
+                inputTown.requestFocusInWindow();
+                inputTown.selectAll();
+            }
+        };
+        pane.createDialog(Main.parent, tr("Add new layer")).setVisible(true);
+        if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
+            return null;
+
+        WMSLayer wmsLayer = null;
+        if (!inputTown.getText().equals("")) {
+            location = inputTown.getText().toUpperCase();
+            codeDepartement = departements[inputDepartement.getSelectedIndex()*2];
+            Main.pref.put("cadastrewms.location", location);
+            Main.pref.put("cadastrewms.codeCommune", codeCommune);
+            Main.pref.put("cadastrewms.codeDepartement", codeDepartement);
+            if (Main.map != null) {
+                for (Layer l : Main.getLayerManager().getLayers()) {
+                    if (l instanceof WMSLayer && l.getName().equalsIgnoreCase(location)) {
+                        return null;
+                    }
+                }
+            }
+            // add the layer if it doesn't exist
+            int zone = CadastrePlugin.getCadastreProjectionLayoutZone();
+            wmsLayer = new WMSLayer(location, codeCommune, zone);
+            wmsLayer.setDepartement(codeDepartement);
+            CadastrePlugin.addWMSLayer(wmsLayer);
+            Main.info("Add new layer with Location:" + inputTown.getText());
+        } else if (existingLayers != null && existingLayers.size() > 0 && Main.getLayerManager().getActiveLayer() instanceof WMSLayer) {
+            wmsLayer = (WMSLayer) Main.getLayerManager().getActiveLayer();
+        }
+
+        return wmsLayer;
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionOpenPreferences.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionOpenPreferences.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionOpenPreferences.java	(revision 33638)
@@ -0,0 +1,32 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.gui.preferences.PreferenceDialog;
+import org.openstreetmap.josm.plugins.fr.cadastre.preferences.CadastrePreferenceSetting;
+
+public class MenuActionOpenPreferences extends JosmAction {
+    private static final long serialVersionUID = 1L;
+
+    public static final String NAME = marktr("Preferences");
+
+    /**
+     * Constructs a new {@code MenuActionOpenPreferences}.
+     */
+    public MenuActionOpenPreferences() {
+        super(tr(NAME), "cadastre_small", tr("Open Cadastre Preferences"), null, false, "cadastrefr/openpreferences", true);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        PreferenceDialog p = new PreferenceDialog(Main.parent);
+        p.selectPreferencesTabByClass(CadastrePreferenceSetting.class);
+        p.setVisible(true);
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionRefineGeoRef.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionRefineGeoRef.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionRefineGeoRef.java	(revision 33638)
@@ -0,0 +1,46 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.RasterImageGeoreferencer;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+
+public class MenuActionRefineGeoRef extends JosmAction {
+
+    public static final String NAME = marktr("Refine georeferencing");
+
+    private WMSLayer wmsLayer;
+    private RasterImageGeoreferencer rasterImageGeoreferencer;
+
+    /**
+     * Constructs a new {@code MenuActionRefineGeoRef}.
+     * @param wmsLayer WMS layer
+     */
+    public MenuActionRefineGeoRef(WMSLayer wmsLayer) {
+        super(tr(NAME), null, tr("Improve georeferencing (only raster images)"), null, false);
+        this.wmsLayer = wmsLayer;
+        rasterImageGeoreferencer = new RasterImageGeoreferencer();
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent arg0) {
+        if (!wmsLayer.isRaster()) {
+            Main.info("MenuActionRefineGeoRef called for unexpected layer type");
+            return;
+        }
+        if (CadastrePlugin.isCadastreProjection()) {
+            //wmsLayer = WMSDownloadAction.getLayer();
+        } else {
+            CadastrePlugin.askToChangeProjection();
+        }
+        rasterImageGeoreferencer.addListener();
+        rasterImageGeoreferencer.startGeoreferencing(wmsLayer);
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionResetCookie.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionResetCookie.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionResetCookie.java	(revision 33638)
@@ -0,0 +1,25 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import org.openstreetmap.josm.actions.JosmAction;
+
+public class MenuActionResetCookie extends JosmAction {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    public MenuActionResetCookie() {
+        super(tr("Reset cookie"), "cadastre_small", tr("Get a new cookie (session timeout)"), null, false);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        //CadastrePlugin.cadastreGrabber.getWmsInterface().resetCookie();
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionSaveRasterAs.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionSaveRasterAs.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/MenuActionSaveRasterAs.java	(revision 33638)
@@ -0,0 +1,140 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.Locale;
+
+import javax.imageio.ImageIO;
+import javax.swing.JFileChooser;
+import javax.swing.filechooser.FileFilter;
+
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.GridCoverageFactory;
+import org.geotools.coverage.grid.io.AbstractGridFormat;
+import org.geotools.gce.geotiff.GeoTiffFormat;
+import org.geotools.gce.geotiff.GeoTiffWriteParams;
+import org.geotools.gce.geotiff.GeoTiffWriter;
+import org.geotools.geometry.Envelope2D;
+import org.geotools.referencing.CRS;
+import org.opengis.parameter.GeneralParameterValue;
+import org.opengis.parameter.ParameterValueGroup;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+
+public class MenuActionSaveRasterAs extends JosmAction {
+
+    public static final String NAME = marktr("Save image as...");
+
+    private static final long serialVersionUID = 1L;
+
+    private WMSLayer wmsLayer;
+
+    public class FiltrePng extends FileFilter {
+        @Override
+        public boolean accept(File file) {
+            if (file.isDirectory()) {
+                return true;
+            }
+            return file.getName().toLowerCase(Locale.ENGLISH).endsWith(".png");
+        }
+
+        @Override
+        public String getDescription() {
+            return tr("PNG files (*.png)");
+        }
+    }
+
+    public class FiltreTiff extends FileFilter {
+        @Override
+        public boolean accept(File file) {
+            if (file.isDirectory()) {
+                return true;
+            }
+            return file.getName().toLowerCase(Locale.ENGLISH).endsWith(".tif");
+        }
+
+        @Override
+        public String getDescription() {
+            return tr("GeoTiff files (*.tif)");
+        }
+    }
+
+    FiltreTiff filtreTiff = new FiltreTiff();
+    FiltrePng filtrePng = new FiltrePng();
+
+    /**
+     * Constructs a new {@code MenuActionSaveRasterAs}.
+     * @param wmsLayer WMS layer
+     */
+    public MenuActionSaveRasterAs(WMSLayer wmsLayer) {
+        super(tr(NAME), "save", tr("Export image (only raster images)"), null, false);
+        this.wmsLayer = wmsLayer;
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent arg0) {
+        File file;
+        JFileChooser fc = new JFileChooser();
+        fc.addChoosableFileFilter(filtreTiff);
+        fc.addChoosableFileFilter(filtrePng);
+        fc.setFileFilter(filtreTiff);
+        int returnVal = fc.showSaveDialog(Main.parent);
+        if (returnVal == JFileChooser.APPROVE_OPTION) {
+            file = fc.getSelectedFile();
+            BufferedImage bi = wmsLayer.getImage(0).image;
+            if (fc.getFileFilter().equals(filtrePng)) {
+                if (!file.getName().endsWith(".png"))
+                    file = new File(file.getParent(), file.getName()+".png");
+                try {
+                    ImageIO.write(bi, "png", file);
+/*
+                    FileOutputStream flux = new FileOutputStream(file);
+                    BufferedOutputStream fluxBuf = new BufferedOutputStream(flux);
+                    JPEGImageEncoder codec = JPEGCodec.createJPEGEncoder(fluxBuf, JPEGCodec.getDefaultJPEGEncodeParam(bi));
+                    codec.encode(bi);
+                    fluxBuf.close();
+*/
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            } else if (fc.getFileFilter().equals(filtreTiff)) {
+                boolean alpha = bi.getColorModel().hasAlpha();
+                Main.info("image with alpha channel : " + alpha);
+                try {
+                    double x = wmsLayer.getImage(0).min.east();
+                    double y = wmsLayer.getImage(0).min.north();
+                    Envelope2D bbox = new Envelope2D(CRS.decode("EPSG:27561"),
+                            x, y,
+                            wmsLayer.getImage(0).max.east()-x, wmsLayer.getImage(0).max.north()-y);
+                    GridCoverageFactory factory = new GridCoverageFactory();
+                    GridCoverage2D coverage = factory.create("tiff", bi, bbox);
+                    final File output = new File(file.getParent(), file.getName()+".tif");
+                    GeoTiffWriter gtwriter = new GeoTiffWriter(output);
+                    GeoTiffWriteParams wp = new GeoTiffWriteParams();
+                    wp.setCompressionMode(GeoTiffWriteParams.MODE_EXPLICIT);
+                    wp.setCompressionType("LZW");
+                    wp.setCompressionQuality(0.75F);
+                    final GeoTiffFormat format = new GeoTiffFormat();
+                    final ParameterValueGroup params = format.getWriteParameters();
+                    params.parameter(
+                                    AbstractGridFormat.GEOTOOLS_WRITE_PARAMS.getName().toString())
+                                    .setValue(wp);
+
+                    gtwriter.write(coverage, params.values().toArray(new GeneralParameterValue[1]));
+                    gtwriter.dispose();
+                    coverage.dispose(true);
+                } catch (Exception e) {
+                    Main.error(e);
+                }
+            }
+        }
+    }
+
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/WMSDownloadAction.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/WMSDownloadAction.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/WMSDownloadAction.java	(revision 33638)
@@ -0,0 +1,45 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+//import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+//import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+
+public class WMSDownloadAction {
+
+    public static WMSLayer getLayer() {
+        // check if we already have a layer created. if not, create; if yes, reuse.
+        ArrayList<WMSLayer> existingWMSlayers = new ArrayList<>();
+        if (Main.map != null) {
+            Layer activeLayer = Main.getLayerManager().getActiveLayer();
+            if (activeLayer instanceof WMSLayer)
+                return (WMSLayer) activeLayer;
+            for (Layer l : Main.getLayerManager().getLayers()) {
+                if (l instanceof WMSLayer) {
+                    existingWMSlayers.add((WMSLayer) l);
+                }
+            }
+            if (existingWMSlayers.size() == 1)
+                return existingWMSlayers.get(0);
+            if (existingWMSlayers.size() == 0)
+                return new MenuActionNewLocation().addNewLayer(existingWMSlayers);
+            if (Main.pref.getBoolean("cadastrewms.autoFirstLayer", false)) {
+                return existingWMSlayers.get(0);
+            } else {
+                JOptionPane.showMessageDialog(Main.parent,
+                        tr("More than one WMS layer present\nSelect one of them first, then retry"));
+            }
+        } else {
+            return new MenuActionNewLocation().addNewLayer(existingWMSlayers);
+        }
+        return null;
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/mapmode/Address.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/mapmode/Address.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/mapmode/Address.java	(revision 33638)
@@ -0,0 +1,540 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions.mapmode;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Cursor;
+import java.awt.GridBagLayout;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.ButtonGroup;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.coor.EastNorth;
+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.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.WaySegment;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Pair;
+import org.openstreetmap.josm.tools.Shortcut;
+
+public class Address extends MapMode {
+
+    // perhaps make all these tags configurable in the future
+    private String tagHighway = "highway";
+    private String tagHighwayName = "name";
+    private String tagHouseNumber = "addr:housenumber";
+    private String tagHouseStreet = "addr:street";
+    private String tagBuilding = "building";
+    private String relationAddrType = "associatedStreet";
+    private String relationAddrName = "name";
+    private String relationAddrStreetRole = "street";
+    private String relationMemberHouse = "house";
+
+    private JRadioButton plusOne = new JRadioButton("+1", false);
+    private JRadioButton plusTwo = new JRadioButton("+2", true); // enable this by default
+    private JRadioButton minusOne = new JRadioButton("-1", false);
+    private JRadioButton minusTwo = new JRadioButton("-2", false);
+    final JCheckBox tagPolygon = new JCheckBox(tr("on polygon"));
+
+    JDialog dialog;
+    JButton clearButton;
+    final JTextField inputNumber = new JTextField();
+    final JTextField inputStreet = new JTextField();
+    JLabel link = new JLabel();
+    private transient Way selectedWay;
+    private boolean shift;
+    private boolean ctrl;
+
+    /**
+     * Constructs a new {@code Address} map mode.
+     */
+    public Address() {
+        super(tr("Add address"), "buildings",
+                tr("Helping tool for tag address"),
+                // CHECKSTYLE.OFF: LineLength
+                Shortcut.registerShortcut("mapmode:cadastre-fr-buildings", tr("Mode: {0}", tr("CadastreFR - Buildings")), KeyEvent.VK_E, Shortcut.DIRECT),
+                // CHECKSTYLE.ON: LineLength
+                getCursor());
+    }
+
+    @Override public void enterMode() {
+        super.enterMode();
+        if (dialog == null) {
+            createDialog();
+        }
+        dialog.setVisible(true);
+        Main.map.mapView.addMouseListener(this);
+    }
+
+    @Override public void exitMode() {
+        if (Main.map.mapView != null) {
+            super.exitMode();
+            Main.map.mapView.removeMouseListener(this);
+        }
+        // kill the window completely to fix an issue on some linux distro and full screen mode.
+        if (dialog != null) {
+            dialog.dispose();
+            dialog = null;
+        }
+    }
+
+    @Override
+    public void mousePressed(MouseEvent e) {
+        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<>();
+        List<Way> mouseOnExistingBuildingWays = new ArrayList<>();
+        Node currentMouseNode = mv.getNearestNode(mousePos, OsmPrimitive::isSelectable);
+        if (currentMouseNode != null) {
+            // click on existing node
+            setNewSelection(currentMouseNode);
+            String num = currentMouseNode.get(tagHouseNumber);
+            if (num != null
+                    && currentMouseNode.get(tagHouseStreet) == null
+                    && findWayInRelationAddr(currentMouseNode) == null
+                    && !inputStreet.getText().isEmpty()) {
+                // house number already present but not linked to a street
+                Collection<Command> cmds = new LinkedList<>();
+                addStreetNameOrRelation(currentMouseNode, cmds);
+                Command c = new SequenceCommand("Add node address", cmds);
+                Main.main.undoRedo.add(c);
+                setNewSelection(currentMouseNode);
+            } else {
+                if (num != null) {
+                    try {
+                        // add new address
+                        Integer.parseInt(num);
+                        inputNumber.setText(num);
+                        applyInputNumberChange();
+                    } catch (NumberFormatException en) {
+                        Main.warn("Unable to parse house number \"" + num + "\"");
+                    }
+                }
+                if (currentMouseNode.get(tagHouseStreet) != null) {
+                    if (Main.pref.getBoolean("cadastrewms.addr.dontUseRelation", false)) {
+                        inputStreet.setText(currentMouseNode.get(tagHouseStreet));
+                        if (ctrl) {
+                            Collection<Command> cmds = new LinkedList<>();
+                            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<>();
+                        addAddrToPrimitive(currentMouseNode, cmds);
+                    } else {
+                        inputStreet.setText(wayInRelationAddr.get(tagHighwayName));
+                        setSelectedWay(wayInRelationAddr);
+                    }
+                }
+            }
+        } else {
+            List<WaySegment> wss = mv.getNearestWaySegments(mousePos, OsmPrimitive::isSelectable);
+            for (WaySegment ws : wss) {
+                if (ws.way.get(tagHighway) != null && ws.way.get(tagHighwayName) != null)
+                    mouseOnExistingWays.add(ws.way);
+                else if (ws.way.get(tagBuilding) != null && ws.way.get(tagHouseNumber) == null)
+                    mouseOnExistingBuildingWays.add(ws.way);
+            }
+            if (mouseOnExistingWays.size() == 1) {
+                // clicked on existing highway => set new street name
+                inputStreet.setText(mouseOnExistingWays.get(0).get(tagHighwayName));
+                setSelectedWay(mouseOnExistingWays.get(0));
+                inputNumber.setText("");
+                setNewSelection(mouseOnExistingWays.get(0));
+            } else if (mouseOnExistingWays.isEmpty()) {
+                // clicked a non highway and not a node => add the new address
+                if (inputStreet.getText().isEmpty() || inputNumber.getText().isEmpty()) {
+                    Toolkit.getDefaultToolkit().beep();
+                } else {
+                    Collection<Command> cmds = new LinkedList<>();
+                    if (ctrl) {
+                        applyInputNumberChange();
+                    }
+                    if (tagPolygon.isSelected()) {
+                        addAddrToPolygon(mouseOnExistingBuildingWays, cmds);
+                    } else {
+                        Node n = createNewNode(e, cmds);
+                        addAddrToPrimitive(n, cmds);
+                    }
+                }
+            }
+        }
+    }
+
+    private Way findWayInRelationAddr(Node n) {
+        List<OsmPrimitive> l = n.getReferrers();
+        for (OsmPrimitive osm : l) {
+            if (osm instanceof Relation && osm.hasKey("type") && osm.get("type").equals(relationAddrType)) {
+                for (RelationMember rm : ((Relation) osm).getMembers()) {
+                    if (rm.getRole().equals(relationAddrStreetRole)) {
+                        OsmPrimitive osp = rm.getMember();
+                        if (osp instanceof Way && osp.hasKey(tagHighwayName)) {
+                            return (Way) osp;
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    private void addAddrToPolygon(List<Way> mouseOnExistingBuildingWays, Collection<Command> cmds) {
+        for (Way w:mouseOnExistingBuildingWays) {
+            addAddrToPrimitive(w, cmds);
+        }
+    }
+
+    private void addAddrToPrimitive(OsmPrimitive osm, Collection<Command> cmds) {
+        // add the current tag addr:housenumber in node and member in relation (if so configured)
+        if (shift) {
+            try {
+                revertInputNumberChange();
+            } catch (NumberFormatException en) {
+                Main.warn("Unable to parse house number \"" + inputNumber.getText() + "\"");
+            }
+        }
+        cmds.add(new ChangePropertyCommand(osm, tagHouseNumber, inputNumber.getText()));
+        addStreetNameOrRelation(osm, cmds);
+        try {
+            applyInputNumberChange();
+            Command c = new SequenceCommand("Add node address", cmds);
+            Main.main.undoRedo.add(c);
+            setNewSelection(osm);
+        } catch (NumberFormatException en) {
+            Main.warn("Unable to parse house number \"" + inputNumber.getText() + "\"");
+        }
+    }
+
+    private Relation findRelationAddr(Way w) {
+        List<OsmPrimitive> l = w.getReferrers();
+        for (OsmPrimitive osm : l) {
+            if (osm instanceof Relation && osm.hasKey("type") && osm.get("type").equals(relationAddrType)) {
+                return (Relation) osm;
+            }
+        }
+        return null;
+    }
+
+    private void addStreetNameOrRelation(OsmPrimitive osm, Collection<Command> cmds) {
+        if (Main.pref.getBoolean("cadastrewms.addr.dontUseRelation", false)) {
+            cmds.add(new ChangePropertyCommand(osm, tagHouseStreet, inputStreet.getText()));
+        } else if (selectedWay != null) {
+            Relation selectedRelation = findRelationAddr(selectedWay);
+            // add the node to its relation
+            if (selectedRelation != null) {
+                RelationMember rm = new RelationMember(relationMemberHouse, osm);
+                Relation newRel = new Relation(selectedRelation);
+                newRel.addMember(rm);
+                cmds.add(new ChangeCommand(selectedRelation, newRel));
+            } else {
+                // create new relation
+                Relation newRel = new Relation();
+                newRel.put("type", relationAddrType);
+                newRel.put(relationAddrName, selectedWay.get(tagHighwayName));
+                newRel.addMember(new RelationMember(relationAddrStreetRole, selectedWay));
+                newRel.addMember(new RelationMember(relationMemberHouse, osm));
+                cmds.add(new AddCommand(newRel));
+            }
+        }
+    }
+
+    private static Node createNewNode(MouseEvent e, Collection<Command> cmds) {
+        // DrawAction.mouseReleased() but without key modifiers
+        Node n = new Node(Main.map.mapView.getLatLon(e.getX(), e.getY()));
+        cmds.add(new AddCommand(n));
+        List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(e.getPoint(), OsmPrimitive::isSelectable);
+        Map<Way, List<Integer>> insertPoints = new HashMap<>();
+        for (WaySegment ws : wss) {
+            List<Integer> is;
+            if (insertPoints.containsKey(ws.way)) {
+                is = insertPoints.get(ws.way);
+            } else {
+                is = new ArrayList<>();
+                insertPoints.put(ws.way, is);
+            }
+
+            is.add(ws.lowerIndex);
+        }
+        Set<Pair<Node, Node>> segSet = new HashSet<>();
+        ArrayList<Way> replacedWays = new ArrayList<>();
+        ArrayList<Way> reuseWays = new ArrayList<>();
+        for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
+            Way w = insertPoint.getKey();
+            List<Integer> is = insertPoint.getValue();
+            Way wnew = new Way(w);
+            pruneSuccsAndReverse(is);
+            for (int i : is) {
+                segSet.add(Pair.sort(new Pair<>(w.getNode(i), w.getNode(i+1))));
+            }
+            for (int i : is) {
+                wnew.addNode(i + 1, n);
+            }
+            cmds.add(new ChangeCommand(insertPoint.getKey(), wnew));
+            replacedWays.add(insertPoint.getKey());
+            reuseWays.add(wnew);
+        }
+        adjustNode(segSet, n);
+
+        return n;
+    }
+
+    private static void adjustNode(Collection<Pair<Node, Node>> segs, Node n) {
+
+        switch (segs.size()) {
+        case 0:
+            return;
+        case 2:
+            // This computes the intersection between
+            // the two segments and adjusts the node position.
+            Iterator<Pair<Node, Node>> i = segs.iterator();
+            Pair<Node, Node> seg = i.next();
+            EastNorth A = seg.a.getEastNorth();
+            EastNorth B = seg.b.getEastNorth();
+            seg = i.next();
+            EastNorth C = seg.a.getEastNorth();
+            EastNorth D = seg.b.getEastNorth();
+
+            double u = det(B.east() - A.east(), B.north() - A.north(), C.east() - D.east(), C.north() - D.north());
+
+            // Check for parallel segments and do nothing if they are
+            // In practice this will probably only happen when a way has been duplicated
+
+            if (u == 0) return;
+
+            // q is a number between 0 and 1
+            // It is the point in the segment where the intersection occurs
+            // if the segment is scaled to lenght 1
+
+            double q = det(B.north() - C.north(), B.east() - C.east(), D.north() - C.north(), D.east() - C.east()) / u;
+            EastNorth intersection = new EastNorth(
+                    B.east() + q * (A.east() - B.east()),
+                    B.north() + q * (A.north() - B.north()));
+
+            int snapToIntersectionThreshold
+            = Main.pref.getInteger("edit.snap-intersection-threshold", 10);
+
+            // only adjust to intersection if within snapToIntersectionThreshold pixel of mouse click; otherwise
+            // fall through to default action.
+            // (for semi-parallel lines, intersection might be miles away!)
+            if (Main.map.mapView.getPoint(n).distance(Main.map.mapView.getPoint(intersection)) < snapToIntersectionThreshold) {
+                n.setEastNorth(intersection);
+                return;
+            }
+
+        default:
+            EastNorth P = n.getEastNorth();
+            seg = segs.iterator().next();
+            A = seg.a.getEastNorth();
+            B = seg.b.getEastNorth();
+            double a = P.distanceSq(B);
+            double b = P.distanceSq(A);
+            double c = A.distanceSq(B);
+            q = (a - b + c) / (2*c);
+            n.setEastNorth(new EastNorth(B.east() + q * (A.east() - B.east()), B.north() + q * (A.north() - B.north())));
+        }
+    }
+
+    static double det(double a, double b, double c, double d) {
+        return a * d - b * c;
+    }
+
+    private static void pruneSuccsAndReverse(List<Integer> is) {
+        HashSet<Integer> is2 = new HashSet<>();
+        for (int i : is) {
+            if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
+                is2.add(i);
+            }
+        }
+        is.clear();
+        is.addAll(is2);
+        Collections.sort(is);
+        Collections.reverse(is);
+    }
+
+    private static Cursor getCursor() {
+        try {
+            return ImageProvider.getCursor("crosshair", null);
+        } catch (RuntimeException e) {
+            Main.warn(e);
+        }
+        return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
+    }
+
+    private void applyInputNumberChange() {
+        Integer num = Integer.parseInt(inputNumber.getText());
+        if (plusOne.isSelected())
+            num = num + 1;
+        if (plusTwo.isSelected())
+            num = num + 2;
+        if (minusOne.isSelected() && num > 1)
+            num = num - 1;
+        if (minusTwo.isSelected() && num > 2)
+            num = num - 2;
+        inputNumber.setText(num.toString());
+    }
+
+    private void revertInputNumberChange() {
+        Integer num = Integer.parseInt(inputNumber.getText());
+        if (plusOne.isSelected())
+            num = num - 1;
+        if (plusTwo.isSelected())
+            num = num - 2;
+        if (minusOne.isSelected() && num > 1)
+            num = num + 1;
+        if (minusTwo.isSelected() && num > 2)
+            num = num + 2;
+        inputNumber.setText(num.toString());
+    }
+
+    private void createDialog() {
+        ImageIcon iconLink = ImageProvider.get(null, "Mf_relation");
+        link.setIcon(iconLink);
+        link.setEnabled(false);
+        JPanel p = new JPanel(new GridBagLayout());
+        JLabel number = new JLabel(tr("Next no"));
+        JLabel street = new JLabel(tr("Street"));
+        p.add(number, GBC.std().insets(0, 0, 0, 0));
+        p.add(inputNumber, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 0, 5));
+        p.add(street, GBC.std().insets(0, 0, 0, 0));
+        JPanel p2 = new JPanel(new GridBagLayout());
+        inputStreet.setEditable(false);
+        p2.add(inputStreet, GBC.std().fill(GBC.HORIZONTAL).insets(5, 0, 0, 0));
+        p2.add(link, GBC.eol().insets(10, 0, 0, 0));
+        p.add(p2, GBC.eol().fill(GBC.HORIZONTAL));
+        clearButton = new JButton("Clear");
+        clearButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                inputNumber.setText("");
+                inputStreet.setText("");
+                setSelectedWay((Way) null);
+            }
+        });
+        ButtonGroup bgIncremental = new ButtonGroup();
+        bgIncremental.add(plusOne);
+        bgIncremental.add(plusTwo);
+        bgIncremental.add(minusOne);
+        bgIncremental.add(minusTwo);
+        p.add(minusOne, GBC.std().insets(10, 0, 10, 0));
+        p.add(plusOne, GBC.std().insets(0, 0, 10, 0));
+        tagPolygon.setSelected(Main.pref.getBoolean("cadastrewms.addr.onBuilding", false));
+        tagPolygon.addChangeListener(new ChangeListener() {
+            @Override
+            public void stateChanged(ChangeEvent arg0) {
+                Main.pref.put("cadastrewms.addr.onBuilding", tagPolygon.isSelected());
+            }
+        });
+        p.add(tagPolygon, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 0, 0));
+        p.add(minusTwo, GBC.std().insets(10, 0, 10, 0));
+        p.add(plusTwo, GBC.std().insets(0, 0, 10, 0));
+        p.add(clearButton, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 0, 0));
+
+        final Object[] options = {};
+        final JOptionPane pane = new JOptionPane(p,
+                JOptionPane.PLAIN_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION,
+                null, options, null);
+        dialog = pane.createDialog(Main.parent, tr("Enter addresses"));
+        dialog.setModal(false);
+        dialog.setAlwaysOnTop(true);
+        dialog.addComponentListener(new ComponentAdapter() {
+            protected void rememberGeometry() {
+                Main.pref.put("cadastrewms.addr.bounds", dialog.getX()+","+dialog.getY()+","+dialog.getWidth()+","+dialog.getHeight());
+            }
+
+            @Override public void componentMoved(ComponentEvent e) {
+                rememberGeometry();
+            }
+
+            @Override public void componentResized(ComponentEvent e) {
+                rememberGeometry();
+            }
+        });
+        dialog.addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosing(WindowEvent arg) {
+                Main.map.selectMapMode((MapMode) Main.map.getDefaultButtonAction());
+            }
+        });
+        String bounds = Main.pref.get("cadastrewms.addr.bounds", null);
+        if (bounds != null) {
+            String[] b = bounds.split(",");
+            dialog.setBounds(new Rectangle(
+                    Integer.parseInt(b[0]), Integer.parseInt(b[1]), Integer.parseInt(b[2]), Integer.parseInt(b[3])));
+        }
+    }
+
+    private void setSelectedWay(Way w) {
+        this.selectedWay = w;
+        if (w == null) {
+            link.setEnabled(false);
+        } else
+            link.setEnabled(true);
+        link.repaint();
+    }
+
+    private static void setNewSelection(OsmPrimitive osm) {
+        DataSet ds = Main.getLayerManager().getEditDataSet();
+        Collection<OsmPrimitive> newSelection = new LinkedList<>(ds.getSelected());
+        newSelection.clear();
+        newSelection.add(osm);
+        ds.setSelected(osm);
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/mapmode/WMSAdjustAction.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/mapmode/WMSAdjustAction.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/mapmode/WMSAdjustAction.java	(revision 33638)
@@ -0,0 +1,199 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions.mapmode;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Graphics2D;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.CacheControl;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class WMSAdjustAction extends MapMode implements
+        MouseListener, MouseMotionListener {
+
+    private static final long serialVersionUID = 1L;
+    private WMSLayer modifiedLayer = null;
+    private boolean rasterMoved;
+    private EastNorth prevEastNorth;
+    enum Mode { moveXY, moveZ, rotate }
+
+    private static Mode mode = null;
+    private static EastNorth[] croppedRaster = new EastNorth[5];;
+
+    /**
+     * Constructs a new {@code WMSAdjustAction} map mode.
+     */
+    public WMSAdjustAction() {
+        super(tr("Adjust WMS"), "adjustxywms",
+                        tr("Adjust the position of the WMS layer (saved for raster images only)"),
+                        ImageProvider.getCursor("normal", "move"));
+    }
+
+    @Override public void enterMode() {
+        if (Main.map != null) {
+            if (Main.getLayerManager().getActiveLayer() instanceof WMSLayer) {
+                modifiedLayer = (WMSLayer) Main.getLayerManager().getActiveLayer();
+                super.enterMode();
+                Main.map.mapView.addMouseListener(this);
+                Main.map.mapView.addMouseMotionListener(this);
+                rasterMoved = false;
+                modifiedLayer.adjustModeEnabled = true;
+            } else {
+                // This mode works only if active layer is a cadastre layer
+                if (Boolean.TRUE.equals(getValue("active"))) {
+                    exitMode();
+                }
+                Main.map.selectMapMode((MapMode) Main.map.getDefaultButtonAction());
+            }
+        }
+    }
+
+    @Override public void exitMode() {
+        super.exitMode();
+        Main.map.mapView.removeMouseListener(this);
+        Main.map.mapView.removeMouseMotionListener(this);
+        if (rasterMoved && CacheControl.cacheEnabled && modifiedLayer.isRaster()) {
+            int reply = JOptionPane.showConfirmDialog(null,
+                    "Save the changes in cache ?",
+                    "Update cache",
+                    JOptionPane.YES_NO_OPTION);
+            if (reply == JOptionPane.OK_OPTION) {
+                saveModifiedLayers();
+            }
+        }
+        rasterMoved = false;
+        if (modifiedLayer != null) {
+            modifiedLayer.adjustModeEnabled = false;
+            modifiedLayer = null;
+        }
+    }
+
+    @Override
+    public void mousePressed(MouseEvent e) {
+        if (e.getButton() != MouseEvent.BUTTON1)
+            return;
+        requestFocusInMapView();
+        boolean ctrl = (e.getModifiers() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) != 0;
+        // boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+        boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+        if (shift && !ctrl && modifiedLayer.isRaster())
+            mode = Mode.moveZ;
+        else if (shift && ctrl && modifiedLayer.isRaster())
+            mode = Mode.rotate;
+        else
+            mode = Mode.moveXY;
+        rasterMoved = true;
+        prevEastNorth = Main.map.mapView.getEastNorth(e.getX(), e.getY());
+        Main.map.mapView.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+    }
+
+    @Override public void mouseDragged(MouseEvent e) {
+        EastNorth newEastNorth = Main.map.mapView.getEastNorth(e.getX(), e.getY());
+        if (mode == Mode.rotate) {
+            rotateFrameOnly(prevEastNorth, newEastNorth);
+        } else {
+            if (mode == Mode.moveXY) {
+                displace(prevEastNorth, newEastNorth);
+            } else if (mode == Mode.moveZ) {
+                resize(newEastNorth);
+            }
+            prevEastNorth = newEastNorth;
+        }
+        if (modifiedLayer != null) {
+            modifiedLayer.invalidate();
+        }
+    }
+
+    public static void paintAdjustFrames(Graphics2D g, final MapView mv) {
+        if (mode == Mode.rotate && croppedRaster != null) {
+            g.setColor(Color.red);
+            for (int i = 0; i < 4; i++) {
+                g.drawLine(mv.getPoint(croppedRaster[i]).x,
+                        mv.getPoint(croppedRaster[i]).y,
+                        mv.getPoint(croppedRaster[i+1]).x,
+                        mv.getPoint(croppedRaster[i+1]).y);
+            }
+        }
+    }
+
+    private void displace(EastNorth start, EastNorth end) {
+        modifiedLayer.displace(end.east()-start.east(), end.north()-start.north());
+    }
+
+    private void resize(EastNorth newEastNorth) {
+        EastNorth center = modifiedLayer.getRasterCenter();
+        double dPrev = prevEastNorth.distance(center.east(), center.north());
+        double dNew = newEastNorth.distance(center.east(), center.north());
+        modifiedLayer.resize(center, dNew/dPrev);
+    }
+
+    private void rotate(EastNorth start, EastNorth end) {
+        EastNorth pivot = modifiedLayer.getRasterCenter();
+        double startAngle = Math.atan2(start.east()-pivot.east(), start.north()-pivot.north());
+        double endAngle = Math.atan2(end.east()-pivot.east(), end.north()-pivot.north());
+        double rotationAngle = endAngle - startAngle;
+        modifiedLayer.rotate(pivot, rotationAngle);
+    }
+
+    private void rotateFrameOnly(EastNorth start, EastNorth end) {
+        if (start != null && end != null) {
+            EastNorth pivot = modifiedLayer.getRasterCenter();
+            double startAngle = Math.atan2(start.east()-pivot.east(), start.north()-pivot.north());
+            double endAngle = Math.atan2(end.east()-pivot.east(), end.north()-pivot.north());
+            double rotationAngle = endAngle - startAngle;
+            if (modifiedLayer.getImage(0).orgCroppedRaster != null) {
+                for (int i = 0; i < 4; i++) {
+                    croppedRaster[i] = modifiedLayer.getImage(0).orgCroppedRaster[i].rotate(pivot, rotationAngle);
+                }
+                croppedRaster[4] = croppedRaster[0];
+            }
+        }
+    }
+
+    @Override
+    public void mouseReleased(MouseEvent e) {
+        if (mode == Mode.rotate) {
+            EastNorth newEastNorth = Main.map.mapView.getEastNorth(e.getX(), e.getY());
+            rotate(prevEastNorth, newEastNorth);
+            if (modifiedLayer != null) {
+                modifiedLayer.invalidate();
+            }
+        }
+        Main.map.mapView.setCursor(Cursor.getDefaultCursor());
+        prevEastNorth = null;
+        mode = 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) {
+    }
+
+    private void saveModifiedLayers() {
+        modifiedLayer.grabThread.saveNewCache();
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/upload/CheckSourceUploadHook.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/upload/CheckSourceUploadHook.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/actions/upload/CheckSourceUploadHook.java	(revision 33638)
@@ -0,0 +1,90 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.actions.upload;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.util.Collection;
+import java.util.HashSet;
+
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.upload.UploadHook;
+import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.data.APIDataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+import org.openstreetmap.josm.tools.GBC;
+
+/**
+ * This hook is called at JOSM upload and will check if new nodes and ways provide
+ * a tag "source=". If not and if auto-sourcing is enabled, it will add
+ * automatically a tag "source"="Cadastre..." as defined in the plugin preferences.
+ */
+public class CheckSourceUploadHook implements UploadHook {
+
+    /**
+     * Add the tag "source" if it doesn't exist for all new Nodes and Ways before uploading
+     */
+    @Override
+    public boolean checkUpload(APIDataSet apiDataSet) {
+        if (CadastrePlugin.autoSourcing && CadastrePlugin.pluginUsed && !apiDataSet.getPrimitivesToAdd().isEmpty()) {
+            Collection<OsmPrimitive> sel = new HashSet<>();
+            for (OsmPrimitive osm : apiDataSet.getPrimitivesToAdd()) {
+                if ((osm instanceof Way && (osm.getKeys().size() == 0 || !tagSourceExist(osm)))
+                 || (osm instanceof Node && osm.getKeys().size() > 0 && !tagSourceExist(osm))) {
+                    sel.add(osm);
+                }
+            }
+            if (!sel.isEmpty()) {
+                displaySource(sel);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Check whenever one of the keys of the object is "source"
+     * @return true if one of keys is "source"
+     */
+    private boolean tagSourceExist(OsmPrimitive osm) {
+        for (String key : osm.keySet()) {
+            if (key.equals("source")) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Displays a screen with the list of objects which will be tagged with
+     * source="cadastre.." if it is approved.
+     * @param sel the list of elements added without a key "source"
+     */
+    private void displaySource(Collection<OsmPrimitive> sel) {
+        if (!sel.isEmpty()) {
+            JPanel p = new JPanel(new GridBagLayout());
+            OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
+            p.add(new JLabel(tr("Add \"source=...\" to elements?")), GBC.eol());
+            JTextField tf = new JTextField(CadastrePlugin.source);
+            p.add(tf, GBC.eol());
+            JList<OsmPrimitive> l = new JList<>(sel.toArray(new OsmPrimitive[0]));
+            l.setCellRenderer(renderer);
+            l.setVisibleRowCount(l.getModel().getSize() < 6 ? l.getModel().getSize() : 10);
+            p.add(new JScrollPane(l), GBC.eol().fill());
+            boolean bContinue = JOptionPane.showConfirmDialog(Main.parent, p, tr("Add \"source=...\" to elements?"),
+                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
+            if (bContinue)
+                Main.main.undoRedo.add(new ChangePropertyCommand(sel, "source", tf.getText()));
+        }
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/preferences/CadastrePreferenceSetting.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/preferences/CadastrePreferenceSetting.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/preferences/CadastrePreferenceSetting.java	(revision 33638)
@@ -0,0 +1,468 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.preferences;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.AbstractButton;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JSlider;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.preferences.DefaultTabPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.CacheControl;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.I18n;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+/**
+ * Preference settings for the French Cadastre plugin
+ *
+ * @author Pieren &lt;pieren3@gmail.com&gt;
+ */
+public class CadastrePreferenceSetting extends DefaultTabPreferenceSetting {
+
+    static final int TRANS_MIN = 1;
+    static final int TRANS_MAX = 10;
+    private JSlider sliderTrans = new JSlider(JSlider.HORIZONTAL, TRANS_MIN, TRANS_MAX, TRANS_MAX);
+
+    private JTextField sourcing = new JTextField(20);
+
+    private JCheckBox alterColors = new JCheckBox(tr("Replace original background by JOSM background color."));
+
+    private JCheckBox reversGrey = new JCheckBox(tr("Reverse grey colors (for black backgrounds)."));
+
+    private JCheckBox transparency = new JCheckBox(tr("Set background transparent."));
+
+    private JCheckBox drawBoundaries = new JCheckBox(tr("Draw boundaries of downloaded data."));
+
+    private JComboBox<String> imageInterpolationMethod = new JComboBox<>();
+
+    private JCheckBox disableImageCropping = new JCheckBox(tr("Disable image cropping during georeferencing."));
+
+    private JCheckBox enableTableauAssemblage = new JCheckBox(tr("Use \"Tableau d''assemblage\""));
+
+    private JCheckBox simplify2BitsColors = new JCheckBox(tr("Replace grey shades by white color only"));
+
+    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)."));
+
+    private JRadioButton grabMultiplier1 = new JRadioButton("", true);
+
+    private JRadioButton grabMultiplier2 = new JRadioButton("", true);
+
+    private JRadioButton grabMultiplier3 = new JRadioButton("", true);
+
+    private JRadioButton grabMultiplier4 = new JRadioButton("", true);
+
+    private JRadioButton crosspiece1 = new JRadioButton(tr("off"));
+
+    private JRadioButton crosspiece2 = new JRadioButton(tr("25 m"));
+
+    private JRadioButton crosspiece3 = new JRadioButton(tr("50 m"));
+
+    private JRadioButton crosspiece4 = new JRadioButton(tr("100 m"));
+
+    private JRadioButton grabRes1 = new JRadioButton(tr("high"));
+    private JRadioButton grabRes2 = new JRadioButton(tr("medium"));
+    private JRadioButton grabRes3 = new JRadioButton(tr("low"));
+
+    private JCheckBox layerLS3 = new JCheckBox(tr("water"));
+    private JCheckBox layerLS2 = new JCheckBox(tr("building"));
+    private JCheckBox layerLS1 = new JCheckBox(tr("symbol"));
+    private JCheckBox layerParcel = new JCheckBox(tr("parcel"));
+    private JCheckBox layerLabel = new JCheckBox(tr("parcel number"));
+    private JCheckBox layerNumero = new JCheckBox(tr("address"));
+    private JCheckBox layerLieudit = new JCheckBox(tr("locality"));
+    private JCheckBox layerSection = new JCheckBox(tr("section"));
+    private JCheckBox layerCommune = new JCheckBox(tr("commune"));
+
+    public static final int DEFAULT_SQUARE_SIZE = 100;
+    private JTextField grabMultiplier4Size = new JTextField(5);
+
+    private JCheckBox enableCache = new JCheckBox(tr("Enable automatic caching."));
+
+    public static final int DEFAULT_CACHE_SIZE = 0; // disabled by default
+    JLabel jLabelCacheSize = new JLabel(tr("Max. cache size (in MB)"));
+    private JTextField cacheSize = new JTextField(20);
+
+    public static final String DEFAULT_RASTER_DIVIDER = "7";
+    private JTextField rasterDivider = new JTextField(10);
+
+    static final int DEFAULT_CROSSPIECES = 0;
+
+    public static final String DEFAULT_GRAB_MULTIPLIER = Scale.SQUARE_100M.value;
+
+    /**
+     * Constructs a new {@code CadastrePreferenceSetting}.
+     */
+    public CadastrePreferenceSetting() {
+        super("cadastrewms.png", I18n.tr("French cadastre WMS"),
+            tr("A special handler of the French cadastre wms at www.cadastre.gouv.fr" + "<BR><BR>"
+                + "Please read the Terms and Conditions of Use here (in French): <br>"
+                + "<a href=\"http://www.cadastre.gouv.fr/scpc/html/CU_01_ConditionsGenerales_fr.html\"> "
+                + "http://www.cadastre.gouv.fr/scpc/html/CU_01_ConditionsGenerales_fr.html</a> <BR>"
+                + "before any upload of data created by this plugin.")
+        );
+    }
+
+    @Override
+    public void addGui(final PreferenceTabbedPane gui) {
+        JPanel cadastrewmsMast = gui.createPreferenceTab(this);
+
+        JPanel cadastrewms = new JPanel(new GridBagLayout());
+        cadastrewms.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+
+        // option to automatically set the source tag when uploading
+        sourcing.setText(CadastrePlugin.source);
+        sourcing.setToolTipText(tr("<html>Value of key \"source\" when autosourcing is enabled</html>"));
+        JLabel jLabelSource = new JLabel(tr("Source"));
+        cadastrewms.add(jLabelSource, GBC.eop().insets(0, 0, 0, 0));
+        cadastrewms.add(sourcing, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 5));
+
+        // option to alter the original colors of the wms images
+        alterColors.setSelected(Main.pref.getBoolean("cadastrewms.alterColors", false));
+        alterColors.setToolTipText(tr("Replace the original white background by the background color defined in JOSM preferences."));
+        cadastrewms.add(alterColors, GBC.eop().insets(0, 0, 0, 0));
+
+        // option to reverse the grey colors (to see texts background)
+        reversGrey.setSelected(Main.pref.getBoolean("cadastrewms.invertGrey", false));
+        reversGrey.setToolTipText(
+                tr("Invert the original black and white colors (and all intermediate greys). Useful for texts on dark backgrounds."));
+        cadastrewms.add(reversGrey, GBC.eop().insets(0, 0, 0, 0));
+
+        // option to enable transparency
+        transparency.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                sliderTrans.setEnabled(transparency.isSelected());
+            }
+        });
+        transparency.setSelected(Main.pref.getBoolean("cadastrewms.backgroundTransparent", false));
+        transparency.setToolTipText(tr("Allows multiple layers stacking"));
+        cadastrewms.add(transparency, GBC.eop().insets(0, 0, 0, 0));
+
+        // slider for transparency level
+        sliderTrans.setSnapToTicks(true);
+        sliderTrans.setToolTipText(tr("Set WMS layers transparency. Right is opaque, left is transparent."));
+        sliderTrans.setMajorTickSpacing(10);
+        sliderTrans.setMinorTickSpacing(1);
+        sliderTrans.setValue((int) (Float.parseFloat(Main.pref.get("cadastrewms.brightness", "1.0f"))*10));
+        sliderTrans.setPaintTicks(true);
+        sliderTrans.setPaintLabels(false);
+        sliderTrans.setEnabled(transparency.isSelected());
+        cadastrewms.add(sliderTrans, GBC.eol().fill(GBC.HORIZONTAL).insets(20, 0, 250, 0));
+
+        // option to draw boundaries of downloaded data
+        drawBoundaries.setSelected(Main.pref.getBoolean("cadastrewms.drawBoundaries", false));
+        drawBoundaries.setToolTipText(tr("Draw a rectangle around downloaded data from WMS server."));
+        cadastrewms.add(drawBoundaries, GBC.eop().insets(0, 0, 0, 5));
+
+        // option to select the single grabbed image resolution
+        JLabel jLabelRes = new JLabel(tr("Image resolution:"));
+        cadastrewms.add(jLabelRes, GBC.std().insets(0, 5, 10, 0));
+        ButtonGroup bgResolution = new ButtonGroup();
+        grabRes1.setToolTipText(tr("High resolution (1000x800)"));
+        grabRes2.setToolTipText(tr("Medium resolution (800x600)"));
+        grabRes3.setToolTipText(tr("Low resolution (600x400)"));
+        bgResolution.add(grabRes1);
+        bgResolution.add(grabRes2);
+        bgResolution.add(grabRes3);
+        String currentResolution = Main.pref.get("cadastrewms.resolution", "high");
+        if (currentResolution.equals("high"))
+            grabRes1.setSelected(true);
+        if (currentResolution.equals("medium"))
+            grabRes2.setSelected(true);
+        if (currentResolution.equals("low"))
+            grabRes3.setSelected(true);
+        cadastrewms.add(grabRes1, GBC.std().insets(5, 0, 5, 0));
+        cadastrewms.add(grabRes2, GBC.std().insets(5, 0, 5, 0));
+        cadastrewms.add(grabRes3, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 0, 5));
+
+        // option to select image zooming interpolation method
+        JLabel jLabelImageZoomInterpolation = new JLabel(tr("Image filter interpolation:"));
+        cadastrewms.add(jLabelImageZoomInterpolation, GBC.std().insets(0, 0, 10, 0));
+        imageInterpolationMethod.addItem(tr("Nearest-Neighbor (fastest) [ Default ]"));
+        imageInterpolationMethod.addItem(tr("Bilinear (fast)"));
+        imageInterpolationMethod.addItem(tr("Bicubic (slow)"));
+        String savedImageInterpolationMethod = Main.pref.get("cadastrewms.imageInterpolation", "standard");
+        if (savedImageInterpolationMethod.equals("bilinear"))
+            imageInterpolationMethod.setSelectedIndex(1);
+        else if (savedImageInterpolationMethod.equals("bicubic"))
+            imageInterpolationMethod.setSelectedIndex(2);
+        else
+            imageInterpolationMethod.setSelectedIndex(0);
+        cadastrewms.add(imageInterpolationMethod, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 200, 5));
+
+        // separator
+        cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
+
+        // the vectorized images multiplier
+        JLabel jLabelScale = new JLabel(tr("Vector images grab multiplier:"));
+        cadastrewms.add(jLabelScale, GBC.std().insets(0, 5, 10, 0));
+        ButtonGroup bgGrabMultiplier = new ButtonGroup();
+        ActionListener multiplierActionListener = new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+              AbstractButton button = (AbstractButton) actionEvent.getSource();
+              grabMultiplier4Size.setEnabled(button == grabMultiplier4);
+            }
+          };
+        grabMultiplier1.setIcon(ImageProvider.get("preferences", "unsel_box_1"));
+        grabMultiplier1.setSelectedIcon(ImageProvider.get("preferences", "sel_box_1"));
+        grabMultiplier1.addActionListener(multiplierActionListener);
+        grabMultiplier1.setToolTipText(tr("Grab one image full screen"));
+        grabMultiplier2.setIcon(ImageProvider.get("preferences", "unsel_box_2"));
+        grabMultiplier2.setSelectedIcon(ImageProvider.get("preferences", "sel_box_2"));
+        grabMultiplier2.addActionListener(multiplierActionListener);
+        grabMultiplier2.setToolTipText(tr("Grab smaller images (higher quality but use more memory)"));
+        grabMultiplier3.setIcon(ImageProvider.get("preferences", "unsel_box_3"));
+        grabMultiplier3.setSelectedIcon(ImageProvider.get("preferences", "sel_box_3"));
+        grabMultiplier3.addActionListener(multiplierActionListener);
+        grabMultiplier3.setToolTipText(tr("Grab smaller images (higher quality but use more memory)"));
+        grabMultiplier4.setIcon(ImageProvider.get("preferences", "unsel_box_4"));
+        grabMultiplier4.setSelectedIcon(ImageProvider.get("preferences", "sel_box_4"));
+        grabMultiplier4.addActionListener(multiplierActionListener);
+        grabMultiplier4.setToolTipText(tr("Fixed size square (default is 100m)"));
+        bgGrabMultiplier.add(grabMultiplier1);
+        bgGrabMultiplier.add(grabMultiplier2);
+        bgGrabMultiplier.add(grabMultiplier3);
+        bgGrabMultiplier.add(grabMultiplier4);
+        String currentScale = Main.pref.get("cadastrewms.scale", DEFAULT_GRAB_MULTIPLIER);
+        if (currentScale.equals(Scale.X1.value))
+            grabMultiplier1.setSelected(true);
+        if (currentScale.equals(Scale.X2.value))
+            grabMultiplier2.setSelected(true);
+        if (currentScale.equals(Scale.X3.value))
+            grabMultiplier3.setSelected(true);
+        if (currentScale.equals(Scale.SQUARE_100M.value))
+            grabMultiplier4.setSelected(true);
+        cadastrewms.add(grabMultiplier1, GBC.std().insets(5, 0, 5, 0));
+        cadastrewms.add(grabMultiplier2, GBC.std().insets(5, 0, 5, 0));
+        cadastrewms.add(grabMultiplier3, GBC.std().insets(5, 0, 5, 0));
+        cadastrewms.add(grabMultiplier4, GBC.std().insets(5, 0, 5, 0));
+        int squareSize = getNumber("cadastrewms.squareSize", DEFAULT_SQUARE_SIZE);
+        grabMultiplier4Size.setText(String.valueOf(squareSize));
+        grabMultiplier4Size.setToolTipText(tr("Fixed size (from 25 to 1000 meters)"));
+        grabMultiplier4Size.setEnabled(currentScale.equals(Scale.SQUARE_100M.value));
+        cadastrewms.add(grabMultiplier4Size, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 0, 5));
+
+        // WMS layers selection
+        JLabel jLabelLayers = new JLabel(tr("Layers:"));
+        cadastrewms.add(jLabelLayers, GBC.std().insets(0, 5, 10, 0));
+        layerLS3.setSelected(Main.pref.getBoolean("cadastrewms.layerWater", true));
+        layerLS3.setToolTipText(tr("Sea, rivers, swimming pools."));
+        cadastrewms.add(layerLS3, GBC.std().insets(5, 0, 5, 0));
+        layerLS2.setSelected(Main.pref.getBoolean("cadastrewms.layerBuilding", true));
+        layerLS2.setToolTipText(tr("Buildings, covers, underground constructions."));
+        cadastrewms.add(layerLS2, GBC.std().insets(5, 0, 5, 0));
+        layerLS1.setSelected(Main.pref.getBoolean("cadastrewms.layerSymbol", true));
+        layerLS1.setToolTipText(tr("Symbols like cristian cross."));
+        cadastrewms.add(layerLS1, GBC.std().insets(5, 0, 5, 0));
+        layerParcel.setSelected(Main.pref.getBoolean("cadastrewms.layerParcel", true));
+        layerParcel.setToolTipText(tr("Parcels."));
+        cadastrewms.add(layerParcel, GBC.eop().insets(5, 0, 5, 0));
+        layerLabel.setSelected(Main.pref.getBoolean("cadastrewms.layerLabel", true));
+        layerLabel.setToolTipText(tr("Parcels numbers, street names."));
+        cadastrewms.add(layerLabel, GBC.std().insets(70, 0, 5, 0));
+        layerNumero.setSelected(Main.pref.getBoolean("cadastrewms.layerNumero", true));
+        layerNumero.setToolTipText(tr("Address, houses numbers."));
+        cadastrewms.add(layerNumero, GBC.std().insets(5, 0, 5, 0));
+        layerLieudit.setSelected(Main.pref.getBoolean("cadastrewms.layerLieudit", true));
+        layerLieudit.setToolTipText(tr("Locality, hamlet, place."));
+        cadastrewms.add(layerLieudit, GBC.std().insets(5, 0, 5, 0));
+        layerSection.setSelected(Main.pref.getBoolean("cadastrewms.layerSection", true));
+        layerSection.setToolTipText(tr("Cadastral sections and subsections."));
+        cadastrewms.add(layerSection, GBC.std().insets(5, 0, 5, 0));
+        layerCommune.setSelected(Main.pref.getBoolean("cadastrewms.layerCommune", true));
+        layerCommune.setToolTipText(tr("Municipality administrative borders."));
+        cadastrewms.add(layerCommune, GBC.eop().insets(5, 0, 5, 0));
+
+        // separator
+        cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
+
+        // for raster images (not vectorized), image grab divider (from 1 to 12)
+        String savedRasterDivider = Main.pref.get("cadastrewms.rasterDivider", DEFAULT_RASTER_DIVIDER);
+        JLabel jLabelRasterDivider = new JLabel(tr("Raster images grab multiplier:"));
+        rasterDivider.setText(savedRasterDivider);
+        rasterDivider.setToolTipText("Raster image grab division, from 1 to 12; 12 is very high definition");
+        cadastrewms.add(jLabelRasterDivider, GBC.std().insets(0, 5, 10, 0));
+        cadastrewms.add(rasterDivider, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 200, 5));
+        // 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.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));
+        // option to use 2 bits colors only
+        simplify2BitsColors.setSelected(Main.pref.getBoolean("cadastrewms.raster2bitsColors", false));
+        simplify2BitsColors.setToolTipText(tr("Replace greyscale by white color (smaller files and memory usage)."));
+        cadastrewms.add(simplify2BitsColors, 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));
+        ButtonGroup bgCrosspieces = new ButtonGroup();
+        int crosspieces = getNumber("cadastrewms.crosspieces", DEFAULT_CROSSPIECES);
+        if (crosspieces == 0) crosspiece1.setSelected(true);
+        if (crosspieces == 1) crosspiece2.setSelected(true);
+        if (crosspieces == 2) crosspiece3.setSelected(true);
+        if (crosspieces == 3) crosspiece4.setSelected(true);
+        bgCrosspieces.add(crosspiece1);
+        bgCrosspieces.add(crosspiece2);
+        bgCrosspieces.add(crosspiece3);
+        bgCrosspieces.add(crosspiece4);
+        cadastrewms.add(crosspiece1, GBC.std().insets(5, 0, 5, 0));
+        cadastrewms.add(crosspiece2, GBC.std().insets(5, 0, 5, 0));
+        cadastrewms.add(crosspiece3, GBC.std().insets(5, 0, 5, 0));
+        cadastrewms.add(crosspiece4, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 0, 5));
+
+        // separator
+        cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
+
+        // option to enable automatic caching
+        enableCache.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                jLabelCacheSize.setEnabled(enableCache.isSelected());
+                cacheSize.setEnabled(enableCache.isSelected());
+            }
+        });
+        enableCache.setSelected(Main.pref.getBoolean("cadastrewms.enableCaching", true));
+        enableCache.setToolTipText(tr("Allows an automatic caching"));
+        cadastrewms.add(enableCache, GBC.eop().insets(0, 0, 0, 0));
+
+        // option to fix the cache size(in MB)
+        int size = getNumber("cadastrewms.cacheSize", DEFAULT_CACHE_SIZE);
+        cacheSize.setText(String.valueOf(size));
+        cacheSize.setToolTipText(tr("Oldest files are automatically deleted when this size is exceeded"));
+        cadastrewms.add(jLabelCacheSize, GBC.std().insets(20, 0, 0, 0));
+        cadastrewms.add(cacheSize, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 200, 5));
+
+        // separator
+        cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
+
+        // option to select the first WMS layer
+        autoFirstLayer.setSelected(Main.pref.getBoolean("cadastrewms.autoFirstLayer", false));
+        autoFirstLayer.setToolTipText(tr("Automatically selects the first WMS layer if multiple layers exist when grabbing."));
+        cadastrewms.add(autoFirstLayer, GBC.eop().insets(0, 0, 0, 0));
+
+        // separator
+        cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
+
+        // option to use or not relations in addresses
+        dontUseRelation.setSelected(Main.pref.getBoolean("cadastrewms.addr.dontUseRelation", false));
+        dontUseRelation.setToolTipText(tr("Enable this to use the tag \"add:street\" on nodes."));
+        cadastrewms.add(dontUseRelation, GBC.eop().insets(0, 0, 0, 0));
+
+        // end of dialog, scroll bar
+        cadastrewms.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
+        JScrollPane scrollpane = new JScrollPane(cadastrewms);
+        scrollpane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+        cadastrewmsMast.add(scrollpane, GBC.eol().fill(GBC.BOTH));
+    }
+
+    @Override
+    public boolean ok() {
+        Main.pref.put("cadastrewms.source", sourcing.getText());
+        CadastrePlugin.source = sourcing.getText();
+        Main.pref.put("cadastrewms.alterColors", alterColors.isSelected());
+        Main.pref.put("cadastrewms.invertGrey", reversGrey.isSelected());
+        Main.pref.put("cadastrewms.backgroundTransparent", transparency.isSelected());
+        Main.pref.put("cadastrewms.brightness", Float.toString((float) sliderTrans.getValue()/10));
+        Main.pref.put("cadastrewms.drawBoundaries", drawBoundaries.isSelected());
+        if (grabRes1.isSelected())
+            Main.pref.put("cadastrewms.resolution", "high");
+        else if (grabRes2.isSelected())
+            Main.pref.put("cadastrewms.resolution", "medium");
+        else if (grabRes3.isSelected())
+            Main.pref.put("cadastrewms.resolution", "low");
+        if (imageInterpolationMethod.getSelectedIndex() == 2)
+            Main.pref.put("cadastrewms.imageInterpolation", "bicubic");
+        else if (imageInterpolationMethod.getSelectedIndex() == 1)
+            Main.pref.put("cadastrewms.imageInterpolation", "bilinear");
+        else
+            Main.pref.put("cadastrewms.imageInterpolation", "standard");
+        if (grabMultiplier1.isSelected())
+            Main.pref.put("cadastrewms.scale", Scale.X1.toString());
+        else if (grabMultiplier2.isSelected())
+            Main.pref.put("cadastrewms.scale", Scale.X2.toString());
+        else if (grabMultiplier3.isSelected())
+            Main.pref.put("cadastrewms.scale", Scale.X3.toString());
+        else {
+            Main.pref.put("cadastrewms.scale", Scale.SQUARE_100M.toString());
+            try {
+                int squareSize = Integer.parseInt(grabMultiplier4Size.getText());
+                if (squareSize >= 25 && squareSize <= 1000)
+                    Main.pref.put("cadastrewms.squareSize", grabMultiplier4Size.getText());
+            } catch (NumberFormatException e) {
+                Main.debug(e);
+            }
+        }
+        Main.pref.put("cadastrewms.layerWater", layerLS3.isSelected());
+        Main.pref.put("cadastrewms.layerBuilding", layerLS2.isSelected());
+        Main.pref.put("cadastrewms.layerSymbol", layerLS1.isSelected());
+        Main.pref.put("cadastrewms.layerParcel", layerParcel.isSelected());
+        Main.pref.put("cadastrewms.layerLabel", layerLabel.isSelected());
+        Main.pref.put("cadastrewms.layerNumero", layerNumero.isSelected());
+        Main.pref.put("cadastrewms.layerLieudit", layerLieudit.isSelected());
+        Main.pref.put("cadastrewms.layerSection", layerSection.isSelected());
+        Main.pref.put("cadastrewms.layerCommune", layerCommune.isSelected());
+        try {
+            int i = Integer.parseInt(rasterDivider.getText());
+            if (i > 0 && i < 13)
+                Main.pref.put("cadastrewms.rasterDivider", String.valueOf(i));
+        } catch (NumberFormatException e) {
+            Main.debug(e);
+        }
+        Main.pref.put("cadastrewms.noImageCropping", disableImageCropping.isSelected());
+        Main.pref.put("cadastrewms.useTA", enableTableauAssemblage.isSelected());
+        Main.pref.put("cadastrewms.raster2bitsColors", simplify2BitsColors.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");
+        else if (crosspiece4.isSelected()) Main.pref.put("cadastrewms.crosspieces", "3");
+        Main.pref.put("cadastrewms.enableCaching", enableCache.isSelected());
+
+        // spread data into objects instead of restarting the application
+        try {
+            CacheControl.cacheSize = Integer.parseInt(cacheSize.getText());
+            Main.pref.put("cadastrewms.cacheSize", String.valueOf(CacheControl.cacheSize));
+        } catch (NumberFormatException e) {
+            Main.debug(e);
+        }
+        Main.pref.put("cadastrewms.autoFirstLayer", autoFirstLayer.isSelected());
+        CacheControl.cacheEnabled = enableCache.isSelected();
+        Main.pref.put("cadastrewms.addr.dontUseRelation", dontUseRelation.isSelected());
+        CadastrePlugin.refreshConfiguration();
+        CadastrePlugin.refreshMenu();
+
+        return false;
+    }
+
+    private int getNumber(String pref_parameter, int def_value) {
+        try {
+            return Integer.parseInt(Main.pref.get(pref_parameter, String.valueOf(def_value)));
+        } catch (NumberFormatException e) {
+            return def_value;
+        }
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/preferences/Scale.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/preferences/Scale.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/preferences/Scale.java	(revision 33638)
@@ -0,0 +1,31 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.preferences;
+
+/**
+ * List of possible grab factors each time we call the grab action.
+ * X1 means that only one bounding box is grabbed where X2 means that the current
+ * view is split in 2x2 bounding boxes and X3 is 3x3 boxes.
+ * SQUARE_100M is a special value where bounding boxes have a fixed size of 100x100 meters
+ * and east,north are rounded to the lowest 100 meter as well, thus none of the bounding boxes
+ * are overlapping each others.
+ */
+public enum Scale {
+    X1("1"),
+    X2("2"),
+    X3("3"),
+    SQUARE_100M("4");
+
+    /**
+     * value is the string equivalent stored in the preferences file
+     */
+    public final String value;
+
+    Scale(String value) {
+        this.value = value;
+    }
+
+    @Override
+    public String toString() {
+        return value;
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/session/CadastreSessionExporter.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/session/CadastreSessionExporter.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/session/CadastreSessionExporter.java	(revision 33638)
@@ -0,0 +1,82 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.session;
+
+import java.awt.Component;
+import java.awt.GridBagLayout;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.io.session.SessionLayerExporter;
+import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+import org.openstreetmap.josm.tools.GBC;
+import org.w3c.dom.Element;
+
+public class CadastreSessionExporter implements SessionLayerExporter {
+
+    private WMSLayer layer;
+    private JCheckBox export;
+
+    public CadastreSessionExporter(WMSLayer layer) {
+        this.layer = layer;
+    }
+
+    @Override
+    public Collection<Layer> getDependencies() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Component getExportPanel() {
+        final JPanel p = new JPanel(new GridBagLayout());
+        export = new JCheckBox();
+        export.setSelected(true);
+        final JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEFT);
+        lbl.setToolTipText(layer.getToolTipText());
+        p.add(export, GBC.std());
+        p.add(lbl, GBC.std());
+        p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
+        return p;
+    }
+
+    @Override
+    public boolean shallExport() {
+        return export.isSelected();
+    }
+
+    @Override
+    public boolean requiresZip() {
+        return false;
+    }
+
+    @Override
+    public Element export(ExportSupport support) throws IOException {
+        Element layerEl = support.createElement("layer");
+        layerEl.setAttribute("type", "cadastre-fr");
+        layerEl.setAttribute("version", "0.1");
+
+        Element file = support.createElement("file");
+        layerEl.appendChild(file);
+
+        URI uri = layer.getAssociatedFile().toURI();
+        URL url = null;
+        try {
+            url = uri.toURL();
+        } catch (MalformedURLException e) {
+            throw new IOException(e);
+        }
+        file.appendChild(support.createTextNode(url.toString()));
+        return layerEl;
+    }
+
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/session/CadastreSessionImporter.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/session/CadastreSessionImporter.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/session/CadastreSessionImporter.java	(revision 33638)
@@ -0,0 +1,67 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.session;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URLDecoder;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.io.session.SessionLayerImporter;
+import org.openstreetmap.josm.io.session.SessionReader.ImportSupport;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.CacheControl;
+import org.openstreetmap.josm.plugins.fr.cadastre.wms.WMSLayer;
+import org.w3c.dom.Element;
+
+public class CadastreSessionImporter implements SessionLayerImporter {
+
+    @Override
+    public Layer load(Element elem, ImportSupport support,
+            ProgressMonitor progressMonitor) throws IOException,
+            IllegalDataException {
+        String version = elem.getAttribute("version");
+        if (!"0.1".equals(version)) {
+            throw new IllegalDataException(tr("Version ''{0}'' of meta data for imagery layer is not supported. Expected: 0.1", version));
+        }
+        try {
+            XPathFactory xPathFactory = XPathFactory.newInstance();
+            XPath xpath = xPathFactory.newXPath();
+            XPathExpression fileExp = xpath.compile("file/text()");
+            String fileStr = (String) fileExp.evaluate(elem, XPathConstants.STRING);
+            if (fileStr == null || fileStr.isEmpty()) {
+                throw new IllegalDataException(tr("File name expected for layer no. {0}", support.getLayerIndex()));
+            }
+
+            fileStr = URLDecoder.decode(fileStr, "UTF-8");
+            fileStr = fileStr.substring(fileStr.indexOf(":/")+2);
+            String filename = fileStr.substring(fileStr.lastIndexOf('/')+1, fileStr.length());
+            String ext = (filename.lastIndexOf('.') == -1) ? "" : filename.substring(filename.lastIndexOf('.')+1, filename.length());
+            // create layer and load cache
+            if (ext.length() == 3 && ext.substring(0, CacheControl.C_LAMBERT_CC_9Z.length()).equals(CacheControl.C_LAMBERT_CC_9Z))
+                ext = ext.substring(2);
+            else if (ext.length() == 4 && ext.substring(0, CacheControl.C_UTM20N.length()).equals(CacheControl.C_UTM20N))
+                ext = ext.substring(3);
+            else if (ext.length() == 2 || ext.length() > 4)
+                throw new IllegalDataException(tr("Unexpected file extension. {0}", ext));
+
+            int layoutZone = Integer.parseInt(ext)-1;
+            WMSLayer wmsLayer = new WMSLayer("", "", layoutZone);
+            File file = new File(fileStr);
+            wmsLayer.grabThread.getCacheControl().loadCache(file, layoutZone);
+            return wmsLayer;
+
+        } catch (XPathExpressionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheControl.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheControl.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheControl.java	(revision 33638)
@@ -0,0 +1,237 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+import org.openstreetmap.josm.plugins.fr.cadastre.preferences.CadastrePreferenceSetting;
+
+/**
+ * This class handles the WMS layer cache mechanism. The design is oriented for a good performance (no
+ * wait status on GUI, fast saving even in big file). A separate thread is created for each WMS
+ * layer to not suspend the GUI until disk I/O is terminated (a file for the cache can take
+ * several MB's). If the cache file already exists, new images are just appended to the file
+ * (performance). Since we use the ObjectStream methods, it is required to modify the standard
+ * ObjectOutputStream in order to have objects appended readable (otherwise a stream header
+ * is inserted before each append and an exception is raised at objects read).
+ */
+public class CacheControl implements Runnable {
+
+    public static final String C_LAMBERT_CC_9Z = "CC";
+
+    public static final String C_UTM20N = "UTM";
+
+    public static class ObjectOutputStreamAppend extends ObjectOutputStream {
+        public ObjectOutputStreamAppend(OutputStream out) throws IOException {
+            super(out);
+        }
+
+        @Override
+        protected void writeStreamHeader() throws IOException {
+            reset();
+        }
+    }
+
+    public static boolean cacheEnabled = true;
+
+    public static int cacheSize = 500;
+
+    public WMSLayer wmsLayer;
+
+    private ArrayList<GeorefImage> imagesToSave = new ArrayList<>();
+    private Lock imagesLock = new ReentrantLock();
+
+    public boolean isCachePipeEmpty() {
+        imagesLock.lock();
+        boolean ret = imagesToSave.isEmpty();
+        imagesLock.unlock();
+        return ret;
+    }
+
+    public CacheControl(WMSLayer wmsLayer) {
+        cacheEnabled = Main.pref.getBoolean("cadastrewms.enableCaching", true);
+        this.wmsLayer = wmsLayer;
+        try {
+            cacheSize = Integer.parseInt(Main.pref.get("cadastrewms.cacheSize", String.valueOf(CadastrePreferenceSetting.DEFAULT_CACHE_SIZE)));
+        } catch (NumberFormatException e) {
+            cacheSize = CadastrePreferenceSetting.DEFAULT_CACHE_SIZE;
+        }
+        File path = new File(CadastrePlugin.cacheDir);
+        if (!path.exists())
+            path.mkdirs();
+        else // check directory capacity
+            checkDirSize(path);
+        new Thread(this).start();
+    }
+
+    private static void checkDirSize(File path) {
+        if (cacheSize != 0) {
+            long size = 0;
+            long oldestFileDate = Long.MAX_VALUE;
+            int oldestFile = 0;
+            File[] files = path.listFiles();
+            for (int i = 0; i < files.length; i++) {
+                size += files[i].length();
+                if (files[i].lastModified() < oldestFileDate) {
+                    oldestFile = i;
+                    oldestFileDate = files[i].lastModified();
+                }
+            }
+            if (size > (long) cacheSize*1024*1024) {
+                Main.info("Delete oldest file  \""+ files[oldestFile].getName()
+                        + "\" in cache dir to stay under the limit of " + cacheSize + " MB.");
+                files[oldestFile].delete();
+                checkDirSize(path);
+            }
+        }
+    }
+
+    public boolean loadCacheIfExist() {
+        if (!CadastrePlugin.isCadastreProjection()) {
+            CadastrePlugin.askToChangeProjection();
+        }
+        File file = new File(CadastrePlugin.cacheDir + wmsLayer.getName() + "." + WMSFileExtension());
+        if (file.exists()) {
+            int reply = GuiHelper.runInEDTAndWaitAndReturn(new Callable<Integer>() {
+                @Override
+                public Integer call() throws Exception {
+                    JOptionPane pane = new JOptionPane(
+                            tr("Location \"{0}\" found in cache.\n"+
+                            "Load cache first ?\n"+
+                            "(No = new cache)", wmsLayer.getName()),
+                            JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION, null);
+                    // this below is a temporary workaround to fix the "always on top" issue
+                    JDialog dialog = pane.createDialog(Main.parent, tr("Select Feuille"));
+                    CadastrePlugin.prepareDialog(dialog);
+                    dialog.setVisible(true);
+                    return (Integer) pane.getValue();
+                    // till here
+                }
+            });
+
+            if (reply == JOptionPane.OK_OPTION && loadCache(file, wmsLayer.getLambertZone())) {
+                return true;
+            } else {
+                delete(file);
+            }
+        }
+        return false;
+    }
+
+    public void deleteCacheFile() {
+        delete(new File(CadastrePlugin.cacheDir + wmsLayer.getName() + "." + WMSFileExtension()));
+    }
+
+    private static void delete(File file) {
+        Main.info("Delete file "+file);
+        if (file.exists())
+            file.delete();
+        while (file.exists()) { // wait until file is really gone (otherwise appends to existing one)
+            CadastrePlugin.safeSleep(500);
+        }
+    }
+
+    public boolean loadCache(File file, int currentLambertZone) {
+        boolean successfulRead = false;
+        try (
+            FileInputStream fis = new FileInputStream(file);
+            ObjectInputStream ois = new ObjectInputStream(fis);
+        ) {
+            successfulRead = wmsLayer.read(file, ois, currentLambertZone);
+        } catch (IOException | ClassNotFoundException ex) {
+            Main.error(ex);
+            GuiHelper.runInEDTAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    JOptionPane.showMessageDialog(Main.parent, tr("Error loading file.\nProbably an old version of the cache file."),
+                            tr("Error"), JOptionPane.ERROR_MESSAGE);
+                }
+            });
+            return false;
+        }
+        if (successfulRead && wmsLayer.isRaster()) {
+            // serialized raster bufferedImage hangs-up on Java6. Recreate them here
+            wmsLayer.getImage(0).image = RasterImageModifier.fixRasterImage(wmsLayer.getImage(0).image);
+        }
+        return successfulRead;
+    }
+
+    public synchronized void saveCache(GeorefImage image) {
+        imagesLock.lock();
+        this.imagesToSave.add(image);
+        this.notifyAll();
+        imagesLock.unlock();
+    }
+
+    /**
+     * Thread saving the grabbed images in background.
+     */
+    @Override
+    public synchronized void run() {
+        for (;;) {
+            imagesLock.lock();
+            int size = imagesToSave.size();
+            imagesLock.unlock();
+            if (size > 0) {
+                File file = new File(CadastrePlugin.cacheDir + wmsLayer.getName() + "." + WMSFileExtension());
+                try {
+                    if (file.exists()) {
+                        try (ObjectOutputStreamAppend oos = new ObjectOutputStreamAppend(
+                                new BufferedOutputStream(new FileOutputStream(file, true)))) {
+                            for (int i = 0; i < size; i++) {
+                                oos.writeObject(imagesToSave.get(i));
+                            }
+                        }
+                    } else {
+                        try (ObjectOutputStream oos = new ObjectOutputStream(
+                                new BufferedOutputStream(new FileOutputStream(file)))) {
+                            wmsLayer.write(file, oos);
+                            for (int i = 0; i < size; i++) {
+                                oos.writeObject(imagesToSave.get(i));
+                            }
+                        }
+                    }
+                } catch (IOException e) {
+                    Main.error(e);
+                }
+                imagesLock.lock();
+                for (int i = 0; i < size; i++) {
+                    imagesToSave.remove(0);
+                }
+                imagesLock.unlock();
+            }
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                Main.error(e);
+            }
+        }
+    }
+
+    private String WMSFileExtension() {
+        String ext = String.valueOf(wmsLayer.getLambertZone() + 1);
+        if (CadastrePlugin.isLambert_cc9())
+            ext = C_LAMBERT_CC_9Z + ext;
+        else if (CadastrePlugin.isUtm_france_dom())
+            ext = C_UTM20N + ext;
+        return ext;
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheFileLambert4ZoneFilter.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheFileLambert4ZoneFilter.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheFileLambert4ZoneFilter.java	(revision 33638)
@@ -0,0 +1,55 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.File;
+import java.util.Locale;
+
+import javax.swing.filechooser.FileFilter;
+
+public final class CacheFileLambert4ZoneFilter extends FileFilter {
+
+    /**
+     * Derived from ExtensionFileFilter writen by imi
+     */
+    private final String extension;
+    private final String description;
+
+    public static final CacheFileLambert4ZoneFilter[] filters = {
+        new CacheFileLambert4ZoneFilter("1", tr("Lambert Zone {0} cache file (.{0})", 1)),
+        new CacheFileLambert4ZoneFilter("2", tr("Lambert Zone {0} cache file (.{0})", 2)),
+        new CacheFileLambert4ZoneFilter("3", tr("Lambert Zone {0} cache file (.{0})", 3)),
+        new CacheFileLambert4ZoneFilter("4", tr("Lambert Zone {0} cache file (.{0})", 4))
+        };
+
+    /**
+     * Construct an extension file filter by giving the extension to check after.
+     *
+     */
+    private CacheFileLambert4ZoneFilter(String extension, String description) {
+        this.extension = extension;
+        this.description = description;
+    }
+
+    public boolean acceptName(String filename) {
+        String name = filename.toLowerCase(Locale.FRANCE);
+        for (String ext : extension.split(",")) {
+            if (name.endsWith("." + ext))
+                return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean accept(File pathname) {
+        if (pathname.isDirectory())
+            return true;
+        return acceptName(pathname.getName());
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheFileLambert9ZoneFilter.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheFileLambert9ZoneFilter.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheFileLambert9ZoneFilter.java	(revision 33638)
@@ -0,0 +1,60 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.File;
+
+import javax.swing.filechooser.FileFilter;
+
+public final class CacheFileLambert9ZoneFilter extends FileFilter {
+
+    /**
+     * Derived from ExtensionFileFilter writen by imi
+     */
+    private final String extension;
+    private final String description;
+
+    public static CacheFileLambert9ZoneFilter[] filters = {
+        new CacheFileLambert9ZoneFilter("cc1", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 1)),
+        new CacheFileLambert9ZoneFilter("cc2", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 2)),
+        new CacheFileLambert9ZoneFilter("cc3", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 3)),
+        new CacheFileLambert9ZoneFilter("cc4", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 4)),
+        new CacheFileLambert9ZoneFilter("cc5", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 5)),
+        new CacheFileLambert9ZoneFilter("cc6", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 6)),
+        new CacheFileLambert9ZoneFilter("cc7", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 7)),
+        new CacheFileLambert9ZoneFilter("cc8", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 8)),
+        new CacheFileLambert9ZoneFilter("cc9", tr("Lambert CC9 Zone {0} cache file (.CC{0})", 9))
+        };
+
+    /**
+     * Construct an extension file filter by giving the extension to check after.
+     *
+     */
+    private CacheFileLambert9ZoneFilter(String extension, String description) {
+        this.extension = extension;
+        this.description = description;
+    }
+
+    public boolean acceptName(String filename) {
+        String name = filename.toLowerCase();
+        for (String ext : extension.split(",")) {
+            if (name.endsWith("." + ext))
+                return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean accept(File pathname) {
+        if (pathname.isDirectory())
+            return true;
+        return acceptName(pathname.getName());
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheFileUTM20NFilter.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheFileUTM20NFilter.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CacheFileUTM20NFilter.java	(revision 33638)
@@ -0,0 +1,55 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.File;
+
+import javax.swing.filechooser.FileFilter;
+
+public final class CacheFileUTM20NFilter extends FileFilter {
+
+    /**
+     * Derived from ExtensionFileFilter writen by imi
+     */
+    private final String extension;
+    private final String description;
+
+    public static CacheFileUTM20NFilter[] filters = {
+        new CacheFileUTM20NFilter("utm1", tr("Guadeloupe Fort-Marigot cache file (.UTM1)")),
+        new CacheFileUTM20NFilter("utm2", tr("Guadeloupe Ste-Anne cache file (.UTM2)")),
+        new CacheFileUTM20NFilter("utm3", tr("Martinique Fort Desaix cache file (.UTM3)")),
+        new CacheFileUTM20NFilter("utm4", tr("Reunion RGR92 cache file (.UTM4)"))
+        };
+
+    /**
+     * Construct an extension file filter by giving the extension to check after.
+     *
+     */
+    private CacheFileUTM20NFilter(String extension, String description) {
+        this.extension = extension;
+        this.description = description;
+    }
+
+    public boolean acceptName(String filename) {
+        String name = filename.toLowerCase();
+        for (String ext : extension.split(",")) {
+            if (name.endsWith("." + ext))
+                return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean accept(File pathname) {
+        if (pathname.isDirectory())
+            return true;
+        return acceptName(pathname.getName());
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CadastreGrabber.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CadastreGrabber.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CadastreGrabber.java	(revision 33638)
@@ -0,0 +1,94 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.imageio.ImageIO;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+
+public class CadastreGrabber {
+
+    private CadastreInterface wmsInterface = new CadastreInterface();
+
+    public GeorefImage grab(WMSLayer wmsLayer, EastNorth lambertMin, EastNorth lambertMax)
+            throws IOException, OsmTransferException {
+        try {
+            URL url = null;
+            if (wmsLayer.isRaster())
+                url = getURLRaster(wmsLayer, lambertMin, lambertMax);
+            else
+                url = getURLVector(lambertMin, lambertMax);
+            BufferedImage img = grab(url);
+            if (img == null)
+                throw new OsmTransferException(url.toString());
+            ImageModifier imageModified;
+            if (wmsLayer.isRaster())
+                imageModified = new RasterImageModifier(img);
+            else
+                imageModified = new VectorImageModifier(img, false);
+            return new GeorefImage(imageModified.getBufferedImage(), lambertMin, lambertMax, wmsLayer);
+        } catch (MalformedURLException e) {
+            throw (IOException) new IOException(tr("CadastreGrabber: Illegal url.")).initCause(e);
+        }
+    }
+
+    private static URL getURLRaster(WMSLayer wmsLayer, EastNorth lambertMin, EastNorth lambertMax) throws MalformedURLException {
+        // GET /scpc/wms?version=1.1&request=GetMap&layers=CDIF:PMC@QH4480001701&format=image/png&bbox=-1186,0,13555,8830&width=576&height=345&exception=application/vnd.ogc.se_inimage&styles= HTTP/1.1
+        final int cRasterX = CadastrePlugin.imageWidth; // keep width constant and adjust width to original image proportions
+        String str = CadastreInterface.BASE_URL+"/scpc/wms?version=1.1&request=GetMap";
+        str += "&layers=CDIF:PMC@";
+        str += wmsLayer.getCodeCommune();
+        str += "&format=image/png";
+        //str += "&format=image/jpeg";
+        str += "&bbox=";
+        str += wmsLayer.eastNorth2raster(lambertMin, lambertMax);
+        str += "&width="+cRasterX+"&height="; // maximum allowed by wms server (576/345, 800/378, 1000/634)
+        str += (int) (cRasterX*(wmsLayer.communeBBox.max.getY() - wmsLayer.communeBBox.min.getY())/(wmsLayer.communeBBox.max.getX() - wmsLayer.communeBBox.min.getX()));
+        str += "&exception=application/vnd.ogc.se_inimage&styles="; // required for raster images
+        Main.info("URL="+str);
+        return new URL(str.replace(" ", "%20"));
+    }
+
+    private static URL buildURLVector(String layers, String styles,
+            int width, int height,
+            EastNorth lambertMin, EastNorth lambertMax) throws MalformedURLException {
+        String str = CadastreInterface.BASE_URL+"/scpc/wms?version=1.1&request=GetMap";
+        str += "&layers="+ layers;
+        str += "&format=image/png";
+        str += "&bbox="+lambertMin.east()+",";
+        str += lambertMin.north() + ",";
+        str += lambertMax.east() + ",";
+        str += lambertMax.north();
+        str += "&width="+width+"&height="+height;
+        str += "&exception=application/vnd.ogc.se_inimage"; // works also without (but slower ?)
+        str += "&styles=" + styles;
+        Main.info("URL="+str);
+        return new URL(str.replace(" ", "%20"));
+    }
+
+    private static URL getURLVector(EastNorth lambertMin, EastNorth lambertMax) throws MalformedURLException {
+        return buildURLVector(CadastrePlugin.grabLayers, CadastrePlugin.grabStyles,
+                CadastrePlugin.imageWidth, CadastrePlugin.imageHeight,
+                lambertMin, lambertMax);
+    }
+
+    private BufferedImage grab(URL url) throws IOException, OsmTransferException {
+        try (InputStream is = wmsInterface.getContent(url)) {
+            return ImageIO.read(is);
+        }
+    }
+
+    public CadastreInterface getWmsInterface() {
+        return wmsInterface;
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CadastreInterface.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CadastreInterface.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/CadastreInterface.java	(revision 33638)
@@ -0,0 +1,608 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.CookieHandler;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.validation.util.Entities;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.io.ProgressInputStream;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+import org.openstreetmap.josm.tools.GBC;
+
+public class CadastreInterface {
+    public boolean downloadCanceled;
+    private HttpURLConnection urlConn;
+
+    private String cookie;
+    private String interfaceRef;
+    private String lastWMSLayerName;
+    private URL searchFormURL;
+    private List<String> listOfCommunes = new ArrayList<>();
+    private List<String> listOfTA = new ArrayList<>();
+    static class PlanImage {
+        String name;
+        String ref;
+        PlanImage(String name, String ref) {
+            this.name = name;
+            this.ref = ref;
+        }
+    }
+
+    private List<PlanImage> listOfFeuilles = new ArrayList<>();
+    private long cookieTimestamp;
+
+    public static final String BASE_URL = "https://www.cadastre.gouv.fr";
+    static final String C_IMAGE_FORMAT = "Cette commune est au format ";
+    static final String C_COMMUNE_LIST_START = "<select name=\"codeCommune\"";
+    static final String C_COMMUNE_LIST_END = "</select>";
+    static final String C_OPTION_LIST_START = "<option value=\"";
+    static final String C_OPTION_LIST_END = "</option>";
+    static final String C_BBOX_COMMUN_START = "new GeoBox(";
+    static final String C_BBOX_COMMUN_END = ")";
+
+    static final String C_INTERFACE_VECTOR = "afficherCarteCommune.do";
+    static final String C_INTERFACE_RASTER_TA = "afficherCarteTa.do";
+    static final String C_INTERFACE_RASTER_FEUILLE = "afficherCarteFeuille.do";
+    static final String C_IMAGE_LINK_START = "<a href=\"#\" class=\"raster\" onClick=\"popup('afficherCarteFeuille.do?f=";
+    static final String C_TA_IMAGE_LINK_START = "<a href=\"#\" class=\"raster\" onClick=\"popup('afficherCarteTa.do?f=";
+    static final String C_IMAGE_NAME_START = ">Feuille ";
+    static final String C_TA_IMAGE_NAME_START = "Tableau d'assemblage <strong>";
+
+    static final long COOKIE_EXPIRATION = 30 * 60 * 1000L; // 30 minutes expressed in milliseconds
+
+    static final int RETRIES_GET_COOKIE = 10; // 10 times every 3 seconds means 30 seconds trying to get a cookie
+
+    public boolean retrieveInterface(WMSLayer wmsLayer) throws DuplicateLayerException, WMSException {
+        if (wmsLayer.getName().isEmpty())
+            return false;
+        boolean isCookieExpired = isCookieExpired();
+        if (wmsLayer.getName().equals(lastWMSLayerName) && !isCookieExpired)
+            return true;
+        if (!wmsLayer.getName().equals(lastWMSLayerName))
+            interfaceRef = null;
+        // open the session with the French Cadastre web front end
+        downloadCanceled = false;
+        try {
+            if (cookie == null || isCookieExpired) {
+                getCookie();
+                interfaceRef = null;
+            }
+            if (cookie == null)
+                throw new WMSException(tr("Cannot open a new client session.\nServer in maintenance or temporary overloaded."));
+            if (interfaceRef == null) {
+                    getInterface(wmsLayer);
+                    this.lastWMSLayerName = wmsLayer.getName();
+            }
+            openInterface();
+        } catch (IOException e) {
+            Main.error(e);
+            GuiHelper.runInEDT(() ->
+                JOptionPane.showMessageDialog(Main.parent,
+                    tr("Town/city {0} not found or not available\n" +
+                            "or action canceled", wmsLayer.getLocation())));
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     *
+     * @return true if a cookie is delivered by WMS and false is WMS is not opening a client session
+     *         (too many clients or in maintenance)
+     */
+    private void getCookie() throws IOException {
+        boolean success = false;
+        int retries = RETRIES_GET_COOKIE;
+        try {
+            searchFormURL = new URL(BASE_URL + "/scpc/accueil.do");
+            while (!success && retries > 0) {
+                urlConn = (HttpURLConnection) searchFormURL.openConnection();
+                urlConn.setRequestProperty("Connection", "close");
+                urlConn.setRequestMethod("GET");
+                urlConn.connect();
+                if (urlConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
+                    Main.info("GET "+searchFormURL);
+                    BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), StandardCharsets.UTF_8));
+                    while (in.readLine() != null) {
+                        // read the buffer otherwise we sent POST too early
+                    }
+                    success = true;
+                    // See https://bugs.openjdk.java.net/browse/JDK-8036017
+                    // When a cookie handler is setup, "Set-Cookie" header returns empty values
+                    CookieHandler cookieHandler = CookieHandler.getDefault();
+                    if (cookieHandler != null) {
+                        if (handleCookie(cookieHandler.get(searchFormURL.toURI(), new HashMap<String, List<String>>()).get("Cookie").get(0))) {
+                            break;
+                        }
+                    } else {
+                        String headerName;
+                        for (int i = 1; (headerName = urlConn.getHeaderFieldKey(i)) != null; i++) {
+                            if ("Set-Cookie".equals(headerName) && handleCookie(urlConn.getHeaderField(i))) {
+                                break;
+                            }
+                        }
+                    }
+                } else {
+                    Main.warn("Request to home page failed. Http error:"+urlConn.getResponseCode()+". Try again "+retries+" times");
+                    CadastrePlugin.safeSleep(3000);
+                    retries--;
+                }
+            }
+        } catch (MalformedURLException | URISyntaxException e) {
+            throw new IOException("Illegal url.", e);
+        }
+    }
+
+    private boolean handleCookie(String pCookie) {
+        cookie = pCookie;
+        if (cookie == null || cookie.isEmpty()) {
+            Main.warn("received empty cookie");
+            cookie = null;
+        } else {
+            int index = cookie.indexOf(';');
+            if (index > -1) {
+                cookie = cookie.substring(0, index);
+            }
+            cookieTimestamp = new Date().getTime();
+            Main.info("received cookie=" + cookie + " at " + new Date(cookieTimestamp));
+        }
+        return cookie != null;
+    }
+
+    public void resetCookie() {
+        lastWMSLayerName = null;
+        cookie = null;
+    }
+
+    public boolean isCookieExpired() {
+        long now = new Date().getTime();
+        if ((now - cookieTimestamp) > COOKIE_EXPIRATION) {
+            Main.info("cookie received at "+new Date(cookieTimestamp)+" expired (now is "+new Date(now)+")");
+            return true;
+        }
+        return false;
+    }
+
+    public void resetInterfaceRefIfNewLayer(String newWMSLayerName) {
+        if (!newWMSLayerName.equals(lastWMSLayerName)) {
+            interfaceRef = null;
+            cookie = null; // new since WMS server requires that we come back to the main form
+        }
+    }
+
+    private void setCookie() {
+        this.urlConn.setRequestProperty("Cookie", this.cookie);
+    }
+
+    public void setCookie(HttpURLConnection urlConn) {
+        urlConn.setRequestProperty("Cookie", this.cookie);
+    }
+
+    private void getInterface(WMSLayer wmsLayer) throws IOException, DuplicateLayerException {
+        // first attempt : search for given name without codeCommune
+        interfaceRef = postForm(wmsLayer, "");
+        // second attempt either from known codeCommune (e.g. from cache) or from ComboBox
+        if (interfaceRef == null) {
+            if (!wmsLayer.getCodeCommune().isEmpty()) {
+                // codeCommune is already known (from previous request or from cache on disk)
+                interfaceRef = postForm(wmsLayer, wmsLayer.getCodeCommune());
+            } else {
+                if (listOfCommunes.size() > 1) {
+                    // commune unknown, prompt the list of communes from server and try with codeCommune
+                    String selected = selectMunicipalityDialog();
+                    if (selected != null) {
+                        String newCodeCommune = selected.substring(1, selected.indexOf('>') - 2);
+                        String newLocation = selected.substring(selected.indexOf('>') + 1, selected.lastIndexOf(" - "));
+                        wmsLayer.setCodeCommune(newCodeCommune);
+                        wmsLayer.setLocation(newLocation);
+                        Main.pref.put("cadastrewms.codeCommune", newCodeCommune);
+                        Main.pref.put("cadastrewms.location", newLocation);
+                    }
+                    checkLayerDuplicates(wmsLayer);
+                    interfaceRef = postForm(wmsLayer, wmsLayer.getCodeCommune());
+                }
+                if (listOfCommunes.size() == 1 && wmsLayer.isRaster()) {
+                    // commune known but raster format. Select "Feuille" (non-georeferenced image) from list.
+                    int res = selectFeuilleDialog();
+                    if (res != -1) {
+                        wmsLayer.setCodeCommune(listOfFeuilles.get(res).name);
+                        checkLayerDuplicates(wmsLayer);
+                        interfaceRef = buildRasterFeuilleInterfaceRef(wmsLayer.getCodeCommune());
+                    }
+                }
+            }
+        }
+
+        if (interfaceRef == null)
+            throw new IOException("Town/city " + wmsLayer.getLocation() + " not found.");
+    }
+
+    private void openInterface() throws IOException {
+        try {
+            // finally, open the interface on server side giving access to the wms server
+            URL interfaceURL = new URL(BASE_URL + "/scpc/"+interfaceRef);
+            urlConn = (HttpURLConnection) interfaceURL.openConnection();
+            urlConn.setRequestMethod("GET");
+            setCookie();
+            urlConn.connect();
+            if (urlConn.getResponseCode() != HttpURLConnection.HTTP_OK) {
+                throw new IOException("Cannot open Cadastre interface. GET response:"+urlConn.getResponseCode());
+            }
+            Main.info("GET "+interfaceURL);
+            BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), StandardCharsets.UTF_8));
+            // read the buffer otherwise we sent POST too early
+            StringBuilder lines = new StringBuilder();
+            String ln;
+            while ((ln = in.readLine()) != null) {
+                if (Main.isDebugEnabled()) {
+                    lines.append(ln);
+                }
+            }
+            if (Main.isDebugEnabled()) {
+                Main.debug(lines.toString());
+            }
+        } catch (MalformedURLException e) {
+            throw (IOException) new IOException(
+                "CadastreGrabber: Illegal url.").initCause(e);
+        }
+    }
+
+    /**
+     * Post the form with the commune name and check the returned answer which is embedded
+     * in HTTP XML packets. This function doesn't use an XML parser yet but that would be a good idea
+     * for the next releases.
+     * Two possibilities :
+     * - either the commune name matches and we receive an URL starting with "afficherCarteCommune.do" or
+     * - we don't receive a single answer but a list of possible values. This answer looks like:
+     *   <select name="codeCommune" class="long erreur" id="codeCommune">
+     *   <option value="">Choisir</option>
+     *   <option value="50061" >COLMARS - 04370</option>
+     *   <option value="QK066" >COLMAR - 68000</option>
+     *   </select>
+     * The returned string is the interface name used in further requests, e.g. "afficherCarteCommune.do?c=QP224"
+     * where QP224 is the code commune known by the WMS (or "afficherCarteTa.do?c=..." for raster images).
+     *
+     * @return retURL url to available code commune in the cadastre; "" if not found
+     */
+    private String postForm(WMSLayer wmsLayer, String codeCommune) throws IOException {
+        try {
+            listOfCommunes.clear();
+            listOfTA.clear();
+            // send a POST request with a city/town/village name
+            String content = "numerovoie=";
+            content += "&indiceRepetition=";
+            content += "&nomvoie=";
+            content += "&lieuDit=";
+            if (codeCommune.isEmpty()) {
+                content += "&ville=" + java.net.URLEncoder.encode(wmsLayer.getLocation(), "UTF-8");
+                content += "&codePostal=";
+            } else {
+                content += "&codeCommune=" + codeCommune;
+            }
+            content += "&codeDepartement=";
+            content += wmsLayer.getDepartement();
+            content += "&nbResultatParPage=10";
+            content += "&x=0&y=0";
+            searchFormURL = new URL(BASE_URL + "/scpc/rechercherPlan.do");
+            urlConn = (HttpURLConnection) searchFormURL.openConnection();
+            urlConn.setRequestMethod("POST");
+            urlConn.setDoOutput(true);
+            urlConn.setDoInput(true);
+            setCookie();
+            try (OutputStream wr = urlConn.getOutputStream()) {
+                wr.write(content.getBytes(StandardCharsets.UTF_8));
+                Main.info("POST "+content);
+                wr.flush();
+            }
+            String ln;
+            StringBuilder sb = new StringBuilder();
+            try (BufferedReader rd = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), StandardCharsets.UTF_8))) {
+                while ((ln = rd.readLine()) != null) {
+                    sb.append(ln);
+                }
+            }
+            String lines = sb.toString();
+            urlConn.disconnect();
+            if (lines != null) {
+                if (lines.indexOf(C_IMAGE_FORMAT) != -1) {
+                    int i = lines.indexOf(C_IMAGE_FORMAT);
+                    int j = lines.indexOf('.', i);
+                    wmsLayer.setRaster("image".equals(lines.substring(i+C_IMAGE_FORMAT.length(), j)));
+                }
+                if (!wmsLayer.isRaster() && lines.indexOf(C_INTERFACE_VECTOR) != -1) {  // "afficherCarteCommune.do"
+                    // shall be something like: interfaceRef = "afficherCarteCommune.do?c=X2269";
+                    lines = lines.substring(lines.indexOf(C_INTERFACE_VECTOR), lines.length());
+                    lines = lines.substring(0, lines.indexOf('\''));
+                    lines = Entities.unescape(lines);
+                    Main.info("interface ref.:"+lines);
+                    return lines;
+                } else if (wmsLayer.isRaster() && lines.indexOf(C_INTERFACE_RASTER_TA) != -1) { // "afficherCarteTa.do"
+                    // list of values parsed in listOfFeuilles (list all non-georeferenced images)
+                    lines = getFeuillesList();
+                    if (!downloadCanceled) {
+                        parseFeuillesList(lines);
+                        if (!listOfFeuilles.isEmpty()) {
+                            int res = selectFeuilleDialog();
+                            if (res != -1) {
+                                wmsLayer.setCodeCommune(listOfFeuilles.get(res).name);
+                                checkLayerDuplicates(wmsLayer);
+                                interfaceRef = buildRasterFeuilleInterfaceRef(wmsLayer.getCodeCommune());
+                                wmsLayer.setCodeCommune(listOfFeuilles.get(res).ref);
+                                lines = buildRasterFeuilleInterfaceRef(listOfFeuilles.get(res).ref);
+                                lines = Entities.unescape(lines);
+                                Main.info("interface ref.:"+lines);
+                                return lines;
+                            }
+                        }
+                    }
+                    return null;
+                } else if (lines.indexOf(C_COMMUNE_LIST_START) != -1 && lines.indexOf(C_COMMUNE_LIST_END) != -1) {
+                    // list of values parsed in listOfCommunes
+                    int i = lines.indexOf(C_COMMUNE_LIST_START);
+                    int j = lines.indexOf(C_COMMUNE_LIST_END, i);
+                    parseCommuneList(lines.substring(i, j));
+                }
+            }
+        } catch (MalformedURLException e) {
+            throw (IOException) new IOException("Illegal url.").initCause(e);
+        } catch (DuplicateLayerException e) {
+            Main.error(e);
+        }
+        return null;
+    }
+
+    private void parseCommuneList(String input) {
+        if (input.indexOf(C_OPTION_LIST_START) != -1) {
+            while (input.indexOf("<option value=\"") != -1) {
+                int i = input.indexOf(C_OPTION_LIST_START);
+                int j = input.indexOf(C_OPTION_LIST_END, i+C_OPTION_LIST_START.length());
+                int k = input.indexOf('"', i+C_OPTION_LIST_START.length());
+                if (j != -1 && k > (i + C_OPTION_LIST_START.length())) {
+                    String lov = input.substring(i+C_OPTION_LIST_START.length()-1, j);
+                    if (lov.indexOf('>') != -1) {
+                        Main.info("parse "+lov);
+                        listOfCommunes.add(lov);
+                    } else
+                        Main.error("unable to parse commune string:"+lov);
+                }
+                input = input.substring(j+C_OPTION_LIST_END.length());
+            }
+        }
+    }
+
+    private String getFeuillesList() {
+        // get all images in one html page
+        String ln = null;
+        StringBuilder lines = new StringBuilder();
+        HttpURLConnection urlConn2 = null;
+        try {
+            URL getAllImagesURL = new URL(BASE_URL + "/scpc/listerFeuillesParcommune.do?keepVolatileSession=&offset=2000");
+            urlConn2 = (HttpURLConnection) getAllImagesURL.openConnection();
+            setCookie(urlConn2);
+            urlConn2.connect();
+            Main.info("GET "+getAllImagesURL);
+            try (BufferedReader rd = new BufferedReader(new InputStreamReader(urlConn2.getInputStream(), StandardCharsets.UTF_8))) {
+                while ((ln = rd.readLine()) != null) {
+                    lines.append(ln);
+                }
+            }
+            urlConn2.disconnect();
+        } catch (IOException e) {
+            listOfFeuilles.clear();
+            Main.error(e);
+        }
+        return lines.toString();
+    }
+
+    private void parseFeuillesList(String input) {
+        listOfFeuilles.clear();
+        // get "Tableau d'assemblage"
+        String inputTA = input;
+        if (Main.pref.getBoolean("cadastrewms.useTA", false)) {
+            while (inputTA.indexOf(C_TA_IMAGE_LINK_START) != -1) {
+                inputTA = inputTA.substring(inputTA.indexOf(C_TA_IMAGE_LINK_START) + C_TA_IMAGE_LINK_START.length());
+                String refTA = inputTA.substring(0, inputTA.indexOf('\''));
+                String nameTA = inputTA.substring(inputTA.indexOf(C_TA_IMAGE_NAME_START) + C_TA_IMAGE_NAME_START.length());
+                nameTA = nameTA.substring(0, nameTA.indexOf('<'));
+                listOfFeuilles.add(new PlanImage(nameTA, refTA));
+            }
+        }
+        // get "Feuilles"
+        while (input.indexOf(C_IMAGE_LINK_START) != -1) {
+            input = input.substring(input.indexOf(C_IMAGE_LINK_START)+C_IMAGE_LINK_START.length());
+            String refFeuille = input.substring(0, input.indexOf('\''));
+            String nameFeuille = input.substring(
+                    input.indexOf(C_IMAGE_NAME_START)+C_IMAGE_NAME_START.length(),
+                    input.indexOf(" -"));
+            listOfFeuilles.add(new PlanImage(nameFeuille, refFeuille));
+        }
+    }
+
+    private String selectMunicipalityDialog() {
+        JPanel p = new JPanel(new GridBagLayout());
+        String[] communeList = new String[listOfCommunes.size() + 1];
+        communeList[0] = tr("Choose from...");
+        for (int i = 0; i < listOfCommunes.size(); i++) {
+            communeList[i + 1] = listOfCommunes.get(i).substring(listOfCommunes.get(i).indexOf('>')+1);
+        }
+        JComboBox<String> inputCommuneList = new JComboBox<>(communeList);
+        p.add(inputCommuneList, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 0, 0, 0));
+        JOptionPane pane = new JOptionPane(p, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null);
+        // this below is a temporary workaround to fix the "always on top" issue
+        JDialog dialog = pane.createDialog(Main.parent, tr("Select commune"));
+        CadastrePlugin.prepareDialog(dialog);
+        dialog.setVisible(true);
+        // till here
+        if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
+            return null;
+        return listOfCommunes.get(inputCommuneList.getSelectedIndex()-1);
+    }
+
+    private int selectFeuilleDialog() {
+        JPanel p = new JPanel(new GridBagLayout());
+        List<String> imageNames = new ArrayList<>();
+        for (PlanImage src : listOfFeuilles) {
+            imageNames.add(src.name);
+        }
+        JComboBox<String> inputFeuilleList = new JComboBox<>(imageNames.toArray(new String[]{}));
+        p.add(inputFeuilleList, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 0, 0, 0));
+        JOptionPane pane = new JOptionPane(p, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null);
+        // this below is a temporary workaround to fix the "always on top" issue
+        JDialog dialog = pane.createDialog(Main.parent, tr("Select Feuille"));
+        CadastrePlugin.prepareDialog(dialog);
+        dialog.setVisible(true);
+        // till here
+        if (!Integer.valueOf(JOptionPane.OK_OPTION).equals(pane.getValue()))
+            return -1;
+        return inputFeuilleList.getSelectedIndex();
+    }
+
+    private static String buildRasterFeuilleInterfaceRef(String codeCommune) {
+        return C_INTERFACE_RASTER_FEUILLE + "?f=" + codeCommune;
+    }
+
+    /**
+     * Retrieve the bounding box size in pixels of the whole commune (point 0,0 at top, left corner)
+     * and store it in given wmsLayer
+     * In case of raster image, we also check in the same http request if the image is already georeferenced
+     * and store the result in the wmsLayer as well.
+     * @param wmsLayer the WMSLayer where the commune data and images are stored
+     */
+    public void retrieveCommuneBBox(WMSLayer wmsLayer) throws IOException {
+        if (interfaceRef == null)
+            return;
+        // send GET opening normally the small window with the commune overview
+        String content = BASE_URL + "/scpc/" + interfaceRef;
+        content += "&dontSaveLastForward&keepVolatileSession=";
+        searchFormURL = new URL(content);
+        urlConn = (HttpURLConnection) searchFormURL.openConnection();
+        urlConn.setRequestMethod("GET");
+        setCookie();
+        urlConn.connect();
+        if (urlConn.getResponseCode() != HttpURLConnection.HTTP_OK) {
+            throw new IOException("Cannot get Cadastre response.");
+        }
+        Main.info("GET "+searchFormURL);
+        String ln;
+        StringBuilder sb = new StringBuilder();
+        try (BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), StandardCharsets.UTF_8))) {
+            while ((ln = in.readLine()) != null) {
+                sb.append(ln);
+            }
+        }
+        urlConn.disconnect();
+        String line = sb.toString();
+        parseBBoxCommune(wmsLayer, line);
+        if (wmsLayer.isRaster() && !wmsLayer.isAlreadyGeoreferenced()) {
+            parseGeoreferences(wmsLayer, line);
+        }
+    }
+
+    private static void parseBBoxCommune(WMSLayer wmsLayer, String input) {
+        if (input.indexOf(C_BBOX_COMMUN_START) != -1) {
+            input = input.substring(input.indexOf(C_BBOX_COMMUN_START));
+            int i = input.indexOf(',');
+            double minx = Double.parseDouble(input.substring(C_BBOX_COMMUN_START.length(), i));
+            int j = input.indexOf(',', i+1);
+            double miny = Double.parseDouble(input.substring(i+1, j));
+            int k = input.indexOf(',', j+1);
+            double maxx = Double.parseDouble(input.substring(j+1, k));
+            int l = input.indexOf(C_BBOX_COMMUN_END, k+1);
+            double maxy = Double.parseDouble(input.substring(k+1, l));
+            wmsLayer.setCommuneBBox(new EastNorthBound(new EastNorth(minx, miny), new EastNorth(maxx, maxy)));
+        }
+    }
+
+    private static void parseGeoreferences(WMSLayer wmsLayer, String input) {
+        /* commented since cadastre WMS changes mid july 2013
+         * until new GeoBox coordinates parsing is solved */
+//        if (input.lastIndexOf(cBBoxCommunStart) != -1) {
+//            input = input.substring(input.lastIndexOf(cBBoxCommunStart));
+//            input = input.substring(input.indexOf(cBBoxCommunEnd)+cBBoxCommunEnd.length());
+//            int i = input.indexOf(",");
+//            int j = input.indexOf(",", i+1);
+//            String str = input.substring(i+1, j);
+//            double unknown_yet = tryParseDouble(str);
+//            int j_ = input.indexOf(",", j+1);
+//            double angle = Double.parseDouble(input.substring(j+1, j_));
+//            int k = input.indexOf(",", j_+1);
+//            double scale_origin = Double.parseDouble(input.substring(j_+1, k));
+//            int l = input.indexOf(",", k+1);
+//            double dpi = Double.parseDouble(input.substring(k+1, l));
+//            int m = input.indexOf(",", l+1);
+//            double fX = Double.parseDouble(input.substring(l+1, m));
+//            int n = input.indexOf(",", m+1);
+//            double fY = Double.parseDouble(input.substring(m+1, n));
+//            int o = input.indexOf(",", n+1);
+//            double X0 = Double.parseDouble(input.substring(n+1, o));
+//            int p = input.indexOf(",", o+1);
+//            double Y0 = Double.parseDouble(input.substring(o+1, p));
+//            if (X0 != 0.0 && Y0 != 0) {
+//                wmsLayer.setAlreadyGeoreferenced(true);
+//                wmsLayer.fX = fX;
+//                wmsLayer.fY = fY;
+//                wmsLayer.angle = angle;
+//                wmsLayer.X0 = X0;
+//                wmsLayer.Y0 = Y0;
+//            }
+//            Main.info("parse georef:"+unknown_yet+","+angle+","+scale_origin+","+dpi+","+fX+","+fY+","+X0+","+Y0);
+//        }
+    }
+
+    private static void checkLayerDuplicates(WMSLayer wmsLayer) throws DuplicateLayerException {
+        if (Main.map != null) {
+            for (Layer l : Main.getLayerManager().getLayers()) {
+                if (l instanceof WMSLayer && l.getName().equals(wmsLayer.getName()) && (!l.equals(wmsLayer))) {
+                    Main.info("Try to grab into a new layer when "+wmsLayer.getName()+" is already opened.");
+                    // remove the duplicated layer
+                    Main.getLayerManager().removeLayer(wmsLayer);
+                    throw new DuplicateLayerException();
+                }
+            }
+        }
+    }
+
+    public void cancel() {
+        if (urlConn != null) {
+            urlConn.setConnectTimeout(1);
+            urlConn.setReadTimeout(1);
+        }
+        downloadCanceled = true;
+        lastWMSLayerName = null;
+    }
+
+    public InputStream getContent(URL url) throws IOException, OsmTransferException {
+        urlConn = (HttpURLConnection) url.openConnection();
+        urlConn.setRequestProperty("Connection", "close");
+        urlConn.setRequestMethod("GET");
+        setCookie();
+        return new ProgressInputStream(urlConn, NullProgressMonitor.INSTANCE);
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadSVGBuilding.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadSVGBuilding.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadSVGBuilding.java	(revision 33638)
@@ -0,0 +1,281 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+
+public class DownloadSVGBuilding extends PleaseWaitRunnable {
+
+    private WMSLayer wmsLayer;
+    private CadastreInterface wmsInterface;
+    private String svg;
+    private static EastNorthBound currentView;
+    private EastNorthBound viewBox;
+    private static String errorMessage;
+
+    /**
+     * Constructs a new {@code DownloadSVGBuilding}.
+     */
+    public DownloadSVGBuilding(WMSLayer wmsLayer) {
+        super(tr("Downloading {0}", wmsLayer.getName()));
+
+        this.wmsLayer = wmsLayer;
+        this.wmsInterface = wmsLayer.grabber.getWmsInterface();
+    }
+
+    @Override
+    public void realRun() throws IOException, OsmTransferException {
+        progressMonitor.indeterminateSubTask(tr("Contacting WMS Server..."));
+        errorMessage = null;
+        try {
+            if (wmsInterface.retrieveInterface(wmsLayer)) {
+                svg = grabBoundary(currentView);
+                if (svg == null)
+                    return;
+                getViewBox(svg);
+                if (viewBox == null)
+                    return;
+                createBuildings(svg);
+            }
+        } catch (DuplicateLayerException e) {
+            Main.warn("removed a duplicated layer");
+        } catch (WMSException e) {
+            errorMessage = e.getMessage();
+            wmsLayer.grabber.getWmsInterface().resetCookie();
+        }
+    }
+
+    @Override
+    protected void cancel() {
+        wmsLayer.grabber.getWmsInterface().cancel();
+    }
+
+    @Override
+    protected void finish() {
+        // Do nothing
+    }
+
+    private boolean getViewBox(String svg) {
+        double[] box = new SVGParser().getViewBox(svg);
+        if (box != null) {
+            viewBox = new EastNorthBound(new EastNorth(box[0], box[1]),
+                    new EastNorth(box[0]+box[2], box[1]+box[3]));
+            return true;
+        }
+        Main.warn("Unable to parse SVG data (viewBox)");
+        return false;
+    }
+
+    /**
+     *  The svg contains more than one commune boundary defined by path elements. So detect
+     *  which path element is the best fitting to the viewBox and convert it to OSM objects
+     */
+    private void createBuildings(String svg) {
+        String[] SVGpaths = new SVGParser().getClosedPaths(svg);
+        ArrayList<ArrayList<EastNorth>> eastNorths = new ArrayList<>();
+
+        // convert SVG nodes to eastNorth coordinates
+        for (int i = 0; i < SVGpaths.length; i++) {
+            ArrayList<EastNorth> eastNorth = new ArrayList<>();
+            createNodes(SVGpaths[i], eastNorth);
+            if (eastNorth.size() > 2)
+                eastNorths.add(eastNorth);
+        }
+
+        // create nodes and closed ways
+        DataSet svgDataSet = new DataSet();
+        for (ArrayList<EastNorth> path : eastNorths) {
+            Way wayToAdd = new Way();
+            for (EastNorth eastNorth : path) {
+                Node nodeToAdd = new Node(Main.getProjection().eastNorth2latlon(eastNorth));
+                // check if new node is not already created by another new path
+                Node nearestNewNode = checkNearestNode(nodeToAdd, svgDataSet.getNodes());
+                if (nodeToAdd.equals(nearestNewNode))
+                    svgDataSet.addPrimitive(nearestNewNode);
+                wayToAdd.addNode(nearestNewNode); // either a new node or an existing one
+            }
+            wayToAdd.addNode(wayToAdd.getNode(0)); // close the way
+            svgDataSet.addPrimitive(wayToAdd);
+        }
+
+        // TODO remove small boxes (4 nodes with less than 1 meter distance)
+        /*
+        for (Way w : svgDataSet.ways)
+            if (w.nodes.size() == 5)
+                for (int i = 0; i < w.nodes.size()-2; i++) {
+                    if (w.nodes.get(i).eastNorth.distance(w.nodes.get(i+1).eastNorth))
+                }*/
+
+        // check if the new way or its nodes is already in OSM layer
+        for (Node n : svgDataSet.getNodes()) {
+            Node nearestNewNode = checkNearestNode(n, Main.getLayerManager().getEditDataSet().getNodes());
+            if (nearestNewNode != n) {
+                // replace the SVG node by the OSM node
+                for (Way w : svgDataSet.getWays()) {
+                    int replaced = 0;
+                    for (Node node : w.getNodes()) {
+                        if (node == n) {
+                            node = nearestNewNode;
+                            replaced++;
+                        }
+                    }
+                    if (w.getNodesCount() == replaced)
+                        w.setDeleted(true);
+                }
+                n.setDeleted(true);
+            }
+
+        }
+
+        Collection<Command> cmds = new LinkedList<>();
+        for (Node node : svgDataSet.getNodes()) {
+            if (!node.isDeleted())
+                cmds.add(new AddCommand(node));
+        }
+        for (Way way : svgDataSet.getWays()) {
+            if (!way.isDeleted())
+                cmds.add(new AddCommand(way));
+        }
+        Main.main.undoRedo.add(new SequenceCommand(tr("Create buildings"), cmds));
+        Main.map.repaint();
+    }
+
+    private void createNodes(String SVGpath, ArrayList<EastNorth> eastNorth) {
+        // looks like "M981283.38 368690.15l143.81 72.46 155.86 ..."
+        String[] coor = SVGpath.split("[MlZ ]"); //coor[1] is x, coor[2] is y
+        double dx = Double.parseDouble(coor[1]);
+        double dy = Double.parseDouble(coor[2]);
+        for (int i = 3; i < coor.length; i += 2) {
+            if (coor[i].isEmpty()) {
+                eastNorth.clear(); // some paths are just artifacts
+                return;
+            }
+            double east = dx += Double.parseDouble(coor[i]);
+            double north = dy += Double.parseDouble(coor[i+1]);
+            eastNorth.add(new EastNorth(east, north));
+        }
+        // flip the image (svg using a reversed Y coordinate system)
+        double pivot = viewBox.min.getY() + (viewBox.max.getY() - viewBox.min.getY()) / 2;
+        for (int i = 0; i < eastNorth.size(); i++) {
+            EastNorth en = eastNorth.get(i);
+            eastNorth.set(i, new EastNorth(en.east(), 2 * pivot - en.north()));
+        }
+        return;
+    }
+
+    /**
+     * Check if node can be reused.
+     * @param nodeToAdd the candidate as new node
+     * @return the already existing node (if any), otherwise the new node candidate.
+     */
+    private static Node checkNearestNode(Node nodeToAdd, Collection<Node> nodes) {
+        double epsilon = 0.05; // smallest distance considering duplicate node
+        for (Node n : nodes) {
+            if (!n.isDeleted() && !n.isIncomplete()) {
+                double dist = n.getEastNorth().distance(nodeToAdd.getEastNorth());
+                if (dist < epsilon) {
+                    return n;
+                }
+            }
+        }
+        return nodeToAdd;
+    }
+
+    private String grabBoundary(EastNorthBound bbox) throws IOException, OsmTransferException {
+        try {
+            URL url = null;
+            url = getURLsvg(bbox);
+            return grabSVG(url);
+        } catch (MalformedURLException e) {
+            throw (IOException) new IOException(tr("CadastreGrabber: Illegal url.")).initCause(e);
+        }
+    }
+
+    private static URL getURLsvg(EastNorthBound bbox) throws MalformedURLException {
+        String str = CadastreInterface.BASE_URL+"/scpc/wms?version=1.1&request=GetMap";
+        str += "&layers=";
+        str += "CDIF:LS2";
+        str += "&format=image/svg";
+        str += "&bbox="+bbox.min.east()+",";
+        str += bbox.min.north() + ",";
+        str += bbox.max.east() + ",";
+        str += bbox.max.north();
+        str += "&width="+CadastrePlugin.imageWidth+"&height="+CadastrePlugin.imageHeight;
+        str += "&exception=application/vnd.ogc.se_inimage";
+        str += "&styles=";
+        str += "LS2_90";
+        Main.info("URL="+str);
+        return new URL(str.replace(" ", "%20"));
+    }
+
+    private String grabSVG(URL url) throws IOException, OsmTransferException {
+        File file = new File(CadastrePlugin.cacheDir + "building.svg");
+        String svg = "";
+        try (InputStream is = wmsInterface.getContent(url)) {
+            if (file.exists())
+                file.delete();
+            try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file, true));
+                 InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
+                 BufferedReader br = new BufferedReader(isr)) {
+                String line;
+                while (null != (line = br.readLine())) {
+                    line += "\n";
+                    bos.write(line.getBytes(StandardCharsets.UTF_8));
+                    svg += line;
+                }
+            }
+        } catch (IOException e) {
+            Main.error(e);
+        }
+        return svg;
+    }
+
+    public static void download(WMSLayer wmsLayer) {
+        MapView mv = Main.map.mapView;
+        currentView = new EastNorthBound(mv.getEastNorth(0, mv.getHeight()),
+                mv.getEastNorth(mv.getWidth(), 0));
+        if ((currentView.max.east() - currentView.min.east()) > 1000 ||
+                (currentView.max.north() - currentView.min.north() > 1000)) {
+            JOptionPane.showMessageDialog(Main.parent,
+                    tr("To avoid cadastre WMS overload,\nbuilding import size is limited to 1 km2 max."));
+            return;
+        }
+        if (CadastrePlugin.autoSourcing == false) {
+            JOptionPane.showMessageDialog(Main.parent,
+                    tr("Please, enable auto-sourcing and check cadastre millesime."));
+            return;
+        }
+        Main.worker.execute(new DownloadSVGBuilding(wmsLayer));
+        if (errorMessage != null)
+            JOptionPane.showMessageDialog(Main.parent, errorMessage);
+    }
+
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadSVGTask.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadSVGTask.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadSVGTask.java	(revision 33638)
@@ -0,0 +1,221 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+
+/**
+ * Grab the SVG administrative boundaries of the active commune layer (cadastre),
+ * isolate the SVG path of the concerned commune (other municipalities are also
+ * downloaded in the SVG data), convert to OSM nodes and way plus simplify.
+ * Thanks to Frederic Rodrigo for his help.
+ */
+public class DownloadSVGTask extends PleaseWaitRunnable {
+
+    private WMSLayer wmsLayer;
+    private CadastreInterface wmsInterface;
+    private String svg;
+    private EastNorthBound viewBox;
+    private static String errorMessage;
+
+    /**
+     * Constructs a new {@code DownloadSVGTask}.
+     */
+    public DownloadSVGTask(WMSLayer wmsLayer) {
+        super(tr("Downloading {0}", wmsLayer.getName()));
+
+        this.wmsLayer = wmsLayer;
+        this.wmsInterface = wmsLayer.grabber.getWmsInterface();
+    }
+
+    @Override
+    public void realRun() throws IOException, OsmTransferException {
+        progressMonitor.indeterminateSubTask(tr("Contacting WMS Server..."));
+        errorMessage = null;
+        try {
+            if (wmsInterface.retrieveInterface(wmsLayer)) {
+                svg = grabBoundary(wmsLayer.getCommuneBBox());
+                if (svg == null)
+                    return;
+                progressMonitor.indeterminateSubTask(tr("Extract SVG ViewBox..."));
+                getViewBox(svg);
+                if (viewBox == null)
+                    return;
+                progressMonitor.indeterminateSubTask(tr("Extract best fitting boundary..."));
+                createWay(svg);
+            }
+        } catch (DuplicateLayerException e) {
+            Main.warn("removed a duplicated layer");
+        } catch (WMSException e) {
+            errorMessage = e.getMessage();
+            wmsLayer.grabber.getWmsInterface().resetCookie();
+        }
+    }
+
+    @Override
+    protected void cancel() {
+        wmsLayer.grabber.getWmsInterface().cancel();
+    }
+
+    @Override
+    protected void finish() {
+        // Do nothing
+    }
+
+    private boolean getViewBox(String svg) {
+        double[] box = new SVGParser().getViewBox(svg);
+        if (box != null) {
+            viewBox = new EastNorthBound(new EastNorth(box[0], box[1]),
+                    new EastNorth(box[0]+box[2], box[1]+box[3]));
+            return true;
+        }
+        Main.warn("Unable to parse SVG data (viewBox)");
+        return false;
+    }
+
+    /**
+     *  The svg contains more than one commune boundary defined by path elements. So detect
+     *  which path element is the best fitting to the viewBox and convert it to OSM objects
+     */
+    private void createWay(String svg) {
+        String[] SVGpaths = new SVGParser().getClosedPaths(svg);
+        ArrayList<Double> fitViewBox = new ArrayList<>();
+        ArrayList<ArrayList<EastNorth>> eastNorths = new ArrayList<>();
+        for (int i = 0; i < SVGpaths.length; i++) {
+            ArrayList<EastNorth> eastNorth = new ArrayList<>();
+            fitViewBox.add(createNodes(SVGpaths[i], eastNorth));
+            eastNorths.add(eastNorth);
+        }
+        // the smallest fitViewBox indicates the best fitting path in viewBox
+        Double min = Collections.min(fitViewBox);
+        int bestPath = fitViewBox.indexOf(min);
+        List<Node> nodeList = new ArrayList<>();
+        for (EastNorth eastNorth : eastNorths.get(bestPath)) {
+            nodeList.add(new Node(Main.getProjection().eastNorth2latlon(eastNorth)));
+        }
+        Way wayToAdd = new Way();
+        Collection<Command> cmds = new LinkedList<>();
+        for (Node node : nodeList) {
+            cmds.add(new AddCommand(node));
+            wayToAdd.addNode(node);
+        }
+        wayToAdd.addNode(wayToAdd.getNode(0)); // close the circle
+
+        cmds.add(new AddCommand(wayToAdd));
+        Main.main.undoRedo.add(new SequenceCommand(tr("Create boundary"), cmds));
+        Main.map.repaint();
+    }
+
+    private double createNodes(String SVGpath, ArrayList<EastNorth> eastNorth) {
+        // looks like "M981283.38 368690.15l143.81 72.46 155.86 ..."
+        String[] coor = SVGpath.split("[MlZ ]"); //coor[1] is x, coor[2] is y
+        double dx = Double.parseDouble(coor[1]);
+        double dy = Double.parseDouble(coor[2]);
+        double minY = Double.MAX_VALUE;
+        double minX = Double.MAX_VALUE;
+        double maxY = Double.MIN_VALUE;
+        double maxX = Double.MIN_VALUE;
+        for (int i = 3; i < coor.length; i += 2) {
+            double east = dx += Double.parseDouble(coor[i]);
+            double north = dy += Double.parseDouble(coor[i+1]);
+            eastNorth.add(new EastNorth(east, north));
+            minX = minX > east ? east : minX;
+            minY = minY > north ? north : minY;
+            maxX = maxX < east ? east : maxX;
+            maxY = maxY < north ? north : maxY;
+        }
+        // flip the image (svg using a reversed Y coordinate system)
+        double pivot = viewBox.min.getY() + (viewBox.max.getY() - viewBox.min.getY()) / 2;
+        for (int i = 0; i < eastNorth.size(); i++) {
+            EastNorth en = eastNorth.get(i);
+            eastNorth.set(i, new EastNorth(en.east(), 2 * pivot - en.north()));
+        }
+        return Math.abs(minX - viewBox.min.getX())+Math.abs(maxX - viewBox.max.getX())
+        +Math.abs(minY - viewBox.min.getY())+Math.abs(maxY - viewBox.max.getY());
+    }
+
+    private String grabBoundary(EastNorthBound bbox) throws IOException, OsmTransferException {
+        try {
+            return grabSVG(getURLsvg(bbox));
+        } catch (MalformedURLException e) {
+            throw (IOException) new IOException(tr("CadastreGrabber: Illegal url.")).initCause(e);
+        }
+    }
+
+    private static URL getURLsvg(EastNorthBound bbox) throws MalformedURLException {
+        String str = CadastreInterface.BASE_URL+"/scpc/wms?version=1.1&request=GetMap";
+        str += "&layers=";
+        str += "CDIF:COMMUNE";
+        str += "&format=image/svg";
+        str += "&bbox="+bbox.min.east()+",";
+        str += bbox.min.north() + ",";
+        str += bbox.max.east() + ",";
+        str += bbox.max.north();
+        str += "&width="+CadastrePlugin.imageWidth+"&height="+CadastrePlugin.imageHeight;
+        str += "&styles=";
+        str += "COMMUNE_90";
+        Main.info("URL="+str);
+        return new URL(str.replace(" ", "%20"));
+    }
+
+    private String grabSVG(URL url) throws IOException, OsmTransferException {
+        File file = new File(CadastrePlugin.cacheDir + "boundary.svg");
+        String svg = "";
+        try (InputStream is = wmsInterface.getContent(url)) {
+            if (file.exists())
+                file.delete();
+            try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file, true));
+                 InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
+                 BufferedReader br = new BufferedReader(isr)) {
+                String line;
+                while (null != (line = br.readLine())) {
+                    line += "\n";
+                    bos.write(line.getBytes(StandardCharsets.UTF_8));
+                    svg += line;
+                }
+            }
+        } catch (IOException e) {
+            Main.error(e);
+        }
+        return svg;
+    }
+
+    public static void download(WMSLayer wmsLayer) {
+        if (!CadastrePlugin.autoSourcing) {
+            JOptionPane.showMessageDialog(Main.parent,
+                    tr("Please, enable auto-sourcing and check cadastre millesime."));
+            return;
+        }
+        Main.worker.execute(new DownloadSVGTask(wmsLayer));
+        if (errorMessage != null)
+            JOptionPane.showMessageDialog(Main.parent, errorMessage);
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadWMSPlanImage.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadWMSPlanImage.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadWMSPlanImage.java	(revision 33638)
@@ -0,0 +1,127 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.IOException;
+import java.util.concurrent.Future;
+
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+
+public class DownloadWMSPlanImage {
+
+    private Future<Task> task = null;
+    private WMSLayer wmsLayer;
+    private Bounds bounds;
+    private static boolean dontGeoreference = false;
+    private static String errorMessage;
+
+    private class Task extends PleaseWaitRunnable {
+        Task(WMSLayer wmsLayer, Bounds bounds) {
+            super(tr("Downloading {0}", wmsLayer.getName()));
+        }
+
+        @Override
+        public void realRun() throws IOException {
+            progressMonitor.indeterminateSubTask(tr("Contacting cadastre WMS ..."));
+            errorMessage = null;
+            try {
+                if (wmsLayer.grabber.getWmsInterface().retrieveInterface(wmsLayer)) {
+                    if (!wmsLayer.getImages().isEmpty()) {
+                        JOptionPane pane = new JOptionPane(tr("Image already loaded"), JOptionPane.INFORMATION_MESSAGE);
+                        // this below is a temporary workaround to fix the "always on top" issue
+                        JDialog dialog = pane.createDialog(Main.parent, "");
+                        CadastrePlugin.prepareDialog(dialog);
+                        dialog.setVisible(true);
+                        // till here
+                        dontGeoreference = true;
+                    } else if (wmsLayer.grabber.getWmsInterface().downloadCanceled) {
+                        // do nothing
+                    } else {
+                        // first time we grab an image for this layer
+                        if (CacheControl.cacheEnabled) {
+                            if (wmsLayer.grabThread.getCacheControl().loadCacheIfExist()) {
+                                dontGeoreference = true;
+                                wmsLayer.invalidate();
+                                return;
+                            }
+                        }
+                        if (wmsLayer.isRaster()) {
+                            // set raster image commune bounding box based on current view (before adjustment)
+                            wmsLayer.grabber.getWmsInterface().retrieveCommuneBBox(wmsLayer);
+                            wmsLayer.setRasterBounds(bounds);
+                            // grab new images from wms server into active layer
+                            wmsLayer.grab(bounds);
+                            if (wmsLayer.grabber.getWmsInterface().downloadCanceled) {
+                                wmsLayer.clearImages();
+                                wmsLayer.invalidate();
+                            } else {
+                                // next steps follow in method finish() when download is terminated
+                                wmsLayer.joinBufferedImages();
+                            }
+                        } else {
+                            /*JOptionPane.showMessageDialog(Main.parent,tr("Municipality vectorized !\n"+
+                                    "Use the normal Cadastre Grab menu."));*/
+                            JOptionPane pane = new JOptionPane(
+                                    tr("Municipality vectorized !\nUse the normal Cadastre Grab menu."),
+                                    JOptionPane.INFORMATION_MESSAGE);
+                            // this below is a temporary workaround to fix the "always on top" issue
+                            JDialog dialog = pane.createDialog(Main.parent, "");
+                            CadastrePlugin.prepareDialog(dialog);
+                            dialog.setVisible(true);
+                            // till here
+                        }
+                    }
+                }
+            } catch (DuplicateLayerException e) {
+                // we tried to grab onto a duplicated layer (removed)
+                Main.warn("removed a duplicated layer");
+            } catch (WMSException e) {
+                errorMessage = e.getMessage();
+                wmsLayer.grabber.getWmsInterface().resetCookie();
+            }
+        }
+
+        @Override
+        protected void cancel() {
+            wmsLayer.grabber.getWmsInterface().cancel();
+            dontGeoreference = true;
+        }
+
+        @Override
+        protected void finish() {
+        }
+    }
+
+    public void download(WMSLayer wmsLayer) {
+        MapView mv = Main.map.mapView;
+        Bounds bounds = new Bounds(mv.getLatLon(0, mv.getHeight()), mv.getLatLon(mv.getWidth(), 0));
+        dontGeoreference = false;
+
+        //Main.worker.execute(new DownloadWMSPlanImage(wmsLayer, bounds));
+        Task t = new Task(wmsLayer, bounds);
+        this.wmsLayer = wmsLayer;
+        this.bounds = bounds;
+        task = Main.worker.submit(t, t);
+        if (errorMessage != null)
+            JOptionPane.showMessageDialog(Main.parent, errorMessage);
+    }
+
+    public boolean waitFinished() {
+        if (task != null) {
+            try {
+                task.get();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return dontGeoreference;
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadWMSVectorImage.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadWMSVectorImage.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DownloadWMSVectorImage.java	(revision 33638)
@@ -0,0 +1,89 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.IOException;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+
+public class DownloadWMSVectorImage extends PleaseWaitRunnable {
+
+    private WMSLayer wmsLayer;
+    private Bounds bounds;
+    private static String errorMessage;
+
+    public DownloadWMSVectorImage(WMSLayer wmsLayer, Bounds bounds) {
+        super(tr("Downloading {0}", wmsLayer.getName()));
+
+        this.wmsLayer = wmsLayer;
+        this.bounds = bounds;
+    }
+
+    @Override
+    public void realRun() throws IOException {
+        progressMonitor.indeterminateSubTask(tr("Contacting WMS Server..."));
+        errorMessage = null;
+        try {
+            if (wmsLayer.grabber.getWmsInterface().retrieveInterface(wmsLayer)) {
+                if (!wmsLayer.hasImages()) {
+                    // first time we grab an image for this layer
+                    if (CacheControl.cacheEnabled) {
+                        if (wmsLayer.grabThread.getCacheControl().loadCacheIfExist()) {
+                            Main.map.mapView.zoomTo(wmsLayer.getFirstViewFromCacheBBox().toBounds());
+                            return;
+                        }
+                    }
+                    if (wmsLayer.isRaster()) {
+                        // set raster image commune bounding box based on current view (before adjustment)
+                        JOptionPane.showMessageDialog(Main.parent,
+                                tr("This commune is not vectorized.\nPlease use the other menu entry to georeference a \"Plan image\""));
+                        Main.getLayerManager().removeLayer(wmsLayer);
+                        wmsLayer = null;
+                        return;
+                    } else {
+                        // set vectorized commune bounding box by opening the standard web window
+                        wmsLayer.grabber.getWmsInterface().retrieveCommuneBBox(wmsLayer);
+                    }
+                }
+                // grab new images from wms server into active layer
+                wmsLayer.grab(bounds);
+            } else if (!wmsLayer.hasImages()) {
+              // failed to contact WMS of find this commune. Remove layer if empty.
+              Main.getLayerManager().removeLayer(wmsLayer);
+            }
+        } catch (DuplicateLayerException e) {
+            // we tried to grab onto a duplicated layer (removed)
+            Main.warn("removed a duplicated layer");
+        } catch (WMSException e) {
+            Main.warn(e);
+            errorMessage = e.getMessage();
+            wmsLayer.grabber.getWmsInterface().resetCookie();
+        }
+    }
+
+    @Override
+    protected void cancel() {
+        wmsLayer.grabber.getWmsInterface().cancel();
+        if (wmsLayer != null)
+            wmsLayer.grabThread.setCanceled(true);
+    }
+
+    @Override
+    protected void finish() {
+    }
+
+    public static void download(WMSLayer wmsLayer) {
+        MapView mv = Main.map.mapView;
+        Bounds bounds = new Bounds(mv.getLatLon(0, mv.getHeight()), mv.getLatLon(mv.getWidth(), 0));
+
+        Main.worker.execute(new DownloadWMSVectorImage(wmsLayer, bounds));
+        if (errorMessage != null)
+            JOptionPane.showMessageDialog(Main.parent, errorMessage);
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DuplicateLayerException.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DuplicateLayerException.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/DuplicateLayerException.java	(revision 33638)
@@ -0,0 +1,6 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+public class DuplicateLayerException extends Exception {
+    private static final long serialVersionUID = 1L;
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/EastNorthBound.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/EastNorthBound.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/EastNorthBound.java	(revision 33638)
@@ -0,0 +1,42 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import java.io.Serializable;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.EastNorth;
+
+public class EastNorthBound implements Serializable {
+
+    private static final long serialVersionUID = 8451650309216472069L;
+
+    public EastNorth min, max;
+    public EastNorthBound(EastNorth min, EastNorth max) {
+        this.min = min;
+        this.max = max;
+    }
+
+    public boolean contains(EastNorth eastNorth) {
+        if (eastNorth.east() < min.east() || eastNorth.north() < min.north())
+            return false;
+        if (eastNorth.east() > max.east() || eastNorth.north() > max.north())
+            return false;
+        return true;
+    }
+
+    public EastNorthBound interpolate(EastNorthBound en2, double proportion) {
+        EastNorthBound enb = new EastNorthBound(this.min.interpolate(en2.min, proportion),
+                this.max.interpolate(en2.max, proportion));
+        return enb;
+    }
+
+    public Bounds toBounds() {
+        return new Bounds(Main.getProjection().eastNorth2latlon(min), Main.getProjection().eastNorth2latlon(max));
+    }
+
+    @Override public String toString() {
+        return "EastNorthBound[" + min.east() + "," + min.north() + "," + max.east() + "," + max.north() + "]";
+    }
+}
+
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/GeorefImage.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/GeorefImage.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/GeorefImage.java	(revision 33638)
@@ -0,0 +1,376 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Objects;
+
+import javax.imageio.ImageIO;
+
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.gui.NavigatableComponent;
+
+public class GeorefImage implements Serializable, ImageObserver, Cloneable {
+    private static final long serialVersionUID = 1L;
+
+    // bbox of the georeferenced image (the nice horizontal and vertical box)
+    public EastNorth min;
+    public EastNorth max;
+    // bbox of the georeferenced original image (raster only) (inclined if rotated and before cropping)
+    // P[0] is bottom,left then next are clockwise.
+    public EastNorth[] orgRaster = new EastNorth[4];
+    // bbox of the georeferenced original image (raster only) after cropping
+    public EastNorth[] orgCroppedRaster = new EastNorth[4];
+    // angle with georeferenced original image after rotation (raster images only)(in radian)
+    public double angle = 0;
+    public int imageOriginalHeight = 0;
+    public int imageOriginalWidth = 0;
+
+    public BufferedImage image;
+    public WMSLayer wmsLayer;
+
+    private double pixelPerEast;
+    private double pixelPerNorth;
+
+    public GeorefImage(BufferedImage img, EastNorth min, EastNorth max, WMSLayer wmsLayer) {
+        image = Objects.requireNonNull(img);
+
+        this.min = Objects.requireNonNull(min);
+        this.max = Objects.requireNonNull(max);
+        this.orgRaster[0] = min;
+        this.orgRaster[1] = new EastNorth(min.east(), max.north());
+        this.orgRaster[2] = max;
+        this.orgRaster[3] = new EastNorth(max.east(), min.north());
+        this.orgCroppedRaster[0] = min;
+        this.orgCroppedRaster[1] = new EastNorth(min.east(), max.north());
+        this.orgCroppedRaster[2] = max;
+        this.orgCroppedRaster[3] = new EastNorth(max.east(), min.north());
+        // img can be null for a hack used in overlapping detection
+        this.imageOriginalHeight = (img == null ? 1 : img.getHeight());
+        this.imageOriginalWidth = (img == null ? 1 : img.getWidth());
+        this.wmsLayer = wmsLayer;
+        updatePixelPer();
+    }
+
+    public static GraphicsConfiguration getDefaultConfiguration() {
+        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        GraphicsDevice gd = ge.getDefaultScreenDevice();
+        return gd.getDefaultConfiguration();
+    }
+
+    /**
+     * Recalculate the new bounding box of the image based on the four points provided as parameters.
+     * The new bbox defined in [min.max] will retain the extreme values of both boxes.
+     * @param p1 one of the bounding box corner
+     * @param p2 one of the bounding box corner
+     * @param p3 one of the bounding box corner
+     * @param p4 one of the bounding box corner
+     */
+    private EastNorthBound computeNewBounding(EastNorth p1, EastNorth p2, EastNorth p3, EastNorth p4) {
+        EastNorth[] pt = new EastNorth[4];
+        pt[0] = p1;
+        pt[1] = p2;
+        pt[2] = p3;
+        pt[3] = p4;
+        double smallestEast = Double.MAX_VALUE;
+        double smallestNorth = Double.MAX_VALUE;
+        double highestEast = Double.MIN_VALUE;
+        double highestNorth = Double.MIN_VALUE;
+        for (int i = 0; i <= 3; i++) {
+            smallestEast = Math.min(pt[i].east(), smallestEast);
+            smallestNorth = Math.min(pt[i].north(), smallestNorth);
+            highestEast = Math.max(pt[i].east(), highestEast);
+            highestNorth = Math.max(pt[i].north(), highestNorth);
+        }
+        return new EastNorthBound(new EastNorth(smallestEast, smallestNorth),
+                new EastNorth(highestEast, highestNorth));
+    }
+
+    public boolean contains(EastNorth en) {
+        return min.east() <= en.east() && en.east() <= max.east() && min.north() <= en.north()
+                && en.north() <= max.north();
+    }
+
+    public void paint(Graphics2D g, NavigatableComponent nc, boolean backgroundTransparent, float transparency,
+            boolean drawBoundaries) {
+        if (image == null || min == null || max == null)
+            return;
+
+        // apply offsets defined manually when vector images are translated manually (not saved in cache)
+        double dx = 0, dy = 0;
+        if (wmsLayer != null) {
+            dx = wmsLayer.deltaEast;
+            dy = wmsLayer.deltaNorth;
+        }
+        Point minPt = nc.getPoint(new EastNorth(min.east()+dx, min.north()+dy));
+        Point maxPt = nc.getPoint(new EastNorth(max.east()+dx, max.north()+dy));
+
+        if (!g.hitClip(minPt.x, maxPt.y, maxPt.x - minPt.x, minPt.y - maxPt.y))
+            return;
+
+        if (backgroundTransparent && transparency < 1.0f)
+            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, transparency));
+        if (drawBoundaries) {
+            if (orgCroppedRaster == null) {
+                // this is the old cache format where only [min,max] bbox is stored
+                g.setColor(Color.green);
+                g.drawRect(minPt.x, maxPt.y, maxPt.x - minPt.x, minPt.y - maxPt.y);
+            } else {
+                Point[] croppedPoint = new Point[5];
+                for (int i = 0; i < 4; i++) {
+                    croppedPoint[i] = nc.getPoint(
+                            new EastNorth(orgCroppedRaster[i].east()+dx, orgCroppedRaster[i].north()+dy));
+                }
+                croppedPoint[4] = croppedPoint[0];
+                for (int i = 0; i < 4; i++) {
+                    g.setColor(Color.green);
+                    g.drawLine(croppedPoint[i].x, croppedPoint[i].y, croppedPoint[i+1].x, croppedPoint[i+1].y);
+                }
+                /*
+                //Uncomment this section to display the original image size (before cropping)
+                Point[] orgPoint = new Point[5];
+                for (int i=0; i<4; i++)
+                    orgPoint[i] = nc.getPoint(orgRaster[i]);
+                orgPoint[4] = orgPoint[0];
+                for (int i=0; i<4; i++) {
+                  g.setColor(Color.red);
+                  g.drawLine(orgPoint[i].x, orgPoint[i].y, orgPoint[i+1].x, orgPoint[i+1].y);
+                }
+                */
+            }
+        }
+            g.drawImage(image, minPt.x, maxPt.y, maxPt.x, minPt.y, // dest
+                        0, 0, image.getWidth(), image.getHeight(), // src
+                        null);
+        if (backgroundTransparent && transparency < 1.0f)
+            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+    }
+
+    /**
+     * Is the given bbox overlapping this image ?
+     */
+    public boolean overlap(GeorefImage georefImage) {
+        if (this.contains(georefImage.min) || this.contains(georefImage.max))
+            return true;
+        if (this.contains(new EastNorth(georefImage.min.east(), georefImage.max.north()))
+                || this.contains(new EastNorth(georefImage.max.east(), georefImage.min.north())))
+            return true;
+        return false;
+    }
+
+    /**
+     * Make all pixels masked by the given georefImage transparent in this image
+     */
+    public void withdraw(GeorefImage georefImage) {
+        double minMaskEast = (georefImage.min.east() > this.min.east()) ? georefImage.min.east() : this.min.east();
+        double maxMaskEast = (georefImage.max.east() < this.max.east()) ? georefImage.max.east() : this.max.east();
+        double minMaskNorth = (georefImage.min.north() > this.min.north()) ? georefImage.min.north() : this.min.north();
+        double maxMaskNorth = (georefImage.max.north() < this.max.north()) ? georefImage.max.north() : this.max.north();
+        if ((maxMaskNorth - minMaskNorth) > 0 && (maxMaskEast - minMaskEast) > 0) {
+            double pxPerEast = (max.east() - min.east()) / image.getWidth();
+            double pxPerNorth = (max.north() - min.north()) / image.getHeight();
+            int minXMaskPixel = (int) ((minMaskEast - min.east()) / pxPerEast);
+            int minYMaskPixel = (int) ((max.north() - maxMaskNorth) / pxPerNorth);
+            int widthXMaskPixel = Math.abs((int) ((maxMaskEast - minMaskEast) / pxPerEast));
+            int heightYMaskPixel = Math.abs((int) ((maxMaskNorth - minMaskNorth) / pxPerNorth));
+            Graphics g = image.getGraphics();
+            for (int x = minXMaskPixel; x < minXMaskPixel + widthXMaskPixel; x++) {
+                for (int y = minYMaskPixel; y < minYMaskPixel + heightYMaskPixel; y++) {
+                    image.setRGB(x, y, VectorImageModifier.cadastreBackgroundTransp);
+                }
+            }
+            g.dispose();
+        }
+    }
+
+    /**
+     * Method required by BufferedImage serialization.
+     * Save only primitives to keep cache independent of software changes.
+     */
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        if (WMSLayer.currentFormat >= 2) {
+            max = new EastNorth(in.readDouble(), in.readDouble());
+            min = new EastNorth(in.readDouble(), in.readDouble());
+        }
+        orgRaster = null;
+        orgCroppedRaster = null;
+        if (WMSLayer.currentFormat >= 3) {
+            orgRaster = new EastNorth[4];
+            orgCroppedRaster = new EastNorth[4];
+            angle = in.readDouble();
+            orgRaster[0] = new EastNorth(in.readDouble(), in.readDouble());
+            orgRaster[1] = new EastNorth(in.readDouble(), in.readDouble());
+            orgRaster[2] = new EastNorth(in.readDouble(), in.readDouble());
+            orgRaster[3] = new EastNorth(in.readDouble(), in.readDouble());
+            orgCroppedRaster[0] = new EastNorth(in.readDouble(), in.readDouble());
+            orgCroppedRaster[1] = new EastNorth(in.readDouble(), in.readDouble());
+            orgCroppedRaster[2] = new EastNorth(in.readDouble(), in.readDouble());
+            orgCroppedRaster[3] = new EastNorth(in.readDouble(), in.readDouble());
+        }
+        if (WMSLayer.currentFormat >= 4) {
+            imageOriginalHeight = in.readInt();
+            imageOriginalWidth = in.readInt();
+        }
+        image = ImageIO.read(ImageIO.createImageInputStream(in));
+        updatePixelPer();
+    }
+
+    /**
+     * Method required by BufferedImage serialization.
+     * Use only primitives for stability in time (not influenced by josm-core changes).
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        out.writeDouble(max.getX()); out.writeDouble(max.getY());
+        out.writeDouble(min.getX()); out.writeDouble(min.getY());
+        if (orgRaster == null) { // just in case we save an old format layer already cached
+            orgRaster = new EastNorth[4];
+            orgCroppedRaster = new EastNorth[4];
+        }
+        out.writeDouble(angle);
+        out.writeDouble(orgRaster[0].getX()); out.writeDouble(orgRaster[0].getY());
+        out.writeDouble(orgRaster[1].getX()); out.writeDouble(orgRaster[1].getY());
+        out.writeDouble(orgRaster[2].getX()); out.writeDouble(orgRaster[2].getY());
+        out.writeDouble(orgRaster[3].getX()); out.writeDouble(orgRaster[3].getY());
+        out.writeDouble(orgCroppedRaster[0].getX()); out.writeDouble(orgCroppedRaster[0].getY());
+        out.writeDouble(orgCroppedRaster[1].getX()); out.writeDouble(orgCroppedRaster[1].getY());
+        out.writeDouble(orgCroppedRaster[2].getX()); out.writeDouble(orgCroppedRaster[2].getY());
+        out.writeDouble(orgCroppedRaster[3].getX()); out.writeDouble(orgCroppedRaster[3].getY());
+        // Write image as a format 3 if cache was loaded with this format to avoid incompatibilities.
+        if (WMSLayer.currentFormat >= 4) {
+            out.writeInt(imageOriginalHeight);
+            out.writeInt(imageOriginalWidth);
+        }
+        ImageIO.write(image, "png", ImageIO.createImageOutputStream(out));
+    }
+
+    private void updatePixelPer() {
+        pixelPerEast = image.getWidth()/(max.east()-min.east());
+        pixelPerNorth = image.getHeight()/(max.north()-min.north());
+    }
+
+    public double getPixelPerEast() {
+        return pixelPerEast;
+    }
+
+    public double getPixelPerNorth() {
+        return pixelPerNorth;
+    }
+
+    @Override
+    public String toString() {
+        return "GeorefImage[min=" + min + ", max=" + max + ", image" + image + "]";
+    }
+
+    /*
+     * Following methods are used for affine transformation of two points p1 and p2
+     */
+    /**
+     * Add a translation (dx, dy) to this image min,max coordinates
+     * @param dx delta added to X image coordinate
+     * @param dy delta added to Y image coordinate
+     */
+    public void shear(double dx, double dy) {
+        min = new EastNorth(min.east() + dx, min.north() + dy);
+        max = new EastNorth(max.east() + dx, max.north() + dy);
+        for (int i = 0; i < 4; i++) {
+            orgRaster[i] = new EastNorth(orgRaster[i].east() + dx, orgRaster[i].north() + dy);
+            orgCroppedRaster[i] = new EastNorth(orgCroppedRaster[i].east() + dx, orgCroppedRaster[i].north() + dy);
+        }
+    }
+
+    /**
+     * Change this image scale by moving the min,max coordinates around an anchor
+     */
+    public void scale(EastNorth anchor, double proportion) {
+        min = anchor.interpolate(min, proportion);
+        max = anchor.interpolate(max, proportion);
+        for (int i = 0; i < 4; i++) {
+            orgRaster[i] = anchor.interpolate(orgRaster[i], proportion);
+            orgCroppedRaster[i] = anchor.interpolate(orgCroppedRaster[i], proportion);
+        }
+        updatePixelPer();
+    }
+
+    /**
+     * Rotate this image and its min/max coordinates around anchor point
+     * @param anchor anchor of rotation
+     * @param old_ang previous angle of image before rotation (0 the first time)(in radian)
+     * @param delta_ang angle of rotation (in radian)
+     */
+    public void rotate(EastNorth anchor, double delta_ang) {
+        if (orgRaster == null || orgCroppedRaster == null)
+            return;
+        // rotate the bounding boxes coordinates first
+        for (int i = 0; i < 4; i++) {
+            orgRaster[i] = orgRaster[i].rotate(anchor, delta_ang);
+            orgCroppedRaster[i] = orgCroppedRaster[i].rotate(anchor, delta_ang);
+        }
+        // rotate the image now
+        double sin = Math.abs(Math.sin(angle+delta_ang)), cos = Math.abs(Math.cos(angle+delta_ang));
+        int w = imageOriginalWidth, h = imageOriginalHeight;
+        int neww = (int) Math.floor(w*cos+h*sin);
+        int newh = (int) Math.floor(h*cos+w*sin);
+        GraphicsConfiguration gc = getDefaultConfiguration();
+        BufferedImage result = gc.createCompatibleImage(neww, newh, image.getTransparency());
+        Graphics2D g = result.createGraphics();
+        g.translate((neww-image.getWidth())/2, (newh-image.getHeight())/2);
+        g.rotate(delta_ang, image.getWidth()/2, image.getHeight()/2);
+        g.drawRenderedImage(image, null);
+        g.dispose();
+        image = result;
+        EastNorthBound enb = computeNewBounding(orgCroppedRaster[0], orgCroppedRaster[1], orgCroppedRaster[2], orgCroppedRaster[3]);
+        min = enb.min;
+        max = enb.max;
+        angle += delta_ang;
+    }
+
+    /**
+     * Crop the image based on new bbox coordinates adj1 and adj2 (for raster images only).
+     * @param adj1 is the new corner bottom, left
+     * @param adj2 is the new corner top, right
+     */
+    public void crop(EastNorth adj1, EastNorth adj2) {
+        // s1 and s2 have 0,0 at top, left where all EastNorth coord. have 0,0 at bottom, left
+        int sx1 = (int) ((adj1.getX() - min.getX())*getPixelPerEast());
+        int sy1 = (int) ((max.getY() - adj2.getY())*getPixelPerNorth());
+        int sx2 = (int) ((adj2.getX() - min.getX())*getPixelPerEast());
+        int sy2 = (int) ((max.getY() - adj1.getY())*getPixelPerNorth());
+        int newWidth = Math.abs(sx2 - sx1);
+        int newHeight = Math.abs(sy2 - sy1);
+        BufferedImage new_img = new BufferedImage(newWidth, newHeight, image.getType());
+        Graphics g = new_img.getGraphics();
+        g.drawImage(image, 0, 0, newWidth-1, newHeight-1,
+                sx1, sy1, sx2, sy2,
+                this);
+        image = new_img;
+        this.min = adj1;
+        this.max = adj2;
+        this.orgCroppedRaster[0] = min;
+        this.orgCroppedRaster[1] = new EastNorth(min.east(), max.north());
+        this.orgCroppedRaster[2] = max;
+        this.orgCroppedRaster[3] = new EastNorth(max.east(), min.north());
+        this.imageOriginalWidth = newWidth;
+        this.imageOriginalHeight = newHeight;
+        updatePixelPer();
+    }
+
+    @Override
+    public boolean imageUpdate(Image img, int infoflags, int x, int y,
+            int width, int height) {
+        return false;
+    }
+
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/GrabThread.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/GrabThread.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/GrabThread.java	(revision 33638)
@@ -0,0 +1,236 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+
+public class GrabThread extends Thread {
+
+    private boolean canceled;
+
+    private CadastreGrabber grabber;
+
+    private WMSLayer wmsLayer;
+
+    private Lock lockImagesToGrag = new ReentrantLock();
+
+    private ArrayList<EastNorthBound> imagesToGrab = new ArrayList<>();
+
+    private CacheControl cacheControl = null;
+
+    private EastNorthBound currentGrabImage;
+
+    private Lock lockCurrentGrabImage = new ReentrantLock();
+
+    /**
+     * Call directly grabber for raster images or prepare thread for vector images
+     */
+    public void addImages(ArrayList<EastNorthBound> moreImages) {
+        lockImagesToGrag.lock();
+        imagesToGrab.addAll(moreImages);
+        lockImagesToGrag.unlock();
+        synchronized (this) {
+            this.notify();
+        }
+        Main.info("Added " + moreImages.size() + " to the grab thread");
+        if (wmsLayer.isRaster()) {
+            waitNotification();
+        }
+    }
+
+    public int getImagesToGrabSize() {
+        lockImagesToGrag.lock();
+        int size = imagesToGrab.size();
+        lockImagesToGrag.unlock();
+        return size;
+    }
+
+    public ArrayList<EastNorthBound> getImagesToGrabCopy() {
+        ArrayList<EastNorthBound> copyList = new ArrayList<>();
+        lockImagesToGrag.lock();
+        for (EastNorthBound img : imagesToGrab) {
+            EastNorthBound imgCpy = new EastNorthBound(img.min, img.max);
+            copyList.add(imgCpy);
+        }
+        lockImagesToGrag.unlock();
+        return copyList;
+    }
+
+    public void clearImagesToGrab() {
+        lockImagesToGrag.lock();
+        imagesToGrab.clear();
+        lockImagesToGrag.unlock();
+    }
+
+    @Override
+    public void run() {
+        for (;;) {
+            while (getImagesToGrabSize() > 0) {
+                lockImagesToGrag.lock();
+                lockCurrentGrabImage.lock();
+                currentGrabImage = imagesToGrab.get(0);
+                lockCurrentGrabImage.unlock();
+                imagesToGrab.remove(0);
+                lockImagesToGrag.unlock();
+                if (canceled) {
+                    break;
+                } else {
+                    GeorefImage newImage;
+                    try {
+                        Main.map.repaint(); // paint the current grab box
+                        newImage = grabber.grab(wmsLayer, currentGrabImage.min, currentGrabImage.max);
+                    } catch (IOException e) {
+                        Main.warn("Download action canceled by user or server did not respond");
+                        setCanceled(true);
+                        break;
+                    } catch (OsmTransferException e) {
+                        Main.error("OSM transfer failed");
+                        setCanceled(true);
+                        break;
+                    }
+                    if (grabber.getWmsInterface().downloadCanceled) {
+                        Main.info("Download action canceled by user");
+                        setCanceled(true);
+                        break;
+                    }
+                    try {
+                        if (CadastrePlugin.backgroundTransparent) {
+                            wmsLayer.imagesLock.lock();
+                            for (GeorefImage img : wmsLayer.getImages()) {
+                                if (img.overlap(newImage))
+                                    // mask overlapping zone in already grabbed image
+                                    img.withdraw(newImage);
+                                else
+                                    // mask overlapping zone in new image only when new image covers completely the
+                                    // existing image
+                                    newImage.withdraw(img);
+                            }
+                            wmsLayer.imagesLock.unlock();
+                        }
+                        wmsLayer.addImage(newImage);
+                        wmsLayer.invalidate();
+                        saveToCache(newImage);
+                    } catch (NullPointerException e) {
+                        Main.info("Layer destroyed. Cancel grab thread");
+                        setCanceled(true);
+                    }
+                }
+            }
+            Main.info("grab thread list empty");
+            lockCurrentGrabImage.lock();
+            currentGrabImage = null;
+            lockCurrentGrabImage.unlock();
+            if (canceled) {
+                clearImagesToGrab();
+                canceled = false;
+            }
+            if (wmsLayer.isRaster()) {
+                notifyWaiter();
+            }
+            waitNotification();
+        }
+    }
+
+    public void saveToCache(GeorefImage image) {
+        if (CacheControl.cacheEnabled && !wmsLayer.isRaster()) {
+            getCacheControl().saveCache(image);
+        }
+    }
+
+    public void saveNewCache() {
+        if (CacheControl.cacheEnabled) {
+            getCacheControl().deleteCacheFile();
+            wmsLayer.imagesLock.lock();
+            for (GeorefImage image : wmsLayer.getImages()) {
+                getCacheControl().saveCache(image);
+            }
+            wmsLayer.imagesLock.unlock();
+        }
+    }
+
+    public void cancel() {
+        clearImagesToGrab();
+        if (cacheControl != null) {
+            while (!cacheControl.isCachePipeEmpty()) {
+                Main.info("Try to close a WMSLayer which is currently saving in cache : wait 1 sec.");
+                CadastrePlugin.safeSleep(1000);
+            }
+        }
+    }
+
+    public CacheControl getCacheControl() {
+        if (cacheControl == null)
+            cacheControl = new CacheControl(wmsLayer);
+        return cacheControl;
+    }
+
+    public GrabThread(WMSLayer wmsLayer) {
+        this.wmsLayer = wmsLayer;
+    }
+
+    public void paintBoxesToGrab(Graphics g, MapView mv) {
+        if (getImagesToGrabSize() > 0) {
+            ArrayList<EastNorthBound> imagesToGrab = getImagesToGrabCopy();
+            for (EastNorthBound img : imagesToGrab) {
+                paintBox(g, mv, img, Color.red);
+            }
+        }
+        lockCurrentGrabImage.lock();
+        if (currentGrabImage != null) {
+            paintBox(g, mv, currentGrabImage, Color.orange);
+        }
+        lockCurrentGrabImage.unlock();
+    }
+
+    private void paintBox(Graphics g, MapView mv, EastNorthBound img, Color color) {
+        Point[] croppedPoint = new Point[5];
+        croppedPoint[0] = mv.getPoint(img.min);
+        croppedPoint[1] = mv.getPoint(new EastNorth(img.min.east(), img.max.north()));
+        croppedPoint[2] = mv.getPoint(img.max);
+        croppedPoint[3] = mv.getPoint(new EastNorth(img.max.east(), img.min.north()));
+        croppedPoint[4] = croppedPoint[0];
+        for (int i = 0; i < 4; i++) {
+            g.setColor(color);
+            g.drawLine(croppedPoint[i].x, croppedPoint[i].y, croppedPoint[i+1].x, croppedPoint[i+1].y);
+        }
+    }
+
+    public boolean isCanceled() {
+        return canceled;
+    }
+
+    public void setCanceled(boolean canceled) {
+        this.canceled = canceled;
+    }
+
+    public CadastreGrabber getGrabber() {
+        return grabber;
+    }
+
+    public void setGrabber(CadastreGrabber grabber) {
+        this.grabber = grabber;
+    }
+
+    private synchronized void notifyWaiter() {
+        this.notify();
+    }
+
+    private synchronized void waitNotification() {
+        try {
+            wait();
+        } catch (InterruptedException e) {
+            Main.error(e);
+        }
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/ImageModifier.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/ImageModifier.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/ImageModifier.java	(revision 33638)
@@ -0,0 +1,178 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import java.awt.Color;
+import java.awt.Transparency;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorConvertOp;
+import java.awt.image.DataBuffer;
+import java.awt.image.IndexColorModel;
+import java.util.Objects;
+
+public abstract class ImageModifier {
+    /**
+     * Current background color used by cadastre.gouv.fr
+     */
+    //public static int cadastreBackgroundTransp = 1; // original white but transparent
+
+    protected int parcelColor = Color.RED.getRGB();
+
+    protected BufferedImage bufferedImage;
+
+    public static int[] cRoofColors = new int[] {-197380, -592138};
+    public static int[] cBuilingFootColors = new int[] {-256};
+
+    protected BufferedImage convert1(BufferedImage src) {
+        IndexColorModel icm = new IndexColorModel(
+            1, 2,
+            new byte[] {(byte) 0, (byte) 0xFF},
+            new byte[] {(byte) 0, (byte) 0xFF},
+            new byte[] {(byte) 0, (byte) 0xFF}
+        );
+
+        BufferedImage dest = new BufferedImage(
+            src.getWidth(), src.getHeight(),
+            BufferedImage.TYPE_BYTE_BINARY,
+            icm
+            );
+
+        ColorConvertOp cco = new ColorConvertOp(
+            src.getColorModel().getColorSpace(),
+            dest.getColorModel().getColorSpace(),
+            null
+            );
+
+        cco.filter(src, dest);
+
+        return dest;
+      }
+
+    /**
+     * Converts the source image to 4-bit colour
+     * using the default 16-colour palette:
+     * <ul>
+     *  <li>black</li><li>dark red</li><li>dark green</li>
+     *  <li>dark yellow</li><li>dark blue</li><li>dark magenta</li>
+     *  <li>dark cyan</li><li>dark grey</li><li>light grey</li>
+     *  <li>red</li><li>green</li><li>yellow</li><li>blue</li>
+     *  <li>magenta</li><li>cyan</li><li>white</li>
+     * </ul>
+     * No transparency.
+     * @param src the source image to convert
+     * @return a copy of the source image with a 4-bit colour depth, with the default colour pallette
+     */
+    protected BufferedImage convert4(BufferedImage src) {
+        int[] cmap = new int[] {
+          0x000000, 0x800000, 0x008000, 0x808000,
+          0x000080, 0x800080, 0x008080, 0x808080,
+          0xC0C0C0, 0xFF0000, 0x00FF00, 0xFFFF00,
+          0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFF
+        };
+        return convert4(src, cmap);
+      }
+
+      /**
+       * Converts the source image to 4-bit colour
+       * using the given colour map.  No transparency.
+       * @param src the source image to convert
+       * @param cmap the colour map, which should contain no more than 16 entries
+       * The entries are in the form RRGGBB (hex).
+       * @return a copy of the source image with a 4-bit colour depth, with the custom colour pallette
+       */
+    protected BufferedImage convert4(BufferedImage src, int[] cmap) {
+        IndexColorModel icm = new IndexColorModel(
+            4, cmap.length, cmap, 0, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE
+            );
+        BufferedImage dest = new BufferedImage(
+            src.getWidth(), src.getHeight(),
+            BufferedImage.TYPE_BYTE_BINARY,
+            icm
+            );
+        ColorConvertOp cco = new ColorConvertOp(
+            src.getColorModel().getColorSpace(),
+            dest.getColorModel().getColorSpace(),
+            null
+            );
+        cco.filter(src, dest);
+
+        return dest;
+      }
+
+    protected BufferedImage convert8(BufferedImage src) {
+        BufferedImage dest = new BufferedImage(
+            src.getWidth(), src.getHeight(),
+            BufferedImage.TYPE_BYTE_INDEXED
+            );
+        ColorConvertOp cco = new ColorConvertOp(
+            src.getColorModel().getColorSpace(),
+            dest.getColorModel().getColorSpace(),
+            null
+            );
+        cco.filter(src, dest);
+        return dest;
+      }
+
+    public boolean isBuildingColor(int rgb, boolean ignoreParcelColor) {
+        for (int i = 0; i < cBuilingFootColors.length; i++) {
+            if (rgb == cBuilingFootColors[i])
+                    return true;
+        }
+        if (ignoreParcelColor && (rgb == parcelColor))
+            return true;
+        return false;
+    }
+
+    public boolean isRoofColor(int rgb, boolean ignoreParcelColor) {
+        for (int i = 0; i < cRoofColors.length; i++) {
+            if (rgb == cRoofColors[i])
+                    return true;
+        }
+        if (ignoreParcelColor && (rgb == parcelColor))
+            return true;
+        return false;
+    }
+
+    public boolean isParcelColor(BufferedImage img, int x, int y) {
+        int rgb = img.getRGB(x, y);
+        return (rgb == parcelColor);
+    }
+
+    public boolean isBuildingOrRoofColor(BufferedImage img, int x, int y, boolean ignoreParcelColor) {
+        int rgb = img.getRGB(x, y);
+        boolean ret = isBuildingColor(rgb, ignoreParcelColor) || isRoofColor(rgb, ignoreParcelColor);
+        return ret;
+    }
+
+    public boolean isBuildingOrRoofColor(BufferedImage img, int x, int y, boolean colorType, boolean ignoreParcelColor) {
+        int rgb = img.getRGB(x, y);
+        boolean ret;
+        if (colorType)
+            ret = isBuildingColor(rgb, ignoreParcelColor);
+        else
+            ret = isRoofColor(rgb, ignoreParcelColor);
+        return ret;
+    }
+
+    /**
+     * Checks if the rgb value is the black background color
+     */
+    public boolean isBackgroundColor(BufferedImage img, int x, int y) {
+        return (img.getRGB(x, y) == -1);
+    }
+
+    /**
+     * Returns the buffered image.
+     * @return the buffered image
+     */
+    public final BufferedImage getBufferedImage() {
+        return bufferedImage;
+    }
+
+    /**
+     * Sets the buffered image.
+     * @param bufferedImage the buffered image
+     */
+    protected final void setBufferedImage(BufferedImage bufferedImage) {
+        this.bufferedImage = Objects.requireNonNull(bufferedImage);
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/RasterImageGeoreferencer.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/RasterImageGeoreferencer.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/RasterImageGeoreferencer.java	(revision 33638)
@@ -0,0 +1,363 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.tools.GBC;
+
+public class RasterImageGeoreferencer implements MouseListener {
+
+    private int countMouseClicked = 0;
+    private int mode = 0;
+    private int cGetCorners = 1;
+    private int cGetLambertCrosspieces = 2;
+    private EastNorth ea1;
+    private EastNorth ea2;
+    private long mouseClickedTime = 0;
+    private WMSLayer wmsLayer;
+    private EastNorth georefpoint1;
+    private EastNorth georefpoint2;
+    private boolean ignoreMouseClick = false;
+    private boolean clickOnTheMap = false;
+
+    /**
+     * The time which needs to pass between two clicks during georeferencing, in milliseconds
+     */
+    private int initialClickDelay;
+
+    public void addListener() {
+        Main.map.mapView.addMouseListener(this);
+    }
+
+    /**
+    *
+    * @return false if all operations are canceled
+    */
+   public boolean startCropping(WMSLayer wmsLayer) {
+       this.wmsLayer = wmsLayer;
+       mode = cGetCorners;
+       countMouseClicked = 0;
+       initialClickDelay = Main.pref.getInteger("cadastrewms.georef-click-delay", 200);
+       mouseClickedTime = System.currentTimeMillis();
+       Object[] options = {"OK", "Cancel"};
+       int ret = JOptionPane.showOptionDialog(null,
+               tr("Click first corner for image cropping\n(two points required)"),
+               tr("Image cropping"),
+               JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
+               null, options, options[0]);
+       if (ret == JOptionPane.OK_OPTION) {
+           mouseClickedTime = System.currentTimeMillis();
+       } else
+           if (canceledOrRestartCurrAction("image cropping"))
+               return startCropping(wmsLayer);
+       return true;
+   }
+
+   /**
+    *
+    * @return false if all operations are canceled
+    */
+  public boolean startGeoreferencing(WMSLayer wmsLayer) {
+      this.wmsLayer = wmsLayer;
+      countMouseClicked = 0;
+      mode = cGetLambertCrosspieces;
+      initialClickDelay = Main.pref.getInteger("cadastrewms.georef-click-delay", 200);
+      mouseClickedTime = System.currentTimeMillis();
+      Object[] options = {"OK", "Cancel"};
+      int ret = JOptionPane.showOptionDialog(null,
+              tr("Click first Lambert crosspiece for georeferencing\n(two points required)"),
+              tr("Image georeferencing"),
+              JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
+              null, options, options[0]);
+      if (ret == JOptionPane.OK_OPTION) {
+          mouseClickedTime = System.currentTimeMillis();
+      } else
+          if (canceledOrRestartCurrAction("georeferencing"))
+              return startGeoreferencing(wmsLayer);
+      return true;
+  }
+
+  public boolean isRunning() {
+      return (countMouseClicked != 0 || mode != 0);
+  }
+
+  @Override
+  public void mouseClicked(MouseEvent e) {
+      if (System.currentTimeMillis() - mouseClickedTime < initialClickDelay) {
+          Main.info("mouse click bounce detected");
+          return; // mouse click anti-bounce
+      } else
+          mouseClickedTime = System.currentTimeMillis();
+      if (e.getButton() != MouseEvent.BUTTON1)
+          return;
+      if (ignoreMouseClick) return; // In case we are currently just allowing zooming to read lambert coordinates
+      EastNorth ea = Main.getProjection().latlon2eastNorth(Main.map.mapView.getLatLon(e.getX(), e.getY()));
+      Main.info("click:"+countMouseClicked+" ,"+ea+", mode:"+mode);
+      if (clickOnTheMap) {
+          clickOnTheMap = false;
+          handleNewCoordinates(ea.east(), ea.north());
+      } else {
+          // ignore clicks outside the image
+          if (ea.east() < wmsLayer.getImage(0).min.east() || ea.east() > wmsLayer.getImage(0).max.east()
+                  || ea.north() < wmsLayer.getImage(0).min.north() || ea.north() > wmsLayer.getImage(0).max.north()) {
+              Main.info("ignore click outside the image");
+              return;
+          }
+          countMouseClicked++;
+          if (mode == cGetCorners) {
+              if (countMouseClicked == 1) {
+                  ea1 = ea;
+                  continueCropping();
+              }
+              if (countMouseClicked == 2) {
+                  wmsLayer.cropImage(ea1, ea);
+                  wmsLayer.invalidate();
+                  startGeoreferencing(wmsLayer);
+              }
+          } else if (mode == cGetLambertCrosspieces) {
+              if (countMouseClicked == 1) {
+                  ea1 = ea;
+                  inputLambertPosition(); // This will automatically asks for second point and continue the georeferencing
+              }
+              if (countMouseClicked == 2) {
+                  ea2 = ea;
+                  inputLambertPosition(); // This will automatically ends the georeferencing
+              }
+          }
+      }
+  }
+
+  /**
+   *
+   * @return false if all operations are canceled
+   */
+ private boolean canceledOrRestartCurrAction(String action) {
+     Object[] options = {"Cancel", "Retry"};
+     int selectedValue = JOptionPane.showOptionDialog(null,
+             tr("Do you want to cancel completely\n"+
+                     "or just retry "+action+" ?"), "",
+             JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
+             null, options, options[0]);
+     countMouseClicked = 0;
+     if (selectedValue == 0) { // "Cancel"
+         // remove layer
+         Main.getLayerManager().removeLayer(wmsLayer);
+         wmsLayer = null;
+         Main.map.mapView.removeMouseListener(this);
+         return false;
+     }
+     return true;
+ }
+
+ /**
+  * Use point org1 as anchor for scale, then move org1 to dst1, then rotate org2 on dst2
+  * around org1/dst1 anchor
+  * @param org1 first point at original coordinate system (the grabbed image)
+  * @param org2 second point
+  * @param dst1 first point at final destination coordinate system (the real east/north coordinate system)
+  * @param dst2 second point
+  */
+ private void affineTransform(EastNorth org1, EastNorth org2, EastNorth dst1, EastNorth dst2) {
+     // handle an NPE case I'm not able to reproduce
+     if (org1 == null || org2 == null || dst1 == null || dst2 == null) {
+         JOptionPane.showMessageDialog(Main.parent,
+                 tr("Ooops. I failed to catch all coordinates\n"+
+                    "correctly. Retry please."));
+         Main.warn("failed to transform: one coordinate missing:"
+                    +"org1="+org1+", org2="+org2+", dst1="+dst1+", dst2="+dst2);
+         return;
+     }
+     double angle = dst1.heading(dst2) - org1.heading(org2);
+     double proportion = dst1.distance(dst2)/org1.distance(org2);
+     // move
+     double dx = dst1.getX() - org1.getX();
+     double dy = dst1.getY() - org1.getY();
+     wmsLayer.getImage(0).shear(dx, dy);
+     // rotate : dst1 is anchor for rotation and scale
+     wmsLayer.getImage(0).rotate(dst1, angle);
+     // scale image from anchor dst1
+     wmsLayer.getImage(0).scale(dst1, proportion);
+ }
+
+ /**
+  * Ends the georeferencing by computing the affine transformation
+  */
+ private void endGeoreferencing() {
+     Main.map.mapView.removeMouseListener(this);
+     affineTransform(ea1, ea2, georefpoint1, georefpoint2);
+     wmsLayer.grabThread.saveNewCache();
+     wmsLayer.invalidate();
+     actionCompleted();
+     clickOnTheMap = false;
+     ignoreMouseClick = false;
+ }
+
+ private void inputLambertPosition() {
+     JLabel labelEnterPosition = new JLabel(
+             tr("Enter cadastre east,north position"));
+     JLabel labelWarning = new JLabel(
+             tr("(Warning: verify north with arrow !!)"));
+     JPanel p = new JPanel(new GridBagLayout());
+     JLabel labelEast = new JLabel(tr("East"));
+     JLabel labelNorth = new JLabel(tr("North"));
+     final JTextField inputEast = new JTextField();
+     final JTextField inputNorth = new JTextField();
+     p.add(labelEnterPosition, GBC.eol());
+     p.add(labelWarning, GBC.eol());
+     p.add(labelEast, GBC.std().insets(0, 0, 10, 0));
+     p.add(inputEast, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 5, 0, 5));
+     p.add(labelNorth, GBC.std().insets(0, 0, 10, 0));
+     p.add(inputNorth, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 5, 0, 5));
+     final Object[] options = {tr("OK"),
+             tr("Cancel"),
+             tr("I use the mouse")};
+     final JOptionPane pane = new JOptionPane(p,
+             JOptionPane.INFORMATION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION,
+             null, options, options[0]);
+     String number;
+     if (countMouseClicked == 1)
+         number = "first";
+     else
+         number = "second";
+     JDialog dialog = pane.createDialog(Main.parent, tr(
+             "Set {0} Lambert coordinates", number));
+     dialog.setModal(false);
+     ignoreMouseClick = true; // To avoid mouseClicked from being called
+                              // during coordinates reading
+     dialog.setAlwaysOnTop(true);
+     dialog.setVisible(true);
+     pane.addPropertyChangeListener(new PropertyChangeListener() {
+         @Override
+         public void propertyChange(PropertyChangeEvent evt) {
+             if (JOptionPane.VALUE_PROPERTY.equals(evt.getPropertyName())) {
+                 ignoreMouseClick = false;
+                 // Cancel
+                 if (pane.getValue().equals(options[1])) {
+                     if (canceledOrRestartCurrAction("georeferencing"))
+                         startGeoreferencing(wmsLayer);
+                 }
+                 // Click on the map
+                 if (pane.getValue().equals(options[2])) {
+                     clickOnTheMap = true;
+                 } else {
+                 // OK (coordinates manually entered)
+                     clickOnTheMap = false;
+                     if (inputEast.getText().length() != 0
+                             && inputNorth.getText().length() != 0) {
+                         double e, n;
+                         try {
+                             e = Double.parseDouble(inputEast.getText());
+                             n = Double.parseDouble(inputNorth.getText());
+                         } catch (NumberFormatException ex) {
+                             return;
+                         }
+                         handleNewCoordinates(e, n);
+                     }
+                 }
+             }
+         }
+     });
+ }
+
+ /**
+ *
+ * @return false if all operations are canceled
+ */
+private boolean continueCropping() {
+    Object[] options = {"OK", "Cancel"};
+    int ret = JOptionPane.showOptionDialog(null,
+            tr("Click second corner for image cropping"),
+            tr("Image cropping"),
+            JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
+            null, options, options[0]);
+    if (ret != JOptionPane.OK_OPTION) {
+        if (canceledOrRestartCurrAction("image cropping"))
+            return startCropping(wmsLayer);
+    }
+    return true;
+}
+
+public void transformGeoreferencedImg() {
+    georefpoint1 = new EastNorth(wmsLayer.X0, wmsLayer.Y0);
+    georefpoint2 = new EastNorth(wmsLayer.X0+wmsLayer.fX*wmsLayer.communeBBox.max.getX(),
+            wmsLayer.Y0+wmsLayer.fY*wmsLayer.communeBBox.max.getX());
+    ea1 = new EastNorth(wmsLayer.getImage(0).min.east(), wmsLayer.getImage(0).max.north());
+    EastNorth ea2 = wmsLayer.getImage(0).max;
+    affineTransform(ea1, ea2, georefpoint1, georefpoint2);
+    wmsLayer.grabThread.saveNewCache();
+    wmsLayer.invalidate();
+}
+
+
+ /**
+ *
+ * @return false if all operations are canceled
+ */
+private boolean continueGeoreferencing() {
+    Object[] options = {"OK", "Cancel"};
+    int ret = JOptionPane.showOptionDialog(null,
+            tr("Click second Lambert crosspiece for georeferencing"),
+            tr("Image georeferencing"),
+            JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
+            null, options, options[0]);
+    if (ret != JOptionPane.OK_OPTION) {
+        if (canceledOrRestartCurrAction("georeferencing"))
+            return startGeoreferencing(wmsLayer);
+    }
+    return true;
+}
+
+ private void handleNewCoordinates(double e, double n) {
+     if (countMouseClicked == 1) {
+         georefpoint1 = new EastNorth(e, n);
+         continueGeoreferencing();
+     } else {
+         georefpoint2 = new EastNorth(e, n);
+         endGeoreferencing();
+     }
+ }
+
+ private void actionCompleted() {
+     countMouseClicked = 0;
+     mode = 0;
+     mouseClickedTime = System.currentTimeMillis();
+ }
+
+ public void actionInterrupted() {
+     actionCompleted();
+     if (wmsLayer != null) {
+         Main.getLayerManager().removeLayer(wmsLayer);
+         wmsLayer = null;
+     }
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent arg0) {
+ }
+
+ @Override
+ public void mouseExited(MouseEvent arg0) {
+ }
+
+ @Override
+ public void mousePressed(MouseEvent arg0) {
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent arg0) {
+ }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/RasterImageModifier.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/RasterImageModifier.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/RasterImageModifier.java	(revision 33638)
@@ -0,0 +1,106 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.IndexColorModel;
+
+import org.openstreetmap.josm.Main;
+
+public class RasterImageModifier extends ImageModifier {
+
+    private int cadastreBackground = -1; // white
+
+    public static int cadastreBackgroundTransp = 16777215; // original white but transparent
+
+    private boolean transparencyEnabled = false;
+
+    public RasterImageModifier(BufferedImage bi) {
+        setBufferedImage(bi);
+        transparencyEnabled = Main.pref.getBoolean("cadastrewms.backgroundTransparent");
+        if (transparencyEnabled)
+            makeTransparent();
+        if (Main.pref.getBoolean("cadastrewms.invertGrey"))
+            invertGrey();
+    }
+
+    /**
+     * Invert black/white/grey pixels (to change original black characters to white).
+     */
+    private void invertGrey() {
+        int w = bufferedImage.getWidth();
+        int h = bufferedImage.getHeight();
+        for (int x = 0; x < w; x++) {
+            for (int y = 0; y < h; y++) {
+                int pixel = bufferedImage.getRGB(x, y);
+                if ((!transparencyEnabled && pixel != cadastreBackground)
+                        || (transparencyEnabled && pixel != cadastreBackgroundTransp)) {
+                    bufferedImage.setRGB(x, y, reverseIfGrey(pixel));
+                }
+            }
+        }
+    }
+
+    /**
+     * Reverse the grey value if the pixel is grey (light grey becomes dark grey)
+     * Used for texts.
+     */
+    private int reverseIfGrey(int pixel) {
+        Color col = new Color(pixel);
+        int r = col.getRed();
+        int g = col.getGreen();
+        int b = col.getBlue();
+        if ((b == r) && (b == g)) {
+            pixel = (0x00 << 32) + ((byte) (255 - r) << 16) + ((byte) (255 - r) << 8) + ((byte) (255 - r));
+        }
+        return pixel;
+    }
+
+    private void makeTransparent() {
+        if (bufferedImage.getColorModel() instanceof ComponentColorModel ||
+            bufferedImage.getColorModel() instanceof IndexColorModel) {
+            int width = bufferedImage.getWidth();
+            int height = bufferedImage.getHeight();
+            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+            // converting grey scale colors to black/white is configurable (use less resources but is less readable)
+            boolean simplifyColors = Main.pref.getBoolean("cadastrewms.raster2bitsColors", false);
+            for (int y = 0; y < height; y++) {
+                for (int x = 0; x < width; x++) {
+                    int rgb = bufferedImage.getRGB(x, y);
+                    Color c = new Color(rgb);
+                    int r = c.getRed();
+                    int g = c.getGreen();
+                    int b = c.getBlue();
+                    Color maskedColor;
+                    if (rgb == cadastreBackground) {
+                        maskedColor = simplifyColors ? new Color(0xff, 0xff, 0xff, 0x00) :
+                            new Color(r, g, b, 0x00); // transparent
+                    } else {
+                        maskedColor = simplifyColors ? new Color(0, 0, 0, 0xFF) :
+                            new Color(r, g, b, 0xFF); // opaque
+                    }
+                    bi.setRGB(x, y, maskedColor.getRGB());
+                }
+            }
+            setBufferedImage(bi);
+        }
+        return;
+    }
+
+    /**
+     * Temporary fix for Java6 which doesn't de-serialize correctly cached image on disk.
+     * Recreate a new raster image based on what is loaded/serialized from disk cache.
+     * @return new image
+     */
+    public static BufferedImage fixRasterImage(BufferedImage img) {
+        int width = img.getWidth();
+        int height = img.getHeight();
+        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+        int[] rgbArray = new int[width * height];
+        img.getRGB(0, 0, width, height, rgbArray, 0, width);
+        bi.setRGB(0, 0, width, height, rgbArray, 0, width);
+        return bi;
+    }
+
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/SVGParser.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/SVGParser.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/SVGParser.java	(revision 33638)
@@ -0,0 +1,64 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import java.util.ArrayList;
+
+/**
+ * This class is not intended to be a real SVG parser. It's also not using existing
+ * xml parsers. It's just extracting the required strings from an SVG file coming
+ * from the French land registry cadastre.gouv.fr
+ *
+ */
+public class SVGParser {
+
+    private String cViewBoxStart = "viewBox=\"";
+    private String cViewBoxEnd = "\"";
+    private String cPathStart = "<path d=\"";
+    private String cClosedPathEnd = "\"/>";
+
+    /**
+     * The SVG viewBox looks like this:
+     *   viewBox="969780.0 320377.11 5466.130000000005 2846.429999999993"
+     * @param svg the SVG XML data
+     * @return double [x,y,dx,dy] of viewBox; null if parsing failed
+     */
+    public double[] getViewBox(String svg) {
+        int s = svg.indexOf(cViewBoxStart)+cViewBoxStart.length();
+        int e = svg.indexOf(cViewBoxEnd, s);
+        if (s != -1 && e != -1) {
+            try {
+                String str = svg.substring(s, e);
+                String[] viewBox = str.split(" ");
+                double[] dbox = new double[4];
+                for (int i = 0; i < 4; i++) {
+                    dbox[i] = Double.parseDouble(viewBox[i]);
+                }
+                return dbox;
+            } catch (Exception ex) {
+                return null;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Closed SVG paths are finishing with a "Z" at the end of the moves list.
+     */
+    public String[] getClosedPaths(String svg) {
+        ArrayList<String> path = new ArrayList<>();
+        int i = 0;
+        while (svg.indexOf(cPathStart, i) != -1) {
+            int s = svg.indexOf(cPathStart, i) + cViewBoxStart.length();
+            int e = svg.indexOf(cClosedPathEnd, s);
+            if (s != -1 && e != -1) {
+                String onePath = svg.substring(s, e);
+                if (onePath.indexOf("Z") != -1) // only closed SVG path
+                    path.add(onePath);
+            } else
+                break;
+            i = e;
+        }
+        return path.toArray(new String[ path.size() ]);
+    }
+
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/VectorImageModifier.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/VectorImageModifier.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/VectorImageModifier.java	(revision 33638)
@@ -0,0 +1,113 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.IndexColorModel;
+import java.awt.image.WritableRaster;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ColorHelper;
+
+public class VectorImageModifier extends ImageModifier {
+
+    private int cadastreBackground = -1; // white
+
+    public static int cadastreBackgroundTransp = 1; // original white but transparent
+
+    private int backgroundPixel = 0;
+
+    public VectorImageModifier() {
+        super();
+    }
+
+    public VectorImageModifier(BufferedImage bi, boolean monocolor) {
+        setBufferedImage(bi);
+        if (Main.pref.getBoolean("cadastrewms.backgroundTransparent"))
+            makeTransparent();
+        else if (Main.pref.getBoolean("cadastrewms.alterColors"))
+            replaceBackground();
+        if (Main.pref.getBoolean("cadastrewms.invertGrey"))
+            invertGrey();
+        if (monocolor)
+            setBufferedImage(convert8(convert4(bufferedImage)));
+    }
+
+    /**
+     * Replace the background color by the josm color.background color.
+     */
+    private void replaceBackground() {
+        int w = bufferedImage.getWidth();
+        int h = bufferedImage.getHeight();
+        int josmBackgroundColor = ColorHelper.html2color(Main.pref.get("color.background", "#000000")).getRGB();
+        for (int x = 0; x < w; x++) {
+            for (int y = 0; y < h; y++) {
+                int pixel = bufferedImage.getRGB(x, y);
+                if (pixel == cadastreBackground) {
+                    bufferedImage.setRGB(x, y, josmBackgroundColor);
+                }
+            }
+        }
+        // The cadastre has now a new background (for invertGrey())
+        cadastreBackground = josmBackgroundColor;
+    }
+
+    /**
+     * Invert black/white/grey pixels (to change original black characters to white).
+     */
+    private void invertGrey() {
+        int w = bufferedImage.getWidth();
+        int h = bufferedImage.getHeight();
+        for (int x = 0; x < w; x++) {
+            for (int y = 0; y < h; y++) {
+                int pixel = bufferedImage.getRGB(x, y);
+                if (pixel != cadastreBackground) {
+                    bufferedImage.setRGB(x, y, reverseIfGrey(pixel));
+                }
+            }
+        }
+    }
+
+    /**
+     * Reverse the grey value if the pixel is grey (light grey becomes dark grey)
+     * Used for texts.
+     */
+    private int reverseIfGrey(int pixel) {
+        Color col = new Color(pixel);
+        int r = col.getRed();
+        int g = col.getGreen();
+        int b = col.getBlue();
+        if ((b == r) && (b == g)) {
+            pixel = ((byte) col.getAlpha() << 24) + ((byte) (255 - r) << 16) + ((byte) (255 - r) << 8) + ((byte) (255 - r));
+        }
+        // Maybe we should try to find a better formula to avoid discontinuity when text is drawn on a colored item
+        // (building, ...). One could use the conversion to and from HSB to only change the brightness not the color.
+        // Note: the color palette does not have the inverse colors so it may be very weird!
+        return pixel;
+    }
+
+    private void makeTransparent() {
+        ColorModel colorModel = bufferedImage.getColorModel();
+        if (bufferedImage.getColorModel() instanceof IndexColorModel) {
+            // vector image (IndexColorModel)
+            IndexColorModel icm = (IndexColorModel) colorModel;
+            WritableRaster raster = bufferedImage.getRaster();
+            // pixel is offset in ICM's palette
+            backgroundPixel = 1; // default Cadastre background sample
+            int size = icm.getMapSize();
+            byte[] reds = new byte[size];
+            byte[] greens = new byte[size];
+            byte[] blues = new byte[size];
+            icm.getReds(reds);
+            icm.getGreens(greens);
+            icm.getBlues(blues);
+            // The cadastre background has now an alpha to 0 (for invertGrey())
+            cadastreBackground = 0x00ffffff;
+            IndexColorModel icm2 = new IndexColorModel(colorModel.getPixelSize(), size, reds, greens, blues,
+                    backgroundPixel);
+            setBufferedImage(new BufferedImage(icm2, raster, bufferedImage.isAlphaPremultiplied(), null));
+        }
+        return;
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/WMSException.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/WMSException.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/WMSException.java	(revision 33638)
@@ -0,0 +1,17 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+public class WMSException extends Exception {
+    private String message;
+    private static final long serialVersionUID = 1L;
+
+    public WMSException(String message) {
+        super();
+        this.message = message;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+}
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/WMSLayer.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/WMSLayer.java	(revision 33638)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/wms/WMSLayer.java	(revision 33638)
@@ -0,0 +1,736 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.fr.cadastre.wms;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.RenderingHints;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Vector;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
+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.gui.util.GuiHelper;
+import org.openstreetmap.josm.plugins.fr.cadastre.CadastrePlugin;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.MenuActionCancelGrab;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.MenuActionLoadFromCache;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.MenuActionRefineGeoRef;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.MenuActionSaveRasterAs;
+import org.openstreetmap.josm.plugins.fr.cadastre.actions.mapmode.WMSAdjustAction;
+import org.openstreetmap.josm.plugins.fr.cadastre.preferences.CadastrePreferenceSetting;
+
+/**
+ * This is a layer that grabs the current screen from the French cadastre WMS
+ * server. The data fetched this way is tiled and managed to the disc to reduce
+ * server load.
+ */
+public class WMSLayer extends Layer implements ImageObserver {
+
+    private int lambertZone = -1;
+
+    public CadastreGrabber grabber = new CadastreGrabber();
+
+    protected static final Icon icon = new ImageIcon(Toolkit.getDefaultToolkit().createImage(
+            CadastrePlugin.class.getResource("/images/cadastre_small.png")));
+
+    private Vector<GeorefImage> images = new Vector<>();
+
+    public Lock imagesLock = new ReentrantLock();
+
+    /**
+     * v1 to v2 = not supported
+     * v2 to v3 = add 4 more EastNorth coordinates in GeorefImages
+     * v3 to v4 = add original raster image width and height
+     */
+    protected final int serializeFormatVersion = 4;
+
+    public static int currentFormat;
+
+    private ArrayList<EastNorthBound> dividedBbox = new ArrayList<>();
+
+    private String location = "";
+
+    private String departement = "";
+
+    private String codeCommune = "";
+
+    public EastNorthBound communeBBox = new EastNorthBound(new EastNorth(0, 0), new EastNorth(0, 0));
+
+    private boolean isRaster;
+    private boolean isAlreadyGeoreferenced;
+    public double X0, Y0, angle, fX, fY;
+
+    // bbox of the georeferenced raster image (the nice horizontal and vertical box)
+    private EastNorth rasterMin;
+    private EastNorth rasterMax;
+    private double rasterRatio;
+
+    // offset for vector images temporarily shifted (correcting Cadastre artifacts), in pixels
+    public double deltaEast;
+    public double deltaNorth;
+
+    private Action saveAsPng;
+
+    private Action cancelGrab;
+
+    private Action refineGeoRef;
+
+    class ResetOffsetActionMenu extends JosmAction {
+        ResetOffsetActionMenu() {
+            super(tr("Reset offset"), null, tr("Reset offset (only vector images)"), null, false);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent arg0) {
+            deltaEast = 0;
+            deltaNorth = 0;
+            invalidate();
+        }
+    }
+
+    public boolean adjustModeEnabled;
+
+    public GrabThread grabThread;
+
+    /**
+     * Constructs a new {@code WMSLayer}.
+     */
+    public WMSLayer() {
+        this(tr("Blank Layer"), "", -1);
+    }
+
+    public WMSLayer(String location, String codeCommune, int lambertZone) {
+        super(buildName(location, codeCommune));
+        this.location = location;
+        this.codeCommune = codeCommune;
+        this.lambertZone = lambertZone;
+        grabThread = new GrabThread(this);
+        grabThread.start();
+        // enable auto-sourcing option
+        CadastrePlugin.pluginUsed = true;
+    }
+
+    @Override
+    public void destroy() {
+        // if the layer is currently saving the images in the cache, wait until it's finished
+        if (grabThread != null)
+                grabThread.cancel();
+        grabThread = null;
+        super.destroy();
+        images = null;
+        dividedBbox = null;
+        Main.info("Layer "+location+" destroyed");
+    }
+
+    private static String buildName(String location, String codeCommune) {
+        String ret = location.toUpperCase(Locale.FRANCE);
+        if (codeCommune != null && !codeCommune.isEmpty())
+            ret += "(" + codeCommune + ")";
+        return ret;
+    }
+
+    private String rebuildName() {
+        return buildName(this.location.toUpperCase(Locale.FRANCE), this.codeCommune);
+    }
+
+    public void grab(Bounds b) throws IOException {
+        grabThread.setCanceled(false);
+        grabThread.setGrabber(grabber);
+        // if it is the first layer, use the communeBBox as grab bbox (and not divided)
+        if (Main.getLayerManager().getLayers().size() == 1) {
+            final Bounds bounds = this.getCommuneBBox().toBounds();
+            GuiHelper.runInEDTAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    Main.map.mapView.zoomTo(bounds);
+                }
+            });
+            divideBbox(bounds, 1);
+        } else {
+            if (isRaster) {
+                divideBbox(new Bounds(Main.getProjection().eastNorth2latlon(rasterMin), Main.getProjection().eastNorth2latlon(rasterMax)),
+                        Integer.parseInt(Main.pref.get("cadastrewms.rasterDivider", CadastrePreferenceSetting.DEFAULT_RASTER_DIVIDER)));
+            } else
+                divideBbox(b,
+                        Integer.parseInt(Main.pref.get("cadastrewms.scale", CadastrePreferenceSetting.DEFAULT_GRAB_MULTIPLIER)));
+        }
+        grabThread.addImages(dividedBbox);
+    }
+
+    /**
+     * Divides the bounding box in smaller squares. Their size (and quantity) is configurable in Preferences.
+     *
+     * @param b      the original bbox, usually the current bbox on screen
+     * @param factor 1 = source bbox 1:1
+     *               2 = source bbox divided by 2x2 smaller boxes
+     *               3 = source bbox divided by 3x3 smaller boxes
+     *               4 = configurable size from preferences (100 meters per default) rounded
+     *                   allowing grabbing of next contiguous zone
+     */
+    private void divideBbox(Bounds b, int factor) {
+        EastNorth lambertMin = Main.getProjection().latlon2eastNorth(b.getMin());
+        EastNorth lambertMax = Main.getProjection().latlon2eastNorth(b.getMax());
+        double minEast = lambertMin.east()+deltaEast;
+        double minNorth = lambertMin.north()+deltaNorth;
+        double dEast = (lambertMax.east() - minEast) / factor;
+        double dNorth = (lambertMax.north() - minNorth) / factor;
+        dividedBbox.clear();
+        if (factor < 4 || isRaster) {
+            for (int xEast = 0; xEast < factor; xEast++) {
+                for (int xNorth = 0; xNorth < factor; xNorth++) {
+                    dividedBbox.add(new EastNorthBound(new EastNorth(minEast + xEast * dEast, minNorth + xNorth * dNorth),
+                                new EastNorth(minEast + (xEast + 1) * dEast, minNorth + (xNorth + 1) * dNorth)));
+                }
+            }
+        } else {
+            // divide to fixed size squares
+            // grab all square in a spiral starting from the center (usually the most interesting place)
+            int c = Integer.parseInt(Main.pref.get("cadastrewms.squareSize", String.valueOf(CadastrePreferenceSetting.DEFAULT_SQUARE_SIZE)));
+            lambertMin = lambertMin.add(-minEast % c, -minNorth % c);
+            lambertMax = lambertMax.add(c - lambertMax.east() % c, c - lambertMax.north() % c);
+            EastNorth mid = lambertMax.getCenter(lambertMin);
+            mid = mid.add(-1, 1); // in case the boxes side is a pair, select the one one top,left to follow the rotation
+            mid = mid.add(-mid.east() % c, -mid.north() % c);
+            int x = (int) (lambertMax.east() -lambertMin.east())/c;
+            int y = (int) (lambertMax.north() -lambertMin.north())/c;
+            int[] dx = {+1, 0, -1, 0};
+            int[] dy = {0, -1, 0, +1};
+            int currDir = -1, lDir = 1, i = 1, j = 0, k = -1;
+            if (x == 1)
+                currDir = 0;
+            dividedBbox.add(new EastNorthBound(mid, new EastNorth(mid.east()+c, mid.north()+c)));
+            while (i < (x*y)) {
+                i++;
+                j++;
+                if (j >= lDir) {
+                    k++;
+                    if (k > 1) {
+                        lDir++;
+                        k = 0;
+                    }
+                    j = 0;
+                    currDir = (currDir+1) % 4;
+                } else if (currDir >= 0 && j >= (currDir == 0 || currDir == 2 ? (x-1) : (y-1))) {
+                    // the overall is a rectangle, not a square. Jump to the other side to grab next square.
+                    k++;
+                    if (k > 1) {
+                        lDir++;
+                        k = 0;
+                    }
+                    j = lDir-1;
+                    currDir = (currDir+1) % 4;
+                    mid = new EastNorth(mid.east() + dx[currDir]*c*(lDir-1), mid.north() + dy[currDir]*c*(lDir-1));
+                }
+                mid = new EastNorth(mid.east() + dx[currDir]*c, mid.north() + dy[currDir]*c);
+                dividedBbox.add(new EastNorthBound(mid, new EastNorth(mid.east()+c, mid.north()+c)));
+            }
+        }
+    }
+
+    @Override
+    public Icon getIcon() {
+        return icon;
+    }
+
+    @Override
+    public String getToolTipText() {
+        String str = tr("WMS layer ({0}), {1} tile(s) loaded", getName(), images.size());
+        if (isRaster) {
+            str += "\n"+tr("Is not vectorized.");
+            str += "\n"+tr("Bounding box: {0}", communeBBox);
+            if (!images.isEmpty())
+                str += "\n"+tr("Image size (px): {0}/{1}", images.get(0).image.getWidth(), images.get(0).image.getHeight());
+        } else {
+            str += "\n"+tr("Is vectorized.");
+            str += "\n"+tr("Commune bbox: {0}", communeBBox);
+        }
+        return str;
+    }
+
+    @Override
+    public boolean isMergable(Layer other) {
+        return false;
+    }
+
+    @Override
+    public void mergeFrom(Layer from) {
+        // Do nothing
+    }
+
+    @Override
+    public void paint(Graphics2D g, final MapView mv, Bounds bounds) {
+        synchronized (this) {
+            Object savedInterpolation = g.getRenderingHint(RenderingHints.KEY_INTERPOLATION);
+            if (savedInterpolation == null) savedInterpolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
+            String interpolation = Main.pref.get("cadastrewms.imageInterpolation", "standard");
+            if (interpolation.equals("bilinear"))
+                g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+            else if (interpolation.equals("bicubic"))
+                g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+            else
+                g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+            imagesLock.lock();
+            for (GeorefImage img : images) {
+                img.paint(g, mv, CadastrePlugin.backgroundTransparent,
+                        CadastrePlugin.transparency, CadastrePlugin.drawBoundaries);
+            }
+            imagesLock.unlock();
+            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, savedInterpolation);
+        }
+        if (this.isRaster) {
+            paintCrosspieces(g, mv);
+        }
+        grabThread.paintBoxesToGrab(g, mv);
+        if (this.adjustModeEnabled) {
+            WMSAdjustAction.paintAdjustFrames(g, mv);
+        }
+    }
+
+    @Override
+    public void visitBoundingBox(BoundingXYVisitor v) {
+        for (GeorefImage img : images) {
+            v.visit(img.min);
+            v.visit(img.max);
+        }
+    }
+
+    @Override
+    public Object getInfoComponent() {
+        return getToolTipText();
+    }
+
+    @Override
+    public Action[] getMenuEntries() {
+        saveAsPng = new MenuActionSaveRasterAs(this);
+        saveAsPng.setEnabled(isRaster);
+        cancelGrab = new MenuActionCancelGrab(this);
+        cancelGrab.setEnabled(!isRaster && grabThread.getImagesToGrabSize() > 0);
+        refineGeoRef = new MenuActionRefineGeoRef(this);
+        refineGeoRef.setEnabled(isRaster && grabThread.getImagesToGrabSize() == 0);
+        Action resetOffset = new ResetOffsetActionMenu();
+        resetOffset.setEnabled(!isRaster && !images.isEmpty() && (deltaEast != 0.0 || deltaNorth != 0.0));
+        return new Action[] {
+                LayerListDialog.getInstance().createShowHideLayerAction(),
+                LayerListDialog.getInstance().createDeleteLayerAction(),
+                new MenuActionLoadFromCache(),
+                saveAsPng,
+                cancelGrab,
+                refineGeoRef,
+                resetOffset,
+                new LayerListPopup.InfoAction(this),
+        };
+    }
+
+    public GeorefImage findImage(EastNorth eastNorth) {
+        // Iterate in reverse, so we return the image which is painted last.
+        // (i.e. the topmost one)
+        for (int i = images.size() - 1; i >= 0; i--) {
+            if (images.get(i).contains(eastNorth)) {
+                return images.get(i);
+            }
+        }
+        return null;
+    }
+
+    public boolean isOverlapping(Bounds bounds) {
+        GeorefImage georefImage =
+            new GeorefImage(null,
+            Main.getProjection().latlon2eastNorth(bounds.getMin()),
+            Main.getProjection().latlon2eastNorth(bounds.getMax()), this);
+        for (GeorefImage img : images) {
+            if (img.overlap(georefImage))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Convert the eastNorth input coordinates to raster coordinates.
+     * The original raster size is [0,0,12286,8730] where 0,0 is the upper left corner and
+     * 12286,8730 is the approx. raster max size.
+     * @return the raster coordinates for the wms server request URL (minX,minY,maxX,maxY)
+     */
+    public String eastNorth2raster(EastNorth min, EastNorth max) {
+        double minX = (min.east() - rasterMin.east()) / rasterRatio;
+        double minY = (min.north() - rasterMin.north()) / rasterRatio;
+        double maxX = (max.east() - rasterMin.east()) / rasterRatio;
+        double maxY = (max.north() - rasterMin.north()) / rasterRatio;
+        return minX+","+minY+","+maxX+","+maxY;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    public void setLocation(String location) {
+        this.location = location;
+        setName(rebuildName());
+    }
+
+    public String getDepartement() {
+        return departement;
+    }
+
+    public void setDepartement(String departement) {
+        this.departement = departement;
+    }
+
+    public String getCodeCommune() {
+        return codeCommune;
+    }
+
+    public void setCodeCommune(String codeCommune) {
+        this.codeCommune = codeCommune;
+        setName(rebuildName());
+    }
+
+    public boolean isRaster() {
+        return isRaster;
+    }
+
+    public void setRaster(boolean isRaster) {
+        this.isRaster = isRaster;
+        if (saveAsPng != null)
+            saveAsPng.setEnabled(isRaster);
+    }
+
+    public boolean isAlreadyGeoreferenced() {
+        return isAlreadyGeoreferenced;
+    }
+
+    public void setAlreadyGeoreferenced(boolean isAlreadyGeoreferenced) {
+        this.isAlreadyGeoreferenced = isAlreadyGeoreferenced;
+    }
+
+    /**
+     * Set raster positions used for grabbing and georeferencing.
+     * rasterMin is the Eaast North of bottom left corner raster image on the screen when image is grabbed.
+     * The bounds width and height are the raster width and height. The image width matches the current view
+     * and the image height is adapted.
+     * Required: the communeBBox must be set (normally it is catched by CadastreInterface and saved by DownloadWMSPlanImage)
+     * @param bounds the current main map view boundaries
+     */
+    public void setRasterBounds(Bounds bounds) {
+        EastNorth rasterCenter = Main.getProjection().latlon2eastNorth(bounds.getCenter());
+        EastNorth eaMin = Main.getProjection().latlon2eastNorth(bounds.getMin());
+        EastNorth eaMax = Main.getProjection().latlon2eastNorth(bounds.getMax());
+        double rasterSizeX = communeBBox.max.getX() - communeBBox.min.getX();
+        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);
+        rasterRatio = (rasterMax.getX()-rasterMin.getX())/rasterSizeX;
+    }
+
+    /**
+     * Called by CacheControl when a new cache file is created on disk.
+     * Save only primitives to keep cache independent of software changes.
+     */
+    public void write(File associatedFile, ObjectOutputStream oos) throws IOException {
+        currentFormat = this.serializeFormatVersion;
+        setAssociatedFile(associatedFile);
+        oos.writeInt(this.serializeFormatVersion);
+        oos.writeObject(this.location);    // String
+        oos.writeObject(this.codeCommune); // String
+        oos.writeInt(this.lambertZone);
+        oos.writeBoolean(this.isRaster);
+        oos.writeBoolean(false); // previously buildingsOnly
+        if (this.isRaster) {
+            oos.writeDouble(this.rasterMin.getX());
+            oos.writeDouble(this.rasterMin.getY());
+            oos.writeDouble(this.rasterMax.getX());
+            oos.writeDouble(this.rasterMax.getY());
+            oos.writeDouble(this.rasterRatio);
+        }
+        oos.writeDouble(this.communeBBox.min.getX());
+        oos.writeDouble(this.communeBBox.min.getY());
+        oos.writeDouble(this.communeBBox.max.getX());
+        oos.writeDouble(this.communeBBox.max.getY());
+    }
+
+    /**
+     * Called by CacheControl when a cache file is read from disk.
+     * Cache uses only primitives to stay independent of software changes.
+     */
+    public boolean read(File associatedFile, ObjectInputStream ois, int currentLambertZone) throws IOException, ClassNotFoundException {
+        currentFormat = ois.readInt();;
+        if (currentFormat < 2) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Unsupported cache file version; found {0}, expected {1}\nCreate a new one.",
+                    currentFormat, this.serializeFormatVersion), tr("Cache Format Error"), JOptionPane.ERROR_MESSAGE);
+            return false;
+        }
+        this.setLocation((String) ois.readObject());
+        this.setCodeCommune((String) ois.readObject());
+        this.lambertZone = ois.readInt();
+        this.setRaster(ois.readBoolean());
+        setAssociatedFile(associatedFile);
+        if (currentFormat >= 4)
+            ois.readBoolean();
+        if (this.isRaster) {
+            double X = ois.readDouble();
+            double Y = ois.readDouble();
+            this.rasterMin = new EastNorth(X, Y);
+            X = ois.readDouble();
+            Y = ois.readDouble();
+            this.rasterMax = new EastNorth(X, Y);
+            this.rasterRatio = ois.readDouble();
+        }
+        double minX = ois.readDouble();
+        double minY = ois.readDouble();
+        double maxX = ois.readDouble();
+        double maxY = ois.readDouble();
+        this.communeBBox = new EastNorthBound(new EastNorth(minX, minY), new EastNorth(maxX, maxY));
+        if (this.lambertZone != currentLambertZone && currentLambertZone != -1) {
+            JOptionPane.showMessageDialog(Main.parent, tr("Lambert zone {0} in cache "+
+                    "incompatible with current Lambert zone {1}",
+                    this.lambertZone+1, currentLambertZone), tr("Cache Lambert Zone Error"), JOptionPane.ERROR_MESSAGE);
+            return false;
+        }
+        synchronized (this) {
+            boolean EOF = false;
+            try {
+                while (!EOF) {
+                    GeorefImage newImage = (GeorefImage) ois.readObject();
+                    for (GeorefImage img : this.images) {
+                        if (CadastrePlugin.backgroundTransparent) {
+                            if (img.overlap(newImage))
+                                // mask overlapping zone in already grabbed image
+                                img.withdraw(newImage);
+                            else
+                                // mask overlapping zone in new image only when
+                                // new image covers completely the existing image
+                                newImage.withdraw(img);
+                        }
+                    }
+                    newImage.wmsLayer = this;
+                    this.images.add(newImage);
+                }
+            } catch (EOFException ex) {
+                // expected exception when all images are read
+                Main.trace(ex);
+            }
+        }
+        Main.info("Cache loaded for location "+location+" with "+images.size()+" images");
+        return true;
+    }
+
+    /**
+     * Join the grabbed images into one single.
+     */
+    public void joinBufferedImages() {
+        if (images.size() > 1) {
+            EastNorth min = images.get(0).min;
+            EastNorth max = images.get(images.size()-1).max;
+            int oldImgWidth = images.get(0).image.getWidth();
+            int oldImgHeight = images.get(0).image.getHeight();
+            HashSet<Double> lx = new HashSet<>();
+            HashSet<Double> ly = new HashSet<>();
+            for (GeorefImage img : images) {
+                lx.add(img.min.east());
+                ly.add(img.min.north());
+            }
+            int newWidth = oldImgWidth*lx.size();
+            int newHeight = oldImgHeight*ly.size();
+            BufferedImage newImg = new BufferedImage(newWidth, newHeight, images.get(0).image.getType()/*BufferedImage.TYPE_INT_ARGB*/);
+            Graphics g = newImg.getGraphics();
+            // Coordinate (0,0) is on top,left corner where images are grabbed from bottom left
+            int rasterDivider = (int) Math.sqrt(images.size());
+            for (int h = 0; h < lx.size(); h++) {
+                for (int v = 0; v < ly.size(); v++) {
+                    int newx = h*oldImgWidth;
+                    int newy = newHeight - oldImgHeight - (v*oldImgHeight);
+                    int j = h*rasterDivider + v;
+                    g.drawImage(images.get(j).image, newx, newy, this);
+                }
+            }
+            synchronized (this) {
+                images.clear();
+                images.add(new GeorefImage(newImg, min, max, this));
+            }
+        }
+    }
+
+    /**
+     * Image cropping based on two EN coordinates pointing to two corners in diagonal
+     * Because it's coming from user mouse clics, we have to sort de positions first.
+     * Works only for raster image layer (only one image in collection).
+     * Updates layer georeferences.
+     */
+    public void cropImage(EastNorth en1, EastNorth en2) {
+        // adj1 is corner bottom, left
+        EastNorth adj1 = new EastNorth(en1.east() <= en2.east() ? en1.east() : en2.east(),
+                en1.north() <= en2.north() ? en1.north() : en2.north());
+        // adj2 is corner top, right
+        EastNorth adj2 = new EastNorth(en1.east() > en2.east() ? en1.east() : en2.east(),
+                en1.north() > en2.north() ? en1.north() : en2.north());
+        images.get(0).crop(adj1, adj2);
+        // update the layer georefs
+        rasterMin = adj1;
+        rasterMax = adj2;
+        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;
+    }
+
+    public EastNorthBound getFirstViewFromCacheBBox() {
+        if (isRaster) {
+            return communeBBox;
+        }
+        double minX = Double.MAX_VALUE;
+        double maxX = Double.MIN_VALUE;
+        double minY = Double.MAX_VALUE;
+        double maxY = Double.MIN_VALUE;
+        for (GeorefImage image:images) {
+            minX = image.min.east() < minX ? image.min.east() : minX;
+            maxX = image.max.east() > maxX ? image.max.east() : maxX;
+            minY = image.min.north() < minY ? image.min.north() : minY;
+            maxY = image.max.north() > maxY ? image.max.north() : maxY;
+        }
+        return new EastNorthBound(new EastNorth(minX, minY), new EastNorth(maxX, maxY));
+    }
+
+    public void setCommuneBBox(EastNorthBound entireCommune) {
+        this.communeBBox = entireCommune;
+    }
+
+    /**
+     * Method required by ImageObserver when drawing an image
+     */
+    @Override
+    public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
+        return false;
+    }
+
+    public int getLambertZone() {
+        return lambertZone;
+    }
+
+    public EastNorth getRasterCenter() {
+        return new EastNorth((images.get(0).max.east()+images.get(0).min.east())/2,
+                (images.get(0).max.north()+images.get(0).min.north())/2);
+    }
+
+    public void displace(double dx, double dy) {
+        if (isRaster) {
+            this.rasterMin = new EastNorth(rasterMin.east() + dx, rasterMin.north() + dy);
+            this.rasterMax = new EastNorth(rasterMax.east() + dx, rasterMax.north() + dy);
+            images.get(0).shear(dx, dy);
+        } else {
+            deltaEast += dx;
+            deltaNorth += dy;
+        }
+    }
+
+    public void resize(EastNorth rasterCenter, double proportion) {
+        this.rasterMin = rasterMin.interpolate(rasterCenter, proportion);
+        this.rasterMax = rasterMax.interpolate(rasterCenter, proportion);
+        images.get(0).scale(rasterCenter, proportion);
+    }
+
+    public void rotate(EastNorth rasterCenter, double angle) {
+        this.rasterMin = rasterMin.rotate(rasterCenter, angle);
+        this.rasterMax = rasterMax.rotate(rasterCenter, angle);
+        images.get(0).rotate(rasterCenter, angle);
+        this.angle += angle;
+    }
+
+    private void paintCrosspieces(Graphics g, MapView mv) {
+        String crosspieces = Main.pref.get("cadastrewms.crosspieces", "0");
+        if (!crosspieces.equals("0")) {
+            int modulo = 25;
+            if (crosspieces.equals("2")) modulo = 50;
+            if (crosspieces.equals("3")) modulo = 100;
+            EastNorthBound currentView = new EastNorthBound(mv.getEastNorth(0, mv.getHeight()),
+                    mv.getEastNorth(mv.getWidth(), 0));
+            int minX = ((int) currentView.min.east()/modulo+1)*modulo;
+            int minY = ((int) currentView.min.north()/modulo+1)*modulo;
+            int maxX = ((int) currentView.max.east()/modulo)*modulo;
+            int maxY = ((int) currentView.max.north()/modulo)*modulo;
+            int size = (maxX-minX)/modulo;
+            if (size < 20) {
+                int px = size > 10 ? 2 : Math.abs(12-size);
+                g.setColor(Color.green);
+                for (int x = minX; x <= maxX; x += modulo) {
+                    for (int y = minY; y <= maxY; y += modulo) {
+                        Point p = mv.getPoint(new EastNorth(x, y));
+                        g.drawLine(p.x-px, p.y, p.x+px, p.y);
+                        g.drawLine(p.x, p.y-px, p.x, p.y+px);
+                    }
+                }
+            }
+        }
+    }
+
+    public GeorefImage getImage(int index) {
+        imagesLock.lock();
+        GeorefImage img = null;
+        try {
+            img = this.images.get(index);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            Main.error(e);
+        }
+        imagesLock.unlock();
+        return img;
+    }
+
+    public Vector<GeorefImage> getImages() {
+        return this.images;
+    }
+
+    public boolean hasImages() {
+        return images != null && !images.isEmpty();
+    }
+
+    public void addImage(GeorefImage img) {
+        imagesLock.lock();
+        this.images.add(img);
+        imagesLock.unlock();
+    }
+
+    public void setImages(Vector<GeorefImage> images) {
+        imagesLock.lock();
+        this.images = images;
+        imagesLock.unlock();
+    }
+
+    public void clearImages() {
+        imagesLock.lock();
+        this.images.clear();
+        imagesLock.unlock();
+    }
+}
