]> git.sur5r.net Git - glabels/blob - glabels2/libglabels/xml-template.c
6f1ae4b852ee5458d6bfde57bf7c3c8f9ae7ae97
[glabels] / glabels2 / libglabels / xml-template.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4  *  (LIBGLABELS) Template library for GLABELS
5  *
6  *  xml-template.c:  template xml module
7  *
8  *  Copyright (C) 2001-2006  Jim Evins <evins@snaught.com>.
9  *
10  *  This file is part of the LIBGLABELS library.
11  *
12  *  This library is free software; you can redistribute it and/or
13  *  modify it under the terms of the GNU Library General Public
14  *  License as published by the Free Software Foundation; either
15  *  version 2 of the License, or (at your option) any later version.
16  *
17  *  This library is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  *  Library General Public License for more details.
21  *
22  *  You should have received a copy of the GNU Library General Public
23  *  License along with this library; if not, write to the Free
24  *  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  *  MA 02111-1307, USA
26  */
27 #include <config.h>
28
29 #include "xml-template.h"
30
31 #include <glib/gi18n.h>
32 #include <glib/gmessages.h>
33 #include <string.h>
34 #include <libintl.h>
35
36 #include "libglabels-private.h"
37
38 #include "db.h"
39 #include "xml.h"
40
41 /*===========================================*/
42 /* Private types                             */
43 /*===========================================*/
44
45 /*===========================================*/
46 /* Private globals                           */
47 /*===========================================*/
48
49 /*===========================================*/
50 /* Local function prototypes                 */
51 /*===========================================*/
52 static void  xml_parse_meta_node            (xmlNodePtr              label_node,
53                                              lglTemplate            *template);
54 static void  xml_parse_label_rectangle_node (xmlNodePtr              label_node,
55                                              lglTemplate            *template);
56 static void  xml_parse_label_round_node     (xmlNodePtr              label_node,
57                                              lglTemplate            *template);
58 static void  xml_parse_label_cd_node        (xmlNodePtr              label_node,
59                                              lglTemplate            *template);
60 static void  xml_parse_layout_node          (xmlNodePtr              layout_node,
61                                              lglTemplateFrame       *frame);
62 static void  xml_parse_markup_margin_node   (xmlNodePtr              markup_node,
63                                              lglTemplateFrame       *frame);
64 static void  xml_parse_markup_line_node     (xmlNodePtr              markup_node,
65                                              lglTemplateFrame       *frame);
66 static void  xml_parse_markup_circle_node   (xmlNodePtr              markup_node,
67                                              lglTemplateFrame       *frame);
68 static void  xml_parse_markup_rect_node     (xmlNodePtr              markup_node,
69                                              lglTemplateFrame       *frame);
70 static void  xml_parse_alias_node           (xmlNodePtr              alias_node,
71                                              lglTemplate            *template);
72
73 static void  xml_create_meta_node           (const gchar                  *category,
74                                              xmlNodePtr                    root,
75                                              const xmlNsPtr                ns);
76 static void  xml_create_label_node          (const lglTemplateFrame       *frame,
77                                              xmlNodePtr                    root,
78                                              const xmlNsPtr                ns);
79 static void  xml_create_layout_node         (const lglTemplateLayout      *layout,
80                                              xmlNodePtr                    root,
81                                              const xmlNsPtr                ns);
82 static void  xml_create_markup_margin_node  (const lglTemplateMarkup      *margin,
83                                              xmlNodePtr                    root,
84                                              const xmlNsPtr                ns);
85 static void  xml_create_markup_line_node    (const lglTemplateMarkup      *line,
86                                              xmlNodePtr                    root,
87                                              const xmlNsPtr                ns);
88 static void  xml_create_markup_circle_node  (const lglTemplateMarkup      *circle,
89                                              xmlNodePtr                    root,
90                                              const xmlNsPtr                ns);
91 static void  xml_create_markup_rect_node    (const lglTemplateMarkup      *circle,
92                                              xmlNodePtr                    root,
93                                              const xmlNsPtr                ns);
94 static void  xml_create_alias_node          (const lglTemplateAlias       *alias,
95                                              xmlNodePtr                    root,
96                                              const xmlNsPtr                ns);
97
98
99 /**
100  * lgl_xml_template_read_templates_from_file:
101  * @utf8_filename:       Filename of papers file (name encoded as UTF-8)
102  *
103  * Read glabels templates from template file.
104  *
105  * Returns: a list of #lglTemplate structures.
106  *
107  */
108 GList *
109 lgl_xml_template_read_templates_from_file (const gchar *utf8_filename)
110 {
111         gchar      *filename;
112         xmlDocPtr   templates_doc;
113         GList      *templates = NULL;
114
115         LIBXML_TEST_VERSION;
116
117         filename = g_filename_from_utf8 (utf8_filename, -1, NULL, NULL, NULL);
118         if (!filename) {
119                 g_message ("Utf8 filename conversion error");
120                 return NULL;
121         }
122
123         templates_doc = xmlParseFile (filename);
124         if (!templates_doc) {
125                 g_message ("\"%s\" is not a glabels template file (not XML)",
126                       filename);
127                 return templates;
128         }
129
130         templates = lgl_xml_template_parse_templates_doc (templates_doc);
131
132         g_free (filename);
133         xmlFreeDoc (templates_doc);
134
135         return templates;
136 }
137
138
139 /**
140  * lgl_xml_template_parse_templates_doc:
141  * @templates_doc:  libxml #xmlDocPtr tree, representing template file.
142  *
143  * Read glabels templates from a libxml #xmlDocPtr tree.
144  *
145  * Returns: a list of #lglTemplate structures.
146  *
147  */
148 GList *
149 lgl_xml_template_parse_templates_doc (const xmlDocPtr templates_doc)
150 {
151         
152         GList       *templates = NULL;
153         xmlNodePtr   root, node;
154         lglTemplate *template;
155
156         LIBXML_TEST_VERSION;
157
158         root = xmlDocGetRootElement (templates_doc);
159         if (!root || !root->name) {
160                 g_message ("\"%s\" is not a glabels template file (no root node)",
161                            templates_doc->URL);
162                 return templates;
163         }
164         if (!lgl_xml_is_node (root, "Glabels-templates")) {
165                 g_message ("\"%s\" is not a glabels template file (wrong root node)",
166                       templates_doc->URL);
167                 return templates;
168         }
169
170         for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
171
172                 if (lgl_xml_is_node (node, "Template")) {
173                         template = lgl_xml_template_parse_template_node (node);
174                         templates = g_list_append (templates, template);
175                 } else {
176                         if ( !xmlNodeIsText(node) ) {
177                                 if (!lgl_xml_is_node (node,"comment")) {
178                                         g_message ("bad node =  \"%s\"",node->name);
179                                 }
180                         }
181                 }
182         }
183
184         return templates;
185 }
186
187
188 /**
189  * lgl_xml_template_parse_template_node:
190  * @template_node:  libxml #xmlNodePtr template node from a #xmlDocPtr tree.
191  *
192  * Read a single glabels template from a libxml #xmlNodePtr node.
193  *
194  * Returns: a pointer to a newly created #lglTemplate structure.
195  *
196  */
197 lglTemplate *
198 lgl_xml_template_parse_template_node (const xmlNodePtr template_node)
199 {
200         gchar                 *brand;
201         gchar                 *part;
202         gchar                 *name;
203         gchar                 *description;
204         gchar                 *paper_id;
205         gdouble                page_width, page_height;
206         lglPaper               *paper = NULL;
207         lglTemplate           *template;
208         xmlNodePtr             node;
209         gchar                **v;
210
211         brand = lgl_xml_get_prop_string (template_node, "brand", NULL);
212         part  = lgl_xml_get_prop_string (template_node, "part", NULL);
213         if (!brand || !part)
214         {
215                 name = lgl_xml_get_prop_string (template_node, "name", NULL);
216                 if (name)
217                 {
218                         v = g_strsplit (name, " ", 2);
219                         brand = g_strdup (v[0]);
220                         part  = g_strchug (g_strdup (v[1]));
221                         g_free (name);
222                         g_strfreev (v);
223                         
224                 }
225                 else
226                 {
227                         g_message (_("Missing name or brand/part attributes."));
228                 }
229         }
230
231         description = lgl_xml_get_prop_i18n_string (template_node, "description", NULL);
232         paper_id = lgl_xml_get_prop_string (template_node, "size", NULL);
233
234         if (lgl_db_is_paper_id_other (paper_id)) {
235
236                 page_width = lgl_xml_get_prop_length (template_node, "width", 0);
237                 page_height = lgl_xml_get_prop_length (template_node, "height", 0);
238
239         } else {
240                 paper = lgl_db_lookup_paper_from_id (paper_id);
241                 if (paper == NULL) {
242                         /* This should always be an id, but just in case a name
243                            slips by! */
244                         g_message (_("Unknown page size id \"%s\", trying as name"),
245                                    paper_id);
246                         paper = lgl_db_lookup_paper_from_name (paper_id);
247                         g_free (paper_id);
248                         paper_id = g_strdup (paper->id);
249                 }
250                 if (paper != NULL) {
251                         page_width  = paper->width;
252                         page_height = paper->height;
253                 } else {
254                         page_width  = 612;
255                         page_height = 792;
256                         g_message (_("Unknown page size id or name \"%s\""),
257                                    paper_id);
258                 }
259                 lgl_paper_free (paper);
260                 paper = NULL;
261         }
262
263         template = lgl_template_new (brand, part, description,
264                                      paper_id, page_width, page_height);
265
266         for (node = template_node->xmlChildrenNode; node != NULL;
267              node = node->next) {
268                 if (lgl_xml_is_node (node, "Meta")) {
269                         xml_parse_meta_node (node, template);
270                 } else if (lgl_xml_is_node (node, "Label-rectangle")) {
271                         xml_parse_label_rectangle_node (node, template);
272                 } else if (lgl_xml_is_node (node, "Label-round")) {
273                         xml_parse_label_round_node (node, template);
274                 } else if (lgl_xml_is_node (node, "Label-cd")) {
275                         xml_parse_label_cd_node (node, template);
276                 } else if (lgl_xml_is_node (node, "Alias")) {
277                         xml_parse_alias_node (node, template);
278                 } else {
279                         if (!xmlNodeIsText (node)) {
280                                 if (!lgl_xml_is_node (node,"comment")) {
281                                         g_message ("bad node =  \"%s\"",node->name);
282                                 }
283                         }
284                 }
285         }
286
287         g_free (brand);
288         g_free (part);
289         g_free (description);
290         g_free (paper_id);
291
292         return template;
293 }
294
295 /*--------------------------------------------------------------------------*/
296 /* PRIVATE.  Parse XML Template->Meta Node.                                 */
297 /*--------------------------------------------------------------------------*/
298 static void
299 xml_parse_meta_node (xmlNodePtr   meta_node,
300                      lglTemplate *template)
301 {
302         gchar               *category;
303
304         category = lgl_xml_get_prop_string (meta_node, "category", NULL);
305
306         if (category != NULL)
307         {
308                 lgl_template_add_category (template, category);
309                 g_free (category);
310         }
311 }
312
313 /*--------------------------------------------------------------------------*/
314 /* PRIVATE.  Parse XML Template->Label-rectangle Node.                      */
315 /*--------------------------------------------------------------------------*/
316 static void
317 xml_parse_label_rectangle_node (xmlNodePtr   label_node,
318                                 lglTemplate *template)
319 {
320         gchar               *id;
321         gchar               *tmp;
322         gdouble              x_waste, y_waste;
323         gdouble              w, h, r;
324         lglTemplateFrame    *frame;
325         xmlNodePtr           node;
326
327         id      = lgl_xml_get_prop_string (label_node, "id", NULL);
328
329         if ((tmp = lgl_xml_get_prop_string (label_node, "waste", NULL))) {
330                 /* Handle single "waste" property. */
331                 x_waste = y_waste = lgl_xml_get_prop_length (label_node, "waste", 0);
332                 g_free (tmp);
333         } else {
334                 x_waste = lgl_xml_get_prop_length (label_node, "x_waste", 0);
335                 y_waste = lgl_xml_get_prop_length (label_node, "y_waste", 0);
336         }
337
338         w       = lgl_xml_get_prop_length (label_node, "width", 0);
339         h       = lgl_xml_get_prop_length (label_node, "height", 0);
340         r       = lgl_xml_get_prop_length (label_node, "round", 0);
341
342         frame = lgl_template_frame_rect_new ((gchar *)id, w, h, r, x_waste, y_waste);
343         lgl_template_add_frame (template, frame);
344
345         for (node = label_node->xmlChildrenNode; node != NULL;
346              node = node->next) {
347                 if (lgl_xml_is_node (node, "Layout")) {
348                         xml_parse_layout_node (node, frame);
349                 } else if (lgl_xml_is_node (node, "Markup-margin")) {
350                         xml_parse_markup_margin_node (node, frame);
351                 } else if (lgl_xml_is_node (node, "Markup-line")) {
352                         xml_parse_markup_line_node (node, frame);
353                 } else if (lgl_xml_is_node (node, "Markup-circle")) {
354                         xml_parse_markup_circle_node (node, frame);
355                 } else if (lgl_xml_is_node (node, "Markup-rect")) {
356                         xml_parse_markup_rect_node (node, frame);
357                 } else if (!xmlNodeIsText (node)) {
358                         if (!lgl_xml_is_node (node, "comment")) {
359                                 g_message ("bad node =  \"%s\"",node->name);
360                         }
361                 }
362         }
363
364         g_free (id);
365 }
366
367 /*--------------------------------------------------------------------------*/
368 /* PRIVATE.  Parse XML Template->Label-round Node.                          */
369 /*--------------------------------------------------------------------------*/
370 static void
371 xml_parse_label_round_node (xmlNodePtr   label_node,
372                             lglTemplate *template)
373 {
374         gchar               *id;
375         gdouble              waste;
376         gdouble              r;
377         lglTemplateFrame    *frame;
378         xmlNodePtr           node;
379
380         id    = lgl_xml_get_prop_string (label_node, "id", NULL);
381         waste = lgl_xml_get_prop_length (label_node, "waste", 0);
382         r     = lgl_xml_get_prop_length (label_node, "radius", 0);
383
384         frame = lgl_template_frame_round_new ((gchar *)id, r, waste);
385         lgl_template_add_frame (template, frame);
386
387         for (node = label_node->xmlChildrenNode; node != NULL;
388              node = node->next) {
389                 if (lgl_xml_is_node (node, "Layout")) {
390                         xml_parse_layout_node (node, frame);
391                 } else if (lgl_xml_is_node (node, "Markup-margin")) {
392                         xml_parse_markup_margin_node (node, frame);
393                 } else if (lgl_xml_is_node (node, "Markup-line")) {
394                         xml_parse_markup_line_node (node, frame);
395                 } else if (lgl_xml_is_node (node, "Markup-circle")) {
396                         xml_parse_markup_circle_node (node, frame);
397                 } else if (lgl_xml_is_node (node, "Markup-rect")) {
398                         xml_parse_markup_rect_node (node, frame);
399                 } else if (!xmlNodeIsText (node)) {
400                         if (!lgl_xml_is_node (node, "comment")) {
401                                 g_message ("bad node =  \"%s\"",node->name);
402                         }
403                 }
404         }
405
406         g_free (id);
407 }
408
409 /*--------------------------------------------------------------------------*/
410 /* PRIVATE.  Parse XML Template->Label-cd Node.                             */
411 /*--------------------------------------------------------------------------*/
412 static void
413 xml_parse_label_cd_node (xmlNodePtr   label_node,
414                          lglTemplate *template)
415 {
416         gchar               *id;
417         gdouble              waste;
418         gdouble              r1, r2, w, h;
419         lglTemplateFrame    *frame;
420         xmlNodePtr           node;
421
422         id    = lgl_xml_get_prop_string (label_node, "id", NULL);
423         waste = lgl_xml_get_prop_length (label_node, "waste", 0);
424         r1    = lgl_xml_get_prop_length (label_node, "radius", 0);
425         r2    = lgl_xml_get_prop_length (label_node, "hole", 0);
426         w     = lgl_xml_get_prop_length (label_node, "width", 0);
427         h     = lgl_xml_get_prop_length (label_node, "height", 0);
428
429         frame = lgl_template_frame_cd_new ((gchar *)id, r1, r2, w, h, waste);
430         lgl_template_add_frame (template, frame);
431
432         for (node = label_node->xmlChildrenNode; node != NULL;
433              node = node->next) {
434                 if (lgl_xml_is_node (node, "Layout")) {
435                         xml_parse_layout_node (node, frame);
436                 } else if (lgl_xml_is_node (node, "Markup-margin")) {
437                         xml_parse_markup_margin_node (node, frame);
438                 } else if (lgl_xml_is_node (node, "Markup-line")) {
439                         xml_parse_markup_line_node (node, frame);
440                 } else if (lgl_xml_is_node (node, "Markup-circle")) {
441                         xml_parse_markup_circle_node (node, frame);
442                 } else if (lgl_xml_is_node (node, "Markup-rect")) {
443                         xml_parse_markup_rect_node (node, frame);
444                 } else if (!xmlNodeIsText (node)) {
445                         if (!lgl_xml_is_node (node, "comment")) {
446                                 g_message ("bad node =  \"%s\"",node->name);
447                         }
448                 }
449         }
450
451         g_free (id);
452 }
453
454 /*--------------------------------------------------------------------------*/
455 /* PRIVATE.  Parse XML Template->Label->Layout Node.                        */
456 /*--------------------------------------------------------------------------*/
457 static void
458 xml_parse_layout_node (xmlNodePtr          layout_node,
459                        lglTemplateFrame   *frame)
460 {
461         gint        nx, ny;
462         gdouble     x0, y0, dx, dy;
463         xmlNodePtr  node;
464
465         nx = lgl_xml_get_prop_int (layout_node, "nx", 1);
466         ny = lgl_xml_get_prop_int (layout_node, "ny", 1);
467
468         x0 = lgl_xml_get_prop_length (layout_node, "x0", 0);
469         y0 = lgl_xml_get_prop_length (layout_node, "y0", 0);
470
471         dx = lgl_xml_get_prop_length (layout_node, "dx", 0);
472         dy = lgl_xml_get_prop_length (layout_node, "dy", 0);
473
474         lgl_template_frame_add_layout (frame, lgl_template_layout_new (nx, ny, x0, y0, dx, dy));
475
476         for (node = layout_node->xmlChildrenNode; node != NULL;
477              node = node->next) {
478                 if (!xmlNodeIsText (node)) {
479                         if (!lgl_xml_is_node (node, "comment")) {
480                                 g_message ("bad node =  \"%s\"",node->name);
481                         }
482                 }
483         }
484
485 }
486
487 /*--------------------------------------------------------------------------*/
488 /* PRIVATE.  Parse XML Template->Label->Markup-margin Node.                 */
489 /*--------------------------------------------------------------------------*/
490 static void
491 xml_parse_markup_margin_node (xmlNodePtr          markup_node,
492                               lglTemplateFrame   *frame)
493 {
494         gdouble     size;
495         xmlNodePtr  node;
496
497         size = lgl_xml_get_prop_length (markup_node, "size", 0);
498
499         lgl_template_frame_add_markup (frame, lgl_template_markup_margin_new (size));
500
501         for (node = markup_node->xmlChildrenNode; node != NULL;
502              node = node->next) {
503                 if (!xmlNodeIsText (node)) {
504                         if (!lgl_xml_is_node (node, "comment")) {
505                                 g_message ("bad node =  \"%s\"",node->name);
506                         }
507                 }
508         }
509
510 }
511
512 /*--------------------------------------------------------------------------*/
513 /* PRIVATE.  Parse XML Template->Label->Markup-line Node.                   */
514 /*--------------------------------------------------------------------------*/
515 static void
516 xml_parse_markup_line_node (xmlNodePtr          markup_node,
517                             lglTemplateFrame   *frame)
518 {
519         gdouble     x1, y1, x2, y2;
520         xmlNodePtr  node;
521
522         x1 = lgl_xml_get_prop_length (markup_node, "x1", 0);
523         y1 = lgl_xml_get_prop_length (markup_node, "y1", 0);
524         x2 = lgl_xml_get_prop_length (markup_node, "x2", 0);
525         y2 = lgl_xml_get_prop_length (markup_node, "y2", 0);
526
527         lgl_template_frame_add_markup (frame, lgl_template_markup_line_new (x1, y1, x2, y2));
528
529         for (node = markup_node->xmlChildrenNode; node != NULL;
530              node = node->next) {
531                 if (!xmlNodeIsText (node)) {
532                         if (!lgl_xml_is_node (node, "comment")) {
533                                 g_message ("bad node =  \"%s\"",node->name);
534                         }
535                 }
536         }
537
538 }
539
540 /*--------------------------------------------------------------------------*/
541 /* PRIVATE.  Parse XML Template->Label->Markup-circle Node.                 */
542 /*--------------------------------------------------------------------------*/
543 static void
544 xml_parse_markup_circle_node (xmlNodePtr          markup_node,
545                               lglTemplateFrame   *frame)
546 {
547         gdouble     x0, y0, r;
548         xmlNodePtr  node;
549
550         x0 = lgl_xml_get_prop_length (markup_node, "x0", 0);
551         y0 = lgl_xml_get_prop_length (markup_node, "y0", 0);
552         r  = lgl_xml_get_prop_length (markup_node, "radius", 0);
553
554         lgl_template_frame_add_markup (frame, lgl_template_markup_circle_new (x0, y0, r));
555
556         for (node = markup_node->xmlChildrenNode; node != NULL;
557              node = node->next) {
558                 if (!xmlNodeIsText (node)) {
559                         if (!lgl_xml_is_node (node, "comment")) {
560                                 g_message ("bad node =  \"%s\"",node->name);
561                         }
562                 }
563         }
564
565 }
566
567 /*--------------------------------------------------------------------------*/
568 /* PRIVATE.  Parse XML Template->Label->Markup-rect Node.                   */
569 /*--------------------------------------------------------------------------*/
570 static void
571 xml_parse_markup_rect_node (xmlNodePtr          markup_node,
572                             lglTemplateFrame   *frame)
573 {
574         gdouble     x1, y1, w, h, r;
575         xmlNodePtr  node;
576
577         x1 = lgl_xml_get_prop_length (markup_node, "x1", 0);
578         y1 = lgl_xml_get_prop_length (markup_node, "y1", 0);
579         w  = lgl_xml_get_prop_length (markup_node, "w", 0);
580         h  = lgl_xml_get_prop_length (markup_node, "h", 0);
581         r  = lgl_xml_get_prop_length (markup_node, "r", 0);
582
583         lgl_template_frame_add_markup (frame, lgl_template_markup_rect_new (x1, y1, w, h, r));
584
585         for (node = markup_node->xmlChildrenNode; node != NULL;
586              node = node->next) {
587                 if (!xmlNodeIsText (node)) {
588                         if (!lgl_xml_is_node (node, "comment")) {
589                                 g_message ("bad node =  \"%s\"",node->name);
590                         }
591                 }
592         }
593
594 }
595
596 /*--------------------------------------------------------------------------*/
597 /* PRIVATE.  Parse XML Template->Alias Node.                                */
598 /*--------------------------------------------------------------------------*/
599 static void
600 xml_parse_alias_node (xmlNodePtr   alias_node,
601                       lglTemplate *template)
602 {
603         gchar             *brand;
604         gchar             *part;
605         gchar             *name;
606         gchar            **v;
607
608         brand = lgl_xml_get_prop_string (alias_node, "brand", NULL);
609         part  = lgl_xml_get_prop_string (alias_node, "part", NULL);
610         if (!brand || !part)
611         {
612                 name = lgl_xml_get_prop_string (alias_node, "name", NULL);
613                 if (name)
614                 {
615                         g_message (_("Missing required \"brand\" or \"part\" attribute, trying deprecated name."));
616                         v = g_strsplit (name, " ", 2);
617                         brand = g_strdup (v[0]);
618                         part  = g_strdup (v[1]);
619                         g_free (name);
620                         g_strfreev (v);
621                         
622                 }
623                 else
624                 {
625                         g_message (_("Name attribute also missing."));
626                 }
627         }
628
629         lgl_template_add_alias (template, lgl_template_alias_new (brand, part));
630
631         g_free (brand);
632         g_free (part);
633 }
634
635 /**
636  * lgl_xml_template_write_templates_to_file:
637  * @templates:      List of #lglTemplate structures
638  * @utf8_filename:  Filename of templates file (name encoded as UTF-8)
639  *
640  * Write a list of #lglTemplate structures to a glabels XML template file.
641  *
642  * Returns: the number of bytes written or -1 in case of failure
643  *
644  */
645 gint
646 lgl_xml_template_write_templates_to_file (GList       *templates,
647                                           const gchar *utf8_filename)
648 {
649         xmlDocPtr    doc;
650         xmlNsPtr     ns;
651         gint         bytes_written;
652         GList       *p;
653         lglTemplate *template;
654         gchar       *filename;
655
656         doc = xmlNewDoc ((xmlChar *)"1.0");
657         doc->xmlRootNode = xmlNewDocNode (doc, NULL, (xmlChar *)"Glabels-templates", NULL);
658
659         ns = xmlNewNs (doc->xmlRootNode, (xmlChar *)LGL_XML_NAME_SPACE, NULL);
660         xmlSetNs (doc->xmlRootNode, ns);
661
662         for (p=templates; p!=NULL; p=p->next) {
663                 template = (lglTemplate *)p->data;
664                 lgl_xml_template_create_template_node (template, doc->xmlRootNode, ns);
665         }
666
667         filename = g_filename_from_utf8 (utf8_filename, -1, NULL, NULL, NULL);
668         if (!filename)
669         {
670                 g_message (_("Utf8 conversion error."));
671                 return -1;
672         }
673         else
674         {
675                 xmlSetDocCompressMode (doc, 0);
676                 bytes_written = xmlSaveFormatFile (filename, doc, TRUE);
677                 xmlFreeDoc (doc);
678                 g_free (filename);
679                 return bytes_written;
680         }
681
682 }
683
684
685 /**
686  * lgl_xml_template_write_template_to_file:
687  * @template:       #lglTemplate structure to be written
688  * @utf8_filename:  Filename of templates file (name encoded as UTF-8)
689  *
690  * Write a single #lglTemplate structures to a glabels XML template file.
691  *
692  * Returns: the number of bytes written or -1 in case of failure
693  *
694  */
695 gint
696 lgl_xml_template_write_template_to_file (const lglTemplate  *template,
697                                          const gchar        *utf8_filename)
698 {
699         GList     *templates = NULL;
700         gint       bytes_written;
701
702         templates = g_list_append (templates, (gpointer)template);
703
704         bytes_written = lgl_xml_template_write_templates_to_file (templates, utf8_filename);
705
706         g_list_free (templates);
707
708         return bytes_written;
709 }
710
711
712 /**
713  * lgl_xml_template_create_template_node:
714  * @template:       #lglTemplate structure to be written
715  * @root:           parent node to receive new child node
716  * @ns:             a libxml #xmlNsPtr
717  *
718  * Add a single #lglTemplate child node to given #xmlNodePtr.
719  *
720  */
721 void
722 lgl_xml_template_create_template_node (const lglTemplate *template,
723                                        xmlNodePtr         root,
724                                        const xmlNsPtr     ns)
725 {
726         xmlNodePtr          node;
727         GList              *p;
728         lglTemplateAlias   *alias;
729         lglTemplateFrame   *frame;
730
731         node = xmlNewChild (root, ns, (xmlChar *)"Template", NULL);
732
733         lgl_xml_set_prop_string (node, "brand", template->brand);
734         lgl_xml_set_prop_string (node, "part", template->part);
735
736         lgl_xml_set_prop_string (node, "size", template->paper_id);
737         if (xmlStrEqual ((xmlChar *)template->paper_id, (xmlChar *)"Other"))
738         {
739
740                 lgl_xml_set_prop_length (node, "width", template->page_width);
741                 lgl_xml_set_prop_length (node, "height", template->page_height);
742
743         }
744
745         lgl_xml_set_prop_string (node, "description", template->description);
746
747         for ( p=template->aliases; p != NULL; p=p->next ) {
748                 alias = (lglTemplateAlias *)p->data;
749                 if ( !(xmlStrEqual ((xmlChar *)template->brand, (xmlChar *)alias->brand) &&
750                        xmlStrEqual ((xmlChar *)template->part, (xmlChar *)alias->part)) )
751                 {
752                         xml_create_alias_node ( alias, node, ns );
753                 }
754         }
755         for ( p=template->category_ids; p != NULL; p=p->next )
756         {
757                 xml_create_meta_node ( p->data, node, ns );
758         }
759         for ( p=template->frames; p != NULL; p=p->next )
760         {
761                 frame = (lglTemplateFrame *)p->data;
762                 xml_create_label_node (frame, node, ns);
763         }
764
765 }
766
767 /*--------------------------------------------------------------------------*/
768 /* PRIVATE.  Add XML Template->Meta Node.                                   */
769 /*--------------------------------------------------------------------------*/
770 static void
771 xml_create_meta_node (const gchar      *category,
772                       xmlNodePtr        root,
773                       const xmlNsPtr    ns)
774 {
775         xmlNodePtr node;
776
777         node = xmlNewChild (root, ns, (xmlChar *)"Meta", NULL);
778         lgl_xml_set_prop_string (node, "category", category);
779
780 }
781
782 /*--------------------------------------------------------------------------*/
783 /* PRIVATE.  Add XML Template->Label Node.                                  */
784 /*--------------------------------------------------------------------------*/
785 static void
786 xml_create_label_node (const lglTemplateFrame  *frame,
787                        xmlNodePtr               root,
788                        const xmlNsPtr           ns)
789 {
790         xmlNodePtr        node;
791         GList            *p;
792         lglTemplateMarkup *markup;
793         lglTemplateLayout *layout;
794
795         switch (frame->shape) {
796
797         case LGL_TEMPLATE_FRAME_SHAPE_RECT:
798                 node = xmlNewChild(root, ns, (xmlChar *)"Label-rectangle", NULL);
799                 lgl_xml_set_prop_string (node, "id",      frame->all.id);
800                 lgl_xml_set_prop_length (node, "width",   frame->rect.w);
801                 lgl_xml_set_prop_length (node, "height",  frame->rect.h);
802                 lgl_xml_set_prop_length (node, "round",   frame->rect.r);
803                 lgl_xml_set_prop_length (node, "x_waste", frame->rect.x_waste);
804                 lgl_xml_set_prop_length (node, "y_waste", frame->rect.y_waste);
805                 break;
806
807         case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
808                 node = xmlNewChild(root, ns, (xmlChar *)"Label-round", NULL);
809                 lgl_xml_set_prop_string (node, "id",      frame->all.id);
810                 lgl_xml_set_prop_length (node, "radius",  frame->round.r);
811                 lgl_xml_set_prop_length (node, "waste",   frame->round.waste);
812                 break;
813
814         case LGL_TEMPLATE_FRAME_SHAPE_CD:
815                 node = xmlNewChild(root, ns, (xmlChar *)"Label-cd", NULL);
816                 lgl_xml_set_prop_string (node, "id",     frame->all.id);
817                 lgl_xml_set_prop_length (node, "radius", frame->cd.r1);
818                 lgl_xml_set_prop_length (node, "hole",   frame->cd.r2);
819                 if (frame->cd.w != 0.0) {
820                         lgl_xml_set_prop_length (node, "width",  frame->cd.w);
821                 }
822                 if (frame->cd.h != 0.0) {
823                         lgl_xml_set_prop_length (node, "height", frame->cd.h);
824                 }
825                 lgl_xml_set_prop_length (node, "waste",  frame->cd.waste);
826                 break;
827
828         default:
829                 g_message ("Unknown label style");
830                 return;
831                 break;
832
833         }
834
835         for ( p=frame->all.markups; p != NULL; p=p->next ) {
836                 markup = (lglTemplateMarkup *)p->data;
837                 switch (markup->type) {
838                 case LGL_TEMPLATE_MARKUP_MARGIN:
839                         xml_create_markup_margin_node (markup, node, ns);
840                         break;
841                 case LGL_TEMPLATE_MARKUP_LINE:
842                         xml_create_markup_line_node (markup, node, ns);
843                         break;
844                 case LGL_TEMPLATE_MARKUP_CIRCLE:
845                         xml_create_markup_circle_node (markup, node, ns);
846                         break;
847                 case LGL_TEMPLATE_MARKUP_RECT:
848                         xml_create_markup_rect_node (markup, node, ns);
849                         break;
850                 default:
851                         g_message ("Unknown markup type");
852                         break;
853                 }
854         }
855
856         for ( p=frame->all.layouts; p != NULL; p=p->next ) {
857                 layout = (lglTemplateLayout *)p->data;
858                 xml_create_layout_node (layout, node, ns);
859         }
860
861 }
862
863 /*--------------------------------------------------------------------------*/
864 /* PRIVATE.  Add XML Template->Label->Layout Node.                          */
865 /*--------------------------------------------------------------------------*/
866 static void
867 xml_create_layout_node (const lglTemplateLayout *layout,
868                         xmlNodePtr               root,
869                         const xmlNsPtr           ns)
870 {
871         xmlNodePtr  node;
872
873         node = xmlNewChild(root, ns, (xmlChar *)"Layout", NULL);
874         lgl_xml_set_prop_int (node, "nx", layout->nx);
875         lgl_xml_set_prop_int (node, "ny", layout->ny);
876         lgl_xml_set_prop_length (node, "x0", layout->x0);
877         lgl_xml_set_prop_length (node, "y0", layout->y0);
878         lgl_xml_set_prop_length (node, "dx", layout->dx);
879         lgl_xml_set_prop_length (node, "dy", layout->dy);
880
881 }
882
883 /*--------------------------------------------------------------------------*/
884 /* PRIVATE.  Add XML Template->Label->Markup-margin Node.                   */
885 /*--------------------------------------------------------------------------*/
886 static void
887 xml_create_markup_margin_node (const lglTemplateMarkup  *markup,
888                                xmlNodePtr                root,
889                                const xmlNsPtr            ns)
890 {
891         xmlNodePtr  node;
892
893         node = xmlNewChild(root, ns, (xmlChar *)"Markup-margin", NULL);
894
895         lgl_xml_set_prop_length (node, "size", markup->margin.size);
896
897 }
898
899 /*--------------------------------------------------------------------------*/
900 /* PRIVATE.  Add XML Template->Label->Markup-line Node.                     */
901 /*--------------------------------------------------------------------------*/
902 static void
903 xml_create_markup_line_node (const lglTemplateMarkup *markup,
904                              xmlNodePtr               root,
905                              const xmlNsPtr           ns)
906 {
907         xmlNodePtr  node;
908
909         node = xmlNewChild(root, ns, (xmlChar *)"Markup-line", NULL);
910
911         lgl_xml_set_prop_length (node, "x1", markup->line.x1);
912         lgl_xml_set_prop_length (node, "y1", markup->line.y1);
913         lgl_xml_set_prop_length (node, "x2", markup->line.x2);
914         lgl_xml_set_prop_length (node, "y2", markup->line.y2);
915
916 }
917
918 /*--------------------------------------------------------------------------*/
919 /* PRIVATE.  Add XML Template->Label->Markup-circle Node.                   */
920 /*--------------------------------------------------------------------------*/
921 static void
922 xml_create_markup_circle_node (const lglTemplateMarkup *markup,
923                                xmlNodePtr               root,
924                                const xmlNsPtr           ns)
925 {
926         xmlNodePtr  node;
927
928         node = xmlNewChild(root, ns, (xmlChar *)"Markup-circle", NULL);
929
930         lgl_xml_set_prop_length (node, "x0",     markup->circle.x0);
931         lgl_xml_set_prop_length (node, "y0",     markup->circle.y0);
932         lgl_xml_set_prop_length (node, "radius", markup->circle.r);
933
934 }
935
936 /*--------------------------------------------------------------------------*/
937 /* PRIVATE.  Add XML Template->Label->Markup-rect Node.                     */
938 /*--------------------------------------------------------------------------*/
939 static void
940 xml_create_markup_rect_node (const lglTemplateMarkup *markup,
941                              xmlNodePtr               root,
942                              const xmlNsPtr           ns)
943 {
944         xmlNodePtr  node;
945
946         node = xmlNewChild(root, ns, (xmlChar *)"Markup-rect", NULL);
947
948         lgl_xml_set_prop_length (node, "x1", markup->rect.x1);
949         lgl_xml_set_prop_length (node, "y1", markup->rect.y1);
950         lgl_xml_set_prop_length (node, "w",  markup->rect.w);
951         lgl_xml_set_prop_length (node, "h",  markup->rect.h);
952         lgl_xml_set_prop_length (node, "r",  markup->rect.r);
953
954 }
955
956 /*--------------------------------------------------------------------------*/
957 /* PRIVATE.  Add XML Template->Alias Node.                                  */
958 /*--------------------------------------------------------------------------*/
959 static void
960 xml_create_alias_node (const lglTemplateAlias *alias,
961                        xmlNodePtr              root,
962                        const xmlNsPtr          ns)
963 {
964         xmlNodePtr node;
965
966         node = xmlNewChild (root, ns, (xmlChar *)"Alias", NULL);
967
968         lgl_xml_set_prop_string (node, "brand", alias->brand);
969         lgl_xml_set_prop_string (node, "part",  alias->part);
970
971 }
972