001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.layer;
003
004import java.util.concurrent.CopyOnWriteArrayList;
005
006/**
007 * This class implements the invalidation listener mechanism suggested by {@link MapViewPaintable} and a default #atta
008 *
009 * @author Michael Zangl
010 * @since 10031
011 */
012public abstract class AbstractMapViewPaintable implements MapViewPaintable {
013
014    /**
015     * This is the default implementation of the layer painter.
016     * <p>
017     * You should not use it. Write your own implementation and put your paint code into that class.
018     * <p>
019     * It propagates all calls to the
020     * {@link MapViewPaintable#paint(java.awt.Graphics2D, org.openstreetmap.josm.gui.MapView, org.openstreetmap.josm.data.Bounds)} method.
021     * @author Michael Zangl
022     * @since 10458
023     */
024    protected class CompatibilityModeLayerPainter implements LayerPainter {
025        @Override
026        public void paint(MapViewGraphics graphics) {
027            AbstractMapViewPaintable.this.paint(
028                    graphics.getDefaultGraphics(),
029                    graphics.getMapView(),
030                    graphics.getClipBounds().getLatLonBoundsBox());
031        }
032
033        @Override
034        public void detachFromMapView(MapViewEvent event) {
035            // ignored in old implementation
036        }
037    }
038
039    /**
040     * A list of invalidation listeners to call when this layer is invalidated.
041     */
042    private final CopyOnWriteArrayList<PaintableInvalidationListener> invalidationListeners = new CopyOnWriteArrayList<>();
043
044    /**
045     * This method is called whenever this layer is added to a map view.
046     * <p>
047     * You need to return a painter here.
048     * The {@link MapViewPaintable.LayerPainter#detachFromMapView} method is called when the layer is removed
049     * from that map view. You are free to reuse painters.
050     * <p>
051     * You should always call the super method. See {@link #createMapViewPainter} if you want to influence painter creation.
052     * <p>
053     * This replaces {@link Layer#hookUpMapView} in the long run.
054     * @param event the event.
055     * @return A layer painter.
056     * @since 10458
057     */
058    public LayerPainter attachToMapView(MapViewEvent event) {
059        return createMapViewPainter(event);
060    }
061
062    /**
063     * Creates a new LayerPainter.
064     * @param event The event that triggered the creation.
065     * @return The painter.
066     * @since 10458
067     */
068    protected LayerPainter createMapViewPainter(MapViewEvent event) {
069        return new CompatibilityModeLayerPainter();
070    }
071
072    /**
073     * Adds a new paintable invalidation listener.
074     * @param l The listener to add.
075     */
076    public void addInvalidationListener(PaintableInvalidationListener l) {
077        invalidationListeners.add(l);
078    }
079
080    /**
081     * Removes an added paintable invalidation listener.
082     * @param l The listener to remove.
083     */
084    public void removeInvalidationListener(PaintableInvalidationListener l) {
085        invalidationListeners.remove(l);
086    }
087
088    /**
089     * This needs to be called whenever the content of this view was invalidated.
090     */
091    public void invalidate() {
092        for (PaintableInvalidationListener l : invalidationListeners) {
093            l.paintableInvalidated(new PaintableInvalidationEvent(this));
094        }
095    }
096}