Contents of /trunk/src/josm_presets.c

Parent Directory Parent Directory | Revision Log Revision Log


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