Contents of /trunk/src/relation_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 76 - (hide annotations)
Fri Feb 13 12:02:26 2009 UTC (15 years, 3 months ago) by harbaum
File MIME type: text/plain
File size: 28854 byte(s)
Global relation handling
1 harbaum 1 /*
2     * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3     *
4     * This file is part of OSM2Go.
5     *
6     * OSM2Go 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 3 of the License, or
9     * (at your option) any later version.
10     *
11     * OSM2Go 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 OSM2Go. If not, see <http://www.gnu.org/licenses/>.
18     */
19    
20     #include "appdata.h"
21    
22     /* --------------- relation dialog for an item (node or way) ----------- */
23    
24     typedef struct {
25     relation_item_t *item;
26     appdata_t *appdata;
27     GtkWidget *dialog, *view;
28     GtkListStore *store;
29     GtkWidget *but_add, *but_edit, *but_remove;
30     } relitem_context_t;
31    
32     enum {
33     RELITEM_COL_SELECTED = 0,
34     RELITEM_COL_TYPE,
35     RELITEM_COL_ROLE,
36     RELITEM_COL_NAME,
37     RELITEM_COL_DATA,
38     RELITEM_NUM_COLS
39     };
40    
41     typedef struct role_chain_s {
42     char *role;
43     struct role_chain_s *next;
44     } role_chain_t;
45    
46 harbaum 73 static gboolean relation_add_item(GtkWidget *parent,
47 harbaum 1 relation_t *relation, relation_item_t *item) {
48     role_chain_t *chain = NULL, **chainP = &chain;
49    
50     printf("add item of type %d to relation #%ld\n",
51     item->type, relation->id);
52    
53     /* ask the user for the role of the new item in this relation */
54    
55     /* collect roles first */
56     member_t *member = relation->member;
57     while(member) {
58     if(member->role) {
59     /* check if this role has already been saved */
60     gboolean already_stored = FALSE;
61     role_chain_t *crole = chain;
62     while(crole) {
63     if(strcasecmp(crole->role, member->role) == 0) already_stored = TRUE;
64     crole = crole->next;
65     }
66    
67     /* not stored yet: attach it */
68     if(!already_stored) {
69     *chainP = g_new0(role_chain_t, 1);
70     (*chainP)->role = g_strdup(member->role);
71     chainP = &(*chainP)->next;
72     }
73     }
74     member = member->next;
75     }
76    
77     /* ------------------ role dialog ---------------- */
78     GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Select role"),
79     GTK_WINDOW(parent), GTK_DIALOG_MODAL,
80     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
81     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
82     NULL);
83    
84     gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
85    
86     char *type = osm_tag_get_by_key(relation->tag, "type");
87    
88     char *info_str = NULL;
89     if(type) info_str = g_strdup_printf(_("In relation of type: %s"), type);
90     else info_str = g_strdup_printf(_("In relation #%ld"), relation->id);
91     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
92     gtk_label_new(info_str));
93     g_free(info_str);
94    
95     char *name = osm_tag_get_by_key(relation->tag, "name");
96     if(name)
97     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
98     gtk_label_new(name));
99    
100     GtkWidget *hbox = gtk_hbox_new(FALSE, 8);
101     gtk_box_pack_start_defaults(GTK_BOX(hbox), gtk_label_new(_("Role:")));
102    
103     GtkWidget *entry = NULL;
104     if(chain) {
105     entry = gtk_combo_box_entry_new_text();
106    
107     /* fill combo box with presets */
108     while(chain) {
109     role_chain_t *next = chain->next;
110     gtk_combo_box_append_text(GTK_COMBO_BOX(entry), chain->role);
111     g_free(chain);
112     chain = next;
113     }
114     } else
115     entry = gtk_entry_new();
116    
117     gtk_box_pack_start_defaults(GTK_BOX(hbox), entry);
118     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
119    
120     gtk_widget_show_all(dialog);
121     if(GTK_RESPONSE_ACCEPT != gtk_dialog_run(GTK_DIALOG(dialog))) {
122     printf("user clicked cancel\n");
123     gtk_widget_destroy(dialog);
124 harbaum 73 return FALSE;
125 harbaum 1 }
126    
127     printf("user clicked ok\n");
128    
129     /* get role from dialog */
130     char *ptr = NULL;
131    
132     if(GTK_IS_COMBO_BOX(entry))
133     ptr = gtk_combo_box_get_active_text(GTK_COMBO_BOX(entry));
134     else
135     ptr = (char*)gtk_entry_get_text(GTK_ENTRY(entry));
136    
137     char *role = NULL;
138     if(ptr && strlen(ptr)) role = g_strdup(ptr);
139    
140     gtk_widget_destroy(dialog);
141    
142     /* search end of member chain */
143     member_t **memberP = &relation->member;
144     while(*memberP) memberP = &(*memberP)->next;
145    
146     /* create new member */
147     *memberP = g_new0(member_t, 1);
148     (*memberP)->type = item->type;
149     (*memberP)->role = role;
150     switch(item->type) {
151     case NODE:
152     (*memberP)->node = item->node;
153     break;
154     case WAY:
155     (*memberP)->way = item->way;
156     break;
157     case RELATION:
158     (*memberP)->relation = item->relation;
159     break;
160     default:
161     g_assert((item->type == NODE)||(item->type == WAY)||
162     (item->type == RELATION));
163     break;
164     }
165    
166     relation->flags |= OSM_FLAG_DIRTY;
167 harbaum 73 return TRUE;
168 harbaum 1 }
169    
170 harbaum 73 static void relation_remove_item(relation_t *relation, relation_item_t *item) {
171    
172     printf("remove item of type %d from relation #%ld\n",
173     item->type, relation->id);
174    
175     member_t **member = &relation->member;
176     while(*member) {
177     if(((*member)->type == item->type) &&
178     (((item->type == NODE) && (item->node == (*member)->node)) ||
179     ((item->type == WAY) && (item->way == (*member)->way)) ||
180     ((item->type == RELATION) && (item->relation == (*member)->relation)))) {
181    
182     member_t *next = (*member)->next;
183     osm_member_free(*member);
184     *member = next;
185    
186     relation->flags |= OSM_FLAG_DIRTY;
187    
188     return;
189     } else
190     member = &(*member)->next;
191     }
192     g_assert(0);
193     }
194    
195 harbaum 76 static void relation_item_list_selected(relitem_context_t *context,
196 harbaum 73 gboolean selected) {
197    
198     if(context->but_remove)
199 harbaum 75 gtk_widget_set_sensitive(context->but_remove, selected);
200 harbaum 73 if(context->but_edit)
201     gtk_widget_set_sensitive(context->but_edit, selected);
202     }
203    
204     static gboolean
205 harbaum 76 relation_item_list_selection_func(GtkTreeSelection *selection, GtkTreeModel *model,
206 harbaum 73 GtkTreePath *path, gboolean path_currently_selected,
207     gpointer userdata) {
208     relitem_context_t *context = (relitem_context_t*)userdata;
209     GtkTreeIter iter;
210    
211     if(gtk_tree_model_get_iter(model, &iter, path)) {
212     g_assert(gtk_tree_path_get_depth(path) == 1);
213 harbaum 76 relation_item_list_selected(context, TRUE);
214 harbaum 73 }
215    
216     return TRUE; /* allow selection state to change */
217     }
218    
219 harbaum 76 static void on_relation_item_add(GtkWidget *but, relitem_context_t *context) {
220 harbaum 73 /* create a new relation */
221    
222     relation_t *relation = osm_relation_new();
223     if(!info_dialog(context->dialog, context->appdata, relation)) {
224     printf("tag edit cancelled\n");
225     osm_relation_free(relation);
226     } else {
227     osm_relation_attach(context->appdata->osm, relation);
228    
229     /* add to list */
230    
231     /* append a row for the new data */
232     /* try to find something descriptive */
233     char *name = osm_tag_get_by_key(relation->tag, "name");
234     if(!name) name = osm_tag_get_by_key(relation->tag, "ref");
235    
236     GtkTreeIter iter;
237     gtk_list_store_append(context->store, &iter);
238     gtk_list_store_set(context->store, &iter,
239     RELITEM_COL_SELECTED, FALSE,
240     RELITEM_COL_TYPE,
241     osm_tag_get_by_key(relation->tag, "type"),
242     RELITEM_COL_NAME, name,
243     RELITEM_COL_DATA, relation,
244     -1);
245    
246     gtk_tree_selection_select_iter(gtk_tree_view_get_selection(
247     GTK_TREE_VIEW(context->view)), &iter);
248    
249     /* scroll to end */
250     // GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment();
251     /* xyz */
252     }
253 harbaum 1 }
254    
255     static relation_t *get_selection(relitem_context_t *context) {
256     GtkTreeSelection *selection;
257     GtkTreeModel *model;
258     GtkTreeIter iter;
259    
260     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view));
261     if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
262     relation_t *relation;
263     gtk_tree_model_get(model, &iter, RELITEM_COL_DATA, &relation, -1);
264     return(relation);
265     }
266     return NULL;
267     }
268    
269 harbaum 76 static void on_relation_item_edit(GtkWidget *but, relitem_context_t *context) {
270 harbaum 1 relation_t *sel = get_selection(context);
271     if(!sel) return;
272    
273     printf("edit relation #%ld\n", sel->id);
274    
275     info_dialog(context->dialog, context->appdata, sel);
276     }
277    
278 harbaum 75 /* remove the selected relation */
279 harbaum 76 static void on_relation_item_remove(GtkWidget *but, relitem_context_t *context) {
280 harbaum 1 relation_t *sel = get_selection(context);
281     if(!sel) return;
282    
283     printf("remove relation #%ld\n", sel->id);
284 harbaum 75
285     int members = 0;
286     member_t *member = sel->member;
287     while(member) {
288     members++;
289     member = member->next;
290     }
291    
292     if(members)
293     if(!yes_no_f(context->dialog, NULL, 0, 0,
294     _("Delete non-empty relation?"),
295     _("This relation still has %d members. "
296     "Delete it anyway?"), members))
297     return;
298    
299     /* first remove selected row from list */
300     GtkTreeIter iter;
301     GtkTreeSelection *selection =
302     gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view));
303     if(gtk_tree_selection_get_selected(selection, NULL, &iter))
304     gtk_list_store_remove(context->store, &iter);
305    
306     /* then really delete it */
307     osm_relation_delete(context->appdata->osm, sel, FALSE);
308    
309 harbaum 76 relation_item_list_selected(context, FALSE);
310 harbaum 1 }
311    
312 harbaum 73 static char *relitem_get_role_in_relation(relation_item_t *item, relation_t *relation) {
313     member_t *member = relation->member;
314     while(member) {
315     switch(member->type) {
316    
317     case NODE:
318     if((item->type == NODE) && (item->node == member->node))
319     return member->role;
320     break;
321    
322     case WAY:
323     if((item->type == WAY) && (item->way == member->way))
324     return member->role;
325     break;
326    
327     default:
328     break;
329     }
330     member = member->next;
331     }
332     return NULL;
333     }
334    
335 harbaum 1 static void
336     relitem_toggled(GtkCellRendererToggle *cell, const gchar *path_str,
337 harbaum 75 relitem_context_t *context) {
338 harbaum 1 GtkTreePath *path;
339     GtkTreeIter iter;
340    
341     path = gtk_tree_path_new_from_string(path_str);
342     gtk_tree_model_get_iter(GTK_TREE_MODEL(context->store), &iter, path);
343 harbaum 73 gtk_tree_path_free(path);
344 harbaum 1
345     /* get current enabled flag */
346     gboolean enabled;
347 harbaum 73 relation_t *relation = NULL;
348 harbaum 1 gtk_tree_model_get(GTK_TREE_MODEL(context->store), &iter,
349 harbaum 73 RELITEM_COL_SELECTED, &enabled,
350     RELITEM_COL_DATA, &relation,
351     -1);
352 harbaum 1
353 harbaum 73 if(!enabled) {
354     printf("will now become be part of this relation\n");
355     if(relation_add_item(context->dialog, relation, context->item))
356     gtk_list_store_set(context->store, &iter,
357     RELITEM_COL_SELECTED, TRUE,
358     RELITEM_COL_ROLE,
359     relitem_get_role_in_relation(context->item, relation),
360     -1);
361     } else {
362     printf("item will not be part of this relation anymore\n");
363     relation_remove_item(relation, context->item);
364     gtk_list_store_set(context->store, &iter,
365     RELITEM_COL_SELECTED, FALSE,
366     RELITEM_COL_ROLE, NULL,
367     -1);
368     }
369 harbaum 1 }
370    
371     static gboolean relitem_is_in_relation(relation_item_t *item, relation_t *relation) {
372     member_t *member = relation->member;
373     while(member) {
374     switch(member->type) {
375    
376     case NODE:
377     if((item->type == NODE) && (item->node == member->node))
378     return TRUE;
379     break;
380    
381     case WAY:
382     if((item->type == WAY) && (item->way == member->way))
383     return TRUE;
384     break;
385    
386     default:
387     break;
388     }
389     member = member->next;
390     }
391     return FALSE;
392     }
393    
394 harbaum 76 static GtkWidget *relation_item_list_widget(relitem_context_t *context) {
395 harbaum 1 GtkWidget *vbox = gtk_vbox_new(FALSE,3);
396     context->view = gtk_tree_view_new();
397    
398     gtk_tree_selection_set_select_function(
399     gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)),
400 harbaum 76 relation_item_list_selection_func,
401 harbaum 1 context, NULL);
402    
403    
404     /* --- "selected" column --- */
405     GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new();
406     g_signal_connect(renderer, "toggled", G_CALLBACK(relitem_toggled), context);
407     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
408     -1, _(""), renderer,
409     "active", RELITEM_COL_SELECTED,
410     NULL);
411    
412     /* --- "Type" column --- */
413     renderer = gtk_cell_renderer_text_new();
414     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
415     -1, _("Type"), renderer, "text", RELITEM_COL_TYPE, NULL);
416    
417     /* --- "Role" column --- */
418     renderer = gtk_cell_renderer_text_new();
419     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
420     -1, _("Role"), renderer, "text", RELITEM_COL_ROLE, NULL);
421    
422     /* --- "Name" column --- */
423     renderer = gtk_cell_renderer_text_new();
424     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
425     GtkTreeViewColumn *column =
426     gtk_tree_view_column_new_with_attributes(_("Name"), renderer,
427     "text", RELITEM_COL_NAME, NULL);
428     gtk_tree_view_column_set_expand(column, TRUE);
429     gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1);
430    
431    
432     /* build and fill the store */
433     context->store = gtk_list_store_new(RELITEM_NUM_COLS,
434     G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING,
435     G_TYPE_STRING, G_TYPE_POINTER);
436    
437     gtk_tree_view_set_model(GTK_TREE_VIEW(context->view),
438     GTK_TREE_MODEL(context->store));
439    
440     GtkTreeIter iter;
441     relation_t *relation = context->appdata->osm->relation;
442     while(relation) {
443     /* try to find something descriptive */
444     char *name = osm_tag_get_by_key(relation->tag, "name");
445     if(!name) name = osm_tag_get_by_key(relation->tag, "ref");
446    
447     /* Append a row and fill in some data */
448     gtk_list_store_append(context->store, &iter);
449     gtk_list_store_set(context->store, &iter,
450     RELITEM_COL_SELECTED, relitem_is_in_relation(context->item, relation),
451     RELITEM_COL_TYPE, osm_tag_get_by_key(relation->tag, "type"),
452     RELITEM_COL_ROLE, relitem_get_role_in_relation(context->item, relation),
453     RELITEM_COL_NAME, name,
454     RELITEM_COL_DATA, relation,
455     -1);
456    
457     relation = relation->next;
458     }
459    
460     g_object_unref(context->store);
461    
462     /* put it into a scrolled window */
463     GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
464     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
465     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
466     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
467     GTK_SHADOW_ETCHED_IN);
468     gtk_container_add(GTK_CONTAINER(scrolled_window), context->view);
469    
470     gtk_box_pack_start_defaults(GTK_BOX(vbox), scrolled_window);
471    
472     /* ------- button box ------------ */
473    
474     GtkWidget *hbox = gtk_hbox_new(TRUE,3);
475    
476     context->but_add = gtk_button_new_with_label(_("Add..."));
477 harbaum 73 // gtk_widget_set_sensitive(context->but_add, FALSE);
478 harbaum 1 gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_add);
479     gtk_signal_connect(GTK_OBJECT(context->but_add), "clicked",
480 harbaum 76 GTK_SIGNAL_FUNC(on_relation_item_add), context);
481 harbaum 1
482     context->but_edit = gtk_button_new_with_label(_("Edit..."));
483     gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_edit);
484     gtk_signal_connect(GTK_OBJECT(context->but_edit), "clicked",
485 harbaum 76 GTK_SIGNAL_FUNC(on_relation_item_edit), context);
486 harbaum 1
487     context->but_remove = gtk_button_new_with_label(_("Remove"));
488     gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_remove);
489     gtk_signal_connect(GTK_OBJECT(context->but_remove), "clicked",
490 harbaum 76 GTK_SIGNAL_FUNC(on_relation_item_remove), context);
491 harbaum 1
492 harbaum 76 relation_item_list_selected(context, FALSE);
493 harbaum 1
494     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
495     return vbox;
496     }
497    
498     void relation_add_dialog(appdata_t *appdata, relation_item_t *relitem) {
499     relitem_context_t *context = g_new0(relitem_context_t, 1);
500     map_t *map = appdata->map;
501     g_assert(map);
502    
503     context->appdata = appdata;
504     context->item = relitem;
505    
506     char *str = NULL;
507     switch(relitem->type) {
508     case NODE:
509     str = g_strdup_printf(_("Relations for node #%ld"), relitem->node->id);
510     break;
511     case WAY:
512     str = g_strdup_printf(_("Relations for way #%ld"), relitem->way->id);
513     break;
514     default:
515     g_assert((relitem->type == NODE) || (relitem->type == WAY));
516     break;
517     }
518    
519     context->dialog = gtk_dialog_new_with_buttons(str,
520     GTK_WINDOW(appdata->window), GTK_DIALOG_MODAL,
521 harbaum 73 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
522 harbaum 1 NULL);
523     g_free(str);
524    
525     gtk_dialog_set_default_response(GTK_DIALOG(context->dialog),
526 harbaum 76 GTK_RESPONSE_CLOSE);
527 harbaum 1
528     /* making the dialog a little wider makes it less "crowded" */
529     #ifdef USE_HILDON
530     gtk_window_set_default_size(GTK_WINDOW(context->dialog), 500, 300);
531     #else
532     gtk_window_set_default_size(GTK_WINDOW(context->dialog), 400, 200);
533     #endif
534     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context->dialog)->vbox),
535 harbaum 76 relation_item_list_widget(context), TRUE, TRUE, 0);
536 harbaum 1
537     /* ----------------------------------- */
538    
539     gtk_widget_show_all(context->dialog);
540 harbaum 73 gtk_dialog_run(GTK_DIALOG(context->dialog));
541 harbaum 1 gtk_widget_destroy(context->dialog);
542    
543     g_free(context);
544     }
545 harbaum 76
546     /* -------------------- global relation list ----------------- */
547    
548     typedef struct {
549     appdata_t *appdata;
550     GtkWidget *dialog, *view;
551     GtkWidget *but_members, *but_add, *but_edit, *but_remove;
552     GtkListStore *store;
553     } relation_context_t;
554    
555     enum {
556     RELATION_COL_ID = 0,
557     RELATION_COL_TYPE,
558     RELATION_COL_NAME,
559     RELATION_COL_MEMBERS,
560     RELATION_COL_DATA,
561     RELATION_NUM_COLS
562     };
563    
564     static void relation_list_selected(relation_context_t *context,
565     gboolean selected) {
566    
567     if(context->but_members)
568     gtk_widget_set_sensitive(context->but_members, selected);
569     }
570    
571     static gboolean
572     relation_list_selection_func(GtkTreeSelection *selection, GtkTreeModel *model,
573     GtkTreePath *path, gboolean path_currently_selected,
574     gpointer userdata) {
575     relation_context_t *context = (relation_context_t*)userdata;
576     GtkTreeIter iter;
577    
578     if(gtk_tree_model_get_iter(model, &iter, path)) {
579     g_assert(gtk_tree_path_get_depth(path) == 1);
580     relation_list_selected(context, TRUE);
581     }
582    
583     return TRUE; /* allow selection state to change */
584     }
585    
586     static relation_t *get_selected_relation(relation_context_t *context) {
587     GtkTreeSelection *selection;
588     GtkTreeModel *model;
589     GtkTreeIter iter;
590    
591     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view));
592     if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
593     relation_t *relation;
594     gtk_tree_model_get(model, &iter, RELATION_COL_DATA, &relation, -1);
595     return(relation);
596     }
597     return NULL;
598     }
599    
600     typedef struct {
601     relation_t *relation;
602     GtkWidget *dialog, *view;
603     GtkListStore *store;
604     } member_context_t;
605    
606     enum {
607     MEMBER_COL_TYPE = 0,
608     MEMBER_COL_ID,
609     MEMBER_COL_NAME,
610     MEMBER_COL_ROLE,
611     MEMBER_COL_REF_ONLY,
612     MEMBER_COL_DATA,
613     MEMBER_NUM_COLS
614     };
615    
616     static gboolean
617     member_list_selection_func(GtkTreeSelection *selection, GtkTreeModel *model,
618     GtkTreePath *path, gboolean path_currently_selected,
619     gpointer userdata) {
620     GtkTreeIter iter;
621    
622     if(gtk_tree_model_get_iter(model, &iter, path)) {
623     g_assert(gtk_tree_path_get_depth(path) == 1);
624    
625     member_t *member = NULL;
626     gtk_tree_model_get(model, &iter, MEMBER_COL_DATA, &member, -1);
627     if(member && member->type < NODE_ID)
628     return TRUE;
629     }
630    
631     return FALSE;
632     }
633    
634    
635     static GtkWidget *member_list_widget(member_context_t *context) {
636     GtkWidget *vbox = gtk_vbox_new(FALSE,3);
637     context->view = gtk_tree_view_new();
638    
639     gtk_tree_selection_set_select_function(
640     gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)),
641     member_list_selection_func,
642     context, NULL);
643    
644     /* --- "type" column --- */
645     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
646     g_object_set(renderer, "foreground", "grey", NULL);
647     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
648     -1, _("Type"), renderer, "text", MEMBER_COL_TYPE,
649     "foreground-set", MEMBER_COL_REF_ONLY, NULL);
650    
651    
652     /* --- "id" column --- */
653     renderer = gtk_cell_renderer_text_new();
654     g_object_set(renderer, "foreground", "grey", NULL);
655     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
656     -1, _("Id"), renderer, "text", MEMBER_COL_ID,
657     "foreground-set", MEMBER_COL_REF_ONLY, NULL);
658    
659     /* --- "Name" column --- */
660     renderer = gtk_cell_renderer_text_new();
661     g_object_set(renderer, "foreground", "grey", NULL);
662     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
663     GtkTreeViewColumn *column =
664     gtk_tree_view_column_new_with_attributes(_("Name"), renderer,
665     "text", MEMBER_COL_NAME,
666     "foreground-set", MEMBER_COL_REF_ONLY, NULL);
667     gtk_tree_view_column_set_expand(column, TRUE);
668     gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1);
669    
670     /* --- "role" column --- */
671     renderer = gtk_cell_renderer_text_new();
672     g_object_set(renderer, "foreground", "grey", NULL);
673     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
674     -1, _("Role"), renderer, "text", MEMBER_COL_ROLE,
675     "foreground-set", MEMBER_COL_REF_ONLY, NULL);
676    
677     /* build and fill the store */
678     context->store = gtk_list_store_new(MEMBER_NUM_COLS,
679     G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
680     G_TYPE_BOOLEAN, G_TYPE_POINTER);
681    
682     gtk_tree_view_set_model(GTK_TREE_VIEW(context->view),
683     GTK_TREE_MODEL(context->store));
684    
685     GtkTreeIter iter;
686     member_t *member = context->relation->member;
687     while(member) {
688     tag_t *tags = osm_object_get_tags(member->type, member->ptr);
689     char *id = osm_id_string(member->type, member->ptr);
690    
691     /* try to find something descriptive */
692     char *name = NULL;
693     if(tags)
694     name = osm_tag_get_by_key(tags, "name");
695    
696     /* Append a row and fill in some data */
697     gtk_list_store_append(context->store, &iter);
698     gtk_list_store_set(context->store, &iter,
699     MEMBER_COL_TYPE, osm_type_string(member->type),
700     MEMBER_COL_ID, id,
701     MEMBER_COL_NAME, name,
702     MEMBER_COL_ROLE, member->role,
703     MEMBER_COL_REF_ONLY, member->type >= NODE_ID,
704     MEMBER_COL_DATA, member,
705     -1);
706    
707     g_free(id);
708     member = member->next;
709     }
710    
711     g_object_unref(context->store);
712    
713     /* put it into a scrolled window */
714     GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
715     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
716     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
717     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
718     GTK_SHADOW_ETCHED_IN);
719     gtk_container_add(GTK_CONTAINER(scrolled_window), context->view);
720    
721     gtk_box_pack_start_defaults(GTK_BOX(vbox), scrolled_window);
722    
723     return vbox;
724     }
725    
726     /* user clicked "members..." button in relation list */
727     static void on_relation_members(GtkWidget *but, relation_context_t *context) {
728     member_context_t *mcontext = g_new0(member_context_t, 1);
729    
730     /* display members list */
731     mcontext->relation = get_selected_relation(context);
732     if(!mcontext->relation) return;
733    
734     char *str = osm_tag_get_by_key(mcontext->relation->tag, "name");
735     if(!str) str = osm_tag_get_by_key(mcontext->relation->tag, "ref");
736     if(!str)
737     str = g_strdup_printf(_("Members of relation #%ld"),
738     mcontext->relation->id);
739     else
740     str = g_strdup_printf(_("Members of relation \"%s\""), str);
741    
742     mcontext->dialog =
743     gtk_dialog_new_with_buttons(str,
744     GTK_WINDOW(context->dialog), GTK_DIALOG_MODAL,
745     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
746     NULL);
747     g_free(str);
748    
749     gtk_dialog_set_default_response(GTK_DIALOG(mcontext->dialog),
750     GTK_RESPONSE_CLOSE);
751    
752     /* making the dialog a little wider makes it less "crowded" */
753     #ifdef USE_HILDON
754     gtk_window_set_default_size(GTK_WINDOW(mcontext->dialog), 500, 300);
755     #else
756     gtk_window_set_default_size(GTK_WINDOW(mcontext->dialog), 400, 200);
757     #endif
758    
759     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(mcontext->dialog)->vbox),
760     member_list_widget(mcontext), TRUE, TRUE, 0);
761    
762     /* ----------------------------------- */
763    
764     gtk_widget_show_all(mcontext->dialog);
765     gtk_dialog_run(GTK_DIALOG(mcontext->dialog));
766     gtk_widget_destroy(mcontext->dialog);
767    
768     g_free(mcontext);
769     }
770    
771     static GtkWidget *relation_list_widget(relation_context_t *context) {
772     GtkWidget *vbox = gtk_vbox_new(FALSE,3);
773     context->view = gtk_tree_view_new();
774    
775     gtk_tree_selection_set_select_function(
776     gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)),
777     relation_list_selection_func,
778     context, NULL);
779    
780     /* --- "id" column --- */
781     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
782     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
783     -1, _("Id"), renderer, "text", RELATION_COL_ID, NULL);
784    
785     /* --- "Type" column --- */
786     renderer = gtk_cell_renderer_text_new();
787     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
788     -1, _("Type"), renderer, "text", RELATION_COL_TYPE, NULL);
789    
790     /* --- "Name" column --- */
791     renderer = gtk_cell_renderer_text_new();
792     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
793     GtkTreeViewColumn *column =
794     gtk_tree_view_column_new_with_attributes(_("Name"), renderer,
795     "text", RELATION_COL_NAME, NULL);
796     gtk_tree_view_column_set_expand(column, TRUE);
797     gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1);
798    
799     /* --- "members" column --- */
800     renderer = gtk_cell_renderer_text_new();
801     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
802     -1, _("Members"), renderer, "text", RELATION_COL_MEMBERS, NULL);
803    
804     /* build and fill the store */
805     context->store = gtk_list_store_new(RELATION_NUM_COLS,
806     G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
807     G_TYPE_POINTER);
808    
809     gtk_tree_view_set_model(GTK_TREE_VIEW(context->view),
810     GTK_TREE_MODEL(context->store));
811    
812     GtkTreeIter iter;
813     relation_t *relation = context->appdata->osm->relation;
814     while(relation) {
815     char *id = g_strdup_printf("#%ld", relation->id);
816    
817     /* try to find something descriptive */
818     char *name = osm_tag_get_by_key(relation->tag, "name");
819     if(!name) name = osm_tag_get_by_key(relation->tag, "ref");
820    
821     char *num = g_strdup_printf("%d", osm_relation_members_num(relation));
822    
823     /* Append a row and fill in some data */
824     gtk_list_store_append(context->store, &iter);
825     gtk_list_store_set(context->store, &iter,
826     RELATION_COL_ID, id,
827     RELATION_COL_TYPE,
828     osm_tag_get_by_key(relation->tag, "type"),
829     RELATION_COL_NAME, name,
830     RELATION_COL_MEMBERS, num,
831     RELATION_COL_DATA, relation,
832     -1);
833    
834     g_free(id);
835     g_free(num);
836     relation = relation->next;
837     }
838    
839     g_object_unref(context->store);
840    
841     /* put it into a scrolled window */
842     GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
843     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
844     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
845     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
846     GTK_SHADOW_ETCHED_IN);
847     gtk_container_add(GTK_CONTAINER(scrolled_window), context->view);
848    
849     gtk_box_pack_start_defaults(GTK_BOX(vbox), scrolled_window);
850    
851     /* ------- button box ------------ */
852    
853     GtkWidget *hbox = gtk_hbox_new(TRUE,3);
854    
855     context->but_add = gtk_button_new_with_label(_("Add..."));
856     gtk_widget_set_sensitive(context->but_add, FALSE);
857     gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_add);
858     // gtk_signal_connect(GTK_OBJECT(context->but_add), "clicked",
859     // GTK_SIGNAL_FUNC(on_relation_add), context);
860    
861     context->but_edit = gtk_button_new_with_label(_("Edit..."));
862     gtk_widget_set_sensitive(context->but_edit, FALSE);
863     gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_edit);
864     // gtk_signal_connect(GTK_OBJECT(context->but_edit), "clicked",
865     // GTK_SIGNAL_FUNC(on_relation_edit), context);
866    
867     context->but_members = gtk_button_new_with_label(_("Members..."));
868     gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_members);
869     gtk_signal_connect(GTK_OBJECT(context->but_members), "clicked",
870     GTK_SIGNAL_FUNC(on_relation_members), context);
871    
872     context->but_remove = gtk_button_new_with_label(_("Remove"));
873     gtk_widget_set_sensitive(context->but_remove, FALSE);
874     gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_remove);
875     // gtk_signal_connect(GTK_OBJECT(context->but_remove), "clicked",
876     // GTK_SIGNAL_FUNC(on_relation_remove), context);
877    
878     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
879    
880     relation_list_selected(context, FALSE);
881    
882     return vbox;
883     }
884    
885     /* a global view on all relations */
886     void relation_list(appdata_t *appdata) {
887     relation_context_t *context = g_new0(relation_context_t, 1);
888     context->appdata = appdata;
889    
890     printf("relation list\n");
891    
892     context->dialog =
893     gtk_dialog_new_with_buttons(_("All relations"),
894     GTK_WINDOW(appdata->window), GTK_DIALOG_MODAL,
895     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
896     NULL);
897    
898     gtk_dialog_set_default_response(GTK_DIALOG(context->dialog),
899     GTK_RESPONSE_CLOSE);
900    
901     /* making the dialog a little wider makes it less "crowded" */
902     #ifdef USE_HILDON
903     gtk_window_set_default_size(GTK_WINDOW(context->dialog), 500, 300);
904     #else
905     gtk_window_set_default_size(GTK_WINDOW(context->dialog), 400, 200);
906     #endif
907     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context->dialog)->vbox),
908     relation_list_widget(context), TRUE, TRUE, 0);
909    
910     /* ----------------------------------- */
911    
912     gtk_widget_show_all(context->dialog);
913     gtk_dialog_run(GTK_DIALOG(context->dialog));
914     gtk_widget_destroy(context->dialog);
915    
916     g_free(context);
917     }