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