This takes the swing-specific map code and creates a generic version.
Signed-off-by: Keith Packard <keithp@keithp.com>
bin
classaltoslib.stamp
altoslib*.jar
+AltosVersion.java
--- /dev/null
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+public interface AltosFlightDisplay extends AltosUnitsListener, AltosFontListener {
+ void reset();
+
+ void show(AltosState state, AltosListenerState listener_state);
+
+ String getName();
+}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+public interface AltosFontListener {
+ void font_size_changed(int font_size);
+}
--- /dev/null
+/*
+ * Copyright © 2015 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+import java.io.*;
+
+public interface AltosImage {
+ /* Discard storage for image */
+ public abstract void flush();
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+public class AltosLatLon {
+ public double lat;
+ public double lon;
+
+ public boolean equals(AltosLatLon other) {
+ if (other == null)
+ return false;
+ return lat == other.lat && lon == other.lon;
+ }
+
+ public AltosLatLon(double lat, double lon) {
+ this.lat = lat;
+ this.lon = lon;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+import java.io.*;
+import java.lang.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+public class AltosMap implements AltosFlightDisplay, AltosMapTileListener, AltosMapStoreListener {
+
+ static final int px_size = 512;
+
+ static final int maptype_hybrid = 0;
+ static final int maptype_roadmap = 1;
+ static final int maptype_satellite = 2;
+ static final int maptype_terrain = 3;
+ static final int maptype_default = maptype_hybrid;
+
+ static final int default_zoom = 15;
+ static final int min_zoom = 3;
+ static final int max_zoom = 21;
+
+ static final String[] maptype_names = {
+ "hybrid",
+ "roadmap",
+ "satellite",
+ "terrain"
+ };
+
+ public static final String[] maptype_labels = {
+ "Hybrid",
+ "Roadmap",
+ "Satellite",
+ "Terrain"
+ };
+
+ AltosMapInterface map_interface;
+
+ AltosMapCache cache;
+
+ LinkedList<AltosMapMark> marks = new LinkedList<AltosMapMark>();
+
+ LinkedList<AltosMapZoomListener> zoom_listeners = new LinkedList<AltosMapZoomListener>();
+
+ public void add_zoom_listener(AltosMapZoomListener listener) {
+ if (!zoom_listeners.contains(listener))
+ zoom_listeners.add(listener);
+ }
+
+ public void remove_zoom_listener(AltosMapZoomListener listener) {
+ zoom_listeners.remove(listener);
+ }
+
+ boolean have_boost = false;
+ boolean have_landed = false;
+
+ ConcurrentHashMap<AltosPointInt,AltosMapTile> tiles = new ConcurrentHashMap<AltosPointInt,AltosMapTile>();
+ int load_radius;
+ AltosLatLon load_centre = null;
+ AltosMapTileListener load_listener;
+
+ int zoom = AltosMap.default_zoom;
+ int maptype = AltosMap.maptype_default;
+
+ long user_input_time;
+
+ /* Milliseconds to wait after user action before auto-scrolling
+ */
+ static final long auto_scroll_delay = 20 * 1000;
+
+ AltosMapTransform transform;
+ AltosLatLon centre;
+
+ public void reset() {
+ // nothing
+ }
+
+ /* MapInterface wrapping functions */
+ public void set_units() {
+ map_interface.set_units();
+ }
+
+ public void repaint(AltosMapRectangle damage, int pad) {
+ map_interface.repaint(damage, pad);
+ }
+
+ public void repaint(double x, double y, double w, double h) {
+ map_interface.repaint(x, y, w, h);
+ }
+
+ public void repaint() {
+ map_interface.repaint();
+ }
+
+ public int width() {
+ return map_interface.width();
+ }
+
+ public int height() {
+ return map_interface.height();
+ }
+
+ public AltosPointInt floor(AltosPointDouble point) {
+ return new AltosPointInt ((int) Math.floor(point.x / AltosMap.px_size) * AltosMap.px_size,
+ (int) Math.floor(point.y / AltosMap.px_size) * AltosMap.px_size);
+ }
+
+ public AltosPointInt ceil(AltosPointDouble point) {
+ return new AltosPointInt ((int) Math.ceil(point.x / AltosMap.px_size) * AltosMap.px_size,
+ (int) Math.ceil(point.y / AltosMap.px_size) * AltosMap.px_size);
+ }
+
+ public void notice_user_input() {
+ user_input_time = System.currentTimeMillis();
+ }
+
+ public boolean recent_user_input() {
+ return (System.currentTimeMillis() - user_input_time) < auto_scroll_delay;
+ }
+
+ public boolean far_from_centre(AltosLatLon lat_lon) {
+
+ if (centre == null || transform == null)
+ return true;
+
+ AltosPointDouble screen = transform.screen(lat_lon);
+
+ int width = width();
+ int dx = Math.abs ((int) (double) screen.x - width/2);
+
+ if (dx > width / 4)
+ return true;
+
+ int height = height();
+ int dy = Math.abs ((int) (double) screen.y - height/2);
+
+ if (dy > height / 4)
+ return true;
+
+ return false;
+ }
+
+ public void font_size_changed(int font_size) {
+ map_interface.line.font_size_changed(font_size);
+ for (AltosMapTile tile : tiles.values())
+ tile.font_size_changed(font_size);
+ repaint();
+ }
+
+ public void units_changed(boolean imperial_units) {
+ }
+
+ private void set_transform() {
+ transform = new AltosMapTransform(width(), height(), zoom, centre);
+ repaint();
+ }
+
+ public boolean set_zoom(int zoom) {
+ if (AltosMap.min_zoom <= zoom && zoom <= AltosMap.max_zoom && zoom != this.zoom) {
+ this.zoom = zoom;
+ tiles.clear();
+ set_transform();
+
+ for (AltosMapZoomListener listener : zoom_listeners)
+ listener.zoom_changed(this.zoom);
+
+ return true;
+ }
+ return false;
+ }
+
+ public int get_zoom() {
+ return zoom;
+ }
+
+ public boolean set_maptype(int maptype) {
+ if (maptype != this.maptype) {
+ this.maptype = maptype;
+ tiles.clear();
+ repaint();
+ return true;
+ }
+ return false;
+ }
+
+ public void show(AltosState state, AltosListenerState listener_state) {
+
+ /* If insufficient gps data, nothing to update
+ */
+ AltosGPS gps = state.gps;
+
+ if (gps == null)
+ return;
+
+ if (!gps.locked && gps.nsat < 4)
+ return;
+
+ AltosMapRectangle damage = map_interface.path.add(gps.lat, gps.lon, state.state);
+
+ switch (state.state) {
+ case AltosLib.ao_flight_boost:
+ if (!have_boost) {
+ add_mark(gps.lat, gps.lon, state.state);
+ have_boost = true;
+ }
+ break;
+ case AltosLib.ao_flight_landed:
+ if (!have_landed) {
+ add_mark(gps.lat, gps.lon, state.state);
+ have_landed = true;
+ }
+ break;
+ }
+
+ if (damage != null)
+ repaint(damage, AltosMapPath.stroke_width);
+ maybe_centre(gps.lat, gps.lon);
+ }
+
+ public void centre(AltosLatLon lat_lon) {
+ centre = lat_lon;
+ set_transform();
+ }
+
+ public void centre(double lat, double lon) {
+ centre(new AltosLatLon(lat, lon));
+ }
+
+ public void centre(AltosState state) {
+ if (!state.gps.locked && state.gps.nsat < 4)
+ return;
+ centre(state.gps.lat, state.gps.lon);
+ }
+
+ public void maybe_centre(double lat, double lon) {
+ AltosLatLon lat_lon = new AltosLatLon(lat, lon);
+ if (centre == null || (!recent_user_input() && far_from_centre(lat_lon)))
+ centre(lat_lon);
+ }
+
+ public void add_mark(double lat, double lon, int state) {
+ synchronized(marks) {
+ marks.add(map_interface.new_mark(lat, lon, state));
+ }
+ repaint();
+ }
+
+ public void clear_marks() {
+ synchronized(marks) {
+ marks.clear();
+ }
+ }
+
+ private void make_tiles() {
+ AltosPointInt upper_left;
+ AltosPointInt lower_right;
+
+ if (load_centre != null) {
+ AltosPointInt centre = floor(transform.point(load_centre));
+
+ upper_left = new AltosPointInt(centre.x - load_radius * AltosMap.px_size,
+ centre.y - load_radius * AltosMap.px_size);
+ lower_right = new AltosPointInt(centre.x + load_radius * AltosMap.px_size,
+ centre.y + load_radius * AltosMap.px_size);
+ } else {
+ upper_left = floor(transform.screen_point(new AltosPointDouble(0.0, 0.0)));
+ lower_right = floor(transform.screen_point(new AltosPointDouble(width(), height())));
+ }
+ LinkedList<AltosPointInt> to_remove = new LinkedList<AltosPointInt>();
+
+ for (AltosPointInt point : tiles.keySet()) {
+ if (point.x < upper_left.x || lower_right.x < point.x ||
+ point.y < upper_left.y || lower_right.y < point.y) {
+ to_remove.add(point);
+ }
+ }
+
+ for (AltosPointInt point : to_remove)
+ tiles.remove(point);
+
+ cache.set_cache_size((width() / AltosMap.px_size + 2) * (height() / AltosMap.px_size + 2));
+ 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) {
+ AltosPointInt point = new AltosPointInt(x, y);
+
+ if (!tiles.containsKey(point)) {
+ AltosLatLon ul = transform.lat_lon(new AltosPointDouble(x, y));
+ AltosLatLon center = transform.lat_lon(new AltosPointDouble(x + AltosMap.px_size/2, y + AltosMap.px_size/2));
+ AltosMapTile tile = new AltosMapTile(this, ul, center, zoom, maptype,
+ AltosMap.px_size);
+ tiles.put(point, tile);
+ }
+ }
+ }
+ }
+
+ public void set_load_params(double lat, double lon, int radius, AltosMapTileListener listener) {
+ load_centre = new AltosLatLon(lat, lon);
+ load_radius = radius;
+ load_listener = listener;
+ centre(lat, lon);
+ make_tiles();
+ for (AltosMapTile tile : tiles.values()) {
+ tile.add_store_listener(this);
+ if (tile.store_status() != AltosMapTile.loading)
+ listener.notify_tile(tile, tile.store_status());
+ }
+ repaint();
+ }
+
+ public String getName() {
+ return "Map";
+ }
+
+ /* AltosMapTileListener methods */
+ public synchronized void notify_tile(AltosMapTile tile, int status) {
+ for (AltosPointInt point : tiles.keySet()) {
+ if (tile == tiles.get(point)) {
+ AltosPointInt screen = transform.screen(point);
+ repaint(screen.x, screen.y, AltosMap.px_size, AltosMap.px_size);
+ }
+ }
+ }
+
+ /* AltosMapStoreListener methods */
+ public synchronized void notify_store(AltosMapStore store, int status) {
+ if (load_listener != null) {
+ for (AltosMapTile tile : tiles.values())
+ if (store.equals(tile.store))
+ load_listener.notify_tile(tile, status);
+ }
+ }
+
+ public AltosMap(AltosMapInterface map_interface) {
+ this.map_interface = map_interface;
+ cache = new AltosMapCache(map_interface);
+ centre(0, 0);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+import java.io.*;
+import java.net.*;
+
+public class AltosMapCache implements AltosMapCacheListener {
+
+ /* An entry in the MapCache */
+ class MapCacheElement implements AltosMapStoreListener {
+
+ AltosMapTile tile; /* Notify when image has been loaded */
+ AltosImage image;
+ AltosMapStore store;
+ long used;
+
+ class loader implements Runnable {
+ public void run() {
+ if (image != null)
+ tile.notify_image(image);
+ try {
+ image = map_interface.load_image(store.file);
+ } catch (Exception ex) {
+ }
+ if (image == null)
+ tile.set_status(AltosMapTile.failed);
+ else
+ tile.set_status(AltosMapTile.success);
+ tile.notify_image(image);
+ }
+ }
+
+ private void load() {
+ loader l = new loader();
+ Thread lt = new Thread(l);
+ lt.start();
+ }
+
+ public void flush() {
+ if (image != null) {
+ image.flush();
+ image = null;
+ }
+ }
+
+ public boolean has_map() {
+ return store.status() == AltosMapTile.success;
+ }
+
+ public synchronized void notify_store(AltosMapStore store, int status) {
+ switch (status) {
+ case AltosMapTile.loading:
+ break;
+ case AltosMapTile.success:
+ load();
+ break;
+ default:
+ tile.set_status(status);
+ tile.notify_image(null);
+ }
+ }
+
+ public MapCacheElement(AltosMapTile tile, AltosMapStore store) throws IOException {
+ this.tile = tile;
+ this.image = null;
+ this.store = store;
+ this.used = 0;
+
+ int status = store.status();
+ switch (status) {
+ case AltosMapTile.loading:
+ store.add_listener(this);
+ break;
+ case AltosMapTile.success:
+ load();
+ break;
+ default:
+ tile.set_status(status);
+ tile.notify_image(null);
+ break;
+ }
+ }
+ }
+
+ int min_cache_size; /* configured minimum cache size */
+ int cache_size; /* current cache size */
+ int requested_cache_size; /* cache size computed by application */
+
+ private Object fetch_lock = new Object();
+ private Object cache_lock = new Object();
+
+ AltosMapInterface map_interface;
+
+ MapCacheElement[] elements = new MapCacheElement[cache_size];
+
+ long used;
+
+ public void set_cache_size(int new_size) {
+
+ requested_cache_size = new_size;
+
+ if (new_size < min_cache_size)
+ new_size = min_cache_size;
+
+ if (new_size == cache_size)
+ return;
+
+ synchronized(cache_lock) {
+ MapCacheElement[] new_elements = new MapCacheElement[new_size];
+
+ for (int i = 0; i < cache_size; i++) {
+ if (i < new_size)
+ new_elements[i] = elements[i];
+ else if (elements[i] != null)
+ elements[i].flush();
+ }
+ elements = new_elements;
+ cache_size = new_size;
+ }
+ }
+
+ public AltosImage get(AltosMapTile tile, AltosMapStore store, int width, int height) {
+ int oldest = -1;
+ long age = used;
+
+ synchronized(cache_lock) {
+ MapCacheElement element = null;
+ for (int i = 0; i < cache_size; i++) {
+ element = elements[i];
+
+ if (element == null) {
+ oldest = i;
+ break;
+ }
+ if (store.equals(element.store)) {
+ element.used = used++;
+ return element.image;
+ }
+ if (element.used < age) {
+ oldest = i;
+ age = element.used;
+ }
+ }
+
+ try {
+ element = new MapCacheElement(tile, store);
+ element.used = used++;
+ if (elements[oldest] != null)
+ elements[oldest].flush();
+
+ elements[oldest] = element;
+
+ if (element.image == null)
+ tile.set_status(AltosMapTile.loading);
+ else
+ tile.set_status(AltosMapTile.success);
+
+ return element.image;
+ } catch (IOException e) {
+ tile.set_status(AltosMapTile.failed);
+ return null;
+ }
+ }
+ }
+
+ public void map_cache_changed(int map_cache) {
+ min_cache_size = map_cache;
+
+ set_cache_size(requested_cache_size);
+ }
+
+ public void dispose() {
+ AltosPreferences.unregister_map_cache_listener(this);
+
+ for (int i = 0; i < cache_size; i++) {
+ MapCacheElement element = elements[i];
+
+ if (element != null)
+ element.flush();
+ }
+ }
+
+ public AltosMapCache(AltosMapInterface map_interface) {
+ this.map_interface = map_interface;
+ min_cache_size = AltosPreferences.map_cache();
+
+ set_cache_size(0);
+
+ AltosPreferences.register_map_cache_listener(this);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+public interface AltosMapCacheListener {
+ public void map_cache_changed(int map_cache);
+}
--- /dev/null
+/*
+ * Copyright © 2015 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+import java.io.*;
+import java.net.*;
+
+public abstract class AltosMapInterface {
+
+ public AltosMapPath path;
+ public AltosMapLine line;
+
+ public abstract AltosImage load_image(File file) throws Exception;
+
+ public abstract AltosMapMark new_mark(double lat, double lon, int state);
+
+ public abstract int width();
+ public abstract int height();
+
+ public abstract void repaint();
+
+ public abstract void repaint(AltosMapRectangle damage, int pad);
+
+ public abstract void repaint(double x, double y, double w, double h);
+
+ public abstract void set_units();
+
+ public AltosMapInterface (AltosMapPath path, AltosMapLine line) {
+ this.path = path;
+ this.line = line;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+import java.io.*;
+import java.lang.Math;
+import java.util.*;
+import java.util.concurrent.*;
+
+public abstract class AltosMapLine implements AltosFontListener {
+ AltosLatLon start, end;
+
+ static public int stroke_width = 6;
+
+ public abstract void font_size_changed(int font_size);
+
+ private AltosLatLon lat_lon(AltosPointDouble pt, AltosMapTransform t) {
+ return t.screen_lat_lon(pt);
+ }
+
+ public void dragged(AltosPointDouble pt, AltosMapTransform t) {
+ end = lat_lon(pt, t);
+ }
+
+ public void pressed(AltosPointDouble pt, AltosMapTransform t) {
+ start = lat_lon(pt, t);
+ end = null;
+ }
+
+ private String line_dist() {
+ String format;
+ AltosGreatCircle g = new AltosGreatCircle(start.lat, start.lon,
+ end.lat, end.lon);
+ double distance = g.distance;
+
+ if (AltosConvert.imperial_units) {
+ distance = AltosConvert.meters_to_feet(distance);
+ if (distance < 10000) {
+ format = "%4.0fft";
+ } else {
+ distance /= 5280;
+ if (distance < 10)
+ format = "%5.3fmi";
+ else if (distance < 100)
+ format = "%5.2fmi";
+ else if (distance < 1000)
+ format = "%5.1fmi";
+ else
+ format = "%5.0fmi";
+ }
+ } else {
+ if (distance < 10000) {
+ format = "%4.0fm";
+ } else {
+ distance /= 1000;
+ if (distance < 100)
+ format = "%5.2fkm";
+ else if (distance < 1000)
+ format = "%5.1fkm";
+ else
+ format = "%5.0fkm";
+ }
+ }
+ return String.format(format, distance);
+ }
+
+ public abstract void paint(AltosMapTransform t);
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+import java.io.*;
+import java.lang.Math;
+import java.util.*;
+import java.util.concurrent.*;
+
+public abstract class AltosMapMark {
+
+ AltosLatLon lat_lon;
+ int state;
+
+ static public int stroke_width = 6;
+
+ public abstract void paint(AltosMapTransform t);
+
+ public AltosMapMark (double lat, double lon, int state) {
+ lat_lon = new AltosLatLon(lat, lon);
+ this.state = state;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+import java.io.*;
+import java.lang.Math;
+import java.util.*;
+import java.util.concurrent.*;
+
+class PathPoint {
+ AltosLatLon lat_lon;
+ int state;
+
+ public PathPoint(AltosLatLon lat_lon, int state) {
+ this.lat_lon = lat_lon;
+ this.state = state;
+ }
+
+ public boolean equals(PathPoint other) {
+ if (other == null)
+ return false;
+
+ return lat_lon.equals(other.lat_lon) && state == other.state;
+ }
+}
+
+public abstract class AltosMapPath {
+
+ LinkedList<PathPoint> points = new LinkedList<PathPoint>();
+ PathPoint last_point = null;
+
+ static public int stroke_width = 6;
+
+ public abstract void paint(AltosMapTransform t);
+
+ public AltosMapRectangle add(double lat, double lon, int state) {
+ PathPoint point = new PathPoint(new AltosLatLon (lat, lon), state);
+ AltosMapRectangle rect = null;
+
+ if (!point.equals(last_point)) {
+ if (last_point != null)
+ rect = new AltosMapRectangle(last_point.lat_lon, point.lat_lon);
+ points.add (point);
+ last_point = point;
+ }
+ return rect;
+ }
+
+ public void clear () {
+ points = new LinkedList<PathPoint>();
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+public class AltosMapRectangle {
+ AltosLatLon ul, lr;
+
+ public AltosMapRectangle(AltosLatLon a, AltosLatLon b) {
+ double ul_lat, ul_lon;
+ double lr_lat, lr_lon;
+
+ if (a.lat > b.lat) {
+ ul_lat = a.lat;
+ lr_lat = b.lat;
+ } else {
+ ul_lat = b.lat;
+ lr_lat = a.lat;
+ }
+ if (a.lon < b.lon) {
+ ul_lon = a.lon;
+ lr_lon = b.lon;
+ } else {
+ ul_lon = b.lon;
+ lr_lon = a.lon;
+ }
+
+ ul = new AltosLatLon(ul_lat, ul_lon);
+ lr = new AltosLatLon(lr_lat, lr_lon);
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+public class AltosMapStore {
+ String url;
+ public File file;
+ LinkedList<AltosMapStoreListener> listeners = new LinkedList<AltosMapStoreListener>();
+
+ int status;
+
+ public int status() {
+ return status;
+ }
+
+ public synchronized void add_listener(AltosMapStoreListener listener) {
+ if (!listeners.contains(listener))
+ listeners.add(listener);
+ }
+
+ public synchronized void remove_listener(AltosMapStoreListener listener) {
+ listeners.remove(listener);
+ }
+
+ private synchronized void notify_listeners(int status) {
+ this.status = status;
+ for (AltosMapStoreListener listener : listeners)
+ listener.notify_store(this, status);
+ }
+
+ static Object forbidden_lock = new Object();
+ static long forbidden_time;
+ static boolean forbidden_set;
+
+ private int fetch_url() {
+ URL u;
+
+ try {
+ u = new URL(url);
+ } catch (java.net.MalformedURLException e) {
+ return AltosMapTile.bad_request;
+ }
+
+ byte[] data;
+ URLConnection uc = null;
+ try {
+ uc = u.openConnection();
+ String type = uc.getContentType();
+ int contentLength = uc.getContentLength();
+ if (uc instanceof HttpURLConnection) {
+ int response = ((HttpURLConnection) uc).getResponseCode();
+ switch (response) {
+ case HttpURLConnection.HTTP_FORBIDDEN:
+ case HttpURLConnection.HTTP_PAYMENT_REQUIRED:
+ case HttpURLConnection.HTTP_UNAUTHORIZED:
+ synchronized (forbidden_lock) {
+ forbidden_time = System.nanoTime();
+ forbidden_set = true;
+ return AltosMapTile.forbidden;
+ }
+ }
+ }
+ InputStream in = new BufferedInputStream(uc.getInputStream());
+ int bytesRead = 0;
+ int offset = 0;
+ data = new byte[contentLength];
+ while (offset < contentLength) {
+ bytesRead = in.read(data, offset, data.length - offset);
+ if (bytesRead == -1)
+ break;
+ offset += bytesRead;
+ }
+ in.close();
+
+ if (offset != contentLength)
+ return AltosMapTile.failed;
+
+ } catch (IOException e) {
+ return AltosMapTile.failed;
+ }
+
+ try {
+ FileOutputStream out = new FileOutputStream(file);
+ out.write(data);
+ out.flush();
+ out.close();
+ } catch (FileNotFoundException e) {
+ return AltosMapTile.bad_request;
+ } catch (IOException e) {
+ if (file.exists())
+ file.delete();
+ return AltosMapTile.bad_request;
+ }
+ return AltosMapTile.success;
+ }
+
+ static Object fetch_lock = new Object();
+
+ static final long forbidden_interval = 60l * 1000l * 1000l * 1000l;
+ static final long google_maps_ratelimit_ms = 1200;
+
+ class loader implements Runnable {
+
+ public void run() {
+ if (file.exists()) {
+ notify_listeners(AltosMapTile.success);
+ return;
+ }
+
+ synchronized(forbidden_lock) {
+ if (forbidden_set && (System.nanoTime() - forbidden_time) < forbidden_interval) {
+ notify_listeners(AltosMapTile.forbidden);
+ return;
+ }
+ }
+
+ int new_status;
+
+ if (!AltosVersion.has_google_maps_api_key()) {
+ synchronized (fetch_lock) {
+ long startTime = System.nanoTime();
+ new_status = fetch_url();
+ if (new_status == AltosMapTile.success) {
+ long duration_ms = (System.nanoTime() - startTime) / 1000000;
+ if (duration_ms < google_maps_ratelimit_ms) {
+ try {
+ Thread.sleep(google_maps_ratelimit_ms - duration_ms);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+ } else {
+ new_status = fetch_url();
+ }
+ notify_listeners(new_status);
+ }
+ }
+
+ private void load() {
+ loader l = new loader();
+ Thread lt = new Thread(l);
+ lt.start();
+ }
+
+ private AltosMapStore (String url, File file) {
+ this.url = url;
+ this.file = file;
+
+ if (file.exists())
+ status = AltosMapTile.success;
+ else {
+ status = AltosMapTile.loading;
+ load();
+ }
+ }
+
+ public boolean equals(AltosMapStore other) {
+ return url.equals(other.url);
+ }
+
+ static HashMap<String,AltosMapStore> stores = new HashMap<String,AltosMapStore>();
+
+ public static AltosMapStore get(String url, File file) {
+ AltosMapStore store;
+ synchronized(stores) {
+ if (stores.containsKey(url)) {
+ store = stores.get(url);
+ } else {
+ store = new AltosMapStore(url, file);
+ stores.put(url, store);
+ }
+ }
+ return store;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+public interface AltosMapStoreListener {
+ abstract void notify_store(AltosMapStore store, int status);
+}
--- /dev/null
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+import java.io.*;
+import java.util.*;
+
+public class AltosMapTile implements AltosFontListener {
+ AltosMapTileListener listener;
+ AltosLatLon upper_left, center;
+ int px_size;
+ int zoom;
+ int maptype;
+ AltosMapStore store;
+ AltosMapCache cache;
+ int status;
+
+ static public final int success = 0;
+ static public final int loading = 1;
+ static public final int failed = 2;
+ static public final int bad_request = 3;
+ static public final int forbidden = 4;
+
+ private File map_file() {
+ double lat = center.lat;
+ double lon = center.lon;
+ char chlat = lat < 0 ? 'S' : 'N';
+ char chlon = lon < 0 ? 'W' : 'E';
+
+ if (lat < 0) lat = -lat;
+ if (lon < 0) lon = -lon;
+ String maptype_string = String.format("%s-", AltosMap.maptype_names[maptype]);
+ String format_string;
+ if (maptype == AltosMap.maptype_hybrid || maptype == AltosMap.maptype_satellite || maptype == AltosMap.maptype_terrain)
+ format_string = "jpg";
+ else
+ format_string = "png";
+ return new File(AltosPreferences.mapdir(),
+ String.format("map-%c%.6f,%c%.6f-%s%d.%s",
+ chlat, lat, chlon, lon, maptype_string, zoom, format_string));
+ }
+
+ private String map_url() {
+ String format_string;
+ if (maptype == AltosMap.maptype_hybrid || maptype == AltosMap.maptype_satellite || maptype == AltosMap.maptype_terrain)
+ format_string = "jpg";
+ else
+ format_string = "png32";
+
+ if (AltosVersion.has_google_maps_api_key())
+ return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=%s&format=%s&key=%s",
+ center.lat, center.lon, zoom, px_size, px_size, AltosMap.maptype_names[maptype], format_string, AltosVersion.google_maps_api_key);
+ else
+ return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=%s&format=%s",
+ center.lat, center.lon, zoom, px_size, px_size, AltosMap.maptype_names[maptype], format_string);
+ }
+
+ public void font_size_changed(int font_size) {
+ }
+
+ public void set_status(int status) {
+ this.status = status;
+ listener.notify_tile(this, status);
+ }
+
+ public void notify_image(AltosImage image) {
+ listener.notify_tile(this, status);
+ }
+
+ public int store_status() {
+ return store.status();
+ }
+
+ public void add_store_listener(AltosMapStoreListener listener) {
+ store.add_listener(listener);
+ }
+
+ public void remove_store_listener(AltosMapStoreListener listener) {
+ store.remove_listener(listener);
+ }
+
+ public AltosMapTile(AltosMapTileListener listener, AltosLatLon upper_left, AltosLatLon center, int zoom, int maptype, int px_size) {
+ this.listener = listener;
+ this.upper_left = upper_left;
+
+ while (center.lon < -180.0)
+ center.lon += 360.0;
+ while (center.lon > 180.0)
+ center.lon -= 360.0;
+
+ this.center = center;
+ this.zoom = zoom;
+ this.maptype = maptype;
+ this.px_size = px_size;
+
+ status = AltosMapTile.loading;
+ store = AltosMapStore.get(map_url(), map_file());
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+public interface AltosMapTileListener {
+ abstract public void notify_tile(AltosMapTile tile, int status);
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+import java.io.*;
+import java.lang.Math;
+import java.util.*;
+import java.util.concurrent.*;
+
+public class AltosMapTransform {
+
+ double scale_x, scale_y;
+
+ double offset_x, offset_y;
+
+ public AltosLatLon lat_lon (AltosPointDouble point) {
+ double lat, lon;
+ double rads;
+
+ lon = point.x/scale_x;
+ rads = 2 * Math.atan(Math.exp(-point.y/scale_y));
+ lat = Math.toDegrees(rads - Math.PI/2);
+
+ return new AltosLatLon(lat,lon);
+ }
+
+ public AltosPointDouble screen_point(AltosPointDouble screen) {
+ return new AltosPointDouble(screen.x + offset_x, screen.y + offset_y);
+ }
+
+ public AltosLatLon screen_lat_lon(AltosPointDouble screen) {
+ return lat_lon(screen_point(screen));
+ }
+
+ public AltosPointDouble point(AltosLatLon lat_lon) {
+ double x, y;
+ double e;
+
+ x = lat_lon.lon * scale_x;
+
+ e = Math.sin(Math.toRadians(lat_lon.lat));
+ e = Math.max(e,-(1-1.0E-15));
+ e = Math.min(e, 1-1.0E-15 );
+
+ y = 0.5*Math.log((1+e)/(1-e))*-scale_y;
+
+ return new AltosPointDouble(x, y);
+ }
+
+ public AltosPointDouble screen(AltosPointDouble point) {
+ return new AltosPointDouble(point.x - offset_x, point.y - offset_y);
+ }
+
+ public AltosPointInt screen(AltosPointInt point) {
+ return new AltosPointInt((int) (point.x - offset_x + 0.5),
+ (int) (point.y - offset_y + 0.5));
+ }
+
+// public Rectangle screen(AltosMapRectangle map_rect) {
+// AltosPoint2D ul = screen(map_rect.ul);
+// AltosPoint2D lr = screen(map_rect.lr);
+//
+// return new Rectangle((int) ul.x, (int) ul.y, (int) (lr.x - ul.x), (int) (lr.y - ul.y));
+// }
+
+ public AltosPointDouble screen(AltosLatLon lat_lon) {
+ return screen(point(lat_lon));
+ }
+
+ private boolean has_location;
+
+ public boolean has_location() {
+ return has_location;
+ }
+
+ public AltosMapTransform(int width, int height, int zoom, AltosLatLon centre_lat_lon) {
+ scale_x = 256/360.0 * Math.pow(2, zoom);
+ scale_y = 256/(2.0*Math.PI) * Math.pow(2, zoom);
+
+ AltosPointDouble centre_pt = point(centre_lat_lon);
+
+ has_location = (centre_lat_lon.lat != 0 || centre_lat_lon.lon != 0);
+ offset_x = centre_pt.x - width / 2.0;
+ offset_y = centre_pt.y - height / 2.0;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+public interface AltosMapZoomListener {
+ abstract public void zoom_changed(int zoom);
+}
--- /dev/null
+/*
+ * Copyright © 2015 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+public class AltosPointDouble {
+ public double x, y;
+
+ public boolean equals(AltosPointDouble n) {
+ return n.x == x && n.y == y;
+ }
+
+ public AltosPointDouble(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public AltosPointDouble(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public AltosPointDouble(AltosPointInt p) {
+ this.x = p.x;
+ this.y = p.y;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2015 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+public class AltosPointInt {
+ public int x, y;
+
+ public boolean equals(AltosPointInt n) {
+ return n.x == x && n.y == y;
+ }
+
+ public AltosPointInt(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+}
public final static String unitsPreference = "IMPERIAL-UNITS";
+ /* Maps cache size preference name */
+ final static String mapCachePreference = "MAP-CACHE";
+
+ static LinkedList<AltosMapCacheListener> map_cache_listeners;
+
+ public static int map_cache = 9;
+
public static AltosFrequency[] load_common_frequencies() {
AltosFrequency[] frequencies = null;
boolean existing = false;
common_frequencies = load_common_frequencies();
AltosConvert.imperial_units = backend.getBoolean(unitsPreference, false);
+
+ map_cache = backend.getInt(mapCachePreference, 9);
+ map_cache_listeners = new LinkedList<AltosMapCacheListener>();
}
public static void flush_preferences() {
units_listeners.remove(l);
}
}
+
+
+ public static void register_map_cache_listener(AltosMapCacheListener l) {
+ synchronized(backend) {
+ map_cache_listeners.add(l);
+ }
+ }
+
+ public static void unregister_map_cache_listener(AltosMapCacheListener l) {
+ synchronized (backend) {
+ map_cache_listeners.remove(l);
+ }
+ }
+
+ public static void set_map_cache(int new_map_cache) {
+ synchronized(backend) {
+ map_cache = new_map_cache;
+ backend.putInt(mapCachePreference, map_cache);
+ flush_preferences();
+ for (AltosMapCacheListener l: map_cache_listeners)
+ l.map_cache_changed(map_cache);
+ }
+ }
+
+ public static int map_cache() {
+ synchronized(backend) {
+ return map_cache;
+ }
+ }
}
--- /dev/null
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.altoslib_6;
+
+public class AltosVersion {
+ public final static String version = "@VERSION@";
+
+ public final static String google_maps_api_key = @GOOGLEKEY@;
+
+ static boolean has_google_maps_api_key() {
+ return google_maps_api_key != null && google_maps_api_key.length() > 1;
+ }
+}
AltosPyro.java \
AltosWriter.java \
AltosQuaternion.java \
- AltosRotation.java
+ AltosRotation.java \
+ AltosImage.java \
+ AltosLatLon.java \
+ AltosMap.java \
+ AltosMapCache.java \
+ AltosMapCacheListener.java \
+ AltosMapInterface.java \
+ AltosMapLine.java \
+ AltosMapMark.java \
+ AltosMapPath.java \
+ AltosMapRectangle.java \
+ AltosMapStore.java \
+ AltosMapStoreListener.java \
+ AltosMapTile.java \
+ AltosMapTileListener.java \
+ AltosMapTransform.java \
+ AltosMapZoomListener.java \
+ AltosPointDouble.java \
+ AltosPointInt.java \
+ AltosFlightDisplay.java \
+ AltosFontListener.java \
+ AltosVersion.java
JAR=altoslib_$(ALTOSLIB_VERSION).jar