]> git.sur5r.net Git - glabels/blob - src/xml-label.c
Imported Upstream version 3.2.0
[glabels] / src / xml-label.c
1 /*
2  *  xml-label.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  gLabels is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include "xml-label.h"
24
25 #include <glib/gi18n.h>
26 #include <glib.h>
27 #include <libxml/tree.h>
28 #include <libxml/parser.h>
29 #include <libxml/xinclude.h>
30 #include <gdk-pixbuf/gdk-pixdata.h>
31
32 #include <libglabels.h>
33 #include "label.h"
34 #include "label-object.h"
35 #include "label-text.h"
36 #include "label-box.h"
37 #include "label-line.h"
38 #include "label-ellipse.h"
39 #include "label-image.h"
40 #include "label-barcode.h"
41 #include "bc-backends.h"
42 #include "xml-label-04.h"
43 #include "str-util.h"
44 #include "prefs.h"
45
46 #include "debug.h"
47
48
49 /*========================================================*/
50 /* Private macros and constants.                          */
51 /*========================================================*/
52 #define COMPAT01_NAME_SPACE "http://snaught.com/glabels/0.1/"
53 #define COMPAT04_NAME_SPACE "http://snaught.com/glabels/0.4/"
54 #define COMPAT20_NAME_SPACE "http://snaught.com/glabels/2.0/"
55 #define COMPAT22_NAME_SPACE "http://snaught.com/glabels/2.2/"
56
57
58 /*========================================================*/
59 /* Private types.                                         */
60 /*========================================================*/
61
62
63 /*========================================================*/
64 /* Private globals.                                       */
65 /*========================================================*/
66
67
68 /*========================================================*/
69 /* Private function prototypes.                           */
70 /*========================================================*/
71
72 static glLabel       *xml_doc_to_label         (xmlDocPtr         doc,
73                                                 glXMLLabelStatus *status);
74
75 static glLabel       *xml_parse_label          (xmlNodePtr        root,
76                                                 glXMLLabelStatus *status);
77
78 static void           xml_parse_objects        (xmlNodePtr        node,
79                                                 glLabel          *label);
80
81 static void           xml_parse_object_text    (xmlNodePtr        node,
82                                                 glLabel          *label);
83
84 static void           xml_parse_object_box     (xmlNodePtr        node,
85                                                 glLabel          *label);
86
87 static void           xml_parse_object_ellipse (xmlNodePtr        node,
88                                                 glLabel          *label);
89
90 static void           xml_parse_object_line    (xmlNodePtr        node,
91                                                 glLabel          *label);
92
93 static void           xml_parse_object_image   (xmlNodePtr        node,
94                                                 glLabel          *label);
95
96 static void           xml_parse_object_barcode (xmlNodePtr        node,
97                                                 glLabel          *label);
98
99 static void           xml_parse_merge_fields   (xmlNodePtr        node,
100                                                 glLabel          *label);
101
102 static void           xml_parse_data           (xmlNodePtr        node,
103                                                 glLabel          *label);
104
105 static void           xml_parse_pixdata        (xmlNodePtr        node,
106                                                 glLabel          *label);
107
108 static void           xml_parse_file_node      (xmlNodePtr        node,
109                                                 glLabel          *label);
110
111 static void           xml_parse_toplevel_span  (xmlNodePtr        node,
112                                                 glLabelObject    *object);
113
114 static void           xml_parse_affine_attrs   (xmlNodePtr        node,
115                                                 glLabelObject    *object);
116
117 static void           xml_parse_shadow_attrs   (xmlNodePtr        node,
118                                                 glLabelObject    *object);
119
120 static xmlDocPtr      xml_label_to_doc         (glLabel          *label,
121                                                 glXMLLabelStatus *status);
122
123 static void           xml_create_objects       (xmlNodePtr        parent,
124                                                 xmlNsPtr          ns,
125                                                 glLabel          *label);
126
127 static void           xml_create_object_text   (xmlNodePtr        parent,
128                                                 xmlNsPtr          ns,
129                                                 glLabelObject    *object);
130
131 static void           xml_create_object_box    (xmlNodePtr        parent,
132                                                 xmlNsPtr          ns,
133                                                 glLabelObject    *object);
134
135 static void           xml_create_object_line   (xmlNodePtr        parent,
136                                                 xmlNsPtr          ns,
137                                                 glLabelObject    *object);
138
139 static void           xml_create_object_ellipse(xmlNodePtr        parent,
140                                                 xmlNsPtr          ns,
141                                                 glLabelObject    *object);
142
143 static void           xml_create_object_image  (xmlNodePtr        parent,
144                                                 xmlNsPtr          ns,
145                                                 glLabelObject    *object);
146
147 static void           xml_create_object_barcode(xmlNodePtr        parent,
148                                                 xmlNsPtr          ns,
149                                                 glLabelObject    *object);
150
151 static void           xml_create_merge_fields  (xmlNodePtr        parent,
152                                                 xmlNsPtr          ns,
153                                                 glLabel          *label);
154
155 static void           xml_create_data          (xmlDocPtr         doc,
156                                                 xmlNodePtr        parent,
157                                                 xmlNsPtr          ns,
158                                                 glLabel          *label);
159
160 static void           xml_create_pixdata       (xmlNodePtr        parent,
161                                                 xmlNsPtr          ns,
162                                                 glLabel          *label,
163                                                 gchar            *name);
164
165 static void           xml_create_file_svg      (xmlDocPtr         doc,
166                                                 xmlNodePtr        parent,
167                                                 xmlNsPtr          ns,
168                                                 glLabel          *label,
169                                                 gchar            *name);
170
171 static void           xml_create_toplevel_span (xmlNodePtr        node,
172                                                 xmlNsPtr          ns,
173                                                 glLabelText      *object_text);
174
175 static void           xml_create_affine_attrs  (xmlNodePtr        node,
176                                                 glLabelObject    *object);
177
178 static void           xml_create_shadow_attrs  (xmlNodePtr        node,
179                                                 glLabelObject    *object);
180
181
182 /****************************************************************************/
183 /* Open and read label from xml file.                                       */
184 /****************************************************************************/
185 glLabel *
186 gl_xml_label_open (const gchar      *utf8_filename,
187                    glXMLLabelStatus *status)
188 {
189         xmlDocPtr  doc;
190         glLabel   *label;
191         gchar     *filename;
192
193         gl_debug (DEBUG_XML, "START");
194
195         filename = g_filename_from_utf8 (utf8_filename, -1, NULL, NULL, NULL);
196         g_return_val_if_fail (filename, NULL);
197
198         doc = xmlReadFile (filename, NULL, XML_PARSE_HUGE);
199         if (!doc) {
200                 g_message ("xmlParseFile error");
201                 *status = XML_LABEL_ERROR_OPEN_PARSE;
202                 return NULL;
203         }
204
205         xmlXIncludeProcess (doc);
206         xmlReconciliateNs (doc, xmlDocGetRootElement (doc));
207
208         label = xml_doc_to_label (doc, status);
209
210         xmlFreeDoc (doc);
211
212         if (label) {
213                 gl_label_set_filename (label, utf8_filename);
214                 gl_label_clear_modified (label);
215         }
216
217         g_free (filename);
218         gl_debug (DEBUG_XML, "END");
219
220         return label;
221 }
222
223
224 /****************************************************************************/
225 /* Read label from xml buffer.                                              */
226 /****************************************************************************/
227 glLabel *
228 gl_xml_label_open_buffer (const gchar      *buffer,
229                           glXMLLabelStatus *status)
230 {
231         xmlDocPtr  doc;
232         glLabel   *label;
233
234         gl_debug (DEBUG_XML, "START");
235
236         doc = xmlReadDoc ((xmlChar *) buffer, NULL, NULL, XML_PARSE_HUGE);
237         if (!doc) {
238                 g_message ("xmlParseFile error");
239                 *status = XML_LABEL_ERROR_OPEN_PARSE;
240                 return NULL;
241         }
242
243         label = xml_doc_to_label (doc, status);
244
245         xmlFreeDoc (doc);
246
247         if (label) {
248                 gl_label_clear_modified (label);
249         }
250
251         gl_debug (DEBUG_XML, "END");
252
253         return label;
254 }
255
256
257 /*--------------------------------------------------------------------------*/
258 /* PRIVATE.  Parse xml doc structure and create label.                      */
259 /*--------------------------------------------------------------------------*/
260 static glLabel *
261 xml_doc_to_label (xmlDocPtr         doc,
262                   glXMLLabelStatus *status)
263 {
264         xmlNodePtr  root;
265         glLabel    *label;
266
267         gl_debug (DEBUG_XML, "START");
268
269         LIBXML_TEST_VERSION;
270
271         *status = XML_LABEL_OK;
272
273         root = xmlDocGetRootElement (doc);
274         if (!root || !root->name) {
275                 g_message ("No document root");
276                 *status = XML_LABEL_ERROR_OPEN_PARSE;
277                 return NULL;
278         }
279
280         /* Try compatability mode 0.1 */
281         if (xmlSearchNsByHref (doc, root, (xmlChar *)COMPAT01_NAME_SPACE))
282         {
283                 g_message ("Importing from glabels 0.1 format");
284                 g_message ("TODO");
285                 label = NULL; /* TODO */
286                 return label;
287         }
288
289         /* Try compatability mode 0.4 */
290         if (xmlSearchNsByHref (doc, root, (xmlChar *)COMPAT04_NAME_SPACE))
291         {
292                 g_message ("Importing from glabels 0.4 format");
293                 label = gl_xml_label_04_parse (root, status);
294                 return label;
295         }
296
297         /* Test for current namespaces. */
298         if ( !xmlSearchNsByHref (doc, root, (xmlChar *)COMPAT20_NAME_SPACE) &&
299              !xmlSearchNsByHref (doc, root, (xmlChar *)COMPAT22_NAME_SPACE) &&
300              !xmlSearchNsByHref (doc, root, (xmlChar *)LGL_XML_NAME_SPACE) )
301         {
302                 g_message ("Unknown glabels Namespace -- Using %s",
303                            LGL_XML_NAME_SPACE);
304         }
305
306         label = xml_parse_label (root, status);
307         if (label)
308         {
309                 gl_label_set_compression (label, xmlGetDocCompressMode (doc));
310         }
311
312         gl_debug (DEBUG_XML, "END");
313
314         return label;
315 }
316
317
318 /*--------------------------------------------------------------------------*/
319 /* PRIVATE.  Parse xml root node and create label.                          */
320 /*--------------------------------------------------------------------------*/
321 static glLabel *
322 xml_parse_label (xmlNodePtr        root,
323                  glXMLLabelStatus *status)
324 {
325         xmlNodePtr   child_node;
326         glLabel     *label;
327         lglTemplate *template;
328
329         gl_debug (DEBUG_XML, "START");
330
331         *status = XML_LABEL_OK;
332
333         if (!lgl_xml_is_node (root, "Glabels-document")) {
334                 g_message ("Bad root node = \"%s\"", root->name);
335                 *status = XML_LABEL_ERROR_OPEN_PARSE;
336                 return NULL;
337         }
338
339         label = GL_LABEL(gl_label_new ());
340
341         /* Pass 1, extract data nodes to pre-load cache. */
342         for (child_node = root->xmlChildrenNode; child_node != NULL; child_node = child_node->next) {
343                 if (lgl_xml_is_node (child_node, "Data")) {
344                         xml_parse_data (child_node, label);
345                 }
346         }
347
348         /* Pass 2, now extract everything else. */
349         for (child_node = root->xmlChildrenNode;
350              child_node != NULL;
351              child_node = child_node->next) {
352
353                 if (lgl_xml_is_node (child_node, "Template")) {
354                         template = lgl_xml_template_parse_template_node (child_node);
355                         if (!template) {
356                                 g_object_unref (label);
357                                 *status = XML_LABEL_UNKNOWN_MEDIA;
358                                 return NULL;
359                         }
360                         lgl_db_register_template (template);
361                         gl_label_set_template (label, template, FALSE);
362                         lgl_template_free (template);
363                 } else if (lgl_xml_is_node (child_node, "Objects")) {
364                         xml_parse_objects (child_node, label);
365                 } else if (lgl_xml_is_node (child_node, "Merge")) {
366                         xml_parse_merge_fields (child_node, label);
367                 } else if (lgl_xml_is_node (child_node, "Data")) {
368                         /* Handled in pass 1. */
369                 } else {
370                         if (!xmlNodeIsText (child_node)) {
371                                 g_message ("bad node in Document node =  \"%s\"",
372                                            child_node->name);
373                                 g_object_unref (label);
374                                 *status = XML_LABEL_ERROR_OPEN_PARSE;
375                                 return NULL;
376                         }
377                 }
378         }
379
380         gl_debug (DEBUG_XML, "END");
381
382         return label;
383 }
384
385
386 /*--------------------------------------------------------------------------*/
387 /* PRIVATE.  Parse Objects node.                                            */
388 /*--------------------------------------------------------------------------*/
389 static void
390 xml_parse_objects (xmlNodePtr  node,
391                    glLabel    *label)
392 {
393         gboolean    rotate_flag;
394         xmlNodePtr  child;
395
396         gl_debug (DEBUG_XML, "START");
397
398         rotate_flag = lgl_xml_get_prop_boolean (node, "rotate", FALSE);
399         gl_label_set_rotate_flag (label, rotate_flag, FALSE);
400
401         for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
402
403                 if (lgl_xml_is_node (child, "Object-text")) {
404                         xml_parse_object_text (child, label);
405                 } else if (lgl_xml_is_node (child, "Object-box")) {
406                         xml_parse_object_box (child, label);
407                 } else if (lgl_xml_is_node (child, "Object-ellipse")) {
408                         xml_parse_object_ellipse (child, label);
409                 } else if (lgl_xml_is_node (child, "Object-line")) {
410                         xml_parse_object_line (child, label);
411                 } else if (lgl_xml_is_node (child, "Object-image")) {
412                         xml_parse_object_image (child, label);
413                 } else if (lgl_xml_is_node (child, "Object-barcode")) {
414                         xml_parse_object_barcode (child, label);
415                 } else {
416                         if (!xmlNodeIsText (child)) {
417                                 g_message ("bad node =  \"%s\"", child->name);
418                                 break;
419                         }
420                 }
421         }
422
423         gl_debug (DEBUG_XML, "END");
424 }
425
426
427 /*--------------------------------------------------------------------------*/
428 /* PRIVATE.  Parse XML Objects->Object-text Node                            */
429 /*--------------------------------------------------------------------------*/
430 static void
431 xml_parse_object_text (xmlNodePtr  node,
432                        glLabel    *label)
433 {
434         GObject          *object;
435         gdouble           x, y;
436         gdouble           w, h;
437         gchar            *string;
438         PangoAlignment    align;
439         glValignment      valign;
440         gboolean          auto_shrink;
441         xmlNodePtr        child;
442
443         gl_debug (DEBUG_XML, "START");
444
445         object = gl_label_text_new (label, FALSE);
446
447         /* position attrs */
448         x = lgl_xml_get_prop_length (node, "x", 0.0);
449         y = lgl_xml_get_prop_length (node, "y", 0.0);
450         gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y, FALSE);
451
452         /* implied size attrs */
453         w = lgl_xml_get_prop_length (node, "w", 0);
454         h = lgl_xml_get_prop_length (node, "h", 0);
455         gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h, FALSE);
456
457         /* justify attr */
458         string = lgl_xml_get_prop_string (node, "justify", NULL);
459         align = gl_str_util_string_to_align (string);
460         g_free (string);
461         gl_label_object_set_text_alignment (GL_LABEL_OBJECT(object), align, FALSE);
462
463         /* valign attr */
464         string = lgl_xml_get_prop_string (node, "valign", NULL);
465         valign = gl_str_util_string_to_valign (string);
466         g_free (string);
467         gl_label_object_set_text_valignment (GL_LABEL_OBJECT(object), valign, FALSE);
468
469         /* auto_shrink attr */
470         auto_shrink = lgl_xml_get_prop_boolean (node, "auto_shrink", FALSE);
471         gl_label_text_set_auto_shrink (GL_LABEL_TEXT(object), auto_shrink, FALSE);
472
473         /* affine attrs */
474         xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
475
476         /* shadow attrs */
477         xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
478
479         /* Process children */
480         for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
481                 if (lgl_xml_is_node (child, "Span")) {
482                         xml_parse_toplevel_span (child, GL_LABEL_OBJECT(object));
483                         break;
484                 } else {
485                         if (!xmlNodeIsText (child)) {
486                                 g_message ("Unexpected Object-text child: \"%s\"",
487                                            child->name);
488                         }
489                 }
490         }
491
492         gl_debug (DEBUG_XML, "END");
493 }
494
495
496 /*--------------------------------------------------------------------------*/
497 /* PRIVATE.  Parse XML Objects->Object-box Node                             */
498 /*--------------------------------------------------------------------------*/
499 static void
500 xml_parse_object_box (xmlNodePtr  node,
501                       glLabel    *label)
502 {
503         GObject      *object;
504         gdouble       x, y;
505         gdouble       w, h;
506         gdouble       line_width;
507         glColorNode  *line_color_node;
508         gchar        *string;
509         glColorNode  *fill_color_node;
510
511         gl_debug (DEBUG_XML, "START");
512
513         object = gl_label_box_new (label, FALSE);
514
515         /* position attrs */
516         x = lgl_xml_get_prop_length (node, "x", 0.0);
517         y = lgl_xml_get_prop_length (node, "y", 0.0);
518         gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y, FALSE);
519
520         /* size attrs */
521         w = lgl_xml_get_prop_length (node, "w", 0);
522         h = lgl_xml_get_prop_length (node, "h", 0);
523         gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h, FALSE);
524
525         /* line attrs */
526         line_width = lgl_xml_get_prop_length (node, "line_width", 1.0);
527         gl_label_object_set_line_width (GL_LABEL_OBJECT(object), line_width, FALSE);
528         
529         line_color_node = gl_color_node_new_default ();
530         string = lgl_xml_get_prop_string (node, "line_color_field", NULL);
531         if ( string ) {
532                 line_color_node->field_flag = TRUE;
533                 line_color_node->key = string;
534         } else {
535                 line_color_node->color = lgl_xml_get_prop_uint (node, "line_color", 0);
536         }
537         gl_label_object_set_line_color (GL_LABEL_OBJECT(object), line_color_node, FALSE);
538         gl_color_node_free (&line_color_node);
539
540
541         /* fill attrs */
542         fill_color_node = gl_color_node_new_default ();
543         string = lgl_xml_get_prop_string (node, "fill_color_field", NULL);
544         if ( string ) {
545                 fill_color_node->field_flag = TRUE;
546                 fill_color_node->key = string;
547         } else {
548                 fill_color_node->color = lgl_xml_get_prop_uint (node, "fill_color", 0);
549         }
550         gl_label_object_set_fill_color (GL_LABEL_OBJECT(object), fill_color_node, FALSE);
551         gl_color_node_free (&fill_color_node);
552         
553         /* affine attrs */
554         xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
555
556         /* shadow attrs */
557         xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
558
559         gl_debug (DEBUG_XML, "END");
560 }
561
562
563 /*--------------------------------------------------------------------------*/
564 /* PRIVATE.  Parse XML Objects->Object-ellipse Node                         */
565 /*--------------------------------------------------------------------------*/
566 static void
567 xml_parse_object_ellipse (xmlNodePtr  node,
568                           glLabel    *label)
569 {
570         GObject     *object;
571         gdouble      x, y;
572         gdouble      w, h;
573         gdouble      line_width;
574         glColorNode *line_color_node;
575         gchar       *string;
576         glColorNode *fill_color_node;
577
578         gl_debug (DEBUG_XML, "START");
579
580         object = gl_label_ellipse_new (label, FALSE);
581
582         /* position attrs */
583         x = lgl_xml_get_prop_length (node, "x", 0.0);
584         y = lgl_xml_get_prop_length (node, "y", 0.0);
585         gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y, FALSE);
586
587         /* size attrs */
588         w = lgl_xml_get_prop_length (node, "w", 0);
589         h = lgl_xml_get_prop_length (node, "h", 0);
590         gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h, FALSE);
591
592         /* line attrs */
593         line_width = lgl_xml_get_prop_length (node, "line_width", 1.0);
594         gl_label_object_set_line_width (GL_LABEL_OBJECT(object), line_width, FALSE);
595
596         line_color_node = gl_color_node_new_default ();
597         string = lgl_xml_get_prop_string (node, "line_color_field", NULL);
598         if ( string ) {
599                 line_color_node->field_flag = TRUE;
600                 line_color_node->key = string;
601         } else {
602                 line_color_node->color = lgl_xml_get_prop_uint (node, "line_color", 0);         
603         }
604         gl_label_object_set_line_color (GL_LABEL_OBJECT(object), line_color_node, FALSE);
605         gl_color_node_free (&line_color_node);
606
607
608         /* fill attrs */
609         fill_color_node = gl_color_node_new_default ();
610         string = lgl_xml_get_prop_string (node, "fill_color_field", NULL);
611         if ( string ) {
612                 fill_color_node->field_flag = TRUE;
613                 fill_color_node->key = string;
614         } else {
615                 fill_color_node->color = lgl_xml_get_prop_uint (node, "fill_color", 0);
616         }
617         gl_label_object_set_fill_color (GL_LABEL_OBJECT(object), fill_color_node, FALSE);
618         gl_color_node_free (&fill_color_node);
619
620         /* affine attrs */
621         xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
622
623         /* shadow attrs */
624         xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
625
626         gl_debug (DEBUG_XML, "END");
627 }
628
629
630 /*--------------------------------------------------------------------------*/
631 /* PRIVATE.  Parse XML Objects->Object-line Node                            */
632 /*--------------------------------------------------------------------------*/
633 static void
634 xml_parse_object_line (xmlNodePtr  node,
635                        glLabel    *label)
636 {
637         GObject     *object;
638         gdouble      x, y;
639         gdouble      dx, dy;
640         gdouble      line_width;
641         glColorNode *line_color_node;
642         gchar       *string;
643
644         gl_debug (DEBUG_XML, "START");
645
646         object = gl_label_line_new (label, FALSE);
647
648         /* position attrs */
649         x = lgl_xml_get_prop_length (node, "x", 0.0);
650         y = lgl_xml_get_prop_length (node, "y", 0.0);
651         gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y, FALSE);
652
653         /* length attrs */
654         dx = lgl_xml_get_prop_length (node, "dx", 0);
655         dy = lgl_xml_get_prop_length (node, "dy", 0);
656         gl_label_object_set_size (GL_LABEL_OBJECT(object), dx, dy, FALSE);
657
658         /* line attrs */
659         line_width = lgl_xml_get_prop_length (node, "line_width", 1.0);
660         gl_label_object_set_line_width (GL_LABEL_OBJECT(object), line_width, FALSE);
661         
662         line_color_node = gl_color_node_new_default ();
663         string = lgl_xml_get_prop_string (node, "line_color_field", NULL);
664         if ( string ) {
665                 line_color_node->field_flag = TRUE;
666                 line_color_node->key = string;
667         } else {
668                 line_color_node->color = lgl_xml_get_prop_uint (node, "line_color", 0);         
669         }
670         gl_label_object_set_line_color (GL_LABEL_OBJECT(object), line_color_node, FALSE);
671         gl_color_node_free (&line_color_node);
672
673         /* affine attrs */
674         xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
675
676         /* shadow attrs */
677         xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
678
679         gl_debug (DEBUG_XML, "END");
680 }
681
682
683 /*--------------------------------------------------------------------------*/
684 /* PRIVATE.  Parse XML Objects->Object-image Node                           */
685 /*--------------------------------------------------------------------------*/
686 static void
687 xml_parse_object_image (xmlNodePtr  node,
688                         glLabel    *label)
689 {
690         GObject      *object;
691         gdouble       x, y;
692         gdouble       w, h;
693         gchar        *string;
694         glTextNode   *filename;
695
696         gl_debug (DEBUG_XML, "START");
697
698         object = gl_label_image_new (label, FALSE);
699
700         /* position attrs */
701         x = lgl_xml_get_prop_length (node, "x", 0.0);
702         y = lgl_xml_get_prop_length (node, "y", 0.0);
703         gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y, FALSE);
704
705         /* src or field attr */
706         string = lgl_xml_get_prop_string (node, "src", NULL);
707         if ( string ) {
708                 filename = g_new0 (glTextNode, 1);
709                 filename->field_flag = FALSE;
710                 filename->data = g_strdup ((gchar *)string);
711                 gl_label_image_set_filename (GL_LABEL_IMAGE(object), filename, FALSE);
712                 gl_text_node_free (&filename);
713                 xmlFree (string);
714         } else {
715                 string = lgl_xml_get_prop_string (node, "field", NULL);
716                 if ( string ) {
717                         filename = g_new0 (glTextNode, 1);
718                         filename->field_flag = TRUE;
719                         filename->data = g_strdup ((gchar *)string);
720                         gl_label_image_set_filename (GL_LABEL_IMAGE(object), filename, FALSE);
721                         gl_text_node_free (&filename);
722                         xmlFree (string);
723                 } else {
724                         g_message ("Missing Object-image src or field attr");
725                 }
726         }
727
728         /* size attrs */
729         w = lgl_xml_get_prop_length (node, "w", 0);
730         h = lgl_xml_get_prop_length (node, "h", 0);
731         gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h, FALSE);
732
733         /* affine attrs */
734         xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
735
736         /* shadow attrs */
737         xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
738
739         gl_debug (DEBUG_XML, "END");
740 }
741
742
743 /*--------------------------------------------------------------------------*/
744 /* PRIVATE.  Parse XML Objects->Object-barcode Node                         */
745 /*--------------------------------------------------------------------------*/
746 static void
747 xml_parse_object_barcode (xmlNodePtr  node,
748                           glLabel    *label)
749 {
750         GObject             *object;
751         gdouble              x, y;
752         gdouble              w, h;
753         gchar               *string;
754         glTextNode          *text_node;
755         gchar               *backend_id;
756         gchar               *id;
757         glLabelBarcodeStyle *style;
758         glColorNode         *color_node;
759
760         gl_debug (DEBUG_XML, "START");
761
762         object = gl_label_barcode_new (label, FALSE);
763
764         /* position attrs */
765         x = lgl_xml_get_prop_length (node, "x", 0.0);
766         y = lgl_xml_get_prop_length (node, "y", 0.0);
767         gl_label_object_set_position (GL_LABEL_OBJECT(object), x, y, FALSE);
768
769         /* size attrs */
770         w = lgl_xml_get_prop_length (node, "w", 0);
771         h = lgl_xml_get_prop_length (node, "h", 0);
772         gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h, FALSE);
773
774         /* style attrs */
775         style = gl_label_barcode_style_new ();
776         backend_id = lgl_xml_get_prop_string (node, "backend", NULL);
777         id = lgl_xml_get_prop_string (node, "style", NULL);
778         if ( !gl_barcode_backends_is_backend_id_valid (backend_id) )
779         {
780                 if ( backend_id == NULL )
781                 {
782                         backend_id = g_strdup (gl_barcode_backends_guess_backend_id (id));
783                 }
784                 else
785                 {
786                         g_free (backend_id);
787                         backend_id = g_strdup ("built-in");
788                 }
789         }
790         gl_label_barcode_style_set_backend_id (style, backend_id);
791         gl_label_barcode_style_set_style_id (style, id);
792         style->text_flag = lgl_xml_get_prop_boolean (node, "text", FALSE);
793         style->checksum_flag = lgl_xml_get_prop_boolean (node, "checksum", TRUE);
794         style->format_digits = lgl_xml_get_prop_uint (node, "format", 10);
795         gl_label_barcode_set_style (GL_LABEL_BARCODE(object), style, FALSE);
796         g_free (backend_id);
797         g_free (id);
798         gl_label_barcode_style_free (style);
799         
800         color_node = gl_color_node_new_default ();
801         string = lgl_xml_get_prop_string (node, "color_field", NULL);
802         if ( string ) {
803                 color_node->field_flag = TRUE;
804                 color_node->key = string;
805         } else {
806                 color_node->color = lgl_xml_get_prop_uint (node, "color", 0);           
807         }
808         gl_label_object_set_line_color (GL_LABEL_OBJECT(object), color_node, FALSE);
809         gl_color_node_free (&color_node);
810
811         /* data or field attr */
812         string = lgl_xml_get_prop_string (node, "data", NULL);
813         if ( string ) {
814                 text_node = g_new0 (glTextNode, 1);
815                 text_node->field_flag = FALSE;
816                 text_node->data = string;
817                 gl_label_barcode_set_data (GL_LABEL_BARCODE(object), text_node, FALSE);
818                 gl_text_node_free (&text_node);
819         } else {
820                 string = lgl_xml_get_prop_string (node, "field", NULL);
821                 if ( string ) {
822                         text_node = g_new0 (glTextNode, 1);
823                         text_node->field_flag = TRUE;
824                         text_node->data = string;
825                         gl_label_barcode_set_data (GL_LABEL_BARCODE(object), text_node, FALSE);
826                         gl_text_node_free (&text_node);
827                 } else {
828                         g_message ("Missing Object-barcode data or field attr");
829                 }
830         }
831
832         /* affine attrs */
833         xml_parse_affine_attrs (node, GL_LABEL_OBJECT(object));
834
835         /* shadow attrs */
836         xml_parse_shadow_attrs (node, GL_LABEL_OBJECT(object));
837
838         gl_debug (DEBUG_XML, "END");
839 }
840
841
842 /*--------------------------------------------------------------------------*/
843 /* PRIVATE.  Parse XML merge fields tag.                                    */
844 /*--------------------------------------------------------------------------*/
845 static void
846 xml_parse_merge_fields (xmlNodePtr  node,
847                         glLabel    *label)
848 {
849         gchar      *string;
850         glMerge    *merge;
851
852         gl_debug (DEBUG_XML, "START");
853
854         string = lgl_xml_get_prop_string (node, "type", NULL);
855         merge = gl_merge_new (string);
856         g_free (string);
857
858         if (merge)
859         {
860                 string = lgl_xml_get_prop_string (node, "src", NULL);
861                 gl_merge_set_src (merge, string);
862                 g_free (string);
863
864                 gl_label_set_merge (label, merge, FALSE);
865
866                 g_object_unref (G_OBJECT(merge));
867         }
868
869         gl_debug (DEBUG_XML, "END");
870 }
871
872
873 /*--------------------------------------------------------------------------*/
874 /* PRIVATE.  Parse XML data tag.                                            */
875 /*--------------------------------------------------------------------------*/
876 static void
877 xml_parse_data (xmlNodePtr  node,
878                 glLabel    *label)
879 {
880         xmlNodePtr  child;
881
882         gl_debug (DEBUG_XML, "START");
883
884         for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
885
886                 if (lgl_xml_is_node (child, "Pixdata")) {
887                         xml_parse_pixdata (child, label);
888                 } else if (lgl_xml_is_node (child, "File")) {
889                         xml_parse_file_node (child, label);
890                 } else {
891                         if (!xmlNodeIsText (child)) {
892                                 g_message ("bad node in Data node =  \"%s\"",
893                                            child->name);
894                         }
895                 }
896         }
897
898         gl_debug (DEBUG_XML, "END");
899 }
900
901
902 /*--------------------------------------------------------------------------*/
903 /* PRIVATE.  Parse XML embedded Pixdata node.                               */
904 /*--------------------------------------------------------------------------*/
905 static void
906 xml_parse_pixdata (xmlNodePtr  node,
907                    glLabel    *label)
908 {
909         gchar      *name, *base64;
910         guchar     *stream;
911         gsize       stream_length;
912         gboolean    ret;
913         GdkPixdata *pixdata;
914         GdkPixbuf  *pixbuf;
915         GHashTable *pixbuf_cache;
916
917         gl_debug (DEBUG_XML, "START");
918
919         name = lgl_xml_get_prop_string (node, "name", NULL);
920         base64 = lgl_xml_get_node_content (node);
921
922         stream = g_base64_decode ((gchar *)base64, &stream_length);
923         pixdata = g_new0 (GdkPixdata, 1);
924         ret = gdk_pixdata_deserialize (pixdata, stream_length, stream, NULL);
925
926         if (ret) {
927                 pixbuf = gdk_pixbuf_from_pixdata (pixdata, TRUE, NULL);
928
929                 pixbuf_cache = gl_label_get_pixbuf_cache (label);
930                 gl_pixbuf_cache_add_pixbuf (pixbuf_cache, (gchar *)name, pixbuf);
931         }
932
933         g_free (name);
934         g_free (base64);
935
936         g_free (stream);
937         g_free (pixdata);
938
939         gl_debug (DEBUG_XML, "END");
940 }
941
942
943 /*--------------------------------------------------------------------------*/
944 /* PRIVATE.  Parse XML embedded File node.                                  */
945 /*--------------------------------------------------------------------------*/
946 static void
947 xml_parse_file_node (xmlNodePtr  node,
948                      glLabel    *label)
949 {
950         gchar      *name, *format;
951         gchar      *content;
952         GHashTable *svg_cache;
953
954         name    = lgl_xml_get_prop_string (node, "name", NULL);
955         format  = lgl_xml_get_prop_string (node, "format", NULL);
956
957         if ( format && (lgl_str_utf8_casecmp (format, "SVG") == 0) )
958         {
959                 content = lgl_xml_get_node_content (node);
960
961                 svg_cache = gl_label_get_svg_cache (label);
962                 gl_svg_cache_add_svg (svg_cache, name, content);
963
964                 g_free (content);
965         }
966         else
967         {
968                 g_message ("Unknown embedded file format: \"%s\"", format);
969                 
970         }
971
972         g_free (name);
973         g_free (format);
974 }
975
976
977 /*--------------------------------------------------------------------------*/
978 /* PRIVATE.  Parse top-level Span tag.                                      */
979 /*--------------------------------------------------------------------------*/
980 static void
981 xml_parse_toplevel_span  (xmlNodePtr        node,
982                           glLabelObject    *object)
983 {
984         gchar            *font_family;
985         gdouble           font_size;
986         PangoWeight       font_weight;
987         gboolean          font_italic_flag;
988         glColorNode      *color_node;
989         gdouble           text_line_spacing;
990         gchar            *string;
991         GList            *lines, *text_nodes;
992         xmlNodePtr        child;
993         glTextNode       *text_node;
994         GRegex                                   *strip_regex;
995
996         gl_debug (DEBUG_XML, "START");
997
998         /* Font family attr */
999         font_family = lgl_xml_get_prop_string (node, "font_family", "Sans");
1000         gl_label_object_set_font_family (object, font_family, FALSE);
1001         g_free (font_family);
1002
1003         /* Font size attr */
1004         font_size = lgl_xml_get_prop_double (node, "font_size", 0.0);
1005         gl_label_object_set_font_size (object, font_size, FALSE);
1006
1007         /* Font weight attr */
1008         string = lgl_xml_get_prop_string (node, "font_weight", NULL);
1009         font_weight = gl_str_util_string_to_weight (string);
1010         g_free (string);
1011         gl_label_object_set_font_weight (object, font_weight, FALSE);
1012
1013         /* Font italic flag attr */
1014         font_italic_flag = lgl_xml_get_prop_boolean (node, "font_italic", FALSE);
1015         gl_label_object_set_font_italic_flag (object, font_italic_flag, FALSE);
1016
1017         /* Text color attr */
1018         color_node = gl_color_node_new_default ();
1019         string = lgl_xml_get_prop_string (node, "color_field", NULL);
1020         if ( string ) {
1021                 color_node->field_flag = TRUE;
1022                 color_node->key = string;
1023         } else {
1024                 color_node->color = lgl_xml_get_prop_uint (node, "color", 0);           
1025         }
1026         gl_label_object_set_text_color (object, color_node, FALSE);
1027         gl_color_node_free (&color_node);
1028         
1029         /* Text line spacing attr  */
1030         text_line_spacing = lgl_xml_get_prop_double (node, "line_spacing", 1.0);
1031         gl_label_object_set_text_line_spacing (object, text_line_spacing, FALSE); 
1032
1033         /* Now descend children, and build lines of text nodes */
1034         lines = NULL;
1035         text_nodes = NULL;
1036         strip_regex = g_regex_new("\\A\\n\\s*|\\n\\s*\\Z", 0, 0, NULL);
1037         for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
1038
1039                 if (lgl_xml_is_node (child, "Span")) {
1040
1041                         g_message ("Unexpected rich text (not supported, yet!)");
1042
1043                 } else if (lgl_xml_is_node (child, "Field")) {
1044
1045                         /* Field node */
1046                         string = lgl_xml_get_prop_string (child, "name", NULL);
1047                         text_node = g_new0 (glTextNode, 1);
1048                         text_node->field_flag = TRUE;
1049                         text_node->data = string;
1050                         text_nodes = g_list_append (text_nodes, text_node);
1051
1052                 } else if (lgl_xml_is_node (child, "NL")) {
1053
1054                         /* Store line. */
1055                         lines = g_list_append (lines, text_nodes);
1056                         text_nodes = NULL;
1057
1058     } else if (xmlNodeIsText (child)) {
1059                         gchar *orig_data = lgl_xml_get_node_content (child); 
1060                         gchar *data;
1061
1062                         /* Literal text */
1063
1064                         /* Stip out white space before and after */
1065                         data = g_regex_replace(strip_regex, orig_data, -1, 0, "", 0, NULL);
1066                         g_free (orig_data);
1067
1068                         text_node = g_new0 (glTextNode, 1);
1069                         text_node->field_flag = FALSE;
1070                         text_node->data = g_strdup ((gchar *)data);
1071                         text_nodes = g_list_append (text_nodes, text_node);
1072
1073                         g_free (data);
1074
1075                 } else {
1076                         g_message ("Unexpected Span child: \"%s\"", child->name);
1077                 }
1078
1079         }
1080   g_free (strip_regex);
1081         if ( text_nodes ) {
1082                 /* Store last line. */
1083                 lines = g_list_append (lines, text_nodes);
1084                 text_nodes = NULL;
1085         }
1086         gl_label_text_set_lines (GL_LABEL_TEXT(object), lines, FALSE);
1087         gl_text_node_lines_free (&lines);
1088
1089         gl_debug (DEBUG_XML, "END");
1090 }
1091
1092
1093 /*--------------------------------------------------------------------------*/
1094 /* PRIVATE.  Parse affine attributes.                                       */
1095 /*--------------------------------------------------------------------------*/
1096 static void
1097 xml_parse_affine_attrs (xmlNodePtr        node,
1098                         glLabelObject    *object)
1099 {
1100         gdouble           a[6];
1101         cairo_matrix_t    matrix;
1102
1103         a[0] = lgl_xml_get_prop_double (node, "a0", 0.0);
1104         a[1] = lgl_xml_get_prop_double (node, "a1", 0.0);
1105         a[2] = lgl_xml_get_prop_double (node, "a2", 0.0);
1106         a[3] = lgl_xml_get_prop_double (node, "a3", 0.0);
1107         a[4] = lgl_xml_get_prop_double (node, "a4", 0.0);
1108         a[5] = lgl_xml_get_prop_double (node, "a5", 0.0);
1109
1110         cairo_matrix_init (&matrix, a[0], a[1], a[2], a[3], a[4], a[5]);
1111
1112         gl_label_object_set_matrix (object, &matrix);
1113 }
1114
1115
1116 /*--------------------------------------------------------------------------*/
1117 /* PRIVATE.  Parse shadow attributes.                                       */
1118 /*--------------------------------------------------------------------------*/
1119 static void
1120 xml_parse_shadow_attrs (xmlNodePtr        node,
1121                         glLabelObject    *object)
1122 {
1123         gboolean         shadow_state;
1124         gdouble          shadow_x;
1125         gdouble          shadow_y;
1126         glColorNode     *shadow_color_node;
1127         gdouble          shadow_opacity;
1128         gchar           *string;
1129
1130         shadow_state = lgl_xml_get_prop_boolean (node, "shadow", FALSE);
1131         gl_label_object_set_shadow_state (object, shadow_state, FALSE);
1132
1133         if (shadow_state)
1134         {
1135                 shadow_x = lgl_xml_get_prop_length (node, "shadow_x", 0.0);
1136                 shadow_y = lgl_xml_get_prop_length (node, "shadow_y", 0.0);
1137                 gl_label_object_set_shadow_offset (object, shadow_x, shadow_y, FALSE);
1138                 
1139                 shadow_color_node = gl_color_node_new_default ();
1140                 string = lgl_xml_get_prop_string (node, "shadow_color_field", NULL);
1141                 if ( string ) {
1142                         shadow_color_node->field_flag = TRUE;
1143                         shadow_color_node->key = string;
1144                 } else {
1145                         shadow_color_node->color = lgl_xml_get_prop_uint (node, "shadow_color", 0);             
1146                 }
1147                 gl_label_object_set_shadow_color (object, shadow_color_node, FALSE);
1148                 gl_color_node_free (&shadow_color_node);
1149
1150                 shadow_opacity = lgl_xml_get_prop_double (node, "shadow_opacity", 1.0);
1151                 gl_label_object_set_shadow_opacity (object, shadow_opacity, FALSE);
1152         }
1153 }
1154
1155
1156 /****************************************************************************/
1157 /* Save label to xml label file.                                            */
1158 /****************************************************************************/
1159 void
1160 gl_xml_label_save (glLabel          *label,
1161                    const gchar      *utf8_filename,
1162                    glXMLLabelStatus *status)
1163 {
1164         xmlDocPtr doc;
1165         gint      xml_ret;
1166         gchar     *filename;
1167
1168         gl_debug (DEBUG_XML, "START");
1169
1170         doc = xml_label_to_doc (label, status);
1171
1172         filename = g_filename_from_utf8 (utf8_filename, -1, NULL, NULL, NULL);
1173         if (!filename)
1174                 g_message ("Utf8 conversion error.");
1175         else {
1176                 xmlSetDocCompressMode (doc, gl_label_get_compression (label));
1177                 xml_ret = xmlSaveFormatFile (filename, doc, TRUE);
1178                 xmlFreeDoc (doc);
1179                 if (xml_ret == -1) {
1180
1181                         g_message ("Problem saving xml file.");
1182                         *status = XML_LABEL_ERROR_SAVE_FILE;
1183
1184                 } else {
1185
1186                         gl_label_set_filename (label, utf8_filename);
1187                         gl_label_clear_modified (label);
1188
1189                 }
1190                 g_free (filename);
1191         }
1192
1193         gl_debug (DEBUG_XML, "END");
1194 }
1195
1196
1197 /****************************************************************************/
1198 /* Save label to xml buffer.                                                */
1199 /****************************************************************************/
1200 gchar *
1201 gl_xml_label_save_buffer (glLabel          *label,
1202                           glXMLLabelStatus *status)
1203 {
1204         xmlDocPtr  doc;
1205         gint       size;
1206         guchar    *buffer;
1207
1208         gl_debug (DEBUG_XML, "START");
1209
1210         doc = xml_label_to_doc (label, status);
1211
1212         xmlDocDumpMemory (doc, &buffer, &size);
1213         xmlFreeDoc (doc);
1214
1215         gl_label_clear_modified (label);
1216
1217         gl_debug (DEBUG_XML, "END");
1218
1219         return (gchar *)buffer;
1220 }
1221
1222
1223 /*--------------------------------------------------------------------------*/
1224 /* PRIVATE.  Convert label to xml doc structure.                            */
1225 /*--------------------------------------------------------------------------*/
1226 static xmlDocPtr
1227 xml_label_to_doc (glLabel          *label,
1228                   glXMLLabelStatus *status)
1229 {
1230         lglUnits           units;
1231         xmlDocPtr          doc;
1232         xmlNsPtr           ns;
1233         const lglTemplate *template;
1234         glMerge           *merge;
1235
1236         gl_debug (DEBUG_XML, "START");
1237
1238         LIBXML_TEST_VERSION;
1239
1240         units = gl_prefs_model_get_units (gl_prefs);
1241         lgl_xml_set_default_units (units);
1242
1243         doc = xmlNewDoc ((xmlChar *)"1.0");
1244         doc->xmlRootNode = xmlNewDocNode (doc, NULL, (xmlChar *)"Glabels-document", NULL);
1245
1246         ns = xmlNewNs (doc->xmlRootNode, (xmlChar *)LGL_XML_NAME_SPACE, NULL);
1247         xmlSetNs (doc->xmlRootNode, ns);
1248
1249         template = gl_label_get_template (label);
1250         lgl_xml_template_create_template_node (template, doc->xmlRootNode, ns);
1251
1252         xml_create_objects (doc->xmlRootNode, ns, label);
1253
1254         merge = gl_label_get_merge (label);
1255         gl_debug (DEBUG_XML, "merge=%p", merge);
1256         if (merge != NULL) {
1257                 xml_create_merge_fields (doc->xmlRootNode, ns, label);
1258                 g_object_unref (G_OBJECT(merge));
1259         }
1260
1261         xml_create_data (doc, doc->xmlRootNode, ns, label);
1262
1263         gl_debug (DEBUG_XML, "END");
1264
1265         *status = XML_LABEL_OK;
1266         return doc;
1267 }
1268
1269
1270 /*--------------------------------------------------------------------------*/
1271 /* PRIVATE.  Add XML Objects Node                                           */
1272 /*--------------------------------------------------------------------------*/
1273 static void
1274 xml_create_objects (xmlNodePtr  parent,
1275                     xmlNsPtr    ns,
1276                     glLabel    *label)
1277 {
1278         xmlNodePtr     node;
1279         gboolean       rotate_flag;
1280         const GList   *object_list;
1281         GList         *p;
1282         glLabelObject *object;
1283
1284         gl_debug (DEBUG_XML, "START");
1285
1286         rotate_flag = gl_label_get_rotate_flag (label);
1287         object_list = gl_label_get_object_list (label);
1288
1289         node = xmlNewChild (parent, ns, (xmlChar *)"Objects", NULL);
1290         lgl_xml_set_prop_string (node, "id", "0");
1291         lgl_xml_set_prop_boolean (node, "rotate", rotate_flag);
1292
1293         for (p = (GList *)object_list; p != NULL; p = p->next) {
1294
1295                 object = GL_LABEL_OBJECT(p->data);
1296
1297                 if ( GL_IS_LABEL_TEXT(object) ) {
1298                         xml_create_object_text (node, ns, object);
1299                 } else if ( GL_IS_LABEL_BOX(object) ) {
1300                         xml_create_object_box (node, ns, object);
1301                 } else if ( GL_IS_LABEL_ELLIPSE(object) ) {
1302                         xml_create_object_ellipse (node, ns, object);
1303                 } else if ( GL_IS_LABEL_LINE(object) ) {
1304                         xml_create_object_line (node, ns, object);
1305                 } else if ( GL_IS_LABEL_IMAGE(object) ) {
1306                         xml_create_object_image (node, ns, object);
1307                 } else if ( GL_IS_LABEL_BARCODE(object) ) {
1308                         xml_create_object_barcode (node, ns, object);
1309                 } else {
1310                         g_message ("Unknown label object");
1311                 }
1312
1313         }
1314
1315         gl_debug (DEBUG_XML, "END");
1316 }
1317
1318
1319 /*--------------------------------------------------------------------------*/
1320 /* PRIVATE.  Add XML Objects->Object-text Node                              */
1321 /*--------------------------------------------------------------------------*/
1322 static void
1323 xml_create_object_text (xmlNodePtr     parent,
1324                         xmlNsPtr       ns,
1325                         glLabelObject *object)
1326 {
1327         xmlNodePtr        node;
1328         gdouble           x, y;
1329         gdouble           w, h;
1330         PangoAlignment    align;
1331         glValignment      valign;
1332         gboolean          auto_shrink;
1333
1334         gl_debug (DEBUG_XML, "START");
1335
1336         node = xmlNewChild (parent, ns, (xmlChar *)"Object-text", NULL);
1337
1338         /* position attrs */
1339         gl_label_object_get_position (object, &x, &y);
1340         lgl_xml_set_prop_length (node, "x", x);
1341         lgl_xml_set_prop_length (node, "y", y);
1342
1343         /* size attrs */
1344         gl_label_object_get_raw_size ( object, &w, &h);
1345         lgl_xml_set_prop_length (node, "w", w);
1346         lgl_xml_set_prop_length (node, "h", h);
1347
1348         /* justify attr */
1349         align = gl_label_object_get_text_alignment (object);
1350         lgl_xml_set_prop_string (node, "justify", gl_str_util_align_to_string (align));
1351
1352         /* valign attr */
1353         valign = gl_label_object_get_text_valignment (object);
1354         lgl_xml_set_prop_string (node, "valign", gl_str_util_valign_to_string (valign));
1355
1356         /* auto_shrink attr */
1357         auto_shrink = gl_label_text_get_auto_shrink (GL_LABEL_TEXT (object));
1358         lgl_xml_set_prop_boolean (node, "auto_shrink", auto_shrink);
1359
1360         /* affine attrs */
1361         xml_create_affine_attrs (node, object);
1362
1363         /* shadow attrs */
1364         xml_create_shadow_attrs (node, object);
1365
1366         /* Add children */
1367         xml_create_toplevel_span (node, ns, GL_LABEL_TEXT(object));
1368
1369         gl_debug (DEBUG_XML, "END");
1370 }
1371
1372
1373 /*--------------------------------------------------------------------------*/
1374 /* PRIVATE.  Add XML Objects->Object-box Node                               */
1375 /*--------------------------------------------------------------------------*/
1376 static void
1377 xml_create_object_box (xmlNodePtr     parent,
1378                        xmlNsPtr       ns,
1379                        glLabelObject *object)
1380 {
1381         xmlNodePtr        node;
1382         gdouble           x, y;
1383         gdouble           w, h;
1384         gdouble           line_width;
1385         glColorNode      *line_color_node;
1386         glColorNode *fill_color_node;
1387
1388         gl_debug (DEBUG_XML, "START");
1389
1390         node = xmlNewChild (parent, ns, (xmlChar *)"Object-box", NULL);
1391
1392         /* position attrs */
1393         gl_label_object_get_position (object, &x, &y);
1394         lgl_xml_set_prop_length (node, "x", x);
1395         lgl_xml_set_prop_length (node, "y", y);
1396
1397         /* size attrs */
1398         gl_label_object_get_size (object, &w, &h);
1399         lgl_xml_set_prop_length (node, "w", w);
1400         lgl_xml_set_prop_length (node, "h", h);
1401
1402         /* line attrs */
1403         line_width = gl_label_object_get_line_width (GL_LABEL_OBJECT(object));
1404         lgl_xml_set_prop_length (node, "line_width", line_width);
1405         
1406         line_color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
1407         if (line_color_node->field_flag)
1408         {
1409                 lgl_xml_set_prop_string (node, "line_color_field", line_color_node->key);
1410         }
1411         else
1412         {
1413                 lgl_xml_set_prop_uint_hex (node, "line_color", line_color_node->color);
1414         }
1415         gl_color_node_free (&line_color_node);
1416
1417         /* fill attrs (color or field) */
1418         fill_color_node = gl_label_object_get_fill_color (GL_LABEL_OBJECT(object));
1419         if (fill_color_node->field_flag)
1420         {
1421                 lgl_xml_set_prop_string (node, "fill_color_field", fill_color_node->key);
1422         }
1423         else
1424         {
1425                 lgl_xml_set_prop_uint_hex (node, "fill_color", fill_color_node->color);
1426         }
1427         gl_color_node_free (&fill_color_node);
1428
1429         /* affine attrs */
1430         xml_create_affine_attrs (node, object);
1431
1432         /* shadow attrs */
1433         xml_create_shadow_attrs (node, object);
1434
1435         gl_debug (DEBUG_XML, "END");
1436 }
1437
1438
1439 /*--------------------------------------------------------------------------*/
1440 /* PRIVATE.  Add XML Objects->Object-ellipse Node                           */
1441 /*--------------------------------------------------------------------------*/
1442 static void
1443 xml_create_object_ellipse (xmlNodePtr     parent,
1444                            xmlNsPtr       ns,
1445                            glLabelObject *object)
1446 {
1447         xmlNodePtr        node;
1448         gdouble           x, y;
1449         gdouble           w, h;
1450         gdouble           line_width;
1451         glColorNode      *line_color_node;
1452         glColorNode *fill_color_node;
1453
1454         gl_debug (DEBUG_XML, "START");
1455
1456         node = xmlNewChild (parent, ns, (xmlChar *)"Object-ellipse", NULL);
1457
1458         /* position attrs */
1459         gl_label_object_get_position (object, &x, &y);
1460         lgl_xml_set_prop_length (node, "x", x);
1461         lgl_xml_set_prop_length (node, "y", y);
1462
1463         /* size attrs */
1464         gl_label_object_get_size (object, &w, &h);
1465         lgl_xml_set_prop_length (node, "w", w);
1466         lgl_xml_set_prop_length (node, "h", h);
1467
1468         /* line attrs */
1469         line_width = gl_label_object_get_line_width (GL_LABEL_OBJECT(object));
1470         lgl_xml_set_prop_length (node, "line_width", line_width);
1471         
1472         line_color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
1473         if (line_color_node->field_flag)
1474         {
1475                 lgl_xml_set_prop_string (node, "line_color_field", line_color_node->key);
1476         }
1477         else
1478         {
1479                 lgl_xml_set_prop_uint_hex (node, "line_color", line_color_node->color);
1480         }
1481         gl_color_node_free (&line_color_node);
1482
1483
1484         /* fill attrs (color or field) */
1485         fill_color_node = gl_label_object_get_fill_color (GL_LABEL_OBJECT(object));
1486         if (fill_color_node->field_flag)
1487         {
1488                 lgl_xml_set_prop_string (node, "fill_color_field", fill_color_node->key);
1489         }
1490         else
1491         {
1492                 lgl_xml_set_prop_uint_hex (node, "fill_color", fill_color_node->color);
1493         }
1494         gl_color_node_free (&fill_color_node);
1495
1496         /* affine attrs */
1497         xml_create_affine_attrs (node, object);
1498
1499         /* shadow attrs */
1500         xml_create_shadow_attrs (node, object);
1501
1502         gl_debug (DEBUG_XML, "END");
1503 }
1504
1505
1506 /*--------------------------------------------------------------------------*/
1507 /* PRIVATE.  Add XML Objects->Object-line Node                              */
1508 /*--------------------------------------------------------------------------*/
1509 static void
1510 xml_create_object_line (xmlNodePtr     parent,
1511                         xmlNsPtr       ns,
1512                         glLabelObject *object)
1513 {
1514         xmlNodePtr        node;
1515         gdouble           x, y;
1516         gdouble           dx, dy;
1517         gdouble           line_width;
1518         glColorNode      *line_color_node;
1519
1520         gl_debug (DEBUG_XML, "START");
1521
1522         node = xmlNewChild (parent, ns, (xmlChar *)"Object-line", NULL);
1523
1524         /* position attrs */
1525         gl_label_object_get_position (object, &x, &y);
1526         lgl_xml_set_prop_length (node, "x", x);
1527         lgl_xml_set_prop_length (node, "y", y);
1528
1529         /* length attrs */
1530         gl_label_object_get_size (object, &dx, &dy);
1531         lgl_xml_set_prop_length (node, "dx", dx);
1532         lgl_xml_set_prop_length (node, "dy", dy);
1533
1534         /* line attrs */
1535         line_width = gl_label_object_get_line_width (GL_LABEL_OBJECT(object));
1536         lgl_xml_set_prop_length (node, "line_width", line_width);
1537         
1538         line_color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
1539         if (line_color_node->field_flag)
1540         {
1541                 lgl_xml_set_prop_string (node, "line_color_field", line_color_node->key);
1542         }
1543         else
1544         {
1545                 lgl_xml_set_prop_uint_hex (node, "line_color", line_color_node->color);
1546         }
1547         gl_color_node_free (&line_color_node);
1548
1549
1550         /* affine attrs */
1551         xml_create_affine_attrs (node, object);
1552
1553         /* shadow attrs */
1554         xml_create_shadow_attrs (node, object);
1555
1556         gl_debug (DEBUG_XML, "END");
1557 }
1558
1559
1560 /*--------------------------------------------------------------------------*/
1561 /* PRIVATE.  Add XML Objects->Object-image Node                             */
1562 /*--------------------------------------------------------------------------*/
1563 static void
1564 xml_create_object_image (xmlNodePtr     parent,
1565                          xmlNsPtr       ns,
1566                          glLabelObject *object)
1567 {
1568         xmlNodePtr        node;
1569         gdouble           x, y;
1570         gdouble           w, h;
1571         glTextNode       *filename;
1572
1573         gl_debug (DEBUG_XML, "START");
1574
1575         node = xmlNewChild (parent, ns, (xmlChar *)"Object-image", NULL);
1576
1577         /* position attrs */
1578         gl_label_object_get_position (object, &x, &y);
1579         lgl_xml_set_prop_length (node, "x", x);
1580         lgl_xml_set_prop_length (node, "y", y);
1581
1582         /* size attrs */
1583         gl_label_object_get_size (object, &w, &h);
1584         lgl_xml_set_prop_length (node, "w", w);
1585         lgl_xml_set_prop_length (node, "h", h);
1586
1587         /* src OR field attr */
1588         filename = gl_label_image_get_filename (GL_LABEL_IMAGE(object));
1589         if (filename->field_flag) {
1590                 lgl_xml_set_prop_string (node, "field", filename->data);
1591         } else {
1592                 lgl_xml_set_prop_string (node, "src", filename->data);
1593         }
1594         gl_text_node_free (&filename);
1595
1596         /* affine attrs */
1597         xml_create_affine_attrs (node, object);
1598
1599         /* shadow attrs */
1600         xml_create_shadow_attrs (node, object);
1601
1602         gl_debug (DEBUG_XML, "END");
1603 }
1604
1605
1606 /*--------------------------------------------------------------------------*/
1607 /* PRIVATE.  Add XML Objects->Object-barcode Node                           */
1608 /*--------------------------------------------------------------------------*/
1609 static void
1610 xml_create_object_barcode (xmlNodePtr     parent,
1611                            xmlNsPtr       ns,
1612                            glLabelObject *object)
1613 {
1614         xmlNodePtr           node;
1615         gdouble              x, y;
1616         gdouble              w, h;
1617         glTextNode          *text_node;
1618         glLabelBarcodeStyle *style;
1619         glColorNode         *color_node;
1620
1621         gl_debug (DEBUG_XML, "START");
1622
1623         node = xmlNewChild (parent, ns, (xmlChar *)"Object-barcode", NULL);
1624
1625         /* position attrs */
1626         gl_label_object_get_position (object, &x, &y);
1627         lgl_xml_set_prop_length (node, "x", x);
1628         lgl_xml_set_prop_length (node, "y", y);
1629
1630         /* size attrs */
1631         gl_label_object_get_raw_size (object, &w, &h);
1632         lgl_xml_set_prop_length (node, "w", w);
1633         lgl_xml_set_prop_length (node, "h", h);
1634
1635         /* Barcode properties attrs */
1636         style = gl_label_barcode_get_style (GL_LABEL_BARCODE(object));
1637         lgl_xml_set_prop_string (node, "backend", style->backend_id);
1638         lgl_xml_set_prop_string (node, "style", style->id);
1639         lgl_xml_set_prop_boolean (node, "text", style->text_flag);
1640         lgl_xml_set_prop_boolean (node, "checksum", style->checksum_flag);
1641         
1642         color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
1643         if (color_node->field_flag)
1644         {
1645                 lgl_xml_set_prop_string (node, "color_field", color_node->key);
1646         }
1647         else
1648         {
1649                 lgl_xml_set_prop_uint_hex (node, "color", color_node->color);
1650         }
1651         gl_color_node_free (&color_node);
1652
1653
1654         /* data OR field attr */
1655         text_node = gl_label_barcode_get_data (GL_LABEL_BARCODE(object));
1656         if (text_node->field_flag) {
1657                 lgl_xml_set_prop_string (node, "field", text_node->data);
1658                 lgl_xml_set_prop_int (node, "format", style->format_digits);
1659         } else {
1660                 lgl_xml_set_prop_string (node, "data", text_node->data);
1661         }
1662         gl_text_node_free (&text_node);
1663
1664         /* affine attrs */
1665         xml_create_affine_attrs (node, object);
1666
1667         /* shadow attrs */
1668         xml_create_shadow_attrs (node, object);
1669
1670         gl_label_barcode_style_free (style);
1671
1672         gl_debug (DEBUG_XML, "END");
1673 }
1674
1675
1676 /*--------------------------------------------------------------------------*/
1677 /* PRIVATE.  Add XML Label Merge Fields Node                                */
1678 /*--------------------------------------------------------------------------*/
1679 static void
1680 xml_create_merge_fields (xmlNodePtr  parent,
1681                          xmlNsPtr    ns,
1682                          glLabel    *label)
1683 {
1684         xmlNodePtr  node;
1685         gchar      *string;
1686         glMerge    *merge;
1687
1688         gl_debug (DEBUG_XML, "START");
1689
1690         merge = gl_label_get_merge (label);
1691
1692         node = xmlNewChild (parent, ns, (xmlChar *)"Merge", NULL);
1693
1694         string = gl_merge_get_name (merge);
1695         lgl_xml_set_prop_string (node, "type", string);
1696         g_free (string);
1697
1698         string = gl_merge_get_src (merge);
1699         lgl_xml_set_prop_string (node, "src", string);
1700         g_free (string);
1701
1702         g_object_unref (G_OBJECT(merge));
1703
1704         gl_debug (DEBUG_XML, "END");
1705 }
1706
1707
1708 /*--------------------------------------------------------------------------*/
1709 /* PRIVATE.  Add XML Label Data Node                                        */
1710 /*--------------------------------------------------------------------------*/
1711 static void
1712 xml_create_data (xmlDocPtr   doc,
1713                  xmlNodePtr  parent,
1714                  xmlNsPtr    ns,
1715                  glLabel    *label)
1716 {
1717         xmlNodePtr  node;
1718         GHashTable *cache;
1719         GList      *name_list, *p;
1720
1721         gl_debug (DEBUG_XML, "START");
1722
1723         node = xmlNewChild (parent, ns, (xmlChar *)"Data", NULL);
1724
1725         cache = gl_label_get_pixbuf_cache (label);
1726         name_list = gl_pixbuf_cache_get_name_list (cache);
1727
1728         for (p = name_list; p != NULL; p=p->next) {
1729                 xml_create_pixdata (node, ns, label, p->data);
1730         }
1731
1732         gl_pixbuf_cache_free_name_list (name_list);
1733
1734
1735         cache = gl_label_get_svg_cache (label);
1736         name_list = gl_svg_cache_get_name_list (cache);
1737
1738         for (p = name_list; p != NULL; p=p->next) {
1739                 xml_create_file_svg (doc, node, ns, label, p->data);
1740         }
1741
1742         gl_pixbuf_cache_free_name_list (name_list);
1743
1744
1745         gl_debug (DEBUG_XML, "END");
1746 }
1747
1748
1749 /*--------------------------------------------------------------------------*/
1750 /* PRIVATE.  Add XML Label Data embedded Pixdata Node                       */
1751 /*--------------------------------------------------------------------------*/
1752 static void
1753 xml_create_pixdata (xmlNodePtr  parent,
1754                     xmlNsPtr    ns,
1755                     glLabel    *label,
1756                     gchar      *name)
1757 {
1758         xmlNodePtr  node;
1759         GHashTable *pixbuf_cache;
1760         GdkPixbuf  *pixbuf;
1761         GdkPixdata *pixdata;
1762         guchar     *stream;
1763         guint       stream_length;
1764         gchar      *base64;
1765
1766         gl_debug (DEBUG_XML, "START");
1767
1768         pixbuf_cache = gl_label_get_pixbuf_cache (label);
1769
1770         pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, name);
1771         if ( pixbuf != NULL ) {
1772
1773                 pixdata = g_new0 (GdkPixdata, 1);
1774                 gdk_pixdata_from_pixbuf (pixdata, pixbuf, FALSE);
1775                 stream = gdk_pixdata_serialize (pixdata, &stream_length);
1776                 base64 = g_base64_encode (stream, stream_length);
1777
1778                 node = xmlNewChild (parent, ns, (xmlChar *)"Pixdata", (xmlChar *)base64);
1779                 lgl_xml_set_prop_string (node, "name", name);
1780                 lgl_xml_set_prop_string (node, "encoding", "Base64");
1781
1782                 gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, name);
1783
1784                 g_free (pixdata);
1785                 g_free (stream);
1786                 g_free (base64);
1787         }
1788
1789
1790         gl_debug (DEBUG_XML, "END");
1791 }
1792
1793
1794 /*--------------------------------------------------------------------------*/
1795 /* PRIVATE.  Add XML Label Data embedded SVG file Node                      */
1796 /*--------------------------------------------------------------------------*/
1797 static void
1798 xml_create_file_svg (xmlDocPtr   doc,
1799                      xmlNodePtr  parent,
1800                      xmlNsPtr    ns,
1801                      glLabel    *label,
1802                      gchar      *name)
1803 {
1804         xmlNodePtr  node;
1805         xmlNodePtr  cdata_section_node;
1806         GHashTable *svg_cache;
1807         gchar      *svg_data;
1808
1809         gl_debug (DEBUG_XML, "START");
1810
1811         svg_cache = gl_label_get_svg_cache (label);
1812
1813         svg_data = gl_svg_cache_get_contents (svg_cache, name);
1814         if ( svg_data != NULL ) {
1815
1816                 node = xmlNewChild (parent, ns, (xmlChar *)"File", NULL);
1817                 lgl_xml_set_prop_string (node, "name", name);
1818                 lgl_xml_set_prop_string (node, "format", "SVG");
1819
1820                 cdata_section_node = xmlNewCDataBlock (doc, (xmlChar *)svg_data, strlen (svg_data));
1821                 xmlAddChild (node, cdata_section_node);
1822
1823                 g_free (svg_data);
1824         }
1825
1826
1827         gl_debug (DEBUG_XML, "END");
1828 }
1829
1830
1831 /*--------------------------------------------------------------------------*/
1832 /* PRIVATE.  Create top-level Span node.                                    */
1833 /*--------------------------------------------------------------------------*/
1834 static void
1835 xml_create_toplevel_span (xmlNodePtr        parent,
1836                           xmlNsPtr          ns,
1837                           glLabelText      *object_text)
1838 {
1839         xmlNodePtr        node;
1840         gchar            *font_family;
1841         gdouble           font_size;
1842         PangoWeight       font_weight;
1843         gboolean          font_italic_flag;
1844         glColorNode      *color_node;
1845         gdouble           text_line_spacing;
1846         GList            *lines, *p_line, *p_node;
1847         glTextNode       *text_node;
1848         xmlNodePtr        child;
1849
1850         node = xmlNewChild (parent, ns, (xmlChar *)"Span", NULL);
1851
1852         /* All span attrs at top level. */
1853         font_family = gl_label_object_get_font_family (GL_LABEL_OBJECT(object_text));
1854         font_size = gl_label_object_get_font_size (GL_LABEL_OBJECT(object_text));
1855         text_line_spacing = gl_label_object_get_text_line_spacing (GL_LABEL_OBJECT(object_text));
1856         font_weight = gl_label_object_get_font_weight (GL_LABEL_OBJECT(object_text));
1857         font_italic_flag = gl_label_object_get_font_italic_flag (GL_LABEL_OBJECT(object_text));
1858         
1859         color_node = gl_label_object_get_text_color (GL_LABEL_OBJECT(object_text));
1860         if (color_node->field_flag)
1861         {
1862                 lgl_xml_set_prop_string (node, "color_field", color_node->key);
1863         }
1864         else
1865         {
1866                 lgl_xml_set_prop_uint_hex (node, "color", color_node->color);
1867         }
1868         gl_color_node_free (&color_node);
1869         
1870         lgl_xml_set_prop_string (node, "font_family", font_family);
1871         lgl_xml_set_prop_double (node, "font_size", font_size);
1872         lgl_xml_set_prop_string (node, "font_weight", gl_str_util_weight_to_string (font_weight));
1873         lgl_xml_set_prop_boolean (node, "font_italic", font_italic_flag);
1874         
1875         lgl_xml_set_prop_double (node, "line_spacing", text_line_spacing);
1876
1877         /* Build children. */
1878         lines = gl_label_text_get_lines (GL_LABEL_TEXT(object_text));
1879         for (p_line = lines; p_line != NULL; p_line = p_line->next) {
1880
1881                 for (p_node = (GList *) p_line->data; p_node != NULL;
1882                      p_node = p_node->next) {
1883                         text_node = (glTextNode *) p_node->data;
1884
1885                         if (text_node->field_flag) {
1886                                 child = xmlNewChild (node, ns, (xmlChar *)"Field", NULL);
1887                                 lgl_xml_set_prop_string (child, "name", text_node->data);
1888                         } else {
1889                                 xmlNodeAddContent (node, (xmlChar *)text_node->data);
1890                         }
1891
1892                 }
1893
1894                 if ( p_line->next ) {
1895                         child = xmlNewChild (node, ns, (xmlChar *)"NL", NULL);
1896                 }
1897
1898         }
1899
1900         gl_text_node_lines_free (&lines);
1901         g_free (font_family);
1902
1903 }
1904
1905
1906 /*--------------------------------------------------------------------------*/
1907 /* PRIVATE.  Create affine attributes.                                      */
1908 /*--------------------------------------------------------------------------*/
1909 static void
1910 xml_create_affine_attrs (xmlNodePtr        node,
1911                          glLabelObject    *object)
1912 {
1913         cairo_matrix_t matrix;
1914
1915         gl_label_object_get_matrix (object, &matrix);
1916
1917         lgl_xml_set_prop_double (node, "a0", matrix.xx);
1918         lgl_xml_set_prop_double (node, "a1", matrix.yx);
1919         lgl_xml_set_prop_double (node, "a2", matrix.xy);
1920         lgl_xml_set_prop_double (node, "a3", matrix.yy);
1921         lgl_xml_set_prop_double (node, "a4", matrix.x0);
1922         lgl_xml_set_prop_double (node, "a5", matrix.y0);
1923 }
1924
1925
1926 /*--------------------------------------------------------------------------*/
1927 /* PRIVATE.  Create shadow attributes.                                      */
1928 /*--------------------------------------------------------------------------*/
1929 static void
1930 xml_create_shadow_attrs (xmlNodePtr        node,
1931                          glLabelObject    *object)
1932 {
1933         gboolean          shadow_state;
1934         gdouble           shadow_x;
1935         gdouble           shadow_y;
1936         glColorNode      *shadow_color_node;
1937         gdouble           shadow_opacity;
1938
1939         shadow_state = gl_label_object_get_shadow_state (object);
1940
1941         if (shadow_state)
1942         {
1943                 lgl_xml_set_prop_boolean (node, "shadow", shadow_state);
1944
1945                 gl_label_object_get_shadow_offset (object, &shadow_x, &shadow_y);
1946                 lgl_xml_set_prop_length (node, "shadow_x", shadow_x);
1947                 lgl_xml_set_prop_length (node, "shadow_y", shadow_y);
1948                 
1949                 shadow_color_node = gl_label_object_get_shadow_color (object);
1950                 if (shadow_color_node->field_flag)
1951                 {
1952                         lgl_xml_set_prop_string (node, "shadow_color_field", shadow_color_node->key);
1953                 }
1954                 else
1955                 {
1956                         lgl_xml_set_prop_uint_hex (node, "shadow_color", shadow_color_node->color);
1957                 }
1958                 gl_color_node_free (&shadow_color_node);
1959
1960                 shadow_opacity = gl_label_object_get_shadow_opacity (object);
1961                 lgl_xml_set_prop_double (node, "shadow_opacity", shadow_opacity);
1962         }
1963 }
1964
1965
1966
1967 /*
1968  * Local Variables:       -- emacs
1969  * mode: C                -- emacs
1970  * c-basic-offset: 8      -- emacs
1971  * tab-width: 8           -- emacs
1972  * indent-tabs-mode: nil  -- emacs
1973  * End:                   -- emacs
1974  */