Contents of /trunk/src/josm_presets.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 53 - (hide annotations)
Fri Feb 6 09:00:44 2009 UTC (15 years, 3 months ago) by harbaum
File MIME type: text/plain
File size: 25906 byte(s)
Hide empty presets groups
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 harbaum 51 #ifndef USE_HILDON
30     #include <libgnome/gnome-url.h>
31     #else
32     #include <tablet-browser-interface.h>
33     #endif
34    
35     typedef struct {
36     appdata_t *appdata;
37     char *link;
38     } www_context_t;
39    
40     /* ---------- simple interface to the systems web browser ---------- */
41     static void on_info(GtkWidget *widget, www_context_t *context) {
42     #ifndef USE_HILDON
43     /* taken from gnome-open, part of libgnome */
44     GError *err = NULL;
45     gnome_url_show(context->link, &err);
46     #else
47     osso_rpc_run_with_defaults(context->appdata->osso_context, "osso_browser",
48     OSSO_BROWSER_OPEN_NEW_WINDOW_REQ, NULL,
49     DBUS_TYPE_STRING, context->link,
50     DBUS_TYPE_BOOLEAN, FALSE, DBUS_TYPE_INVALID);
51     #endif
52     }
53    
54 harbaum 1 /* --------------------- presets.xml parsing ----------------------- */
55    
56     static gboolean xmlGetPropIs(xmlNode *node, char *prop, char *is) {
57     char *prop_str = (char*)xmlGetProp(node, BAD_CAST prop);
58     if(!prop_str) return FALSE;
59    
60     gboolean retval = FALSE;
61     retval = (strcasecmp(prop_str, is) == 0);
62     xmlFree(prop_str);
63     return retval;
64     }
65    
66     static presets_value_t *xmlGetPropValues(xmlNode *node, char *prop) {
67     char *prop_str = (char*)xmlGetProp(node, BAD_CAST prop);
68     if(!prop_str) return NULL;
69     presets_value_t *value = NULL, **cur = &value;
70    
71     /* cut values strings */
72     char *c, *p = prop_str;
73     while((c = strchr(p, ','))) {
74    
75     *cur = g_new0(presets_value_t, 1);
76     (*cur)->text = g_strndup(p, c-p);
77     cur = &((*cur)->next);
78    
79     p = c+1;
80     }
81    
82     /* attach remaining string as last value */
83     *cur = g_new0(presets_value_t, 1);
84     (*cur)->text = g_strdup(p);
85    
86     xmlFree(prop_str);
87     return value;
88     }
89    
90     char *josm_icon_name_adjust(char *name) {
91 harbaum 52 if(!name) return NULL;
92    
93 harbaum 1 /* the icon loader uses names without extension */
94     if(!strcasecmp(name+strlen(name)-4, ".png"))
95     name[strlen(name)-4] = 0;
96    
97     #ifdef JOSM_PATH_ADJUST
98     if(strncmp(name, "presets/", strlen("presets/")) != 0) {
99     if(strrchr(name, '/')) {
100     char *new = g_strdup_printf("presets%s", strrchr(name, '/'));
101     xmlFree(name);
102     name = new;
103    
104     printf("icon path adjusted to %s\n", name);
105     }
106     }
107     #endif
108     return name;
109     }
110    
111 harbaum 52 static int josm_type_bit(char *type) {
112     struct { int bit; char *str; } types[] = {
113     { PRESETS_TYPE_WAY, "way" },
114     { PRESETS_TYPE_NODE, "node" },
115     { PRESETS_TYPE_RELATION, "relation" },
116     { PRESETS_TYPE_CLOSEDWAY, "closedway" },
117     { 0, NULL }};
118    
119     int i;
120     for(i=0;types[i].bit;i++) {
121     if(strcasecmp(types[i].str, type) == 0)
122     return types[i].bit;
123     }
124    
125     printf("WARNING: unexpected type %s\n", type);
126     return 0;
127     }
128    
129     /* parse a comma seperated list of types and set their bits */
130     static int josm_type_parse(char *type) {
131     int type_mask = 0;
132    
133     if(!type) return PRESETS_TYPE_ALL;
134    
135     while(strchr(type, ',')) {
136     *strchr(type, ',') = 0;
137    
138     type_mask |= josm_type_bit(type);
139     type = type + strlen(type) + 1;
140     }
141    
142     type_mask |= josm_type_bit(type);
143     return type_mask;
144     }
145    
146 achadwick 50 /* parse children of a given node for into *widget */
147 harbaum 51 static presets_widget_t **parse_widgets(xmlNode *a_node,
148     presets_item_t *item,
149     presets_widget_t **widget) {
150 harbaum 1 xmlNode *cur_node = NULL;
151    
152     for(cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
153     if(cur_node->type == XML_ELEMENT_NODE) {
154    
155 harbaum 51 if(strcasecmp((char*)cur_node->name, "space") == 0) {
156    
157     /* --------- space widget --------- */
158     /* we are low on screen space on the handhelds, */
159     /* so we just ignore extra spaces */
160     #ifndef USE_HILDON
161     *widget = g_new0(presets_widget_t, 1);
162     (*widget)->type = WIDGET_TYPE_SPACE;
163     #endif
164    
165     } else if(strcasecmp((char*)cur_node->name, "label") == 0) {
166    
167 harbaum 1 /* --------- label widget --------- */
168     *widget = g_new0(presets_widget_t, 1);
169     (*widget)->type = WIDGET_TYPE_LABEL;
170     (*widget)->text = (char*)xmlGetProp(cur_node, BAD_CAST "text");
171    
172 achadwick 50 /* special handling of pre-<space/> separators */
173 harbaum 1 if(!(*widget)->text || (strcmp((*widget)->text, " ") == 0)) {
174     (*widget)->type = WIDGET_TYPE_SEPARATOR;
175     if((*widget)->text) xmlFree((*widget)->text);
176     (*widget)->text = NULL;
177     }
178    
179     widget = &((*widget)->next);
180    
181 achadwick 50 }
182     else if(strcasecmp((char*)cur_node->name, "space") == 0) {
183     // new-style separators
184     *widget = g_new0(presets_widget_t, 1);
185     (*widget)->type = WIDGET_TYPE_SEPARATOR;
186     (*widget)->text = NULL;
187     widget = &((*widget)->next);
188     }
189     else if(strcasecmp((char*)cur_node->name, "text") == 0) {
190 harbaum 1
191     /* --------- text widget --------- */
192     *widget = g_new0(presets_widget_t, 1);
193     (*widget)->type = WIDGET_TYPE_TEXT;
194     (*widget)->text = (char*)xmlGetProp(cur_node, BAD_CAST "text");
195     (*widget)->key = (char*)xmlGetProp(cur_node, BAD_CAST "key");
196     (*widget)->del_if_empty = xmlGetPropIs(cur_node, "delete_if_empty", "true");
197     (*widget)->text_w.def = (char*)xmlGetProp(cur_node, BAD_CAST "default");
198     widget = &((*widget)->next);
199    
200     } else if(strcasecmp((char*)cur_node->name, "combo") == 0) {
201    
202     /* --------- combo widget --------- */
203     *widget = g_new0(presets_widget_t, 1);
204     (*widget)->type = WIDGET_TYPE_COMBO;
205     (*widget)->text = (char*)xmlGetProp(cur_node, BAD_CAST "text");
206     (*widget)->key = (char*)xmlGetProp(cur_node, BAD_CAST "key");
207     (*widget)->del_if_empty = xmlGetPropIs(cur_node,
208     "delete_if_empty", "true");
209     (*widget)->combo_w.def = (char*)xmlGetProp(cur_node,
210     BAD_CAST "default");
211     (*widget)->combo_w.values = xmlGetPropValues(cur_node, "values");
212     widget = &((*widget)->next);
213    
214     } else if(strcasecmp((char*)cur_node->name, "key") == 0) {
215    
216     /* --------- invisible key widget --------- */
217     *widget = g_new0(presets_widget_t, 1);
218     (*widget)->type = WIDGET_TYPE_KEY;
219     (*widget)->key = (char*)xmlGetProp(cur_node, BAD_CAST "key");
220     (*widget)->key_w.value = (char*)xmlGetProp(cur_node, BAD_CAST "value");
221     widget = &((*widget)->next);
222    
223     } else if(strcasecmp((char*)cur_node->name, "check") == 0) {
224    
225     /* --------- check widget --------- */
226     *widget = g_new0(presets_widget_t, 1);
227     (*widget)->type = WIDGET_TYPE_CHECK;
228     (*widget)->text = (char*)xmlGetProp(cur_node, BAD_CAST "text");
229     (*widget)->key = (char*)xmlGetProp(cur_node, BAD_CAST "key");
230     (*widget)->del_if_empty = xmlGetPropIs(cur_node,
231     "delete_if_empty", "true");
232     (*widget)->check_w.def = xmlGetPropIs(cur_node, "default", "on");
233     widget = &((*widget)->next);
234    
235 achadwick 50 }
236     else if (strcasecmp((char*)cur_node->name, "optional") == 0) {
237     // Could be done as a fold-out box width twisties.
238     // Or maybe as a separate dialog for small screens.
239     // For now, just recurse and build up our current list.
240 harbaum 51 widget = parse_widgets(cur_node, item, widget);
241 achadwick 50 }
242 harbaum 51
243 achadwick 50 else if (strcasecmp((char*)cur_node->name, "link") == 0) {
244 harbaum 51
245     /* --------- link is not a widget, but a property of item --------- */
246     if(!item->link) {
247     item->link = (char*)xmlGetProp(cur_node, BAD_CAST "href");
248     } else
249     printf("ignoring surplus link\n");
250    
251     } else
252 harbaum 1 printf("found unhandled annotations/item/%s\n", cur_node->name);
253     }
254     }
255 achadwick 50 return widget;
256     }
257    
258     static presets_item_t *parse_item(xmlDocPtr doc, xmlNode *a_node) {
259     presets_item_t *item = g_new0(presets_item_t, 1);
260     item->is_group = FALSE;
261    
262     /* ------ parse items own properties ------ */
263     item->name = (char*)xmlGetProp(a_node, BAD_CAST "name");
264    
265 harbaum 52 item->icon =
266     josm_icon_name_adjust((char*)xmlGetProp(a_node, BAD_CAST "icon"));
267 achadwick 50
268 harbaum 52 item->type =
269     josm_type_parse((char*)xmlGetProp(a_node, BAD_CAST "type"));
270    
271 achadwick 50 presets_widget_t **widget = &item->widget;
272 harbaum 51 parse_widgets(a_node, item, widget);
273 harbaum 1 return item;
274     }
275    
276     static presets_item_t *parse_group(xmlDocPtr doc, xmlNode *a_node) {
277     xmlNode *cur_node = NULL;
278    
279     presets_item_t *group = g_new0(presets_item_t, 1);
280     group->is_group = TRUE;
281    
282     /* ------ parse groups own properties ------ */
283     group->name = (char*)xmlGetProp(a_node, BAD_CAST "name");
284    
285 harbaum 52 group->icon =
286     josm_icon_name_adjust((char*)xmlGetProp(a_node, BAD_CAST "icon"));
287 harbaum 1
288 harbaum 53 group->type = 0;
289 harbaum 52
290 harbaum 1 presets_item_t **preset = &group->group;
291    
292     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
293     if (cur_node->type == XML_ELEMENT_NODE) {
294     if(strcasecmp((char*)cur_node->name, "item") == 0) {
295     *preset = parse_item(doc, cur_node);
296 harbaum 53 if(*preset) {
297     group->type |= (*preset)->type;
298     preset = &((*preset)->next);
299     }
300 harbaum 1 } else if(strcasecmp((char*)cur_node->name, "group") == 0) {
301     *preset = parse_group(doc, cur_node);
302 harbaum 53 if(*preset) {
303     group->type |= (*preset)->type;
304     preset = &((*preset)->next);
305     }
306 harbaum 1 } else if(strcasecmp((char*)cur_node->name, "separator") == 0) {
307     *preset = g_new0(presets_item_t, 1);
308     preset = &((*preset)->next);
309     } else
310     printf("found unhandled annotations/group/%s\n", cur_node->name);
311     }
312     }
313 harbaum 53
314    
315    
316 harbaum 1 return group;
317     }
318    
319     static presets_item_t *parse_annotations(xmlDocPtr doc, xmlNode *a_node) {
320     xmlNode *cur_node = NULL;
321     presets_item_t *presets = NULL, **preset = &presets;
322    
323     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
324     if (cur_node->type == XML_ELEMENT_NODE) {
325     if(strcasecmp((char*)cur_node->name, "item") == 0) {
326     *preset = parse_item(doc, cur_node);
327     if(*preset) preset = &((*preset)->next);
328     } else if(strcasecmp((char*)cur_node->name, "group") == 0) {
329     *preset = parse_group(doc, cur_node);
330     if(*preset) preset = &((*preset)->next);
331     } else if(strcasecmp((char*)cur_node->name, "separator") == 0) {
332     *preset = g_new0(presets_item_t, 1);
333     preset = &((*preset)->next);
334     } else
335     printf("found unhandled annotations/%s\n", cur_node->name);
336     }
337     }
338     return presets;
339     }
340    
341     static presets_item_t *parse_doc(xmlDocPtr doc) {
342     /* Get the root element node */
343     xmlNode *cur_node = NULL;
344     presets_item_t *presets = NULL;
345    
346     for(cur_node = xmlDocGetRootElement(doc);
347     cur_node; cur_node = cur_node->next) {
348     if (cur_node->type == XML_ELEMENT_NODE) {
349     if(strcasecmp((char*)cur_node->name, "annotations") == 0) {
350     presets = parse_annotations(doc, cur_node);
351     } else
352     printf("found unhandled %s\n", cur_node->name);
353     }
354     }
355    
356     xmlFreeDoc(doc);
357     xmlCleanupParser();
358     return presets;
359     }
360    
361     presets_item_t *josm_presets_load(void) {
362     presets_item_t *presets = NULL;
363    
364     printf("Loading JOSM presets ...\n");
365    
366     LIBXML_TEST_VERSION;
367    
368     char *filename = find_file("presets.xml");
369     if(!filename) return NULL;
370    
371     /* parse the file and get the DOM */
372     xmlDoc *doc = NULL;
373     if((doc = xmlReadFile(filename, NULL, 0)) == NULL) {
374     xmlErrorPtr errP = xmlGetLastError();
375     printf("presets download failed: "
376     "XML error while parsing:\n"
377     "%s\n", errP->message);
378     } else {
379     printf("ok, parse doc tree\n");
380     presets = parse_doc(doc);
381     }
382    
383     g_free(filename);
384     return presets;
385     }
386    
387     /* --------------------- the items dialog -------------------- */
388    
389     static void attach_both(GtkWidget *table, GtkWidget *widget, gint y) {
390     gtk_table_attach(GTK_TABLE(table), widget, 0,2,y,y+1,
391     GTK_EXPAND | GTK_FILL, 0,0,0);
392     }
393    
394     static void attach_text(GtkWidget *table, char *text, gint y) {
395     gtk_table_attach(GTK_TABLE(table), gtk_label_new(text), 0,1,y,y+1,
396     GTK_EXPAND | GTK_FILL, 0,0,0);
397     }
398    
399     static void attach_right(GtkWidget *table, GtkWidget *widget, gint y) {
400     gtk_table_attach(GTK_TABLE(table), widget, 1,2,y,y+1,
401     GTK_EXPAND | GTK_FILL, 0,0,0);
402     }
403    
404     static tag_t **store_value(presets_widget_t *widget, tag_t **ctag,
405     char *value) {
406     if((value && strlen(value)) || !widget->del_if_empty) {
407     *ctag = g_new0(tag_t, 1);
408     (*ctag)->key = g_strdup(widget->key);
409     (*ctag)->value = g_strdup(value?value:"");
410    
411     printf("key = %s, value = %s\n",
412     widget->key, (*ctag)->value);
413    
414     ctag = &((*ctag)->next);
415     } else
416     printf("ignore empty key = %s\n", widget->key);
417    
418     return ctag;
419     }
420    
421     #ifdef USE_HILDON
422     static gint table_expose_event(GtkWidget *widget, GdkEventExpose *event,
423     gboolean *first) {
424    
425     if(*first) {
426     guint border_width =
427     gtk_container_get_border_width(GTK_CONTAINER(widget->parent));
428     gtk_viewport_set_shadow_type(GTK_VIEWPORT(widget->parent), GTK_SHADOW_NONE);
429    
430     gtk_widget_set_size_request(GTK_WIDGET(widget->parent), -1,
431     widget->allocation.height + 2*border_width);
432     *first = FALSE;
433     }
434     return FALSE;
435     }
436     #endif
437    
438 harbaum 51 static tag_t *presets_item_dialog(appdata_t *appdata, GtkWindow *parent,
439 harbaum 1 presets_item_t *item, tag_t *orig_tag) {
440 harbaum 51 GtkWidget *dialog = NULL;
441 harbaum 1 gboolean ok = FALSE;
442     tag_t *tag = NULL, **ctag = &tag;
443 harbaum 51 www_context_t *www_context = NULL;
444 harbaum 1
445     printf("dialog for item %s\n", item->name);
446    
447     /* build dialog from items widget list */
448     presets_widget_t *widget = item->widget;
449    
450     /* count total number of widgets and number of widgets that */
451     /* have an interactive gui element. We won't show a dialog */
452     /* at all if there's no interactive gui element at all */
453     gint widget_cnt = 0, interactive_widget_cnt = 0;
454     while(widget) {
455     if((widget->type != WIDGET_TYPE_LABEL) &&
456     (widget->type != WIDGET_TYPE_SEPARATOR) &&
457     (widget->type != WIDGET_TYPE_KEY))
458     interactive_widget_cnt++;
459    
460     widget_cnt++;
461     widget = widget->next;
462     }
463    
464     /* allocate space for required number of gtk widgets */
465     GtkWidget **gtk_widgets = (GtkWidget**)g_new0(GtkWidget, widget_cnt);
466    
467     if(interactive_widget_cnt) {
468 harbaum 51 dialog = gtk_dialog_new_with_buttons(
469     item->name, parent, GTK_DIALOG_MODAL,
470     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
471     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
472     NULL);
473    
474     /* if a web link has been provided for this item install */
475     /* a button for this */
476     if(item->link) {
477     www_context = g_new0(www_context_t, 1);
478     www_context->link = item->link;
479     www_context->appdata = appdata;
480    
481     GtkWidget *button = gtk_dialog_add_button(GTK_DIALOG(dialog), _
482     ("Info..."), GTK_RESPONSE_HELP);
483     gtk_signal_connect(GTK_OBJECT(button), "clicked",
484     GTK_SIGNAL_FUNC(on_info), (gpointer)www_context);
485     }
486    
487 harbaum 1 /* special handling for the first label/separators */
488     guint widget_skip = 0; // number of initial widgets to skip
489     widget = item->widget;
490     if(widget && (widget->type == WIDGET_TYPE_LABEL)) {
491     gtk_window_set_title(GTK_WINDOW(dialog), widget->text);
492    
493     widget_skip++; // this widget isn't part of the contents anymore
494     widget = widget->next;
495    
496     /* skip all following separators (and keys) */
497     while(widget &&
498     ((widget->type == WIDGET_TYPE_SEPARATOR) ||
499 harbaum 51 (widget->type == WIDGET_TYPE_SPACE) ||
500 harbaum 1 (widget->type == WIDGET_TYPE_KEY))) {
501     widget_skip++; // this widget isn't part of the contents anymore
502     widget = widget->next;
503     }
504     }
505    
506     /* create table of required size */
507     GtkWidget *table = gtk_table_new(widget_cnt-widget_skip, 2, FALSE);
508    
509     widget_cnt = widget_skip;
510     while(widget) {
511     /* check if there's a value with this key already */
512     char *preset = osm_tag_get_by_key(orig_tag, widget->key);
513    
514     switch(widget->type) {
515     case WIDGET_TYPE_SEPARATOR:
516     attach_both(table, gtk_hseparator_new(), widget_cnt-widget_skip);
517     break;
518    
519 harbaum 51 case WIDGET_TYPE_SPACE:
520     /* space is just an empty label until we find something better */
521     attach_both(table, gtk_label_new(" "), widget_cnt-widget_skip);
522     break;
523    
524 harbaum 1 case WIDGET_TYPE_LABEL:
525     attach_both(table, gtk_label_new(widget->text), widget_cnt-widget_skip);
526     break;
527    
528     case WIDGET_TYPE_COMBO:
529     attach_text(table, widget->text, widget_cnt-widget_skip);
530    
531     if(!preset && widget->combo_w.def) preset = widget->combo_w.def;
532     gtk_widgets[widget_cnt] = gtk_combo_box_new_text();
533     presets_value_t *value = widget->combo_w.values;
534     int count = 0, active = -1;
535     while(value) {
536     if(active < 0 && preset && strcmp(preset, value->text)==0)
537     active = count;
538    
539     gtk_combo_box_append_text(GTK_COMBO_BOX(gtk_widgets[widget_cnt]),
540     value->text);
541     value = value->next;
542     count++;
543     }
544    
545     gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_widgets[widget_cnt]),
546     active);
547     attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
548     break;
549    
550     case WIDGET_TYPE_CHECK:
551     { gboolean def = FALSE;
552     if(preset) def = ((strcasecmp(preset, "true") == 0) ||
553     (strcasecmp(preset, "yes") == 0));
554     else def = widget->check_w.def;
555    
556     gtk_widgets[widget_cnt] =
557     gtk_check_button_new_with_label(widget->text);
558     gtk_toggle_button_set_active(
559     GTK_TOGGLE_BUTTON(gtk_widgets[widget_cnt]), def);
560     attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
561     } break;
562    
563     case WIDGET_TYPE_TEXT:
564     attach_text(table, widget->text, widget_cnt-widget_skip);
565    
566     if(!preset && widget->text_w.def) preset = widget->text_w.def;
567     gtk_widgets[widget_cnt] = gtk_entry_new();
568     if(preset)
569     gtk_entry_set_text(GTK_ENTRY(gtk_widgets[widget_cnt]), preset);
570    
571     attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
572     break;
573    
574     default:
575     break;
576     }
577    
578     widget_cnt++;
579     widget = widget->next;
580     }
581    
582     #ifndef USE_HILDON
583     /* add widget to dialog */
584     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
585     gtk_window_set_default_size(GTK_WINDOW(dialog), 300, 50);
586     #else
587     /* put it into a scrolled window */
588     GtkWidget *scroll_win = gtk_scrolled_window_new(NULL, NULL);
589     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win),
590     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
591     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll_win),
592     table);
593    
594     gboolean first = TRUE;
595     gtk_signal_connect(GTK_OBJECT(table), "expose_event",
596     G_CALLBACK(table_expose_event), &first);
597    
598     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), scroll_win);
599     // gtk_window_set_default_size(GTK_WINDOW(dialog), 50, 400);
600     #endif
601    
602     gtk_widget_show_all(dialog);
603 harbaum 51
604     /* run gtk_dialog_run, but continue if e.g. the help button was pressed */
605     int result = -1;
606     do
607     result = gtk_dialog_run(GTK_DIALOG(dialog));
608     while((result != GTK_RESPONSE_DELETE_EVENT) &&
609     (result != GTK_RESPONSE_ACCEPT) &&
610     (result != GTK_RESPONSE_REJECT));
611    
612     if(result == GTK_RESPONSE_ACCEPT)
613     ok = TRUE;
614    
615     } else
616 harbaum 1 ok = TRUE;
617 harbaum 51
618     if(ok) {
619 harbaum 1 /* handle all children of the table */
620     widget = item->widget;
621     widget_cnt = 0;
622     while(widget) {
623     switch(widget->type) {
624     case WIDGET_TYPE_COMBO:
625     g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
626     GTK_TYPE_COMBO_BOX);
627    
628     ctag = store_value(widget, ctag, gtk_combo_box_get_active_text(
629     GTK_COMBO_BOX(gtk_widgets[widget_cnt])));
630     break;
631    
632     case WIDGET_TYPE_TEXT:
633     g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
634     GTK_TYPE_ENTRY);
635    
636     ctag = store_value(widget, ctag, (char*)gtk_entry_get_text(
637     GTK_ENTRY(gtk_widgets[widget_cnt])));
638     break;
639    
640     case WIDGET_TYPE_CHECK:
641     g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
642     GTK_TYPE_CHECK_BUTTON);
643    
644     ctag = store_value(widget, ctag,
645     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
646 harbaum 51 gtk_widgets[widget_cnt]))?"yes":
647     (widget->del_if_empty?NULL:"no"));
648 harbaum 1 break;
649    
650     case WIDGET_TYPE_KEY:
651     g_assert(!gtk_widgets[widget_cnt]);
652    
653     ctag = store_value(widget, ctag, widget->key_w.value);
654     break;
655    
656     default:
657     break;
658     }
659    
660     widget_cnt++;
661     widget = widget->next;
662     }
663    
664     *ctag = g_new0(tag_t, 1);
665     (*ctag)->key = g_strdup("created_by");
666     (*ctag)->value = g_strdup(PACKAGE " v" VERSION);
667     }
668    
669     g_free(gtk_widgets);
670    
671     if(interactive_widget_cnt)
672     gtk_widget_destroy(dialog);
673    
674 harbaum 51 if(www_context)
675     g_free(www_context);
676    
677 harbaum 1 return tag;
678     }
679    
680     /* ------------------- the item list (popup menu) -------------- */
681    
682     typedef struct {
683     appdata_t *appdata;
684     GtkWidget *menu;
685     tag_context_t *tag_context;
686     } presets_context_t;
687    
688     static void
689     cb_menu_item(GtkMenuItem *menu_item, gpointer data) {
690     presets_context_t *context = (presets_context_t*)data;
691    
692     presets_item_t *item = g_object_get_data(G_OBJECT(menu_item), "item");
693     g_assert(item);
694    
695     tag_t *tag =
696 harbaum 51 presets_item_dialog(context->appdata,
697     GTK_WINDOW(context->tag_context->dialog), item,
698 harbaum 1 *context->tag_context->tag);
699    
700     if(tag) {
701     tag_context_t *tag_context = context->tag_context;
702    
703     /* add new tags to the old list and replace entries with the same key */
704    
705     while(tag) {
706     #if 0
707     printf("current:\n");
708     tag_t *mdst = &tag_context->tag;
709     while(mdst) {
710     printf("%s: %s\n", msdt
711     #endif
712    
713     tag_t *next = tag->next;
714     tag->next = NULL;
715    
716     tag_t **dst = tag_context->tag;
717     gboolean replaced = FALSE;
718     while(*dst && !replaced) {
719     if(strcasecmp((*dst)->key, tag->key) == 0) {
720     g_free((*dst)->value);
721     (*dst)->value = g_strdup(tag->value);
722     replaced = TRUE;
723     }
724     dst = &(*dst)->next;
725     }
726    
727     /* if nothing was replaced, then just append new tag */
728     if(!replaced)
729     *dst = tag;
730     else
731     osm_tag_free(tag);
732    
733     tag = next;
734     }
735    
736     #if 0
737     /* free existing tags */
738     osm_tags_free(*tag_context->tag);
739    
740     /* attach new tags */
741     *tag_context->tag = tag;
742     #endif
743    
744     info_tags_replace(tag_context);
745     }
746     }
747    
748     static GtkWidget *build_menu(presets_context_t *context,
749     presets_item_t *item) {
750     GtkWidget *menu = gtk_menu_new();
751    
752     while(item) {
753     GtkWidget *menu_item;
754    
755 harbaum 52 /* check if this presets entry is appropriate for the current item */
756     if(item->type & context->tag_context->presets_type) {
757 harbaum 1
758 harbaum 52 if(item->name) {
759     if(!item->icon)
760     menu_item = gtk_menu_item_new_with_label(item->name);
761     else {
762     menu_item = gtk_image_menu_item_new_with_label(item->name);
763     gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
764     icon_widget_load(&context->appdata->icon, item->icon));
765     }
766    
767     if(item->is_group)
768     gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
769     build_menu(context, item->group));
770     else {
771     g_object_set_data(G_OBJECT(menu_item), "item", item);
772     g_signal_connect(menu_item, "activate",
773     GTK_SIGNAL_FUNC(cb_menu_item), context);
774     }
775     } else
776     menu_item = gtk_separator_menu_item_new();
777 harbaum 1
778 harbaum 52 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
779     }
780    
781 harbaum 1 item = item->next;
782     }
783    
784     return menu;
785     }
786    
787     static gint button_press(GtkWidget *widget, GdkEventButton *event,
788     gpointer data) {
789     presets_context_t *context = (presets_context_t*)data;
790    
791     if(event->type == GDK_BUTTON_PRESS) {
792     printf("button press %d %d\n", event->button, event->time);
793    
794     gtk_menu_popup(GTK_MENU(context->menu), NULL, NULL, NULL, NULL,
795     event->button, event->time);
796    
797     /* Tell calling code that we have handled this event; the buck
798     * stops here. */
799     return TRUE;
800     }
801     return FALSE;
802     }
803    
804     static gint on_button_destroy(GtkWidget *widget, gpointer data) {
805     presets_context_t *context = (presets_context_t*)data;
806    
807     printf("freeing preset button context\n");
808     gtk_widget_destroy(context->menu);
809     g_free(context);
810    
811     return FALSE;
812     }
813    
814 harbaum 52 GtkWidget *josm_presets_select(appdata_t *appdata,
815     tag_context_t *tag_context) {
816 harbaum 1 presets_context_t *context = g_new0(presets_context_t, 1);
817     context->appdata = appdata;
818     context->tag_context = tag_context;
819    
820     context->menu = build_menu(context, appdata->presets);
821     gtk_widget_show_all( GTK_WIDGET(context->menu) );
822    
823     GtkWidget *but = gtk_button_new_with_label(_("Presets..."));
824     gtk_widget_set_events(but, GDK_EXPOSURE_MASK);
825     gtk_widget_add_events(but, GDK_BUTTON_PRESS_MASK);
826     gtk_signal_connect(GTK_OBJECT(but), "button-press-event",
827     (GtkSignalFunc)button_press, context);
828    
829     gtk_signal_connect(GTK_OBJECT(but), "destroy",
830     (GtkSignalFunc)on_button_destroy, context);
831    
832     return but;
833     }
834    
835     /* ----------------------- cleaning up --------------------- */
836    
837     static void free_values(presets_value_t *value) {
838     while(value) {
839     presets_value_t *next = value->next;
840     if(value->text) g_free(value->text);
841     g_free(value);
842     value = next;
843     }
844    
845     }
846    
847     static void free_widget(presets_widget_t *widget) {
848     if(widget->key) xmlFree(widget->key);
849     if(widget->text) xmlFree(widget->text);
850    
851     switch(widget->type) {
852     case WIDGET_TYPE_TEXT:
853     if(widget->text_w.def) xmlFree(widget->text_w.def);
854     break;
855    
856     case WIDGET_TYPE_COMBO:
857     if(widget->combo_w.def) xmlFree(widget->combo_w.def);
858     if(widget->combo_w.values) free_values(widget->combo_w.values);
859     break;
860    
861     case WIDGET_TYPE_KEY:
862     if(widget->key_w.value) xmlFree(widget->key_w.value);
863     break;
864    
865     default:
866     break;
867     }
868    
869     g_free(widget);
870     }
871    
872     static void free_widgets(presets_widget_t *widget) {
873     while(widget) {
874     presets_widget_t *next = widget->next;
875     free_widget(widget);
876     widget = next;
877     }
878     }
879    
880     static void free_items(presets_item_t *item);
881     static void free_item(presets_item_t *item) {
882     if(item->name) xmlFree(item->name);
883     if(item->icon) xmlFree(item->icon);
884    
885     if(item->is_group)
886     free_items(item->group);
887     else
888     free_widgets(item->widget);
889    
890     g_free(item);
891     }
892    
893     static void free_items(presets_item_t *item) {
894     while(item) {
895     presets_item_t *next = item->next;
896     free_item(item);
897     item = next;
898     }
899     }
900    
901     void josm_presets_free(presets_item_t *presets) {
902     free_items(presets);
903     }
904 achadwick 50
905     // vim:et:ts=8:sw=2:sts=2:ai