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