Index: applications/editors/josm/plugins/piclayer/build.xml
===================================================================
--- applications/editors/josm/plugins/piclayer/build.xml	(revision 27220)
+++ applications/editors/josm/plugins/piclayer/build.xml	(revision 27231)
@@ -22,5 +22,5 @@
 -->
 <project name="PicLayer" default="dist" basedir=".">
-    <property name="commit.message" value="PicLayer - changed marker icon to make it more visible"/>
+    <property name="commit.message" value="PicLayer - changed marker icon to make it more visible; #5451; #7124 - first stage"/>
     <property name="plugin.main.version" value="4549"/>
     <!--
Index: applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/ActionVisibilityChangeMenu.java
===================================================================
--- applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/ActionVisibilityChangeMenu.java	(revision 27220)
+++ 	(revision )
@@ -1,50 +1,0 @@
-package org.openstreetmap.josm.plugins.piclayer;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JMenu;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.JosmAction;
-
-enum PicActions {MOVE_PICTURE, MOVE_POINT, TRANSFORM_POINT, SCALEX, SCALEY, SCALEXY, SHEAR, ROTATE}
-
-@SuppressWarnings("serial")
-public class ActionVisibilityChangeMenu extends JMenu {
-    public ActionVisibilityChangeMenu() {
-        super(tr("Change visibility of controls"));
-
-        for (int i = 0;i < PicLayerPlugin.buttonList.size(); i++) {
-            add(new SwitchVisibilityMenuItem(PicLayerPlugin.buttonList.get(i)));
-        }
-    }
-}
-
-@SuppressWarnings("serial")
-class SwitchVisibilityMenuItem extends JCheckBoxMenuItem {
-    public SwitchVisibilityMenuItem(final PicToggleButton button) {
-        super();
-        setSelected(Main.pref.getBoolean(button.getVisibilityKey(), button.getDefVisibility()));
-        setAction(new ButtonAction(button));
-    }
-    class ButtonAction extends JosmAction {
-        private PicToggleButton button;
-
-        public ButtonAction(PicToggleButton button) {
-            super(button.getBtnName(), null, button.getBtnName(), null, false, false);
-            this.button = button;
-        }
-
-        @Override
-        public void actionPerformed(ActionEvent e) {
-            boolean val = !Main.pref.getBoolean(button.getVisibilityKey(), button.getDefVisibility());
-            Main.pref.put(button.getVisibilityKey(), val);
-            SwitchVisibilityMenuItem.this.setSelected(val);
-            button.setVisible(val);
-        }
-
-    }
-}
Index: applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/actions/newlayer/NewLayerFromFileAction.java
===================================================================
--- applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/actions/newlayer/NewLayerFromFileAction.java	(revision 27220)
+++ applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/actions/newlayer/NewLayerFromFileAction.java	(revision 27231)
@@ -26,4 +26,6 @@
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.imageio.ImageIO;
@@ -36,5 +38,9 @@
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
 import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.plugins.piclayer.layer.PicLayerAbstract;
 import org.openstreetmap.josm.plugins.piclayer.layer.PicLayerFromFile;
