Contents of /trunk/src/josm_presets.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Tue Dec 9 20:06:06 2008 UTC (15 years, 6 months ago) by harbaum
Original Path: src/josm_presets.c
File MIME type: text/plain
File size: 21627 byte(s)
Initial import
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     #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     }