Contents of /trunk/src/josm_presets.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations)
Wed Dec 10 00:00:05 2008 UTC (15 years, 5 months ago) by achadwick
File MIME type: text/plain
File size: 21627 byte(s)
Begin trunk. No code changes.
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 #include <libxml/parser.h>
23 #include <libxml/tree.h>
24
25 #ifndef LIBXML_TREE_ENABLED
26 #error "Tree not enabled in libxml"
27 #endif
28
29 /* --------------------- presets.xml parsing ----------------------- */
30
31 static gboolean xmlGetPropIs(xmlNode *node, char *prop, char *is) {
32 char *prop_str = (char*)xmlGetProp(node, BAD_CAST prop);
33 if(!prop_str) return FALSE;
34
35 gboolean retval = FALSE;
36 retval = (strcasecmp(prop_str, is) == 0);
37 xmlFree(prop_str);
38 return retval;
39 }
40
41 static presets_value_t *xmlGetPropValues(xmlNode *node, char *prop) {
42 char *prop_str = (char*)xmlGetProp(node, BAD_CAST prop);
43 if(!prop_str) return NULL;
44 presets_value_t *value = NULL, **cur = &value;
45
46 /* cut values strings */
47 char *c, *p = prop_str;
48 while((c = strchr(p, ','))) {
49
50 *cur = g_new0(presets_value_t, 1);
51 (*cur)->text = g_strndup(p, c-p);
52 cur = &((*cur)->next);
53
54 p = c+1;
55 }
56
57 /* attach remaining string as last value */
58 *cur = g_new0(presets_value_t, 1);
59 (*cur)->text = g_strdup(p);
60
61 xmlFree(prop_str);
62 return value;
63 }
64
65 char *josm_icon_name_adjust(char *name) {
66 /* the icon loader uses names without extension */
67 if(!strcasecmp(name+strlen(name)-4, ".png"))
68 name[strlen(name)-4] = 0;
69
70 #ifdef JOSM_PATH_ADJUST
71 if(strncmp(name, "presets/", strlen("presets/")) != 0) {
72 if(strrchr(name, '/')) {
73 char *new = g_strdup_printf("presets%s", strrchr(name, '/'));
74 xmlFree(name);
75 name = new;
76
77 printf("icon path adjusted to %s\n", name);
78 }
79 }
80 #endif
81 return name;
82 }
83
84 static presets_item_t *parse_item(xmlDocPtr doc, xmlNode *a_node) {
85 xmlNode *cur_node = NULL;
86
87 presets_item_t *item = g_new0(presets_item_t, 1);
88 item->is_group = FALSE;
89
90 /* ------ parse items own properties ------ */
91 item->name = (char*)xmlGetProp(a_node, BAD_CAST "name");
92
93 if((item->icon = (char*)xmlGetProp(a_node, BAD_CAST "icon")))
94 item->icon = josm_icon_name_adjust(item->icon);
95
96 presets_widget_t **widget = &item->widget;
97
98 /* ---- parse children (widgets) ----- */
99 for(cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
100 if(cur_node->type == XML_ELEMENT_NODE) {
101 if(strcasecmp((char*)cur_node->name, "label") == 0) {
102
103 /* --------- label widget --------- */
104 *widget = g_new0(presets_widget_t, 1);
105 (*widget)->type = WIDGET_TYPE_LABEL;
106 (*widget)->text = (char*)xmlGetProp(cur_node, BAD_CAST "text");
107
108 /* special handling of separators */
109 if(!(*widget)->text || (strcmp((*widget)->text, " ") == 0)) {
110 (*widget)->type = WIDGET_TYPE_SEPARATOR;
111 if((*widget)->text) xmlFree((*widget)->text);
112 (*widget)->text = NULL;
113 }
114
115 widget = &((*widget)->next);
116
117 } else if(strcasecmp((char*)cur_node->name, "text") == 0) {
118
119 /* --------- text widget --------- */
120 *widget = g_new0(presets_widget_t, 1);
121 (*widget)->type = WIDGET_TYPE_TEXT;
122 (*widget)->text = (char*)xmlGetProp(cur_node, BAD_CAST "text");
123 (*widget)->key = (char*)xmlGetProp(cur_node, BAD_CAST "key");
124 (*widget)->del_if_empty = xmlGetPropIs(cur_node, "delete_if_empty", "true");
125 (*widget)->text_w.def = (char*)xmlGetProp(cur_node, BAD_CAST "default");
126 widget = &((*widget)->next);
127
128 } else if(strcasecmp((char*)cur_node->name, "combo") == 0) {
129
130 /* --------- combo widget --------- */
131 *widget = g_new0(presets_widget_t, 1);
132 (*widget)->type = WIDGET_TYPE_COMBO;
133 (*widget)->text = (char*)xmlGetProp(cur_node, BAD_CAST "text");
134 (*widget)->key = (char*)xmlGetProp(cur_node, BAD_CAST "key");
135 (*widget)->del_if_empty = xmlGetPropIs(cur_node,
136 "delete_if_empty", "true");
137 (*widget)->combo_w.def = (char*)xmlGetProp(cur_node,
138 BAD_CAST "default");
139 (*widget)->combo_w.values = xmlGetPropValues(cur_node, "values");
140 widget = &((*widget)->next);
141
142 } else if(strcasecmp((char*)cur_node->name, "key") == 0) {
143
144 /* --------- invisible key widget --------- */
145 *widget = g_new0(presets_widget_t, 1);
146 (*widget)->type = WIDGET_TYPE_KEY;
147 (*widget)->key = (char*)xmlGetProp(cur_node, BAD_CAST "key");
148 (*widget)->key_w.value = (char*)xmlGetProp(cur_node, BAD_CAST "value");
149 widget = &((*widget)->next);
150
151 } else if(strcasecmp((char*)cur_node->name, "check") == 0) {
152
153 /* --------- check widget --------- */
154 *widget = g_new0(presets_widget_t, 1);
155 (*widget)->type = WIDGET_TYPE_CHECK;
156 (*widget)->text = (char*)xmlGetProp(cur_node, BAD_CAST "text");
157 (*widget)->key = (char*)xmlGetProp(cur_node, BAD_CAST "key");
158 (*widget)->del_if_empty = xmlGetPropIs(cur_node,
159 "delete_if_empty", "true");
160 (*widget)->check_w.def = xmlGetPropIs(cur_node, "default", "on");
161 widget = &((*widget)->next);
162
163 } else
164 printf("found unhandled annotations/item/%s\n", cur_node->name);
165 }
166 }
167 return item;
168 }
169
170 static presets_item_t *parse_group(xmlDocPtr doc, xmlNode *a_node) {
171 xmlNode *cur_node = NULL;
172
173 presets_item_t *group = g_new0(presets_item_t, 1);
174 group->is_group = TRUE;
175
176 /* ------ parse groups own properties ------ */
177 group->name = (char*)xmlGetProp(a_node, BAD_CAST "name");
178
179 if((group->icon = (char*)xmlGetProp(a_node, BAD_CAST "icon")))
180 group->icon = josm_icon_name_adjust(group->icon);
181
182 presets_item_t **preset = &group->group;
183
184 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
185 if (cur_node->type == XML_ELEMENT_NODE) {
186 if(strcasecmp((char*)cur_node->name, "item") == 0) {
187 *preset = parse_item(doc, cur_node);
188 if(*preset) preset = &((*preset)->next);
189 } else if(strcasecmp((char*)cur_node->name, "group") == 0) {
190 *preset = parse_group(doc, cur_node);
191 if(*preset) preset = &((*preset)->next);
192 } else if(strcasecmp((char*)cur_node->name, "separator") == 0) {
193 *preset = g_new0(presets_item_t, 1);
194 preset = &((*preset)->next);
195 } else
196 printf("found unhandled annotations/group/%s\n", cur_node->name);
197 }
198 }
199 return group;
200 }
201
202 static presets_item_t *parse_annotations(xmlDocPtr doc, xmlNode *a_node) {
203 xmlNode *cur_node = NULL;
204 presets_item_t *presets = NULL, **preset = &presets;
205
206 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
207 if (cur_node->type == XML_ELEMENT_NODE) {
208 if(strcasecmp((char*)cur_node->name, "item") == 0) {
209 *preset = parse_item(doc, cur_node);
210 if(*preset) preset = &((*preset)->next);
211 } else if(strcasecmp((char*)cur_node->name, "group") == 0) {
212 *preset = parse_group(doc, cur_node);
213 if(*preset) preset = &((*preset)->next);
214 } else if(strcasecmp((char*)cur_node->name, "separator") == 0) {
215 *preset = g_new0(presets_item_t, 1);
216 preset = &((*preset)->next);
217 } else
218 printf("found unhandled annotations/%s\n", cur_node->name);
219 }
220 }
221 return presets;
222 }
223
224 static presets_item_t *parse_doc(xmlDocPtr doc) {
225 /* Get the root element node */
226 xmlNode *cur_node = NULL;
227 presets_item_t *presets = NULL;
228
229 for(cur_node = xmlDocGetRootElement(doc);
230 cur_node; cur_node = cur_node->next) {
231 if (cur_node->type == XML_ELEMENT_NODE) {
232 if(strcasecmp((char*)cur_node->name, "annotations") == 0) {
233 presets = parse_annotations(doc, cur_node);
234 } else
235 printf("found unhandled %s\n", cur_node->name);
236 }
237 }
238
239 xmlFreeDoc(doc);
240 xmlCleanupParser();
241 return presets;
242 }
243
244 presets_item_t *josm_presets_load(void) {
245 presets_item_t *presets = NULL;
246
247 printf("Loading JOSM presets ...\n");
248
249 LIBXML_TEST_VERSION;
250
251 char *filename = find_file("presets.xml");
252 if(!filename) return NULL;
253
254 /* parse the file and get the DOM */
255 xmlDoc *doc = NULL;
256 if((doc = xmlReadFile(filename, NULL, 0)) == NULL) {
257 xmlErrorPtr errP = xmlGetLastError();
258 printf("presets download failed: "
259 "XML error while parsing:\n"
260 "%s\n", errP->message);
261 } else {
262 printf("ok, parse doc tree\n");
263 presets = parse_doc(doc);
264 }
265
266 g_free(filename);
267 return presets;
268 }
269
270 /* --------------------- the items dialog -------------------- */
271
272 static void attach_both(GtkWidget *table, GtkWidget *widget, gint y) {
273 gtk_table_attach(GTK_TABLE(table), widget, 0,2,y,y+1,
274 GTK_EXPAND | GTK_FILL, 0,0,0);
275 }
276
277 static void attach_text(GtkWidget *table, char *text, gint y) {
278 gtk_table_attach(GTK_TABLE(table), gtk_label_new(text), 0,1,y,y+1,
279 GTK_EXPAND | GTK_FILL, 0,0,0);
280 }
281
282 static void attach_right(GtkWidget *table, GtkWidget *widget, gint y) {
283 gtk_table_attach(GTK_TABLE(table), widget, 1,2,y,y+1,
284 GTK_EXPAND | GTK_FILL, 0,0,0);
285 }
286
287 static tag_t **store_value(presets_widget_t *widget, tag_t **ctag,
288 char *value) {
289 if((value && strlen(value)) || !widget->del_if_empty) {
290 *ctag = g_new0(tag_t, 1);
291 (*ctag)->key = g_strdup(widget->key);
292 (*ctag)->value = g_strdup(value?value:"");
293
294 printf("key = %s, value = %s\n",
295 widget->key, (*ctag)->value);
296
297 ctag = &((*ctag)->next);
298 } else
299 printf("ignore empty key = %s\n", widget->key);
300
301 return ctag;
302 }
303
304 #ifdef USE_HILDON
305 static gint table_expose_event(GtkWidget *widget, GdkEventExpose *event,
306 gboolean *first) {
307
308 if(*first) {
309 guint border_width =
310 gtk_container_get_border_width(GTK_CONTAINER(widget->parent));
311 gtk_viewport_set_shadow_type(GTK_VIEWPORT(widget->parent), GTK_SHADOW_NONE);
312
313 gtk_widget_set_size_request(GTK_WIDGET(widget->parent), -1,
314 widget->allocation.height + 2*border_width);
315 *first = FALSE;
316 }
317 return FALSE;
318 }
319 #endif
320
321 static tag_t *presets_item_dialog(GtkWindow *parent,
322 presets_item_t *item, tag_t *orig_tag) {
323 gboolean ok = FALSE;
324 tag_t *tag = NULL, **ctag = &tag;
325
326 printf("dialog for item %s\n", item->name);
327 GtkWidget *dialog = gtk_dialog_new_with_buttons(
328 item->name, parent, GTK_DIALOG_MODAL,
329 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
330 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
331 NULL);
332
333 /* build dialog from items widget list */
334 presets_widget_t *widget = item->widget;
335
336 /* count total number of widgets and number of widgets that */
337 /* have an interactive gui element. We won't show a dialog */
338 /* at all if there's no interactive gui element at all */
339 gint widget_cnt = 0, interactive_widget_cnt = 0;
340 while(widget) {
341 if((widget->type != WIDGET_TYPE_LABEL) &&
342 (widget->type != WIDGET_TYPE_SEPARATOR) &&
343 (widget->type != WIDGET_TYPE_KEY))
344 interactive_widget_cnt++;
345
346 widget_cnt++;
347 widget = widget->next;
348 }
349
350 /* allocate space for required number of gtk widgets */
351 GtkWidget **gtk_widgets = (GtkWidget**)g_new0(GtkWidget, widget_cnt);
352
353 if(interactive_widget_cnt) {
354 /* special handling for the first label/separators */
355 guint widget_skip = 0; // number of initial widgets to skip
356 widget = item->widget;
357 if(widget && (widget->type == WIDGET_TYPE_LABEL)) {
358 gtk_window_set_title(GTK_WINDOW(dialog), widget->text);
359
360 widget_skip++; // this widget isn't part of the contents anymore
361 widget = widget->next;
362
363 /* skip all following separators (and keys) */
364 while(widget &&
365 ((widget->type == WIDGET_TYPE_SEPARATOR) ||
366 (widget->type == WIDGET_TYPE_KEY))) {
367 widget_skip++; // this widget isn't part of the contents anymore
368 widget = widget->next;
369 }
370 }
371
372 /* create table of required size */
373 GtkWidget *table = gtk_table_new(widget_cnt-widget_skip, 2, FALSE);
374
375 widget_cnt = widget_skip;
376 while(widget) {
377 /* check if there's a value with this key already */
378 char *preset = osm_tag_get_by_key(orig_tag, widget->key);
379
380 switch(widget->type) {
381 case WIDGET_TYPE_SEPARATOR:
382 attach_both(table, gtk_hseparator_new(), widget_cnt-widget_skip);
383 break;
384
385 case WIDGET_TYPE_LABEL:
386 attach_both(table, gtk_label_new(widget->text), widget_cnt-widget_skip);
387 break;
388
389 case WIDGET_TYPE_COMBO:
390 attach_text(table, widget->text, widget_cnt-widget_skip);
391
392 if(!preset && widget->combo_w.def) preset = widget->combo_w.def;
393 gtk_widgets[widget_cnt] = gtk_combo_box_new_text();
394 presets_value_t *value = widget->combo_w.values;
395 int count = 0, active = -1;
396 while(value) {
397 if(active < 0 && preset && strcmp(preset, value->text)==0)
398 active = count;
399
400 gtk_combo_box_append_text(GTK_COMBO_BOX(gtk_widgets[widget_cnt]),
401 value->text);
402 value = value->next;
403 count++;
404 }
405
406 gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_widgets[widget_cnt]),
407 active);
408 attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
409 break;
410
411 case WIDGET_TYPE_CHECK:
412 { gboolean def = FALSE;
413 if(preset) def = ((strcasecmp(preset, "true") == 0) ||
414 (strcasecmp(preset, "yes") == 0));
415 else def = widget->check_w.def;
416
417 gtk_widgets[widget_cnt] =
418 gtk_check_button_new_with_label(widget->text);
419 gtk_toggle_button_set_active(
420 GTK_TOGGLE_BUTTON(gtk_widgets[widget_cnt]), def);
421 attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
422 } break;
423
424 case WIDGET_TYPE_TEXT:
425 attach_text(table, widget->text, widget_cnt-widget_skip);
426
427 if(!preset && widget->text_w.def) preset = widget->text_w.def;
428 gtk_widgets[widget_cnt] = gtk_entry_new();
429 if(preset)
430 gtk_entry_set_text(GTK_ENTRY(gtk_widgets[widget_cnt]), preset);
431
432 attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
433 break;
434
435 default:
436 break;
437 }
438
439 widget_cnt++;
440 widget = widget->next;
441 }
442
443 #ifndef USE_HILDON
444 /* add widget to dialog */
445 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
446 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, 50);
447 #else
448 /* put it into a scrolled window */
449 GtkWidget *scroll_win = gtk_scrolled_window_new(NULL, NULL);
450 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win),
451 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
452 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll_win),
453 table);
454
455 gboolean first = TRUE;
456 gtk_signal_connect(GTK_OBJECT(table), "expose_event",
457 G_CALLBACK(table_expose_event), &first);
458
459 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), scroll_win);
460 // gtk_window_set_default_size(GTK_WINDOW(dialog), 50, 400);
461 #endif
462
463 gtk_widget_show_all(dialog);
464 }
465
466 if(!interactive_widget_cnt ||
467 (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))) {
468 ok = TRUE;
469
470 /* handle all children of the table */
471 widget = item->widget;
472 widget_cnt = 0;
473 while(widget) {
474 switch(widget->type) {
475 case WIDGET_TYPE_COMBO:
476 g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
477 GTK_TYPE_COMBO_BOX);
478
479 ctag = store_value(widget, ctag, gtk_combo_box_get_active_text(
480 GTK_COMBO_BOX(gtk_widgets[widget_cnt])));
481 break;
482
483 case WIDGET_TYPE_TEXT:
484 g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
485 GTK_TYPE_ENTRY);
486
487 ctag = store_value(widget, ctag, (char*)gtk_entry_get_text(
488 GTK_ENTRY(gtk_widgets[widget_cnt])));
489 break;
490
491 case WIDGET_TYPE_CHECK:
492 g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
493 GTK_TYPE_CHECK_BUTTON);
494
495 ctag = store_value(widget, ctag,
496 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
497 gtk_widgets[widget_cnt]))?"true":
498 (widget->del_if_empty?NULL:"false"));
499 break;
500
501 case WIDGET_TYPE_KEY:
502 g_assert(!gtk_widgets[widget_cnt]);
503
504 ctag = store_value(widget, ctag, widget->key_w.value);
505 break;
506
507 default:
508 break;
509 }
510
511 widget_cnt++;
512 widget = widget->next;
513 }
514
515 *ctag = g_new0(tag_t, 1);
516 (*ctag)->key = g_strdup("created_by");
517 (*ctag)->value = g_strdup(PACKAGE " v" VERSION);
518 }
519
520 g_free(gtk_widgets);
521
522 if(interactive_widget_cnt)
523 gtk_widget_destroy(dialog);
524
525 return tag;
526 }
527
528 /* ------------------- the item list (popup menu) -------------- */
529
530 typedef struct {
531 appdata_t *appdata;
532 GtkWidget *menu;
533 tag_context_t *tag_context;
534 } presets_context_t;
535
536 static void
537 cb_menu_item(GtkMenuItem *menu_item, gpointer data) {
538 presets_context_t *context = (presets_context_t*)data;
539
540 presets_item_t *item = g_object_get_data(G_OBJECT(menu_item), "item");
541 g_assert(item);
542
543 tag_t *tag =
544 presets_item_dialog(GTK_WINDOW(context->tag_context->dialog), item,
545 *context->tag_context->tag);
546
547 if(tag) {
548 tag_context_t *tag_context = context->tag_context;
549
550 /* add new tags to the old list and replace entries with the same key */
551
552 while(tag) {
553 #if 0
554 printf("current:\n");
555 tag_t *mdst = &tag_context->tag;
556 while(mdst) {
557 printf("%s: %s\n", msdt
558 #endif
559
560 tag_t *next = tag->next;
561 tag->next = NULL;
562
563 tag_t **dst = tag_context->tag;
564 gboolean replaced = FALSE;
565 while(*dst && !replaced) {
566 if(strcasecmp((*dst)->key, tag->key) == 0) {
567 g_free((*dst)->value);
568 (*dst)->value = g_strdup(tag->value);
569 replaced = TRUE;
570 }
571 dst = &(*dst)->next;
572 }
573
574 /* if nothing was replaced, then just append new tag */
575 if(!replaced)
576 *dst = tag;
577 else
578 osm_tag_free(tag);
579
580 tag = next;
581 }
582
583 #if 0
584 /* free existing tags */
585 osm_tags_free(*tag_context->tag);
586
587 /* attach new tags */
588 *tag_context->tag = tag;
589 #endif
590
591 info_tags_replace(tag_context);
592 }
593 }
594
595 static GtkWidget *build_menu(presets_context_t *context,
596 presets_item_t *item) {
597 GtkWidget *menu = gtk_menu_new();
598
599 while(item) {
600 GtkWidget *menu_item;
601
602 if(item->name) {
603 if(!item->icon)
604 menu_item = gtk_menu_item_new_with_label(item->name);
605 else {
606 menu_item = gtk_image_menu_item_new_with_label(item->name);
607 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
608 icon_widget_load(&context->appdata->icon, item->icon));
609 }
610
611 if(item->is_group)
612 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
613 build_menu(context, item->group));
614 else {
615 g_object_set_data(G_OBJECT(menu_item), "item", item);
616 g_signal_connect(menu_item, "activate",
617 GTK_SIGNAL_FUNC(cb_menu_item), context);
618 }
619 } else
620 menu_item = gtk_separator_menu_item_new();
621
622 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
623 item = item->next;
624 }
625
626 return menu;
627 }
628
629 static gint button_press(GtkWidget *widget, GdkEventButton *event,
630 gpointer data) {
631 presets_context_t *context = (presets_context_t*)data;
632
633 if(event->type == GDK_BUTTON_PRESS) {
634 printf("button press %d %d\n", event->button, event->time);
635
636 gtk_menu_popup(GTK_MENU(context->menu), NULL, NULL, NULL, NULL,
637 event->button, event->time);
638
639 /* Tell calling code that we have handled this event; the buck
640 * stops here. */
641 return TRUE;
642 }
643 return FALSE;
644 }
645
646 static gint on_button_destroy(GtkWidget *widget, gpointer data) {
647 presets_context_t *context = (presets_context_t*)data;
648
649 printf("freeing preset button context\n");
650 gtk_widget_destroy(context->menu);
651 g_free(context);
652
653 return FALSE;
654 }
655
656 GtkWidget *josm_presets_select(appdata_t *appdata, tag_context_t *tag_context) {
657 presets_context_t *context = g_new0(presets_context_t, 1);
658 context->appdata = appdata;
659 context->tag_context = tag_context;
660
661 context->menu = build_menu(context, appdata->presets);
662 gtk_widget_show_all( GTK_WIDGET(context->menu) );
663
664 GtkWidget *but = gtk_button_new_with_label(_("Presets..."));
665 gtk_widget_set_events(but, GDK_EXPOSURE_MASK);
666 gtk_widget_add_events(but, GDK_BUTTON_PRESS_MASK);
667 gtk_signal_connect(GTK_OBJECT(but), "button-press-event",
668 (GtkSignalFunc)button_press, context);
669
670 gtk_signal_connect(GTK_OBJECT(but), "destroy",
671 (GtkSignalFunc)on_button_destroy, context);
672
673 return but;
674 }
675
676 /* ----------------------- cleaning up --------------------- */
677
678 static void free_values(presets_value_t *value) {
679 while(value) {
680 presets_value_t *next = value->next;
681 if(value->text) g_free(value->text);
682 g_free(value);
683 value = next;
684 }
685
686 }
687
688 static void free_widget(presets_widget_t *widget) {
689 if(widget->key) xmlFree(widget->key);
690 if(widget->text) xmlFree(widget->text);
691
692 switch(widget->type) {
693 case WIDGET_TYPE_TEXT:
694 if(widget->text_w.def) xmlFree(widget->text_w.def);
695 break;
696
697 case WIDGET_TYPE_COMBO:
698 if(widget->combo_w.def) xmlFree(widget->combo_w.def);
699 if(widget->combo_w.values) free_values(widget->combo_w.values);
700 break;
701
702 case WIDGET_TYPE_KEY:
703 if(widget->key_w.value) xmlFree(widget->key_w.value);
704 break;
705
706 default:
707 break;
708 }
709
710 g_free(widget);
711 }
712
713 static void free_widgets(presets_widget_t *widget) {
714 while(widget) {
715 presets_widget_t *next = widget->next;
716 free_widget(widget);
717 widget = next;
718 }
719 }
720
721 static void free_items(presets_item_t *item);
722 static void free_item(presets_item_t *item) {
723 if(item->name) xmlFree(item->name);
724 if(item->icon) xmlFree(item->icon);
725
726 if(item->is_group)
727 free_items(item->group);
728 else
729 free_widgets(item->widget);
730
731 g_free(item);
732 }
733
734 static void free_items(presets_item_t *item) {
735 while(item) {
736 presets_item_t *next = item->next;
737 free_item(item);
738 item = next;
739 }
740 }
741
742 void josm_presets_free(presets_item_t *presets) {
743 free_items(presets);
744 }