Parent Directory | Revision Log
ID hashing for fast ID resolving
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 | enum { |
23 | TAG_COL_KEY = 0, |
24 | TAG_COL_VALUE, |
25 | TAG_COL_COLLISION, |
26 | TAG_COL_DATA, |
27 | TAG_NUM_COLS |
28 | }; |
29 | |
30 | gboolean info_tag_key_collision(tag_t *tags, tag_t *tag) { |
31 | while(tags) { |
32 | if((tags != tag) && (strcasecmp(tags->key, tag->key) == 0)) |
33 | return TRUE; |
34 | |
35 | tags = tags->next; |
36 | } |
37 | return FALSE; |
38 | } |
39 | |
40 | static gboolean |
41 | view_selection_func(GtkTreeSelection *selection, GtkTreeModel *model, |
42 | GtkTreePath *path, gboolean path_currently_selected, |
43 | gpointer userdata) { |
44 | tag_context_t *context = (tag_context_t*)userdata; |
45 | GtkTreeIter iter; |
46 | |
47 | if(gtk_tree_model_get_iter(model, &iter, path)) { |
48 | g_assert(gtk_tree_path_get_depth(path) == 1); |
49 | |
50 | tag_t *tag; |
51 | gtk_tree_model_get(model, &iter, TAG_COL_DATA, &tag, -1); |
52 | |
53 | if(context->but_remove && context->but_edit) { |
54 | |
55 | /* you just cannot delete or edit the "created_by" tag */ |
56 | if(context->but_remove && context->but_edit) { |
57 | if(strcasecmp(tag->key, "created_by") == 0) { |
58 | gtk_widget_set_sensitive(context->but_remove, FALSE); |
59 | gtk_widget_set_sensitive(context->but_edit, FALSE); |
60 | } else { |
61 | gtk_widget_set_sensitive(context->but_remove, TRUE); |
62 | gtk_widget_set_sensitive(context->but_edit, TRUE); |
63 | } |
64 | } |
65 | } |
66 | } |
67 | |
68 | return TRUE; /* allow selection state to change */ |
69 | } |
70 | |
71 | static void update_collisions(GtkListStore *store, tag_t *tags) { |
72 | GtkTreeIter iter; |
73 | tag_t *tag = NULL; |
74 | |
75 | /* walk the entire store to get all values */ |
76 | if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { |
77 | gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, TAG_COL_DATA, &tag, -1); |
78 | g_assert(tag); |
79 | gtk_list_store_set(store, &iter, |
80 | TAG_COL_COLLISION, info_tag_key_collision(tags, tag), -1); |
81 | |
82 | while(gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)) { |
83 | gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, |
84 | TAG_COL_DATA, &tag, -1); |
85 | g_assert(tag); |
86 | gtk_list_store_set(store, &iter, |
87 | TAG_COL_COLLISION, info_tag_key_collision(tags, tag), -1); |
88 | } |
89 | } |
90 | } |
91 | |
92 | static void on_tag_remove(GtkWidget *but, tag_context_t *context) { |
93 | GtkTreeSelection *selection; |
94 | GtkTreeModel *model; |
95 | GtkTreeIter iter; |
96 | |
97 | selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)); |
98 | if(gtk_tree_selection_get_selected(selection, &model, &iter)) { |
99 | tag_t *tag; |
100 | gtk_tree_model_get(model, &iter, TAG_COL_DATA, &tag, -1); |
101 | |
102 | g_assert(tag); |
103 | |
104 | /* de-chain */ |
105 | printf("de-chaining tag %s/%s\n", tag->key, tag->value); |
106 | tag_t **prev = context->tag; |
107 | while(*prev != tag) prev = &((*prev)->next); |
108 | *prev = tag->next; |
109 | |
110 | /* free tag itself */ |
111 | osm_tag_free(tag); |
112 | |
113 | /* and remove from store */ |
114 | gtk_list_store_remove(GTK_LIST_STORE(model), &iter); |
115 | |
116 | update_collisions(context->store, *context->tag); |
117 | } |
118 | |
119 | /* disable remove and edit buttons */ |
120 | gtk_widget_set_sensitive(context->but_remove, FALSE); |
121 | gtk_widget_set_sensitive(context->but_edit, FALSE); |
122 | } |
123 | |
124 | static gboolean tag_edit(tag_context_t *context) { |
125 | |
126 | GtkTreeModel *model; |
127 | GtkTreeIter iter; |
128 | tag_t *tag; |
129 | |
130 | GtkTreeSelection *sel = gtk_tree_view_get_selection( |
131 | GTK_TREE_VIEW(context->view)); |
132 | if(!sel) { |
133 | printf("got no selection object\n"); |
134 | return FALSE; |
135 | } |
136 | |
137 | if(!gtk_tree_selection_get_selected(sel, &model, &iter)) { |
138 | printf("nothing selected\n"); |
139 | return FALSE; |
140 | } |
141 | |
142 | gtk_tree_model_get(model, &iter, TAG_COL_DATA, &tag, -1); |
143 | printf("got %s/%s\n", tag->key, tag->value); |
144 | |
145 | GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Edit Tag"), |
146 | GTK_WINDOW(context->dialog), GTK_DIALOG_MODAL, |
147 | GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, |
148 | GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, |
149 | NULL); |
150 | |
151 | #ifdef USE_HILDON |
152 | gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 100); |
153 | #else |
154 | gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 100); |
155 | #endif |
156 | |
157 | gtk_dialog_set_default_response(GTK_DIALOG(dialog), |
158 | GTK_RESPONSE_ACCEPT); |
159 | |
160 | GtkWidget *label, *key, *value; |
161 | GtkWidget *table = gtk_table_new(2, 2, FALSE); |
162 | |
163 | gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Key:")), |
164 | 0, 1, 0, 1, 0, 0, 0, 0); |
165 | gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); |
166 | gtk_table_attach_defaults(GTK_TABLE(table), |
167 | key = gtk_entry_new(), 1, 2, 0, 1); |
168 | gtk_entry_set_activates_default(GTK_ENTRY(key), TRUE); |
169 | HILDON_ENTRY_NO_AUTOCAP(key); |
170 | |
171 | gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Value:")), |
172 | 0, 1, 1, 2, 0, 0, 0, 0); |
173 | gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); |
174 | gtk_table_attach_defaults(GTK_TABLE(table), |
175 | value = gtk_entry_new(), 1, 2, 1, 2); |
176 | gtk_entry_set_activates_default(GTK_ENTRY(value), TRUE); |
177 | HILDON_ENTRY_NO_AUTOCAP(value); |
178 | |
179 | gtk_entry_set_text(GTK_ENTRY(key), tag->key); |
180 | gtk_entry_set_text(GTK_ENTRY(value), tag->value); |
181 | |
182 | gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table); |
183 | |
184 | gtk_widget_show_all(dialog); |
185 | |
186 | if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) { |
187 | free(tag->key); free(tag->value); |
188 | tag->key = strdup((char*)gtk_entry_get_text(GTK_ENTRY(key))); |
189 | tag->value = strdup((char*)gtk_entry_get_text(GTK_ENTRY(value))); |
190 | printf("setting %s/%s\n", tag->key, tag->value); |
191 | |
192 | gtk_list_store_set(context->store, &iter, |
193 | TAG_COL_KEY, tag->key, |
194 | TAG_COL_VALUE, tag->value, |
195 | -1); |
196 | |
197 | gtk_widget_destroy(dialog); |
198 | |
199 | /* update collisions for all entries */ |
200 | update_collisions(context->store, *context->tag); |
201 | return TRUE; |
202 | } |
203 | |
204 | gtk_widget_destroy(dialog); |
205 | return FALSE; |
206 | } |
207 | |
208 | static void on_tag_edit(GtkWidget *button, tag_context_t *context) { |
209 | tag_edit(context); |
210 | } |
211 | |
212 | static void on_tag_last(GtkWidget *button, tag_context_t *context) { |
213 | static const char *type_name[] = { "illegal", "node", "way", "relation" }; |
214 | |
215 | if(yes_no_f(context->dialog, |
216 | context->appdata, MISC_AGAIN_ID_OVERWRITE_TAGS, 0, |
217 | _("Overwrite tags?"), |
218 | _("This will overwrite all tags of this %s with the " |
219 | "ones from the %s selected last.\n\n" |
220 | "Do you really want this?"), |
221 | type_name[context->type], type_name[context->type])) { |
222 | |
223 | osm_tags_free(*context->tag); |
224 | |
225 | if(context->type == NODE) |
226 | *context->tag = osm_tags_copy(context->appdata->map->last_node_tags, TRUE); |
227 | else |
228 | *context->tag = osm_tags_copy(context->appdata->map->last_way_tags, TRUE); |
229 | |
230 | info_tags_replace(context); |
231 | } |
232 | } |
233 | |
234 | static void on_tag_add(GtkWidget *button, tag_context_t *context) { |
235 | /* search end of tag chain */ |
236 | tag_t **tag = context->tag; |
237 | while(*tag) |
238 | tag = &(*tag)->next; |
239 | |
240 | /* create and append a new tag */ |
241 | *tag = g_new0(tag_t, 1); |
242 | if(!*tag) { |
243 | errorf(GTK_WIDGET(context->appdata->window), _("Out of memory")); |
244 | return; |
245 | } |
246 | |
247 | /* fill with some empty strings */ |
248 | (*tag)->key = strdup(""); |
249 | (*tag)->value = strdup(""); |
250 | |
251 | /* append a row for the new data */ |
252 | GtkTreeIter iter; |
253 | gtk_list_store_append(context->store, &iter); |
254 | gtk_list_store_set(context->store, &iter, |
255 | TAG_COL_KEY, (*tag)->key, |
256 | TAG_COL_VALUE, (*tag)->value, |
257 | TAG_COL_COLLISION, FALSE, |
258 | TAG_COL_DATA, *tag, |
259 | -1); |
260 | |
261 | gtk_tree_selection_select_iter(gtk_tree_view_get_selection( |
262 | GTK_TREE_VIEW(context->view)), &iter); |
263 | |
264 | if(!tag_edit(context)) { |
265 | printf("cancelled\n"); |
266 | on_tag_remove(NULL, context); |
267 | } |
268 | } |
269 | |
270 | void info_tags_replace(tag_context_t *context) { |
271 | gtk_list_store_clear(context->store); |
272 | |
273 | GtkTreeIter iter; |
274 | tag_t *tag = *context->tag; |
275 | while(tag) { |
276 | gtk_list_store_append(context->store, &iter); |
277 | gtk_list_store_set(context->store, &iter, |
278 | TAG_COL_KEY, tag->key, |
279 | TAG_COL_VALUE, tag->value, |
280 | TAG_COL_COLLISION, info_tag_key_collision(*context->tag, tag), |
281 | TAG_COL_DATA, tag, |
282 | -1); |
283 | tag = tag->next; |
284 | } |
285 | } |
286 | |
287 | static GtkWidget *tag_widget(tag_context_t *context) { |
288 | GtkWidget *vbox = gtk_vbox_new(FALSE,3); |
289 | context->view = gtk_tree_view_new(); |
290 | |
291 | gtk_tree_selection_set_select_function( |
292 | gtk_tree_view_get_selection(GTK_TREE_VIEW(context->view)), |
293 | view_selection_func, |
294 | context, NULL); |
295 | |
296 | /* --- "Key" column --- */ |
297 | GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); |
298 | g_object_set(renderer, |
299 | "ellipsize", PANGO_ELLIPSIZE_END, |
300 | "background", "red", |
301 | NULL ); |
302 | GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes( |
303 | _("Key"), renderer, |
304 | "text", TAG_COL_KEY, |
305 | "background-set", TAG_COL_COLLISION, |
306 | NULL); |
307 | gtk_tree_view_column_set_expand(column, TRUE); |
308 | gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1); |
309 | |
310 | /* --- "Value" column --- */ |
311 | renderer = gtk_cell_renderer_text_new(); |
312 | g_object_set(renderer, |
313 | "ellipsize", PANGO_ELLIPSIZE_END, |
314 | NULL ); |
315 | column = gtk_tree_view_column_new_with_attributes( |
316 | _("Value"), renderer, |
317 | "text", TAG_COL_VALUE, |
318 | NULL); |
319 | gtk_tree_view_column_set_expand(column, TRUE); |
320 | gtk_tree_view_insert_column(GTK_TREE_VIEW(context->view), column, -1); |
321 | |
322 | /* build and fill the store */ |
323 | context->store = gtk_list_store_new(TAG_NUM_COLS, |
324 | G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER); |
325 | |
326 | gtk_tree_view_set_model(GTK_TREE_VIEW(context->view), |
327 | GTK_TREE_MODEL(context->store)); |
328 | |
329 | GtkTreeIter iter; |
330 | tag_t *tag = *context->tag; |
331 | while(tag) { |
332 | /* Append a row and fill in some data */ |
333 | gtk_list_store_append(context->store, &iter); |
334 | gtk_list_store_set(context->store, &iter, |
335 | TAG_COL_KEY, tag->key, |
336 | TAG_COL_VALUE, tag->value, |
337 | TAG_COL_COLLISION, info_tag_key_collision(*context->tag, tag), |
338 | TAG_COL_DATA, tag, |
339 | -1); |
340 | tag = tag->next; |
341 | } |
342 | |
343 | g_object_unref(context->store); |
344 | |
345 | /* put it into a scrolled window */ |
346 | GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL); |
347 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), |
348 | GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); |
349 | gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), |
350 | GTK_SHADOW_ETCHED_IN); |
351 | // gtk_container_set_border_width(GTK_CONTAINER(scrolled_window), 3); |
352 | gtk_container_add(GTK_CONTAINER(scrolled_window), context->view); |
353 | gtk_box_pack_start_defaults(GTK_BOX(vbox), scrolled_window); |
354 | |
355 | /* ------- button box ------------ */ |
356 | |
357 | GtkWidget *hbox = gtk_hbox_new(TRUE,3); |
358 | |
359 | GtkWidget *but_last = gtk_button_new_with_label(_("Last...")); |
360 | gtk_box_pack_start_defaults(GTK_BOX(hbox), but_last); |
361 | |
362 | /* disable if no appropriate "last" tags have been stored or if the */ |
363 | /* selected item isn't a node or way */ |
364 | if(((context->type == NODE) && |
365 | (!context->appdata->map->last_node_tags)) || |
366 | ((context->type == WAY) && |
367 | (!context->appdata->map->last_way_tags)) || |
368 | ((context->type != NODE) && (context->type != WAY))) |
369 | gtk_widget_set_sensitive(but_last, FALSE); |
370 | |
371 | gtk_signal_connect(GTK_OBJECT(but_last), "clicked", |
372 | GTK_SIGNAL_FUNC(on_tag_last), context); |
373 | |
374 | GtkWidget *presets = josm_presets_select(context->appdata, context); |
375 | if(presets) gtk_box_pack_start_defaults(GTK_BOX(hbox), presets); |
376 | |
377 | context->but_add = gtk_button_new_with_label(_("Add...")); |
378 | gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_add); |
379 | gtk_signal_connect(GTK_OBJECT(context->but_add), "clicked", |
380 | GTK_SIGNAL_FUNC(on_tag_add), context); |
381 | |
382 | context->but_edit = gtk_button_new_with_label(_("Edit...")); |
383 | gtk_widget_set_sensitive(context->but_edit, FALSE); |
384 | gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_edit); |
385 | gtk_signal_connect(GTK_OBJECT(context->but_edit), "clicked", |
386 | GTK_SIGNAL_FUNC(on_tag_edit), context); |
387 | |
388 | context->but_remove = gtk_button_new_with_label(_("Remove")); |
389 | gtk_widget_set_sensitive(context->but_remove, FALSE); |
390 | gtk_box_pack_start_defaults(GTK_BOX(hbox), context->but_remove); |
391 | gtk_signal_connect(GTK_OBJECT(context->but_remove), "clicked", |
392 | GTK_SIGNAL_FUNC(on_tag_remove), context); |
393 | |
394 | |
395 | gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
396 | return vbox; |
397 | } |
398 | |
399 | /* edit tags of currently selected node or way or of the relation */ |
400 | /* given */ |
401 | void info_dialog(GtkWidget *parent, appdata_t *appdata, relation_t *relation) { |
402 | if(!relation) |
403 | g_assert(appdata->map->selected.type != MAP_TYPE_ILLEGAL); |
404 | |
405 | tag_context_t *context = g_new0(tag_context_t, 1); |
406 | user_t *user = NULL; |
407 | char *str = NULL; |
408 | time_t stime = 0; |
409 | tag_t *work_copy = NULL; |
410 | |
411 | context->appdata = appdata; |
412 | context->tag = &work_copy; |
413 | |
414 | if(!relation) { |
415 | switch(appdata->map->selected.type) { |
416 | case MAP_TYPE_NODE: |
417 | str = g_strdup_printf(_("Node #%ld"), appdata->map->selected.node->id); |
418 | user = appdata->map->selected.node->user; |
419 | work_copy = osm_tags_copy(appdata->map->selected.node->tag, FALSE); |
420 | stime = appdata->map->selected.node->time; |
421 | context->type = NODE; |
422 | break; |
423 | case MAP_TYPE_WAY: |
424 | str = g_strdup_printf(_("Way #%ld"), appdata->map->selected.way->id); |
425 | user = appdata->map->selected.way->user; |
426 | work_copy = osm_tags_copy(appdata->map->selected.way->tag, FALSE); |
427 | stime = appdata->map->selected.way->time; |
428 | context->type = WAY; |
429 | break; |
430 | default: |
431 | g_assert((appdata->map->selected.type == MAP_TYPE_NODE) || |
432 | (appdata->map->selected.type == MAP_TYPE_WAY)); |
433 | break; |
434 | } |
435 | } else { |
436 | str = g_strdup_printf(_("Relation #%ld"), relation->id); |
437 | user = relation->user; |
438 | work_copy = osm_tags_copy(relation->tag, FALSE); |
439 | stime = relation->time; |
440 | context->type = RELATION; |
441 | } |
442 | |
443 | context->dialog = gtk_dialog_new_with_buttons(str, |
444 | GTK_WINDOW(parent), GTK_DIALOG_MODAL, |
445 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
446 | GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, |
447 | NULL); |
448 | g_free(str); |
449 | |
450 | gtk_dialog_set_default_response(GTK_DIALOG(context->dialog), |
451 | GTK_RESPONSE_ACCEPT); |
452 | |
453 | /* making the dialog a little wider makes it less "crowded" */ |
454 | #ifdef USE_HILDON |
455 | gtk_window_set_default_size(GTK_WINDOW(context->dialog), 500, 300); |
456 | #else |
457 | gtk_window_set_default_size(GTK_WINDOW(context->dialog), 400, 200); |
458 | #endif |
459 | |
460 | GtkWidget *label; |
461 | GtkWidget *table = gtk_table_new(2, 2, FALSE); // x, y |
462 | |
463 | /* ------------ user ----------------- */ |
464 | char *u_str = NULL; |
465 | if(user) u_str = g_strdup_printf(_("User: %s"), user->name); |
466 | else u_str = g_strdup_printf(_("User: ---")); |
467 | label = gtk_label_new(u_str); |
468 | gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); |
469 | g_free(u_str); |
470 | |
471 | /* ------------ time ----------------- */ |
472 | |
473 | struct tm *loctime = localtime(&stime); |
474 | char time_str[32]; |
475 | strftime(time_str, sizeof(time_str), "%x %X", loctime); |
476 | char *t_str = g_strdup_printf(_("Time: %s"), time_str); |
477 | label = gtk_label_new(t_str); |
478 | g_free(t_str); |
479 | gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 0, 1); |
480 | |
481 | /* ------------ coordinate (only for nodes) ----------------- */ |
482 | if(!relation) { |
483 | if(appdata->map->selected.type == MAP_TYPE_NODE) { |
484 | char pos_str[32]; |
485 | pos_lat_str(pos_str, sizeof(pos_str),appdata->map->selected.node->pos.lat); |
486 | label = gtk_label_new(pos_str); |
487 | gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); |
488 | pos_lat_str(pos_str, sizeof(pos_str),appdata->map->selected.node->pos.lon); |
489 | label = gtk_label_new(pos_str); |
490 | gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2); |
491 | } else { |
492 | char *nodes_str = g_strdup_printf(_("Length: %u nodes"), |
493 | osm_way_number_of_nodes(appdata->map->selected.way)); |
494 | label = gtk_label_new(nodes_str); |
495 | gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); |
496 | g_free(nodes_str); |
497 | |
498 | char *type_str = g_strdup_printf("%s (%s)", |
499 | (osm_way_get_last_node(appdata->map->selected.way) == |
500 | osm_way_get_first_node(appdata->map->selected.way))? |
501 | "closed way":"open way", |
502 | (appdata->map->selected.way->draw.flags & OSM_DRAW_FLAG_AREA)? |
503 | "area":"line"); |
504 | |
505 | label = gtk_label_new(type_str); |
506 | gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2); |
507 | g_free(type_str); |
508 | } |
509 | } else { |
510 | /* relations tell something about their members */ |
511 | gint nodes = 0, ways = 0, relations = 0; |
512 | member_t *member = relation->member; |
513 | while(member) { |
514 | switch(member->type) { |
515 | case NODE: |
516 | case NODE_ID: |
517 | nodes++; |
518 | break; |
519 | case WAY: |
520 | case WAY_ID: |
521 | ways++; |
522 | break; |
523 | case RELATION: |
524 | case RELATION_ID: |
525 | relations++; |
526 | break; |
527 | |
528 | default: |
529 | break; |
530 | } |
531 | |
532 | member = member->next; |
533 | } |
534 | |
535 | char *str = g_strdup_printf(_("Members: %d nodes, %d ways, %d relations"), |
536 | nodes, ways, relations); |
537 | |
538 | gtk_table_attach_defaults(GTK_TABLE(table), gtk_label_new(str), 0, 2, 1, 2); |
539 | g_free(str); |
540 | } |
541 | |
542 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context->dialog)->vbox), table, |
543 | FALSE, FALSE, 0); |
544 | |
545 | |
546 | /* ------------ tags ----------------- */ |
547 | |
548 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context->dialog)->vbox), |
549 | tag_widget(context), TRUE, TRUE, 0); |
550 | |
551 | /* ----------------------------------- */ |
552 | |
553 | gtk_widget_show_all(context->dialog); |
554 | if(gtk_dialog_run(GTK_DIALOG(context->dialog)) == GTK_RESPONSE_ACCEPT) { |
555 | gtk_widget_destroy(context->dialog); |
556 | |
557 | if(!relation) { |
558 | /* replace original tags with work copy */ |
559 | switch(appdata->map->selected.type) { |
560 | |
561 | case MAP_TYPE_NODE: |
562 | osm_tags_free(appdata->map->selected.node->tag); |
563 | appdata->map->selected.node->tag = osm_tags_copy(work_copy, TRUE); |
564 | break; |
565 | |
566 | case MAP_TYPE_WAY: |
567 | osm_tags_free(appdata->map->selected.way->tag); |
568 | appdata->map->selected.way->tag = osm_tags_copy(work_copy, TRUE); |
569 | break; |
570 | |
571 | default: |
572 | break; |
573 | } |
574 | |
575 | /* since nodes being parts of ways but with no tags are invisible, */ |
576 | /* the result of editing them may have changed their visibility */ |
577 | map_item_redraw(appdata, &appdata->map->selected); |
578 | map_item_set_flags(&context->appdata->map->selected, OSM_FLAG_DIRTY, 0); |
579 | } else { |
580 | osm_tags_free(relation->tag); |
581 | relation->tag = osm_tags_copy(work_copy, TRUE); |
582 | relation->flags |= OSM_FLAG_DIRTY; |
583 | } |
584 | } else { |
585 | gtk_widget_destroy(context->dialog); |
586 | osm_tags_free(work_copy); |
587 | } |
588 | |
589 | g_free(context); |
590 | } |