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