]> git.street.me.uk Git - andy/viking.git/blame - src/vikaggregatelayer.c
fix sprintf warning
[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"
23#include "vikaggregatelayer_pixmap.h"
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
29static VikAggregateLayer *aggregate_layer_copy ( VikAggregateLayer *val, gpointer vp );
30static void aggregate_layer_change_coord_mode ( VikAggregateLayer *val, VikCoordMode mode );
70a23263 31static void aggregate_layer_drag_drop_request ( VikAggregateLayer *val_src, VikAggregateLayer *val_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
50a14534
EB
32
33VikLayerInterface vik_aggregate_layer_interface = {
34 "Aggregate",
35 &aggregatelayer_pixbuf,
36
37 NULL,
38 0,
39
40 NULL,
41 0,
42 NULL,
43 0,
44
45 (VikLayerFuncCreate) vik_aggregate_layer_create,
46 (VikLayerFuncRealize) vik_aggregate_layer_realize,
47 (VikLayerFuncPostRead) NULL,
48 (VikLayerFuncFree) vik_aggregate_layer_free,
49
50 (VikLayerFuncProperties) NULL,
51 (VikLayerFuncDraw) vik_aggregate_layer_draw,
52 (VikLayerFuncChangeCoordMode) aggregate_layer_change_coord_mode,
53
54 (VikLayerFuncAddMenuItems) NULL,
55 (VikLayerFuncSublayerAddMenuItems) NULL,
56
57 (VikLayerFuncSublayerRenameRequest) NULL,
58 (VikLayerFuncSublayerToggleVisible) NULL,
59
60 (VikLayerFuncCopy) aggregate_layer_copy,
911400b5
AF
61 (VikLayerFuncMarshall) NULL,
62 (VikLayerFuncUnmarshall) NULL,
50a14534
EB
63
64 (VikLayerFuncSetParam) NULL,
65 (VikLayerFuncGetParam) NULL,
66
67 (VikLayerFuncReadFileData) NULL,
68 (VikLayerFuncWriteFileData) NULL,
69
70 (VikLayerFuncCopyItem) NULL,
71 (VikLayerFuncPasteItem) NULL,
72 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 73 (VikLayerFuncDragDropRequest) aggregate_layer_drag_drop_request,
50a14534
EB
74};
75
76struct _VikAggregateLayer {
77 VikLayer vl;
78 GList *children;
79};
80
81GType vik_aggregate_layer_get_type ()
82{
83 static GType val_type = 0;
84
85 if (!val_type)
86 {
87 static const GTypeInfo val_info =
88 {
89 sizeof (VikAggregateLayerClass),
90 NULL, /* base_init */
91 NULL, /* base_finalize */
92 NULL, /* class init */
93 NULL, /* class_finalize */
94 NULL, /* class_data */
95 sizeof (VikAggregateLayer),
96 0,
97 NULL /* instance init */
98 };
99 val_type = g_type_register_static ( VIK_LAYER_TYPE, "VikAggregateLayer", &val_info, 0 );
100 }
101
102 return val_type;
103}
104
105VikAggregateLayer *vik_aggregate_layer_create (VikViewport *vp)
106{
107 VikAggregateLayer *rv = vik_aggregate_layer_new ();
108 vik_layer_rename ( VIK_LAYER(rv), vik_aggregate_layer_interface.name );
109 return rv;
110}
111
112static VikAggregateLayer *aggregate_layer_copy ( VikAggregateLayer *val, gpointer vp )
113{
114 VikAggregateLayer *rv = vik_aggregate_layer_new ();
115 VikLayer *child_layer;
116 GList *child = val->children;
117 while ( child )
118 {
119 child_layer = vik_layer_copy ( VIK_LAYER(child->data), vp );
120 if ( child_layer )
121 rv->children = g_list_append ( rv->children, child_layer );
122 g_signal_connect_swapped ( G_OBJECT(child_layer), "update", G_CALLBACK(vik_layer_emit_update), rv );
123 child = child->next;
124 }
125 return rv;
126}
127
128VikAggregateLayer *vik_aggregate_layer_new ()
129{
130 VikAggregateLayer *val = VIK_AGGREGATE_LAYER ( g_object_new ( VIK_AGGREGATE_LAYER_TYPE, NULL ) );
131 vik_layer_init ( VIK_LAYER(val), VIK_LAYER_AGGREGATE );
132 val->children = NULL;
133 return val;
134}
135
136void vik_aggregate_layer_insert_layer ( VikAggregateLayer *val, VikLayer *l, GtkTreeIter *replace_iter )
137{
50a14534 138 GtkTreeIter iter;
e673b75f 139
50a14534
EB
140 if ( VIK_LAYER(val)->realized )
141 {
142 vik_treeview_insert_layer ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter), &iter, l->name, val, l, l->type, l->type, replace_iter );
143 if ( ! l->visible )
144 vik_treeview_item_set_visible ( VIK_LAYER(val)->vt, &iter, FALSE );
145 vik_layer_realize ( l, VIK_LAYER(val)->vt, &iter );
146
147 if ( val->children == NULL )
148 vik_treeview_expand ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter) );
149 }
50a14534 150
e673b75f
AF
151 if (replace_iter) {
152 GList *theone = g_list_find ( val->children, vik_treeview_item_get_pointer ( VIK_LAYER(val)->vt, replace_iter ) );
153 val->children = g_list_insert ( val->children, l, g_list_position(val->children,theone)+1 );
154 } else {
155 val->children = g_list_append ( val->children, l );
156 }
50a14534
EB
157 g_signal_connect_swapped ( G_OBJECT(l), "update", G_CALLBACK(vik_layer_emit_update), val );
158}
159
160void vik_aggregate_layer_add_layer ( VikAggregateLayer *val, VikLayer *l )
161{
162 GtkTreeIter iter;
163
164 if ( VIK_LAYER(val)->realized )
165 {
166 vik_treeview_add_layer ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter), &iter, l->name, val, l, l->type, l->type);
167 if ( ! l->visible )
168 vik_treeview_item_set_visible ( VIK_LAYER(val)->vt, &iter, FALSE );
169 vik_layer_realize ( l, VIK_LAYER(val)->vt, &iter );
170
171 if ( val->children == NULL )
172 vik_treeview_expand ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter) );
173 }
174
175 val->children = g_list_append ( val->children, l );
176 g_signal_connect_swapped ( G_OBJECT(l), "update", G_CALLBACK(vik_layer_emit_update), val );
177}
178
179void vik_aggregate_layer_move_layer ( VikAggregateLayer *val, GtkTreeIter *child_iter, gboolean up )
180{
181 GList *theone, *first, *second;
182 vik_treeview_move_item ( VIK_LAYER(val)->vt, child_iter, up );
183
184 theone = g_list_find ( val->children, vik_treeview_item_get_pointer ( VIK_LAYER(val)->vt, child_iter ) );
185
186 g_assert ( theone != NULL );
187
188 /* the old switcheroo */
189 if ( up && theone->next )
190 {
191 first = theone;
192 second = theone->next;
193 }
194 else if ( !up && theone->prev )
195 {
196 first = theone->prev;
197 second = theone;
198 }
199 else
200 return;
201
202 first->next = second->next;
203 second->prev = first->prev;
204 first->prev = second;
205 second->next = first;
206
207 /* second is now first */
208
209 if ( second->prev )
210 second->prev->next = second;
211 if ( first->next )
212 first->next->prev = first;
213
214 if ( second->prev == NULL )
215 val->children = second;
216}
217
218void vik_aggregate_layer_draw ( VikAggregateLayer *val, gpointer data )
219{
220 g_list_foreach ( val->children, (GFunc)(vik_layer_draw), data );
221}
222
223static void aggregate_layer_change_coord_mode ( VikAggregateLayer *val, VikCoordMode mode )
224{
225 GList *iter = val->children;
226 while ( iter )
227 {
228 vik_layer_change_coord_mode ( VIK_LAYER(iter->data), mode );
229 iter = iter->next;
230 }
231}
232
233static void disconnect_layer_signal ( VikLayer *vl, VikAggregateLayer *val )
234{
235 g_assert(DISCONNECT_UPDATE_SIGNAL(vl,val)==1);
236}
237
238void vik_aggregate_layer_free ( VikAggregateLayer *val )
239{
240 g_list_foreach ( val->children, (GFunc)(disconnect_layer_signal), val );
241 g_list_foreach ( val->children, (GFunc)(g_object_unref), NULL );
242 g_list_free ( val->children );
243}
244
245static void delete_layer_iter ( VikLayer *vl )
246{
247 if ( vl->realized )
248 vik_treeview_item_delete ( vl->vt, &(vl->iter) );
249}
250
251void vik_aggregate_layer_clear ( VikAggregateLayer *val )
252{
253 g_list_foreach ( val->children, (GFunc)(disconnect_layer_signal), val );
254 g_list_foreach ( val->children, (GFunc)(delete_layer_iter), NULL );
255 g_list_foreach ( val->children, (GFunc)(g_object_unref), NULL );
256 g_list_free ( val->children );
257 val->children = NULL;
258}
259
260gboolean vik_aggregate_layer_delete ( VikAggregateLayer *val, GtkTreeIter *iter )
261{
262 VikLayer *l = VIK_LAYER( vik_treeview_item_get_pointer ( VIK_LAYER(val)->vt, iter ) );
263 gboolean was_visible = l->visible;
264
265 vik_treeview_item_delete ( VIK_LAYER(val)->vt, iter );
266 val->children = g_list_remove ( val->children, l );
267 g_assert(DISCONNECT_UPDATE_SIGNAL(l,val)==1);
268 g_object_unref ( l );
269
270 return was_visible;
271}
272
273/* returns 0 == we're good, 1 == didn't find any layers, 2 == got rejected */
274guint vik_aggregate_layer_tool ( VikAggregateLayer *val, guint16 layer_type, VikToolInterfaceFunc tool_func, GdkEventButton *event, VikViewport *vvp )
275{
276 GList *iter = val->children;
277 gboolean found_rej = FALSE;
278 if (!iter)
279 return FALSE;
280 while (iter->next)
281 iter = iter->next;
282
283 while ( iter )
284 {
285 /* if this layer "accepts" the tool call */
286 if ( VIK_LAYER(iter->data)->visible && VIK_LAYER(iter->data)->type == layer_type )
287 {
288 if ( tool_func ( VIK_LAYER(iter->data), event, vvp ) )
289 return 0;
290 else
291 found_rej = TRUE;
292 }
293
294 /* recursive -- try the same for the child aggregate layer. */
295 else if ( VIK_LAYER(iter->data)->visible && VIK_LAYER(iter->data)->type == VIK_LAYER_AGGREGATE )
296 {
297 gint rv = vik_aggregate_layer_tool(VIK_AGGREGATE_LAYER(iter->data), layer_type, tool_func, event, vvp);
298 if ( rv == 0 )
299 return 0;
300 else if ( rv == 2 )
301 found_rej = TRUE;
302 }
303 iter = iter->prev;
304 }
305 return found_rej ? 2 : 1; /* no one wanted to accept the tool call in this layer */
306}
307
308VikLayer *vik_aggregate_layer_get_top_visible_layer_of_type ( VikAggregateLayer *val, gint type )
309{
310 VikLayer *rv;
311 GList *ls = val->children;
312 if (!ls)
313 return NULL;
314 while (ls->next)
315 ls = ls->next;
316
317 while ( ls )
318 {
319 if ( VIK_LAYER(ls->data)->visible && VIK_LAYER(ls->data)->type == type )
320 return VIK_LAYER(ls->data);
321 else if ( VIK_LAYER(ls->data)->visible && VIK_LAYER(ls->data)->type == VIK_LAYER_AGGREGATE )
322 {
323 rv = vik_aggregate_layer_get_top_visible_layer_of_type(VIK_AGGREGATE_LAYER(ls->data), type);
324 if ( rv )
325 return rv;
326 }
327 ls = ls->prev;
328 }
329 return NULL;
330}
331
332void vik_aggregate_layer_realize ( VikAggregateLayer *val, VikTreeview *vt, GtkTreeIter *layer_iter )
333{
334 GList *i = val->children;
335 GtkTreeIter iter;
336 while ( i )
337 {
338 vik_treeview_add_layer ( VIK_LAYER(val)->vt, layer_iter, &iter, VIK_LAYER(i->data)->name, val,
339 VIK_LAYER(i->data), VIK_LAYER(i->data)->type, VIK_LAYER(i->data)->type );
340 if ( ! VIK_LAYER(i->data)->visible )
341 vik_treeview_item_set_visible ( VIK_LAYER(val)->vt, &iter, FALSE );
342 vik_layer_realize ( VIK_LAYER(i->data), VIK_LAYER(val)->vt, &iter );
343 i = i->next;
344 }
345}
346
347const GList *vik_aggregate_layer_get_children ( VikAggregateLayer *val )
348{
349 return val->children;
350}
351
352gboolean vik_aggregate_layer_is_empty ( VikAggregateLayer *val )
353{
354 if ( val->children )
355 return FALSE;
356 return TRUE;
357}
70a23263
AF
358
359static void aggregate_layer_drag_drop_request ( VikAggregateLayer *val_src, VikAggregateLayer *val_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path )
360{
361 VikTreeview *vt = VIK_LAYER(val_src)->vt;
362 VikLayer *vl = vik_treeview_item_get_pointer(vt, src_item_iter);
e673b75f 363 GtkTreeIter dest_iter;
c390aa71
AF
364 gchar *dp;
365 gboolean target_exists;
e673b75f 366
c390aa71
AF
367 dp = gtk_tree_path_to_string(dest_path);
368 target_exists = vik_treeview_get_iter_from_path_str(vt, &dest_iter, dp);
801ce684
EB
369
370 /* vik_aggregate_layer_delete unrefs, but we don't want that here.
371 * we're still using the layer. */
372 g_object_ref ( vl );
373 vik_aggregate_layer_delete(val_src, src_item_iter);
374
c390aa71 375 if (target_exists) {
e673b75f
AF
376 vik_aggregate_layer_insert_layer(val_dest, vl, &dest_iter);
377 } else {
378 vik_aggregate_layer_insert_layer(val_dest, vl, NULL); /* append */
379 }
c390aa71 380 g_free(dp);
70a23263
AF
381}
382