Index: /applications/editors/josm/plugins/photoadjust/build.xml
===================================================================
--- /applications/editors/josm/plugins/photoadjust/build.xml	(revision 34785)
+++ /applications/editors/josm/plugins/photoadjust/build.xml	(revision 34786)
@@ -5,5 +5,5 @@
     <property name="commit.message" value="Commit message"/>
     <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
-    <property name="plugin.main.version" value="14205"/>
+    <property name="plugin.main.version" value="14590"/>
 
     <!-- Configure these properties (replace "..." accordingly).
Index: /applications/editors/josm/plugins/photoadjust/src/org/openstreetmap/josm/plugins/photoadjust/PhotoAdjustWorker.java
===================================================================
--- /applications/editors/josm/plugins/photoadjust/src/org/openstreetmap/josm/plugins/photoadjust/PhotoAdjustWorker.java	(revision 34785)
+++ /applications/editors/josm/plugins/photoadjust/src/org/openstreetmap/josm/plugins/photoadjust/PhotoAdjustWorker.java	(revision 34786)
@@ -7,4 +7,5 @@
 import java.util.List;
 
+import org.openstreetmap.josm.data.ImageData;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.gui.MainApplication;
@@ -19,5 +20,5 @@
 
     private ImageEntry dragPhoto;
-    private GeoImageLayer dragLayer;
+    private ImageData dragData;
     // Offset between center of the photo and point where it is
     // clicked.  This must be in pixels to maintain the same offset if
@@ -32,5 +33,5 @@
     public void reset() {
         dragPhoto = null;
-        dragLayer = null;
+        dragData = null;
         dragOffset = null;
     }
