From 31a56b670a37c1c4a39cd3e35e45e5a04352c4b5 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Tue, 18 May 2010 07:10:37 +0000 Subject: [PATCH] implement bundle tile download git-svn-id: https://osmand.googlecode.com/svn/trunk@66 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8 --- .../src/com/osmand/ToDoConstants.java | 5 + .../data/preparation/MapTileDownloader.java | 11 +- .../src/com/osmand/swing/MapPanel.java | 3 +- .../swing/TileBundleDownloadDialog.java | 243 ++++++++++++++++++ 4 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 DataExtractionOSM/src/com/osmand/swing/TileBundleDownloadDialog.java diff --git a/DataExtractionOSM/src/com/osmand/ToDoConstants.java b/DataExtractionOSM/src/com/osmand/ToDoConstants.java index 3f2416b11d..8a13fe36ef 100644 --- a/DataExtractionOSM/src/com/osmand/ToDoConstants.java +++ b/DataExtractionOSM/src/com/osmand/ToDoConstants.java @@ -40,6 +40,10 @@ public class ToDoConstants { // 14. Show zoom level directly on map // ------------------- + // BUGS Androd : + // 1. When firstly run osmand navigation (from notification bar) show map & go to menu shows desktop. + // No chance to close application + /// SWING version : // TODO : @@ -52,5 +56,6 @@ public class ToDoConstants { // 9. Normalizing streets // 10. Reinvent index mechanism (save in zip file with tile indexes, save city/town addresses separately, read partially !) // 11. Street setName() change in city index! + // 12. Invent different file extensions for poi.index, address.index,... } diff --git a/DataExtractionOSM/src/com/osmand/data/preparation/MapTileDownloader.java b/DataExtractionOSM/src/com/osmand/data/preparation/MapTileDownloader.java index cdaae884fd..69735d763e 100644 --- a/DataExtractionOSM/src/com/osmand/data/preparation/MapTileDownloader.java +++ b/DataExtractionOSM/src/com/osmand/data/preparation/MapTileDownloader.java @@ -107,6 +107,14 @@ public class MapTileDownloader { return currentlyDownloaded.contains(f); } + public boolean isSomethingBeingDownloaded(){ + return !currentlyDownloaded.isEmpty(); + } + + public int getRemainingWorkers(){ + return (int) (threadPoolExecutor.getTaskCount()); + } + public void refuseAllPreviousRequests(){ while(!threadPoolExecutor.getQueue().isEmpty()){ @@ -130,7 +138,7 @@ public class MapTileDownloader { private class DownloadMapWorker implements Runnable, Comparable { - private long time = System.currentTimeMillis(); + private DownloadRequest request; private DownloadMapWorker(DownloadRequest request){ @@ -143,6 +151,7 @@ public class MapTileDownloader { log.debug("Start downloading tile : " + request.url); } if (request != null && request.fileToSave != null && request.url != null) { + long time = System.currentTimeMillis(); currentlyDownloaded.add(request.fileToSave); try { request.fileToSave.getParentFile().mkdirs(); diff --git a/DataExtractionOSM/src/com/osmand/swing/MapPanel.java b/DataExtractionOSM/src/com/osmand/swing/MapPanel.java index 9d4dca4868..1ed4e990d5 100644 --- a/DataExtractionOSM/src/com/osmand/swing/MapPanel.java +++ b/DataExtractionOSM/src/com/osmand/swing/MapPanel.java @@ -398,6 +398,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback { return; } this.zoom = zoom; + updateLocationLabel(); prepareImage(); } @@ -529,7 +530,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback { @Override public void actionPerformed(ActionEvent e) { - + new TileBundleDownloadDialog(MapPanel.this, MapPanel.this).showDialog(); } }); diff --git a/DataExtractionOSM/src/com/osmand/swing/TileBundleDownloadDialog.java b/DataExtractionOSM/src/com/osmand/swing/TileBundleDownloadDialog.java new file mode 100644 index 0000000000..9ba4f3c61b --- /dev/null +++ b/DataExtractionOSM/src/com/osmand/swing/TileBundleDownloadDialog.java @@ -0,0 +1,243 @@ +package com.osmand.swing; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.text.MessageFormat; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import com.osmand.ExceptionHandler; +import com.osmand.data.preparation.MapTileDownloader; +import com.osmand.data.preparation.MapTileDownloader.DownloadRequest; +import com.osmand.data.preparation.MapTileDownloader.IMapDownloaderCallback; +import com.osmand.map.ITileSource; +import com.osmand.osm.MapUtils; +import com.osmand.swing.MapPanel.MapSelectionArea; + +public class TileBundleDownloadDialog extends JDialog { + + private static final long serialVersionUID = -4862884032977071296L; + + private JLabel label; + private ITileSource map; + private MapSelectionArea selectionArea; + private int zoom; + private JSpinner startSpinner; + private JSpinner endSpinner; + private JButton downloadButton; + private JButton cancelButton; + private File tilesLocation; + + public TileBundleDownloadDialog(Component parent, MapPanel panel){ + super(JOptionPane.getFrameForComponent(parent), true); + map = panel.getMap(); + panel.getLatitude(); + selectionArea = panel.getSelectionArea(); + zoom = panel.getZoom(); + tilesLocation = panel.getTilesLocation(); + setTitle("Download bundle tiles"); + initDialog(); + + } + + public void showDialog(){ + setSize(550, 150); + double x = getParent().getBounds().getCenterX(); + double y = getParent().getBounds().getCenterY(); + setLocation((int) x - getWidth() / 2, (int) y - getHeight() / 2); + setVisible(true); + } + + protected SpinnerNumberModel getSpinnerModel(int minimum, int maximum){ + SpinnerNumberModel model = new SpinnerNumberModel(); + model.setStepSize(1); + model.setValue(zoom); + model.setMaximum(maximum); + model.setMinimum(minimum); + return model; + } + + private void initDialog() { + JPanel pane = new JPanel(new BorderLayout()); + pane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + add(pane); + + label = new JLabel(); + pane.add(label, BorderLayout.CENTER); + + JPanel zoomControls = new JPanel(); + zoomControls.setLayout(new BoxLayout(zoomControls, BoxLayout.X_AXIS)); + + JLabel lab = new JLabel("Start zoom level : "); + zoomControls.add(lab); + startSpinner = new JSpinner(getSpinnerModel(map.getMinimumZoomSupported(), zoom)); + zoomControls.add(startSpinner); + startSpinner.setMaximumSize(new Dimension(15, startSpinner.getMaximumSize().height)); + + zoomControls.add(Box.createHorizontalStrut(15)); + lab = new JLabel("End zoom level : "); + zoomControls.add(lab); + endSpinner = new JSpinner(getSpinnerModel(zoom, map.getMaximumZoomSupported())); + zoomControls.add(endSpinner); + endSpinner.setMaximumSize(new Dimension(15, endSpinner.getMaximumSize().height)); + zoomControls.add(Box.createHorizontalGlue()); + pane.add(zoomControls, BorderLayout.NORTH); + + + JPanel buttonControls = new JPanel(); + buttonControls.setLayout(new BoxLayout(buttonControls, BoxLayout.X_AXIS)); + buttonControls.add(Box.createHorizontalGlue()); + downloadButton = new JButton("Download tiles"); + buttonControls.add(downloadButton); + buttonControls.add(Box.createHorizontalStrut(3)); + cancelButton = new JButton("Cancel"); + buttonControls.add(cancelButton); + pane.add(buttonControls, BorderLayout.SOUTH); + + updateLabel(); + addListeners(); + } + + private void addListeners(){ + cancelButton.addActionListener(new ActionListener(){ + @Override + public void actionPerformed(ActionEvent e) { + setVisible(false); + } + }); + startSpinner.addChangeListener(new ChangeListener(){ + @Override + public void stateChanged(ChangeEvent e) { + ((SpinnerNumberModel)endSpinner.getModel()).setMinimum((Integer) startSpinner.getValue()); + updateLabel(); + } + }); + endSpinner.addChangeListener(new ChangeListener(){ + @Override + public void stateChanged(ChangeEvent e) { + ((SpinnerNumberModel)startSpinner.getModel()).setMaximum((Integer) endSpinner.getValue()); + updateLabel(); + } + }); + downloadButton.addActionListener(new ActionListener(){ + + @Override + public void actionPerformed(ActionEvent e) { + downloadTiles(); + } + + }); + + } + + public void downloadTiles(){ + setVisible(false); + final ProgressDialog progressDialog = new ProgressDialog(this, "Downloading tiles"); + int numberTiles = 0; + final int startZoom = (Integer) startSpinner.getValue(); + final int endZoom = (Integer) endSpinner.getValue(); + for (int zoom = startZoom; zoom <= endZoom; zoom++) { + int x1 = (int) MapUtils.getTileNumberX(zoom, selectionArea.getLon1()); + int x2 = (int) MapUtils.getTileNumberX(zoom, selectionArea.getLon2()); + int y1 = (int) MapUtils.getTileNumberY(zoom, selectionArea.getLat1()); + int y2 = (int) MapUtils.getTileNumberY(zoom, selectionArea.getLat2()); + numberTiles += (x2 - x1 + 1) * (y2 - y1 + 1); + } + final int number = numberTiles; + final MapTileDownloader instance = MapTileDownloader.getInstance(); + progressDialog.setRunnable(new Runnable(){ + + @Override + public void run() { + progressDialog.startTask("Loading...", number); + for (int zoom = startZoom; zoom <= endZoom; zoom++) { + int x1 = (int) MapUtils.getTileNumberX(zoom, selectionArea.getLon1()); + int x2 = (int) MapUtils.getTileNumberX(zoom, selectionArea.getLon2()); + int y1 = (int) MapUtils.getTileNumberY(zoom, selectionArea.getLat1()); + int y2 = (int) MapUtils.getTileNumberY(zoom, selectionArea.getLat2()); + for(int x = x1; x <= x2; x++){ + for(int y=y1; y<= y2; y++){ + String file = getFileForImage(x, y, zoom, map.getTileFormat()); + if(new File(tilesLocation, file).exists()){ + progressDialog.progress(1); + } else { + DownloadRequest req = new DownloadRequest(map.getUrlToLoad(x, y, zoom), + new File(tilesLocation, file), x, y, zoom); + instance.requestToDownload(req); + } + + } + } + while(instance.isSomethingBeingDownloaded()){ + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new IllegalArgumentException(e); + } + } + } + + } + + }); + IMapDownloaderCallback previousCallback = instance.getDownloaderCallback(); + instance.setDownloaderCallback(new IMapDownloaderCallback(){ + + @Override + public void tileDownloaded(DownloadRequest request) { + // TODO request could be null if bundle loading? + progressDialog.progress(1); + } + + }); + + try { + progressDialog.run(); + instance.refuseAllPreviousRequests(); + } catch (InvocationTargetException e) { + ExceptionHandler.handle((Exception) e.getCause()); + } catch (InterruptedException e) { + ExceptionHandler.handle(e); + } finally { + instance.setDownloaderCallback(previousCallback); + } + + } + + public String getFileForImage (int x, int y, int zoom, String ext){ + return map.getName() +"/"+zoom+"/"+(x) +"/"+y+ext+".tile"; + } + + + protected void updateLabel(){ + int numberTiles = 0; + for (int zoom = (Integer) startSpinner.getValue(); zoom <= (Integer) endSpinner.getValue(); zoom++) { + int x1 = (int) MapUtils.getTileNumberX(zoom, selectionArea.getLon1()); + int x2 = (int) MapUtils.getTileNumberX(zoom, selectionArea.getLon2()); + int y1 = (int) MapUtils.getTileNumberY(zoom, selectionArea.getLat1()); + int y2 = (int) MapUtils.getTileNumberY(zoom, selectionArea.getLat2()); + numberTiles += (x2 - x1 + 1) * (y2 - y1 + 1); + } + + String text = MessageFormat.format("Request to download {0} tiles from ''{1}'' (approximately {2} Mb)", + numberTiles, map.getName(), (double)numberTiles*12/1000); + label.setText(text); + } + +}