Contents of /trunk/src/josm_presets.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 52 - (show annotations)
Fri Feb 6 08:14:09 2009 UTC (15 years, 3 months ago) by harbaum
File MIME type: text/plain
File size: 25982 byte(s)
Honour type in presets
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 #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 /* --------------------- 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 if(!name) return NULL;
92
93 /* 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 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 /* parse children of a given node for into *widget */
147 static presets_widget_t **parse_widgets(xmlNode *a_node,
148 presets_item_t *item,
149 presets_widget_t **widget) {
150 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 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 /* --------- 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 /* special handling of pre-<space/> separators */
173 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 }
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
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 }
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 widget = parse_widgets(cur_node, item, widget);
241 }
242
243 else if (strcasecmp((char*)cur_node->name, "link") == 0) {
244
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 printf("found unhandled annotations/item/%s\n", cur_node->name);
253 }
254 }
255 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 item->icon =
266 josm_icon_name_adjust((char*)xmlGetProp(a_node, BAD_CAST "icon"));
267
268 item->type =
269 josm_type_parse((char*)xmlGetProp(a_node, BAD_CAST "type"));
270
271 presets_widget_t **widget = &item->widget;
272 parse_widgets(a_node, item, widget);
273 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 group->icon =
286 josm_icon_name_adjust((char*)xmlGetProp(a_node, BAD_CAST "icon"));
287
288 /* 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 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 static tag_t *presets_item_dialog(appdata_t *appdata, GtkWindow *parent,
432 presets_item_t *item, tag_t *orig_tag) {
433 GtkWidget *dialog = NULL;
434 gboolean ok = FALSE;
435 tag_t *tag = NULL, **ctag = &tag;
436 www_context_t *www_context = NULL;
437
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 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 /* 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 (widget->type == WIDGET_TYPE_SPACE) ||
493 (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 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 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
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 ok = TRUE;
610
611 if(ok) {
612 /* 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 gtk_widgets[widget_cnt]))?"yes":
640 (widget->del_if_empty?NULL:"no"));
641 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 if(www_context)
668 g_free(www_context);
669
670 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 presets_item_dialog(context->appdata,
690 GTK_WINDOW(context->tag_context->dialog), item,
691 *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 /* check if this presets entry is appropriate for the current item */
749 if(item->type & context->tag_context->presets_type) {
750
751 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
771 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
772 }
773
774 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 GtkWidget *josm_presets_select(appdata_t *appdata,
808 tag_context_t *tag_context) {
809 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
898 // vim:et:ts=8:sw=2:sts=2:ai