- Timestamp:
- 2022-11-09T20:26:24+01:00 (22 months ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/ImageData.java
r18444 r18591 11 11 import org.openstreetmap.josm.data.gpx.GpxImageEntry; 12 12 import org.openstreetmap.josm.data.osm.QuadBuckets; 13 import org.openstreetmap.josm.gui.layer.Layer; 13 14 import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry; 14 15 import org.openstreetmap.josm.tools.ListenerList; … … 42 43 private final ListenerList<ImageDataUpdateListener> listeners = ListenerList.create(); 43 44 private final QuadBuckets<ImageEntry> geoImages = new QuadBuckets<>(); 45 private Layer layer; 44 46 45 47 /** … … 327 329 328 330 /** 329 * Remove the image from the list and option nally trigger update listener331 * Remove the image from the list and optionally trigger update listener 330 332 * @param img the {@link ImageEntry} to remove 331 333 * @param fireUpdateEvent if {@code true}, notifies listeners of image update … … 377 379 378 380 /** 381 * Set the layer for use with {@link org.openstreetmap.josm.gui.layer.geoimage.ImageViewerDialog#displayImages(Layer, List)} 382 * @param layer The layer to use for organization 383 * @since 18591 384 */ 385 public void setLayer(Layer layer) { 386 this.layer = layer; 387 } 388 389 /** 390 * Get the layer that this data is associated with. May be {@code null}. 391 * @return The layer this data is associated with. 392 * @since 18591 393 */ 394 public Layer getLayer() { 395 return this.layer; 396 } 397 398 /** 379 399 * Add a listener that listens to image data changes 380 400 * @param listener the {@link ImageDataUpdateListener} -
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
r18265 r18591 172 172 this.useThumbs = useThumbs; 173 173 this.data.addImageDataUpdateListener(this); 174 this.data.setLayer(this); 174 175 } 175 176 … … 232 233 } else { 233 234 data.setSelectedImage(img); 235 ImageViewerDialog.getInstance().displayImages(GeoImageLayer.this, Collections.singletonList(img)); 234 236 } 235 237 } … … 522 524 */ 523 525 public void showCurrentPhoto() { 524 if (data.getSelectedImage() != null) {525 clearOtherCurrentPhotos();526 }527 526 updateBufferAndRepaint(); 528 527 } … … 630 629 631 630 /** 632 * Clears the currentPhoto of the other GeoImageLayer's. Otherwise there could be multiple selected photos.633 */634 private void clearOtherCurrentPhotos() {635 for (GeoImageLayer layer:636 MainApplication.getLayerManager().getLayersOfType(GeoImageLayer.class)) {637 if (layer != this) {638 layer.getImageData().clearSelectedImage();639 }640 }641 }642 643 /**644 631 * Registers a map mode for which the functionality of this layer should be available. 645 632 * @param mapMode Map mode to be registered -
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java
r18421 r18591 154 154 @Override 155 155 public void selectImage(ImageViewerDialog imageViewerDialog, IImageEntry<?> entry) { 156 IImageEntry.super.selectImage(imageViewerDialog, entry);157 156 if (entry instanceof ImageEntry) { 158 157 this.dataSet.setSelectedImage((ImageEntry) entry); 159 158 } 159 imageViewerDialog.displayImages(this.dataSet.getLayer(), Collections.singletonList(entry)); 160 160 } 161 161 … … 212 212 } 213 213 214 private ImageReadParam withSubsampling(ImageReader reader, Dimension target) {214 private static ImageReadParam withSubsampling(ImageReader reader, Dimension target) { 215 215 try { 216 216 ImageReadParam param = reader.getDefaultReadParam(); -
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java
r18427 r18591 12 12 import java.awt.GridBagLayout; 13 13 import java.awt.event.ActionEvent; 14 import java.awt.event.ActionListener; 14 15 import java.awt.event.KeyEvent; 15 16 import java.awt.event.WindowEvent; … … 22 23 import java.util.Arrays; 23 24 import java.util.Collections; 25 import java.util.Comparator; 26 import java.util.HashMap; 24 27 import java.util.List; 28 import java.util.Map; 25 29 import java.util.Objects; 26 30 import java.util.Optional; … … 37 41 import javax.swing.JToggleButton; 38 42 import javax.swing.SwingConstants; 43 import javax.swing.SwingUtilities; 39 44 40 45 import org.openstreetmap.josm.actions.JosmAction; … … 53 58 import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent; 54 59 import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent; 60 import org.openstreetmap.josm.gui.layer.MainLayerManager; 55 61 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent; 56 62 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener; 57 63 import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings; 64 import org.openstreetmap.josm.gui.util.GuiHelper; 58 65 import org.openstreetmap.josm.gui.util.imagery.Vector3D; 59 66 import org.openstreetmap.josm.tools.ImageProvider; … … 121 128 private JButton btnDeleteFromDisk; 122 129 private JToggleButton tbCentre; 130 /** The layer tab (used to select images when multiple layers provide images, makes for easy switching) */ 131 private JPanel layers; 123 132 124 133 private ImageViewerDialog() { … … 153 162 private void build() { 154 163 JPanel content = new JPanel(new BorderLayout()); 164 this.layers = new JPanel(new GridBagLayout()); 165 content.add(layers, BorderLayout.NORTH); 155 166 156 167 content.add(imgDisplay, BorderLayout.CENTER); … … 212 223 213 224 createLayout(content, false, null); 225 } 226 227 private void updateLayers() { 228 if (this.tabbedEntries.size() <= 1) { 229 this.layers.setVisible(false); 230 this.layers.removeAll(); 231 } else { 232 this.layers.setVisible(true); 233 // Remove all old components 234 this.layers.removeAll(); 235 MainLayerManager layerManager = MainApplication.getLayerManager(); 236 List<Layer> invalidLayers = this.tabbedEntries.keySet().stream().filter(layer -> !layerManager.containsLayer(layer)) 237 .collect(Collectors.toList()); 238 // `null` is for anything using the old methods, without telling us what layer it comes from. 239 invalidLayers.remove(null); 240 // We need to do multiple calls to avoid ConcurrentModificationExceptions 241 invalidLayers.forEach(this.tabbedEntries::remove); 242 addButtonsForImageLayers(); 243 } 244 this.revalidate(); 245 } 246 247 /** 248 * Add the buttons for image layers 249 */ 250 private void addButtonsForImageLayers() { 251 final IImageEntry<?> current; 252 synchronized (this) { 253 current = this.currentEntry; 254 } 255 List<JButton> layerButtons = new ArrayList<>(this.tabbedEntries.size()); 256 if (this.tabbedEntries.containsKey(null)) { 257 List<IImageEntry<?>> nullEntries = this.tabbedEntries.get(null); 258 JButton layerButton = createImageLayerButton(null, nullEntries); 259 layerButtons.add(layerButton); 260 layerButton.setEnabled(!nullEntries.contains(current)); 261 } 262 for (Map.Entry<Layer, List<IImageEntry<?>>> entry : 263 this.tabbedEntries.entrySet().stream().filter(entry -> entry.getKey() != null) 264 .sorted(Comparator.comparing(entry -> entry.getKey().getName())).collect(Collectors.toList())) { 265 JButton layerButton = createImageLayerButton(entry.getKey(), entry.getValue()); 266 layerButtons.add(layerButton); 267 layerButton.setEnabled(!entry.getValue().contains(current)); 268 } 269 layerButtons.forEach(this.layers::add); 270 } 271 272 /** 273 * Create a button for a specific layer and its entries 274 * 275 * @param layer The layer to switch to 276 * @param entries The entries to display 277 * @return The button to use to switch to the specified layer 278 */ 279 private static JButton createImageLayerButton(Layer layer, List<IImageEntry<?>> entries) { 280 final JButton layerButton = new JButton(); 281 layerButton.addActionListener(new ImageActionListener(layer, entries)); 282 layerButton.setText(layer != null ? layer.getLabel() : tr("Default")); 283 return layerButton; 214 284 } 215 285 … … 307 377 } 308 378 379 /** 380 * Update the icon for this action 381 */ 309 382 public void updateIcon() { 310 383 if (this.last != null) { … … 350 423 } 351 424 return super.getSupplier(); 425 } 426 } 427 428 /** 429 * A listener that is called to change the viewing layer 430 */ 431 private static class ImageActionListener implements ActionListener { 432 433 private final Layer layer; 434 private final List<IImageEntry<?>> entries; 435 436 ImageActionListener(Layer layer, List<IImageEntry<?>> entries) { 437 this.layer = layer; 438 this.entries = entries; 439 } 440 441 @Override 442 public void actionPerformed(ActionEvent e) { 443 ImageViewerDialog.getInstance().displayImages(this.layer, this.entries); 352 444 } 353 445 } … … 552 644 } 553 645 646 /** Used for tabbed panes */ 647 private final transient Map<Layer, List<IImageEntry<?>>> tabbedEntries = new HashMap<>(); 554 648 private transient IImageEntry<? extends IImageEntry<?>> currentEntry; 555 649 … … 579 673 */ 580 674 public void displayImages(List<IImageEntry<?>> entries) { 675 this.displayImages((Layer) null, entries); 676 } 677 678 /** 679 * Displays images for the given layer. 680 * @param layer The layer to use for the tab ui 681 * @param entries image entries 682 * @since 18591 683 */ 684 public void displayImages(Layer layer, List<IImageEntry<?>> entries) { 581 685 boolean imageChanged; 582 686 IImageEntry<?> entry = entries != null && entries.size() == 1 ? entries.get(0) : null; … … 599 703 } 600 704 705 if (entries == null || entries.isEmpty() || entries.stream().allMatch(Objects::isNull)) { 706 this.tabbedEntries.remove(layer); 707 } else { 708 this.tabbedEntries.put(layer, entries); 709 } 710 this.updateLayers(); 601 711 if (entry != null) { 602 712 this.updateButtonsNonNullEntry(entry, imageChanged); 713 } else if (this.tabbedEntries.isEmpty()) { 714 this.updateButtonsNullEntry(entries); 715 return; 603 716 } else { 604 this.updateButtonsNullEntry(entries); 717 Map.Entry<Layer, List<IImageEntry<?>>> realEntry = 718 this.tabbedEntries.entrySet().stream().filter(mapEntry -> mapEntry.getValue().size() == 1).findFirst().orElse(null); 719 if (realEntry == null) { 720 this.updateButtonsNullEntry(entries); 721 } else { 722 this.displayImages(realEntry.getKey(), realEntry.getValue()); 723 } 605 724 return; 606 725 } … … 731 850 btnCollapse.setVisible(!isDocked); 732 851 } 852 this.updateLayers(); 733 853 } 734 854 … … 798 918 } 799 919 920 /** 921 * Reload the image. Call this if you load a low-resolution image first, and then get a high-resolution image, or 922 * if you know that the image has changed on disk. 923 * @since 18591 924 */ 925 public void refresh() { 926 if (SwingUtilities.isEventDispatchThread()) { 927 this.updateButtonsNonNullEntry(currentEntry, true); 928 } else { 929 GuiHelper.runInEDT(this::refresh); 930 } 931 } 932 800 933 private void registerOnLayer(Layer layer) { 801 934 if (layer instanceof GeoImageLayer) { … … 820 953 @Override 821 954 public void selectedImageChanged(ImageData data) { 822 displayImages(new ArrayList<>(data.getSelectedImages())); 955 if (this.currentEntry != data.getSelectedImage() && this.currentEntry instanceof ImageEntry && 956 !data.getSelectedImages().contains(this.currentEntry)) { 957 displayImages(data.getLayer(), new ArrayList<>(data.getSelectedImages())); 958 } 823 959 } 824 960 825 961 @Override 826 962 public void imageDataUpdated(ImageData data) { 827 displayImages( new ArrayList<>(data.getSelectedImages()));963 displayImages(data.getLayer(), new ArrayList<>(data.getSelectedImages())); 828 964 } 829 965 }
Note:
See TracChangeset
for help on using the changeset viewer.