altosdroid: fixup fetching active device address
[fw/altos] / altosuilib / AltosUIMapTile.java
1 /*
2  * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 package org.altusmetrum.altosuilib_3;
19
20 import java.awt.*;
21 import java.awt.image.*;
22 import javax.swing.*;
23 import javax.imageio.*;
24 import java.awt.geom.*;
25 import java.io.*;
26 import java.util.*;
27 import java.awt.RenderingHints.*;
28 import org.altusmetrum.altoslib_5.*;
29
30 public class AltosUIMapTile {
31         AltosUIMapTileListener  listener;
32         AltosUILatLon   upper_left, center;
33         int             px_size;
34         int             zoom;
35         int             maptype;
36         AltosUIMapStore store;
37         AltosUIMapCache cache;
38         int             status;
39
40         private File map_file() {
41                 double lat = center.lat;
42                 double lon = center.lon;
43                 char chlat = lat < 0 ? 'S' : 'N';
44                 char chlon = lon < 0 ? 'W' : 'E';
45
46                 if (lat < 0) lat = -lat;
47                 if (lon < 0) lon = -lon;
48                 String maptype_string = String.format("%s-", AltosUIMap.maptype_names[maptype]);
49                 String format_string;
50                 if (maptype == AltosUIMap.maptype_hybrid || maptype == AltosUIMap.maptype_satellite || maptype == AltosUIMap.maptype_terrain)
51                         format_string = "jpg";
52                 else
53                         format_string = "png";
54                 return new File(AltosUIPreferences.mapdir(),
55                                 String.format("map-%c%.6f,%c%.6f-%s%d.%s",
56                                               chlat, lat, chlon, lon, maptype_string, zoom, format_string));
57         }
58
59         private String map_url() {
60                 String format_string;
61                 if (maptype == AltosUIMap.maptype_hybrid || maptype == AltosUIMap.maptype_satellite || maptype == AltosUIMap.maptype_terrain)
62                         format_string = "jpg";
63                 else
64                         format_string = "png32";
65
66                 if (AltosUIVersion.has_google_maps_api_key())
67                         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",
68                                              center.lat, center.lon, zoom, px_size, px_size, AltosUIMap.maptype_names[maptype], format_string, AltosUIVersion.google_maps_api_key);
69                 else
70                         return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=%s&format=%s",
71                                              center.lat, center.lon, zoom, px_size, px_size, AltosUIMap.maptype_names[maptype], format_string);
72         }
73         private Font    font = null;
74
75         public void set_font(Font font) {
76                 this.font = font;
77         }
78
79         int     painting_serial;
80         int     painted_serial;
81
82         Image   image;
83
84         public void paint_graphics(Graphics2D g2d, AltosUIMapTransform t, int serial) {
85                 if (serial < painted_serial)
86                         return;
87
88                 Point2D.Double  point_double = t.screen(upper_left);
89                 Point           point = new Point((int) (point_double.x + 0.5),
90                                                   (int) (point_double.y + 0.5));
91
92                 painted_serial = serial;
93
94                 if (!g2d.hitClip(point.x, point.y, px_size, px_size))
95                         return;
96
97                 if (image != null) {
98                         g2d.drawImage(image, point.x, point.y, null);
99                         image = null;
100                 } else {
101                         g2d.setColor(Color.GRAY);
102                         g2d.fillRect(point.x, point.y, px_size, px_size);
103
104                         if (t.has_location()) {
105                                 String  message = null;
106                                 switch (status) {
107                                 case AltosUIMapCache.loading:
108                                         message = "Loading...";
109                                         break;
110                                 case AltosUIMapCache.bad_request:
111                                         message = "Internal error";
112                                         break;
113                                 case AltosUIMapCache.failed:
114                                         message = "Network error, check connection";
115                                         break;
116                                 case AltosUIMapCache.forbidden:
117                                         message = "Too many requests, try later";
118                                         break;
119                                 }
120                                 if (message != null && font != null) {
121                                         g2d.setFont(font);
122                                         g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
123                                         Rectangle2D bounds = font.getStringBounds(message, g2d.getFontRenderContext());
124
125                                         float x = px_size / 2.0f;
126                                         float y = px_size / 2.0f;
127                                         x = x - (float) bounds.getWidth() / 2.0f;
128                                         y = y + (float) bounds.getHeight() / 2.0f;
129                                         g2d.setColor(Color.BLACK);
130                                         g2d.drawString(message, (float) point_double.x + x, (float) point_double.y + y);
131                                 }
132                         }
133                 }
134         }
135
136         public void set_status(int status) {
137                 this.status = status;
138                 listener.notify_tile(this, status);
139         }
140
141         public void notify_image(Image image) {
142                 listener.notify_tile(this, status);
143         }
144
145         public void paint(Graphics g, AltosUIMapTransform t) {
146                 Graphics2D              g2d = (Graphics2D) g;
147                 boolean                 queued = false;
148
149                 Point2D.Double  point = t.screen(upper_left);
150
151                 if (!g.hitClip((int) (point.x + 0.5), (int) (point.y + 0.5), px_size, px_size))
152                         return;
153
154                 ++painting_serial;
155
156                 if (image == null && t.has_location())
157                         image = cache.get(this, store, px_size, px_size);
158
159                 paint_graphics(g2d, t, painting_serial);
160         }
161
162         public int store_status() {
163                 return store.status();
164         }
165
166         public void add_store_listener(AltosUIMapStoreListener listener) {
167                 store.add_listener(listener);
168         }
169
170         public void remove_store_listener(AltosUIMapStoreListener listener) {
171                 store.remove_listener(listener);
172         }
173
174         public AltosUIMapTile(AltosUIMapTileListener listener, AltosUILatLon upper_left, AltosUILatLon center, int zoom, int maptype, int px_size, Font font) {
175                 this.listener = listener;
176                 this.upper_left = upper_left;
177                 cache = listener.cache();
178
179                 while (center.lon < -180.0)
180                         center.lon += 360.0;
181                 while (center.lon > 180.0)
182                         center.lon -= 360.0;
183
184                 this.center = center;
185                 this.zoom = zoom;
186                 this.maptype = maptype;
187                 this.px_size = px_size;
188                 this.font = font;
189                 status = AltosUIMapCache.loading;
190                 store = AltosUIMapStore.get(map_url(), map_file());
191         }
192 }