Changeset 14590 in josm for trunk


Ignore:
Timestamp:
2018-12-22T21:54:34+01:00 (5 years ago)
Author:
Don-vip
Message:

fix #17050 - Refactor the GeoImageLayer and related to use a Data class with a selection listener (patch by francois2, modified)

Location:
trunk
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java

    r14456 r14590  
    179179            case CANCEL:
    180180                if (yLayer != null) {
    181                     if (yLayer.data != null) {
    182                         for (ImageEntry ie : yLayer.data) {
    183                             ie.discardTmp();
    184                         }
     181                    for (ImageEntry ie : yLayer.getImageData().getImages()) {
     182                        ie.discardTmp();
    185183                    }
    186184                    yLayer.updateBufferAndRepaint();
     
    217215                }
    218216
    219                 if (yLayer.data != null) {
    220                     for (ImageEntry ie : yLayer.data) {
    221                         ie.applyTmp();
    222                     }
     217                for (ImageEntry ie : yLayer.getImageData().getImages()) {
     218                    ie.applyTmp();
    223219                }
    224220
     
    646642                @Override
    647643                public String getElementAt(int i) {
    648                     return yLayer.data.get(i).getFile().getName();
     644                    return yLayer.getImageData().getImages().get(i).getFile().getName();
    649645                }
    650646
    651647                @Override
    652648                public int getSize() {
    653                     return yLayer.data != null ? yLayer.data.size() : 0;
     649                    return yLayer.getImageData().getImages().size();
    654650                }
    655651            });
     
    657653            imgList.getSelectionModel().addListSelectionListener(evt -> {
    658654                int index = imgList.getSelectedIndex();
    659                 imgDisp.setImage(yLayer.data.get(index));
    660                 Date date = yLayer.data.get(index).getExifTime();
     655                ImageEntry img = yLayer.getImageData().getImages().get(index);
     656                imgDisp.setImage(img);
     657                Date date = img.getExifTime();
    661658                if (date != null) {
    662659                    DateFormat df = DateUtils.getDateTimeFormat(DateFormat.SHORT, DateFormat.MEDIUM);
     
    10421039            // The selection of images we are about to correlate may have changed.
    10431040            // So reset all images.
    1044             if (yLayer.data != null) {
    1045                 for (ImageEntry ie: yLayer.data) {
    1046                     ie.discardTmp();
    1047                 }
     1041            for (ImageEntry ie: yLayer.getImageData().getImages()) {
     1042                ie.discardTmp();
    10481043            }
    10491044
     
    13011296     */
    13021297    private List<ImageEntry> getSortedImgList(boolean exif, boolean tagged) {
    1303         if (yLayer.data == null) {
    1304             return Collections.emptyList();
    1305         }
    1306         List<ImageEntry> dateImgLst = new ArrayList<>(yLayer.data.size());
    1307         for (ImageEntry e : yLayer.data) {
     1298        List<ImageEntry> dateImgLst = new ArrayList<>(yLayer.getImageData().getImages().size());
     1299        for (ImageEntry e : yLayer.getImageData().getImages()) {
    13081300            if (!e.hasExifTime()) {
    13091301                continue;
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java

    r14472 r14590  
    2424import java.util.Arrays;
    2525import java.util.Collection;
    26 import java.util.Collections;
    2726import java.util.HashSet;
    2827import java.util.LinkedHashSet;
     
    3534import javax.swing.Action;
    3635import javax.swing.Icon;
    37 import javax.swing.JLabel;
    3836import javax.swing.JOptionPane;
    39 import javax.swing.SwingConstants;
    4037
    4138import org.openstreetmap.josm.actions.LassoModeAction;
     
    4441import org.openstreetmap.josm.actions.mapmode.SelectAction;
    4542import org.openstreetmap.josm.data.Bounds;
     43import org.openstreetmap.josm.data.ImageData;
     44import org.openstreetmap.josm.data.ImageData.ImageDataUpdateListener;
    4645import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
    47 import org.openstreetmap.josm.gui.ExtendedDialog;
    4846import org.openstreetmap.josm.gui.MainApplication;
    4947import org.openstreetmap.josm.gui.MapFrame;
     
    5250import org.openstreetmap.josm.gui.NavigatableComponent;
    5351import org.openstreetmap.josm.gui.PleaseWaitRunnable;
    54 import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    5552import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
    5653import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
     
    6360import org.openstreetmap.josm.gui.layer.Layer;
    6461import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
    65 import org.openstreetmap.josm.gui.util.GuiHelper;
    6662import org.openstreetmap.josm.tools.ImageProvider;
    6763import org.openstreetmap.josm.tools.Logging;
     
    7268 */
    7369public class GeoImageLayer extends AbstractModifiableLayer implements
    74         JumpToMarkerLayer, NavigatableComponent.ZoomChangeListener {
     70        JumpToMarkerLayer, NavigatableComponent.ZoomChangeListener, ImageDataUpdateListener {
    7571
    7672    private static List<Action> menuAdditions = new LinkedList<>();
     
    7874    private static volatile List<MapMode> supportedMapModes;
    7975
    80     List<ImageEntry> data;
     76    private final ImageData data;
    8177    GpxLayer gpxLayer;
    8278
    8379    private final Icon icon = ImageProvider.get("dialogs/geoimage/photo-marker");
    8480    private final Icon selectedIcon = ImageProvider.get("dialogs/geoimage/photo-marker-selected");
    85 
    86     private int currentPhoto = -1;
    8781
    8882    boolean useThumbs;
     
    152146    public GeoImageLayer(final List<ImageEntry> data, GpxLayer gpxLayer, final String name, boolean useThumbs) {
    153147        super(name != null ? name : tr("Geotagged Images"));
    154         if (data != null) {
    155             Collections.sort(data);
    156         }
    157         this.data = data;
     148        this.data = new ImageData(data);
    158149        this.gpxLayer = gpxLayer;
    159150        this.useThumbs = useThumbs;
     151        this.data.addImageDataUpdateListener(this);
    160152    }
    161153
     
    293285                MainApplication.getLayerManager().addLayer(layer);
    294286
    295                 if (!canceled && layer.data != null && !layer.data.isEmpty()) {
     287                if (!canceled && !layer.getImageData().getImages().isEmpty()) {
    296288                    boolean noGeotagFound = true;
    297                     for (ImageEntry e : layer.data) {
     289                    for (ImageEntry e : layer.getImageData().getImages()) {
    298290                        if (e.getPos() != null) {
    299291                            noGeotagFound = false;
     
    312304    }
    313305
     306    /**
     307     * Create a GeoImageLayer asynchronously
     308     * @param files the list of image files to display
     309     * @param gpxLayer the gpx layer
     310     */
    314311    public static void create(Collection<File> files, GpxLayer gpxLayer) {
    315312        MainApplication.worker.execute(new Loader(files, gpxLayer));
     
    321318    }
    322319
     320    /**
     321     * Register actions on the layer
     322     * @param addition the action to be added
     323     */
    323324    public static void registerMenuAddition(Action addition) {
    324325        menuAdditions.add(addition);
     
    357358        int tagged = 0;
    358359        int newdata = 0;
    359         int n = 0;
    360         if (data != null) {
    361             n = data.size();
    362             for (ImageEntry e : data) {
    363                 if (e.getPos() != null) {
    364                     tagged++;
    365                 }
    366                 if (e.hasNewGpsData()) {
    367                     newdata++;
    368                 }
     360        int n = data.getImages().size();
     361        for (ImageEntry e : data.getImages()) {
     362            if (e.getPos() != null) {
     363                tagged++;
     364            }
     365            if (e.hasNewGpsData()) {
     366                newdata++;
    369367            }
    370368        }
     
    392390    @Override
    393391    public boolean isModified() {
    394         if (data != null) {
    395             for (ImageEntry e : data) {
    396                 if (e.hasNewGpsData()) {
    397                     return true;
    398                 }
    399             }
    400         }
    401         return false;
     392        return this.data.isModified();
    402393    }
    403394
     
    418409        l.stopLoadThumbs();
    419410
    420         final ImageEntry selected = l.data != null && l.currentPhoto >= 0 ? l.data.get(l.currentPhoto) : null;
    421 
    422         if (l.data != null) {
    423             data.addAll(l.data);
    424         }
    425         Collections.sort(data);
    426 
    427         // Suppress the double photos.
    428         if (data.size() > 1) {
    429             ImageEntry cur;
    430             ImageEntry prev = data.get(data.size() - 1);
    431             for (int i = data.size() - 2; i >= 0; i--) {
    432                 cur = data.get(i);
    433                 if (cur.getFile().equals(prev.getFile())) {
    434                     data.remove(i);
    435                 } else {
    436                     prev = cur;
    437                 }
    438             }
    439         }
    440 
    441         if (selected != null && !data.isEmpty()) {
    442             GuiHelper.runInEDTAndWait(() -> {
    443                 for (int i = 0; i < data.size(); i++) {
    444                     if (selected.equals(data.get(i))) {
    445                         currentPhoto = i;
    446                         ImageViewerDialog.showImage(this, data.get(i));
    447                         break;
    448                     }
    449                 }
    450             });
    451         }
     411        this.data.mergeFrom(l.getImageData());
    452412
    453413        setName(l.getName());
     
    531491                tempG.setComposite(saveComp);
    532492
    533                 if (data != null) {
    534                     for (ImageEntry e : data) {
    535                         paintImage(e, mv, clip, tempG);
    536                     }
    537                     if (currentPhoto >= 0 && currentPhoto < data.size()) {
    538                         // Make sure the selected image is on top in case multiple images overlap.
    539                         paintImage(data.get(currentPhoto), mv, clip, tempG);
    540                     }
     493                for (ImageEntry e : data.getImages()) {
     494                    paintImage(e, mv, clip, tempG);
     495                }
     496                if (data.getSelectedImage() != null) {
     497                    // Make sure the selected image is on top in case multiple images overlap.
     498                    paintImage(data.getSelectedImage(), mv, clip, tempG);
    541499                }
    542500                updateOffscreenBuffer = false;
    543501            }
    544502            g.drawImage(offscreenBuffer, 0, 0, null);
    545         } else if (data != null) {
    546             for (ImageEntry e : data) {
     503        } else {
     504            for (ImageEntry e : data.getImages()) {
    547505                if (e.getPos() == null) {
    548506                    continue;
     
    555513        }
    556514
    557         if (currentPhoto >= 0 && currentPhoto < data.size()) {
    558             ImageEntry e = data.get(currentPhoto);
    559 
     515        ImageEntry e = data.getSelectedImage();
     516        if (e != null) {
    560517            if (e.getPos() != null) {
    561518                Point p = mv.getPoint(e.getPos());
     
    622579    @Override
    623580    public void visitBoundingBox(BoundingXYVisitor v) {
    624         for (ImageEntry e : data) {
     581        for (ImageEntry e : data.getImages()) {
    625582            v.visit(e.getPos());
    626583        }
     
    631588     */
    632589    public void showCurrentPhoto() {
    633         clearOtherCurrentPhotos();
    634         if (currentPhoto >= 0) {
    635             ImageViewerDialog.showImage(this, data.get(currentPhoto));
    636         } else {
    637             ImageViewerDialog.showImage(this, null);
     590        if (data.getSelectedImage() != null) {
     591            clearOtherCurrentPhotos();
    638592        }
    639593        updateBufferAndRepaint();
     
    641595
    642596    /**
    643      * Shows next photo.
    644      */
    645     public void showNextPhoto() {
    646         if (data != null && !data.isEmpty()) {
    647             currentPhoto++;
    648             if (currentPhoto >= data.size()) {
    649                 currentPhoto = data.size() - 1;
    650             }
    651         } else {
    652             currentPhoto = -1;
    653         }
    654         showCurrentPhoto();
    655     }
    656 
    657     /**
    658      * Shows previous photo.
    659      */
    660     public void showPreviousPhoto() {
    661         if (data != null && !data.isEmpty()) {
    662             currentPhoto--;
    663             if (currentPhoto < 0) {
    664                 currentPhoto = 0;
    665             }
    666         } else {
    667             currentPhoto = -1;
    668         }
    669         showCurrentPhoto();
    670     }
    671 
    672     /**
    673      * Shows first photo.
    674      */
    675     public void showFirstPhoto() {
    676         if (data != null && !data.isEmpty()) {
    677             currentPhoto = 0;
    678         } else {
    679             currentPhoto = -1;
    680         }
    681         showCurrentPhoto();
    682     }
    683 
    684     /**
    685      * Shows last photo.
    686      */
    687     public void showLastPhoto() {
    688         if (data != null && !data.isEmpty()) {
    689             currentPhoto = data.size() - 1;
    690         } else {
    691             currentPhoto = -1;
    692         }
    693         showCurrentPhoto();
    694     }
    695 
    696     public void checkPreviousNextButtons() {
    697         ImageViewerDialog.setNextEnabled(data != null && currentPhoto < data.size() - 1);
    698         ImageViewerDialog.setPreviousEnabled(currentPhoto > 0);
    699     }
    700 
    701     public void removeCurrentPhoto() {
    702         if (data != null && !data.isEmpty() && currentPhoto >= 0 && currentPhoto < data.size()) {
    703             data.remove(currentPhoto);
    704             if (currentPhoto >= data.size()) {
    705                 currentPhoto = data.size() - 1;
    706             }
    707             showCurrentPhoto();
    708         }
    709     }
    710 
    711     public void removeCurrentPhotoFromDisk() {
    712         ImageEntry toDelete;
    713         if (data != null && !data.isEmpty() && currentPhoto >= 0 && currentPhoto < data.size()) {
    714             toDelete = data.get(currentPhoto);
    715 
    716             int result = new ExtendedDialog(
    717                     MainApplication.getMainFrame(),
    718                     tr("Delete image file from disk"),
    719                     tr("Cancel"), tr("Delete"))
    720             .setButtonIcons("cancel", "dialogs/delete")
    721             .setContent(new JLabel(tr("<html><h3>Delete the file {0} from disk?<p>The image file will be permanently lost!</h3></html>",
    722                     toDelete.getFile().getName()), ImageProvider.get("dialogs/geoimage/deletefromdisk"), SwingConstants.LEFT))
    723                     .toggleEnable("geoimage.deleteimagefromdisk")
    724                     .setCancelButton(1)
    725                     .setDefaultButton(2)
    726                     .showDialog()
    727                     .getValue();
    728 
    729             if (result == 2) {
    730                 data.remove(currentPhoto);
    731                 if (currentPhoto >= data.size()) {
    732                     currentPhoto = data.size() - 1;
    733                 }
    734 
    735                 if (Utils.deleteFile(toDelete.getFile())) {
    736                     Logging.info("File "+toDelete.getFile()+" deleted. ");
    737                 } else {
    738                     JOptionPane.showMessageDialog(
    739                             MainApplication.getMainFrame(),
    740                             tr("Image file could not be deleted."),
    741                             tr("Error"),
    742                             JOptionPane.ERROR_MESSAGE
    743                             );
    744                 }
    745 
    746                 showCurrentPhoto();
    747             }
    748         }
    749     }
    750 
    751     public void copyCurrentPhotoPath() {
    752         if (data != null && !data.isEmpty() && currentPhoto >= 0 && currentPhoto < data.size()) {
    753             ClipboardUtils.copyString(data.get(currentPhoto).getFile().toString());
    754         }
    755     }
    756 
    757     /**
    758      * Removes a photo from the list of images by index.
    759      * @param idx Image index
    760      * @since 6392
    761      */
    762     public void removePhotoByIdx(int idx) {
    763         if (idx >= 0 && data != null && idx < data.size()) {
    764             data.remove(idx);
    765         }
    766     }
    767 
    768     /**
    769597     * Check if the position of the mouse event is within the rectangle of the photo icon or thumbnail.
    770      * @param idx Image index, range 0 .. size-1
     598     * @param idx the image index
    771599     * @param evt Mouse event
    772600     * @return {@code true} if the photo matches the mouse position, {@code false} otherwise
    773601     */
    774602    private boolean isPhotoIdxUnderMouse(int idx, MouseEvent evt) {
    775         if (idx >= 0 && data != null && idx < data.size()) {
    776             ImageEntry img = data.get(idx);
    777             if (img.getPos() != null) {
    778                 Point imgCenter = MainApplication.getMap().mapView.getPoint(img.getPos());
    779                 Rectangle imgRect;
    780                 if (useThumbs && img.hasThumbnail()) {
    781                     Dimension imgDim = scaledDimension(img.getThumbnail());
    782                     if (imgDim != null) {
    783                         imgRect = new Rectangle(imgCenter.x - imgDim.width / 2,
    784                                                 imgCenter.y - imgDim.height / 2,
    785                                                 imgDim.width, imgDim.height);
    786                     } else {
    787                         imgRect = null;
    788                     }
     603        ImageEntry img = data.getImages().get(idx);
     604        if (img.getPos() != null) {
     605            Point imgCenter = MainApplication.getMap().mapView.getPoint(img.getPos());
     606            Rectangle imgRect;
     607            if (useThumbs && img.hasThumbnail()) {
     608                Dimension imgDim = scaledDimension(img.getThumbnail());
     609                if (imgDim != null) {
     610                    imgRect = new Rectangle(imgCenter.x - imgDim.width / 2,
     611                                            imgCenter.y - imgDim.height / 2,
     612                                            imgDim.width, imgDim.height);
    789613                } else {
    790                     imgRect = new Rectangle(imgCenter.x - icon.getIconWidth() / 2,
    791                                             imgCenter.y - icon.getIconHeight() / 2,
    792                                             icon.getIconWidth(), icon.getIconHeight());
    793                 }
    794                 if (imgRect != null && imgRect.contains(evt.getPoint())) {
    795                     return true;
    796                 }
     614                    imgRect = null;
     615                }
     616            } else {
     617                imgRect = new Rectangle(imgCenter.x - icon.getIconWidth() / 2,
     618                                        imgCenter.y - icon.getIconHeight() / 2,
     619                                        icon.getIconWidth(), icon.getIconHeight());
     620            }
     621            if (imgRect != null && imgRect.contains(evt.getPoint())) {
     622                return true;
    797623            }
    798624        }
     
    810636     */
    811637    private int getPhotoIdxUnderMouse(MouseEvent evt, boolean cycle) {
    812         if (data != null) {
    813             if (cycle && currentPhoto >= 0) {
    814                 // Cycle loop is forward as that is the natural order.
    815                 // Loop 1: One after current photo up to last one.
    816                 for (int idx = currentPhoto + 1; idx < data.size(); ++idx) {
    817                     if (isPhotoIdxUnderMouse(idx, evt)) {
    818                         return idx;
    819                     }
    820                 }
    821                 // Loop 2: First photo up to current one.
    822                 for (int idx = 0; idx <= currentPhoto; ++idx) {
    823                     if (isPhotoIdxUnderMouse(idx, evt)) {
    824                         return idx;
    825                     }
    826                 }
    827             } else {
    828                 // Check for current photo first, i.e. keep it selected if it is under the mouse.
    829                 if (currentPhoto >= 0 && isPhotoIdxUnderMouse(currentPhoto, evt)) {
    830                     return currentPhoto;
    831                 }
    832                 // Loop from last to first to prefer topmost image.
    833                 for (int idx = data.size() - 1; idx >= 0; --idx) {
    834                     if (isPhotoIdxUnderMouse(idx, evt)) {
    835                         return idx;
    836                     }
     638        ImageEntry selectedImage = data.getSelectedImage();
     639        int selectedIndex = data.getImages().indexOf(selectedImage);
     640
     641        if (cycle && selectedImage != null) {
     642            // Cycle loop is forward as that is the natural order.
     643            // Loop 1: One after current photo up to last one.
     644            for (int idx = selectedIndex + 1; idx < data.getImages().size(); ++idx) {
     645                if (isPhotoIdxUnderMouse(idx, evt)) {
     646                    return idx;
     647                }
     648            }
     649            // Loop 2: First photo up to current one.
     650            for (int idx = 0; idx <= selectedIndex; ++idx) {
     651                if (isPhotoIdxUnderMouse(idx, evt)) {
     652                    return idx;
     653                }
     654            }
     655        } else {
     656            // Check for current photo first, i.e. keep it selected if it is under the mouse.
     657            if (selectedImage != null && isPhotoIdxUnderMouse(selectedIndex, evt)) {
     658                return selectedIndex;
     659            }
     660            // Loop from last to first to prefer topmost image.
     661            for (int idx = data.getImages().size() - 1; idx >= 0; --idx) {
     662                if (isPhotoIdxUnderMouse(idx, evt)) {
     663                    return idx;
    837664                }
    838665            }
     
    862689        int idx = getPhotoIdxUnderMouse(evt);
    863690        if (idx >= 0) {
    864             return data.get(idx);
     691            return data.getImages().get(idx);
    865692        } else {
    866693            return null;
     
    871698     * Clears the currentPhoto, i.e. remove select marker, and optionally repaint.
    872699     * @param repaint Repaint flag
     700     * @deprecated Use {@link ImageData#clearSelectedImage}
    873701     * @since 6392
    874702     */
     703    @Deprecated
    875704    public void clearCurrentPhoto(boolean repaint) {
    876         currentPhoto = -1;
     705        data.clearSelectedImage();
    877706        if (repaint) {
    878707            updateBufferAndRepaint();
     
    887716                 MainApplication.getLayerManager().getLayersOfType(GeoImageLayer.class)) {
    888717            if (layer != this) {
    889                 layer.clearCurrentPhoto(false);
     718                layer.getImageData().clearSelectedImage();
    890719            }
    891720        }
     
    948777                if (ev.getButton() != MouseEvent.BUTTON1)
    949778                    return;
    950                 if (data == null || !isVisible() || !isMapModeOk())
     779                if (!isVisible() || !isMapModeOk())
    951780                    return;
    952781
     
    957786                    lastSelPos = mousePos;
    958787                    cycleModeArmed = false;
    959                     currentPhoto = idx;
    960                     showCurrentPhoto();
     788                    data.setSelectedImage(data.getImages().get(idx));
    961789                }
    962790            }
     
    1014842        MapFrame.removeMapModeChangeListener(mapModeListener);
    1015843        MainApplication.getLayerManager().removeActiveLayerChangeListener(activeLayerChangeListener);
    1016         currentPhoto = -1;
    1017         if (data != null) {
    1018             data.clear();
    1019         }
    1020         data = null;
     844        data.removeImageDataUpdateListener(this);
    1021845    }
    1022846
     
    1084908     */
    1085909    public List<ImageEntry> getImages() {
    1086         return data == null ? Collections.<ImageEntry>emptyList() : new ArrayList<>(data);
     910        return new ArrayList<>(data.getImages());
     911    }
     912
     913    /**
     914     * Returns the image data store being used by this layer
     915     * @return imageData
     916     * @since 14590
     917     */
     918    public ImageData getImageData() {
     919        return data;
    1087920    }
    1088921
     
    1097930    @Override
    1098931    public void jumpToNextMarker() {
    1099         showNextPhoto();
     932        data.selectNextImage();
    1100933    }
    1101934
    1102935    @Override
    1103936    public void jumpToPreviousMarker() {
    1104         showPreviousPhoto();
     937        data.selectPreviousImage();
    1105938    }
    1106939
     
    1129962        invalidate();
    1130963    }
     964
     965    @Override
     966    public void selectedImageChanged(ImageData data) {
     967        showCurrentPhoto();
     968    }
     969
     970    @Override
     971    public void imageDataUpdated(ImageData data) {
     972        updateBufferAndRepaint();
     973    }
    1131974}
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplay.java

    r13581 r14590  
    703703     */
    704704    public void setOsdText(String text) {
    705         this.osdText = text;
    706         repaint();
     705        if (!text.equals(this.osdText)) {
     706            this.osdText = text;
     707            repaint();
     708        }
    707709    }
    708710
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java

    r13832 r14590  
    1414import java.text.DateFormat;
    1515import java.text.SimpleDateFormat;
     16import java.util.Objects;
    1617
    1718import javax.swing.Box;
    1819import javax.swing.JButton;
     20import javax.swing.JLabel;
     21import javax.swing.JOptionPane;
    1922import javax.swing.JPanel;
    2023import javax.swing.JToggleButton;
     24import javax.swing.SwingConstants;
    2125
    2226import org.openstreetmap.josm.actions.JosmAction;
     27import org.openstreetmap.josm.data.ImageData;
     28import org.openstreetmap.josm.data.ImageData.ImageDataUpdateListener;
     29import org.openstreetmap.josm.gui.ExtendedDialog;
    2330import org.openstreetmap.josm.gui.MainApplication;
     31import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
    2432import org.openstreetmap.josm.gui.dialogs.DialogsPanel.Action;
    2533import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
     
    3240import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
    3341import org.openstreetmap.josm.tools.ImageProvider;
     42import org.openstreetmap.josm.tools.Logging;
    3443import org.openstreetmap.josm.tools.Shortcut;
     44import org.openstreetmap.josm.tools.Utils;
    3545import org.openstreetmap.josm.tools.date.DateUtils;
    3646
     
    3848 * Dialog to view and manipulate geo-tagged images from a {@link GeoImageLayer}.
    3949 */
    40 public final class ImageViewerDialog extends ToggleDialog implements LayerChangeListener, ActiveLayerChangeListener {
     50public final class ImageViewerDialog extends ToggleDialog implements LayerChangeListener, ActiveLayerChangeListener, ImageDataUpdateListener {
    4151
    4252    private final ImageZoomAction imageZoomAction = new ImageZoomAction();
     
    8090    private JButton btnFirst;
    8191    private JButton btnCollapse;
     92    private JButton btnDelete;
     93    private JButton btnCopyPath;
     94    private JButton btnDeleteFromDisk;
    8295    private JToggleButton tbCentre;
    8396
     
    88101        MainApplication.getLayerManager().addActiveLayerChangeListener(this);
    89102        MainApplication.getLayerManager().addLayerChangeListener(this);
     103        for (Layer l: MainApplication.getLayerManager().getLayers()) {
     104            registerOnLayer(l);
     105        }
    90106    }
    91107
     
    107123        btnPrevious = createNavigationButton(imagePreviousAction, buttonDim);
    108124
    109         JButton btnDelete = new JButton(imageRemoveAction);
     125        btnDelete = new JButton(imageRemoveAction);
    110126        btnDelete.setPreferredSize(buttonDim);
    111127
    112         JButton btnDeleteFromDisk = new JButton(imageRemoveFromDiskAction);
     128        btnDeleteFromDisk = new JButton(imageRemoveFromDiskAction);
    113129        btnDeleteFromDisk.setPreferredSize(buttonDim);
    114130
    115         JButton btnCopyPath = new JButton(imageCopyPathAction);
     131        btnCopyPath = new JButton(imageCopyPathAction);
    116132        btnCopyPath.setPreferredSize(buttonDim);
    117133
     
    190206        @Override
    191207        public void actionPerformed(ActionEvent e) {
    192             if (currentLayer != null) {
    193                 currentLayer.showNextPhoto();
     208            if (currentData != null) {
     209                currentData.selectNextImage();
    194210            }
    195211        }
     
    205221        @Override
    206222        public void actionPerformed(ActionEvent e) {
    207             if (currentLayer != null) {
    208                 currentLayer.showPreviousPhoto();
     223            if (currentData != null) {
     224                currentData.selectPreviousImage();
    209225            }
    210226        }
     
    220236        @Override
    221237        public void actionPerformed(ActionEvent e) {
    222             if (currentLayer != null) {
    223                 currentLayer.showFirstPhoto();
     238            if (currentData != null) {
     239                currentData.selectFirstImage();
    224240            }
    225241        }
     
    235251        @Override
    236252        public void actionPerformed(ActionEvent e) {
    237             if (currentLayer != null) {
    238                 currentLayer.showLastPhoto();
     253            if (currentData != null) {
     254                currentData.selectLastImage();
    239255            }
    240256        }
     
    278294        @Override
    279295        public void actionPerformed(ActionEvent e) {
    280             if (currentLayer != null) {
    281                 currentLayer.removeCurrentPhoto();
     296            if (currentData != null) {
     297                currentData.removeSelectedImage();
    282298            }
    283299        }
     
    294310        @Override
    295311        public void actionPerformed(ActionEvent e) {
    296             if (currentLayer != null) {
    297                 currentLayer.removeCurrentPhotoFromDisk();
     312            if (currentData != null && currentData.getSelectedImage() != null) {
     313                ImageEntry toDelete = currentData.getSelectedImage();
     314
     315                int result = new ExtendedDialog(
     316                        MainApplication.getMainFrame(),
     317                        tr("Delete image file from disk"),
     318                        tr("Cancel"), tr("Delete"))
     319                        .setButtonIcons("cancel", "dialogs/delete")
     320                        .setContent(new JLabel("<html><h3>" + tr("Delete the file {0} from disk?", toDelete.getFile().getName())
     321                                + "<p>" + tr("The image file will be permanently lost!") + "</h3></html>",
     322                                ImageProvider.get("dialogs/geoimage/deletefromdisk"), SwingConstants.LEFT))
     323                        .toggleEnable("geoimage.deleteimagefromdisk")
     324                        .setCancelButton(1)
     325                        .setDefaultButton(2)
     326                        .showDialog()
     327                        .getValue();
     328
     329                if (result == 2) {
     330                    currentData.removeSelectedImage();
     331
     332                    if (Utils.deleteFile(toDelete.getFile())) {
     333                        Logging.info("File " + toDelete.getFile() + " deleted.");
     334                    } else {
     335                        JOptionPane.showMessageDialog(
     336                                MainApplication.getMainFrame(),
     337                                tr("Image file could not be deleted."),
     338                                tr("Error"),
     339                                JOptionPane.ERROR_MESSAGE
     340                                );
     341                    }
     342                }
    298343            }
    299344        }
     
    309354        @Override
    310355        public void actionPerformed(ActionEvent e) {
    311             if (currentLayer != null) {
    312                 currentLayer.copyCurrentPhotoPath();
     356            if (currentData != null) {
     357                ClipboardUtils.copyString(currentData.getSelectedImage().getFile().toString());
    313358            }
    314359        }
     
    329374
    330375    /**
    331      * Displays image for the given layer.
    332      * @param layer geo image layer
     376     * Displays image for the given data.
     377     * @param data geo image data
    333378     * @param entry image entry
    334379     */
    335     public static void showImage(GeoImageLayer layer, ImageEntry entry) {
    336         getInstance().displayImage(layer, entry);
    337         if (layer != null) {
    338             layer.checkPreviousNextButtons();
    339         } else {
    340             setPreviousEnabled(false);
    341             setNextEnabled(false);
    342         }
     380    public static void showImage(ImageData data, ImageEntry entry) {
     381        getInstance().displayImage(data, entry);
    343382    }
    344383
     
    347386     * @param value {@code true} to enable the button, {@code false} otherwise
    348387     */
    349     public static void setPreviousEnabled(boolean value) {
    350         getInstance().btnFirst.setEnabled(value);
    351         getInstance().btnPrevious.setEnabled(value);
     388    public void setPreviousEnabled(boolean value) {
     389        btnFirst.setEnabled(value);
     390        btnPrevious.setEnabled(value);
    352391    }
    353392
     
    356395     * @param value {@code true} to enable the button, {@code false} otherwise
    357396     */
    358     public static void setNextEnabled(boolean value) {
    359         getInstance().btnNext.setEnabled(value);
    360         getInstance().btnLast.setEnabled(value);
     397    public void setNextEnabled(boolean value) {
     398        btnNext.setEnabled(value);
     399        btnLast.setEnabled(value);
    361400    }
    362401
     
    374413    }
    375414
    376     private transient GeoImageLayer currentLayer;
     415    private transient ImageData currentData;
    377416    private transient ImageEntry currentEntry;
    378417
    379418    /**
    380419     * Displays image for the given layer.
    381      * @param layer geo image layer
     420     * @param data the image data
    382421     * @param entry image entry
    383422     */
    384     public void displayImage(GeoImageLayer layer, ImageEntry entry) {
     423    public void displayImage(ImageData data, ImageEntry entry) {
    385424        boolean imageChanged;
    386425
     
    394433            }
    395434
    396             currentLayer = layer;
     435            currentData = data;
    397436            currentEntry = entry;
    398437        }
    399438
    400439        if (entry != null) {
     440            setNextEnabled(data.hasNextImage());
     441            setPreviousEnabled(data.hasPreviousImage());
     442            btnDelete.setEnabled(true);
     443            btnDeleteFromDisk.setEnabled(true);
     444            btnCopyPath.setEnabled(true);
     445
    401446            if (imageChanged) {
    402447                // Set only if the image is new to preserve zoom and position if the same image is redisplayed
     
    437482            imgDisplay.setImage(null);
    438483            imgDisplay.setOsdText("");
     484            setNextEnabled(false);
     485            setPreviousEnabled(false);
     486            btnDelete.setEnabled(false);
     487            btnDeleteFromDisk.setEnabled(false);
     488            btnCopyPath.setEnabled(false);
    439489            return;
    440490        }
     
    489539
    490540    /**
    491      * Returns the layer associated with the image.
    492      * @return Layer associated with the image
    493      * @since 6392
    494      */
    495     public static GeoImageLayer getCurrentLayer() {
    496         return getInstance().currentLayer;
    497     }
    498 
    499     /**
    500541     * Returns whether the center view is currently active.
    501542     * @return {@code true} if the center view is active, {@code false} otherwise
     
    508549    @Override
    509550    public void layerAdded(LayerAddEvent e) {
     551        registerOnLayer(e.getAddedLayer());
    510552        showLayer(e.getAddedLayer());
    511553    }
     
    513555    @Override
    514556    public void layerRemoving(LayerRemoveEvent e) {
    515         // Clear current image and layer if current layer is deleted
    516         if (currentLayer != null && currentLayer.equals(e.getRemovedLayer())) {
    517             showImage(null, null);
    518         }
    519         // Check buttons state in case of layer merging
    520         if (currentLayer != null && e.getRemovedLayer() instanceof GeoImageLayer) {
    521             currentLayer.checkPreviousNextButtons();
     557        if (e.getRemovedLayer() instanceof GeoImageLayer) {
     558            ImageData removedData = ((GeoImageLayer) e.getRemovedLayer()).getImageData();
     559            if (removedData == currentData) {
     560                displayImage(null, null);
     561            }
     562            removedData.removeImageDataUpdateListener(this);
    522563        }
    523564    }
     
    533574    }
    534575
     576    private void registerOnLayer(Layer layer) {
     577        if (layer instanceof GeoImageLayer) {
     578            ((GeoImageLayer) layer).getImageData().addImageDataUpdateListener(this);
     579        }
     580    }
     581
    535582    private void showLayer(Layer newLayer) {
    536         if (currentLayer == null && newLayer instanceof GeoImageLayer) {
    537             ((GeoImageLayer) newLayer).showFirstPhoto();
    538         }
     583        if (currentData == null && newLayer instanceof GeoImageLayer) {
     584            ((GeoImageLayer) newLayer).getImageData().selectFirstImage();
     585        }
     586    }
     587
     588    @Override
     589    public void selectedImageChanged(ImageData data) {
     590        showImage(data, data.getSelectedImage());
     591    }
     592
     593    @Override
     594    public void imageDataUpdated(ImageData data) {
     595        showImage(data, data.getSelectedImage());
    539596    }
    540597}
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ShowThumbnailAction.java

    r13130 r14590  
    5050     */
    5151    private static boolean enabled(GeoImageLayer layer) {
    52         return layer.data != null && !layer.data.isEmpty();
     52        return !layer.getImageData().getImages().isEmpty();
    5353    }
    5454
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ThumbsLoader.java

    r13643 r14590  
    5252     */
    5353    public ThumbsLoader(GeoImageLayer layer) {
    54         this(new ArrayList<>(layer.data), layer);
     54        this(new ArrayList<>(layer.getImageData().getImages()), layer);
    5555    }
    5656
Note: See TracChangeset for help on using the changeset viewer.