Index: /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CacheControl.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CacheControl.java	(revision 19370)
+++ /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CacheControl.java	(revision 19371)
@@ -49,4 +49,11 @@
     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);
@@ -171,9 +178,8 @@
         for (;;) {
             imagesLock.lock();
-            // copy locally the images to save for better performance
-            ArrayList<GeorefImage> images = new ArrayList<GeorefImage>(imagesToSave);
-            imagesToSave.clear();
+            //ArrayList<GeorefImage> images = new ArrayList<GeorefImage>(imagesToSave);
+            int size = imagesToSave.size();
             imagesLock.unlock();
-            if (images != null && !images.isEmpty()) {
+            if (size > 0) {
                 String extension = String.valueOf((wmsLayer.getLambertZone() + 1));
                 if (Main.proj instanceof LambertCC9Zones)
@@ -186,6 +192,6 @@
                         ObjectOutputStreamAppend oos = new ObjectOutputStreamAppend(
                                 new BufferedOutputStream(new FileOutputStream(file, true)));
-                        for (GeorefImage img : images) {
-                            oos.writeObject(img);
+                        for (int i=0; i < size; i++) {
+                            oos.writeObject(imagesToSave.get(i));
                         }
                         oos.close();
@@ -194,6 +200,6 @@
                                 new BufferedOutputStream(new FileOutputStream(file)));
                         wmsLayer.write(oos);
-                        for (GeorefImage img : images) {
-                            oos.writeObject(img);
+                        for (int i=0; i < size; i++) {
+                            oos.writeObject(imagesToSave.get(i));
                         }
                         oos.close();
@@ -202,4 +208,9 @@
                     e.printStackTrace(System.out);
                 }
+                imagesLock.lock();
+                for (int i=0; i < size; i++) {
+                    imagesToSave.remove(0);
+                }
+                imagesLock.unlock();
             }
             try {wait();} catch (InterruptedException e) {
Index: /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastrePlugin.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastrePlugin.java	(revision 19370)
+++ /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/CadastrePlugin.java	(revision 19371)
@@ -93,4 +93,8 @@
  *                 - cookie expiration automatically detected and renewed (after 30 minutes)
  *                 - proper WMS layer cleanup at destruction (workaround for memory leak)
+ *                 - new cache format (v3) storing original image and cropped image bbox + angle
+ *                 - cache management compatible with previous v2 format
+ *                 - raster image rotation using shift+ctrl key instead of ctrl
+ *                 - raster image adjustment using default system menu modifier (ctrl for windows) for Mac support  
  */
 public class CadastrePlugin extends Plugin {
Index: /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/GeorefImage.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/GeorefImage.java	(revision 19370)
+++ /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/GeorefImage.java	(revision 19371)
@@ -25,6 +25,15 @@
     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. 
+    private EastNorth[] orgRaster = new EastNorth[4];
+    // bbox of the georeferenced original image (raster only) after cropping 
+    private EastNorth[] orgCroppedRaster = new EastNorth[4];
+    // angle with georeferenced original image after rotation (raster images only)(in radian)
+    private double angle = 0;
+
     public BufferedImage image;
 
@@ -36,4 +45,12 @@
         this.min = min;
         this.max = 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());
         updatePixelPer();
     }
@@ -45,8 +62,17 @@
     }
 
-    private void getNewBounding(EastNorth min, EastNorth max, EastNorth c, EastNorth d) {
+    /**
+     * Recalculate the new bounding box of the image based on the previous [min,max] bbox 
+     * and the new box after rotation [c,d]. 
+     * The new bbox defined in [min.max] will retain the extreme values of both boxes. 
+     * @param oldMin the original box min point, before rotation
+     * @param oldMax the original box max point, before rotation
+     * @param c the new box min point, after rotation
+     * @param d the new box max point, after rotation
+     */
+    private EastNorthBound getNewBounding(EastNorth oldMin, EastNorth oldMax, EastNorth c, EastNorth d) {
         EastNorth pt[] = new EastNorth[4];
-        pt[0] = min;
-        pt[1] = max;
+        pt[0] = oldMin;
+        pt[1] = oldMax;
         pt[2] = c;
         pt[3] = d;
@@ -61,6 +87,6 @@
             highestNorth = Math.max(pt[i].north(), highestNorth);
         }
-        min.setLocation(smallestEast, smallestNorth);
-        max.setLocation(highestEast, highestNorth);
+        return new EastNorthBound(new EastNorth(smallestEast, smallestNorth),
+                new EastNorth(highestEast, highestNorth));
     }
 
@@ -84,5 +110,15 @@
         if (drawBoundaries) {
             g.setColor(Color.green);
-            g.drawRect(minPt.x, maxPt.y, maxPt.x - minPt.x, minPt.y - maxPt.y);
+            if (orgCroppedRaster == null) {
+                // this is the old cache format where only [min,max] bbox is stored
+                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(orgCroppedRaster[i]);
+                croppedPoint[4] = croppedPoint[0]; 
+                for (int i=0; i<4; i++)
+                    g.drawLine(croppedPoint[i].x, croppedPoint[i].y, croppedPoint[i+1].x, croppedPoint[i+1].y);
+            }
         }
         g.drawImage(image, minPt.x, maxPt.y, maxPt.x, minPt.y, // dest
@@ -135,6 +171,25 @@
      */
     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
-        max = new EastNorth(in.readDouble(), in.readDouble());
-        min = new EastNorth(in.readDouble(), in.readDouble());
+        if (WMSLayer.currentFormat == 2 || WMSLayer.currentFormat == 3) {
+            max = new EastNorth(in.readDouble(), in.readDouble());
+            min = new EastNorth(in.readDouble(), in.readDouble());
+        }
+        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());
+        } else {
+            orgRaster = null;
+            orgCroppedRaster = null;
+            angle = 0;
+        }
         image = (BufferedImage) ImageIO.read(ImageIO.createImageInputStream(in));
         updatePixelPer();
