GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 20.7% 25 / 0 / 121
Functions: 22.7% 5 / 0 / 22
Branches: 8.7% 4 / 0 / 46

shumate/shumate-symbol-event.c
Line Branch Exec Source
1 /*
2 * Copyright (C) 2022 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 #include "shumate-location.h"
19 #include "shumate-symbol-event-private.h"
20
21 /**
22 * ShumateSymbolEvent:
23 *
24 * An object containing the details of a map feature that has been clicked.
25 * It is the argument of the [signal@MapLayer::symbol-clicked] and
26 * [signal@SimpleMap::symbol-clicked] signals.
27 *
28 * When vector maps are rendered, they may contain labels and icons. When one
29 * of these symbols is clicked, these signals are emitted to give the
30 * application access to the original location and details of the map feature.
31 *
32 * [class@SymbolEvent] implements [iface@Location] so you can get the latitude
33 * and longitude of the feature that was clicked.
34 *
35 * Since: 1.1
36 */
37
38 struct _ShumateSymbolEvent
39 {
40 GObject parent_instance;
41
42 char *layer;
43 char *source_layer;
44 char *feature_id;
45 double lat, lon;
46 GHashTable *tags;
47 gint n_press;
48 };
49
50 static void location_interface_init (ShumateLocationInterface *iface);
51
52
4/6
shumate_symbol_event_class_intern_init:
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
shumate_symbol_event_get_type:
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 7 taken 2 times.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 7 not taken.
5 G_DEFINE_FINAL_TYPE_WITH_CODE (ShumateSymbolEvent, shumate_symbol_event, G_TYPE_OBJECT,
53 G_IMPLEMENT_INTERFACE (SHUMATE_TYPE_LOCATION, location_interface_init))
54
55 enum {
56 PROP_0,
57 PROP_LAYER,
58 PROP_SOURCE_LAYER,
59 PROP_FEATURE_ID,
60 PROP_N_PRESS,
61 N_PROPS,
62
63 PROP_LONGITUDE,
64 PROP_LATITUDE,
65 };
66
67 static GParamSpec *properties [N_PROPS];
68
69 static void
70 ✗ shumate_symbol_event_finalize (GObject *object)
71 {
72 ✗ ShumateSymbolEvent *self = (ShumateSymbolEvent *)object;
73
74 ✗ g_clear_pointer (&self->layer, g_free);
75 ✗ g_clear_pointer (&self->source_layer, g_free);
76 ✗ g_clear_pointer (&self->feature_id, g_free);
77 ✗ g_clear_pointer (&self->tags, g_hash_table_unref);
78
79 ✗ G_OBJECT_CLASS (shumate_symbol_event_parent_class)->finalize (object);
80 ✗ }
81
82 static void
83 ✗ shumate_symbol_event_get_property (GObject *object,
84 guint prop_id,
85 GValue *value,
86 GParamSpec *pspec)
87 {
88 ✗ ShumateSymbolEvent *self = SHUMATE_SYMBOL_EVENT (object);
89
90 ✗ switch (prop_id)
91 {
92 ✗ case PROP_LAYER:
93 ✗ g_value_set_string (value, self->layer);
94 ✗ break;
95 ✗ case PROP_SOURCE_LAYER:
96 ✗ g_value_set_string (value, self->source_layer);
97 ✗ break;
98 ✗ case PROP_FEATURE_ID:
99 ✗ g_value_set_string (value, self->feature_id);
100 ✗ break;
101 ✗ case PROP_LATITUDE:
102 ✗ g_value_set_double (value, self->lat);
103 ✗ break;
104 ✗ case PROP_LONGITUDE:
105 ✗ g_value_set_double (value, self->lon);
106 ✗ break;
107 ✗ case PROP_N_PRESS:
108 ✗ g_value_set_int (value, self->n_press);
109 ✗ break;
110 ✗ default:
111 ✗ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
112 }
113 ✗ }
114
115 static void
116 ✗ shumate_symbol_event_set_property (GObject *object,
117 guint prop_id,
118 const GValue *value,
119 GParamSpec *pspec)
120 {
121 ✗ ShumateSymbolEvent *symbol_event = SHUMATE_SYMBOL_EVENT (object);
122
123 ✗ switch (prop_id)
124 {
125 ✗ case PROP_LATITUDE:
126 case PROP_LONGITUDE:
127 ✗ g_warning ("Cannot change the location of a ShumateSymbolEvent");
128 ✗ break;
129 ✗ case PROP_N_PRESS:
130 ✗ shumate_symbol_event_set_n_press (symbol_event, g_value_get_int (value));
131 ✗ break;
132 ✗ default:
133 ✗ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
134 }
135 ✗ }
136
137 static void
138 1 shumate_symbol_event_class_init (ShumateSymbolEventClass *klass)
139 {
140 1 GObjectClass *object_class = G_OBJECT_CLASS (klass);
141
142 1 object_class->finalize = shumate_symbol_event_finalize;
143 1 object_class->get_property = shumate_symbol_event_get_property;
144 1 object_class->set_property = shumate_symbol_event_set_property;
145
146 /**
147 * ShumateSymbolEvent:layer:
148 *
149 * The ID of the style layer of the symbol that this event pertains to.
150 *
151 * Since: 1.1
152 */
153 2 properties[PROP_LAYER] =
154 1 g_param_spec_string ("layer", NULL, NULL,
155 NULL,
156 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
157
158 /**
159 * ShumateSymbolEvent:source-layer:
160 *
161 * The ID of the source layer of the symbol that this event pertains to.
162 */
163 2 properties[PROP_SOURCE_LAYER] =
164 1 g_param_spec_string ("source-layer", NULL, NULL,
165 NULL,
166 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
167
168 /**
169 * ShumateSymbolEvent:feature-id:
170 *
171 * The ID of the feature that this event pertains to, as it was given in the
172 * data source.
173 *
174 * Since: 1.1
175 */
176 2 properties[PROP_FEATURE_ID] =
177 1 g_param_spec_string ("feature-id", NULL, NULL,
178 NULL,
179 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
180
181 /**
182 * ShumateSymbolEvent:n-press:
183 *
184 * The number of clicks/presses triggering the symbol event.
185 *
186 * Since: 1.5
187 */
188 2 properties[PROP_N_PRESS] =
189 1 g_param_spec_uint ("n-press", NULL, NULL,
190 1,
191 INT_MAX,
192 1,
193 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
194
195 1 g_object_class_install_properties (object_class, N_PROPS, properties);
196
197 1 g_object_class_override_property (object_class,
198 PROP_LONGITUDE,
199 "longitude");
200
201 1 g_object_class_override_property (object_class,
202 PROP_LATITUDE,
203 "latitude");
204 1 }
205
206 static void
207 ✗ shumate_symbol_event_init (ShumateSymbolEvent *self)
208 {
209 ✗ self->tags = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
210 ✗ }
211
212 static double
213 ✗ shumate_symbol_event_get_latitude (ShumateLocation *location)
214 {
215 ✗ ShumateSymbolEvent *self = (ShumateSymbolEvent *) location;
216 ✗ return self->lat;
217 }
218
219 static double
220 ✗ shumate_symbol_event_get_longitude (ShumateLocation *location)
221 {
222 ✗ ShumateSymbolEvent *self = (ShumateSymbolEvent *) location;
223 ✗ return self->lon;
224 }
225
226 static void
227 ✗ shumate_symbol_event_set_location (ShumateLocation *location,
228 double lat,
229 double lon)
230 {
231 ✗ g_warning ("Cannot change the location of a ShumateSymbolEvent");
232 ✗ }
233
234 static void
235 1 location_interface_init (ShumateLocationInterface *iface)
236 {
237 1 iface->get_latitude = shumate_symbol_event_get_latitude;
238 1 iface->get_longitude = shumate_symbol_event_get_longitude;
239 1 iface->set_location = shumate_symbol_event_set_location;
240 1 }
241
242 /**
243 * shumate_symbol_event_get_layer:
244 * @self: a [class@SymbolEvent]
245 *
246 * Gets the name of the layer the clicked symbol is in, as named in the vector
247 * stylesheet.
248 *
249 * Note that this is distinct from the name of the layer in the vector tile
250 * schema. Some styles have multiple symbol layers derived from the same
251 * data source layer.
252 *
253 * Returns: (transfer none): the layer name
254 *
255 * Since: 1.1
256 */
257 const char *
258 ✗ shumate_symbol_event_get_layer (ShumateSymbolEvent *self)
259 {
260 ✗ g_return_val_if_fail (SHUMATE_IS_SYMBOL_EVENT (self), NULL);
261 ✗ return self->layer;
262 }
263
264 /**
265 * shumate_symbol_event_get_source_layer:
266 * @self: a [class@SymbolEvent]
267 *
268 * Gets the name of the source layer the clicked feature is in,
269 * as named in the vector tile schema.
270 *
271 * Returns: (transfer none): the layer name
272 *
273 * Since: 1.1
274 */
275 const char *
276 ✗ shumate_symbol_event_get_source_layer (ShumateSymbolEvent *self)
277 {
278 ✗ g_return_val_if_fail (SHUMATE_IS_SYMBOL_EVENT (self), NULL);
279 ✗ return self->source_layer;
280 }
281
282 /**
283 * shumate_symbol_event_get_feature_id:
284 * @self: a [class@SymbolEvent]
285 *
286 * Gets the feature ID as specified in the data source. The meaning of the
287 * ID, if any, is up to the source.
288 *
289 * Feature IDs in Mapbox Vector Tile format are integers, but they are
290 * formatted as a string here for futureproofing.
291 *
292 * Returns: (transfer none): the feature ID
293 *
294 * Since: 1.1
295 */
296 const char *
297 ✗ shumate_symbol_event_get_feature_id (ShumateSymbolEvent *self)
298 {
299 ✗ g_return_val_if_fail (SHUMATE_IS_SYMBOL_EVENT (self), NULL);
300 ✗ return self->feature_id;
301 }
302
303 /**
304 * shumate_symbol_event_get_keys:
305 * @self: a [class@SymbolEvent]
306 *
307 * Gets a list of the keys of the source feature's tags.
308 *
309 * Returns: (transfer container): a list of the tag keys
310 *
311 * Since: 1.1
312 */
313 const GStrv
314 ✗ shumate_symbol_event_get_keys (ShumateSymbolEvent *self)
315 {
316 ✗ g_return_val_if_fail (SHUMATE_IS_SYMBOL_EVENT (self), NULL);
317 ✗ return (GStrv)g_hash_table_get_keys_as_array (self->tags, NULL);
318 }
319
320 /**
321 * shumate_symbol_event_get_tag:
322 * @self: a [class@SymbolEvent]
323 * @tag_name: the tag to get
324 *
325 * Gets a tag from the source feature.
326 *
327 * The available tags depend on the vector tile schema and the source layer.
328 * Check the documentation for the tiles you're using to see what information
329 * is available.
330 *
331 * Returns: (transfer none): the tag value, formatted as a string
332 *
333 * Since: 1.1
334 */
335 const char *
336 ✗ shumate_symbol_event_get_tag (ShumateSymbolEvent *self,
337 const char *tag_name)
338 {
339 ✗ g_return_val_if_fail (SHUMATE_IS_SYMBOL_EVENT (self), NULL);
340 ✗ return g_hash_table_lookup (self->tags, tag_name);
341 }
342
343 ShumateSymbolEvent *
344 ✗ shumate_symbol_event_new (const char *layer,
345 const char *source_layer,
346 const char *feature_id,
347 GHashTable *tags)
348 {
349 ✗ ShumateSymbolEvent *self = g_object_new (SHUMATE_TYPE_SYMBOL_EVENT, NULL);
350
351 ✗ self->layer = g_strdup (layer);
352 ✗ self->source_layer = g_strdup (source_layer);
353 ✗ self->feature_id = g_strdup (feature_id);
354 ✗ self->tags = g_hash_table_ref (tags);
355 ✗ self->n_press = 1;
356
357 ✗ return self;
358 }
359
360 ShumateSymbolEvent *
361 ✗ shumate_symbol_event_new_with_n_press (const char *layer,
362 const char *source_layer,
363 const char *feature_id,
364 GHashTable *tags,
365 gint n_press)
366 {
367 ✗ ShumateSymbolEvent *self = g_object_new (SHUMATE_TYPE_SYMBOL_EVENT, NULL);
368
369 ✗ self->layer = g_strdup (layer);
370 ✗ self->source_layer = g_strdup (source_layer);
371 ✗ self->feature_id = g_strdup (feature_id);
372 ✗ self->tags = g_hash_table_ref (tags);
373 ✗ self->n_press = n_press;
374
375 ✗ return self;
376 }
377
378 void
379 ✗ shumate_symbol_event_set_lat_lon (ShumateSymbolEvent *self,
380 double lat,
381 double lon)
382 {
383 ✗ self->lat = lat;
384 ✗ self->lon = lon;
385 ✗ }
386
387 /**
388 * shumate_symbol_event_get_n_press:
389 * @self: a [class@SymbolEvent]
390 *
391 * Gets the number of clicks/presses that initiated the event.
392 *
393 * Returns: the number of presses
394 *
395 * Since: 1.5
396 */
397 gint
398 ✗ shumate_symbol_event_get_n_press (ShumateSymbolEvent *self)
399 {
400 ✗ return self->n_press;
401 }
402
403 /**
404 * shumate_symbol_event_set_n_press:
405 * @self: a [class@SymbolEvent]
406 * @n_press: the number of presses of the event
407 *
408 * Sets the number of clicks/presses that initiated the event.
409 *
410 *
411 * Since: 1.5
412 */
413 void
414 ✗ shumate_symbol_event_set_n_press (ShumateSymbolEvent *self, gint n_press)
415 {
416 ✗ self->n_press = n_press;
417 ✗ }
418