Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2021 James Westman <james@jwestman.net>
3 : : *
4 : : * This library is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * This library is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : : * Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with this library; if not, see <https://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : typedef struct {
19 : : int min_zoom_level;
20 : : int max_zoom_level;
21 : : } ShumateDataSourcePrivate;
22 : :
23 : : #include "shumate-data-source.h"
24 : : #include "shumate-data-source-request.h"
25 : :
26 : : /**
27 : : * ShumateDataSource:
28 : : *
29 : : * The base class used to retrieve tiles as [struct@GLib.Bytes].
30 : : */
31 : :
32 [ + + + - ]: 191 : G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ShumateDataSource, shumate_data_source, G_TYPE_OBJECT)
33 : :
34 : : enum {
35 : : PROP_0,
36 : : PROP_MIN_ZOOM_LEVEL,
37 : : PROP_MAX_ZOOM_LEVEL,
38 : : N_PROPS,
39 : : };
40 : :
41 : : static GParamSpec *properties[N_PROPS];
42 : :
43 : : enum
44 : : {
45 : : RECEIVED_DATA,
46 : : LAST_SIGNAL
47 : : };
48 : : static guint signals[LAST_SIGNAL] = { 0, };
49 : :
50 : :
51 : : static void
52 : 0 : shumate_data_source_get_property (GObject *object,
53 : : guint prop_id,
54 : : GValue *value,
55 : : GParamSpec *pspec)
56 : : {
57 : 0 : ShumateDataSource *data_source = SHUMATE_DATA_SOURCE (object);
58 : :
59 [ # # # ]: 0 : switch (prop_id)
60 : : {
61 : 0 : case PROP_MIN_ZOOM_LEVEL:
62 : 0 : g_value_set_uint (value, shumate_data_source_get_min_zoom_level (data_source));
63 : 0 : break;
64 : :
65 : 0 : case PROP_MAX_ZOOM_LEVEL:
66 : 0 : g_value_set_uint (value, shumate_data_source_get_max_zoom_level (data_source));
67 : 0 : break;
68 : :
69 : 0 : default:
70 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
71 : : }
72 : 0 : }
73 : :
74 : : static void
75 : 66 : shumate_data_source_set_property (GObject *object,
76 : : guint prop_id,
77 : : const GValue *value,
78 : : GParamSpec *pspec)
79 : : {
80 : 66 : ShumateDataSource *data_source = SHUMATE_DATA_SOURCE (object);
81 : :
82 [ + + - ]: 66 : switch (prop_id)
83 : : {
84 : 33 : case PROP_MIN_ZOOM_LEVEL:
85 : 33 : shumate_data_source_set_min_zoom_level (data_source,
86 : : g_value_get_uint (value));
87 : 33 : break;
88 : :
89 : 33 : case PROP_MAX_ZOOM_LEVEL:
90 : 33 : shumate_data_source_set_max_zoom_level (data_source,
91 : : g_value_get_uint (value));
92 : 33 : break;
93 : :
94 : 0 : default:
95 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
96 : : }
97 : 66 : }
98 : :
99 : : static GBytes *
100 : 0 : shumate_data_source_real_get_tile_data_finish (ShumateDataSource *self,
101 : : GAsyncResult *result,
102 : : GError **error)
103 : : {
104 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_DATA_SOURCE (self), FALSE);
105 [ # # ]: 0 : g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
106 : :
107 : 0 : return g_task_propagate_pointer (G_TASK (result), error);
108 : : }
109 : :
110 : : static void
111 : 0 : on_get_tile_data_done (GObject *source,
112 : : GAsyncResult *result,
113 : : gpointer user_data)
114 : : {
115 : 0 : ShumateDataSource *self = (ShumateDataSource *)source;
116 : 0 : g_autoptr(ShumateDataSourceRequest) req = user_data;
117 [ # # ]: 0 : g_autoptr(GError) error = NULL;
118 [ # # ]: 0 : g_autoptr(GBytes) data = NULL;
119 : :
120 : 0 : data = shumate_data_source_get_tile_data_finish (self, result, &error);
121 : :
122 [ # # ]: 0 : if (data)
123 : 0 : shumate_data_source_request_emit_data (req, data, TRUE);
124 : : else
125 : 0 : shumate_data_source_request_emit_error (req, error);
126 : 0 : }
127 : :
128 : : static ShumateDataSourceRequest *
129 : 0 : shumate_data_source_real_start_request (ShumateDataSource *self,
130 : : int x,
131 : : int y,
132 : : int zoom_level,
133 : : GCancellable *cancellable)
134 : : {
135 : 0 : ShumateDataSourceRequest *req = shumate_data_source_request_new (x, y, zoom_level);
136 : 0 : shumate_data_source_get_tile_data_async (self,
137 : : x, y, zoom_level,
138 : : cancellable,
139 : : on_get_tile_data_done,
140 : : g_object_ref (req));
141 : 0 : return req;
142 : : }
143 : :
144 : : static void
145 : 10 : shumate_data_source_class_init (ShumateDataSourceClass *klass)
146 : : {
147 : 10 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
148 : :
149 : 10 : object_class->get_property = shumate_data_source_get_property;
150 : 10 : object_class->set_property = shumate_data_source_set_property;
151 : :
152 : 10 : klass->get_tile_data_async = NULL;
153 : 10 : klass->get_tile_data_finish = shumate_data_source_real_get_tile_data_finish;
154 : 10 : klass->start_request = shumate_data_source_real_start_request;
155 : :
156 : : /**
157 : : * ShumateDataSource:min-zoom-level:
158 : : *
159 : : * The minimum zoom level
160 : : *
161 : : * Since: 1.1
162 : : */
163 : 20 : properties[PROP_MIN_ZOOM_LEVEL] =
164 : 10 : g_param_spec_uint ("min-zoom-level",
165 : : "min-zoom-level",
166 : : "min-zoom-level",
167 : : 0, 30, 0,
168 : : G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
169 : :
170 : : /**
171 : : * ShumateDataSource:max-zoom-level:
172 : : *
173 : : * The maximum zoom level
174 : : *
175 : : * Since: 1.1
176 : : */
177 : 20 : properties[PROP_MAX_ZOOM_LEVEL] =
178 : 10 : g_param_spec_uint ("max-zoom-level",
179 : : "max-zoom-level",
180 : : "max-zoom-level",
181 : : 0, 30, 30,
182 : : G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
183 : :
184 : 10 : g_object_class_install_properties (object_class,
185 : : N_PROPS,
186 : : properties);
187 : :
188 : : /**
189 : : * ShumateDataSource::received-data:
190 : : * @self: the [class@DataSource] emitting the signal
191 : : * @x: the X coordinate of the tile
192 : : * @y: the Y coordinate of the tile
193 : : * @zoom_level: the zoom level of the tile
194 : : * @bytes: the received data
195 : : *
196 : : * Emitted when data is received for any tile. This includes any intermediate
197 : : * steps, such as data from the file cache, as well as the final result.
198 : : *
199 : : * Deprecated: 1.1: Use [method@DataSource.start_request] and connect to the
200 : : * notify signals of the resulting [class@DataSourceRequest].
201 : : */
202 : 20 : signals[RECEIVED_DATA] =
203 : 10 : g_signal_new ("received-data",
204 : : G_OBJECT_CLASS_TYPE (object_class),
205 : : G_SIGNAL_RUN_LAST | G_SIGNAL_DEPRECATED,
206 : : 0, NULL, NULL,
207 : : NULL,
208 : : G_TYPE_NONE,
209 : : 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_BYTES);
210 : 10 : }
211 : :
212 : : static void
213 : 33 : shumate_data_source_init (ShumateDataSource *self)
214 : : {
215 : 33 : }
216 : :
217 : :
218 : : /**
219 : : * shumate_data_source_get_tile_data_async:
220 : : * @self: a [class@DataSource]
221 : : * @x: the X coordinate to fetch
222 : : * @y: the Y coordinate to fetch
223 : : * @zoom_level: the Z coordinate to fetch
224 : : * @cancellable: a #GCancellable
225 : : * @callback: a #GAsyncReadyCallback to execute upon completion
226 : : * @user_data: closure data for @callback
227 : : *
228 : : * Gets the data for the tile at the given coordinates.
229 : : *
230 : : * Some data sources may return data multiple times. For example,
231 : : * [class@TileDownloader] may return data from a cache, then return updated
232 : : * data from the network. [signal@ShumateDataSource::received-data] is emitted
233 : : * each time data is received, then @callback is called after the last update.
234 : : */
235 : : void
236 : 0 : shumate_data_source_get_tile_data_async (ShumateDataSource *self,
237 : : int x,
238 : : int y,
239 : : int zoom_level,
240 : : GCancellable *cancellable,
241 : : GAsyncReadyCallback callback,
242 : : gpointer user_data)
243 : : {
244 [ # # ]: 0 : g_return_if_fail (SHUMATE_IS_DATA_SOURCE (self));
245 [ # # # # : 0 : g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
# # # # ]
246 : :
247 : 0 : return SHUMATE_DATA_SOURCE_GET_CLASS (self)->get_tile_data_async (self, x, y, zoom_level, cancellable, callback, user_data);
248 : : }
249 : :
250 : :
251 : : /**
252 : : * shumate_data_source_get_tile_data_finish:
253 : : * @self: a [class@DataSource]
254 : : * @result: a #GAsyncResult provided to callback
255 : : * @error: a location for a #GError, or %NULL
256 : : *
257 : : * Gets the final result of a request started with
258 : : * shumate_data_source_get_tile_data_async().
259 : : *
260 : : * Returns: (transfer full) (nullable): The requested data, or %NULL if an
261 : : * error occurred
262 : : */
263 : : GBytes *
264 : 0 : shumate_data_source_get_tile_data_finish (ShumateDataSource *self,
265 : : GAsyncResult *result,
266 : : GError **error)
267 : : {
268 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_DATA_SOURCE (self), FALSE);
269 : :
270 : 0 : return SHUMATE_DATA_SOURCE_GET_CLASS (self)->get_tile_data_finish (self, result, error);
271 : : }
272 : :
273 : :
274 : : /**
275 : : * shumate_data_source_start_request:
276 : : * @self: a [class@DataSource]
277 : : * @x: X coordinate to request
278 : : * @y: Y coordinate to request
279 : : * @zoom_level: zoom level to request
280 : : * @cancellable: for cancelling the request
281 : : *
282 : : * Begins a request for a tile.
283 : : *
284 : : * Returns: (transfer full): a [class@DataSourceRequest] object for tracking
285 : : * the request.
286 : : *
287 : : * Since: 1.1
288 : : */
289 : : ShumateDataSourceRequest *
290 : 0 : shumate_data_source_start_request (ShumateDataSource *self,
291 : : int x,
292 : : int y,
293 : : int zoom_level,
294 : : GCancellable *cancellable)
295 : : {
296 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_DATA_SOURCE (self), NULL);
297 : :
298 : 0 : return SHUMATE_DATA_SOURCE_GET_CLASS (self)->start_request (self, x, y, zoom_level, cancellable);
299 : : }
300 : :
301 : :
302 : : /**
303 : : * shumate_data_source_get_min_zoom_level:
304 : : * @self: a [class@DataSource]
305 : : *
306 : : * Gets the data source's minimum zoom level.
307 : : *
308 : : * Returns: the minimum zoom level this data source supports
309 : : *
310 : : * Since: 1.1
311 : : */
312 : : guint
313 : 0 : shumate_data_source_get_min_zoom_level (ShumateDataSource *self)
314 : : {
315 : 0 : ShumateDataSourcePrivate *priv = shumate_data_source_get_instance_private (self);
316 : :
317 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_DATA_SOURCE (self), 0);
318 : :
319 : 0 : return priv->min_zoom_level;
320 : : }
321 : :
322 : : /**
323 : : * shumate_data_source_set_min_zoom_level:
324 : : * @self: a [class@DataSource]
325 : : * @zoom_level: the minimum zoom level
326 : : *
327 : : * Sets the data source's minimum zoom level.
328 : : *
329 : : * Since: 1.1
330 : : */
331 : : void
332 : 39 : shumate_data_source_set_min_zoom_level (ShumateDataSource *self,
333 : : guint zoom_level)
334 : : {
335 : 39 : ShumateDataSourcePrivate *priv = shumate_data_source_get_instance_private (self);
336 : :
337 [ + - ]: 39 : g_return_if_fail (SHUMATE_IS_DATA_SOURCE (self));
338 [ - + ]: 39 : g_return_if_fail (zoom_level <= 30u);
339 : :
340 [ - + ]: 39 : if (priv->min_zoom_level != zoom_level)
341 : : {
342 : 0 : priv->min_zoom_level = zoom_level;
343 : :
344 : 0 : g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MIN_ZOOM_LEVEL]);
345 : : }
346 : : }
347 : :
348 : : /**
349 : : * shumate_data_source_get_max_zoom_level:
350 : : * @self: a [class@DataSource]
351 : : *
352 : : * Gets the data source's maximum zoom level.
353 : : *
354 : : * Returns: the maximum zoom level this data source supports
355 : : *
356 : : * Since: 1.1
357 : : */
358 : : guint
359 : 0 : shumate_data_source_get_max_zoom_level (ShumateDataSource *self)
360 : : {
361 : 0 : ShumateDataSourcePrivate *priv = shumate_data_source_get_instance_private (self);
362 : :
363 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_DATA_SOURCE (self), 0);
364 : :
365 : 0 : return priv->max_zoom_level;
366 : : }
367 : :
368 : : /**
369 : : * shumate_data_source_set_max_zoom_level:
370 : : * @self: a [class@DataSource]
371 : : * @zoom_level: the maximum zoom level
372 : : *
373 : : * Sets the data source's maximum zoom level.
374 : : *
375 : : * Since: 1.1
376 : : */
377 : : void
378 : 39 : shumate_data_source_set_max_zoom_level (ShumateDataSource *self,
379 : : guint zoom_level)
380 : : {
381 : 39 : ShumateDataSourcePrivate *priv = shumate_data_source_get_instance_private (self);
382 : :
383 [ + - ]: 39 : g_return_if_fail (SHUMATE_IS_DATA_SOURCE (self));
384 [ - + ]: 39 : g_return_if_fail (zoom_level <= 30u);
385 : :
386 [ + + ]: 39 : if (priv->max_zoom_level != zoom_level)
387 : : {
388 : 33 : priv->max_zoom_level = zoom_level;
389 : :
390 : 33 : g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_ZOOM_LEVEL]);
391 : : }
392 : : }
393 : :
|