@@ -143,11 +198,22 @@
     /**
      * Method required by BufferedImage serialization.
-     * Cache uses only primitives to stay independent of software changes.
+     * 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());
+        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());
         ImageIO.write(image, "png", ImageIO.createImageOutputStream(out));
     }
@@ -182,4 +248,8 @@
         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);
+        }
     }
     
@@ -192,4 +262,8 @@
         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();
     }
@@ -198,25 +272,23 @@
      * Rotate this image and its min/max coordinates around anchor point
      * @param anchor anchor of rotation
-     * @param angle angle of rotation (in radians)
-     */
-    public void rotate(EastNorth anchor, double angle) {
-        EastNorth min2 = new EastNorth(min.east(), max.north());
-        EastNorth max2 = new EastNorth(max.east(), min.north());
-        min = min.rotate(anchor, angle);
-        max = max.rotate(anchor, angle);
-        min2 = min2.rotate(anchor, angle);
-        max2 = max2.rotate(anchor, angle);
-        getNewBounding(min, max, min2, max2);
-        image = tilt(image, angle);
-    }
-
-    /**
-     * Rotate by copying original buffered image into a new one with new dimensions 
-     * @param image
-     * @param angle
-     * @return
-     */
-    public static BufferedImage tilt(BufferedImage image, double angle) {
-        double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
+     * @param ang angle of rotation (in radian)
+     */
+    public void rotate(EastNorth anchor, double ang) {
+        // rotate the bounding boxes coordinates first
+        EastNorth min2 = new EastNorth(orgRaster[0].east(), orgRaster[2].north());
+        EastNorth max2 = new EastNorth(orgRaster[2].east(), orgRaster[0].north());
+        for (int i=0; i<4; i++) {
+            orgRaster[i] = orgRaster[i].rotate(anchor, ang);
+            orgCroppedRaster[i] = orgCroppedRaster[i].rotate(anchor, ang);
+        }
+        min2 = min2.rotate(anchor, ang);
+        max2 = max2.rotate(anchor, ang);
+        EastNorthBound enb = getNewBounding(orgCroppedRaster[0], orgCroppedRaster[2], min2, max2);
+        min = enb.min;
+        max = enb.max;
+        angle=+ang;
+        
+        // rotate the image now
+        double sin = Math.abs(Math.sin(ang)), cos = Math.abs(Math.cos(ang));
         int w = image.getWidth(), h = image.getHeight();
         int neww = (int)Math.floor(w*cos+h*sin), newh = (int)Math.floor(h*cos+w*sin);
@@ -225,8 +297,8 @@
         Graphics2D g = result.createGraphics();
         g.translate((neww-w)/2, (newh-h)/2);
-        g.rotate(angle, w/2, h/2);
+        g.rotate(ang, w/2, h/2);
         g.drawRenderedImage(image, null);
         g.dispose();
-        return result;
+        image = result;
     }
 
Index: /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSAdjustAction.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSAdjustAction.java	(revision 19370)
+++ /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSAdjustAction.java	(revision 19371)
@@ -5,4 +5,5 @@
 
 import java.awt.Cursor;
+import java.awt.Toolkit;
 import java.awt.event.ActionEvent;
 import java.awt.event.MouseEvent;
@@ -87,10 +88,10 @@
         if (e.getButton() != MouseEvent.BUTTON1)
             return;
-        boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+        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)
+        if (shift && !ctrl)
             mode = Mode.moveZ;
