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