source: josm/trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java@ 15348

Last change on this file since 15348 was 15348, checked in by Don-vip, 5 years ago

fix #18119 - Deselect and remove multiple images in the ImageViewerDialog (patch by francois2)

  • Property svn:eol-style set to native
File size: 24.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.layer.geoimage;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.awt.BorderLayout;
8import java.awt.Component;
9import java.awt.Dimension;
10import java.awt.GridBagConstraints;
11import java.awt.GridBagLayout;
12import java.awt.event.ActionEvent;
13import java.awt.event.KeyEvent;
14import java.awt.event.WindowEvent;
15import java.text.DateFormat;
16import java.text.SimpleDateFormat;
17import java.util.Collections;
18import java.util.List;
19import java.util.Optional;
20
21import javax.swing.Box;
22import javax.swing.JButton;
23import javax.swing.JLabel;
24import javax.swing.JOptionPane;
25import javax.swing.JPanel;
26import javax.swing.JToggleButton;
27import javax.swing.SwingConstants;
28
29import org.openstreetmap.josm.actions.JosmAction;
30import org.openstreetmap.josm.data.ImageData;
31import org.openstreetmap.josm.data.ImageData.ImageDataUpdateListener;
32import org.openstreetmap.josm.gui.ExtendedDialog;
33import org.openstreetmap.josm.gui.MainApplication;
34import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
35import org.openstreetmap.josm.gui.dialogs.DialogsPanel.Action;
36import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
37import org.openstreetmap.josm.gui.layer.Layer;
38import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
39import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
40import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
41import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
42import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
43import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
44import org.openstreetmap.josm.tools.ImageProvider;
45import org.openstreetmap.josm.tools.Logging;
46import org.openstreetmap.josm.tools.Shortcut;
47import org.openstreetmap.josm.tools.Utils;
48import org.openstreetmap.josm.tools.date.DateUtils;
49
50/**
51 * Dialog to view and manipulate geo-tagged images from a {@link GeoImageLayer}.
52 */
53public final class ImageViewerDialog extends ToggleDialog implements LayerChangeListener, ActiveLayerChangeListener, ImageDataUpdateListener {
54
55 private final ImageZoomAction imageZoomAction = new ImageZoomAction();
56 private final ImageCenterViewAction imageCenterViewAction = new ImageCenterViewAction();
57 private final ImageNextAction imageNextAction = new ImageNextAction();
58 private final ImageRemoveAction imageRemoveAction = new ImageRemoveAction();
59 private final ImageRemoveFromDiskAction imageRemoveFromDiskAction = new ImageRemoveFromDiskAction();
60 private final ImagePreviousAction imagePreviousAction = new ImagePreviousAction();
61 private final ImageCollapseAction imageCollapseAction = new ImageCollapseAction();
62 private final ImageFirstAction imageFirstAction = new ImageFirstAction();
63 private final ImageLastAction imageLastAction = new ImageLastAction();
64 private final ImageCopyPathAction imageCopyPathAction = new ImageCopyPathAction();
65
66 private final ImageDisplay imgDisplay = new ImageDisplay();
67 private boolean centerView;
68
69 // Only one instance of that class is present at one time
70 private static volatile ImageViewerDialog dialog;
71
72 private boolean collapseButtonClicked;
73
74 static void createInstance() {
75 if (dialog != null)
76 throw new IllegalStateException("ImageViewerDialog instance was already created");
77 dialog = new ImageViewerDialog();
78 }
79
80 /**
81 * Replies the unique instance of this dialog
82 * @return the unique instance
83 */
84 public static ImageViewerDialog getInstance() {
85 if (dialog == null)
86 throw new AssertionError("a new instance needs to be created first");
87 return dialog;
88 }
89
90 private JButton btnLast;
91 private JButton btnNext;
92 private JButton btnPrevious;
93 private JButton btnFirst;
94 private JButton btnCollapse;
95 private JButton btnDelete;
96 private JButton btnCopyPath;
97 private JButton btnDeleteFromDisk;
98 private JToggleButton tbCentre;
99
100 private ImageViewerDialog() {
101 super(tr("Geotagged Images"), "geoimage", tr("Display geotagged images"), Shortcut.registerShortcut("tools:geotagged",
102 tr("Tool: {0}", tr("Display geotagged images")), KeyEvent.VK_Y, Shortcut.DIRECT), 200);
103 build();
104 MainApplication.getLayerManager().addActiveLayerChangeListener(this);
105 MainApplication.getLayerManager().addLayerChangeListener(this);
106 for (Layer l: MainApplication.getLayerManager().getLayers()) {
107 registerOnLayer(l);
108 }
109 }
110
111 private static JButton createNavigationButton(JosmAction action, Dimension buttonDim) {
112 JButton btn = new JButton(action);
113 btn.setPreferredSize(buttonDim);
114 btn.setEnabled(false);
115 return btn;
116 }
117
118 private void build() {
119 JPanel content = new JPanel(new BorderLayout());
120
121 content.add(imgDisplay, BorderLayout.CENTER);
122
123 Dimension buttonDim = new Dimension(26, 26);
124
125 btnFirst = createNavigationButton(imageFirstAction, buttonDim);
126 btnPrevious = createNavigationButton(imagePreviousAction, buttonDim);
127
128 btnDelete = new JButton(imageRemoveAction);
129 btnDelete.setPreferredSize(buttonDim);
130
131 btnDeleteFromDisk = new JButton(imageRemoveFromDiskAction);
132 btnDeleteFromDisk.setPreferredSize(buttonDim);
133
134 btnCopyPath = new JButton(imageCopyPathAction);
135 btnCopyPath.setPreferredSize(buttonDim);
136
137 btnNext = createNavigationButton(imageNextAction, buttonDim);
138 btnLast = createNavigationButton(imageLastAction, buttonDim);
139
140 tbCentre = new JToggleButton(imageCenterViewAction);
141 tbCentre.setPreferredSize(buttonDim);
142
143 JButton btnZoomBestFit = new JButton(imageZoomAction);
144 btnZoomBestFit.setPreferredSize(buttonDim);
145
146 btnCollapse = new JButton(imageCollapseAction);
147 btnCollapse.setPreferredSize(new Dimension(20, 20));
148 btnCollapse.setAlignmentY(Component.TOP_ALIGNMENT);
149
150 JPanel buttons = new JPanel();
151 buttons.add(btnFirst);
152 buttons.add(btnPrevious);
153 buttons.add(btnNext);
154 buttons.add(btnLast);
155 buttons.add(Box.createRigidArea(new Dimension(7, 0)));
156 buttons.add(tbCentre);
157 buttons.add(btnZoomBestFit);
158 buttons.add(Box.createRigidArea(new Dimension(7, 0)));
159 buttons.add(btnDelete);
160 buttons.add(btnDeleteFromDisk);
161 buttons.add(Box.createRigidArea(new Dimension(7, 0)));
162 buttons.add(btnCopyPath);
163
164 JPanel bottomPane = new JPanel(new GridBagLayout());
165 GridBagConstraints gc = new GridBagConstraints();
166 gc.gridx = 0;
167 gc.gridy = 0;
168 gc.anchor = GridBagConstraints.CENTER;
169 gc.weightx = 1;
170 bottomPane.add(buttons, gc);
171
172 gc.gridx = 1;
173 gc.gridy = 0;
174 gc.anchor = GridBagConstraints.PAGE_END;
175 gc.weightx = 0;
176 bottomPane.add(btnCollapse, gc);
177
178 content.add(bottomPane, BorderLayout.SOUTH);
179
180 createLayout(content, false, null);
181 }
182
183 @Override
184 public void destroy() {
185 MainApplication.getLayerManager().removeActiveLayerChangeListener(this);
186 MainApplication.getLayerManager().removeLayerChangeListener(this);
187 // Manually destroy actions until JButtons are replaced by standard SideButtons
188 imageFirstAction.destroy();
189 imageLastAction.destroy();
190 imagePreviousAction.destroy();
191 imageNextAction.destroy();
192 imageCenterViewAction.destroy();
193 imageCollapseAction.destroy();
194 imageCopyPathAction.destroy();
195 imageRemoveAction.destroy();
196 imageRemoveFromDiskAction.destroy();
197 imageZoomAction.destroy();
198 super.destroy();
199 dialog = null;
200 }
201
202 private class ImageNextAction extends JosmAction {
203 ImageNextAction() {
204 super(null, new ImageProvider("dialogs", "next"), tr("Next"), Shortcut.registerShortcut(
205 "geoimage:next", tr("Geoimage: {0}", tr("Show next Image")), KeyEvent.VK_PAGE_DOWN, Shortcut.DIRECT),
206 false, null, false);
207 }
208
209 @Override
210 public void actionPerformed(ActionEvent e) {
211 if (currentData != null) {
212 currentData.selectNextImage();
213 }
214 }
215 }
216
217 private class ImagePreviousAction extends JosmAction {
218 ImagePreviousAction() {
219 super(null, new ImageProvider("dialogs", "previous"), tr("Previous"), Shortcut.registerShortcut(
220 "geoimage:previous", tr("Geoimage: {0}", tr("Show previous Image")), KeyEvent.VK_PAGE_UP, Shortcut.DIRECT),
221 false, null, false);
222 }
223
224 @Override
225 public void actionPerformed(ActionEvent e) {
226 if (currentData != null) {
227 currentData.selectPreviousImage();
228 }
229 }
230 }
231
232 private class ImageFirstAction extends JosmAction {
233 ImageFirstAction() {
234 super(null, new ImageProvider("dialogs", "first"), tr("First"), Shortcut.registerShortcut(
235 "geoimage:first", tr("Geoimage: {0}", tr("Show first Image")), KeyEvent.VK_HOME, Shortcut.DIRECT),
236 false, null, false);
237 }
238
239 @Override
240 public void actionPerformed(ActionEvent e) {
241 if (currentData != null) {
242 currentData.selectFirstImage();
243 }
244 }
245 }
246
247 private class ImageLastAction extends JosmAction {
248 ImageLastAction() {
249 super(null, new ImageProvider("dialogs", "last"), tr("Last"), Shortcut.registerShortcut(
250 "geoimage:last", tr("Geoimage: {0}", tr("Show last Image")), KeyEvent.VK_END, Shortcut.DIRECT),
251 false, null, false);
252 }
253
254 @Override
255 public void actionPerformed(ActionEvent e) {
256 if (currentData != null) {
257 currentData.selectLastImage();
258 }
259 }
260 }
261
262 private class ImageCenterViewAction extends JosmAction {
263 ImageCenterViewAction() {
264 super(null, new ImageProvider("dialogs", "centreview"), tr("Center view"), null,
265 false, null, false);
266 }
267
268 @Override
269 public void actionPerformed(ActionEvent e) {
270 final JToggleButton button = (JToggleButton) e.getSource();
271 centerView = button.isEnabled() && button.isSelected();
272 if (centerView && currentEntry != null && currentEntry.getPos() != null) {
273 MainApplication.getMap().mapView.zoomTo(currentEntry.getPos());
274 }
275 }
276 }
277
278 private class ImageZoomAction extends JosmAction {
279 ImageZoomAction() {
280 super(null, new ImageProvider("dialogs", "zoom-best-fit"), tr("Zoom best fit and 1:1"), null,
281 false, null, false);
282 }
283
284 @Override
285 public void actionPerformed(ActionEvent e) {
286 imgDisplay.zoomBestFitOrOne();
287 }
288 }
289
290 private class ImageRemoveAction extends JosmAction {
291 ImageRemoveAction() {
292 super(null, new ImageProvider("dialogs", "delete"), tr("Remove photo(s) from layer"), Shortcut.registerShortcut(
293 "geoimage:deleteimagefromlayer", tr("Geoimage: {0}", tr("Remove photo(s) from layer")), KeyEvent.VK_DELETE, Shortcut.SHIFT),
294 false, null, false);
295 }
296
297 @Override
298 public void actionPerformed(ActionEvent e) {
299 if (currentData != null) {
300 currentData.removeSelectedImages();
301 }
302 }
303 }
304
305 private class ImageRemoveFromDiskAction extends JosmAction {
306 ImageRemoveFromDiskAction() {
307 super(null, new ImageProvider("dialogs", "geoimage/deletefromdisk"), tr("Delete photo file(s) from disk"),
308 Shortcut.registerShortcut(
309 "geoimage:deletefilefromdisk", tr("Geoimage: {0}", tr("Delete file(s) from disk")), KeyEvent.VK_DELETE, Shortcut.CTRL_SHIFT),
310 false, null, false);
311 }
312
313 @Override
314 public void actionPerformed(ActionEvent e) {
315 if (currentData != null && currentData.getSelectedImage() != null) {
316 List<ImageEntry> toDelete = currentData.getSelectedImages();
317 int size = toDelete.size();
318
319 int result = new ExtendedDialog(
320 MainApplication.getMainFrame(),
321 tr("Delete image file from disk"),
322 tr("Cancel"), tr("Delete"))
323 .setButtonIcons("cancel", "dialogs/delete")
324 .setContent(new JLabel("<html><h3>"
325 + trn("Delete the file from disk?",
326 "Delete the {0} files from disk?", size, size)
327 + "<p>" + trn("The image file will be permanently lost!",
328 "The images files will be permanently lost!", size) + "</h3></html>",
329 ImageProvider.get("dialogs/geoimage/deletefromdisk"), SwingConstants.LEFT))
330 .toggleEnable("geoimage.deleteimagefromdisk")
331 .setCancelButton(1)
332 .setDefaultButton(2)
333 .showDialog()
334 .getValue();
335
336 if (result == 2) {
337 currentData.removeSelectedImages();
338 for (ImageEntry delete : toDelete) {
339 if (Utils.deleteFile(delete.getFile())) {
340 Logging.info("File " + delete.getFile() + " deleted.");
341 } else {
342 JOptionPane.showMessageDialog(
343 MainApplication.getMainFrame(),
344 tr("Image file could not be deleted."),
345 tr("Error"),
346 JOptionPane.ERROR_MESSAGE
347 );
348 }
349 }
350 }
351 }
352 }
353 }
354
355 private class ImageCopyPathAction extends JosmAction {
356 ImageCopyPathAction() {
357 super(null, new ImageProvider("copy"), tr("Copy image path"), Shortcut.registerShortcut(
358 "geoimage:copypath", tr("Geoimage: {0}", tr("Copy image path")), KeyEvent.VK_C, Shortcut.ALT_CTRL_SHIFT),
359 false, null, false);
360 }
361
362 @Override
363 public void actionPerformed(ActionEvent e) {
364 if (currentData != null) {
365 ClipboardUtils.copyString(currentData.getSelectedImage().getFile().toString());
366 }
367 }
368 }
369
370 private class ImageCollapseAction extends JosmAction {
371 ImageCollapseAction() {
372 super(null, new ImageProvider("dialogs", "collapse"), tr("Move dialog to the side pane"), null,
373 false, null, false);
374 }
375
376 @Override
377 public void actionPerformed(ActionEvent e) {
378 collapseButtonClicked = true;
379 detachedDialog.getToolkit().getSystemEventQueue().postEvent(new WindowEvent(detachedDialog, WindowEvent.WINDOW_CLOSING));
380 }
381 }
382
383 /**
384 * Displays image for the given data.
385 * @param data geo image data
386 * @param entry image entry
387 * @deprecated Use {@link #displayImage}
388 */
389 @Deprecated
390 public static void showImage(ImageData data, ImageEntry entry) {
391 getInstance().displayImage(data, entry);
392 }
393
394 /**
395 * Enables (or disables) the "Previous" button.
396 * @param value {@code true} to enable the button, {@code false} otherwise
397 */
398 public void setPreviousEnabled(boolean value) {
399 btnFirst.setEnabled(value);
400 btnPrevious.setEnabled(value);
401 }
402
403 /**
404 * Enables (or disables) the "Next" button.
405 * @param value {@code true} to enable the button, {@code false} otherwise
406 */
407 public void setNextEnabled(boolean value) {
408 btnNext.setEnabled(value);
409 btnLast.setEnabled(value);
410 }
411
412 /**
413 * Enables (or disables) the "Center view" button.
414 * @param value {@code true} to enable the button, {@code false} otherwise
415 * @return the old enabled value. Can be used to restore the original enable state
416 */
417 public static synchronized boolean setCentreEnabled(boolean value) {
418 final ImageViewerDialog instance = getInstance();
419 final boolean wasEnabled = instance.tbCentre.isEnabled();
420 instance.tbCentre.setEnabled(value);
421 instance.tbCentre.getAction().actionPerformed(new ActionEvent(instance.tbCentre, 0, null));
422 return wasEnabled;
423 }
424
425 private transient ImageData currentData;
426 private transient ImageEntry currentEntry;
427
428 /**
429 * Displays a single image for the given layer.
430 * @param data the image data
431 * @param entry image entry
432 * @see #displayImages
433 */
434 public void displayImage(ImageData data, ImageEntry entry) {
435 displayImages(data, Collections.singletonList(entry));
436 }
437
438 /**
439 * Displays images for the given layer.
440 * @param data the image data
441 * @param entries image entries
442 * @since 15333
443 */
444 public void displayImages(ImageData data, List<ImageEntry> entries) {
445 boolean imageChanged;
446 ImageEntry entry = entries != null && entries.size() == 1 ? entries.get(0) : null;
447
448 synchronized (this) {
449 // TODO: pop up image dialog but don't load image again
450
451 imageChanged = currentEntry != entry;
452
453 if (centerView && entry != null && MainApplication.isDisplayingMapView() && entry.getPos() != null) {
454 MainApplication.getMap().mapView.zoomTo(entry.getPos());
455 }
456
457 currentData = data;
458 currentEntry = entry;
459 }
460
461 if (entry != null) {
462 setNextEnabled(data.hasNextImage());
463 setPreviousEnabled(data.hasPreviousImage());
464 btnDelete.setEnabled(true);
465 btnDeleteFromDisk.setEnabled(true);
466 btnCopyPath.setEnabled(true);
467
468 if (imageChanged) {
469 // Set only if the image is new to preserve zoom and position if the same image is redisplayed
470 // (e.g. to update the OSD).
471 imgDisplay.setImage(entry);
472 }
473 setTitle(tr("Geotagged Images") + (entry.getFile() != null ? " - " + entry.getFile().getName() : ""));
474 StringBuilder osd = new StringBuilder(entry.getFile() != null ? entry.getFile().getName() : "");
475 if (entry.getElevation() != null) {
476 osd.append(tr("\nAltitude: {0} m", Math.round(entry.getElevation())));
477 }
478 if (entry.getSpeed() != null) {
479 osd.append(tr("\nSpeed: {0} km/h", Math.round(entry.getSpeed())));
480 }
481 if (entry.getExifImgDir() != null) {
482 osd.append(tr("\nDirection {0}\u00b0", Math.round(entry.getExifImgDir())));
483 }
484 DateFormat dtf = DateUtils.getDateTimeFormat(DateFormat.SHORT, DateFormat.MEDIUM);
485 // Make sure date/time format includes milliseconds
486 if (dtf instanceof SimpleDateFormat) {
487 String pattern = ((SimpleDateFormat) dtf).toPattern();
488 if (!pattern.contains(".SSS")) {
489 dtf = new SimpleDateFormat(pattern.replace(":ss", ":ss.SSS"));
490 }
491 }
492 if (entry.hasExifTime()) {
493 osd.append(tr("\nEXIF time: {0}", dtf.format(entry.getExifTime())));
494 }
495 if (entry.hasGpsTime()) {
496 osd.append(tr("\nGPS time: {0}", dtf.format(entry.getGpsTime())));
497 }
498 Optional.ofNullable(entry.getIptcCaption()).map(s -> tr("\nCaption: {0}", s)).ifPresent(osd::append);
499 Optional.ofNullable(entry.getIptcHeadline()).map(s -> tr("\nHeadline: {0}", s)).ifPresent(osd::append);
500 Optional.ofNullable(entry.getIptcKeywords()).map(s -> tr("\nKeywords: {0}", s)).ifPresent(osd::append);
501 Optional.ofNullable(entry.getIptcObjectName()).map(s -> tr("\nObject name: {0}", s)).ifPresent(osd::append);
502
503 imgDisplay.setOsdText(osd.toString());
504 } else {
505 boolean hasMultipleImages = entries != null && entries.size() > 1;
506 // if this method is called to reinitialize dialog content with a blank image,
507 // do not actually show the dialog again with a blank image if currently hidden (fix #10672)
508 setTitle(tr("Geotagged Images"));
509 imgDisplay.setImage(null);
510 imgDisplay.setOsdText("");
511 setNextEnabled(false);
512 setPreviousEnabled(false);
513 btnDelete.setEnabled(hasMultipleImages);
514 btnDeleteFromDisk.setEnabled(hasMultipleImages);
515 btnCopyPath.setEnabled(false);
516 if (hasMultipleImages) {
517 imgDisplay.setEmptyText(tr("Multiple images selected"));
518 btnFirst.setEnabled(!isFirstImageSelected(data));
519 btnLast.setEnabled(!isLastImageSelected(data));
520 }
521 imgDisplay.setImage(null);
522 imgDisplay.setOsdText("");
523 return;
524 }
525 if (!isDialogShowing()) {
526 setIsDocked(false); // always open a detached window when an image is clicked and dialog is closed
527 showDialog();
528 } else {
529 if (isDocked && isCollapsed) {
530 expand();
531 dialogsPanel.reconstruct(Action.COLLAPSED_TO_DEFAULT, this);
532 }
533 }
534 }
535
536 private static boolean isLastImageSelected(ImageData data) {
537 return data.isImageSelected(data.getImages().get(data.getImages().size() - 1));
538 }
539
540 private static boolean isFirstImageSelected(ImageData data) {
541 return data.isImageSelected(data.getImages().get(0));
542 }
543
544 /**
545 * When an image is closed, really close it and do not pop
546 * up the side dialog.
547 */
548 @Override
549 protected boolean dockWhenClosingDetachedDlg() {
550 if (collapseButtonClicked) {
551 collapseButtonClicked = false;
552 return super.dockWhenClosingDetachedDlg();
553 }
554 return false;
555 }
556
557 @Override
558 protected void stateChanged() {
559 super.stateChanged();
560 if (btnCollapse != null) {
561 btnCollapse.setVisible(!isDocked);
562 }
563 }
564
565 /**
566 * Returns whether an image is currently displayed
567 * @return If image is currently displayed
568 */
569 public boolean hasImage() {
570 return currentEntry != null;
571 }
572
573 /**
574 * Returns the currently displayed image.
575 * @return Currently displayed image or {@code null}
576 * @since 6392
577 */
578 public static ImageEntry getCurrentImage() {
579 return getInstance().currentEntry;
580 }
581
582 /**
583 * Returns whether the center view is currently active.
584 * @return {@code true} if the center view is active, {@code false} otherwise
585 * @since 9416
586 */
587 public static boolean isCenterView() {
588 return getInstance().centerView;
589 }
590
591 @Override
592 public void layerAdded(LayerAddEvent e) {
593 registerOnLayer(e.getAddedLayer());
594 showLayer(e.getAddedLayer());
595 }
596
597 @Override
598 public void layerRemoving(LayerRemoveEvent e) {
599 if (e.getRemovedLayer() instanceof GeoImageLayer) {
600 ImageData removedData = ((GeoImageLayer) e.getRemovedLayer()).getImageData();
601 if (removedData == currentData) {
602 displayImages(null, null);
603 }
604 removedData.removeImageDataUpdateListener(this);
605 }
606 }
607
608 @Override
609 public void layerOrderChanged(LayerOrderChangeEvent e) {
610 // ignored
611 }
612
613 @Override
614 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
615 showLayer(e.getSource().getActiveLayer());
616 }
617
618 private void registerOnLayer(Layer layer) {
619 if (layer instanceof GeoImageLayer) {
620 ((GeoImageLayer) layer).getImageData().addImageDataUpdateListener(this);
621 }
622 }
623
624 private void showLayer(Layer newLayer) {
625 if (currentData == null && newLayer instanceof GeoImageLayer) {
626 ((GeoImageLayer) newLayer).getImageData().selectFirstImage();
627 }
628 }
629
630 @Override
631 public void selectedImageChanged(ImageData data) {
632 displayImages(data, data.getSelectedImages());
633 }
634
635 @Override
636 public void imageDataUpdated(ImageData data) {
637 displayImages(data, data.getSelectedImages());
638 }
639}
Note: See TracBrowser for help on using the repository browser.