001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.layer.gpx;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.GraphicsEnvironment;
007import java.awt.GridBagLayout;
008import java.awt.event.ActionEvent;
009import java.io.IOException;
010import java.util.ArrayList;
011import java.util.List;
012
013import javax.swing.AbstractAction;
014import javax.swing.JLabel;
015import javax.swing.JOptionPane;
016import javax.swing.JPanel;
017
018import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource;
019import org.openstreetmap.josm.Main;
020import org.openstreetmap.josm.actions.AbstractMergeAction.LayerListCellRenderer;
021import org.openstreetmap.josm.data.coor.LatLon;
022import org.openstreetmap.josm.data.gpx.GpxData;
023import org.openstreetmap.josm.data.gpx.GpxTrack;
024import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
025import org.openstreetmap.josm.data.gpx.WayPoint;
026import org.openstreetmap.josm.gui.ExtendedDialog;
027import org.openstreetmap.josm.gui.PleaseWaitRunnable;
028import org.openstreetmap.josm.gui.layer.AbstractTileSourceLayer;
029import org.openstreetmap.josm.gui.progress.ProgressTaskId;
030import org.openstreetmap.josm.gui.progress.ProgressTaskIds;
031import org.openstreetmap.josm.gui.widgets.JosmComboBox;
032import org.openstreetmap.josm.io.OsmTransferException;
033import org.openstreetmap.josm.tools.GBC;
034import org.openstreetmap.josm.tools.ImageProvider;
035import org.xml.sax.SAXException;
036
037/**
038 * Class downloading WMS and TMS along the GPX track.
039 * @since 5715
040 */
041public class DownloadWmsAlongTrackAction extends AbstractAction {
042
043    private final transient GpxData data;
044
045    /**
046     * @param data that represents GPX track, along which data should be downloaded
047     */
048    public DownloadWmsAlongTrackAction(final GpxData data) {
049        super(tr("Precache imagery tiles along this track"), ImageProvider.get("downloadalongtrack"));
050        this.data = data;
051    }
052
053    static class PrecacheWmsTask extends PleaseWaitRunnable {
054
055        private final AbstractTileSourceLayer<? extends AbstractTMSTileSource> layer;
056        private final List<LatLon> points;
057        private AbstractTileSourceLayer<? extends AbstractTMSTileSource>.PrecacheTask precacheTask;
058
059        protected PrecacheWmsTask(AbstractTileSourceLayer<? extends AbstractTMSTileSource> layer, List<LatLon> points) {
060            super(tr("Precaching WMS"));
061            this.layer = layer;
062            this.points = points;
063        }
064
065        @Override
066        protected void realRun() throws SAXException, IOException, OsmTransferException {
067            precacheTask = layer.downloadAreaToCache(progressMonitor, points, 0, 0);
068            while (!precacheTask.isFinished() && !progressMonitor.isCanceled()) {
069                synchronized (this) {
070                    try {
071                        wait(200);
072                    } catch (InterruptedException ex) {
073                        Main.warn("InterruptedException in "+getClass().getSimpleName()+" while precaching WMS");
074                    }
075                }
076            }
077        }
078
079        @Override
080        protected void finish() {
081            // Do nothing
082        }
083
084        @Override
085        protected void cancel() {
086            precacheTask.cancel();
087        }
088
089        @Override
090        public ProgressTaskId canRunInBackground() {
091            return ProgressTaskIds.PRECACHE_WMS;
092        }
093    }
094
095    PrecacheWmsTask createTask() {
096        List<LatLon> points = new ArrayList<>();
097        for (GpxTrack trk : data.tracks) {
098            for (GpxTrackSegment segment : trk.getSegments()) {
099                for (WayPoint p : segment.getWayPoints()) {
100                    points.add(p.getCoor());
101                }
102            }
103        }
104        for (WayPoint p : data.waypoints) {
105            points.add(p.getCoor());
106        }
107        AbstractTileSourceLayer<? extends AbstractTMSTileSource> layer = askedLayer();
108        return layer != null ? new PrecacheWmsTask(layer, points) : null;
109    }
110
111    @Override
112    public void actionPerformed(ActionEvent e) {
113        PrecacheWmsTask task = createTask();
114        if (task != null) {
115            Main.worker.execute(task);
116        }
117    }
118
119    @SuppressWarnings({ "rawtypes", "unchecked" })
120    protected AbstractTileSourceLayer<? extends AbstractTMSTileSource> askedLayer() {
121        if (!Main.isDisplayingMapView()) {
122            return null;
123        }
124        List<AbstractTileSourceLayer> targetLayers = Main.map.mapView.getLayersOfType(AbstractTileSourceLayer.class);
125        if (targetLayers.isEmpty()) {
126            if (!GraphicsEnvironment.isHeadless()) {
127                warnNoImageryLayers();
128            }
129            return null;
130        }
131        JosmComboBox<AbstractTileSourceLayer> layerList = new JosmComboBox<>(targetLayers.toArray(new AbstractTileSourceLayer[0]));
132        layerList.setRenderer(new LayerListCellRenderer());
133        layerList.setSelectedIndex(0);
134        JPanel pnl = new JPanel(new GridBagLayout());
135        pnl.add(new JLabel(tr("Please select the imagery layer.")), GBC.eol());
136        pnl.add(layerList, GBC.eol());
137        if (GraphicsEnvironment.isHeadless()) {
138            // return first layer in headless mode, for unit tests
139            return targetLayers.get(0);
140        }
141        ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Select imagery layer"), new String[]{tr("Download"), tr("Cancel")});
142        ed.setButtonIcons(new String[]{"dialogs/down", "cancel"});
143        ed.setContent(pnl);
144        ed.showDialog();
145        if (ed.getValue() != 1) {
146            return null;
147        }
148        return (AbstractTileSourceLayer) layerList.getSelectedItem();
149    }
150
151    protected void warnNoImageryLayers() {
152        JOptionPane.showMessageDialog(Main.parent, tr("There are no imagery layers."), tr("No imagery layers"), JOptionPane.WARNING_MESSAGE);
153    }
154}