Ticket #12255: 12255-v3.patch

File 12255-v3.patch, 24.7 KB (added by simon04, 10 years ago)
  • src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java b/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
    index c5f440b..f0564cc 100644
    a b  
    2121import java.beans.PropertyChangeListener;
    2222import java.io.File;
    2323import java.io.IOException;
    24 import java.text.ParseException;
    2524import java.util.ArrayList;
    2625import java.util.Arrays;
    27 import java.util.Calendar;
    2826import java.util.Collection;
    2927import java.util.Collections;
    30 import java.util.GregorianCalendar;
    3128import java.util.HashSet;
    3229import java.util.LinkedHashSet;
    3330import java.util.LinkedList;
    3431import java.util.List;
    3532import java.util.Set;
    36 import java.util.TimeZone;
    3733import java.util.concurrent.ExecutorService;
    3834import java.util.concurrent.Executors;
    3935
     
    4945import org.openstreetmap.josm.actions.mapmode.MapMode;
    5046import org.openstreetmap.josm.actions.mapmode.SelectAction;
    5147import org.openstreetmap.josm.data.Bounds;
    52 import org.openstreetmap.josm.data.coor.LatLon;
    5348import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
    5449import org.openstreetmap.josm.gui.ExtendedDialog;
    5550import org.openstreetmap.josm.gui.MapFrame;
     
    6762import org.openstreetmap.josm.gui.layer.Layer;
    6863import org.openstreetmap.josm.gui.util.GuiHelper;
    6964import org.openstreetmap.josm.io.JpgImporter;
    70 import org.openstreetmap.josm.tools.ExifReader;
    7165import org.openstreetmap.josm.tools.ImageProvider;
    7266import org.openstreetmap.josm.tools.Utils;
    7367
    74 import com.drew.imaging.jpeg.JpegMetadataReader;
    75 import com.drew.lang.CompoundException;
    76 import com.drew.metadata.Directory;
    77 import com.drew.metadata.Metadata;
    78 import com.drew.metadata.MetadataException;
    79 import com.drew.metadata.exif.ExifIFD0Directory;
    80 import com.drew.metadata.exif.GpsDirectory;
    81 
    8268/**
    8369 * Layer displaying geottaged pictures.
    8470 */
    protected void realRun() throws IOException {  
    157143                progressMonitor.subTask(tr("Reading {0}...", f.getName()));
    158144                progressMonitor.worked(1);
    159145
    160                 ImageEntry e = new ImageEntry();
    161 
    162                 // Changed to silently cope with no time info in exif. One case
    163                 // of person having time that couldn't be parsed, but valid GPS info
    164 
    165                 try {
    166                     e.setExifTime(ExifReader.readTime(f));
    167                 } catch (ParseException ex) {
    168                     e.setExifTime(null);
    169                 }
    170                 e.setFile(f);
    171                 extractExif(e);
     146                ImageEntry e = new ImageEntry(f);
     147                e.extractExif();
    172148                data.add(e);
    173149            }
    174150            layer = new GeoImageLayer(data, gpxLayer);
    public void paint(Graphics2D g, MapView mv, Bounds bounds) {  
    498474                            continue;
    499475                        }
    500476                        Point p = mv.getPoint(e.getPos());
    501                         if (e.thumbnail != null) {
    502                             Dimension d = scaledDimension(e.thumbnail);
     477                        if (e.hasThumbnail()) {
     478                            Dimension d = scaledDimension(e.getThumbnail());
    503479                            Rectangle target = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height);
    504480                            if (clip.intersects(target)) {
    505                                 tempG.drawImage(e.thumbnail, target.x, target.y, target.width, target.height, null);
     481                                tempG.drawImage(e.getThumbnail(), target.x, target.y, target.width, target.height, null);
    506482                            }
    507483                        } else { // thumbnail not loaded yet
    508484                            icon.paintIcon(mv, tempG,
    public void paint(Graphics2D g, MapView mv, Bounds bounds) {  
    534510
    535511                int imgWidth = 100;
    536512                int imgHeight = 100;
    537                 if (useThumbs && e.thumbnail != null) {
    538                     Dimension d = scaledDimension(e.thumbnail);
     513                if (useThumbs && e.hasThumbnail()) {
     514                    Dimension d = scaledDimension(e.getThumbnail());
    539515                    imgWidth = d.width;
    540516                    imgHeight = d.height;
    541517                } else {
    public void paint(Graphics2D g, MapView mv, Bounds bounds) {  
    573549                    g.drawPolyline(xar, yar, 3);
    574550                }
    575551
    576                 if (useThumbs && e.thumbnail != null) {
     552                if (useThumbs && e.hasThumbnail()) {
    577553                    g.setColor(new Color(128, 0, 0, 122));
    578554                    g.fillRect(p.x - imgWidth / 2, p.y - imgHeight / 2, imgWidth, imgHeight);
    579555                } else {
    public void visitBoundingBox(BoundingXYVisitor v) {  
    593569        }
    594570    }
    595571
    596     /**
    597      * Extract GPS metadata from image EXIF
    598      *
    599      * If successful, fills in the LatLon and EastNorth attributes of passed in image
    600      * @param e image entry
    601      */
    602     private static void extractExif(ImageEntry e) {
    603 
    604         Metadata metadata;
    605         Directory dirExif;
    606         GpsDirectory dirGps;
    607 
    608         try {
    609             metadata = JpegMetadataReader.readMetadata(e.getFile());
    610             dirExif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
    611             dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
    612         } catch (CompoundException | IOException p) {
    613             e.setExifCoor(null);
    614             e.setPos(null);
    615             return;
    616         }
    617 
    618         try {
    619             if (dirExif != null) {
    620                 int orientation = dirExif.getInt(ExifIFD0Directory.TAG_ORIENTATION);
    621                 e.setExifOrientation(orientation);
    622             }
    623         } catch (MetadataException ex) {
    624             Main.debug(ex.getMessage());
    625         }
    626 
    627         if (dirGps == null) {
    628             e.setExifCoor(null);
    629             e.setPos(null);
    630             return;
    631         }
    632 
    633         try {
    634             double speed = dirGps.getDouble(GpsDirectory.TAG_SPEED);
    635             String speedRef = dirGps.getString(GpsDirectory.TAG_SPEED_REF);
    636             if ("M".equalsIgnoreCase(speedRef)) {
    637                 // miles per hour
    638                 speed *= 1.609344;
    639             } else if ("N".equalsIgnoreCase(speedRef)) {
    640                 // knots == nautical miles per hour
    641                 speed *= 1.852;
    642             }
    643             // default is K (km/h)
    644             e.setSpeed(speed);
    645         } catch (Exception ex) {
    646             Main.debug(ex.getMessage());
    647         }
    648 
    649         try {
    650             double ele = dirGps.getDouble(GpsDirectory.TAG_ALTITUDE);
    651             int d = dirGps.getInt(GpsDirectory.TAG_ALTITUDE_REF);
    652             if (d == 1) {
    653                 ele *= -1;
    654             }
    655             e.setElevation(ele);
    656         } catch (MetadataException ex) {
    657             Main.debug(ex.getMessage());
    658         }
    659 
    660         try {
    661             LatLon latlon = ExifReader.readLatLon(dirGps);
    662             e.setExifCoor(latlon);
    663             e.setPos(e.getExifCoor());
    664 
    665         } catch (Exception ex) { // (other exceptions, e.g. #5271)
    666             Main.error("Error reading EXIF from file: "+ex);
    667             e.setExifCoor(null);
    668             e.setPos(null);
    669         }
    670 
    671         try {
    672             Double direction = ExifReader.readDirection(dirGps);
    673             if (direction != null) {
    674                 e.setExifImgDir(direction.doubleValue());
    675             }
    676         } catch (Exception ex) { // (CompoundException and other exceptions, e.g. #5271)
    677             Main.debug(ex.getMessage());
    678         }
    679 
    680         // Time and date. We can have these cases:
    681         // 1) GPS_TIME_STAMP not set -> date/time will be null
    682         // 2) GPS_DATE_STAMP not set -> use EXIF date or set to default
    683         // 3) GPS_TIME_STAMP and GPS_DATE_STAMP are set
    684         int[] timeStampComps = dirGps.getIntArray(GpsDirectory.TAG_TIME_STAMP);
    685         if (timeStampComps != null) {
    686             int gpsHour = timeStampComps[0];
    687             int gpsMin = timeStampComps[1];
    688             int gpsSec = timeStampComps[2];
    689             Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
    690 
    691             // We have the time. Next step is to check if the GPS date stamp is set.
    692             // dirGps.getString() always succeeds, but the return value might be null.
    693             String dateStampStr = dirGps.getString(GpsDirectory.TAG_DATE_STAMP);
    694             if (dateStampStr != null && dateStampStr.matches("^\\d+:\\d+:\\d+$")) {
    695                 String[] dateStampComps = dateStampStr.split(":");
    696                 cal.set(Calendar.YEAR, Integer.parseInt(dateStampComps[0]));
    697                 cal.set(Calendar.MONTH, Integer.parseInt(dateStampComps[1]) - 1);
    698                 cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateStampComps[2]));
    699             } else {
    700                 // No GPS date stamp in EXIF data. Copy it from EXIF time.
    701                 // Date is not set if EXIF time is not available.
    702                 if (e.hasExifTime()) {
    703                     // Time not set yet, so we can copy everything, not just date.
    704                     cal.setTime(e.getExifTime());
    705                 }
    706             }
    707 
    708             cal.set(Calendar.HOUR_OF_DAY, gpsHour);
    709             cal.set(Calendar.MINUTE, gpsMin);
    710             cal.set(Calendar.SECOND, gpsSec);
    711 
    712             e.setExifGpsTime(cal.getTime());
    713         }
    714     }
    715 
    716572    public void showNextPhoto() {
    717573        if (data != null && !data.isEmpty()) {
    718574            currentPhoto++;
    public ImageEntry getPhotoUnderMouse(MouseEvent evt) {  
    861717                }
    862718                Point p = Main.map.mapView.getPoint(img.getPos());
    863719                Rectangle r;
    864                 if (useThumbs && img.thumbnail != null) {
    865                     Dimension d = scaledDimension(img.thumbnail);
     720                if (useThumbs && img.hasThumbnail()) {
     721                    Dimension d = scaledDimension(img.getThumbnail());
    866722                    r = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height);
    867723                } else {
    868724                    r = new Rectangle(p.x - icon.getIconWidth() / 2,
    public void mouseReleased(MouseEvent ev) {  
    971827                    }
    972828                    Point p = Main.map.mapView.getPoint(e.getPos());
    973829                    Rectangle r;
    974                     if (useThumbs && e.thumbnail != null) {
    975                         Dimension d = scaledDimension(e.thumbnail);
     830                    if (useThumbs && e.hasThumbnail()) {
     831                        Dimension d = scaledDimension(e.getThumbnail());
    976832                        r = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height);
    977833                    } else {
    978834                        r = new Rectangle(p.x - icon.getIconWidth() / 2,
  • src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java b/src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java
    index 29b4f22..2684288 100644
    a b  
    33
    44import java.awt.Image;
    55import java.io.File;
     6import java.io.IOException;
     7import java.text.ParseException;
     8import java.util.Calendar;
    69import java.util.Date;
     10import java.util.GregorianCalendar;
     11import java.util.TimeZone;
    712
     13import com.drew.imaging.jpeg.JpegMetadataReader;
     14import com.drew.lang.CompoundException;
     15import com.drew.metadata.Directory;
     16import com.drew.metadata.Metadata;
     17import com.drew.metadata.MetadataException;
     18import com.drew.metadata.exif.ExifIFD0Directory;
     19import com.drew.metadata.exif.GpsDirectory;
     20import org.openstreetmap.josm.Main;
     21import org.openstreetmap.josm.data.SystemOfMeasurement;
    822import org.openstreetmap.josm.data.coor.CachedLatLon;
    923import org.openstreetmap.josm.data.coor.LatLon;
     24import org.openstreetmap.josm.tools.ExifReader;
    1025
    1126/**
    1227 * Stores info about each image
     
    2540    private boolean isNewGpsData;
    2641    /** Temporary source of GPS time if not correlated with GPX track. */
    2742    private Date exifGpsTime;
    28     Image thumbnail;
     43    private Image thumbnail;
    2944
    3045    /**
    3146     * The following values are computed from the correlation with the gpx track
     
    4358     * When the correlation dialog is open, we like to show the image position
    4459     * for the current time offset on the map in real time.
    4560     * On the other hand, when the user aborts this operation, the old values
    46      * should be restored. We have a temprary copy, that overrides
     61     * should be restored. We have a temporary copy, that overrides
    4762     * the normal values if it is not null. (This may be not the most elegant
    4863     * solution for this, but it works.)
    4964     */
    5065    ImageEntry tmp;
    5166
    5267    /**
     68     * Constructs a new {@code ImageEntry}.
     69     */
     70    public ImageEntry() {}
     71
     72    /**
     73     * Constructs a new {@code ImageEntry}.
     74     * @param file Path to image file on disk
     75     */
     76    public ImageEntry(File file) {
     77        setFile(file);
     78    }
     79
     80    /**
    5381     * Returns the cached temporary position value.
    5482     * @return the cached temporary position value
    5583     */
    public boolean hasGpsTime() {  
    98126        return (tmp != null && tmp.gpsTime != null) || gpsTime != null;
    99127    }
    100128
     129    public Double getExifImgDir() {
     130        if (tmp != null)
     131            return tmp.exifImgDir;
     132        return exifImgDir;
     133    }
     134
    101135    /**
    102136     * Returns associated file.
    103137     * @return associated file
    public LatLon getExifCoor() {  
    159193        return exifCoor;
    160194    }
    161195
    162     public Double getExifImgDir() {
    163         return exifImgDir;
    164     }
    165 
    166196    public boolean hasThumbnail() {
    167197        return thumbnail != null;
    168198    }
    169199
     200    public Image getThumbnail() {
     201        return thumbnail;
     202    }
     203
     204    public void setThumbnail(Image thumbnail) {
     205        this.thumbnail = thumbnail;
     206    }
     207
    170208    /**
    171209     * Sets the position.
    172210     * @param pos cached position
    public void setPos(CachedLatLon pos) {  
    180218     * @param pos position (will be cached)
    181219     */
    182220    public void setPos(LatLon pos) {
    183         setPos(new CachedLatLon(pos));
     221        setPos(pos != null ? new CachedLatLon(pos) : null);
    184222    }
    185223
    186224    /**
    public void setExifCoor(LatLon exifCoor) {  
    240278        this.exifCoor = exifCoor;
    241279    }
    242280
    243     public void setExifImgDir(double exifDir) {
     281    public void setExifImgDir(Double exifDir) {
    244282        this.exifImgDir = exifDir;
    245283    }
    246284
    public void cleanTmp() {  
    277315    }
    278316
    279317    /**
    280      * Copy the values from the temporary variable to the main instance.
     318     * Get temporary variable that is used for real time parameter
     319     * adjustments. The temporary variable is created if it does not exist
     320     * yet. Use {@link #applyTmp()} or {@link #discardTmp()} if the temporary variable is not
     321     * needed anymore.
     322     */
     323    public ImageEntry getTmp() {
     324        if (tmp == null) {
     325            cleanTmp();
     326        }
     327        return tmp;
     328    }
     329
     330    /**
     331     * Copy the values from the temporary variable to the main instance. The
     332     * temporary variable is deleted.
     333     * @see #discardTmp()
    281334     */
    282335    public void applyTmp() {
    283336        if (tmp != null) {
    public void applyTmp() {  
    285338            speed = tmp.speed;
    286339            elevation = tmp.elevation;
    287340            gpsTime = tmp.gpsTime;
     341            exifImgDir = tmp.exifImgDir;
    288342            tmp = null;
    289343        }
    290344    }
    291345
    292346    /**
     347     * Delete the temporary variable. Temporary modifications are lost.
     348     * @see #applyTmp()
     349     */
     350    public void discardTmp() {
     351        tmp = null;
     352    }
     353
     354    /**
    293355     * If it has been tagged i.e. matched to a gpx track or retrieved lat/lon from exif
    294356     * @return {@code true} if it has been tagged
    295357     */
    public void unflagNewGpsData() {  
    335397    public boolean hasNewGpsData() {
    336398        return isNewGpsData;
    337399    }
     400
     401    /**
     402     * Extract GPS metadata from image EXIF. Has no effect if the image file is not set
     403     *
     404     * If successful, fills in the LatLon, speed, elevation, image direction, and other attributes
     405     */
     406    public void extractExif() {
     407
     408        Metadata metadata;
     409        Directory dirExif;
     410        GpsDirectory dirGps;
     411
     412        if (file == null) {
     413            return;
     414        }
     415
     416        try {
     417            metadata = JpegMetadataReader.readMetadata(file);
     418            dirExif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
     419            dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     420        } catch (CompoundException | IOException p) {
     421            setExifCoor(null);
     422            setPos(null);
     423            return;
     424        }
     425
     426        try {
     427            if (dirExif != null) {
     428                int orientation = dirExif.getInt(ExifIFD0Directory.TAG_ORIENTATION);
     429                setExifOrientation(orientation);
     430            }
     431        } catch (MetadataException ex) {
     432            Main.debug(ex.getMessage());
     433        }
     434
     435        if (dirGps == null) {
     436            setExifCoor(null);
     437            setPos(null);
     438            return;
     439        }
     440
     441        try {
     442            double speed = dirGps.getDouble(GpsDirectory.TAG_SPEED);
     443            String speedRef = dirGps.getString(GpsDirectory.TAG_SPEED_REF);
     444            if ("M".equalsIgnoreCase(speedRef)) {
     445                // miles per hour
     446                speed *= SystemOfMeasurement.IMPERIAL.bValue / 1000;
     447            } else if ("N".equalsIgnoreCase(speedRef)) {
     448                // knots == nautical miles per hour
     449                speed *= SystemOfMeasurement.NAUTICAL_MILE.bValue / 1000;
     450            }
     451            // default is K (km/h)
     452            setSpeed(speed);
     453        } catch (Exception ex) {
     454            Main.debug(ex.getMessage());
     455        }
     456
     457        try {
     458            double ele = dirGps.getDouble(GpsDirectory.TAG_ALTITUDE);
     459            int d = dirGps.getInt(GpsDirectory.TAG_ALTITUDE_REF);
     460            if (d == 1) {
     461                ele *= -1;
     462            }
     463            setElevation(ele);
     464        } catch (MetadataException ex) {
     465            Main.debug(ex.getMessage());
     466        }
     467
     468        try {
     469            LatLon latlon = ExifReader.readLatLon(dirGps);
     470            setExifCoor(latlon);
     471            setPos(getExifCoor());
     472
     473        } catch (Exception ex) { // (other exceptions, e.g. #5271)
     474            Main.error("Error reading EXIF from file: " + ex);
     475            setExifCoor(null);
     476            setPos(null);
     477        }
     478
     479        try {
     480            Double direction = ExifReader.readDirection(dirGps);
     481            if (direction != null) {
     482                setExifImgDir(direction);
     483            }
     484        } catch (Exception ex) { // (CompoundException and other exceptions, e.g. #5271)
     485            Main.debug(ex.getMessage());
     486        }
     487
     488        // Changed to silently cope with no time info in exif. One case
     489        // of person having time that couldn't be parsed, but valid GPS info
     490        try {
     491            setExifTime(ExifReader.readTime(file));
     492        } catch (ParseException ex) {
     493            setExifTime(null);
     494        }
     495
     496        // Time and date. We can have these cases:
     497        // 1) GPS_TIME_STAMP not set -> date/time will be null
     498        // 2) GPS_DATE_STAMP not set -> use EXIF date or set to default
     499        // 3) GPS_TIME_STAMP and GPS_DATE_STAMP are set
     500        int[] timeStampComps = dirGps.getIntArray(GpsDirectory.TAG_TIME_STAMP);
     501        if (timeStampComps != null) {
     502            int gpsHour = timeStampComps[0];
     503            int gpsMin = timeStampComps[1];
     504            int gpsSec = timeStampComps[2];
     505            Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
     506
     507            // We have the time. Next step is to check if the GPS date stamp is set.
     508            // dirGps.getString() always succeeds, but the return value might be null.
     509            String dateStampStr = dirGps.getString(GpsDirectory.TAG_DATE_STAMP);
     510            if (dateStampStr != null && dateStampStr.matches("^\\d+:\\d+:\\d+$")) {
     511                String[] dateStampComps = dateStampStr.split(":");
     512                cal.set(Calendar.YEAR, Integer.parseInt(dateStampComps[0]));
     513                cal.set(Calendar.MONTH, Integer.parseInt(dateStampComps[1]) - 1);
     514                cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateStampComps[2]));
     515            } else {
     516                // No GPS date stamp in EXIF data. Copy it from EXIF time.
     517                // Date is not set if EXIF time is not available.
     518                if (hasExifTime()) {
     519                    // Time not set yet, so we can copy everything, not just date.
     520                    cal.setTime(getExifTime());
     521                }
     522            }
     523
     524            cal.set(Calendar.HOUR_OF_DAY, gpsHour);
     525            cal.set(Calendar.MINUTE, gpsMin);
     526            cal.set(Calendar.SECOND, gpsSec);
     527
     528            setExifGpsTime(cal.getTime());
     529        }
     530    }
    338531}
  • src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java b/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java
    index 8ff6a51..6666eb2 100644
    a b public static ImageViewerDialog getInstance() {  
    6969    private JButton btnNext;
    7070    private JButton btnPrevious;
    7171    private JButton btnCollapse;
     72    private JToggleButton tbCentre;
    7273
    7374    private ImageViewerDialog() {
    7475        super(tr("Geotagged Images"), "geoimage", tr("Display geotagged images"), Shortcut.registerShortcut("tools:geotagged",
    protected void build() {  
    149150                        "geoimage:last", tr("Geoimage: {0}", tr("Show last Image")), KeyEvent.VK_END, Shortcut.DIRECT)
    150151        );
    151152
    152         JToggleButton tbCentre = new JToggleButton(new ImageAction(COMMAND_CENTERVIEW,
     153        tbCentre = new JToggleButton(new ImageAction(COMMAND_CENTERVIEW,
    153154                ImageProvider.get("dialogs", "centreview"), tr("Center view")));
    154155        tbCentre.setPreferredSize(buttonDim);
    155156
    public void actionPerformed(ActionEvent e) {  
    224225            } else if (COMMAND_LAST.equals(action) && currentLayer != null) {
    225226                currentLayer.showLastPhoto();
    226227            } else if (COMMAND_CENTERVIEW.equals(action)) {
    227                 centerView = ((JToggleButton) e.getSource()).isSelected();
     228                final JToggleButton button = (JToggleButton) e.getSource();
     229                centerView = button.isEnabled() && button.isSelected();
    228230                if (centerView && currentEntry != null && currentEntry.getPos() != null) {
    229231                    Main.map.mapView.zoomTo(currentEntry.getPos());
    230232                }
    public static void setNextEnabled(boolean value) {  
    275277        getInstance().btnNext.setEnabled(value);
    276278    }
    277279
     280    /**
     281     * Enables (or disables) the "Center view" button.
     282     * @param value {@code true} to enable the button, {@code false} otherwise
     283     * @return the old enabled value. Can be used to restore the original enable state
     284     */
     285    public static synchronized boolean setCentreEnabled(boolean value) {
     286        final ImageViewerDialog instance = getInstance();
     287        final boolean wasEnabled = instance.tbCentre.isEnabled();
     288        instance.tbCentre.setEnabled(value);
     289        instance.tbCentre.getAction().actionPerformed(new ActionEvent(instance.tbCentre, 0, null));
     290        return wasEnabled;
     291    }
     292
    278293    private transient GeoImageLayer currentLayer;
    279294    private transient ImageEntry currentEntry;
    280295
    public void displayImage(GeoImageLayer layer, ImageEntry entry) {  
    303318            setTitle(tr("Geotagged Images") + (entry.getFile() != null ? " - " + entry.getFile().getName() : ""));
    304319            StringBuilder osd = new StringBuilder(entry.getFile() != null ? entry.getFile().getName() : "");
    305320            if (entry.getElevation() != null) {
    306                 osd.append(tr("\nAltitude: {0} m", entry.getElevation().longValue()));
     321                osd.append(tr("\nAltitude: {0} m", Math.round(entry.getElevation())));
    307322            }
    308323            if (entry.getSpeed() != null) {
    309324                osd.append(tr("\nSpeed: {0} km/h", Math.round(entry.getSpeed())));
  • src/org/openstreetmap/josm/gui/layer/geoimage/ThumbsLoader.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/ThumbsLoader.java b/src/org/openstreetmap/josm/gui/layer/geoimage/ThumbsLoader.java
    index 9460d76..47706a3 100644
    a b public void run() {  
    5454            if (stop) return;
    5555
    5656            // Do not load thumbnails that were loaded before.
    57             if (entry.thumbnail == null) {
    58                 entry.thumbnail = loadThumb(entry);
     57            if (entry.hasThumbnail()) {
     58                entry.setThumbnail(loadThumb(entry));
    5959
    6060                if (Main.isDisplayingMapView()) {
    6161                    layer.updateOffscreenBuffer = true;