]> git.sur5r.net Git - glabels/blob - libglabels/xml-template.c
Imported Upstream version 2.2.8
[glabels] / 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         /*
293          * Create a default full-page frame, if a known frame type was not found.
294          */
295         if ( template->frames == NULL )
296         {
297                 lglTemplateFrame    *frame;
298
299                 frame = lgl_template_frame_rect_new ("0", page_width, page_height, 0, 0, 0);
300                 lgl_template_frame_add_layout (frame, lgl_template_layout_new (1, 1, 0, 0, 0, 0));
301                 lgl_template_add_frame (template, frame);
302         }
303
304         return template;
305 }
306
307 /*--------------------------------------------------------------------------*/
308 /* PRIVATE.  Parse XML Template->Meta Node.                                 */
309 /*--------------------------------------------------------------------------*/
310 static void
311 xml_parse_meta_node (xmlNodePtr   meta_node,
312                      lglTemplate *template)
313 {
314         gchar               *category;
315
316         category = lgl_xml_get_prop_string (meta_node, "category", NULL);
317
318         if (category != NULL)
319         {
320                 lgl_template_add_category (template, category);
321                 g_free (category);
322         }
323 }
324
325 /*--------------------------------------------------------------------------*/
326 /* PRIVATE.  Parse XML Template->Label-rectangle Node.                      */
327 /*--------------------------------------------------------------------------*/
328 static void
329 xml_parse_label_rectangle_node (xmlNodePtr   label_node,
330                                 lglTemplate *template)
331 {
332         gchar               *id;
333         gchar               *tmp;
334         gdouble              x_waste, y_waste;
335         gdouble              w, h, r;
336         lglTemplateFrame    *frame;
337         xmlNodePtr           node;
338
339         id      = lgl_xml_get_prop_string (label_node, "id", NULL);
340
341         if ((tmp = lgl_xml_get_prop_string (label_node, "waste", NULL))) {
342                 /* Handle single "waste" property. */
343                 x_waste = y_waste = lgl_xml_get_prop_length (label_node, "waste", 0);
344                 g_free (tmp);
345         } else {
346                 x_waste = lgl_xml_get_prop_length (label_node, "x_waste", 0);
347                 y_waste = lgl_xml_get_prop_length (label_node, "y_waste", 0);
348         }
349
350         w       = lgl_xml_get_prop_length (label_node, "width", 0);
351         h       = lgl_xml_get_prop_length (label_node, "height", 0);
352         r       = lgl_xml_get_prop_length (label_node, "round", 0);
353
354         frame = lgl_template_frame_rect_new ((gchar *)id, w, h, r, x_waste, y_waste);
355         lgl_template_add_frame (template, frame);
356
357         for (node = label_node->xmlChildrenNode; node != NULL;
358              node = node->next) {
359                 if (lgl_xml_is_node (node, "Layout")) {
360                         xml_parse_layout_node (node, frame);
361                 } else if (lgl_xml_is_node (node, "Markup-margin")) {
362                         xml_parse_markup_margin_node (node, frame);
363                 } else if (lgl_xml_is_node (node, "Markup-line")) {
364                         xml_parse_markup_line_node (node, frame);
365                 } else if (lgl_xml_is_node (node, "Markup-circle")) {
366                         xml_parse_markup_circle_node (node, frame);
367                 } else if (lgl_xml_is_node (node, "Markup-rect")) {
368                         xml_parse_markup_rect_node (node, frame);
369                 } else if (!xmlNodeIsText (node)) {
370                         if (!lgl_xml_is_node (node, "comment")) {
371                                 g_message ("bad node =  \"%s\"",node->name);
372                         }
373                 }
374         }
375
376         g_free (id);
377 }
378
379 /*--------------------------------------------------------------------------*/
380 /* PRIVATE.  Parse XML Template->Label-round Node.                          */
381 /*--------------------------------------------------------------------------*/
382 static void
383 xml_parse_label_round_node (xmlNodePtr   label_node,
384                             lglTemplate *template)
385 {
386         gchar               *id;
387         gdouble              waste;
388         gdouble              r;
389         lglTemplateFrame    *frame;
390         xmlNodePtr           node;
391
392         id    = lgl_xml_get_prop_string (label_node, "id", NULL);
393         waste = lgl_xml_get_prop_length (label_node, "waste", 0);
394         r     = lgl_xml_get_prop_length (label_node, "radius", 0);
395
396         frame = lgl_template_frame_round_new ((gchar *)id, r, waste);
397         lgl_template_add_frame (template, frame);
398
399         for (node = label_node->xmlChildrenNode; node != NULL;
400              node = node->next) {
401                 if (lgl_xml_is_node (node, "Layout")) {
402                         xml_parse_layout_node (node, frame);
403                 } else if (lgl_xml_is_node (node, "Markup-margin")) {
404                         xml_parse_markup_margin_node (node, frame);
405                 } else if (lgl_xml_is_node (node, "Markup-line")) {
406                         xml_parse_markup_line_node (node, frame);
407                 } else if (lgl_xml_is_node (node, "Markup-circle")) {
408                         xml_parse_markup_circle_node (node, frame);
409                 } else if (lgl_xml_is_node (node, "Markup-rect")) {
410                         xml_parse_markup_rect_node (node, frame);
411                 } else if (!xmlNodeIsText (node)) {
412                         if (!lgl_xml_is_node (node, "comment")) {
413                                 g_message ("bad node =  \"%s\"",node->name);
414                         }
415                 }
416         }
417
418         g_free (id);
419 }
420
421 /*--------------------------------------------------------------------------*/
422 /* PRIVATE.  Parse XML Template->Label-cd Node.                             */
423 /*--------------------------------------------------------------------------*/
424 static void
425 xml_parse_label_cd_node (xmlNodePtr   label_node,
426                          lglTemplate *template)
427 {
428         gchar               *id;
429         gdouble              waste;
430         gdouble              r1, r2, w, h;
431         lglTemplateFrame    *frame;
432         xmlNodePtr           node;
433
434         id    = lgl_xml_get_prop_string (label_node, "id", NULL);
435         waste = lgl_xml_get_prop_length (label_node, "waste", 0);
436         r1    = lgl_xml_get_prop_length (label_node, "radius", 0);
437         r2    = lgl_xml_get_prop_length (label_node, "hole", 0);
438         w     = lgl_xml_get_prop_length (label_node, "width", 0);
439         h     = lgl_xml_get_prop_length (label_node, "height", 0);
440
441         frame = lgl_template_frame_cd_new ((gchar *)id, r1, r2, w, h, waste);
442         lgl_template_add_frame (template, frame);
443
444         for (node = label_node->xmlChildrenNode; node != NULL;
445              node = node->next) {
446                 if (lgl_xml_is_node (node, "Layout")) {
447                         xml_parse_layout_node (node, frame);
448                 } else if (lgl_xml_is_node (node, "Markup-margin")) {
449                         xml_parse_markup_margin_node (node, frame);
450                 } else if (lgl_xml_is_node (node, "Markup-line")) {
451                         xml_parse_markup_line_node (node, frame);
452                 } else if (lgl_xml_is_node (node, "Markup-circle")) {
453                         xml_parse_markup_circle_node (node, frame);
454                 } else if (lgl_xml_is_node (node, "Markup-rect")) {
455                         xml_parse_markup_rect_node (node, frame);
456                 } else if (!xmlNodeIsText (node)) {
457                         if (!lgl_xml_is_node (node, "comment")) {
458                                 g_message ("bad node =  \"%s\"",node->name);
459                         }
460                 }
461         }
462
463         g_free (id);
464 }
465
466 /*--------------------------------------------------------------------------*/
467 /* PRIVATE.  Parse XML Template->Label->Layout Node.                        */
468 /*--------------------------------------------------------------------------*/
469 static void
470 xml_parse_layout_node (xmlNodePtr          layout_node,
471                        lglTemplateFrame   *frame)
472 {
473         gint        nx, ny;
474         gdouble     x0, y0, dx, dy;
475         xmlNodePtr  node;
476
477         nx = lgl_xml_get_prop_int (layout_node, "nx", 1);
478         ny = lgl_xml_get_prop_int (layout_node, "ny", 1);
479
480         x0 = lgl_xml_get_prop_length (layout_node, "x0", 0);
481         y0 = lgl_xml_get_prop_length (layout_node, "y0", 0);
482
483         dx = lgl_xml_get_prop_length (layout_node, "dx", 0);
484         dy = lgl_xml_get_prop_length (layout_node, "dy", 0);
485
486         lgl_template_frame_add_layout (frame, lgl_template_layout_new (nx, ny, x0, y0, dx, dy));
487
488         for (node = layout_node->xmlChildrenNode; node != NULL;
489              node = node->next) {
490                 if (!xmlNodeIsText (node)) {
491                         if (!lgl_xml_is_node (node, "comment")) {
492                                 g_message ("bad node =  \"%s\"",node->name);
493                         }
494                 }
495         }
496
497 }
498
499 /*--------------------------------------------------------------------------*/
500 /* PRIVATE.  Parse XML Template->Label->Markup-margin Node.                 */
501 /*--------------------------------------------------------------------------*/
502 static void
503 xml_parse_markup_margin_node (xmlNodePtr          markup_node,
504                               lglTemplateFrame   *frame)
505 {
506         gdouble     size;
507         xmlNodePtr  node;
508
509         size = lgl_xml_get_prop_length (markup_node, "size", 0);
510
511         lgl_template_frame_add_markup (frame, lgl_template_markup_margin_new (size));
512
513         for (node = markup_node->xmlChildrenNode; node != NULL;
514              node = node->next) {
515                 if (!xmlNodeIsText (node)) {
516                         if (!lgl_xml_is_node (node, "comment")) {
517                                 g_message ("bad node =  \"%s\"",node->name);
518                         }
519                 }
520         }
521
522 }
523
524 /*--------------------------------------------------------------------------*/
525 /* PRIVATE.  Parse XML Template->Label->Markup-line Node.                   */
526 /*--------------------------------------------------------------------------*/
527 static void
528 xml_parse_markup_line_node (xmlNodePtr          markup_node,
529                             lglTemplateFrame   *frame)
530 {
531         gdouble     x1, y1, x2, y2;
532         xmlNodePtr  node;
533
534         x1 = lgl_xml_get_prop_length (markup_node, "x1", 0);
535         y1 = lgl_xml_get_prop_length (markup_node, "y1", 0);
536         x2 = lgl_xml_get_prop_length (markup_node, "x2", 0);
537         y2 = lgl_xml_get_prop_length (markup_node, "y2", 0);
538
539         lgl_template_frame_add_markup (frame, lgl_template_markup_line_new (x1, y1, x2, y2));
540
541         for (node = markup_node->xmlChildrenNode; node != NULL;
542              node = node->next) {
543                 if (!xmlNodeIsText (node)) {
544                         if (!lgl_xml_is_node (node, "comment")) {
545                                 g_message ("bad node =  \"%s\"",node->name);
546                         }
547                 }
548         }
549
550 }
551
552 /*--------------------------------------------------------------------------*/
553 /* PRIVATE.  Parse XML Template->Label->Markup-circle Node.                 */
554 /*--------------------------------------------------------------------------*/
555 static void
556 xml_parse_markup_circle_node (xmlNodePtr          markup_node,
557                               lglTemplateFrame   *frame)
558 {
559         gdouble     x0, y0, r;
560         xmlNodePtr  node;
561
562         x0 = lgl_xml_get_prop_length (markup_node, "x0", 0);
563         y0 = lgl_xml_get_prop_length (markup_node, "y0", 0);
564         r  = lgl_xml_get_prop_length (markup_node, "radius", 0);
565
566         lgl_template_frame_add_markup (frame, lgl_template_markup_circle_new (x0, y0, r));
567
568         for (node = markup_node->xmlChildrenNode; node != NULL;
569              node = node->next) {
570                 if (!xmlNodeIsText (node)) {
571                         if (!lgl_xml_is_node (node, "comment")) {
572                                 g_message ("bad node =  \"%s\"",node->name);
573                         }
574                 }
575         }
576
577 }
578
579 /*--------------------------------------------------------------------------*/
580 /* PRIVATE.  Parse XML Template->Label->Markup-rect Node.                   */
581 /*--------------------------------------------------------------------------*/
582 static void
583 xml_parse_markup_rect_node (xmlNodePtr          markup_node,
584                             lglTemplateFrame   *frame)
585 {
586         gdouble     x1, y1, w, h, r;
587         xmlNodePtr  node;
588
589         x1 = lgl_xml_get_prop_length (markup_node, "x1", 0);
590         y1 = lgl_xml_get_prop_length (markup_node, "y1", 0);
591         w  = lgl_xml_get_prop_length (markup_node, "w", 0);
592         h  = lgl_xml_get_prop_length (markup_node, "h", 0);
593         r  = lgl_xml_get_prop_length (markup_node, "r", 0);
594
595         lgl_template_frame_add_markup (frame, lgl_template_markup_rect_new (x1, y1, w, h, r));
596
597         for (node = markup_node->xmlChildrenNode; node != NULL;
598              node = node->next) {
599                 if (!xmlNodeIsText (node)) {
600                         if (!lgl_xml_is_node (node, "comment")) {
601                                 g_message ("bad node =  \"%s\"",node->name);
602                         }
603                 }
604         }
605
606 }
607
608 /*--------------------------------------------------------------------------*/
609 /* PRIVATE.  Parse XML Template->Alias Node.                                */
610 /*--------------------------------------------------------------------------*/
611 static void
612 xml_parse_alias_node (xmlNodePtr   alias_node,
613                       lglTemplate *template)
614 {
615         gchar             *brand;
616         gchar             *part;
617         gchar             *name;
618         gchar            **v;
619
620         brand = lgl_xml_get_prop_string (alias_node, "brand", NULL);
621         part  = lgl_xml_get_prop_string (alias_node, "part", NULL);
622         if (!brand || !part)
623         {
624                 name = lgl_xml_get_prop_string (alias_node, "name", NULL);
625                 if (name)
626                 {
627                         g_message (_("Missing required \"brand\" or \"part\" attribute, trying deprecated name."));
628                         v = g_strsplit (name, " ", 2);
629                         brand = g_strdup (v[0]);
630                         part  = g_strdup (v[1]);
631                         g_free (name);
632                         g_strfreev (v);
633                         
634                 }
635                 else
636                 {
637                         g_message (_("Name attribute also missing."));
638                 }
639         }
640
641         lgl_template_add_alias (template, lgl_template_alias_new (brand, part));
642
643         g_free (brand);
644         g_free (part);
645 }
646
647 /**
648  * lgl_xml_template_write_templates_to_file:
649  * @templates:      List of #lglTemplate structures
650  * @utf8_filename:  Filename of templates file (name encoded as UTF-8)
651  *
652  * Write a list of #lglTemplate structures to a glabels XML template file.
653  *
654  * Returns: the number of bytes written or -1 in case of failure
655  *
656  */
657 gint
658 lgl_xml_template_write_templates_to_file (GList       *templates,
659                                           const gchar *utf8_filename)
660 {
661         xmlDocPtr    doc;
662         xmlNsPtr     ns;
663         gint         bytes_written;
664         GList       *p;
665         lglTemplate *template;
666         gchar       *filename;
667
668         doc = xmlNewDoc ((xmlChar *)"1.0");
669         doc->xmlRootNode = xmlNewDocNode (doc, NULL, (xmlChar *)"Glabels-templates", NULL);
670
671         ns = xmlNewNs (doc->xmlRootNode, (xmlChar *)LGL_XML_NAME_SPACE, NULL);
672         xmlSetNs (doc->xmlRootNode, ns);
673
674         for (p=templates; p!=NULL; p=p->next) {
675                 template = (lglTemplate *)p->data;
676                 lgl_xml_template_create_template_node (template, doc->xmlRootNode, ns);
677         }
678
679         filename = g_filename_from_utf8 (utf8_filename, -1, NULL, NULL, NULL);
680         if (!filename)
681         {
682                 g_message (_("Utf8 conversion error."));
683                 return -1;
684         }
685         else
686         {
687                 xmlSetDocCompressMode (doc, 0);
688                 bytes_written = xmlSaveFormatFile (filename, doc, TRUE);
689                 xmlFreeDoc (doc);
690                 g_free (filename);
691                 return bytes_written;
692         }
693
694 }
695
696
697 /**
698  * lgl_xml_template_write_template_to_file:
699  * @template:       #lglTemplate structure to be written
700  * @utf8_filename:  Filename of templates file (name encoded as UTF-8)
701  *
702  * Write a single #lglTemplate structures to a glabels XML template file.
703  *
704  * Returns: the number of bytes written or -1 in case of failure
705  *
706  */
707 gint
708 lgl_xml_template_write_template_to_file (const lglTemplate  *template,
709                                          const gchar        *utf8_filename)
710 {
711         GList     *templates = NULL;
712         gint       bytes_written;
713
714         templates = g_list_append (templates, (gpointer)template);
715
716         bytes_written = lgl_xml_template_write_templates_to_file (templates, utf8_filename);
717
718         g_list_free (templates);
719
720         return bytes_written;
721 }
722
723
724 /**
725  * lgl_xml_template_create_template_node:
726  * @template:       #lglTemplate structure to be written
727  * @root:           parent node to receive new child node
728  * @ns:             a libxml #xmlNsPtr
729  *
730  * Add a single #lglTemplate child node to given #xmlNodePtr.
731  *
732  */
733 void
734 lgl_xml_template_create_template_node (const lglTemplate *template,
735                                        xmlNodePtr         root,
736                                        const xmlNsPtr     ns)
737 {
738         xmlNodePtr          node;
739         GList              *p;
740         lglTemplateAlias   *alias;
741         lglTemplateFrame   *frame;
742
743         node = xmlNewChild (root, ns, (xmlChar *)"Template", NULL);
744
745         lgl_xml_set_prop_string (node, "brand", template->brand);
746         lgl_xml_set_prop_string (node, "part", template->part);
747
748         lgl_xml_set_prop_string (node, "size", template->paper_id);
749         if (xmlStrEqual ((xmlChar *)template->paper_id, (xmlChar *)"Other"))
750         {
751
752                 lgl_xml_set_prop_length (node, "width", template->page_width);
753                 lgl_xml_set_prop_length (node, "height", template->page_height);
754
755         }
756
757         lgl_xml_set_prop_string (node, "description", template->description);
758
759         for ( p=template->aliases; p != NULL; p=p->next ) {
760                 alias = (lglTemplateAlias *)p->data;
761                 if ( !(xmlStrEqual ((xmlChar *)template->brand, (xmlChar *)alias->brand) &&
762                        xmlStrEqual ((xmlChar *)template->part, (xmlChar *)alias->part)) )
763                 {
764                         xml_create_alias_node ( alias, node, ns );
765                 }
766         }
767         for ( p=template->category_ids; p != NULL; p=p->next )
768         {
769                 xml_create_meta_node ( p->data, node, ns );
770         }
771         for ( p=template->frames; p != NULL; p=p->next )
772         {
773                 frame = (lglTemplateFrame *)p->data;
774                 xml_create_label_node (frame, node, ns);
775         }
776
777 }
778
779 /*--------------------------------------------------------------------------*/
780 /* PRIVATE.  Add XML Template->Meta Node.                                   */
781 /*--------------------------------------------------------------------------*/
782 static void
783 xml_create_meta_node (const gchar      *category,
784                       xmlNodePtr        root,
785                       const xmlNsPtr    ns)
786 {
787         xmlNodePtr node;
788
789         node = xmlNewChild (root, ns, (xmlChar *)"Meta", NULL);
790         lgl_xml_set_prop_string (node, "category", category);
791
792 }
793
794 /*--------------------------------------------------------------------------*/
795 /* PRIVATE.  Add XML Template->Label Node.                                  */
796 /*--------------------------------------------------------------------------*/
797 static void
798 xml_create_label_node (const lglTemplateFrame  *frame,
799                        xmlNodePtr               root,
800                        const xmlNsPtr           ns)
801 {
802         xmlNodePtr        node;
803         GList            *p;
804         lglTemplateMarkup *markup;
805         lglTemplateLayout *layout;
806
807         switch (frame->shape) {
808
809         case LGL_TEMPLATE_FRAME_SHAPE_RECT:
810                 node = xmlNewChild(root, ns, (xmlChar *)"Label-rectangle", NULL);
811                 lgl_xml_set_prop_string (node, "id",      frame->all.id);
812                 lgl_xml_set_prop_length (node, "width",   frame->rect.w);
813                 lgl_xml_set_prop_length (node, "height",  frame->rect.h);
814                 lgl_xml_set_prop_length (node, "round",   frame->rect.r);
815                 lgl_xml_set_prop_length (node, "x_waste", frame->rect.x_waste);
816                 lgl_xml_set_prop_length (node, "y_waste", frame->rect.y_waste);
817                 break;
818
819         case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
820                 node = xmlNewChild(root, ns, (xmlChar *)"Label-round", NULL);
821                 lgl_xml_set_prop_string (node, "id",      frame->all.id);
822                 lgl_xml_set_prop_length (node, "radius",  frame->round.r);
823                 lgl_xml_set_prop_length (node, "waste",   frame->round.waste);
824                 break;
825
826         case LGL_TEMPLATE_FRAME_SHAPE_CD:
827                 node = xmlNewChild(root, ns, (xmlChar *)"Label-cd", NULL);
828                 lgl_xml_set_prop_string (node, "id",     frame->all.id);
829                 lgl_xml_set_prop_length (node, "radius", frame->cd.r1);
830                 lgl_xml_set_prop_length (node, "hole",   frame->cd.r2);
831                 if (frame->cd.w != 0.0) {
832                         lgl_xml_set_prop_length (node, "width",  frame->cd.w);
833                 }
834                 if (frame->cd.h != 0.0) {
835                         lgl_xml_set_prop_length (node, "height", frame->cd.h);
836                 }
837                 lgl_xml_set_prop_length (node, "waste",  frame->cd.waste);
838                 break;
839
840         default:
841                 g_message ("Unknown label style");
842                 return;
843                 break;
844
845         }
846
847         for ( p=frame->all.markups; p != NULL; p=p->next ) {
848                 markup = (lglTemplateMarkup *)p->data;
849                 switch (markup->type) {
850                 case LGL_TEMPLATE_MARKUP_MARGIN:
851                         xml_create_markup_margin_node (markup, node, ns);
852                         break;
853                 case LGL_TEMPLATE_MARKUP_LINE:
854                         xml_create_markup_line_node (markup, node, ns);
855                         break;
856                 case LGL_TEMPLATE_MARKUP_CIRCLE:
857                         xml_create_markup_circle_node (markup, node, ns);
858                         break;
859                 case LGL_TEMPLATE_MARKUP_RECT:
860                         xml_create_markup_rect_node (markup, node, ns);
861                         break;
862                 default:
863                         g_message ("Unknown markup type");
864                         break;
865                 }
866         }
867
868         for ( p=frame->all.layouts; p != NULL; p=p->next ) {
869                 layout = (lglTemplateLayout *)p->data;
870                 xml_create_layout_node (layout, node, ns);
871         }
872
873 }
874
875 /*--------------------------------------------------------------------------*/
876 /* PRIVATE.  Add XML Template->Label->Layout Node.                          */
877 /*--------------------------------------------------------------------------*/
878 static void
879 xml_create_layout_node (const lglTemplateLayout *layout,
880                         xmlNodePtr               root,
881                         const xmlNsPtr           ns)
882 {
883         xmlNodePtr  node;
884
885         node = xmlNewChild(root, ns, (xmlChar *)"Layout", NULL);
886         lgl_xml_set_prop_int (node, "nx", layout->nx);
887         lgl_xml_set_prop_int (node, "ny", layout->ny);
888         lgl_xml_set_prop_length (node, "x0", layout->x0);
889         lgl_xml_set_prop_length (node, "y0", layout->y0);
890         lgl_xml_set_prop_length (node, "dx", layout->dx);
891         lgl_xml_set_prop_length (node, "dy", layout->dy);
892
893 }
894
895 /*--------------------------------------------------------------------------*/
896 /* PRIVATE.  Add XML Template->Label->Markup-margin Node.                   */
897 /*--------------------------------------------------------------------------*/
898 static void
899 xml_create_markup_margin_node (const lglTemplateMarkup  *markup,
900                                xmlNodePtr                root,
901                                const xmlNsPtr            ns)
902 {
903         xmlNodePtr  node;
904
905         node = xmlNewChild(root, ns, (xmlChar *)"Markup-margin", NULL);
906
907         lgl_xml_set_prop_length (node, "size", markup->margin.size);
908
909 }
910
911 /*--------------------------------------------------------------------------*/
912 /* PRIVATE.  Add XML Template->Label->Markup-line Node.                     */
913 /*--------------------------------------------------------------------------*/
914 static void
915 xml_create_markup_line_node (const lglTemplateMarkup *markup,
916                              xmlNodePtr               root,
917                              const xmlNsPtr           ns)
918 {
919         xmlNodePtr  node;
920
921         node = xmlNewChild(root, ns, (xmlChar *)"Markup-line", NULL);
922
923         lgl_xml_set_prop_length (node, "x1", markup->line.x1);
924         lgl_xml_set_prop_length (node, "y1", markup->line.y1);
925         lgl_xml_set_prop_length (node, "x2", markup->line.x2);
926         lgl_xml_set_prop_length (node, "y2", markup->line.y2);
927
928 }
929
930 /*--------------------------------------------------------------------------*/
931 /* PRIVATE.  Add XML Template->Label->Markup-circle Node.                   */
932 /*--------------------------------------------------------------------------*/
933 static void
934 xml_create_markup_circle_node (const lglTemplateMarkup *markup,
935                                xmlNodePtr               root,
936                                const xmlNsPtr           ns)
937 {
938         xmlNodePtr  node;
939
940         node = xmlNewChild(root, ns, (xmlChar *)"Markup-circle", NULL);
941
942         lgl_xml_set_prop_length (node, "x0",     markup->circle.x0);
943         lgl_xml_set_prop_length (node, "y0",     markup->circle.y0);
944         lgl_xml_set_prop_length (node, "radius", markup->circle.r);
945
946 }
947
948 /*--------------------------------------------------------------------------*/
949 /* PRIVATE.  Add XML Template->Label->Markup-rect Node.                     */
950 /*--------------------------------------------------------------------------*/
951 static void
952 xml_create_markup_rect_node (const lglTemplateMarkup *markup,
953                              xmlNodePtr               root,
954                              const xmlNsPtr           ns)
955 {
956         xmlNodePtr  node;
957
958         node = xmlNewChild(root, ns, (xmlChar *)"Markup-rect", NULL);
959
960         lgl_xml_set_prop_length (node, "x1", markup->rect.x1);
961         lgl_xml_set_prop_length (node, "y1", markup->rect.y1);
962         lgl_xml_set_prop_length (node, "w",  markup->rect.w);
963         lgl_xml_set_prop_length (node, "h",  markup->rect.h);
964         lgl_xml_set_prop_length (node, "r",  markup->rect.r);
965
966 }
967
968 /*--------------------------------------------------------------------------*/
969 /* PRIVATE.  Add XML Template->Alias Node.                                  */
970 /*--------------------------------------------------------------------------*/
971 static void
972 xml_create_alias_node (const lglTemplateAlias *alias,
973                        xmlNodePtr              root,
974                        const xmlNsPtr          ns)
975 {
976         xmlNodePtr node;
977
978         node = xmlNewChild (root, ns, (xmlChar *)"Alias", NULL);
979
980         lgl_xml_set_prop_string (node, "brand", alias->brand);
981         lgl_xml_set_prop_string (node, "part",  alias->part);
982
983 }
984