+import org.openstreetmap.josm.plugins.piclayer.layer.PicLayerFromKML;
+import org.openstreetmap.josm.plugins.piclayer.layer.kml.KMLGroundOverlay;
+import org.openstreetmap.josm.plugins.piclayer.layer.kml.KMLReader;
 
 /**
@@ -51,4 +57,15 @@
     private class ImageFileFilter extends FileFilter {
 
+        private String[] supportedExtensions;
+
+        public ImageFileFilter() {
+            List<String> extensions = new ArrayList<String>();
+            extensions.add("zip");
+            extensions.add("kml");
+            for (String ext : ImageIO.getReaderFormatNames())
+                extensions.add(ext);
+            supportedExtensions = extensions.toArray(new String[0]);
+        }
+
         @Override
         public boolean accept(File f) {
@@ -56,10 +73,6 @@
                 return true;
 
-            int dotIdx = f.getName().lastIndexOf('.');
-            if (dotIdx == -1) return false;
-            String fileExtension = f.getName().substring(dotIdx+1);
-            String[] supportedExtensions = ImageIO.getReaderFormatNames();
+            String fileExtension = PicLayerFromFile.getFileExtension(f);
 
-            if ("zip".equalsIgnoreCase(fileExtension)) return true;
             // Unfortunately, getReaderFormatNames does not always return ALL extensions in
             // both lower and upper case, so we can not do a search in the array
@@ -75,19 +88,7 @@
         @Override
         public String getDescription() {
-            return tr("Supported image files + *.zip");
+            return tr("Supported image files, *.zip, *.kml");
         }
 
-    }
-
-    private class AllFilesFilter extends FileFilter {
-        @Override
-        public String getDescription() {
-            return tr("All Files");
-        }
-
-        @Override
-        public boolean accept(File f) {
-            return true;
-        }
     }
 
@@ -119,5 +120,5 @@
             // The next layers we load will be placed one after the other after this first layer
             int newLayerPos = Main.map.mapView.getAllLayers().size();
-            for(Layer l : Main.map.mapView.getLayersOfType(PicLayerFromFile.class)) {
+            for(Layer l : Main.map.mapView.getLayersOfType(PicLayerAbstract.class)) {
                 int pos = Main.map.mapView.getLayerPos(l);
                 if (pos < newLayerPos) newLayerPos = pos;
@@ -127,27 +128,18 @@
                 // TODO: we need a progress bar here, it can take quite some time
 
-                // Create layer from file
-                PicLayerFromFile layer = new PicLayerFromFile( file );
-                // Add layer only if successfully initialized
-                try {
-                    layer.initialize();
-                }
-                catch (IOException e) {
-                    // Failed
-                    System.out.println( "NewLayerFromFileAction::actionPerformed - " + e.getMessage() );
-                    JOptionPane.showMessageDialog(null, e.getMessage() );
-                    return;
-                }
                 Main.pref.put(m_lastdirprefname, file.getParent());
 
-                Main.main.addLayer( layer );
-                Main.map.mapView.moveLayer(layer, newLayerPos++);
+                // Create layer from file
+                if ("kml".equalsIgnoreCase(PicLayerFromFile.getFileExtension(file))) {
+                    KMLReader kml = new KMLReader(file);
+                    kml.process();
+                    JOptionPane.showMessageDialog(null, tr("KML calibration is in beta stage and may produce incorrectly calibrated layers!\nPlease use http://josm.openstreetmap.de/ticket/5451 to upload your KMLs that were calibrated incorrectly."));
+                    for (KMLGroundOverlay overlay : kml.getGroundOverlays()) {
+                        //TODO: zoom to whole picture, not only the last
+                        addNewLayerFromKML(file, overlay, newLayerPos);
+                    }
 
-                if ( fc.getSelectedFiles().length == 1 && Main.pref.getInteger("piclayer.zoom-on-load", 1) != 0 ) {
-                    // if we are loading a single picture file, zoom on it, so that the user can see something
-                    BoundingXYVisitor v = new BoundingXYVisitor();
-                    layer.visitBoundingBox(v);
-                    Main.map.mapView.recalculateCenterScale(v);
-                }
+                } else {
+                addNewLayerFromFile(file, newLayerPos, fc.getSelectedFiles().length == 1);
 
             }
@@ -155,2 +147,43 @@
     }
 }
+
+    private void addNewLayerFromFile(File file, int newLayerPos, boolean isZoomToLayer) {
+        try {
+            PicLayerFromFile layer = new PicLayerFromFile( file );
+            layer.initialize();
+
+            placeLayer(layer, newLayerPos, isZoomToLayer);
+        }
+        catch (IOException e) {
+            // Failed
+            System.out.println( "NewLayerFromFileAction::actionPerformed - " + e.getMessage() );
+            JOptionPane.showMessageDialog(null, e.getMessage() );
+        }
+    }
+
+    private void placeLayer(PicLayerAbstract layer, int newLayerPos, boolean isZoomToLayer) throws IOException {
+        // Add layer only if successfully initialized
+
+        Main.main.addLayer( layer );
+        Main.map.mapView.moveLayer(layer, newLayerPos++);
+
+        if ( isZoomToLayer && Main.pref.getInteger("piclayer.zoom-on-load", 1) != 0 ) {
+            // if we are loading a single picture file, zoom on it, so that the user can see something
+            BoundingXYVisitor v = new BoundingXYVisitor();
+            layer.visitBoundingBox(v);
+            Main.map.mapView.recalculateCenterScale(v);
+        }
+    }
+    private void addNewLayerFromKML(File root, KMLGroundOverlay overlay, int newLayerPos) {
+        try {
+            PicLayerFromKML layer = new PicLayerFromKML(root, overlay);
+            layer.initialize();
+
+            placeLayer(layer, newLayerPos, true);
+        } catch (IOException e) {
+            // Failed
+            System.out.println( "NewLayerFromFileAction::actionPerformed - " + e.getMessage() );
+            JOptionPane.showMessageDialog(null, e.getMessage() );
+        }
+    }
+}
Index: applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/PicLayerAbstract.java
===================================================================
--- applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/PicLayerAbstract.java	(revision 27220)
+++ applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/PicLayerAbstract.java	(revision 27231)
@@ -65,13 +65,19 @@
     // Counter - just for naming of layers
     private static int imageCounter = 0;
+
     // This is the main image to be displayed
-    private Image image = null;
-    private static Image pinImage;
+    protected Image image = null;
+    // Tiles of pin images
+    private static Image pinTiledImage;
+
     // Initial position of the image in the real world
-    private EastNorth initialImagePosition;
+    protected EastNorth initialImagePosition;
+
     // Position of the image in the real world
-    private EastNorth imagePosition;
+    protected EastNorth imagePosition;
+
     // The scale that was set on the map during image creation
-    private double initialImageScale = 1.0;
+    protected double initialImageScale = 1.0;
+
     // Layer icon
     private Icon layerIcon = null;
@@ -83,5 +89,5 @@
     }
 
-    private PictureTransform transformer;
+    protected PictureTransform transformer;
 
     public PictureTransform getTransformer() {
@@ -89,22 +95,31 @@
     }
 
-    // Keys for saving in Properties
-    private final String INITIAL_POS_X = "INITIAL_POS_X";
-    private final String INITIAL_POS_Y = "INITIAL_POS_y";
-    private final String POSITION_X = "POSITION_X";
-    private final String POSITION_Y = "POSITION_Y";
-    private final String ANGLE = "ANGLE";
-    private final String INITIAL_SCALE = "INITIAL_SCALE";
-    private final String SCALEX = "SCALEX";
-    private final String SCALEY = "SCALEY";
-    private final String SHEARX = "SHEARX";
-    private final String SHEARY = "SHEARY";
-
-    private final String MATRIXm00 = "M00";
-    private final String MATRIXm01 = "M01";
-    private final String MATRIXm10 = "M10";
-    private final String MATRIXm11 = "M11";
-    private final String MATRIXm02 = "M02";
-    private final String MATRIXm12 = "M12";
+    // Keys for loading from old/new Properties
+    private static final String INITIAL_POS_X = "INITIAL_POS_X";
+    private static final String INITIAL_POS_Y = "INITIAL_POS_y";
+    private static final String POSITION_X = "POSITION_X";
+    private static final String POSITION_Y = "POSITION_Y";
+    private static final String ANGLE = "ANGLE";
+    private static final String INITIAL_SCALE = "INITIAL_SCALE";
+    private static final String SCALEX = "SCALEX";
+    private static final String SCALEY = "SCALEY";
+    private static final String SHEARX = "SHEARX";
+    private static final String SHEARY = "SHEARY";
+    // new properties
+    private static final String MATRIXm00 = "M00";
+    private static final String MATRIXm01 = "M01";
+    private static final String MATRIXm10 = "M10";
+    private static final String MATRIXm11 = "M11";
+    private static final String MATRIXm02 = "M02";
+    private static final String MATRIXm12 = "M12";
+
+    // pin images properties - tile anchors, width and offset
+    // TODO: load these from properties file in images folder...
+    private static final int pinAnchorX = 31;
+    private static final int pinAnchorY = 31;
+    private static final int[] pinTileOffsetX = {74, 0, 74, 0};
+    private static final int[] pinTileOffsetY = {0, 74, 74, 0};
+    private static final int pinWidth = 64;
+    private static final int pinHeight = 64;
 
     /**
@@ -120,7 +135,7 @@
         layerIcon = new ImageIcon(Toolkit.getDefaultToolkit().createImage(getClass().getResource("/images/layericon.png")));
 
-        if (pinImage == null) {
+        if (pinTiledImage == null) {
             // allow system to load the image and use it in future
-            pinImage = new ImageIcon(Toolkit.getDefaultToolkit().createImage(getClass().getResource("/images/marker.png"))).getImage();
+            pinTiledImage = new ImageIcon(Toolkit.getDefaultToolkit().createImage(getClass().getResource("/images/v6_64.png"))).getImage();
         }
     }
@@ -256,9 +271,11 @@
                 tr.concatenate(transformer.getTransform());
 
-                for (Point2D p : transformer.getOriginPoints()) {
-                   Point2D trP = tr.transform(p, null);
+                for (int i = 0; i < transformer.getOriginPoints().size(); i++) {
+                   Point2D trP = tr.transform(transformer.getOriginPoints().get(i), null);
                    int x = (int)trP.getX(), y = (int)trP.getY();
-                   //gPoints.drawOval(x-2, y-2, 5, 5);
-                   gPoints.drawImage(pinImage, x-15, y-15, null);
+
+                   int dstx = x-pinAnchorX;
+                   int dsty = y-pinAnchorY;
+                   gPoints.drawImage(pinTiledImage, dstx, dsty, dstx+pinWidth, dsty+pinHeight, pinTileOffsetX[i], pinTileOffsetY[i], pinTileOffsetX[i]+pinWidth, pinTileOffsetY[i]+pinHeight, null);
                 }
             }
@@ -276,5 +293,5 @@
      * next (a couple of kilometers).
      */
