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