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