]> git.street.me.uk Git - andy/viking.git/blame - src/vikaggregatelayer.c
Prevent Gtk-CRITICAL **: gtk_list_store_get_path: assertion `iter->stamp == GTK_LIST_...
[andy/viking.git] / src / vikaggregatelayer.c
CommitLineData
50a14534
EB
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include "viking.h"
5bfafde9 23#include "icons/icons.h"
50a14534
EB
24
25#include <string.h>
26
27#define DISCONNECT_UPDATE_SIGNAL(vl, val) g_signal_handlers_disconnect_matched(vl, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, val)
28
0a6cab71
AF
29static void aggregate_layer_marshall( VikAggregateLayer *val, guint8 **data, gint *len );
30static VikAggregateLayer *aggregate_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
50a14534 31static void aggregate_layer_change_coord_mode ( VikAggregateLayer *val, VikCoordMode mode );
70a23263 32static void aggregate_layer_drag_drop_request ( VikAggregateLayer *val_src, VikAggregateLayer *val_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
50a14534
EB
33
34VikLayerInterface vik_aggregate_layer_interface = {
35 "Aggregate",
5bfafde9 36 &vikaggregatelayer_pixbuf,
50a14534
EB
37
38 NULL,
39 0,
40
41 NULL,
42 0,
43 NULL,
44 0,
45
5a4a28bf
QT
46 VIK_MENU_ITEM_ALL,
47
50a14534
EB
48 (VikLayerFuncCreate) vik_aggregate_layer_create,
49 (VikLayerFuncRealize) vik_aggregate_layer_realize,
50 (VikLayerFuncPostRead) NULL,
51 (VikLayerFuncFree) vik_aggregate_layer_free,
52
53 (VikLayerFuncProperties) NULL,
54 (VikLayerFuncDraw) vik_aggregate_layer_draw,
55 (VikLayerFuncChangeCoordMode) aggregate_layer_change_coord_mode,
20c7a3a0
QT
56
57 (VikLayerFuncSetMenuItemsSelection) NULL,
58 (VikLayerFuncGetMenuItemsSelection) NULL,
50a14534
EB
59
60 (VikLayerFuncAddMenuItems) NULL,
61 (VikLayerFuncSublayerAddMenuItems) NULL,
62
63 (VikLayerFuncSublayerRenameRequest) NULL,
64 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 65 (VikLayerFuncSublayerTooltip) NULL,
1e8b7f57 66 (VikLayerFuncLayerTooltip) NULL,
50a14534 67
0a6cab71
AF
68 (VikLayerFuncMarshall) aggregate_layer_marshall,
69 (VikLayerFuncUnmarshall) aggregate_layer_unmarshall,
50a14534
EB
70
71 (VikLayerFuncSetParam) NULL,
72 (VikLayerFuncGetParam) NULL,
73
74 (VikLayerFuncReadFileData) NULL,
75 (VikLayerFuncWriteFileData) NULL,
76
33534cd8 77 (VikLayerFuncDeleteItem) NULL,
50a14534
EB
78 (VikLayerFuncCopyItem) NULL,
79 (VikLayerFuncPasteItem) NULL,
80 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 81 (VikLayerFuncDragDropRequest) aggregate_layer_drag_drop_request,
50a14534
EB
82};
83
84struct _VikAggregateLayer {
85 VikLayer vl;
86 GList *children;
87};
88
89GType vik_aggregate_layer_get_type ()
90{
91 static GType val_type = 0;
92
93 if (!val_type)
94 {
95 static const GTypeInfo val_info =
96 {
97 sizeof (VikAggregateLayerClass),
98 NULL, /* base_init */
99 NULL, /* base_finalize */
100 NULL, /* class init */
101 NULL, /* class_finalize */
102 NULL, /* class_data */
103 sizeof (VikAggregateLayer),
104 0,
105 NULL /* instance init */
106 };
107 val_type = g_type_register_static ( VIK_LAYER_TYPE, "VikAggregateLayer", &val_info, 0 );
108 }
109
110 return val_type;
111}
112
113VikAggregateLayer *vik_aggregate_layer_create (VikViewport *vp)
114{
115 VikAggregateLayer *rv = vik_aggregate_layer_new ();
116 vik_layer_rename ( VIK_LAYER(rv), vik_aggregate_layer_interface.name );
117 return rv;
118}
119
0a6cab71
AF
120static void aggregate_layer_marshall( VikAggregateLayer *val, guint8 **data, gint *datalen )
121{
122 GList *child = val->children;
123 VikLayer *child_layer;
124 guint8 *ld;
125 gint ll;
126 GByteArray* b = g_byte_array_new ();
127 gint len;
128
129#define alm_append(obj, sz) \
130 len = (sz); \
131 g_byte_array_append ( b, (guint8 *)&len, sizeof(len) ); \
132 g_byte_array_append ( b, (guint8 *)(obj), len );
133
134 vik_layer_marshall_params(VIK_LAYER(val), &ld, &ll);
135 alm_append(ld, ll);
136 g_free(ld);
137
138 while (child) {
139 child_layer = VIK_LAYER(child->data);
140 vik_layer_marshall ( child_layer, &ld, &ll );
141 if (ld) {
142 alm_append(ld, ll);
143 g_free(ld);
144 }
145 child = child->next;
146 }
147 *data = b->data;
148 *datalen = b->len;
149 g_byte_array_free(b, FALSE);
150#undef alm_append
151}
152
153static VikAggregateLayer *aggregate_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
154{
155#define alm_size (*(gint *)data)
156#define alm_next \
157 len -= sizeof(gint) + alm_size; \
158 data += sizeof(gint) + alm_size;
159
160 VikAggregateLayer *rv = vik_aggregate_layer_new();
161 VikLayer *child_layer;
162
163 vik_layer_unmarshall_params ( VIK_LAYER(rv), data+sizeof(gint), alm_size, vvp );
164 alm_next;
165
166 while (len>0) {
167 child_layer = vik_layer_unmarshall ( data + sizeof(gint), alm_size, vvp );
168 if (child_layer) {
169 rv->children = g_list_append ( rv->children, child_layer );
0df66d57 170 g_signal_connect_swapped ( G_OBJECT(child_layer), "update", G_CALLBACK(vik_layer_emit_update_secondary), rv );
0a6cab71
AF
171 }
172 alm_next;
173 }
174 // g_print("aggregate_layer_unmarshall ended with len=%d\n", len);
175 return rv;
176#undef alm_size
177#undef alm_next
178}
179
50a14534
EB
180VikAggregateLayer *vik_aggregate_layer_new ()
181{
182 VikAggregateLayer *val = VIK_AGGREGATE_LAYER ( g_object_new ( VIK_AGGREGATE_LAYER_TYPE, NULL ) );
183 vik_layer_init ( VIK_LAYER(val), VIK_LAYER_AGGREGATE );
184 val->children = NULL;
185 return val;
186}
187
188void vik_aggregate_layer_insert_layer ( VikAggregateLayer *val, VikLayer *l, GtkTreeIter *replace_iter )
189{
50a14534 190 GtkTreeIter iter;
e673b75f 191
50a14534
EB
192 if ( VIK_LAYER(val)->realized )
193 {
194 vik_treeview_insert_layer ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter), &iter, l->name, val, l, l->type, l->type, replace_iter );
195 if ( ! l->visible )
196 vik_treeview_item_set_visible ( VIK_LAYER(val)->vt, &iter, FALSE );
197 vik_layer_realize ( l, VIK_LAYER(val)->vt, &iter );
198
199 if ( val->children == NULL )
200 vik_treeview_expand ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter) );
201 }
50a14534 202
e673b75f
AF
203 if (replace_iter) {
204 GList *theone = g_list_find ( val->children, vik_treeview_item_get_pointer ( VIK_LAYER(val)->vt, replace_iter ) );
205 val->children = g_list_insert ( val->children, l, g_list_position(val->children,theone)+1 );
206 } else {
207 val->children = g_list_append ( val->children, l );
208 }
0df66d57 209 g_signal_connect_swapped ( G_OBJECT(l), "update", G_CALLBACK(vik_layer_emit_update_secondary), val );
50a14534
EB
210}
211
212void vik_aggregate_layer_add_layer ( VikAggregateLayer *val, VikLayer *l )
213{
214 GtkTreeIter iter;
215
216 if ( VIK_LAYER(val)->realized )
217 {
218 vik_treeview_add_layer ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter), &iter, l->name, val, l, l->type, l->type);
219 if ( ! l->visible )
220 vik_treeview_item_set_visible ( VIK_LAYER(val)->vt, &iter, FALSE );
221 vik_layer_realize ( l, VIK_LAYER(val)->vt, &iter );
222
223 if ( val->children == NULL )
224 vik_treeview_expand ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter) );
225 }
226
227 val->children = g_list_append ( val->children, l );
0df66d57 228 g_signal_connect_swapped ( G_OBJECT(l), "update", G_CALLBACK(vik_layer_emit_update_secondary), val );
50a14534
EB
229}
230
231void vik_aggregate_layer_move_layer ( VikAggregateLayer *val, GtkTreeIter *child_iter, gboolean up )
232{
233 GList *theone, *first, *second;
234 vik_treeview_move_item ( VIK_LAYER(val)->vt, child_iter, up );
235
236 theone = g_list_find ( val->children, vik_treeview_item_get_pointer ( VIK_LAYER(val)->vt, child_iter ) );
237
238 g_assert ( theone != NULL );
239
240 /* the old switcheroo */
241 if ( up && theone->next )
242 {
243 first = theone;
244 second = theone->next;
245 }
246 else if ( !up && theone->prev )
247 {
248 first = theone->prev;
249 second = theone;
250 }
251 else
252 return;
253
254 first->next = second->next;
255 second->prev = first->prev;
256 first->prev = second;
257 second->next = first;
258
259 /* second is now first */
260
261 if ( second->prev )
262 second->prev->next = second;
263 if ( first->next )
264 first->next->prev = first;
265
266 if ( second->prev == NULL )
267 val->children = second;
268}
269
0df66d57
EB
270/* Draw the aggregate layer. If vik viewport is in half_drawn mode, this means we are only
271 * to draw the layers above and including the trigger layer.
272 * To do this we don't draw any layers if in half drawn mode, unless we find the
273 * trigger layer, in which case we pull up the saved pixmap, turn off half drawn mode and
274 * start drawing layers.
275 * Also, if we were never in half drawn mode, we save a snapshot
276 * of the pixmap before drawing the trigger layer so we can use it again
277 * later.
278 */
50a14534
EB
279void vik_aggregate_layer_draw ( VikAggregateLayer *val, gpointer data )
280{
0df66d57
EB
281 GList *iter = val->children;
282 VikLayer *vl;
283 VikLayer *trigger = VIK_LAYER(vik_viewport_get_trigger( VIK_VIEWPORT(data) ));
284 while ( iter ) {
285 vl = VIK_LAYER(iter->data);
286 if ( vl == trigger ) {
287 if ( vik_viewport_get_half_drawn ( VIK_VIEWPORT(data) ) ) {
288 vik_viewport_set_half_drawn ( VIK_VIEWPORT(data), FALSE );
289 vik_viewport_snapshot_load( VIK_VIEWPORT(data) );
290 } else {
291 vik_viewport_snapshot_save( VIK_VIEWPORT(data) );
292 }
293 }
8fcff869 294 if ( vl->type == VIK_LAYER_AGGREGATE || vl->type == VIK_LAYER_GPS || ! vik_viewport_get_half_drawn( VIK_VIEWPORT(data) ) )
0df66d57
EB
295 vik_layer_draw ( vl, data );
296 iter = iter->next;
297 }
50a14534
EB
298}
299
300static void aggregate_layer_change_coord_mode ( VikAggregateLayer *val, VikCoordMode mode )
301{
302 GList *iter = val->children;
303 while ( iter )
304 {
305 vik_layer_change_coord_mode ( VIK_LAYER(iter->data), mode );
306 iter = iter->next;
307 }
308}
309
310static void disconnect_layer_signal ( VikLayer *vl, VikAggregateLayer *val )
311{
312 g_assert(DISCONNECT_UPDATE_SIGNAL(vl,val)==1);
313}
314
315void vik_aggregate_layer_free ( VikAggregateLayer *val )
316{
317 g_list_foreach ( val->children, (GFunc)(disconnect_layer_signal), val );
318 g_list_foreach ( val->children, (GFunc)(g_object_unref), NULL );
319 g_list_free ( val->children );
320}
321
322static void delete_layer_iter ( VikLayer *vl )
323{
324 if ( vl->realized )
325 vik_treeview_item_delete ( vl->vt, &(vl->iter) );
326}
327
328void vik_aggregate_layer_clear ( VikAggregateLayer *val )
329{
330 g_list_foreach ( val->children, (GFunc)(disconnect_layer_signal), val );
331 g_list_foreach ( val->children, (GFunc)(delete_layer_iter), NULL );
332 g_list_foreach ( val->children, (GFunc)(g_object_unref), NULL );
333 g_list_free ( val->children );
334 val->children = NULL;
335}
336
337gboolean vik_aggregate_layer_delete ( VikAggregateLayer *val, GtkTreeIter *iter )
338{
339 VikLayer *l = VIK_LAYER( vik_treeview_item_get_pointer ( VIK_LAYER(val)->vt, iter ) );
340 gboolean was_visible = l->visible;
341
342 vik_treeview_item_delete ( VIK_LAYER(val)->vt, iter );
343 val->children = g_list_remove ( val->children, l );
344 g_assert(DISCONNECT_UPDATE_SIGNAL(l,val)==1);
345 g_object_unref ( l );
346
347 return was_visible;
348}
349
941aa6e9 350#if 0
50a14534
EB
351/* returns 0 == we're good, 1 == didn't find any layers, 2 == got rejected */
352guint vik_aggregate_layer_tool ( VikAggregateLayer *val, guint16 layer_type, VikToolInterfaceFunc tool_func, GdkEventButton *event, VikViewport *vvp )
353{
354 GList *iter = val->children;
355 gboolean found_rej = FALSE;
356 if (!iter)
357 return FALSE;
358 while (iter->next)
359 iter = iter->next;
360
361 while ( iter )
362 {
363 /* if this layer "accepts" the tool call */
364 if ( VIK_LAYER(iter->data)->visible && VIK_LAYER(iter->data)->type == layer_type )
365 {
366 if ( tool_func ( VIK_LAYER(iter->data), event, vvp ) )
367 return 0;
368 else
369 found_rej = TRUE;
370 }
371
372 /* recursive -- try the same for the child aggregate layer. */
373 else if ( VIK_LAYER(iter->data)->visible && VIK_LAYER(iter->data)->type == VIK_LAYER_AGGREGATE )
374 {
375 gint rv = vik_aggregate_layer_tool(VIK_AGGREGATE_LAYER(iter->data), layer_type, tool_func, event, vvp);
376 if ( rv == 0 )
377 return 0;
378 else if ( rv == 2 )
379 found_rej = TRUE;
380 }
381 iter = iter->prev;
382 }
383 return found_rej ? 2 : 1; /* no one wanted to accept the tool call in this layer */
384}
941aa6e9 385#endif
50a14534
EB
386
387VikLayer *vik_aggregate_layer_get_top_visible_layer_of_type ( VikAggregateLayer *val, gint type )
388{
389 VikLayer *rv;
390 GList *ls = val->children;
391 if (!ls)
392 return NULL;
393 while (ls->next)
394 ls = ls->next;
395
396 while ( ls )
397 {
398 if ( VIK_LAYER(ls->data)->visible && VIK_LAYER(ls->data)->type == type )
399 return VIK_LAYER(ls->data);
400 else if ( VIK_LAYER(ls->data)->visible && VIK_LAYER(ls->data)->type == VIK_LAYER_AGGREGATE )
401 {
402 rv = vik_aggregate_layer_get_top_visible_layer_of_type(VIK_AGGREGATE_LAYER(ls->data), type);
403 if ( rv )
404 return rv;
405 }
406 ls = ls->prev;
407 }
408 return NULL;
409}
410
7114e879
QT
411GList *vik_aggregate_layer_get_all_layers_of_type(VikAggregateLayer *val, GList *layers, gint type)
412{
413 GList *l = layers;
414 GList *children = val->children;
415 if (!children)
416 return layers;
417 while (children) {
418 if (VIK_LAYER(children->data)->type == VIK_LAYER_AGGREGATE)
8ece78c0 419 l = vik_aggregate_layer_get_all_layers_of_type(VIK_AGGREGATE_LAYER(children->data), l, type);
7114e879
QT
420 else if (VIK_LAYER(children->data)->type == type)
421 l = g_list_prepend(l, children->data); /* now in top down order */
422 children = children->next;
423 }
424 return l;
425}
426
50a14534
EB
427void vik_aggregate_layer_realize ( VikAggregateLayer *val, VikTreeview *vt, GtkTreeIter *layer_iter )
428{
429 GList *i = val->children;
430 GtkTreeIter iter;
431 while ( i )
432 {
433 vik_treeview_add_layer ( VIK_LAYER(val)->vt, layer_iter, &iter, VIK_LAYER(i->data)->name, val,
434 VIK_LAYER(i->data), VIK_LAYER(i->data)->type, VIK_LAYER(i->data)->type );
435 if ( ! VIK_LAYER(i->data)->visible )
436 vik_treeview_item_set_visible ( VIK_LAYER(val)->vt, &iter, FALSE );
437 vik_layer_realize ( VIK_LAYER(i->data), VIK_LAYER(val)->vt, &iter );
438 i = i->next;
439 }
440}
441
442const GList *vik_aggregate_layer_get_children ( VikAggregateLayer *val )
443{
444 return val->children;
445}
446
447gboolean vik_aggregate_layer_is_empty ( VikAggregateLayer *val )
448{
449 if ( val->children )
450 return FALSE;
451 return TRUE;
452}
70a23263
AF
453
454static void aggregate_layer_drag_drop_request ( VikAggregateLayer *val_src, VikAggregateLayer *val_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path )
455{
456 VikTreeview *vt = VIK_LAYER(val_src)->vt;
457 VikLayer *vl = vik_treeview_item_get_pointer(vt, src_item_iter);
e673b75f 458 GtkTreeIter dest_iter;
c390aa71
AF
459 gchar *dp;
460 gboolean target_exists;
e673b75f 461
c390aa71
AF
462 dp = gtk_tree_path_to_string(dest_path);
463 target_exists = vik_treeview_get_iter_from_path_str(vt, &dest_iter, dp);
801ce684
EB
464
465 /* vik_aggregate_layer_delete unrefs, but we don't want that here.
466 * we're still using the layer. */
467 g_object_ref ( vl );
468 vik_aggregate_layer_delete(val_src, src_item_iter);
469
c390aa71 470 if (target_exists) {
e673b75f
AF
471 vik_aggregate_layer_insert_layer(val_dest, vl, &dest_iter);
472 } else {
473 vik_aggregate_layer_insert_layer(val_dest, vl, NULL); /* append */
474 }
c390aa71 475 g_free(dp);
70a23263
AF
476}
477