Contents of /trunk/src/relation_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 77 - (show annotations)
Fri Feb 13 20:30:32 2009 UTC (15 years, 4 months ago) by harbaum
File MIME type: text/plain
File size: 31654 byte(s)
More relation handling
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 static gboolean relation_add_item(GtkWidget *parent,
47 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 return FALSE;
125 }
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 return TRUE;
168 }
169
170 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 static void relation_item_list_selected(relitem_context_t *context,
196 gboolean selected) {
197
198 if(context->but_remove)
199 gtk_widget_set_sensitive(context->but_remove, selected);
200 if(context->but_edit)
201 gtk_widget_set_sensitive(context->but_edit, selected);
202 }
203
204 static gboolean
205 relation_item_list_selection_func(GtkTreeSelection *selection, GtkTreeModel *model,
206 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 relation_item_list_selected(context, TRUE);
214 }
215
216 return TRUE; /* allow selection state to change */
217 }
218
219 static void on_relation_item_add(GtkWidget *but, relitem_context_t *context) {
220 /* 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 }
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 static void on_relation_item_edit(GtkWidget *but, relitem_context_t *context) {
270 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 /* remove the selected relation */
279 static void on_relation_item_remove(GtkWidget *but, relitem_context_t *context) {
280 relation_t *sel = get_selection(context);
281 if(!sel) return;
282
283 printf("remove relation #%ld\n", sel->id);
284
285 gint members = osm_relation_members_num(sel);
286
287 if(members)
288 if(!yes_no_f(context->dialog, NULL, 0, 0,
289 _("Delete non-empty relation?"),
290 _("This relation still has %d members. "
291 "Delete it anyway?"), members))
292 return;
293
294 /* first remove selected row from list */
295 GtkTreeIter iter;
296 GtkTreeSelection *selection =
297 gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view));
298 if(gtk_tree_selection_get_selected(selection, NULL, &iter))
299 gtk_list_store_remove(context->store, &iter);
300
301 /* then really delete it */
302 osm_relation_delete(context->appdata->osm, sel, FALSE);
303
304 relation_item_list_selected(context, FALSE);
305 }
306
307 static char *relitem_get_role_in_relation(relation_item_t *item, relation_t *relation) {
308 member_t *member = relation->member;
309 while(member) {
310 switch(member->type) {
311
312 case NODE:
313 if((item->type == NODE) && (item->node == member->node))
314 return member->role;
315 break;
316
317 case WAY:
318 if((item->type == WAY) && (item->way == member->way))
319 return member->role;
320 break;
321
322 default:
323 break;
324 }
325 member = member->next;
326 }
327 return NULL;
328 }
329
330 static void
331 relitem_toggled(GtkCellRendererToggle *cell, const gchar *path_str,
332 relitem_context_t *context) {
333 GtkTreePath *path;
334 GtkTreeIter iter;
335
336 path = gtk_tree_path_new_from_string(path_str);
337 gtk_tree_model_get_iter(GTK_TREE_MODEL(context->store), &iter, path);
338 gtk_tree_path_free(path);
339
340 /* get current enabled flag */
341 gboolean enabled;
342 relation_t *relation = NULL;
343 gtk_tree_model_get(GTK_TREE_MODEL(context->store), &iter,
344 RELITEM_COL_SELECTED, &enabled,
345 RELITEM_COL_DATA, &relation,
346 -1);
347
348 if(!enabled) {
349 printf("will now become be part of this relation\n");
350 if(relation_add_item(context->dialog, relation, context->item))
351 gtk_list_store_set(context->store, &iter,
352 RELITEM_COL_SELECTED, TRUE,
353 RELITEM_COL_ROLE,
354 relitem_get_role_in_relation(context->item, relation),
355 -1);
356 } else {
357 printf("item will not be part of this relation anymore\n");
358 relation_remove_item(relation, context->item);
359 gtk_list_store_set(context->store, &iter,
360 RELITEM_COL_SELECTED, FALSE,
361 RELITEM_COL_ROLE, NULL,
362 -1);
363 }
364 }
365
366 static gboolean relitem_is_in_relation(relation_item_t *item, relation_t *relation) {
367 member_t *member = relation->member;
368 while(member) {
369 switch(member->type) {
370
371 case NODE:
372 if((item->type == NODE) && (item->node == member->node))
373 return TRUE;
374 break;
375
376 case WAY:
377 if((item->type == WAY) && (item->way == member->way))
378 return TRUE;
379 break;
380
381 default:
382 break;
383 }
384 member = member->next;
385 }
386 return FALSE;
387 }
388
389 static GtkWidget *relation_item_list_widget(relitem_context_t *context) {
390 GtkWidget *vbox = gtk_vbox_new(FALSE,3);
391 context->view = gtk_tree_view_new();
392
393 gtk_tree_selection_set_select_function(
394 gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)),
395 relation_item_list_selection_func,
396 context, NULL);
397
398
399 /* --- "selected" column --- */
400 GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new();
401 g_signal_connect(renderer, "toggled", G_CALLBACK(relitem_toggled), context);
402 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
403 -1, _(""), renderer,
404 "active", RELITEM_COL_SELECTED,
405 NULL);
406
407 /* --- "Type" column --- */
408 renderer = gtk_cell_renderer_text_new();
409 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
410 -1, _("Type"), renderer, "text", RELITEM_COL_TYPE, NULL);
411
412 /* --- "Role" column --- */
413 renderer = gtk_cell_renderer_text_new();
414 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
415 -1, _("Role"), renderer, "text", RELITEM_COL_ROLE, NULL);
416
417 /* --- "Name" column --- */
418 renderer = gtk_cell_renderer_text_new();
419 g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
420 GtkTreeViewColumn *column =
421 gtk_tree_view_column_new_with_attributes(_("Name"), renderer,
422 "text", RELITEM_COL_NAME, NULL);
423 gtk_tree_view_column_set_expand(column, TRUE);
424 gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1);
425
426
427 /* build and fill the store */
428 context->store = gtk_list_store_new(RELITEM_NUM_COLS,
429 G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING,
430 G_TYPE_STRING, G_TYPE_POINTER);
431
432 gtk_tree_view_set_model(GTK_TREE_VIEW(context->view),
433 GTK_TREE_MODEL(context->store));
434
435 GtkTreeIter iter;
436 relation_t *relation = context->appdata->osm->relation;
437 while(relation) {
438 /* try to find something descriptive */
439 char *name = osm_tag_get_by_key(relation->tag, "name");
440 if(!name) name = osm_tag_get_by_key(relation->tag, "ref");
441
442 /* Append a row and fill in some data */
443 gtk_list_store_append(context->store, &iter);
444 gtk_list_store_set(context->store, &iter,
445 RELITEM_COL_SELECTED, relitem_is_in_relation(context->item, relation),
446 RELITEM_COL_TYPE, osm_tag_get_by_key(relation->tag, "type"),
447 RELITEM_COL_ROLE, relitem_get_role_in_relation(context->item, relation),
448 RELITEM_COL_NAME, name,
449 RELITEM_COL_DATA, relation,
450 -1);
451
452 relation = relation->next;
453 }
454
455 g_object_unref(context->store);
456
457 /* put it into a scrolled window */
458 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
459 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
460 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
461 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
462 GTK_SHADOW_ETCHED_IN);
463 gtk_container_add(GTK_CONTAINER(scrolled_window), context->view);
464
465 gtk_box_pack_start_defaults(GTK_BOX(vbox), scrolled_window);
466
467 /* ------- button box ------------ */
468
469 GtkWidget *hbox = gtk_hbox_new(TRUE,3);
470
471 context->but_add = gtk_button_new_with_label(_("Add..."));
472 // gtk_widget_set_sensitive(context->but_add, FALSE);
473 gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_add);
474 gtk_signal_connect(GTK_OBJECT(context->but_add), "clicked",
475 GTK_SIGNAL_FUNC(on_relation_item_add), context);
476
477 context->but_edit = gtk_button_new_with_label(_("Edit..."));
478 gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_edit);
479 gtk_signal_connect(GTK_OBJECT(context->but_edit), "clicked",
480 GTK_SIGNAL_FUNC(on_relation_item_edit), context);
481
482 context->but_remove = gtk_button_new_with_label(_("Remove"));
483 gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_remove);
484 gtk_signal_connect(GTK_OBJECT(context->but_remove), "clicked",
485 GTK_SIGNAL_FUNC(on_relation_item_remove), context);
486
487 relation_item_list_selected(context, FALSE);
488
489 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
490 return vbox;
491 }
492
493 void relation_add_dialog(appdata_t *appdata, relation_item_t *relitem) {
494 relitem_context_t *context = g_new0(relitem_context_t, 1);
495 map_t *map = appdata->map;
496 g_assert(map);
497
498 context->appdata = appdata;
499 context->item = relitem;
500
501 char *str = NULL;
502 switch(relitem->type) {
503 case NODE:
504 str = g_strdup_printf(_("Relations for node #%ld"), relitem->node->id);
505 break;
506 case WAY:
507 str = g_strdup_printf(_("Relations for way #%ld"), relitem->way->id);
508 break;
509 default:
510 g_assert((relitem->type == NODE) || (relitem->type == WAY));
511 break;
512 }
513
514 context->dialog = gtk_dialog_new_with_buttons(str,
515 GTK_WINDOW(appdata->window), GTK_DIALOG_MODAL,
516 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
517 NULL);
518 g_free(str);
519
520 gtk_dialog_set_default_response(GTK_DIALOG(context->dialog),
521 GTK_RESPONSE_CLOSE);
522
523 /* making the dialog a little wider makes it less "crowded" */
524 #ifdef USE_HILDON
525 gtk_window_set_default_size(GTK_WINDOW(context->dialog), 500, 300);
526 #else
527 gtk_window_set_default_size(GTK_WINDOW(context->dialog), 400, 200);
528 #endif
529 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context->dialog)->vbox),
530 relation_item_list_widget(context), TRUE, TRUE, 0);
531
532 /* ----------------------------------- */
533
534 gtk_widget_show_all(context->dialog);
535 gtk_dialog_run(GTK_DIALOG(context->dialog));
536 gtk_widget_destroy(context->dialog);
537
538 g_free(context);
539 }
540
541 /* -------------------- global relation list ----------------- */
542
543 typedef struct {
544 appdata_t *appdata;
545 GtkWidget *dialog, *view;
546 GtkWidget *but_members, *but_add, *but_edit, *but_remove;
547 GtkListStore *store;
548 } relation_context_t;
549
550 enum {
551 RELATION_COL_ID = 0,
552 RELATION_COL_TYPE,
553 RELATION_COL_NAME,
554 RELATION_COL_MEMBERS,
555 RELATION_COL_DATA,
556 RELATION_NUM_COLS
557 };
558
559 static relation_t *get_selected_relation(relation_context_t *context) {
560 GtkTreeSelection *selection;
561 GtkTreeModel *model;
562 GtkTreeIter iter;
563
564 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view));
565 if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
566 relation_t *relation;
567 gtk_tree_model_get(model, &iter, RELATION_COL_DATA, &relation, -1);
568 return(relation);
569 }
570 return NULL;
571 }
572
573 static void relation_list_selected(relation_context_t *context,
574 relation_t *selected) {
575
576 if(context->but_members)
577 gtk_widget_set_sensitive(context->but_members,
578 (selected != NULL) && (selected->member != NULL));
579
580 if(context->but_remove)
581 gtk_widget_set_sensitive(context->but_remove, selected != NULL);
582 if(context->but_edit)
583 gtk_widget_set_sensitive(context->but_edit, selected != NULL);
584 }
585
586 static gboolean
587 relation_list_selection_func(GtkTreeSelection *selection, GtkTreeModel *model,
588 GtkTreePath *path, gboolean path_currently_selected,
589 gpointer userdata) {
590 relation_context_t *context = (relation_context_t*)userdata;
591 GtkTreeIter iter;
592
593 if(gtk_tree_model_get_iter(model, &iter, path)) {
594 g_assert(gtk_tree_path_get_depth(path) == 1);
595
596 relation_t *relation = NULL;
597 gtk_tree_model_get(model, &iter, RELATION_COL_DATA, &relation, -1);
598 relation_list_selected(context, relation);
599 }
600
601 return TRUE; /* allow selection state to change */
602 }
603
604 typedef struct {
605 relation_t *relation;
606 GtkWidget *dialog, *view;
607 GtkListStore *store;
608 } member_context_t;
609
610 enum {
611 MEMBER_COL_TYPE = 0,
612 MEMBER_COL_ID,
613 MEMBER_COL_NAME,
614 MEMBER_COL_ROLE,
615 MEMBER_COL_REF_ONLY,
616 MEMBER_COL_DATA,
617 MEMBER_NUM_COLS
618 };
619
620 static gboolean
621 member_list_selection_func(GtkTreeSelection *selection, GtkTreeModel *model,
622 GtkTreePath *path, gboolean path_currently_selected,
623 gpointer userdata) {
624 GtkTreeIter iter;
625
626 if(gtk_tree_model_get_iter(model, &iter, path)) {
627 g_assert(gtk_tree_path_get_depth(path) == 1);
628
629 member_t *member = NULL;
630 gtk_tree_model_get(model, &iter, MEMBER_COL_DATA, &member, -1);
631 if(member && member->type < NODE_ID)
632 return TRUE;
633 }
634
635 return FALSE;
636 }
637
638
639 static GtkWidget *member_list_widget(member_context_t *context) {
640 GtkWidget *vbox = gtk_vbox_new(FALSE,3);
641 context->view = gtk_tree_view_new();
642
643 gtk_tree_selection_set_select_function(
644 gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)),
645 member_list_selection_func,
646 context, NULL);
647
648 /* --- "type" column --- */
649 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
650 g_object_set(renderer, "foreground", "grey", NULL);
651 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
652 -1, _("Type"), renderer, "text", MEMBER_COL_TYPE,
653 "foreground-set", MEMBER_COL_REF_ONLY, NULL);
654
655
656 /* --- "id" column --- */
657 renderer = gtk_cell_renderer_text_new();
658 g_object_set(renderer, "foreground", "grey", NULL);
659 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
660 -1, _("Id"), renderer, "text", MEMBER_COL_ID,
661 "foreground-set", MEMBER_COL_REF_ONLY, NULL);
662
663 /* --- "Name" column --- */
664 renderer = gtk_cell_renderer_text_new();
665 g_object_set(renderer, "foreground", "grey", NULL);
666 g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
667 GtkTreeViewColumn *column =
668 gtk_tree_view_column_new_with_attributes(_("Name"), renderer,
669 "text", MEMBER_COL_NAME,
670 "foreground-set", MEMBER_COL_REF_ONLY, NULL);
671 gtk_tree_view_column_set_expand(column, TRUE);
672 gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1);
673
674 /* --- "role" column --- */
675 renderer = gtk_cell_renderer_text_new();
676 g_object_set(renderer, "foreground", "grey", NULL);
677 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
678 -1, _("Role"), renderer, "text", MEMBER_COL_ROLE,
679 "foreground-set", MEMBER_COL_REF_ONLY, NULL);
680
681 /* build and fill the store */
682 context->store = gtk_list_store_new(MEMBER_NUM_COLS,
683 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
684 G_TYPE_BOOLEAN, G_TYPE_POINTER);
685
686 gtk_tree_view_set_model(GTK_TREE_VIEW(context->view),
687 GTK_TREE_MODEL(context->store));
688
689 GtkTreeIter iter;
690 member_t *member = context->relation->member;
691 while(member) {
692 tag_t *tags = osm_object_get_tags(member->type, member->ptr);
693 char *id = osm_id_string(member->type, member->ptr);
694
695 /* try to find something descriptive */
696 char *name = NULL;
697 if(tags)
698 name = osm_tag_get_by_key(tags, "name");
699
700 /* Append a row and fill in some data */
701 gtk_list_store_append(context->store, &iter);
702 gtk_list_store_set(context->store, &iter,
703 MEMBER_COL_TYPE, osm_type_string(member->type),
704 MEMBER_COL_ID, id,
705 MEMBER_COL_NAME, name,
706 MEMBER_COL_ROLE, member->role,
707 MEMBER_COL_REF_ONLY, member->type >= NODE_ID,
708 MEMBER_COL_DATA, member,
709 -1);
710
711 g_free(id);
712 member = member->next;
713 }
714
715 g_object_unref(context->store);
716
717 /* put it into a scrolled window */
718 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
719 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
720 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
721 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
722 GTK_SHADOW_ETCHED_IN);
723 gtk_container_add(GTK_CONTAINER(scrolled_window), context->view);
724
725 gtk_box_pack_start_defaults(GTK_BOX(vbox), scrolled_window);
726
727 return vbox;
728 }
729
730 /* user clicked "members..." button in relation list */
731 static void on_relation_members(GtkWidget *but, relation_context_t *context) {
732 member_context_t *mcontext = g_new0(member_context_t, 1);
733
734 /* display members list */
735 mcontext->relation = get_selected_relation(context);
736 if(!mcontext->relation) return;
737
738 char *str = osm_tag_get_by_key(mcontext->relation->tag, "name");
739 if(!str) str = osm_tag_get_by_key(mcontext->relation->tag, "ref");
740 if(!str)
741 str = g_strdup_printf(_("Members of relation #%ld"),
742 mcontext->relation->id);
743 else
744 str = g_strdup_printf(_("Members of relation \"%s\""), str);
745
746 mcontext->dialog =
747 gtk_dialog_new_with_buttons(str,
748 GTK_WINDOW(context->dialog), GTK_DIALOG_MODAL,
749 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
750 NULL);
751 g_free(str);
752
753 gtk_dialog_set_default_response(GTK_DIALOG(mcontext->dialog),
754 GTK_RESPONSE_CLOSE);
755
756 /* making the dialog a little wider makes it less "crowded" */
757 #ifdef USE_HILDON
758 gtk_window_set_default_size(GTK_WINDOW(mcontext->dialog), 500, 300);
759 #else
760 gtk_window_set_default_size(GTK_WINDOW(mcontext->dialog), 400, 200);
761 #endif
762
763 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(mcontext->dialog)->vbox),
764 member_list_widget(mcontext), TRUE, TRUE, 0);
765
766 /* ----------------------------------- */
767
768 gtk_widget_show_all(mcontext->dialog);
769 gtk_dialog_run(GTK_DIALOG(mcontext->dialog));
770 gtk_widget_destroy(mcontext->dialog);
771
772 g_free(mcontext);
773 }
774
775 static void on_relation_add(GtkWidget *but, relation_context_t *context) {
776 /* create a new relation */
777
778 relation_t *relation = osm_relation_new();
779 if(!info_dialog(context->dialog, context->appdata, relation)) {
780 printf("tag edit cancelled\n");
781 osm_relation_free(relation);
782 } else {
783 osm_relation_attach(context->appdata->osm, relation);
784
785 /* append a row for the new data */
786 /* try to find something descriptive */
787
788 char *id = g_strdup_printf("#%ld", relation->id);
789
790 /* try to find something descriptive */
791 char *name = osm_tag_get_by_key(relation->tag, "name");
792 if(!name) name = osm_tag_get_by_key(relation->tag, "ref");
793
794 char *num = g_strdup_printf("%d", osm_relation_members_num(relation));
795
796 /* Append a row and fill in some data */
797 GtkTreeIter iter;
798 gtk_list_store_append(context->store, &iter);
799 gtk_list_store_set(context->store, &iter,
800 RELATION_COL_ID, id,
801 RELATION_COL_TYPE,
802 osm_tag_get_by_key(relation->tag, "type"),
803 RELATION_COL_NAME, name,
804 RELATION_COL_MEMBERS, num,
805 RELATION_COL_DATA, relation,
806 -1);
807
808 g_free(id);
809 g_free(num);
810
811 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(
812 GTK_TREE_VIEW(context->view)), &iter);
813
814 /* scroll to end */
815 // GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment();
816 /* xyz */
817 }
818 }
819
820 /* user clicked "edit..." button in relation list */
821 static void on_relation_edit(GtkWidget *but, relation_context_t *context) {
822 relation_t *sel = get_selected_relation(context);
823 if(!sel) return;
824
825 printf("edit relation #%ld\n", sel->id);
826
827 info_dialog(context->dialog, context->appdata, sel);
828 }
829
830 /* remove the selected relation */
831 static void on_relation_remove(GtkWidget *but, relation_context_t *context) {
832 relation_t *sel = get_selected_relation(context);
833 if(!sel) return;
834
835 printf("remove relation #%ld\n", sel->id);
836
837 gint members = osm_relation_members_num(sel);
838
839 if(members)
840 if(!yes_no_f(context->dialog, NULL, 0, 0,
841 _("Delete non-empty relation?"),
842 _("This relation still has %d members. "
843 "Delete it anyway?"), members))
844 return;
845
846 /* first remove selected row from list */
847 GtkTreeIter iter;
848 GtkTreeSelection *selection =
849 gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view));
850 if(gtk_tree_selection_get_selected(selection, NULL, &iter))
851 gtk_list_store_remove(context->store, &iter);
852
853 /* then really delete it */
854 osm_relation_delete(context->appdata->osm, sel, FALSE);
855
856 relation_list_selected(context, NULL);
857 }
858
859 static GtkWidget *relation_list_widget(relation_context_t *context) {
860 GtkWidget *vbox = gtk_vbox_new(FALSE,3);
861 context->view = gtk_tree_view_new();
862
863 gtk_tree_selection_set_select_function(
864 gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)),
865 relation_list_selection_func,
866 context, NULL);
867
868 /* --- "id" column --- */
869 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
870 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
871 -1, _("Id"), renderer, "text", RELATION_COL_ID, NULL);
872
873 /* --- "Type" column --- */
874 renderer = gtk_cell_renderer_text_new();
875 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
876 -1, _("Type"), renderer, "text", RELATION_COL_TYPE, NULL);
877
878 /* --- "Name" column --- */
879 renderer = gtk_cell_renderer_text_new();
880 g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
881 GtkTreeViewColumn *column =
882 gtk_tree_view_column_new_with_attributes(_("Name"), renderer,
883 "text", RELATION_COL_NAME, NULL);
884 gtk_tree_view_column_set_expand(column, TRUE);
885 gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1);
886
887 /* --- "members" column --- */
888 renderer = gtk_cell_renderer_text_new();
889 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(context->view),
890 -1, _("Members"), renderer, "text", RELATION_COL_MEMBERS, NULL);
891
892 /* build and fill the store */
893 context->store = gtk_list_store_new(RELATION_NUM_COLS,
894 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
895 G_TYPE_POINTER);
896
897 gtk_tree_view_set_model(GTK_TREE_VIEW(context->view),
898 GTK_TREE_MODEL(context->store));
899
900 GtkTreeIter iter;
901 relation_t *relation = context->appdata->osm->relation;
902 while(relation) {
903 char *id = g_strdup_printf("#%ld", relation->id);
904
905 /* try to find something descriptive */
906 char *name = osm_tag_get_by_key(relation->tag, "name");
907 if(!name) name = osm_tag_get_by_key(relation->tag, "ref");
908
909 char *num = g_strdup_printf("%d", osm_relation_members_num(relation));
910
911 /* Append a row and fill in some data */
912 gtk_list_store_append(context->store, &iter);
913 gtk_list_store_set(context->store, &iter,
914 RELATION_COL_ID, id,
915 RELATION_COL_TYPE,
916 osm_tag_get_by_key(relation->tag, "type"),
917 RELATION_COL_NAME, name,
918 RELATION_COL_MEMBERS, num,
919 RELATION_COL_DATA, relation,
920 -1);
921
922 g_free(id);
923 g_free(num);
924 relation = relation->next;
925 }
926
927 g_object_unref(context->store);
928
929 /* put it into a scrolled window */
930 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
931 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
932 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
933 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
934 GTK_SHADOW_ETCHED_IN);
935 gtk_container_add(GTK_CONTAINER(scrolled_window), context->view);
936
937 gtk_box_pack_start_defaults(GTK_BOX(vbox), scrolled_window);
938
939 /* ------- button box ------------ */
940
941 GtkWidget *hbox = gtk_hbox_new(TRUE,3);
942
943 context->but_add = gtk_button_new_with_label(_("Add..."));
944 gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_add);
945 gtk_signal_connect(GTK_OBJECT(context->but_add), "clicked",
946 GTK_SIGNAL_FUNC(on_relation_add), context);
947
948 context->but_edit = gtk_button_new_with_label(_("Edit..."));
949 gtk_widget_set_sensitive(context->but_edit, FALSE);
950 gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_edit);
951 gtk_signal_connect(GTK_OBJECT(context->but_edit), "clicked",
952 GTK_SIGNAL_FUNC(on_relation_edit), context);
953
954 context->but_members = gtk_button_new_with_label(_("Members..."));
955 gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_members);
956 gtk_signal_connect(GTK_OBJECT(context->but_members), "clicked",
957 GTK_SIGNAL_FUNC(on_relation_members), context);
958
959 context->but_remove = gtk_button_new_with_label(_("Remove"));
960 gtk_widget_set_sensitive(context->but_remove, FALSE);
961 gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_remove);
962 gtk_signal_connect(GTK_OBJECT(context->but_remove), "clicked",
963 GTK_SIGNAL_FUNC(on_relation_remove), context);
964
965 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
966
967 relation_list_selected(context, NULL);
968
969 return vbox;
970 }
971
972 /* a global view on all relations */
973 void relation_list(appdata_t *appdata) {
974 relation_context_t *context = g_new0(relation_context_t, 1);
975 context->appdata = appdata;
976
977 printf("relation list\n");
978
979 context->dialog =
980 gtk_dialog_new_with_buttons(_("All relations"),
981 GTK_WINDOW(appdata->window), GTK_DIALOG_MODAL,
982 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
983 NULL);
984
985 gtk_dialog_set_default_response(GTK_DIALOG(context->dialog),
986 GTK_RESPONSE_CLOSE);
987
988 /* making the dialog a little wider makes it less "crowded" */
989 #ifdef USE_HILDON
990 gtk_window_set_default_size(GTK_WINDOW(context->dialog), 500, 300);
991 #else
992 gtk_window_set_default_size(GTK_WINDOW(context->dialog), 400, 200);
993 #endif
994 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context->dialog)->vbox),
995 relation_list_widget(context), TRUE, TRUE, 0);
996
997 /* ----------------------------------- */
998
999 gtk_widget_show_all(context->dialog);
1000 gtk_dialog_run(GTK_DIALOG(context->dialog));
1001 gtk_widget_destroy(context->dialog);
1002
1003 g_free(context);
1004 }