altoslib: Allow map preloading to be aborted
[fw/altos] / altoslib / AltosMapLoader.java
index 7112a1c4d22f06e8c7af078ff8b4ef2c93957fe7..8b856e13debbb5cbbc8b5df832cc38fff342ae04 100644 (file)
@@ -19,6 +19,7 @@ package org.altusmetrum.altoslib_10;
 
 import java.io.*;
 import java.util.*;
+import java.util.concurrent.*;
 import java.text.*;
 import java.lang.Math;
 import java.net.URL;
@@ -42,6 +43,12 @@ public class AltosMapLoader extends Thread implements AltosMapTileListener {
        int     layers_total;
        int     layers_loaded;
 
+       private static final int        MAX_LOADING = 200;
+
+       private Semaphore       loading = new Semaphore(MAX_LOADING);
+
+       boolean abort;
+
        AltosMap        map;
 
        int tile_radius(int zoom) {
@@ -62,7 +69,7 @@ public class AltosMapLoader extends Thread implements AltosMapTileListener {
                return (tile_radius * 2 + 1) * (tile_radius * 2 + 1);
        }
 
-       public void do_load() {
+       private boolean do_load() {
                tiles_this_layer = tiles_per_layer(cur_z);
                tiles_loaded_layer = 0;
                listener.debug("tiles_this_layer %d (zoom %d)\n", tiles_this_layer, cur_z);
@@ -88,16 +95,24 @@ public class AltosMapLoader extends Thread implements AltosMapTileListener {
 
                for (int y = (int) upper_left.y; y <= lower_right.y; y += AltosMap.px_size) {
                        for (int x = (int) upper_left.x; x <= lower_right.x; x += AltosMap.px_size) {
+                               try {
+                                       loading.acquire();
+                               } catch (InterruptedException ie) {
+                                       return false;
+                               }
                                AltosPointInt   point = new AltosPointInt(x, y);
                                AltosLatLon     ul = transform.lat_lon(point);
                                AltosLatLon     center = transform.lat_lon(new AltosPointDouble(x + AltosMap.px_size/2, y + AltosMap.px_size/2));
-                               AltosMapTile    tile = map.map_interface.new_tile(null, ul, center, zoom, maptype, AltosMap.px_size);
+                               AltosMapTile    tile = new AltosMapTile(null, ul, center, zoom, maptype, AltosMap.px_size);
                                tile.add_listener(this);
+                               if (abort)
+                                       return false;
                        }
                }
+               return true;
        }
 
-       public int next_type(int start) {
+       private int next_type(int start) {
                int next_type;
                for (next_type = start;
                     next_type <= AltosMap.maptype_terrain && (all_types & (1 << next_type)) == 0;
@@ -106,19 +121,19 @@ public class AltosMapLoader extends Thread implements AltosMapTileListener {
                return next_type;
        }
 
-       public void next_load() {
+       private boolean next_load() {
                int next_type = next_type(cur_type + 1);
 
                if (next_type > AltosMap.maptype_terrain) {
                        if (cur_z == max_z) {
-                               return;
+                               return false;
                        } else {
                                cur_z++;
                        }
                        next_type = next_type(0);
                }
                cur_type = next_type;
-               do_load();
+               return true;
        }
 
        public void run() {
@@ -147,7 +162,12 @@ public class AltosMapLoader extends Thread implements AltosMapTileListener {
                listener.debug("total tiles %d layers %d\n", tiles_total, layers_total);
 
                listener.loader_start(tiles_total);
-               do_load();
+               do {
+                       if (!do_load())
+                               break;
+               } while (next_load());
+               if (abort)
+                       listener.loader_done(tiles_total);
        }
 
        public synchronized void notify_tile(AltosMapTile tile, int status) {
@@ -155,6 +175,8 @@ public class AltosMapLoader extends Thread implements AltosMapTileListener {
                if (status == AltosMapTile.fetching)
                        return;
 
+               loading.release();
+
                tile.remove_listener(this);
 
                if (layers_loaded >= layers_total)
@@ -174,12 +196,13 @@ public class AltosMapLoader extends Thread implements AltosMapTileListener {
 
                if (tiles_loaded_total == tiles_total)
                        listener.loader_done(tiles_total);
-               else {
+               else
                        listener.loader_notify(tiles_loaded_total,
                                               tiles_total, tile.store.file.toString());
-                       if (do_next)
-                               next_load();
-               }
+       }
+
+       public void abort() {
+               this.abort = true;
        }
 
        public AltosMapLoader(AltosMap map, AltosMapLoaderListener listener,
@@ -194,6 +217,7 @@ public class AltosMapLoader extends Thread implements AltosMapTileListener {
                this.max_z = max_z;
                this.radius = radius;
                this.all_types = all_types;
+               this.abort = false;
                start();
        }
 }