Contents of /branches/ports/maemo/src/josm_presets.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 137 - (show annotations)
Sat Mar 21 22:37:16 2009 UTC (15 years, 2 months ago) by achadwick
File MIME type: text/plain
File size: 26062 byte(s)
Merge to tags/trunk-0.6.14 (-r89:HEAD). Will commit build fixes separately.
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 #ifdef ENABLE_BROWSER_INTERFACE
30 #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 #endif
55
56 /* --------------------- 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 if(!name) return NULL;
94
95 /* 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 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 /* parse children of a given node for into *widget */
149 static presets_widget_t **parse_widgets(xmlNode *a_node,
150 presets_item_t *item,
151 presets_widget_t **widget) {
152 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 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 /* --------- 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 /* special handling of pre-<space/> separators */
175 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 }
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
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 }
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 widget = parse_widgets(cur_node, item, widget);
243 }
244
245 else if (strcasecmp((char*)cur_node->name, "link") == 0) {
246
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 printf("found unhandled annotations/item/%s\n", cur_node->name);
255 }
256 }
257 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 item->icon =
268 josm_icon_name_adjust((char*)xmlGetProp(a_node, BAD_CAST "icon"));
269
270 item->type =
271 josm_type_parse((char*)xmlGetProp(a_node, BAD_CAST "type"));
272
273 presets_widget_t **widget = &item->widget;
274 parse_widgets(a_node, item, widget);
275 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 group->icon =
288 josm_icon_name_adjust((char*)xmlGetProp(a_node, BAD_CAST "icon"));
289
290 group->type = 0;
291
292 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) {
299 group->type |= (*preset)->type;
300 preset = &((*preset)->next);
301 }
302 } else if(strcasecmp((char*)cur_node->name, "group") == 0) {
303 *preset = parse_group(doc, cur_node);
304 if(*preset) {
305 group->type |= (*preset)->type;
306 preset = &((*preset)->next);
307 }
308 } 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
316
317
318 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 static tag_t *presets_item_dialog(appdata_t *appdata, GtkWindow *parent,
441 presets_item_t *item, tag_t *orig_tag) {
442 GtkWidget *dialog = NULL;
443 gboolean ok = FALSE;
444 tag_t *tag = NULL, **ctag = &tag;
445 #ifdef ENABLE_BROWSER_INTERFACE
446 www_context_t *www_context = NULL;
447 #endif
448
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 dialog = gtk_dialog_new_with_buttons(
473 item->name, parent, GTK_DIALOG_MODAL,
474 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
475 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
476 NULL);
477
478 #ifdef ENABLE_BROWSER_INTERFACE
479 /* if a web link has been provided for this item install */
480 /* a button for this */
481 if(item->link) {
482 www_context = g_new0(www_context_t, 1);
483 www_context->link = item->link;
484 www_context->appdata = appdata;
485
486 GtkWidget *button = gtk_dialog_add_button(GTK_DIALOG(dialog), _
487 ("Info..."), GTK_RESPONSE_HELP);
488 gtk_signal_connect(GTK_OBJECT(button), "clicked",
489 GTK_SIGNAL_FUNC(on_info), (gpointer)www_context);
490 }
491 #endif
492
493 /* special handling for the first label/separators */
494 guint widget_skip = 0; // number of initial widgets to skip
495 widget = item->widget;
496 if(widget && (widget->type == WIDGET_TYPE_LABEL)) {
497 gtk_window_set_title(GTK_WINDOW(dialog), widget->text);
498
499 widget_skip++; // this widget isn't part of the contents anymore
500 widget = widget->next;
501
502 /* skip all following separators (and keys) */
503 while(widget &&
504 ((widget->type == WIDGET_TYPE_SEPARATOR) ||
505 (widget->type == WIDGET_TYPE_SPACE) ||
506 (widget->type == WIDGET_TYPE_KEY))) {
507 widget_skip++; // this widget isn't part of the contents anymore
508 widget = widget->next;
509 }
510 }
511
512 /* create table of required size */
513 GtkWidget *table = gtk_table_new(widget_cnt-widget_skip, 2, FALSE);
514
515 widget_cnt = widget_skip;
516 while(widget) {
517 /* check if there's a value with this key already */
518 char *preset = osm_tag_get_by_key(orig_tag, widget->key);
519
520 switch(widget->type) {
521 case WIDGET_TYPE_SEPARATOR:
522 attach_both(table, gtk_hseparator_new(), widget_cnt-widget_skip);
523 break;
524
525 case WIDGET_TYPE_SPACE:
526 /* space is just an empty label until we find something better */
527 attach_both(table, gtk_label_new(" "), widget_cnt-widget_skip);
528 break;
529
530 case WIDGET_TYPE_LABEL:
531 attach_both(table, gtk_label_new(widget->text), widget_cnt-widget_skip);
532 break;
533
534 case WIDGET_TYPE_COMBO:
535 attach_text(table, widget->text, widget_cnt-widget_skip);
536
537 if(!preset && widget->combo_w.def) preset = widget->combo_w.def;
538 gtk_widgets[widget_cnt] = gtk_combo_box_new_text();
539 presets_value_t *value = widget->combo_w.values;
540 int count = 0, active = -1;
541 while(value) {
542 if(active < 0 && preset && strcmp(preset, value->text)==0)
543 active = count;
544
545 gtk_combo_box_append_text(GTK_COMBO_BOX(gtk_widgets[widget_cnt]),
546 value->text);
547 value = value->next;
548 count++;
549 }
550
551 gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_widgets[widget_cnt]),
552 active);
553 attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
554 break;
555
556 case WIDGET_TYPE_CHECK:
557 { gboolean def = FALSE;
558 if(preset) def = ((strcasecmp(preset, "true") == 0) ||
559 (strcasecmp(preset, "yes") == 0));
560 else def = widget->check_w.def;
561
562 gtk_widgets[widget_cnt] =
563 gtk_check_button_new_with_label(widget->text);
564 gtk_toggle_button_set_active(
565 GTK_TOGGLE_BUTTON(gtk_widgets[widget_cnt]), def);
566 attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
567 } break;
568
569 case WIDGET_TYPE_TEXT:
570 attach_text(table, widget->text, widget_cnt-widget_skip);
571
572 if(!preset && widget->text_w.def) preset = widget->text_w.def;
573 gtk_widgets[widget_cnt] = gtk_entry_new();
574 if(preset)
575 gtk_entry_set_text(GTK_ENTRY(gtk_widgets[widget_cnt]), preset);
576
577 attach_right(table, gtk_widgets[widget_cnt], widget_cnt-widget_skip);
578 break;
579
580 default:
581 break;
582 }
583
584 widget_cnt++;
585 widget = widget->next;
586 }
587
588 #ifndef USE_HILDON
589 /* add widget to dialog */
590 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
591 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, 50);
592 #else
593 /* put it into a scrolled window */
594 GtkWidget *scroll_win = gtk_scrolled_window_new(NULL, NULL);
595 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win),
596 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
597 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll_win),
598 table);
599
600 gboolean first = TRUE;
601 gtk_signal_connect(GTK_OBJECT(table), "expose_event",
602 G_CALLBACK(table_expose_event), &first);
603
604 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), scroll_win);
605 // gtk_window_set_default_size(GTK_WINDOW(dialog), 50, 400);
606 #endif
607
608 gtk_widget_show_all(dialog);
609
610 /* run gtk_dialog_run, but continue if e.g. the help button was pressed */
611 int result = -1;
612 do
613 result = gtk_dialog_run(GTK_DIALOG(dialog));
614 while((result != GTK_RESPONSE_DELETE_EVENT) &&
615 (result != GTK_RESPONSE_ACCEPT) &&
616 (result != GTK_RESPONSE_REJECT));
617
618 if(result == GTK_RESPONSE_ACCEPT)
619 ok = TRUE;
620
621 } else
622 ok = TRUE;
623
624 if(ok) {
625 /* handle all children of the table */
626 widget = item->widget;
627 widget_cnt = 0;
628 while(widget) {
629 switch(widget->type) {
630 case WIDGET_TYPE_COMBO:
631 g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
632 GTK_TYPE_COMBO_BOX);
633
634 ctag = store_value(widget, ctag, gtk_combo_box_get_active_text(
635 GTK_COMBO_BOX(gtk_widgets[widget_cnt])));
636 break;
637
638 case WIDGET_TYPE_TEXT:
639 g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
640 GTK_TYPE_ENTRY);
641
642 ctag = store_value(widget, ctag, (char*)gtk_entry_get_text(
643 GTK_ENTRY(gtk_widgets[widget_cnt])));
644 break;
645
646 case WIDGET_TYPE_CHECK:
647 g_assert(GTK_WIDGET_TYPE(gtk_widgets[widget_cnt]) ==
648 GTK_TYPE_CHECK_BUTTON);
649
650 ctag = store_value(widget, ctag,
651 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
652 gtk_widgets[widget_cnt]))?"yes":
653 (widget->del_if_empty?NULL:"no"));
654 break;
655
656 case WIDGET_TYPE_KEY:
657 g_assert(!gtk_widgets[widget_cnt]);
658
659 ctag = store_value(widget, ctag, widget->key_w.value);
660 break;
661
662 default:
663 break;
664 }
665
666 widget_cnt++;
667 widget = widget->next;
668 }
669
670 *ctag = g_new0(tag_t, 1);
671 (*ctag)->key = g_strdup("created_by");
672 (*ctag)->value = g_strdup(PACKAGE " v" VERSION);
673 }
674
675 g_free(gtk_widgets);
676
677 if(interactive_widget_cnt)
678 gtk_widget_destroy(dialog);
679
680 #ifdef ENABLE_BROWSER_INTERFACE
681 if(www_context)
682 g_free(www_context);
683 #endif
684
685 return tag;
686 }
687
688 /* ------------------- the item list (popup menu) -------------- */
689
690 typedef struct {
691 appdata_t *appdata;
692 GtkWidget *menu;
693 tag_context_t *tag_context;
694 } presets_context_t;
695
696 static void
697 cb_menu_item(GtkMenuItem *menu_item, gpointer data) {
698 presets_context_t *context = (presets_context_t*)data;
699
700 presets_item_t *item = g_object_get_data(G_OBJECT(menu_item), "item");
701 g_assert(item);
702
703 tag_t *tag =
704 presets_item_dialog(context->appdata,
705 GTK_WINDOW(context->tag_context->dialog), item,
706 *context->tag_context->tag);
707
708 if(tag) {
709 tag_context_t *tag_context = context->tag_context;
710
711 /* add new tags to the old list and replace entries with the same key */
712
713 while(tag) {
714 #if 0
715 printf("current:\n");
716 tag_t *mdst = &tag_context->tag;
717 while(mdst) {
718 printf("%s: %s\n", msdt
719 #endif
720
721 tag_t *next = tag->next;
722 tag->next = NULL;
723
724 tag_t **dst = tag_context->tag;
725 gboolean replaced = FALSE;
726 while(*dst && !replaced) {
727 if(strcasecmp((*dst)->key, tag->key) == 0) {
728 g_free((*dst)->value);
729 (*dst)->value = g_strdup(tag->value);
730 replaced = TRUE;
731 }
732 dst = &(*dst)->next;
733 }
734
735 /* if nothing was replaced, then just append new tag */
736 if(!replaced)
737 *dst = tag;
738 else
739 osm_tag_free(tag);
740
741 tag = next;
742 }
743
744 #if 0
745 /* free existing tags */
746 osm_tags_free(*tag_context->tag);
747
748 /* attach new tags */
749 *tag_context->tag = tag;
750 #endif
751
752 info_tags_replace(tag_context);
753 }
754 }
755
756 static GtkWidget *build_menu(presets_context_t *context,
757 presets_item_t *item) {
758 GtkWidget *menu = gtk_menu_new();
759
760 while(item) {
761 GtkWidget *menu_item;
762
763 /* check if this presets entry is appropriate for the current item */
764 if(item->type & context->tag_context->presets_type) {
765
766 if(item->name) {
767 if(!item->icon)
768 menu_item = gtk_menu_item_new_with_label(item->name);
769 else {
770 menu_item = gtk_image_menu_item_new_with_label(item->name);
771 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
772 icon_widget_load(&context->appdata->icon, item->icon));
773 }
774
775 if(item->is_group)
776 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
777 build_menu(context, item->group));
778 else {
779 g_object_set_data(G_OBJECT(menu_item), "item", item);
780 g_signal_connect(menu_item, "activate",
781 GTK_SIGNAL_FUNC(cb_menu_item), context);
782 }
783 } else
784 menu_item = gtk_separator_menu_item_new();
785
786 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
787 }
788
789 item = item->next;
790 }
791
792 return menu;
793 }
794
795 static gint button_press(GtkWidget *widget, GdkEventButton *event,
796 gpointer data) {
797 presets_context_t *context = (presets_context_t*)data;
798
799 if(event->type == GDK_BUTTON_PRESS) {
800 printf("button press %d %d\n", event->button, event->time);
801
802 gtk_menu_popup(GTK_MENU(context->menu), NULL, NULL, NULL, NULL,
803 event->button, event->time);
804
805 /* Tell calling code that we have handled this event; the buck
806 * stops here. */
807 return TRUE;
808 }
809 return FALSE;
810 }
811
812 static gint on_button_destroy(GtkWidget *widget, gpointer data) {
813 presets_context_t *context = (presets_context_t*)data;
814
815 printf("freeing preset button context\n");
816 gtk_widget_destroy(context->menu);
817 g_free(context);
818
819 return FALSE;
820 }
821
822 GtkWidget *josm_presets_select(appdata_t *appdata,
823 tag_context_t *tag_context) {
824 presets_context_t *context = g_new0(presets_context_t, 1);
825 context->appdata = appdata;
826 context->tag_context = tag_context;
827
828 context->menu = build_menu(context, appdata->presets);
829 gtk_widget_show_all( GTK_WIDGET(context->menu) );
830
831 GtkWidget *but = gtk_button_new_with_label(_("Presets..."));
832 gtk_widget_set_events(but, GDK_EXPOSURE_MASK);
833 gtk_widget_add_events(but, GDK_BUTTON_PRESS_MASK);
834 gtk_signal_connect(GTK_OBJECT(but), "button-press-event",
835 (GtkSignalFunc)button_press, context);
836
837 gtk_signal_connect(GTK_OBJECT(but), "destroy",
838 (GtkSignalFunc)on_button_destroy, context);
839
840 return but;
841 }
842
843 /* ----------------------- cleaning up --------------------- */
844
845 static void free_values(presets_value_t *value) {
846 while(value) {
847 presets_value_t *next = value->next;
848 if(value->text) g_free(value->text);
849 g_free(value);
850 value = next;
851 }
852
853 }
854
855 static void free_widget(presets_widget_t *widget) {
856 if(widget->key) xmlFree(widget->key);
857 if(widget->text) xmlFree(widget->text);
858
859 switch(widget->type) {
860 case WIDGET_TYPE_TEXT:
861 if(widget->text_w.def) xmlFree(widget->text_w.def);
862 break;
863
864 case WIDGET_TYPE_COMBO:
865 if(widget->combo_w.def) xmlFree(widget->combo_w.def);
866 if(widget->combo_w.values) free_values(widget->combo_w.values);
867 break;
868
869 case WIDGET_TYPE_KEY:
870 if(widget->key_w.value) xmlFree(widget->key_w.value);
871 break;
872
873 default:
874 break;
875 }
876
877 g_free(widget);
878 }
879
880 static void free_widgets(presets_widget_t *widget) {
881 while(widget) {
882 presets_widget_t *next = widget->next;
883 free_widget(widget);
884 widget = next;
885 }
886 }
887
888 static void free_items(presets_item_t *item);
889 static void free_item(presets_item_t *item) {
890 if(item->name) xmlFree(item->name);
891 if(item->icon) xmlFree(item->icon);
892
893 if(item->is_group)
894 free_items(item->group);
895 else
896 free_widgets(item->widget);
897
898 g_free(item);
899 }
900
901 static void free_items(presets_item_t *item) {
902 while(item) {
903 presets_item_t *next = item->next;
904 free_item(item);
905 item = next;
906 }
907 }
908
909 void josm_presets_free(presets_item_t *presets) {
910 free_items(presets);
911 }
912
913 // vim:et:ts=8:sw=2:sts=2:ai