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