Ticket #12255: 12255-v4.patch
File 12255-v4.patch, 28.7 KB (added by , 8 years ago) |
---|
-
src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java
156 156 if (yLayer != null) { 157 157 if (yLayer.data != null) { 158 158 for (ImageEntry ie : yLayer.data) { 159 ie. tmp = null;159 ie.discardTmp(); 160 160 } 161 161 } 162 162 yLayer.updateBufferAndRepaint(); … … 825 825 // So reset all images. 826 826 if (yLayer.data != null) { 827 827 for (ImageEntry ie: yLayer.data) { 828 ie. tmp = null;828 ie.discardTmp(); 829 829 } 830 830 } 831 831 … … 833 833 List<ImageEntry> dateImgLst = getSortedImgList(); 834 834 // Create a temporary copy for each image 835 835 for (ImageEntry ie : dateImgLst) { 836 ie.cleanTmp(); 836 ie.createTmp(); 837 ie.tmp.setPos(null); 837 838 } 838 839 839 840 GpxDataWrapper selGpx = selectedGPX(false); -
src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
21 21 import java.beans.PropertyChangeListener; 22 22 import java.io.File; 23 23 import java.io.IOException; 24 import java.text.ParseException;25 24 import java.util.ArrayList; 26 25 import java.util.Arrays; 27 import java.util.Calendar;28 26 import java.util.Collection; 29 27 import java.util.Collections; 30 import java.util.GregorianCalendar;31 28 import java.util.HashSet; 32 29 import java.util.LinkedHashSet; 33 30 import java.util.LinkedList; 34 31 import java.util.List; 35 32 import java.util.Set; 36 import java.util.TimeZone;37 33 import java.util.concurrent.ExecutorService; 38 34 import java.util.concurrent.Executors; 39 35 … … 49 45 import org.openstreetmap.josm.actions.mapmode.MapMode; 50 46 import org.openstreetmap.josm.actions.mapmode.SelectAction; 51 47 import org.openstreetmap.josm.data.Bounds; 52 import org.openstreetmap.josm.data.coor.LatLon;53 48 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; 54 49 import org.openstreetmap.josm.gui.ExtendedDialog; 55 50 import org.openstreetmap.josm.gui.MapFrame; … … 67 62 import org.openstreetmap.josm.gui.layer.Layer; 68 63 import org.openstreetmap.josm.gui.util.GuiHelper; 69 64 import org.openstreetmap.josm.io.JpgImporter; 70 import org.openstreetmap.josm.tools.ExifReader;71 65 import org.openstreetmap.josm.tools.ImageProvider; 72 66 import org.openstreetmap.josm.tools.Utils; 73 67 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 82 68 /** 83 69 * Layer displaying geottaged pictures. 84 70 */ … … 157 143 progressMonitor.subTask(tr("Reading {0}...", f.getName())); 158 144 progressMonitor.worked(1); 159 145 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(); 172 148 data.add(e); 173 149 } 174 150 layer = new GeoImageLayer(data, gpxLayer); … … 498 474 continue; 499 475 } 500 476 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()); 503 479 Rectangle target = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height); 504 480 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); 506 482 } 507 483 } else { // thumbnail not loaded yet 508 484 icon.paintIcon(mv, tempG, … … 534 510 535 511 int imgWidth = 100; 536 512 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()); 539 515 imgWidth = d.width; 540 516 imgHeight = d.height; 541 517 } else { … … 573 549 g.drawPolyline(xar, yar, 3); 574 550 } 575 551 576 if (useThumbs && e. thumbnail != null) {552 if (useThumbs && e.hasThumbnail()) { 577 553 g.setColor(new Color(128, 0, 0, 122)); 578 554 g.fillRect(p.x - imgWidth / 2, p.y - imgHeight / 2, imgWidth, imgHeight); 579 555 } else { … … 593 569 } 594 570 } 595 571 596 /**597 * Extract GPS metadata from image EXIF598 *599 * If successful, fills in the LatLon and EastNorth attributes of passed in image600 * @param e image entry601 */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 hour638 speed *= 1.609344;639 } else if ("N".equalsIgnoreCase(speedRef)) {640 // knots == nautical miles per hour641 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 null682 // 2) GPS_DATE_STAMP not set -> use EXIF date or set to default683 // 3) GPS_TIME_STAMP and GPS_DATE_STAMP are set684 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 716 572 public void showNextPhoto() { 717 573 if (data != null && !data.isEmpty()) { 718 574 currentPhoto++; … … 861 717 } 862 718 Point p = Main.map.mapView.getPoint(img.getPos()); 863 719 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()); 866 722 r = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height); 867 723 } else { 868 724 r = new Rectangle(p.x - icon.getIconWidth() / 2, … … 971 827 } 972 828 Point p = Main.map.mapView.getPoint(e.getPos()); 973 829 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()); 976 832 r = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height); 977 833 } else { 978 834 r = new Rectangle(p.x - icon.getIconWidth() / 2, -
src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java
3 3 4 4 import java.awt.Image; 5 5 import java.io.File; 6 import java.io.IOException; 7 import java.text.ParseException; 8 import java.util.Calendar; 6 9 import java.util.Date; 10 import java.util.GregorianCalendar; 11 import java.util.TimeZone; 7 12 13 import com.drew.imaging.jpeg.JpegMetadataReader; 14 import com.drew.lang.CompoundException; 15 import com.drew.metadata.Directory; 16 import com.drew.metadata.Metadata; 17 import com.drew.metadata.MetadataException; 18 import com.drew.metadata.exif.ExifIFD0Directory; 19 import com.drew.metadata.exif.GpsDirectory; 20 import org.openstreetmap.josm.Main; 21 import org.openstreetmap.josm.data.SystemOfMeasurement; 8 22 import org.openstreetmap.josm.data.coor.CachedLatLon; 9 23 import org.openstreetmap.josm.data.coor.LatLon; 24 import org.openstreetmap.josm.tools.ExifReader; 10 25 11 26 /** 12 27 * Stores info about each image … … 25 40 private boolean isNewGpsData; 26 41 /** Temporary source of GPS time if not correlated with GPX track. */ 27 42 private Date exifGpsTime; 28 Image thumbnail;43 private Image thumbnail; 29 44 30 45 /** 31 46 * The following values are computed from the correlation with the gpx track … … 43 58 * When the correlation dialog is open, we like to show the image position 44 59 * for the current time offset on the map in real time. 45 60 * On the other hand, when the user aborts this operation, the old values 46 * should be restored. We have a temp rary copy, that overrides61 * should be restored. We have a temporary copy, that overrides 47 62 * the normal values if it is not null. (This may be not the most elegant 48 63 * solution for this, but it works.) 49 64 */ … … 50 65 ImageEntry tmp; 51 66 52 67 /** 53 * Returns the cached temporary position value. 54 * @return the cached temporary position value 68 * Constructs a new {@code ImageEntry}. 55 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 /** 81 * Returns the position value. The position value from the temporary copy 82 * is returned if that copy exists. 83 * @return the position value 84 */ 56 85 public CachedLatLon getPos() { 57 86 if (tmp != null) 58 87 return tmp.pos; … … 60 89 } 61 90 62 91 /** 63 * Returns the cached temporary speed value. 64 * @return the cached temporary speed value 92 * Returns the speed value. The speed value from the temporary copy is 93 * returned if that copy exists. 94 * @return the speed value 65 95 */ 66 96 public Double getSpeed() { 67 97 if (tmp != null) … … 70 100 } 71 101 72 102 /** 73 * Returns the cached temporary elevation value. 74 * @return the cached temporary elevation value 103 * Returns the elevation value. The elevation value from the temporary 104 * copy is returned if that copy exists. 105 * @return the elevation value 75 106 */ 76 107 public Double getElevation() { 77 108 if (tmp != null) … … 80 111 } 81 112 82 113 /** 83 * Returns the cached temporary GPS time value. 84 * @return the cached temporary GPS time value 114 * Returns the GPS time value. The GPS time value from the temporary copy 115 * is returned if that copy exists. 116 * @return the GPS time value 85 117 */ 86 118 public Date getGpsTime() { 87 119 if (tmp != null) … … 98 130 return (tmp != null && tmp.gpsTime != null) || gpsTime != null; 99 131 } 100 132 133 public Double getExifImgDir() { 134 if (tmp != null) 135 return tmp.exifImgDir; 136 return exifImgDir; 137 } 138 101 139 /** 102 140 * Returns associated file. 103 141 * @return associated file … … 159 197 return exifCoor; 160 198 } 161 199 162 public Double getExifImgDir() {163 return exifImgDir;164 }165 166 200 public boolean hasThumbnail() { 167 201 return thumbnail != null; 168 202 } 169 203 204 public Image getThumbnail() { 205 return thumbnail; 206 } 207 170 208 /** 209 * Sets the thumbnail. 210 * @param thumbnail thumbnail 211 */ 212 public void setThumbnail(Image thumbnail) { 213 this.thumbnail = thumbnail; 214 } 215 216 /** 217 * Loads the thumbnail if it was not loaded yet. 218 */ 219 public void loadThumbnail() { 220 if (thumbnail == null) { 221 ThumbsLoader thumbsloader = new ThumbsLoader(this); 222 thumbsloader.run(); 223 } 224 } 225 226 /** 171 227 * Sets the position. 172 228 * @param pos cached position 173 229 */ … … 180 236 * @param pos position (will be cached) 181 237 */ 182 238 public void setPos(LatLon pos) { 183 setPos( new CachedLatLon(pos));239 setPos(pos != null ? new CachedLatLon(pos) : null); 184 240 } 185 241 186 242 /** … … 240 296 this.exifCoor = exifCoor; 241 297 } 242 298 243 public void setExifImgDir( double exifDir) {299 public void setExifImgDir(Double exifDir) { 244 300 this.exifImgDir = exifDir; 245 301 } 246 302 … … 268 324 } 269 325 270 326 /** 271 * Make a fresh copy and save it in the temporary variable. 327 * Make a fresh copy and save it in the temporary variable. Use 328 * {@link #applyTmp()} or {@link #discardTmp()} if the temporary variable 329 * is not needed anymore. 272 330 */ 273 public void c leanTmp() {331 public void createTmp() { 274 332 tmp = clone(); 275 tmp.setPos(null);276 333 tmp.tmp = null; 277 334 } 278 335 279 336 /** 280 * Copy the values from the temporary variable to the main instance. 337 * Get temporary variable that is used for real time parameter 338 * adjustments. The temporary variable is created if it does not exist 339 * yet. Use {@link #applyTmp()} or {@link #discardTmp()} if the temporary 340 * variable is not needed anymore. 341 * @return temporary variable 281 342 */ 343 public ImageEntry getTmp() { 344 if (tmp == null) { 345 createTmp(); 346 } 347 return tmp; 348 } 349 350 /** 351 * Copy the values from the temporary variable to the main instance. The 352 * temporary variable is deleted. 353 * @see #discardTmp() 354 */ 282 355 public void applyTmp() { 283 356 if (tmp != null) { 284 357 pos = tmp.pos; … … 285 358 speed = tmp.speed; 286 359 elevation = tmp.elevation; 287 360 gpsTime = tmp.gpsTime; 361 exifImgDir = tmp.exifImgDir; 288 362 tmp = null; 289 363 } 290 364 } 291 365 292 366 /** 367 * Delete the temporary variable. Temporary modifications are lost. 368 * @see #applyTmp() 369 */ 370 public void discardTmp() { 371 tmp = null; 372 } 373 374 /** 293 375 * If it has been tagged i.e. matched to a gpx track or retrieved lat/lon from exif 294 376 * @return {@code true} if it has been tagged 295 377 */ … … 335 417 public boolean hasNewGpsData() { 336 418 return isNewGpsData; 337 419 } 420 421 /** 422 * Extract GPS metadata from image EXIF. Has no effect if the image file is not set 423 * 424 * If successful, fills in the LatLon, speed, elevation, image direction, and other attributes 425 */ 426 public void extractExif() { 427 428 Metadata metadata; 429 Directory dirExif; 430 GpsDirectory dirGps; 431 432 if (file == null) { 433 return; 434 } 435 436 try { 437 metadata = JpegMetadataReader.readMetadata(file); 438 dirExif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); 439 dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class); 440 } catch (CompoundException | IOException p) { 441 setExifCoor(null); 442 setPos(null); 443 return; 444 } 445 446 try { 447 if (dirExif != null) { 448 int orientation = dirExif.getInt(ExifIFD0Directory.TAG_ORIENTATION); 449 setExifOrientation(orientation); 450 } 451 } catch (MetadataException ex) { 452 Main.debug(ex.getMessage()); 453 } 454 455 if (dirGps == null) { 456 setExifCoor(null); 457 setPos(null); 458 return; 459 } 460 461 try { 462 double speed = dirGps.getDouble(GpsDirectory.TAG_SPEED); 463 String speedRef = dirGps.getString(GpsDirectory.TAG_SPEED_REF); 464 if ("M".equalsIgnoreCase(speedRef)) { 465 // miles per hour 466 speed *= SystemOfMeasurement.IMPERIAL.bValue / 1000; 467 } else if ("N".equalsIgnoreCase(speedRef)) { 468 // knots == nautical miles per hour 469 speed *= SystemOfMeasurement.NAUTICAL_MILE.bValue / 1000; 470 } 471 // default is K (km/h) 472 setSpeed(speed); 473 } catch (Exception ex) { 474 Main.debug(ex.getMessage()); 475 } 476 477 try { 478 double ele = dirGps.getDouble(GpsDirectory.TAG_ALTITUDE); 479 int d = dirGps.getInt(GpsDirectory.TAG_ALTITUDE_REF); 480 if (d == 1) { 481 ele *= -1; 482 } 483 setElevation(ele); 484 } catch (MetadataException ex) { 485 Main.debug(ex.getMessage()); 486 } 487 488 try { 489 LatLon latlon = ExifReader.readLatLon(dirGps); 490 setExifCoor(latlon); 491 setPos(getExifCoor()); 492 493 } catch (Exception ex) { // (other exceptions, e.g. #5271) 494 Main.error("Error reading EXIF from file: " + ex); 495 setExifCoor(null); 496 setPos(null); 497 } 498 499 try { 500 Double direction = ExifReader.readDirection(dirGps); 501 if (direction != null) { 502 setExifImgDir(direction); 503 } 504 } catch (Exception ex) { // (CompoundException and other exceptions, e.g. #5271) 505 Main.debug(ex.getMessage()); 506 } 507 508 // Changed to silently cope with no time info in exif. One case 509 // of person having time that couldn't be parsed, but valid GPS info 510 try { 511 setExifTime(ExifReader.readTime(file)); 512 } catch (ParseException ex) { 513 setExifTime(null); 514 } 515 516 // Time and date. We can have these cases: 517 // 1) GPS_TIME_STAMP not set -> date/time will be null 518 // 2) GPS_DATE_STAMP not set -> use EXIF date or set to default 519 // 3) GPS_TIME_STAMP and GPS_DATE_STAMP are set 520 int[] timeStampComps = dirGps.getIntArray(GpsDirectory.TAG_TIME_STAMP); 521 if (timeStampComps != null) { 522 int gpsHour = timeStampComps[0]; 523 int gpsMin = timeStampComps[1]; 524 int gpsSec = timeStampComps[2]; 525 Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); 526 527 // We have the time. Next step is to check if the GPS date stamp is set. 528 // dirGps.getString() always succeeds, but the return value might be null. 529 String dateStampStr = dirGps.getString(GpsDirectory.TAG_DATE_STAMP); 530 if (dateStampStr != null && dateStampStr.matches("^\\d+:\\d+:\\d+$")) { 531 String[] dateStampComps = dateStampStr.split(":"); 532 cal.set(Calendar.YEAR, Integer.parseInt(dateStampComps[0])); 533 cal.set(Calendar.MONTH, Integer.parseInt(dateStampComps[1]) - 1); 534 cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateStampComps[2])); 535 } else { 536 // No GPS date stamp in EXIF data. Copy it from EXIF time. 537 // Date is not set if EXIF time is not available. 538 if (hasExifTime()) { 539 // Time not set yet, so we can copy everything, not just date. 540 cal.setTime(getExifTime()); 541 } 542 } 543 544 cal.set(Calendar.HOUR_OF_DAY, gpsHour); 545 cal.set(Calendar.MINUTE, gpsMin); 546 cal.set(Calendar.SECOND, gpsSec); 547 548 setExifGpsTime(cal.getTime()); 549 } 550 } 338 551 } -
src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java
69 69 private JButton btnNext; 70 70 private JButton btnPrevious; 71 71 private JButton btnCollapse; 72 private JToggleButton tbCentre; 72 73 73 74 private ImageViewerDialog() { 74 75 super(tr("Geotagged Images"), "geoimage", tr("Display geotagged images"), Shortcut.registerShortcut("tools:geotagged", … … 149 150 "geoimage:last", tr("Geoimage: {0}", tr("Show last Image")), KeyEvent.VK_END, Shortcut.DIRECT) 150 151 ); 151 152 152 JToggleButtontbCentre = new JToggleButton(new ImageAction(COMMAND_CENTERVIEW,153 tbCentre = new JToggleButton(new ImageAction(COMMAND_CENTERVIEW, 153 154 ImageProvider.get("dialogs", "centreview"), tr("Center view"))); 154 155 tbCentre.setPreferredSize(buttonDim); 155 156 … … 224 225 } else if (COMMAND_LAST.equals(action) && currentLayer != null) { 225 226 currentLayer.showLastPhoto(); 226 227 } 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(); 228 230 if (centerView && currentEntry != null && currentEntry.getPos() != null) { 229 231 Main.map.mapView.zoomTo(currentEntry.getPos()); 230 232 } … … 275 277 getInstance().btnNext.setEnabled(value); 276 278 } 277 279 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 278 293 private transient GeoImageLayer currentLayer; 279 294 private transient ImageEntry currentEntry; 280 295 … … 303 318 setTitle(tr("Geotagged Images") + (entry.getFile() != null ? " - " + entry.getFile().getName() : "")); 304 319 StringBuilder osd = new StringBuilder(entry.getFile() != null ? entry.getFile().getName() : ""); 305 320 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()))); 307 322 } 308 323 if (entry.getSpeed() != null) { 309 324 osd.append(tr("\nSpeed: {0} km/h", Math.round(entry.getSpeed()))); -
src/org/openstreetmap/josm/gui/layer/geoimage/ThumbsLoader.java
32 32 private ICacheAccess<String, BufferedImageCacheEntry> cache; 33 33 private final boolean cacheOff = Main.pref.getBoolean("geoimage.noThumbnailCache", false); 34 34 35 /** 36 * Constructs a new thumbnail loader that operates on a geoimage layer. 37 * @param layer geoimage layer 38 */ 35 39 public ThumbsLoader(GeoImageLayer layer) { 36 40 this.layer = layer; 37 41 this.data = new ArrayList<>(layer.data); 42 initCache(); 43 } 44 45 /** 46 * Constructs a new thumbnail loader that operates on a single image entry. 47 * @param entry image entry 48 */ 49 public ThumbsLoader(ImageEntry entry) { 50 layer = null; 51 data = new ArrayList<>(1); 52 data.add(entry); 53 initCache(); 54 } 55 56 /** 57 * Initialize the thumbnail cache. 58 */ 59 private void initCache() { 38 60 if (!cacheOff) { 39 61 try { 40 62 cache = JCSCacheManager.getCache("geoimage-thumbnails", 0, 120, … … 54 76 if (stop) return; 55 77 56 78 // Do not load thumbnails that were loaded before. 57 if ( entry.thumbnail == null) {58 entry. thumbnail = loadThumb(entry);79 if (!entry.hasThumbnail()) { 80 entry.setThumbnail(loadThumb(entry)); 59 81 60 if ( Main.isDisplayingMapView()) {82 if (layer != null && Main.isDisplayingMapView()) { 61 83 layer.updateOffscreenBuffer = true; 62 84 Main.map.mapView.repaint(); 63 85 } 64 86 } 65 87 } 66 layer.thumbsLoaded(); 67 layer.updateOffscreenBuffer = true; 68 Main.map.mapView.repaint(); 88 if (layer != null) { 89 layer.thumbsLoaded(); 90 layer.updateOffscreenBuffer = true; 91 Main.map.mapView.repaint(); 92 } 69 93 } 70 94 71 95 private BufferedImage loadThumb(ImageEntry entry) {