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

Last change on this file since 17188 was 17188, checked in by Klumbumbus, 4 years ago

fix #19851 - Fix shortcut names

  • 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("Windows: {0}", tr("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/autoscale", "selection"), 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 from layer"), Shortcut.registerShortcut(
293 "geoimage:deleteimagefromlayer", tr("Geoimage: {0}", tr("Remove photo 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 image file from disk"),
308 Shortcut.registerShortcut("geoimage:deletefilefromdisk",
309 tr("Geoimage: {0}", tr("Delete image file 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/geoimage/deletefromdisk")
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 * Enables (or disables) the "Previous" button.
385 * @param value {@code true} to enable the button, {@code false} otherwise
386 */
387 public void setPreviousEnabled(boolean value) {
388 btnFirst.setEnabled(value);
389 btnPrevious.setEnabled(value);
390 }
391
392 /**
393 * Enables (or disables) the "Next" button.
394 * @param value {@code true} to enable the button, {@code false} otherwise
395 */
396 public void setNextEnabled(boolean value) {
397 btnNext.setEnabled(value);
398 btnLast.setEnabled(value);
399 }
400
401 /**
402 * Enables (or disables) the "Center view" button.
403 * @param value {@code true} to enable the button, {@code false} otherwise
404 * @return the old enabled value. Can be used to restore the original enable state
405 */
406 public static synchronized boolean setCentreEnabled(boolean value) {
407 final ImageViewerDialog instance = getInstance();
408 final boolean wasEnabled = instance.tbCentre.isEnabled();
409 instance.tbCentre.setEnabled(value);
410 instance.tbCentre.getAction().actionPerformed(new ActionEvent(instance.tbCentre, 0, null));
411 return wasEnabled;
412 }
413
414 private transient ImageData currentData;
415 private transient ImageEntry currentEntry;
416
417 /**
418 * Displays a single image for the given layer.
419 * @param data the image data
420 * @param entry image entry
421 * @see #displayImages
422 */
423 public void displayImage(ImageData data, ImageEntry entry) {
424 displayImages(data, Collections.singletonList(entry));
425 }
426
427 /**
428 * Displays images for the given layer.
429 * @param data the image data
430 * @param entries image entries
431 * @since 15333
432 */
433 public void displayImages(ImageData data, List<ImageEntry> entries) {
434 boolean imageChanged;
435 ImageEntry entry = entries != null && entries.size() == 1 ? entries.get(0) : null;
436
437 synchronized (this) {
438 // TODO: pop up image dialog but don't load image again
439
440 imageChanged = currentEntry != entry;
441
442 if (centerView && entry != null && MainApplication.isDisplayingMapView() && entry.getPos() != null) {
443 MainApplication.getMap().mapView.zoomTo(entry.getPos());
444 }
445
446 currentData = data;
447 currentEntry = entry;
448 }
449
450 if (entry != null) {
451 setNextEnabled(data.hasNextImage());
452 setPreviousEnabled(data.hasPreviousImage());
453 btnDelete.setEnabled(true);
454 btnDeleteFromDisk.setEnabled(true);
455 btnCopyPath.setEnabled(true);
456
457 if (imageChanged) {
458 // Set only if the image is new to preserve zoom and position if the same image is redisplayed
459 // (e.g. to update the OSD).
460 imgDisplay.setImage(entry);
461 }
462 setTitle(tr("Geotagged Images") + (entry.getFile() != null ? " - " + entry.getFile().getName() : ""));
463 StringBuilder osd = new StringBuilder(entry.getFile() != null ? entry.getFile().getName() : "");
464 if (entry.getElevation() != null) {
465 osd.append(tr("\nAltitude: {0} m", Math.round(entry.getElevation())));
466 }
467 if (entry.getSpeed() != null) {
468 osd.append(tr("\nSpeed: {0} km/h", Math.round(entry.getSpeed())));
469 }
470 if (entry.getExifImgDir() != null) {
471 osd.append(tr("\nDirection {0}\u00b0", Math.round(entry.getExifImgDir())));
472 }
473
474 DateFormat dtf = DateUtils.getDateTimeFormat(DateFormat.SHORT, DateFormat.MEDIUM);
475 // Make sure date/time format includes milliseconds
476 if (dtf instanceof SimpleDateFormat) {
477 String pattern = ((SimpleDateFormat) dtf).toPattern();
478 if (!pattern.contains(".SSS")) {
479 dtf = new SimpleDateFormat(pattern.replace(":ss", ":ss.SSS"));
480 }
481 }
482 // Set timezone to UTC since UTC is assumed when parsing the EXIF timestamp,
483 // see see org.openstreetmap.josm.tools.ExifReader.readTime(com.drew.metadata.Metadata)
484 dtf.setTimeZone(DateUtils.UTC);
485
486 if (entry.hasExifTime()) {
487 osd.append(tr("\nEXIF time: {0}", dtf.format(entry.getExifTime())));
488 }
489 if (entry.hasGpsTime()) {
490 osd.append(tr("\nGPS time: {0}", dtf.format(entry.getGpsTime())));
491 }
492 Optional.ofNullable(entry.getIptcCaption()).map(s -> tr("\nCaption: {0}", s)).ifPresent(osd::append);
493 Optional.ofNullable(entry.getIptcHeadline()).map(s -> tr("\nHeadline: {0}", s)).ifPresent(osd::append);
494 Optional.ofNullable(entry.getIptcKeywords()).map(s -> tr("\nKeywords: {0}", s)).ifPresent(osd::append);
495 Optional.ofNullable(entry.getIptcObjectName()).map(s -> tr("\nObject name: {0}", s)).ifPresent(osd::append);
496
497 imgDisplay.setOsdText(osd.toString());
498 } else {
499 boolean hasMultipleImages = entries != null && entries.size() > 1;
500 // if this method is called to reinitialize dialog content with a blank image,
501 // do not actually show the dialog again with a blank image if currently hidden (fix #10672)
502 setTitle(tr("Geotagged Images"));
503 imgDisplay.setImage(null);
504 imgDisplay.setOsdText("");
505 setNextEnabled(false);
506 setPreviousEnabled(false);
507 btnDelete.setEnabled(hasMultipleImages);
508 btnDeleteFromDisk.setEnabled(hasMultipleImages);
509 btnCopyPath.setEnabled(false);
510 if (hasMultipleImages) {
511 imgDisplay.setEmptyText(tr("Multiple images selected"));
512 btnFirst.setEnabled(!isFirstImageSelected(data));
513 btnLast.setEnabled(!isLastImageSelected(data));
514 }
515 imgDisplay.setImage(null);
516 imgDisplay.setOsdText("");
517 return;
518 }
519 if (!isDialogShowing()) {
520 setIsDocked(false); // always open a detached window when an image is clicked and dialog is closed
521 showDialog();
522 } else {
523 if (isDocked && isCollapsed) {
524 expand();
525 dialogsPanel.reconstruct(Action.COLLAPSED_TO_DEFAULT, this);
526 }
527 }
528 }
529
530 private static boolean isLastImageSelected(ImageData data) {
531 return data.isImageSelected(data.getImages().get(data.getImages().size() - 1));
532 }
533
534 private static boolean isFirstImageSelected(ImageData data) {
535 return data.isImageSelected(data.getImages().get(0));
536 }
537
538 /**
539 * When an image is closed, really close it and do not pop
540 * up the side dialog.
541 */
542 @Override
543 protected boolean dockWhenClosingDetachedDlg() {
544 if (collapseButtonClicked) {
545 collapseButtonClicked = false;
546 return super.dockWhenClosingDetachedDlg();
547 }
548 return false;
549 }
550
551 @Override
552 protected void stateChanged() {
553 super.stateChanged();
554 if (btnCollapse != null) {
555 btnCollapse.setVisible(!isDocked);
556 }
557 }
558
559 /**
560 * Returns whether an image is currently displayed
561 * @return If image is currently displayed
562 */
563 public boolean hasImage() {
564 return currentEntry != null;
565 }
566
567 /**
568 * Returns the currently displayed image.
569 * @return Currently displayed image or {@code null}
570 * @since 6392
571 */
572 public static ImageEntry getCurrentImage() {
573 return getInstance().currentEntry;
574 }
575
576 /**
577 * Returns whether the center view is currently active.
578 * @return {@code true} if the center view is active, {@code false} otherwise
579 * @since 9416
580 */
581 public static boolean isCenterView() {
582 return getInstance().centerView;
583 }
584
585 @Override
586 public void layerAdded(LayerAddEvent e) {
587 registerOnLayer(e.getAddedLayer());
588 showLayer(e.getAddedLayer());
589 }
590
591 @Override
592 public void layerRemoving(LayerRemoveEvent e) {
593 if (e.getRemovedLayer() instanceof GeoImageLayer) {
594 ImageData removedData = ((GeoImageLayer) e.getRemovedLayer()).getImageData();
595 if (removedData == currentData) {
596 displayImages(null, null);
597 }
598 removedData.removeImageDataUpdateListener(this);
599 }
600 }
601
602 @Override
603 public void layerOrderChanged(LayerOrderChangeEvent e) {
604 // ignored
605 }
606
607 @Override
608 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
609 showLayer(e.getSource().getActiveLayer());
610 }
611
612 private void registerOnLayer(Layer layer) {
613 if (layer instanceof GeoImageLayer) {
614 ((GeoImageLayer) layer).getImageData().addImageDataUpdateListener(this);
615 }
616 }
617
618 private void showLayer(Layer newLayer) {
619 if (currentData == null && newLayer instanceof GeoImageLayer) {
620 ((GeoImageLayer) newLayer).getImageData().selectFirstImage();
621 }
622 }
623
624 @Override
625 public void selectedImageChanged(ImageData data) {
626 displayImages(data, data.getSelectedImages());
627 }
628
629 @Override
630 public void imageDataUpdated(ImageData data) {
631 displayImages(data, data.getSelectedImages());
632 }
633}
Note: See TracBrowser for help on using the repository browser.