Parent Directory | Revision Log
Relation editor lists are now sorted by name.
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 | 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 | harbaum | 42 | #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 | harbaum | 1 | 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 | harbaum | 42 | gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Key:")), |
164 | 0, 1, 0, 1, 0, 0, 0, 0); | ||
165 | harbaum | 1 | gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); |
166 | gtk_table_attach_defaults(GTK_TABLE(table), | ||
167 | harbaum | 42 | key = gtk_entry_new(), 1, 2, 0, 1); |
168 | harbaum | 1 | gtk_entry_set_activates_default(GTK_ENTRY(key), TRUE); |
169 | HILDON_ENTRY_NO_AUTOCAP(key); | ||
170 | |||
171 | harbaum | 42 | gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Value:")), |
172 | 0, 1, 1, 2, 0, 0, 0, 0); | ||
173 | harbaum | 1 | 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 | harbaum | 73 | gboolean info_dialog(GtkWidget *parent, appdata_t *appdata, relation_t *relation) { |
402 | harbaum | 1 | 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 | harbaum | 52 | context->presets_type = PRESETS_TYPE_NODE; |
423 | harbaum | 1 | break; |
424 | case MAP_TYPE_WAY: | ||
425 | str = g_strdup_printf(_("Way #%ld"), appdata->map->selected.way->id); | ||
426 | user = appdata->map->selected.way->user; | ||
427 | work_copy = osm_tags_copy(appdata->map->selected.way->tag, FALSE); | ||
428 | stime = appdata->map->selected.way->time; | ||
429 | context->type = WAY; | ||
430 | harbaum | 52 | context->presets_type = PRESETS_TYPE_WAY; |
431 | |||
432 | if(osm_way_get_last_node(appdata->map->selected.way) == | ||
433 | osm_way_get_first_node(appdata->map->selected.way)) | ||
434 | context->presets_type |= PRESETS_TYPE_CLOSEDWAY; | ||
435 | |||
436 | harbaum | 1 | break; |
437 | default: | ||
438 | g_assert((appdata->map->selected.type == MAP_TYPE_NODE) || | ||
439 | (appdata->map->selected.type == MAP_TYPE_WAY)); | ||
440 | break; | ||
441 | } | ||
442 | } else { | ||
443 | str = g_strdup_printf(_("Relation #%ld"), relation->id); | ||
444 | user = relation->user; | ||
445 | work_copy = osm_tags_copy(relation->tag, FALSE); | ||
446 | stime = relation->time; | ||
447 | context->type = RELATION; | ||
448 | harbaum | 52 | context->presets_type = PRESETS_TYPE_RELATION; |
449 | harbaum | 1 | } |
450 | |||
451 | context->dialog = gtk_dialog_new_with_buttons(str, | ||
452 | GTK_WINDOW(parent), GTK_DIALOG_MODAL, | ||
453 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | ||
454 | GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, | ||
455 | NULL); | ||
456 | g_free(str); | ||
457 | |||
458 | gtk_dialog_set_default_response(GTK_DIALOG(context->dialog), | ||
459 | GTK_RESPONSE_ACCEPT); | ||
460 | |||
461 | /* making the dialog a little wider makes it less "crowded" */ | ||
462 | #ifdef USE_HILDON | ||
463 | gtk_window_set_default_size(GTK_WINDOW(context->dialog), 500, 300); | ||
464 | #else | ||
465 | achadwick | 99 | // Conversely, desktop builds should display a little narrower |
466 | gtk_window_set_default_size(GTK_WINDOW(context->dialog), 400, 300); | ||
467 | harbaum | 1 | #endif |
468 | |||
469 | GtkWidget *label; | ||
470 | GtkWidget *table = gtk_table_new(2, 2, FALSE); // x, y | ||
471 | |||
472 | /* ------------ user ----------------- */ | ||
473 | char *u_str = NULL; | ||
474 | if(user) u_str = g_strdup_printf(_("User: %s"), user->name); | ||
475 | else u_str = g_strdup_printf(_("User: ---")); | ||
476 | label = gtk_label_new(u_str); | ||
477 | gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); | ||
478 | g_free(u_str); | ||
479 | |||
480 | /* ------------ time ----------------- */ | ||
481 | |||
482 | struct tm *loctime = localtime(&stime); | ||
483 | char time_str[32]; | ||
484 | strftime(time_str, sizeof(time_str), "%x %X", loctime); | ||
485 | char *t_str = g_strdup_printf(_("Time: %s"), time_str); | ||
486 | label = gtk_label_new(t_str); | ||
487 | g_free(t_str); | ||
488 | gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 0, 1); | ||
489 | |||
490 | /* ------------ coordinate (only for nodes) ----------------- */ | ||
491 | if(!relation) { | ||
492 | if(appdata->map->selected.type == MAP_TYPE_NODE) { | ||
493 | char pos_str[32]; | ||
494 | pos_lat_str(pos_str, sizeof(pos_str),appdata->map->selected.node->pos.lat); | ||
495 | label = gtk_label_new(pos_str); | ||
496 | gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); | ||
497 | pos_lat_str(pos_str, sizeof(pos_str),appdata->map->selected.node->pos.lon); | ||
498 | label = gtk_label_new(pos_str); | ||
499 | gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2); | ||
500 | } else { | ||
501 | char *nodes_str = g_strdup_printf(_("Length: %u nodes"), | ||
502 | osm_way_number_of_nodes(appdata->map->selected.way)); | ||
503 | label = gtk_label_new(nodes_str); | ||
504 | gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); | ||
505 | g_free(nodes_str); | ||
506 | |||
507 | char *type_str = g_strdup_printf("%s (%s)", | ||
508 | (osm_way_get_last_node(appdata->map->selected.way) == | ||
509 | osm_way_get_first_node(appdata->map->selected.way))? | ||
510 | "closed way":"open way", | ||
511 | (appdata->map->selected.way->draw.flags & OSM_DRAW_FLAG_AREA)? | ||
512 | "area":"line"); | ||
513 | |||
514 | label = gtk_label_new(type_str); | ||
515 | gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 1, 2); | ||
516 | g_free(type_str); | ||
517 | } | ||
518 | } else { | ||
519 | /* relations tell something about their members */ | ||
520 | gint nodes = 0, ways = 0, relations = 0; | ||
521 | member_t *member = relation->member; | ||
522 | while(member) { | ||
523 | switch(member->type) { | ||
524 | case NODE: | ||
525 | case NODE_ID: | ||
526 | nodes++; | ||
527 | break; | ||
528 | case WAY: | ||
529 | case WAY_ID: | ||
530 | ways++; | ||
531 | break; | ||
532 | case RELATION: | ||
533 | case RELATION_ID: | ||
534 | relations++; | ||
535 | break; | ||
536 | |||
537 | default: | ||
538 | break; | ||
539 | } | ||
540 | |||
541 | member = member->next; | ||
542 | } | ||
543 | |||
544 | char *str = g_strdup_printf(_("Members: %d nodes, %d ways, %d relations"), | ||
545 | nodes, ways, relations); | ||
546 | |||
547 | gtk_table_attach_defaults(GTK_TABLE(table), gtk_label_new(str), 0, 2, 1, 2); | ||
548 | g_free(str); | ||
549 | } | ||
550 | |||
551 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context->dialog)->vbox), table, | ||
552 | FALSE, FALSE, 0); | ||
553 | |||
554 | |||
555 | /* ------------ tags ----------------- */ | ||
556 | |||
557 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context->dialog)->vbox), | ||
558 | tag_widget(context), TRUE, TRUE, 0); | ||
559 | |||
560 | /* ----------------------------------- */ | ||
561 | |||
562 | gtk_widget_show_all(context->dialog); | ||
563 | harbaum | 73 | gboolean ok = FALSE; |
564 | |||
565 | harbaum | 1 | if(gtk_dialog_run(GTK_DIALOG(context->dialog)) == GTK_RESPONSE_ACCEPT) { |
566 | harbaum | 73 | ok = TRUE; |
567 | |||
568 | harbaum | 1 | gtk_widget_destroy(context->dialog); |
569 | |||
570 | if(!relation) { | ||
571 | /* replace original tags with work copy */ | ||
572 | switch(appdata->map->selected.type) { | ||
573 | |||
574 | case MAP_TYPE_NODE: | ||
575 | osm_tags_free(appdata->map->selected.node->tag); | ||
576 | appdata->map->selected.node->tag = osm_tags_copy(work_copy, TRUE); | ||
577 | break; | ||
578 | |||
579 | case MAP_TYPE_WAY: | ||
580 | osm_tags_free(appdata->map->selected.way->tag); | ||
581 | appdata->map->selected.way->tag = osm_tags_copy(work_copy, TRUE); | ||
582 | break; | ||
583 | |||
584 | default: | ||
585 | break; | ||
586 | } | ||
587 | |||
588 | /* since nodes being parts of ways but with no tags are invisible, */ | ||
589 | /* the result of editing them may have changed their visibility */ | ||
590 | map_item_redraw(appdata, &appdata->map->selected); | ||
591 | map_item_set_flags(&context->appdata->map->selected, OSM_FLAG_DIRTY, 0); | ||
592 | } else { | ||
593 | osm_tags_free(relation->tag); | ||
594 | relation->tag = osm_tags_copy(work_copy, TRUE); | ||
595 | relation->flags |= OSM_FLAG_DIRTY; | ||
596 | } | ||
597 | } else { | ||
598 | gtk_widget_destroy(context->dialog); | ||
599 | osm_tags_free(work_copy); | ||
600 | } | ||
601 | |||
602 | g_free(context); | ||
603 | harbaum | 73 | return ok; |
604 | harbaum | 1 | } |