@@ -73,9 +74,9 @@
      */
     public void doMousePressed(MouseEvent evt,
-                               List<GeoImageLayer> imageLayers) {
+            List<GeoImageLayer> imageLayers) {
         reset();
 
         if (evt.getButton() == MouseEvent.BUTTON1
-            && imageLayers != null && !imageLayers.isEmpty()) {
+                && imageLayers != null && !imageLayers.isEmpty()) {
             // Check if modifier key is pressed and change to
             // image viewer photo if it is.
@@ -83,34 +84,36 @@
             final boolean isCtrl = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0;
             if (isShift || isCtrl) {
-                final GeoImageLayer viewerLayer = ImageViewerDialog.getCurrentLayer();
-                final ImageEntry img = ImageViewerDialog.getCurrentImage();
-                if (img != null && viewerLayer != null
-                    && viewerLayer.isVisible()
-                    && imageLayers.contains(viewerLayer)) {
-                    // Change direction if control is pressed, position
-                    // otherwise.  Shift+control changes direction, similar to
-                    // rotate in select mode.
-                    //
-                    // Combinations:
-                    // S ... shift pressed
-                    // C ... control pressed
-                    // pos ... photo has a position set == is displayed on the map
-                    // nopos ... photo has no position set
-                    //
-                    // S + pos: position at mouse
-                    // S + nopos: position at mouse
-                    // C + pos: change orientation
-                    // C + nopos: ignored
-                    // S + C + pos: change orientation
-                    // S + C + nopos: ignore
-                    if (isCtrl) {
-                        if (img.getPos() != null) {
-                            changeDirection(img, viewerLayer, evt);
+                for (GeoImageLayer layer: imageLayers) {
+                    if (layer.isVisible()) {
+                        final ImageEntry img = layer.getImageData().getSelectedImage();
+                        if (img != null) {
+                            // Change direction if control is pressed, position
+                            // otherwise.  Shift+control changes direction, similar to
+                            // rotate in select mode.
+                            //
+                            // Combinations:
+                            // S ... shift pressed
+                            // C ... control pressed
+                            // pos ... photo has a position set == is displayed on the map
+                            // nopos ... photo has no position set
+                            //
+                            // S + pos: position at mouse
+                            // S + nopos: position at mouse
+                            // C + pos: change orientation
+                            // C + nopos: ignored
+                            // S + C + pos: change orientation
+                            // S + C + nopos: ignore
+                            if (isCtrl) {
+                                if (img.getPos() != null) {
+                                    changeDirection(img, layer.getImageData(), evt);
+                                }
+                            } else { // shift pressed
+                                movePhoto(img, layer.getImageData(), evt);
+                            }
+                            dragPhoto = img;
+                            dragData = layer.getImageData();
+                            break;
                         }
-                    } else { // shift pressed
-                        movePhoto(img, viewerLayer, evt);
                     }
-                    dragPhoto = img;
-                    dragLayer = viewerLayer;
                 }
             } else {
@@ -120,5 +123,5 @@
                         dragPhoto = layer.getPhotoUnderMouse(evt);
                         if (dragPhoto != null) {
-                            dragLayer = layer;
+                            dragData = layer.getImageData();
                             setDragOffset(dragPhoto, evt);
                             disableCenterView();
@@ -150,11 +153,10 @@
      */
     public void doMouseDragged(MouseEvent evt) {
-        if (dragLayer != null && dragLayer.isVisible()
-            && dragPhoto != null) {
+        if (dragData != null && dragPhoto != null) {
             if ((evt.getModifiers() & InputEvent.CTRL_MASK) != 0) {
-                changeDirection(dragPhoto, dragLayer, evt);
+                changeDirection(dragPhoto, dragData, evt);
             } else {
                 disableCenterView();
-                movePhoto(dragPhoto, dragLayer, evt);
+                movePhoto(dragPhoto, dragData, evt);
             }
         }
@@ -177,9 +179,9 @@
      *
      * @param photo The photo to move.
-     * @param layer GeoImageLayer of the photo.
+     * @param data ImageData of the photo.
      * @param evt Mouse event from one of the mouse adapters.
      */
-    private void movePhoto(ImageEntry photo, GeoImageLayer layer,
-                           MouseEvent evt) {
+    private void movePhoto(ImageEntry photo, ImageData data,
+            MouseEvent evt) {
         LatLon newPos;
         if (dragOffset != null) {
@@ -190,7 +192,5 @@
             newPos = MainApplication.getMap().mapView.getLatLon(evt.getX(), evt.getY());
         }
-        photo.setPos(newPos);
-        photo.flagNewGpsData();
-        layer.updateBufferAndRepaint();
+        data.updateImagePosition(photo, newPos);
         // Re-display the photo because the OSD data might change (new
         // coordinates).  Or do that in doMouseReleased().
@@ -202,9 +202,9 @@
      *
      * @param photo The photo to move.
-     * @param layer GeoImageLayer of the photo.
+     * @param data ImageData of the photo.
      * @param evt Mouse event from one of the mouse adapters.
      */
-    private void changeDirection(ImageEntry photo, GeoImageLayer layer,
-                                MouseEvent evt) {
+    private void changeDirection(ImageEntry photo, ImageData data,
+            MouseEvent evt) {
         final LatLon photoLL = photo.getPos();
         if (photoLL == null) {
@@ -220,8 +220,5 @@
             direction -= 360.0;
         }
-        photo.setExifImgDir(direction);
-        photo.flagNewGpsData();
-        layer.updateBufferAndRepaint();
-        ImageViewerDialog.showImage(layer, photo);
+        data.updateImageDirection(photo, direction);
         setDragOffset(photo, evt);
     }
Index: /applications/editors/josm/plugins/photoadjust/src/org/openstreetmap/josm/plugins/photoadjust/PhotoPropertyEditor.java
===================================================================
--- /applications/editors/josm/plugins/photoadjust/src/org/openstreetmap/josm/plugins/photoadjust/PhotoPropertyEditor.java	(revision 34785)
+++ /applications/editors/josm/plugins/photoadjust/src/org/openstreetmap/josm/plugins/photoadjust/PhotoPropertyEditor.java	(revision 34786)
@@ -7,12 +7,12 @@
 import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
+import java.util.List;
+import java.util.Optional;
 
 import javax.swing.AbstractAction;
-import javax.swing.Action;
 import javax.swing.BorderFactory;
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
 import javax.swing.JLabel;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JSeparator;
@@ -22,4 +22,6 @@
 
 import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.data.ImageData;
+import org.openstreetmap.josm.data.ImageData.ImageDataUpdateListener;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager;
@@ -30,7 +32,11 @@
 import org.openstreetmap.josm.gui.MainMenu;
 import org.openstreetmap.josm.gui.dialogs.LatLonDialog;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
+import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
+import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
+import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
 import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer;
 import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
-import org.openstreetmap.josm.gui.layer.geoimage.ImageViewerDialog;
 import org.openstreetmap.josm.gui.widgets.JosmTextField;
 import org.openstreetmap.josm.tools.GBC;
@@ -58,63 +64,49 @@
 
     /**
-     * Update the geo image layer and the image viewer.
-     *
-     * @param layer GeoImageLayer of the photo.
-     * @param photo The photo that is updated.
-     */
-    private static void updateLayer(GeoImageLayer layer, ImageEntry photo) {
-        layer.updateBufferAndRepaint();
-        ImageViewerDialog.showImage(layer, photo);
-    }
-
-    /**
      * Action if the menu entry is selected.
      */
-    private static class PropertyEditorAction extends JosmAction {
+    private static class PropertyEditorAction extends JosmAction implements LayerChangeListener, ImageDataUpdateListener {
         public PropertyEditorAction() {
             super(tr("Edit photo GPS data"),    // String name
-                  (String)null,                         // String iconName
-                  tr("Edit GPS data of selected photo."), // String tooltip
-                  null,                                 // Shortcut shortcut
-                  true,                                 // boolean registerInToolbar
-                  "photoadjust/propertyeditor", // String toolbarId
-                  true                          // boolean installAdapters
-                  );
+                    (String)null,                         // String iconName
+                    tr("Edit GPS data of selected photo."), // String tooltip
+                    null,                                 // Shortcut shortcut
+                    true,                                 // boolean registerInToolbar
+                    "photoadjust/propertyeditor", // String toolbarId
+                    false                          // boolean installAdapters
+                    );
+            this.installAdapters();
+        }
+
+        @Override
+        protected void installAdapters() {
+            MainApplication.getLayerManager().addLayerChangeListener(this);
+            initEnabledState();
         }
 
         @Override
         public void actionPerformed(ActionEvent evt) {
-            try {
-                final ImageEntry photo = ImageViewerDialog.getCurrentImage();
-                final GeoImageLayer layer = ImageViewerDialog.getCurrentLayer();
-                if (photo == null) {
-                    throw new AssertionError("No image selected.");
-                }
-                StringBuilder title =
+            final ImageData data = getLayerWithSelectedImage().get().getImageData();
+            final ImageEntry photo = data.getSelectedImage();
+
+            StringBuilder title =
                     new StringBuilder(tr("Edit Photo GPS Data"));
-                if (photo.getFile() != null) {
-                    title.append(" - ");
-                    title.append(photo.getFile().getName());
-                }
-                PropertyEditorDialog dialog =
-                    new PropertyEditorDialog(title.toString(), photo, layer);
-                if (dialog.getValue() == 1) {
-                    dialog.updateImageTmp();
-                    // There are cases where isNewGpsData is not set but there
-                    // is still new data, e.g. if the EXIF data was re-read
-                    // from the image file.
-                    photo.applyTmp();
-                } else {
-                    photo.discardTmp();
-                }
-                updateLayer(layer, photo);
-            } catch (AssertionError err) {
-                JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
-                                              tr("Please select an image first."),
-                                              tr("No image selected"),
-                                              JOptionPane.INFORMATION_MESSAGE);
-                return;
-            }
-       }
+            if (photo.getFile() != null) {
+                title.append(" - ");
+                title.append(photo.getFile().getName());
+            }
+            PropertyEditorDialog dialog =
+                    new PropertyEditorDialog(title.toString(), photo, data);
+            if (dialog.getValue() == 1) {
+                dialog.updateImageTmp();
+                // There are cases where isNewGpsData is not set but there
+                // is still new data, e.g. if the EXIF data was re-read
+                // from the image file.
+                photo.applyTmp();
+            } else {
+                photo.discardTmp();
+            }
+            data.notifyImageUpdate();
+        }
 
         /**
@@ -125,11 +117,10 @@
          */
         private static boolean enabled() {
-            try {
-                //return ImageViewerDialog.getInstance().hasImage();
-                ImageViewerDialog.getInstance().hasImage();
-                return true;
-            } catch (AssertionError err) {
-                return false;
-            }
+            return getLayerWithSelectedImage().isPresent();
+        }
+
+        private static Optional<GeoImageLayer> getLayerWithSelectedImage() {
+            List<GeoImageLayer> list = MainApplication.getLayerManager().getLayersOfType(GeoImageLayer.class);
+            return list.stream().filter(l -> l.getImageData().getSelectedImage() != null).findFirst();
         }
 
@@ -137,4 +128,37 @@
         protected void updateEnabledState() {
             setEnabled(enabled());
+        }
+
+        @Override
+        public void layerAdded(LayerAddEvent e) {
+            Layer layer = e.getAddedLayer();
+            if (layer instanceof GeoImageLayer) {
+                ((GeoImageLayer) layer).getImageData().addImageDataUpdateListener(this);
+            }
+        }
+
+        @Override
+        public void layerRemoving(LayerRemoveEvent e) {
+            Layer layer = e.getRemovedLayer();
+
+            if (layer instanceof GeoImageLayer) {
+                ((GeoImageLayer) layer).getImageData().removeImageDataUpdateListener(this);
+            }
+            this.updateEnabledState();
+        }
+
+        @Override
+        public void layerOrderChanged(LayerOrderChangeEvent e) {
+            // ignored
+        }
+
+        @Override
+        public void imageDataUpdated(ImageData data) {
+            // ignored
+        }
+
+        @Override
+        public void selectedImageChanged(ImageData data) {
+            this.updateEnabledState();
         }
     }
@@ -150,5 +174,5 @@
         // Image that is to be updated.
         private final ImageEntry image;
-        private final GeoImageLayer layer;
+        private final ImageData data;
         // Image as it was when the dialog was opened.
         private final GpxImageEntry imgOrig;
@@ -156,8 +180,8 @@
 
         public PropertyEditorDialog(String title, final ImageEntry image,
-                                    final GeoImageLayer layer) {
+                final ImageData data) {
             super(MainApplication.getMainFrame(), title, tr("Ok"), tr("Cancel"));
             this.image = image;
-            this.layer = layer;
+            this.data = data;
             imgOrig = image.clone();
             setButtonIcons("ok", "cancel");
@@ -200,5 +224,5 @@
                 @Override public void updateValue(Double value) {
                     image.getTmp().setElevation(value);
-                    updateLayer(layer, image);
+                    data.notifyImageUpdate();
                 }
             };
@@ -214,5 +238,5 @@
                 @Override public void updateValue(Double value) {
                     image.getTmp().setSpeed(value);
-                    updateLayer(layer, image);
+                    data.notifyImageUpdate();
                 }
             };
@@ -230,5 +254,5 @@
                 @Override public void updateValue(Double value) {
                     image.getTmp().setExifImgDir(value);
-                    updateLayer(layer, image);
+                    data.notifyImageUpdate();
                 }
             };
@@ -573,5 +597,5 @@
             public void updateLatLon(LatLon latLon) {
                 image.getTmp().setPos(latLon);
-                updateLayer(layer, image);
+                data.notifyImageUpdate();
             }
 
Index: /applications/editors/josm/plugins/photoadjust/src/org/openstreetmap/josm/plugins/photoadjust/UntaggedGeoImageLayerAction.java
===================================================================
--- /applications/editors/josm/plugins/photoadjust/src/org/openstreetmap/josm/plugins/photoadjust/UntaggedGeoImageLayerAction.java	(revision 34785)
+++ /applications/editors/josm/plugins/photoadjust/src/org/openstreetmap/josm/plugins/photoadjust/UntaggedGeoImageLayerAction.java	(revision 34786)
@@ -54,5 +54,5 @@
                     // from the original layer.
                     untagged.add(img);
-                    layer.removePhotoByIdx(idx);
+                    layer.getImageData().removeImage(img);
                 }
             }