-        else if (ctrl)
+        else if (shift && ctrl)
             mode = Mode.rotate;
         else
Index: /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSLayer.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSLayer.java	(revision 19370)
+++ /applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/WMSLayer.java	(revision 19371)
@@ -51,5 +51,11 @@
     protected Vector<GeorefImage> images = new Vector<GeorefImage>();
 
-    protected final int serializeFormatVersion = 2;
+    /**
+     * v1 to v2 = not supported
+     * v2 to v3 = add 4 more EastNorth coordinates in GeorefImages 
+     */
+    protected final int serializeFormatVersion = 3;
+    
+    public static int currentFormat;
 
     private ArrayList<EastNorthBound> dividedBbox = new ArrayList<EastNorthBound>();
@@ -69,4 +75,5 @@
     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;
@@ -89,4 +96,9 @@
 
     public void destroy() {
+        // if the layer is currently saving the images in the cache, wait until it's finished
+        while (!cacheControl.isCachePipeEmpty()) {
+            System.out.println("Try to close a WMSLayer which is currently saving in cache : wait 1 sec.");
+            CadastrePlugin.safeSleep(1000);
+        }
         super.destroy();
         images = null;
@@ -364,6 +376,6 @@
         double ratio = rasterSizeY/rasterSizeX;
         // keep same ratio on screen as WMS bbox (stored in communeBBox)
-        rasterMin = new EastNorth(eaMin.getX(), rasterCenter.getY()-(eaMax.getX()-eaMin.getX())*ratio/2);
-        rasterMax = new EastNorth(eaMax.getX(), rasterCenter.getY()+(eaMax.getX()-eaMin.getX())*ratio/2);
+        rasterMin = new EastNorth(eaMin.getX(), rasterCenter.getY()-(eaMax.getX()-eaMin.getX())*ratio/2); 
+        rasterMax = new EastNorth(eaMax.getX(), rasterCenter.getY()+(eaMax.getX()-eaMin.getX())*ratio/2); 
         rasterRatio = (rasterMax.getX()-rasterMin.getX())/rasterSizeX;
     }
@@ -402,8 +414,8 @@
      */
     public boolean read(ObjectInputStream ois, int currentLambertZone) throws IOException, ClassNotFoundException {
-        int sfv = ois.readInt();
-        if (sfv != this.serializeFormatVersion) {
+        currentFormat = ois.readInt();;
+        if (currentFormat < 2) {
             JOptionPane.showMessageDialog(Main.parent, tr("Unsupported cache file version; found {0}, expected {1}\nCreate a new one.",
-                    sfv, this.serializeFormatVersion), tr("Cache Format Error"), JOptionPane.ERROR_MESSAGE);
+                    currentFormat, this.serializeFormatVersion), tr("Cache Format Error"), JOptionPane.ERROR_MESSAGE);
             return false;
         }
@@ -531,6 +543,4 @@
     public void setCommuneBBox(EastNorthBound entireCommune) {
         this.communeBBox = entireCommune;
-//        if (Main.proj instanceof LambertCC9Zones)
-//            setLambertCC9Zone(communeBBox.min.north());
     }
 
@@ -545,30 +555,4 @@
         return lambertZone;
     }
-
-//    public void setLambertCC9Zone(double north) {
-//        int lambertZone = LambertCC9Zones.north2ZoneNumber(north);
-//        this.lambertZone = lambertZone;
-//        if (((LambertCC9Zones)Main.proj).getLayoutZone() != lambertZone) {
-//            String currentZone = MenuActionLambertZone.lambert9zones[((LambertCC9Zones)Main.proj).getLayoutZone()+1];
-//            String destZone = MenuActionLambertZone.lambert9zones[lambertZone+1];
-//            if (Main.map.mapView.getAllLayers().size() == 1) {
-//                /* Enable this code below when JOSM will have a proper support of dynamic projection change
-//                 *
-//                System.out.println("close all layers and change current Lambert zone from "+LambertCC9Zones.layoutZone+" to "+lambertZone);
-//                Bounds b = null;
-//                if (Main.map != null && Main.map.mapView != null)
-//                    b = Main.map.mapView.getRealBounds();
-//                LambertCC9Zones.layoutZone = lambertZone;
-//                Main.map.mapView.zoomTo(b);
-//                */
-//            } else {
-//                JOptionPane.showMessageDialog(Main.parent, tr("Current layer is in Lambert CC9 Zone \"{0}\"\n"+
-//                        "where the commune is in Lambert CC9 Zone \"{1}\".\n"+
-//                        "Upload your changes, close all layers and change\n"+
-//                        "manually the Lambert zone from the Cadastre menu"
-//                        , currentZone, destZone));
-//            }
-//        }
-//    }
 
     public EastNorth getRasterCenter() {
