]> git.sur5r.net Git - glabels/blob - glabels2/src/xml-label.c
Added capability to import files created w/ 0.4.x
[glabels] / glabels2 / src / xml-label.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  label.c:  GLabels xml label module
5  *
6  *  Copyright (C) 2001-2002  Jim Evins <evins@snaught.com>.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21  */
22
23 #include <config.h>
24
25 #include <gnome.h>
26
27 #include <libxml/tree.h>
28 #include <libxml/parser.h>
29
30 #include "label.h"
31 #include "label-object.h"
32 #include "label-text.h"
33 #include "label-box.h"
34 #include "label-line.h"
35 #include "label-ellipse.h"
36 #include "label-image.h"
37 #include "label-barcode.h"
38 #include "template.h"
39 #include "xml-label.h"
40 #include "util.h"
41
42 #include "debug.h"
43
44 /*========================================================*/
45 /* Private macros and constants.                          */
46 /*========================================================*/
47 #define NAME_SPACE "http://snaught.com/glabels/1.90/"
48 #define COMPAT01_NAME_SPACE "http://snaught.com/glabels/0.1/"
49 #define COMPAT04_NAME_SPACE "http://snaught.com/glabels/0.4/"
50
51 /*========================================================*/
52 /* Private types.                                         */
53 /*========================================================*/
54
55 /*========================================================*/
56 /* Private globals.                                       */
57 /*========================================================*/
58
59 /*========================================================*/
60 /* Private function prototypes.                           */
61 /*========================================================*/
62
63 static glLabel *xml_doc_to_label (xmlDocPtr doc, glXMLLabelStatus *status);
64 static glLabel *xml_parse_label (xmlNodePtr root, glXMLLabelStatus *status);
65 static void xml_parse_objects (xmlNodePtr node, glLabel * label);
66 static void xml_parse_object(xmlNodePtr node, glLabel *label);
67 static glLabelObject *xml_parse_text_props (xmlNodePtr node, glLabel *label);
68 static glLabelObject *xml_parse_box_props (xmlNodePtr node, glLabel *label);
69 static glLabelObject *xml_parse_line_props (xmlNodePtr node, glLabel *label);
70 static glLabelObject *xml_parse_ellipse_props (xmlNodePtr node, glLabel *label);
71 static glLabelObject *xml_parse_image_props (xmlNodePtr node, glLabel *label);
72 static glLabelObject *xml_parse_barcode_props (xmlNodePtr node, glLabel *label);
73 static void xml_parse_merge_fields (xmlNodePtr node, glLabel *label);
74
75 static xmlDocPtr xml_label_to_doc (glLabel * label, glXMLLabelStatus *status);
76 static void xml_create_objects (xmlNodePtr root, xmlNsPtr ns, glLabel * label);
77 static void xml_create_object (xmlNodePtr root, xmlNsPtr ns,
78                                glLabelObject * object);
79 static void xml_create_text_props (xmlNodePtr root, xmlNsPtr ns,
80                                  glLabelObject * object);
81 static void xml_create_box_props (xmlNodePtr root, xmlNsPtr ns,
82                                 glLabelObject * object);
83 static void xml_create_line_props (xmlNodePtr root, xmlNsPtr ns,
84                                  glLabelObject * object);
85 static void xml_create_ellipse_props (xmlNodePtr root, xmlNsPtr ns,
86                                     glLabelObject * object);
87 static void xml_create_image_props (xmlNodePtr root, xmlNsPtr ns,
88                                   glLabelObject * object);
89 static void xml_create_barcode_props (xmlNodePtr root, xmlNsPtr ns,
90                                     glLabelObject * object);
91 static void xml_create_merge_fields (xmlNodePtr root, xmlNsPtr ns,
92                                       glLabel * label);
93
94 /****************************************************************************/
95 /* Open and read label from xml file.                                       */
96 /****************************************************************************/
97 glLabel *
98 gl_xml_label_open (const gchar * filename,
99                    glXMLLabelStatus *status)
100 {
101         xmlDocPtr doc;
102         glLabel *label;
103
104         gl_debug (DEBUG_XML, "START");
105
106         doc = xmlParseFile (filename);
107         if (!doc) {
108                 g_warning (_("xmlParseFile error"));
109                 *status = XML_LABEL_ERROR_OPEN_PARSE;
110                 return NULL;
111         }
112
113         label = xml_doc_to_label (doc, status);
114
115         xmlFreeDoc (doc);
116
117         gl_label_set_filename (label, filename);
118         gl_label_clear_modified (label);
119
120         gl_debug (DEBUG_XML, "END");
121
122         return label;
123 }
124
125 /****************************************************************************/
126 /* Read label from xml buffer.                                              */
127 /****************************************************************************/
128 glLabel *
129 gl_xml_label_open_buffer (const gchar * buffer,
130                           glXMLLabelStatus *status)
131 {
132         xmlDocPtr doc;
133         glLabel *label;
134
135         gl_debug (DEBUG_XML, "START");
136
137         doc = xmlParseDoc ((xmlChar *) buffer);
138         if (!doc) {
139                 g_warning (_("xmlParseFile error"));
140                 *status = XML_LABEL_ERROR_OPEN_PARSE;
141                 return NULL;
142         }
143
144         label = xml_doc_to_label (doc, status);
145
146         gl_label_clear_modified (label);
147
148         xmlFreeDoc (doc);
149
150         gl_debug (DEBUG_XML, "END");
151
152         return label;
153 }
154
155 /*--------------------------------------------------------------------------*/
156 /* PRIVATE.  Parse xml doc structure and create label.                      */
157 /*--------------------------------------------------------------------------*/
158 static glLabel *
159 xml_doc_to_label (xmlDocPtr doc,
160                   glXMLLabelStatus *status)
161 {
162         xmlNodePtr root, node;
163         xmlNsPtr ns;
164         glLabel *label;
165
166         gl_debug (DEBUG_XML, "START");
167
168         LIBXML_TEST_VERSION;
169
170         *status = XML_LABEL_OK;
171
172         root = xmlDocGetRootElement (doc);
173         if (!root || !root->name) {
174                 g_warning (_("No document root"));
175                 *status = XML_LABEL_ERROR_OPEN_PARSE;
176                 return NULL;
177         }
178
179         ns = xmlSearchNsByHref (doc, root, NAME_SPACE);
180         if (ns != NULL) {
181                 label = xml_parse_label (root, status);
182         } else {
183                 /* Try compatability mode 0.1 */
184                 ns = xmlSearchNsByHref (doc, root, COMPAT01_NAME_SPACE);
185                 if (ns != NULL) {
186                         g_warning (_("Importing from glabels 0.1 format"));
187                         g_warning ("TODO");
188                         label = NULL; /* TODO */
189                 } else {
190                         /* Try compatability mode 0.4 */
191                         ns = xmlSearchNsByHref (doc, root,
192                                                 COMPAT04_NAME_SPACE);
193                         if (ns != NULL) {
194                                 g_warning (_("Importing from glabels 0.4 format"));
195                                 label = gl_xml_label_04_parse (root, status);
196                         } else {
197                                 g_warning (_("bad document, unknown glabels Namespace"));
198                                 *status = XML_LABEL_ERROR_OPEN_PARSE;
199                                 return NULL;
200                         }
201                 }
202         }
203
204         gl_debug (DEBUG_XML, "END");
205
206         return label;
207 }
208
209 /*--------------------------------------------------------------------------*/
210 /* PRIVATE.  Parse xml root node and create label.                          */
211 /*--------------------------------------------------------------------------*/
212 static glLabel *
213 xml_parse_label (xmlNodePtr       root,
214                  glXMLLabelStatus *status)
215 {
216         xmlNodePtr node;
217         glLabel *label;
218         glTemplate *template;
219
220         gl_debug (DEBUG_XML, "START");
221
222         *status = XML_LABEL_OK;
223
224         if (g_strcasecmp (root->name, "Document") != 0) {
225                 g_warning (_("Bad root node = \"%s\""), root->name);
226                 *status = XML_LABEL_ERROR_OPEN_PARSE;
227                 return NULL;
228         }
229
230         label = GL_LABEL(gl_label_new ());
231
232         for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
233
234                 if (g_strcasecmp (node->name, "Sheet") == 0) {
235                         template = gl_template_xml_parse_sheet (node);
236                         if (!template) {
237                                 *status = XML_LABEL_UNKNOWN_MEDIA;
238                                 return NULL;
239                         }
240                         gl_label_set_template (label, template);
241                         gl_template_free (&template);
242                 } else if (g_strcasecmp (node->name, "Objects") == 0) {
243                         xml_parse_objects (node, label);
244                 } else if (g_strcasecmp (node->name, "Merge_Fields") == 0) {
245                         xml_parse_merge_fields (node, label);
246                 } else {
247                         if (!xmlNodeIsText (node)) {
248                                 g_warning (_("bad node =  \"%s\""), node->name);
249                         }
250                 }
251         }
252
253         gl_debug (DEBUG_XML, "END");
254
255         return label;
256 }
257
258 /*--------------------------------------------------------------------------*/
259 /* PRIVATE.  Parse Objects node.                                            */
260 /*--------------------------------------------------------------------------*/
261 static void
262 xml_parse_objects (xmlNodePtr objects_node,
263                    glLabel * label)
264 {
265         gboolean rotate_flag;
266         xmlNodePtr node;
267
268         gl_debug (DEBUG_XML, "START");
269
270         rotate_flag =
271                 !(g_strcasecmp (xmlGetProp (objects_node, "rotate"), "false") == 0);
272         gl_label_set_rotate_flag (label, rotate_flag);
273
274         for (node = objects_node->xmlChildrenNode; node != NULL; node = node->next) {
275
276                 if (g_strcasecmp (node->name, "Object") == 0) {
277                         xml_parse_object (node, label);
278                 } else {
279                         if (!xmlNodeIsText (node)) {
280                                 g_warning (_("bad node =  \"%s\""), node->name);
281                         }
282                 }
283         }
284
285         gl_debug (DEBUG_XML, "END");
286 }
287
288 /*--------------------------------------------------------------------------*/
289 /* PRIVATE.  Parse XML Object Node                                          */
290 /*--------------------------------------------------------------------------*/
291 static void
292 xml_parse_object (xmlNodePtr object_node,
293                   glLabel * label)
294 {
295         glLabelObject *object;
296         gdouble x, y;
297         gchar *type_string;
298
299         gl_debug (DEBUG_XML, "START");
300
301         type_string = xmlGetProp (object_node, "type");
302
303         if ( g_strcasecmp (type_string, "text") == 0 ) {
304                 object = xml_parse_text_props (object_node, label);
305         } else if ( g_strcasecmp (type_string, "box") == 0 ) {
306                 object = xml_parse_box_props (object_node, label);
307         } else if ( g_strcasecmp (type_string, "line") == 0 ) {
308                 object = xml_parse_line_props (object_node, label);
309         } else if ( g_strcasecmp (type_string, "ellipse") == 0 ) {
310                 object = xml_parse_ellipse_props (object_node, label);
311         } else if ( g_strcasecmp (type_string, "image") == 0 ) {
312                 object = xml_parse_image_props (object_node, label);
313         } else if ( g_strcasecmp (type_string, "barcode") == 0 ) {
314                 object = xml_parse_barcode_props (object_node, label);
315         } else {
316                 g_warning ("Unknown label object type \"%s\"", type_string);
317                 return;
318         }
319
320         x = g_strtod (xmlGetProp (object_node, "x"), NULL);
321         y = g_strtod (xmlGetProp (object_node, "y"), NULL);
322
323         gl_label_object_set_position (object, x, y);
324
325         gl_debug (DEBUG_XML, "END");
326 }
327
328 /*--------------------------------------------------------------------------*/
329 /* PRIVATE.  Parse XML Label->Text Node Properties                          */
330 /*--------------------------------------------------------------------------*/
331 static glLabelObject *
332 xml_parse_text_props (xmlNodePtr object_node,
333                       glLabel * label)
334 {
335         GObject *object;
336         GList *lines;
337         gchar *font_family;
338         gdouble font_size;
339         GnomeFontWeight font_weight;
340         gboolean font_italic_flag;
341         guint color;
342         GtkJustification just;
343         xmlNodePtr line_node, text_node;
344         glTextNode *node_text;
345         GList *nodes;
346
347         gl_debug (DEBUG_XML, "START");
348
349         object = gl_label_text_new (label);
350
351         font_family = xmlGetProp (object_node, "font_family");
352         font_size = g_strtod (xmlGetProp (object_node, "font_size"), NULL);
353         font_weight = gl_util_string_to_weight (xmlGetProp (object_node,
354                                                           "font_weight"));
355         font_italic_flag =
356                 !(g_strcasecmp (xmlGetProp (object_node, "font_italic"), "false") ==
357                   0);
358
359         just = gl_util_string_to_just (xmlGetProp (object_node, "justify"));
360
361         sscanf (xmlGetProp (object_node, "color"), "%x", &color);
362
363         lines = NULL;
364         for (line_node = object_node->xmlChildrenNode;
365              line_node != NULL;
366              line_node = line_node->next) {
367
368                 if (g_strcasecmp (line_node->name, "Line") == 0) {
369
370                         nodes = NULL;
371                         for (text_node = line_node->xmlChildrenNode;
372                              text_node != NULL; text_node = text_node->next) {
373
374                                 if (g_strcasecmp (text_node->name, "Field") ==
375                                     0) {
376                                         node_text = g_new0 (glTextNode, 1);
377                                         node_text->field_flag = TRUE;
378                                         node_text->data =
379                                                 xmlGetProp (text_node, "name");
380                                         nodes =
381                                                 g_list_append (nodes, node_text);
382                                 } else if (xmlNodeIsText (text_node)) {
383                                         node_text = g_new0 (glTextNode, 1);
384                                         node_text->field_flag = FALSE;
385                                         node_text->data =
386                                                 xmlNodeGetContent (text_node);
387                                         nodes =
388                                                 g_list_append (nodes, node_text);
389                                 } else {
390                                         g_warning ("Unexpected Text Line child: \"%s\"",
391                                                    text_node->name);
392                                 }
393
394                         }
395                         lines = g_list_append (lines, nodes);
396
397                 } else if (!xmlNodeIsText (line_node)) {
398                         g_warning ("Unexpected Text child: \"%s\"",
399                                    line_node->name);
400                 }
401
402         }
403
404         gl_label_text_set_lines (GL_LABEL_TEXT(object), lines);
405         gl_label_text_set_props (GL_LABEL_TEXT(object),
406                                  font_family, font_size, font_weight,
407                                  font_italic_flag,
408                                  color, just);
409
410         gl_text_node_lines_free (&lines);
411         g_free (font_family);
412
413         gl_debug (DEBUG_XML, "END");
414
415         return GL_LABEL_OBJECT(object);
416 }
417
418 /*--------------------------------------------------------------------------*/
419 /* PRIVATE.  Parse XML Label->Box Node Properties                           */
420 /*--------------------------------------------------------------------------*/
421 static glLabelObject *
422 xml_parse_box_props (xmlNodePtr node,
423                      glLabel * label)
424 {
425         GObject *object;
426         gdouble line_width;
427         guint line_color, fill_color;
428         gdouble w, h;
429
430         gl_debug (DEBUG_XML, "START");
431
432         object = gl_label_box_new (label);
433
434         w = g_strtod (xmlGetProp (node, "w"), NULL);
435         h = g_strtod (xmlGetProp (node, "h"), NULL);
436
437         line_width = g_strtod (xmlGetProp (node, "line_width"), NULL);
438
439         sscanf (xmlGetProp (node, "line_color"), "%x", &line_color);
440         sscanf (xmlGetProp (node, "fill_color"), "%x", &fill_color);
441
442         gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
443         gl_label_box_set_line_width (GL_LABEL_BOX(object), line_width);
444         gl_label_box_set_line_color (GL_LABEL_BOX(object), line_color);
445         gl_label_box_set_fill_color (GL_LABEL_BOX(object), fill_color);
446
447         gl_debug (DEBUG_XML, "END");
448
449         return GL_LABEL_OBJECT(object);
450 }
451
452 /*--------------------------------------------------------------------------*/
453 /* PRIVATE.  Parse XML Label->Line Node Properties                          */
454 /*--------------------------------------------------------------------------*/
455 static glLabelObject *
456 xml_parse_line_props (xmlNodePtr node,
457                       glLabel * label)
458 {
459         GObject *object;
460         gdouble line_width;
461         guint line_color;
462         gdouble w, h;
463
464         gl_debug (DEBUG_XML, "START");
465
466         object = gl_label_line_new (label);
467
468         w = g_strtod (xmlGetProp (node, "dx"), NULL);
469         h = g_strtod (xmlGetProp (node, "dy"), NULL);
470
471         line_width = g_strtod (xmlGetProp (node, "line_width"), NULL);
472
473         sscanf (xmlGetProp (node, "line_color"), "%x", &line_color);
474
475         gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
476         gl_label_line_set_line_width (GL_LABEL_LINE(object), line_width);
477         gl_label_line_set_line_color (GL_LABEL_LINE(object), line_color);
478
479         gl_debug (DEBUG_XML, "END");
480
481         return GL_LABEL_OBJECT(object);
482 }
483
484 /*--------------------------------------------------------------------------*/
485 /* PRIVATE.  Parse XML Label->Ellipse Node Properties                       */
486 /*--------------------------------------------------------------------------*/
487 static glLabelObject *
488 xml_parse_ellipse_props (xmlNodePtr node,
489                          glLabel * label)
490 {
491         GObject *object;
492         gdouble line_width;
493         guint line_color, fill_color;
494         gdouble w, h;
495
496         gl_debug (DEBUG_XML, "START");
497
498         object = gl_label_ellipse_new (label);
499
500         w = g_strtod (xmlGetProp (node, "w"), NULL);
501         h = g_strtod (xmlGetProp (node, "h"), NULL);
502
503         line_width = g_strtod (xmlGetProp (node, "line_width"), NULL);
504
505         sscanf (xmlGetProp (node, "line_color"), "%x", &line_color);
506         sscanf (xmlGetProp (node, "fill_color"), "%x", &fill_color);
507
508         gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
509         gl_label_ellipse_set_line_width (GL_LABEL_ELLIPSE(object), line_width);
510         gl_label_ellipse_set_line_color (GL_LABEL_ELLIPSE(object), line_color);
511         gl_label_ellipse_set_fill_color (GL_LABEL_ELLIPSE(object), fill_color);
512
513         gl_debug (DEBUG_XML, "END");
514
515         return GL_LABEL_OBJECT(object);
516 }
517
518 /*--------------------------------------------------------------------------*/
519 /* PRIVATE.  Parse XML Label->Image Node Properties                         */
520 /*--------------------------------------------------------------------------*/
521 static glLabelObject *
522 xml_parse_image_props (xmlNodePtr node,
523                        glLabel *label)
524 {
525         GObject *object;
526         gdouble w, h;
527         gchar   *filename;
528
529         gl_debug (DEBUG_XML, "START");
530
531         object = gl_label_image_new (label);
532
533         w = g_strtod (xmlGetProp (node, "w"), NULL);
534         h = g_strtod (xmlGetProp (node, "h"), NULL);
535
536         filename = xmlNodeGetContent (node);
537
538         gl_label_object_set_size (GL_LABEL_OBJECT(object), w, h);
539         gl_label_image_set_filename (GL_LABEL_IMAGE(object), filename);
540
541         g_free (filename);
542
543         gl_debug (DEBUG_XML, "END");
544
545         return GL_LABEL_OBJECT(object);
546 }
547
548 /*--------------------------------------------------------------------------*/
549 /* PRIVATE.  Parse XML Label->Barcode Node Properties                       */
550 /*--------------------------------------------------------------------------*/
551 static glLabelObject *
552 xml_parse_barcode_props (xmlNodePtr node,
553                          glLabel *label)
554 {
555         GObject *object;
556         xmlNodePtr child;
557         glTextNode          *text_node;
558         glBarcodeStyle      style;
559         gboolean            text_flag;
560         guint               color;
561         gdouble             scale;
562
563         gl_debug (DEBUG_XML, "START");
564
565         object = gl_label_barcode_new (label);
566
567         sscanf (xmlGetProp (node, "color"), "%x", &color);
568
569         style = gl_barcode_text_to_style (xmlGetProp (node, "style"));
570         text_flag = !(g_strcasecmp (xmlGetProp (node, "text"), "false") == 0);
571         scale = g_strtod (xmlGetProp (node, "scale"), NULL);
572
573         child = node->xmlChildrenNode;
574         text_node = g_new0 (glTextNode, 1);
575         if (g_strcasecmp (child->name, "Field") == 0) {
576                 text_node->field_flag = TRUE;
577                 text_node->data = xmlGetProp (child, "name");
578         } else if (xmlNodeIsText (child)) {
579                 text_node->field_flag = FALSE;
580                 text_node->data = xmlNodeGetContent (child);
581         } else {
582                 g_warning ("Unexpected Barcode child: \"%s\"", child->name);
583         }
584
585         gl_label_barcode_set_data (GL_LABEL_BARCODE(object), text_node);
586         gl_label_barcode_set_props (GL_LABEL_BARCODE(object),
587                                     style, text_flag, color, scale);
588
589         gl_text_node_free (&text_node);
590
591         gl_debug (DEBUG_XML, "END");
592
593         return GL_LABEL_OBJECT(object);
594 }
595
596 /*--------------------------------------------------------------------------*/
597 /* PRIVATE.  Parse XML merge fields tag.                                */
598 /*--------------------------------------------------------------------------*/
599 static void
600 xml_parse_merge_fields (xmlNodePtr node,
601                         glLabel * label)
602 {
603         xmlNodePtr child;
604         glMerge *merge;
605         glMergeFieldDefinition *field_def;
606
607         gl_debug (DEBUG_XML, "START");
608
609         merge = gl_merge_new ();
610
611         merge->type = gl_merge_text_to_type (xmlGetProp (node, "type"));
612         merge->src = xmlGetProp (node, "src");
613
614         for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
615
616                 if (g_strcasecmp (child->name, "Field") == 0) {
617                         field_def = g_new0 (glMergeFieldDefinition, 1);
618                         field_def->key = xmlGetProp (child, "key");
619                         field_def->loc = xmlGetProp (child, "loc");
620                         merge->field_defs =
621                             g_list_append (merge->field_defs,
622                                            field_def);
623                 } else if (!xmlNodeIsText (child)) {
624                         g_warning ("Unexpected Merge_Fields child: \"%s\"",
625                                    child->name);
626                 }
627
628         }
629
630         gl_label_set_merge (label, merge);
631
632         gl_merge_free (&merge);
633
634         gl_debug (DEBUG_XML, "END");
635 }
636
637 /****************************************************************************/
638 /* Save label to xml label file.                                            */
639 /****************************************************************************/
640 void
641 gl_xml_label_save (glLabel *label,
642                    const gchar *filename,
643                    glXMLLabelStatus *status)
644 {
645         xmlDocPtr doc;
646         gint xml_ret;
647
648         gl_debug (DEBUG_XML, "START");
649
650         doc = xml_label_to_doc (label, status);
651
652         xml_ret = xmlSaveFormatFile (filename, doc, TRUE);
653         xmlFreeDoc (doc);
654         if (xml_ret == -1) {
655                 g_warning (_("Problem saving xml file."));
656                 *status = XML_LABEL_ERROR_SAVE_FILE;
657         }
658
659         gl_label_set_filename (label, filename);
660         gl_label_clear_modified (label);
661
662         gl_debug (DEBUG_XML, "END");
663 }
664
665 /****************************************************************************/
666 /* Save label to xml buffer.                                                */
667 /****************************************************************************/
668 gchar *
669 gl_xml_label_save_buffer (glLabel *label,
670                           glXMLLabelStatus *status)
671 {
672         xmlDocPtr doc;
673         gint size;
674         gchar *buffer;
675
676         gl_debug (DEBUG_XML, "START");
677
678         doc = xml_label_to_doc (label, status);
679
680         xmlDocDumpMemory (doc, (xmlChar **)&buffer, &size);
681         xmlFreeDoc (doc);
682
683         gl_label_clear_modified (label);
684
685         gl_debug (DEBUG_XML, "END");
686
687         return buffer;
688 }
689
690 /*--------------------------------------------------------------------------*/
691 /* PRIVATE.  Convert label to xml doc structure.                            */
692 /*--------------------------------------------------------------------------*/
693 static xmlDocPtr
694 xml_label_to_doc (glLabel * label,
695                   glXMLLabelStatus *status)
696 {
697         xmlDocPtr doc;
698         xmlNsPtr ns;
699         glTemplate *template;
700         glMerge *merge;
701
702         gl_debug (DEBUG_XML, "START");
703
704         LIBXML_TEST_VERSION;
705
706         doc = xmlNewDoc ("1.0");
707         doc->xmlRootNode = xmlNewDocNode (doc, NULL, "Document", NULL);
708
709         ns = xmlNewNs (doc->xmlRootNode, NAME_SPACE, "glabels");
710         xmlSetNs (doc->xmlRootNode, ns);
711
712         template = gl_label_get_template (label);
713         gl_template_xml_add_sheet (template, doc->xmlRootNode, ns);
714
715         xml_create_objects (doc->xmlRootNode, ns, label);
716
717         merge = gl_label_get_merge (label);
718         gl_debug (DEBUG_XML, "merge=%p", merge);
719         if (merge->type != GL_MERGE_NONE) {
720                 xml_create_merge_fields (doc->xmlRootNode, ns, label);
721         }
722         gl_merge_free (&merge);
723
724         gl_debug (DEBUG_XML, "END");
725
726         *status = XML_LABEL_OK;
727         return doc;
728 }
729
730 /*--------------------------------------------------------------------------*/
731 /* PRIVATE.  Add XML Label->Objects Node                                    */
732 /*--------------------------------------------------------------------------*/
733 static void
734 xml_create_objects (xmlNodePtr root,
735                     xmlNsPtr ns,
736                     glLabel * label)
737 {
738         xmlNodePtr node;
739         gboolean rotate_flag;
740         GList *p;
741
742         gl_debug (DEBUG_XML, "START");
743
744         rotate_flag = gl_label_get_rotate_flag (label);
745
746         node = xmlNewChild (root, ns, "Objects", NULL);
747         xmlSetProp (node, "id", "0");
748         xmlSetProp (node, "rotate", rotate_flag ? "True" : "False");
749
750         for (p = label->objects; p != NULL; p = p->next) {
751                 xml_create_object (node, ns, GL_LABEL_OBJECT(p->data));
752         }
753
754         gl_debug (DEBUG_XML, "END");
755 }
756
757 /*--------------------------------------------------------------------------*/
758 /* PRIVATE.  Add XML label object Node                                      */
759 /*--------------------------------------------------------------------------*/
760 static void
761 xml_create_object (xmlNodePtr root,
762                    xmlNsPtr ns,
763                    glLabelObject * object)
764 {
765         xmlNodePtr object_node;
766         gdouble x, y;
767         gchar *string;
768
769         gl_debug (DEBUG_XML, "START");
770
771         object_node = xmlNewChild (root, ns, "Object", NULL);
772
773         gl_label_object_get_position (object, &x, &y);
774         string = g_strdup_printf ("%g", x);
775         xmlSetProp (object_node, "x", string);
776         g_free (string);
777         string = g_strdup_printf ("%g", y);
778         xmlSetProp (object_node, "y", string);
779         g_free (string);
780
781         if ( GL_IS_LABEL_TEXT(object) ) {
782                 xml_create_text_props (object_node, ns, object);
783         } else if ( GL_IS_LABEL_BOX(object) ) {
784                 xml_create_box_props (object_node, ns, object);
785         } else if ( GL_IS_LABEL_LINE(object) ) {
786                 xml_create_line_props (object_node, ns, object);
787         } else if ( GL_IS_LABEL_ELLIPSE(object) ) {
788                 xml_create_ellipse_props (object_node, ns, object);
789         } else if ( GL_IS_LABEL_IMAGE(object) ) {
790                 xml_create_image_props (object_node, ns, object);
791         } else if ( GL_IS_LABEL_BARCODE(object) ) {
792                 xml_create_barcode_props (object_node, ns, object);
793         } else {
794                 g_warning ("Unknown label object");
795         }
796
797         gl_debug (DEBUG_XML, "END");
798 }
799
800 /*--------------------------------------------------------------------------*/
801 /* PRIVATE.  Add XML Label->Text Node Properties                            */
802 /*--------------------------------------------------------------------------*/
803 static void
804 xml_create_text_props (xmlNodePtr object_node,
805                        xmlNsPtr ns,
806                        glLabelObject * object)
807 {
808         xmlNodePtr line_node, field_node;
809         GList *lines;
810         gchar *font_family;
811         gdouble font_size;
812         GnomeFontWeight font_weight;
813         gboolean font_italic_flag;
814         guint color;
815         GtkJustification just;
816         gchar *string;
817         GList *p_line, *p_node;
818         glTextNode *node_text;
819
820         gl_debug (DEBUG_XML, "START");
821
822         xmlSetProp (object_node, "type", "Text");
823
824         lines = gl_label_text_get_lines (GL_LABEL_TEXT(object));
825         gl_label_text_get_props (GL_LABEL_TEXT(object),
826                                  &font_family, &font_size, &font_weight,
827                                  &font_italic_flag,
828                                  &color, &just);
829
830         xmlSetProp (object_node, "font_family", font_family);
831         string = g_strdup_printf ("%g", font_size);
832         xmlSetProp (object_node, "font_size", string);
833         g_free (string);
834         xmlSetProp (object_node, "font_weight",
835                     gl_util_weight_to_string (font_weight));
836         xmlSetProp (object_node, "font_italic",
837                     font_italic_flag?"True":"False");
838
839         xmlSetProp (object_node, "justify", gl_util_just_to_string (just));
840
841         string = g_strdup_printf ("0x%08x", color);
842         xmlSetProp (object_node, "color", string);
843         g_free (string);
844
845         for (p_line = lines; p_line != NULL; p_line = p_line->next) {
846                 line_node = xmlNewChild (object_node, ns, "Line", NULL);
847
848                 for (p_node = (GList *) p_line->data; p_node != NULL;
849                      p_node = p_node->next) {
850                         node_text = (glTextNode *) p_node->data;
851
852                         if (node_text->field_flag) {
853                                 field_node =
854                                     xmlNewChild (line_node, ns, "Field", NULL);
855                                 xmlSetProp (field_node, "name",
856                                             node_text->data);
857                         } else {
858                                 xmlNodeAddContent (line_node, node_text->data);
859                         }
860
861                 }
862
863         }
864
865         gl_text_node_lines_free (&lines);
866         g_free (font_family);
867
868         gl_debug (DEBUG_XML, "END");
869 }
870
871 /*--------------------------------------------------------------------------*/
872 /* PRIVATE.  Add XML Label->Box Node Properties                             */
873 /*--------------------------------------------------------------------------*/
874 static void
875 xml_create_box_props (xmlNodePtr object_node,
876                       xmlNsPtr ns,
877                       glLabelObject * object)
878 {
879         gchar *string;
880         gdouble line_width;
881         guint line_color, fill_color;
882         gdouble w, h;
883
884         gl_debug (DEBUG_XML, "START");
885
886         xmlSetProp (object_node, "type", "Box");
887
888         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
889         line_width = gl_label_box_get_line_width (GL_LABEL_BOX(object));
890         line_color = gl_label_box_get_line_color (GL_LABEL_BOX(object));
891         fill_color = gl_label_box_get_fill_color (GL_LABEL_BOX(object));
892
893         string = g_strdup_printf ("%g", w);
894         xmlSetProp (object_node, "w", string);
895         g_free (string);
896         string = g_strdup_printf ("%g", h);
897         xmlSetProp (object_node, "h", string);
898         g_free (string);
899
900         string = g_strdup_printf ("%g", line_width);
901         xmlSetProp (object_node, "line_width", string);
902         g_free (string);
903
904         string = g_strdup_printf ("0x%08x", line_color);
905         xmlSetProp (object_node, "line_color", string);
906         g_free (string);
907
908         string = g_strdup_printf ("0x%08x", fill_color);
909         xmlSetProp (object_node, "fill_color", string);
910         g_free (string);
911
912         gl_debug (DEBUG_XML, "END");
913 }
914
915 /*--------------------------------------------------------------------------*/
916 /* PRIVATE.  Add XML Label->Line Node Properties                            */
917 /*--------------------------------------------------------------------------*/
918 static void
919 xml_create_line_props (xmlNodePtr object_node,
920                        xmlNsPtr ns,
921                        glLabelObject * object)
922 {
923         gchar *string;
924         gdouble line_width;
925         guint line_color;
926         gdouble w, h;
927
928         gl_debug (DEBUG_XML, "START");
929
930         xmlSetProp (object_node, "type", "Line");
931
932         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
933         line_width = gl_label_line_get_line_width (GL_LABEL_LINE(object));
934         line_color = gl_label_line_get_line_color (GL_LABEL_LINE(object));
935
936         string = g_strdup_printf ("%g", w);
937         xmlSetProp (object_node, "dx", string);
938         g_free (string);
939         string = g_strdup_printf ("%g", h);
940         xmlSetProp (object_node, "dy", string);
941         g_free (string);
942
943         string = g_strdup_printf ("%g", line_width);
944         xmlSetProp (object_node, "line_width", string);
945         g_free (string);
946
947         string = g_strdup_printf ("0x%08x", line_color);
948         xmlSetProp (object_node, "line_color", string);
949         g_free (string);
950
951         gl_debug (DEBUG_XML, "END");
952 }
953
954 /*--------------------------------------------------------------------------*/
955 /* PRIVATE.  Add XML Label->Ellipse Node Properties                         */
956 /*--------------------------------------------------------------------------*/
957 static void
958 xml_create_ellipse_props (xmlNodePtr object_node,
959                           xmlNsPtr ns,
960                           glLabelObject * object)
961 {
962         gchar *string;
963         gdouble line_width;
964         guint line_color, fill_color;
965         gdouble w, h;
966
967         gl_debug (DEBUG_XML, "START");
968
969         xmlSetProp (object_node, "type", "Ellipse");
970
971         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
972         line_width = gl_label_ellipse_get_line_width (GL_LABEL_ELLIPSE(object));
973         line_color = gl_label_ellipse_get_line_color (GL_LABEL_ELLIPSE(object));
974         fill_color = gl_label_ellipse_get_fill_color (GL_LABEL_ELLIPSE(object));
975
976         string = g_strdup_printf ("%g", w);
977         xmlSetProp (object_node, "w", string);
978         g_free (string);
979         string = g_strdup_printf ("%g", h);
980         xmlSetProp (object_node, "h", string);
981         g_free (string);
982
983         string = g_strdup_printf ("%g", line_width);
984         xmlSetProp (object_node, "line_width", string);
985         g_free (string);
986
987         string = g_strdup_printf ("0x%08x", line_color);
988         xmlSetProp (object_node, "line_color", string);
989         g_free (string);
990
991         string = g_strdup_printf ("0x%08x", fill_color);
992         xmlSetProp (object_node, "fill_color", string);
993         g_free (string);
994
995         gl_debug (DEBUG_XML, "END");
996 }
997
998 /*--------------------------------------------------------------------------*/
999 /* PRIVATE.  Add XML Label->Image Node Properties                           */
1000 /*--------------------------------------------------------------------------*/
1001 static void
1002 xml_create_image_props (xmlNodePtr object_node,
1003                         xmlNsPtr ns,
1004                         glLabelObject * object)
1005 {
1006         gchar *string;
1007         gdouble w, h;
1008         gchar *filename;
1009
1010         gl_debug (DEBUG_XML, "START");
1011
1012         xmlSetProp (object_node, "type", "Image");
1013
1014         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1015         filename = gl_label_image_get_filename (GL_LABEL_IMAGE(object));
1016
1017         string = g_strdup_printf ("%g", w);
1018         xmlSetProp (object_node, "w", string);
1019         g_free (string);
1020         string = g_strdup_printf ("%g", h);
1021         xmlSetProp (object_node, "h", string);
1022         g_free (string);
1023
1024         xmlNodeSetContent (object_node, filename);
1025
1026         g_free (filename);
1027
1028         gl_debug (DEBUG_XML, "END");
1029 }
1030
1031 /*--------------------------------------------------------------------------*/
1032 /* PRIVATE.  Add XML Label->Barcode Node Properties                         */
1033 /*--------------------------------------------------------------------------*/
1034 static void
1035 xml_create_barcode_props (xmlNodePtr object_node,
1036                           xmlNsPtr ns,
1037                           glLabelObject * object)
1038 {
1039         glTextNode          *text_node;
1040         glBarcodeStyle      style;
1041         gboolean            text_flag;
1042         guint               color;
1043         gdouble             scale;
1044         xmlNodePtr child;
1045         gchar *string;
1046
1047         gl_debug (DEBUG_XML, "START");
1048
1049         xmlSetProp (object_node, "type", "Barcode");
1050
1051         text_node = gl_label_barcode_get_data (GL_LABEL_BARCODE(object));
1052         gl_label_barcode_get_props (GL_LABEL_BARCODE(object),
1053                                     &style, &text_flag, &color, &scale);
1054
1055         string = g_strdup_printf ("0x%08x", color);
1056         xmlSetProp (object_node, "color", string);
1057         g_free (string);
1058
1059         xmlSetProp (object_node, "style", gl_barcode_style_to_text (style));
1060         xmlSetProp (object_node, "text", text_flag?"True":"False");
1061         string = g_strdup_printf ("%g", scale);
1062         xmlSetProp (object_node, "scale", string);
1063         g_free (string);
1064
1065         if (text_node->field_flag) {
1066                 child = xmlNewChild (object_node, ns, "Field", NULL);
1067                 xmlSetProp (child, "name", text_node->data);
1068         } else {
1069                 xmlNodeSetContent (object_node, text_node->data);
1070         }
1071
1072         gl_text_node_free (&text_node);
1073
1074         gl_debug (DEBUG_XML, "END");
1075 }
1076
1077 /*--------------------------------------------------------------------------*/
1078 /* PRIVATE.  Add XML Label Merge Fields Node                                */
1079 /*--------------------------------------------------------------------------*/
1080 static void
1081 xml_create_merge_fields (xmlNodePtr root,
1082                              xmlNsPtr ns,
1083                              glLabel * label)
1084 {
1085         xmlNodePtr node, child;
1086         gchar *string;
1087         GList *p;
1088         glMerge *merge;
1089         glMergeFieldDefinition *field_def;
1090
1091         gl_debug (DEBUG_XML, "START");
1092
1093         merge = gl_label_get_merge (label);
1094
1095         node = xmlNewChild (root, ns, "Merge_Fields", NULL);
1096
1097         string = gl_merge_type_to_text (merge->type);
1098         xmlSetProp (node, "type", string);
1099         g_free (string);
1100
1101         xmlSetProp (node, "src", merge->src);
1102
1103         for (p = merge->field_defs; p != NULL; p = p->next) {
1104                 field_def = (glMergeFieldDefinition *) p->data;
1105
1106                 child = xmlNewChild (node, ns, "Field", NULL);
1107                 xmlSetProp (child, "key", field_def->key);
1108                 xmlSetProp (child, "loc", field_def->loc);
1109         }
1110
1111         gl_merge_free (&merge);
1112
1113         gl_debug (DEBUG_XML, "END");
1114 }
1115