-    private double getMetersPerEasting(EastNorth en) {
+    protected double getMetersPerEasting(EastNorth en) {
         /* Natural scale in east/north units per pixel.
          * This means, the projection should be able to handle
Index: applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/PicLayerFromKML.java
===================================================================
--- applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/PicLayerFromKML.java	(revision 27231)
+++ applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/PicLayerFromKML.java	(revision 27231)
@@ -0,0 +1,70 @@
+package org.openstreetmap.josm.plugins.piclayer.layer;
+
+import java.awt.Image;
+import java.awt.geom.AffineTransform;
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.plugins.piclayer.layer.kml.KMLGroundOverlay;
+
+public class PicLayerFromKML extends PicLayerAbstract {
+
+    private KMLGroundOverlay calibration;
+    private File picture;
+    private String pictureName;
+
+    public PicLayerFromKML(File main, KMLGroundOverlay calibration) {
+
+        picture = new File(main.getParent() + File.separatorChar + calibration.getFileName());
+        this.calibration = calibration;
+
+        pictureName = calibration.getName();
+
+        // Set the name of the layer as the base name of the file
+        setName(picture.getName());
+    }
+    @Override
+    protected Image createImage() throws IOException {
+        Image image = ImageIO.read(picture);
+        return image;
+    }
+
+    @Override
+    protected void lookForCalibration() throws IOException {
+        if (calibration != null)
+            loadCalibration(calibration);
+
+    }
+
+    @Override
+    public String getPicLayerName() {
+        return pictureName;
+    }
+
+    public void loadCalibration(KMLGroundOverlay cal) {
+        int w = image.getWidth(null);
+        int h = image.getHeight(null);
+        LatLon coord1 = new LatLon(cal.getNorth(), cal.getEast());
+        LatLon coord2 = new LatLon(cal.getSouth(), cal.getWest());
+
+        EastNorth en1 = Main.getProjection().latlon2eastNorth(coord1);
+        EastNorth en2 = Main.getProjection().latlon2eastNorth(coord2);
+
+
+        imagePosition.setLocation((en1.getX()+en2.getX())/2, (en1.getY()+en2.getY())/2);
+        initialImageScale = 100*getMetersPerEasting(imagePosition);
+        initialImagePosition.setLocation(imagePosition);
+
+        AffineTransform transform = AffineTransform.getScaleInstance((en1.getX()-en2.getX())/w, (en1.getY()-en2.getY())/h);
+        transform.rotate(cal.getRotate()/180.0*Math.PI);
+
+        transformer.resetCalibration();
+        transformer.getTransform().concatenate(transform);
+    }
+
+}
Index: applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/kml/KMLGroundOverlay.java
===================================================================
--- applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/kml/KMLGroundOverlay.java	(revision 27231)
+++ applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/kml/KMLGroundOverlay.java	(revision 27231)
@@ -0,0 +1,56 @@
+package org.openstreetmap.josm.plugins.piclayer.layer.kml;
+
+
+public class KMLGroundOverlay {
+
+    private String filename;
+    private double north;
+    private double south;
+    private double east;
+    private double west;
+    private double rotate;
+    private String name;
+
+    public String getFileName() {
+        return filename;
+    }
+    public void setFileName(String file) {
+        this.filename = file;
+    }
+    public double getNorth() {
+        return north;
+    }
+    public void setNorth(double north) {
+        this.north = north;
+    }
+    public double getSouth() {
+        return south;
+    }
+    public void setSouth(double south) {
+        this.south = south;
+    }
+    public double getEast() {
+        return east;
+    }
+    public void setEast(double east) {
+        this.east = east;
+    }
+    public double getWest() {
+        return west;
+    }
+    public void setWest(double west) {
+        this.west = west;
+    }
+    public double getRotate() {
+        return rotate;
+    }
+    public void setRotate(double rotate) {
+        this.rotate = rotate;
+    }
+    public String getName() {
+        return name;
+    }
+    public void setName(String name) {
+        this.name = name;
+    }
+}
Index: applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/kml/KMLReader.java
===================================================================
--- applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/kml/KMLReader.java	(revision 27231)
+++ applications/editors/josm/plugins/piclayer/src/org/openstreetmap/josm/plugins/piclayer/layer/kml/KMLReader.java	(revision 27231)
@@ -0,0 +1,106 @@
+package org.openstreetmap.josm.plugins.piclayer.layer.kml;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+public class KMLReader {
+
+    private List<KMLGroundOverlay> groundOverlays;
+
+    private File file;
+    public KMLReader(File file) {
+        this.file = file;
+    }
+
+    public void process() {
+        KMLHandler handler = new KMLHandler();
+        try {
+            XMLReader xr = XMLReaderFactory.createXMLReader();
+            xr.setContentHandler(handler);
+            xr.parse(new InputSource(new FileReader(file)));
+        } catch (SAXException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        groundOverlays = handler.getResult();
+    }
+
+    public List<KMLGroundOverlay> getGroundOverlays() {
+        return groundOverlays;
+    }
+}
+
+class KMLHandler extends DefaultHandler {
+
+    private boolean inGroundOverlay = false;
+    private boolean inIcon = false;
+    private boolean inLatLonBox = false;
+    private String value;
+    private List<KMLGroundOverlay> result;
+    private KMLGroundOverlay overlay;
+
+    public KMLHandler() {
+        result = new ArrayList<KMLGroundOverlay>();
+    }
+
+    @Override
+    public void startElement(String uri, String localName, String qName,
+            Attributes attributes) throws SAXException {
+        if ("GroundOverlay".equals(localName)) {
+            inGroundOverlay = true;
+            overlay = new KMLGroundOverlay();
+        } else if (inGroundOverlay && "Icon".equals(localName)) {
+            inIcon = true;
+        } else if (inGroundOverlay && "LatLonBox".equals(localName)) {
+            inLatLonBox = true;
+        }
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String qName)
+            throws SAXException {
+        if (inGroundOverlay && "name".equals(localName)) {
+            overlay.setName(value.trim());
+        } else if (inIcon && "href".equals(localName)) {
+            overlay.setFileName(value.trim());
+        } else if (inLatLonBox && "north".equals(localName)) {
+            overlay.setNorth(Double.valueOf(value.trim()));
+        } else if (inLatLonBox && "east".equals(localName)) {
+            overlay.setEast(Double.valueOf(value.trim()));
+        } else if (inLatLonBox && "south".equals(localName)) {
+            overlay.setSouth(Double.valueOf(value.trim()));
+        } else if (inLatLonBox && "west".equals(localName)) {
+            overlay.setWest(Double.valueOf(value.trim()));
+        } else if (inLatLonBox && "rotate".equals(localName)) {
+            overlay.setRotate(Double.valueOf(value.trim()));
+        } else if (inLatLonBox && "LatLonBox".equals(localName)) {
+            inLatLonBox = false;
+        } else if (inIcon && "Icon".equals(localName)) {
+            inIcon = false;
+        } else if (inGroundOverlay && "GroundOverlay".equals(localName)) {
+            inGroundOverlay = false;
+            result.add(overlay);
+        }
+    }
+
+    @Override
+    public void characters(char[] ch, int start, int length)
+            throws SAXException {
+        value = new String(ch, start, length);
+    }
+
+    public List<KMLGroundOverlay> getResult() {
+        return result;
+    }
+}
