Contents of /trunk/src/josm_presets.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 52 - (hide annotations)
Fri Feb 6 08:14:09 2009 UTC (15 years, 4 months ago) by harbaum
File MIME type: text/plain
File size: 25982 byte(s)
Honour type in presets
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 52 /* TODO: sum up bits from all subentries so the main entry vanishes */
289     /* if none of the subentries matches (empty subs are not displayed) */
290     group->type = PRESETS_TYPE_ALL;
291    
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     if(*preset) preset = &((*preset)->next);
299     } else if(strcasecmp((char*)cur_node->name, "group") == 0) {
300     *preset = parse_group(doc, cur_node);
301     if(*preset) preset = &((*preset)->next);
302     } else if(strcasecmp((char*)cur_node->name, "separator") == 0) {
303     *preset = g_new0(presets_item_t, 1);
304     preset = &((*preset)->next);
305     } else
306     printf("found unhandled annotations/group/%s\n", cur_node->name);
307     }
308     }
309     return group;
310     }
311    
312     static presets_item_t *parse_annotations(xmlDocPtr doc, xmlNode *a_node) {
313     xmlNode *cur_node = NULL;
314     presets_item_t *presets = NULL, **preset = &presets;
315    
316     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
317     if (cur_node->type == XML_ELEMENT_NODE) {
318     if(strcasecmp((char*)cur_node->name, "item") == 0) {
319     *preset = parse_item(doc, cur_node);
320     if(*preset) preset = &((*preset)->next);
321     } else if(strcasecmp((char*)cur_node->name, "group") == 0) {
322     *preset = parse_group(doc, cur_node);
323     if(*preset) preset = &((*preset)->next);
324     } else if(strcasecmp((char*)cur_node->name, "separator") == 0) {
325     *preset = g_new0(presets_item_t, 1);
326     preset = &((*preset)->next);
327     } else
328     printf("found unhandled annotations/%s\n", cur_node->name);
329     }
330     }
331     return presets;
332     }
333    
334     static presets_item_t *parse_doc(xmlDocPtr doc) {
335     /* Get the root element node */
336     xmlNode *cur_node = NULL;
337     presets_item_t *presets = NULL;
338    
339     for(cur_node = xmlDocGetRootElement(doc);
340     cur_node; cur_node = cur_node->next) {
341     if (cur_node->type == XML_ELEMENT_NODE) {
342     if(strcasecmp((char*)cur_node->name, "annotations") == 0) {
343     presets = parse_annotations(doc, cur_node);
344     } else
345     printf("found unhandled %s\n", cur_node->name);
346     }
347     }
348    
349     xmlFreeDoc(doc);
350     xmlCleanupParser();
351     return presets;
352     }
353    
354     presets_item_t *josm_presets_load(void) {
355     presets_item_t *presets = NULL;
356    
357     printf("Loading JOSM presets ...\n");
358    
359     LIBXML_TEST_VERSION;
360    
361     char *filename = find_file("presets.xml");
362     if(!filename) return NULL;
363    
364     /* parse the file and get the DOM */
365     xmlDoc *doc = NULL;
366     if((doc = xmlReadFile(filename, NULL, 0)) == NULL) {
367     xmlErrorPtr errP = xmlGetLastError();
368     printf("presets download failed: "
369     "XML error while parsing:\n"
370     "%s\n", errP->message);
371     } else {
372     printf("ok, parse doc tree\n");
373     presets = parse_doc(doc);
374     }
375    
376     g_free(filename);
377     return presets;
378     }
379    
380     /* --------------------- the items dialog -------------------- */
381    
382     static void attach_both(GtkWidget *table, GtkWidget *widget, gint y) {
383     gtk_table_attach(GTK_TABLE(table), widget, 0,2,y,y+1,
384     GTK_EXPAND | GTK_FILL, 0,0,0);
385     }
386    
387     static void attach_text(GtkWidget *table, char *text, gint y) {
388     gtk_table_attach(GTK_TABLE(table), gtk_label_new(text), 0,1,y,y+1,
389     GTK_EXPAND | GTK_FILL, 0,0,0);
390     }
391    
392     static void attach_right(GtkWidget *table, GtkWidget *widget, gint y) {
393     gtk_table_attach(GTK_TABLE(table), widget, 1,2,y,y+1,
394     GTK_EXPAND | GTK_FILL, 0,0,0);
395     }
396    
397     static tag_t **store_value(presets_widget_t *widget, tag_t **ctag,
398     char *value) {
399     if((value && strlen(value)) || !widget->del_if_empty) {
400     *ctag = g_new0(tag_t, 1);
401     (*ctag)->key = g_strdup(widget->key);
402     (*ctag)->value = g_strdup(value?value:"");
403    
404     printf("key = %s, value = %s\n",
405     widget->key, (*ctag)->value);
406    
407     ctag = &((*ctag)->next);
408     } else
409     printf("ignore empty key = %s\n", widget->key);
410    
411     return ctag;
412     }
413    
414     #ifdef USE_HILDON
415     static gint table_expose_event(GtkWidget *widget, GdkEventExpose *event,
416     gboolean *first) {
417    
418     if(*first) {
419     guint border_width =
420     gtk_container_get_border_width(GTK_CONTAINER(widget->parent));
421     gtk_viewport_set_shadow_type(GTK_VIEWPORT(widget->parent), GTK_SHADOW_NONE);
422    
423     gtk_widget_set_size_request(GTK_WIDGET(widget->parent), -1,
424     widget->allocation.height + 2*border_width);
425     *first = FALSE;
426     }
427     return FALSE;
428     }
429     #endif
430    
431 harbaum 51 static tag_t *presets_item_dialog(appdata_t *appdata, GtkWindow *parent,
432 harbaum 1 presets_item_t *item, tag_t *orig_tag) {
433 harbaum 51 GtkWidget *dialog = NULL;
434 harbaum 1 gboolean ok = FALSE;
435     tag_t *tag = NULL, **ctag = &tag;
436 harbaum 51 www_context_t *www_context = NULL;
437 harbaum 1
438     printf("dialog for item %s\n", item->name);
439    
440     /* build dialog from items widget list */
441     presets_widget_t *widget = item->widget;
442    
443     /* count total number of widgets and number of widgets that */
444     /* have an interactive gui element. We won't show a dialog */
445     /* at all if there's no interactive gui element at all */
446     gint widget_cnt = 0, interactive_widget_cnt = 0;
447     while(widget) {
448     if((widget->type != WIDGET_TYPE_LABEL) &&
449     (widget->type != WIDGET_TYPE_SEPARATOR) &&
450     (widget->type != WIDGET_TYPE_KEY))
451     interactive_widget_cnt++;
452    
453     widget_cnt++;
454     widget = widget->next;
455     }
456    
457     /* allocate space for required number of gtk widgets */
458     GtkWidget **gtk_widgets = (GtkWidget**)g_new0(GtkWidget, widget_cnt);
459    
460     if(interactive_widget_cnt) {
461 harbaum 51 dialog = gtk_dialog_new_with_buttons(
462     item->name, parent, GTK_DIALOG_MODAL,
463     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
464     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
465     NULL);
466    
467     /* if a web link has been provided for this item install */
468     /* a button for this */
469     if(item->link) {
470     www_context = g_new0(www_context_t, 1);
471     www_context->link = item->link;
472     www_context->appdata = appdata;
473    
474     GtkWidget *button = gtk_dialog_add_button(GTK_DIALOG(dialog), _
475     ("Info..."), GTK_RESPONSE_HELP);
476     gtk_signal_connect(GTK_OBJECT(button), "clicked",
477     GTK_SIGNAL_FUNC(on_info), (gpointer)www_context);
478     }
479    
480 harbaum 1 /* special handling for the first label/separators */
481     guint widget_skip = 0; // number of initial widgets to skip
482     widget = item->widget;
483     if(widget && (widget->type == WIDGET_TYPE_LABEL)) {
484     gtk_window_set_title(GTK_WINDOW(dialog), widget->text);
485    
486     widget_skip++; // this widget isn't part of the contents anymore
487     widget = widget->next;
488    
489     /* skip all following separators (and keys) */
490     while(widget &&
491     ((widget->type == WIDGET_TYPE_SEPARATOR) ||
492 harbaum 51 (widget->type == WIDGET_TYPE_SPACE) ||
493 harbaum 1 (widget->type == WIDGET_TYPE_KEY))) {
494     widget_skip++; // this widget isn't part of the contents anymore
495     widget = widget->next;
496     }
497     }
498    
499     /* create table of required size */
500     GtkWidget *table = gtk_table_new(widget_cnt-widget_skip, 2, FALSE);
501    
502     widget_cnt = widget_skip;
503     while(widget) {
504     /* check if there's a value with this key already */
505     char *preset = osm_tag_get_by_key(orig_tag, widget->key);
506    
507     switch(widget->type) {
508     case WIDGET_TYPE_SEPARATOR:
509     attach_both(table, gtk_hseparator_new(), widget_cnt-widget_skip);
510     break;
511    
512 harbaum 51 case WIDGET_TYPE_SPACE:
513     /* space is just an empty label until we find something better */
514     attach_both(table, gtk_label_new(" "), widget_cnt-widget_skip);
515     break;
516    
517 harbaum 1 case WIDGET_TYPE_LABEL:
518     attach_both(table, gtk_label_new(widget->text), widget_cnt-widget_skip);
519     break;
520    
521     case WIDGET_TYPE_COMBO:
522     attach_text(table, widget->text, widget_cnt-widget_skip);
523    
524     if(!preset && widget->combo_w.def) preset = widget->combo_w.def;
525     gtk_widgets[widget_cnt] = gtk_combo_box_new_text();
526     presets_value_t *value = widget->combo_w.values;
527     int count = 0, active = -1;
528     while(value) {
529     if(active < 0 && preset && strcmp(preset, value->text)==0)
530     active = count;
531    
532     gtk_combo_box_append_text(GTK_COMBO_BOX(gtk_widgets[widget_cnt]),
533     value->text);
534     value = value->next;
535     count++;
536     }
537    
538     gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_widgets[widget_cnt]),
539     active);
540     attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
541     break;
542    
543     case WIDGET_TYPE_CHECK:
544     { gboolean def = FALSE;
545     if(preset) def = ((strcasecmp(preset, "true") == 0) ||
546     (strcasecmp(preset, "yes") == 0));
547     else def = widget->check_w.def;
548    
549     gtk_widgets[widget_cnt] =
550     gtk_check_button_new_with_label(widget->text);
551     gtk_toggle_button_set_active(
552     GTK_TOGGLE_BUTTON(gtk_widgets[widget_cnt]), def);
553     attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
554     } break;
555    
556     case WIDGET_TYPE_TEXT:
557     attach_text(table, widget->text, widget_cnt-widget_skip);
558    
559     if(!preset && widget->text_w.def) preset = widget->text_w.def;
560     gtk_widgets[widget_cnt] = gtk_entry_new();
561     if(preset)
562     gtk_entry_set_text(GTK_ENTRY(gtk_widgets[widget_cnt]), preset);
563    
564     attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
565     break;
566    
567     default:
568     break;
569     }
570    
571     widget_cnt++;
572     widget = widget->next;
573     }
574    
575     #ifndef USE_HILDON
576     /* add widget to dialog */
577     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
578     gtk_window_set_default_size(GTK_WINDOW(dialog), 300, 50);
579     #else
580     /* put it into a scrolled window */
581     GtkWidget *scroll_win = gtk_scrolled_window_new(NULL, NULL);
582     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win),
583     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
584     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll_win),
585     table);
586    
587     gboolean first = TRUE;
588     gtk_signal_connect(GTK_OBJECT(table), "expose_event",
589     G_CALLBACK(table_expose_event), &first);
590    
591     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), scroll_win);
592     // gtk_window_set_default_size(GTK_WINDOW(dialog), 50, 400);
593     #endif
594    
595     gtk_widget_show_all(dialog);
596 harbaum 51
597     /* run gtk_dialog_run, but continue if e.g. the help button was pressed */
598     int result = -1;
599     do
600     result = gtk_dialog_run(GTK_DIALOG(dialog));
601     while((result != GTK_RESPONSE_DELETE_EVENT) &&
602     (result != GTK_RESPONSE_ACCEPT) &&
603     (result != GTK_RESPONSE_REJECT));
604    
605     if(result == GTK_RESPONSE_ACCEPT)
606     ok = TRUE;
607    
608     } else
609 harbaum 1 ok = TRUE;
610 harbaum 51
611     if(ok) {
612 harbaum 1 /* handle all children of the table */
613     widget = item->widget;
614     widget_cnt = 0;
615     while(widget) {
616     switch(widget->type) {
617     case WIDGET_TYPE_COMBO:
618     g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
619     GTK_TYPE_COMBO_BOX);
620    
621     ctag = store_value(widget, ctag, gtk_combo_box_get_active_text(
622     GTK_COMBO_BOX(gtk_widgets[widget_cnt])));
623     break;
624    
625     case WIDGET_TYPE_TEXT:
626     g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
627     GTK_TYPE_ENTRY);
628    
629     ctag = store_value(widget, ctag, (char*)gtk_entry_get_text(
630     GTK_ENTRY(gtk_widgets[widget_cnt])));
631     break;
632    
633     case WIDGET_TYPE_CHECK:
634     g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
635     GTK_TYPE_CHECK_BUTTON);
636    
637     ctag = store_value(widget, ctag,
638     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
639 harbaum 51 gtk_widgets[widget_cnt]))?"yes":
640     (widget->del_if_empty?NULL:"no"));
641 harbaum 1 break;
642    
643     case WIDGET_TYPE_KEY:
644     g_assert(!gtk_widgets[widget_cnt]);
645    
646     ctag = store_value(widget, ctag, widget->key_w.value);
647     break;
648    
649     default:
650     break;
651     }
652    
653     widget_cnt++;
654     widget = widget->next;
655     }
656    
657     *ctag = g_new0(tag_t, 1);
658     (*ctag)->key = g_strdup("created_by");
659     (*ctag)->value = g_strdup(PACKAGE " v" VERSION);
660     }
661    
662     g_free(gtk_widgets);
663    
664     if(interactive_widget_cnt)
665     gtk_widget_destroy(dialog);
666    
667 harbaum 51 if(www_context)
668     g_free(www_context);
669    
670 harbaum 1 return tag;
671     }
672    
673     /* ------------------- the item list (popup menu) -------------- */
674    
675     typedef struct {
676     appdata_t *appdata;
677     GtkWidget *menu;
678     tag_context_t *tag_context;
679     } presets_context_t;
680    
681     static void
682     cb_menu_item(GtkMenuItem *menu_item, gpointer data) {
683     presets_context_t *context = (presets_context_t*)data;
684    
685     presets_item_t *item = g_object_get_data(G_OBJECT(menu_item), "item");
686     g_assert(item);
687    
688     tag_t *tag =
689 harbaum 51 presets_item_dialog(context->appdata,
690     GTK_WINDOW(context->tag_context->dialog), item,
691 harbaum 1 *context->tag_context->tag);
692    
693     if(tag) {
694     tag_context_t *tag_context = context->tag_context;
695    
696     /* add new tags to the old list and replace entries with the same key */
697    
698     while(tag) {
699     #if 0
700     printf("current:\n");
701     tag_t *mdst = &tag_context->tag;
702     while(mdst) {
703     printf("%s: %s\n", msdt
704     #endif
705    
706     tag_t *next = tag->next;
707     tag->next = NULL;
708    
709     tag_t **dst = tag_context->tag;
710     gboolean replaced = FALSE;
711     while(*dst && !replaced) {
712     if(strcasecmp((*dst)->key, tag->key) == 0) {
713     g_free((*dst)->value);
714     (*dst)->value = g_strdup(tag->value);
715     replaced = TRUE;
716     }
717     dst = &(*dst)->next;
718     }
719    
720     /* if nothing was replaced, then just append new tag */
721     if(!replaced)
722     *dst = tag;
723     else
724     osm_tag_free(tag);
725    
726     tag = next;
727     }
728    
729     #if 0
730     /* free existing tags */
731     osm_tags_free(*tag_context->tag);
732    
733     /* attach new tags */
734     *tag_context->tag = tag;
735     #endif
736    
737     info_tags_replace(tag_context);
738     }
739     }
740    
741     static GtkWidget *build_menu(presets_context_t *context,
742     presets_item_t *item) {
743     GtkWidget *menu = gtk_menu_new();
744    
745     while(item) {
746     GtkWidget *menu_item;
747    
748 harbaum 52 /* check if this presets entry is appropriate for the current item */
749     if(item->type & context->tag_context->presets_type) {
750 harbaum 1
751 harbaum 52 if(item->name) {
752     if(!item->icon)
753     menu_item = gtk_menu_item_new_with_label(item->name);
754     else {
755     menu_item = gtk_image_menu_item_new_with_label(item->name);
756     gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
757     icon_widget_load(&context->appdata->icon, item->icon));
758     }
759    
760     if(item->is_group)
761     gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
762     build_menu(context, item->group));
763     else {
764     g_object_set_data(G_OBJECT(menu_item), "item", item);
765     g_signal_connect(menu_item, "activate",
766     GTK_SIGNAL_FUNC(cb_menu_item), context);
767     }
768     } else
769     menu_item = gtk_separator_menu_item_new();
770 harbaum 1
771 harbaum 52 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
772     }
773    
774 harbaum 1 item = item->next;
775     }
776    
777     return menu;
778     }
779    
780     static gint button_press(GtkWidget *widget, GdkEventButton *event,
781     gpointer data) {
782     presets_context_t *context = (presets_context_t*)data;
783    
784     if(event->type == GDK_BUTTON_PRESS) {
785     printf("button press %d %d\n", event->button, event->time);
786    
787     gtk_menu_popup(GTK_MENU(context->menu), NULL, NULL, NULL, NULL,
788     event->button, event->time);
789    
790     /* Tell calling code that we have handled this event; the buck
791     * stops here. */
792     return TRUE;
793     }
794     return FALSE;
795     }
796    
797     static gint on_button_destroy(GtkWidget *widget, gpointer data) {
798     presets_context_t *context = (presets_context_t*)data;
799    
800     printf("freeing preset button context\n");
801     gtk_widget_destroy(context->menu);
802     g_free(context);
803    
804     return FALSE;
805     }
806    
807 harbaum 52 GtkWidget *josm_presets_select(appdata_t *appdata,
808     tag_context_t *tag_context) {
809 harbaum 1 presets_context_t *context = g_new0(presets_context_t, 1);
810     context->appdata = appdata;
811     context->tag_context = tag_context;
812    
813     context->menu = build_menu(context, appdata->presets);
814     gtk_widget_show_all( GTK_WIDGET(context->menu) );
815    
816     GtkWidget *but = gtk_button_new_with_label(_("Presets..."));
817     gtk_widget_set_events(but, GDK_EXPOSURE_MASK);
818     gtk_widget_add_events(but, GDK_BUTTON_PRESS_MASK);
819     gtk_signal_connect(GTK_OBJECT(but), "button-press-event",
820     (GtkSignalFunc)button_press, context);
821    
822     gtk_signal_connect(GTK_OBJECT(but), "destroy",
823     (GtkSignalFunc)on_button_destroy, context);
824    
825     return but;
826     }
827    
828     /* ----------------------- cleaning up --------------------- */
829    
830     static void free_values(presets_value_t *value) {
831     while(value) {
832     presets_value_t *next = value->next;
833     if(value->text) g_free(value->text);
834     g_free(value);
835     value = next;
836     }
837    
838     }
839    
840     static void free_widget(presets_widget_t *widget) {
841     if(widget->key) xmlFree(widget->key);
842     if(widget->text) xmlFree(widget->text);
843    
844     switch(widget->type) {
845     case WIDGET_TYPE_TEXT:
846     if(widget->text_w.def) xmlFree(widget->text_w.def);
847     break;
848    
849     case WIDGET_TYPE_COMBO:
850     if(widget->combo_w.def) xmlFree(widget->combo_w.def);
851     if(widget->combo_w.values) free_values(widget->combo_w.values);
852     break;
853    
854     case WIDGET_TYPE_KEY:
855     if(widget->key_w.value) xmlFree(widget->key_w.value);
856     break;
857    
858     default:
859     break;
860     }
861    
862     g_free(widget);
863     }
864    
865     static void free_widgets(presets_widget_t *widget) {
866     while(widget) {
867     presets_widget_t *next = widget->next;
868     free_widget(widget);
869     widget = next;
870     }
871     }
872    
873     static void free_items(presets_item_t *item);
874     static void free_item(presets_item_t *item) {
875     if(item->name) xmlFree(item->name);
876     if(item->icon) xmlFree(item->icon);
877    
878     if(item->is_group)
879     free_items(item->group);
880     else
881     free_widgets(item->widget);
882    
883     g_free(item);
884     }
885    
886     static void free_items(presets_item_t *item) {
887     while(item) {
888     presets_item_t *next = item->next;
889     free_item(item);
890     item = next;
891     }
892     }
893    
894     void josm_presets_free(presets_item_t *presets) {
895     free_items(presets);
896     }
897 achadwick 50
898     // vim:et:ts=8:sw=2:sts=2:ai