]> git.sur5r.net Git - glabels/blob - glabels2/libglabels/template.c
2007-09-27 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / libglabels / 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  *  template.c:  template 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 "template.h"
30
31 #include <glib/gi18n.h>
32 #include <glib/gmem.h>
33 #include <glib/gstrfuncs.h>
34 #include <glib/gdir.h>
35 #include <glib/gmessages.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39
40 #include "libglabels-private.h"
41 #include "xml.h"
42 #include "xml-template.h"
43 #include "paper.h"
44
45 #define FULL_PAGE "Full-page"
46
47 /*===========================================*/
48 /* Private types                             */
49 /*===========================================*/
50
51 /*===========================================*/
52 /* Private globals                           */
53 /*===========================================*/
54
55 static GList *templates = NULL;
56
57 /*===========================================*/
58 /* Local function prototypes                 */
59 /*===========================================*/
60 static lglTemplate *template_full_page           (const gchar            *page_size);
61
62 static GList       *read_templates               (void);
63
64 static GList       *read_template_files_from_dir (GList                  *templates,
65                                                   const gchar            *dirname);
66
67 static gint         compare_origins              (gconstpointer           a,
68                                                   gconstpointer           b,
69                                                   gpointer                user_data);
70
71 /*****************************************************************************/
72 /* Initialize module.                                                        */
73 /*****************************************************************************/
74 void
75 lgl_template_init (void)
76 {
77         GList *page_sizes, *p;
78
79         if (templates) {
80                 return; /* Already initialized */
81         }
82
83         templates = read_templates ();
84
85         page_sizes = lgl_paper_get_id_list ();
86         for ( p=page_sizes; p != NULL; p=p->next ) {
87                 if ( !lgl_paper_is_id_other (p->data) ) {
88                         templates = g_list_append (templates,
89                                                    template_full_page (p->data));
90                 }
91         }
92         lgl_paper_free_id_list (page_sizes);
93 }
94
95 /*****************************************************************************/
96 /* Register template: if not in current list, add it.                        */
97 /*****************************************************************************/
98 void
99 lgl_template_register (const lglTemplate  *template)
100 {
101         GList       *p_tmplt, *pa1;
102         lglTemplate *template1;
103
104         if (!templates) {
105                 lgl_template_init ();
106         }
107
108         for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) {
109                 template1 = (lglTemplate *) p_tmplt->data;
110
111                 for (pa1=template1->aliases; pa1!=NULL; pa1=pa1->next) {
112                         
113                         if (g_strcasecmp (template->name, pa1->data) == 0) {
114
115                                 /* FIXME: make sure templates are really identical */
116                                 /*        if not, apply hash to name to make unique. */
117                                 return;
118                         }
119                                 
120                 }
121
122         }
123
124         if (lgl_paper_is_id_known (template->page_size)) {
125
126                 gchar *dir, *filename, *abs_filename;
127
128                 templates = g_list_append (templates,
129                                            lgl_template_dup (template));
130
131                 /* FIXME: make sure filename is unique */
132                 dir = LGL_USER_DATA_DIR;
133                 mkdir (dir, 0775); /* Try to make sure directory exists. */
134                 filename = g_strconcat (template->name, ".template", NULL);
135                 abs_filename = g_build_filename (dir, filename, NULL);
136                 lgl_xml_template_write_template_to_file (template, abs_filename);
137                 g_free (dir);
138                 g_free (filename);
139                 g_free (abs_filename);
140
141         } else {
142                 g_message ("Cannot register new template with unknown page size.");
143         }
144
145 }
146
147 /*********************************************************************************/
148 /* Get a list of valid names of unique templates for given page size             */
149 /*********************************************************************************/
150 GList *
151 lgl_template_get_name_list_unique (const gchar *page_size,
152                                    const gchar *category)
153 {
154         GList       *p_tmplt;
155         lglTemplate *template;
156         GList       *names = NULL;
157
158         if (!templates)
159         {
160                 lgl_template_init ();
161         }
162
163         for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next)
164         {
165                 template = (lglTemplate *) p_tmplt->data;
166                 if (lgl_template_does_page_size_match (template, page_size) &&
167                     lgl_template_does_category_match (template, category))
168                 {
169                         names = g_list_insert_sorted (names, g_strdup (template->name),
170                                                       (GCompareFunc)g_strcasecmp);
171                 }
172         }
173
174         return names;
175 }
176
177 /*********************************************************************************/
178 /* Get a list of all valid template names for given page size (includes aliases) */
179 /*********************************************************************************/
180 GList *
181 lgl_template_get_name_list_all (const gchar *page_size,
182                                 const gchar *category)
183 {
184         GList       *p_tmplt, *p_alias;
185         lglTemplate *template;
186         gchar       *str;
187         GList       *names = NULL;
188
189         if (!templates)
190         {
191                 lgl_template_init ();
192         }
193
194         for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next)
195         {
196                 template = (lglTemplate *) p_tmplt->data;
197                 if (lgl_template_does_page_size_match (template, page_size) &&
198                     lgl_template_does_category_match (template, category))
199                 {
200                         for (p_alias = template->aliases; p_alias != NULL;
201                              p_alias = p_alias->next)
202                         {
203                                 str = g_strdup ((gchar *) p_alias->data);
204                                 names = g_list_insert_sorted (names, str,
205                                                              (GCompareFunc)g_strcasecmp);
206                         }
207                 }
208         }
209
210         return names;
211 }
212
213 /*****************************************************************************/
214 /* Free a list of template names.                                            */
215 /*****************************************************************************/
216 void
217 lgl_template_free_name_list (GList *names)
218 {
219         GList *p_name;
220
221         for (p_name = names; p_name != NULL; p_name = p_name->next) {
222                 g_free (p_name->data);
223                 p_name->data = NULL;
224         }
225
226         g_list_free (names);
227 }
228
229 /*****************************************************************************/
230 /* Return a template structure from a name.                                  */
231 /*****************************************************************************/
232 lglTemplate *
233 lgl_template_from_name (const gchar *name)
234 {
235         GList        *p_tmplt, *p_alias;
236         lglTemplate  *template;
237
238         if (!templates) {
239                 lgl_template_init ();
240         }
241
242         if (name == NULL) {
243                 /* If no name, return first template as a default */
244                 return lgl_template_dup ((lglTemplate *) templates->data);
245         }
246
247         for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) {
248                 template = (lglTemplate *) p_tmplt->data;
249                 for (p_alias = template->aliases; p_alias != NULL;
250                      p_alias = p_alias->next) {
251                         if (g_strcasecmp (p_alias->data, name) == 0) {
252
253                                 return lgl_template_dup (template);
254                         }
255                 }
256         }
257
258         /* No matching template has been found so return the first template */
259         return lgl_template_dup ((lglTemplate *) templates->data);
260 }
261
262 /*****************************************************************************/
263 /* Get first label type in template.                                         */
264 /*****************************************************************************/
265 const lglTemplateFrame *
266 lgl_template_get_first_frame (const lglTemplate *template)
267 {
268         g_return_val_if_fail (template, NULL);
269
270         return (lglTemplateFrame *)template->frames->data;
271 }
272
273 /****************************************************************************/
274 /* Get raw label size (width and height).                                   */
275 /****************************************************************************/
276 void
277 lgl_template_frame_get_size (const lglTemplateFrame *frame,
278                              gdouble                *w,
279                              gdouble                *h)
280 {
281         g_return_if_fail (frame);
282
283         switch (frame->shape) {
284         case LGL_TEMPLATE_FRAME_SHAPE_RECT:
285                 *w = frame->rect.w;
286                 *h = frame->rect.h;
287                 break;
288         case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
289                 *w = 2.0 * frame->round.r;
290                 *h = 2.0 * frame->round.r;
291                 break;
292         case LGL_TEMPLATE_FRAME_SHAPE_CD:
293                 if (frame->cd.w == 0.0) {
294                         *w = 2.0 * frame->cd.r1;
295                 } else {
296                         *w = frame->cd.w;
297                 }
298                 if (frame->cd.h == 0.0) {
299                         *h = 2.0 * frame->cd.r1;
300                 } else {
301                         *h = frame->cd.h;
302                 }
303                 break;
304         default:
305                 *w = 0.0;
306                 *h = 0.0;
307                 break;
308         }
309 }
310
311 /****************************************************************************/
312 /* Get total number of labels per sheet of a label type.                    */
313 /****************************************************************************/
314 gint
315 lgl_template_frame_get_n_labels (const lglTemplateFrame *frame)
316 {
317         gint               n_labels = 0;
318         GList             *p;
319         lglTemplateLayout *layout;
320
321         g_return_val_if_fail (frame, 0);
322
323         for ( p=frame->all.layouts; p != NULL; p=p->next ) {
324                 layout = (lglTemplateLayout *)p->data;
325
326                 n_labels += layout->nx * layout->ny;
327         }
328
329         return n_labels;
330 }
331
332 /****************************************************************************/
333 /* Get array of origins of individual labels.                               */
334 /****************************************************************************/
335 lglTemplateOrigin *
336 lgl_template_frame_get_origins (const lglTemplateFrame *frame)
337 {
338         gint               i_label, n_labels, ix, iy;
339         lglTemplateOrigin *origins;
340         GList             *p;
341         lglTemplateLayout *layout;
342
343         g_return_val_if_fail (frame, NULL);
344
345         n_labels = lgl_template_frame_get_n_labels (frame);
346         origins = g_new0 (lglTemplateOrigin, n_labels);
347
348         i_label = 0;
349         for ( p=frame->all.layouts; p != NULL; p=p->next ) {
350                 layout = (lglTemplateLayout *)p->data;
351
352                 for (iy = 0; iy < layout->ny; iy++) {
353                         for (ix = 0; ix < layout->nx; ix++, i_label++) {
354                                 origins[i_label].x = ix*layout->dx + layout->x0;
355                                 origins[i_label].y = iy*layout->dy + layout->y0;
356                         }
357                 }
358         }
359
360         g_qsort_with_data (origins, n_labels, sizeof(lglTemplateOrigin),
361                            compare_origins, NULL);
362
363         return origins;
364 }
365
366 /*****************************************************************************/
367 /* Create a new template with given properties.                              */
368 /*****************************************************************************/
369 lglTemplate *
370 lgl_template_new (const gchar         *name,
371                   const gchar         *description,
372                   const gchar         *page_size,
373                   gdouble              page_width,
374                   gdouble              page_height)
375 {
376         lglTemplate *template;
377
378         template = g_new0 (lglTemplate,1);
379
380         template->name        = g_strdup (name);
381         template->description = g_strdup (description);
382         template->page_size   = g_strdup (page_size);
383         template->page_width  = page_width;
384         template->page_height = page_height;
385
386         /* Always include primary name in alias list. */
387         template->aliases = NULL;
388         template->aliases = g_list_append (template->aliases, g_strdup (name));
389
390         return template;
391 }
392
393 /*****************************************************************************/
394 /* Does page size match given id?                                            */
395 /*****************************************************************************/
396 gboolean
397 lgl_template_does_page_size_match (const lglTemplate  *template,
398                                    const gchar        *page_size)
399 {
400         g_return_val_if_fail (template, FALSE);
401
402         /* NULL matches everything. */
403         if (page_size == NULL)
404         {
405                 return TRUE;
406         }
407
408         return g_strcasecmp(page_size, template->page_size) == 0;
409 }
410
411 /*****************************************************************************/
412 /* Does category match given id?                                             */
413 /*****************************************************************************/
414 gboolean
415 lgl_template_does_category_match  (const lglTemplate  *template,
416                                    const gchar        *category)
417 {
418         GList *p;
419
420         g_return_val_if_fail (template, FALSE);
421
422         /* NULL matches everything. */
423         if (category == NULL)
424         {
425                 return TRUE;
426         }
427
428         for ( p=template->categories; p != NULL; p=p->next )
429         {
430                 if (g_strcasecmp(category, p->data) == 0)
431                 {
432                         return TRUE;
433                 }
434         }
435
436         return FALSE;
437 }
438
439 /*****************************************************************************/
440 /* Add category to category list of template.                                */
441 /*****************************************************************************/
442 void
443 lgl_template_add_category (lglTemplate         *template,
444                            const gchar         *category)
445 {
446         g_return_if_fail (template);
447         g_return_if_fail (category);
448
449         template->categories = g_list_append (template->categories,
450                                               g_strdup (category));
451 }
452  
453 /*****************************************************************************/
454 /* Add label type structure to label type list of template.                  */
455 /*****************************************************************************/
456 void
457 lgl_template_add_frame (lglTemplate      *template,
458                         lglTemplateFrame *frame)
459 {
460         g_return_if_fail (template);
461         g_return_if_fail (frame);
462
463         template->frames = g_list_append (template->frames, frame);
464 }
465  
466 /*****************************************************************************/
467 /* Add alias to alias list of template.                                      */
468 /*****************************************************************************/
469 void
470 lgl_template_add_alias (lglTemplate         *template,
471                         const gchar         *alias)
472 {
473         g_return_if_fail (template);
474         g_return_if_fail (alias);
475
476         template->aliases = g_list_append (template->aliases,
477                                            g_strdup (alias));
478 }
479  
480 /*****************************************************************************/
481 /* Create a new label type structure for a rectangular label.                */
482 /*****************************************************************************/
483 lglTemplateFrame *
484 lgl_template_frame_rect_new  (const gchar         *id,
485                               gdouble              w,
486                               gdouble              h,
487                               gdouble              r,
488                               gdouble              x_waste,
489                               gdouble              y_waste)
490 {
491         lglTemplateFrame *frame;
492
493         frame = g_new0 (lglTemplateFrame, 1);
494
495         frame->shape = LGL_TEMPLATE_FRAME_SHAPE_RECT;
496         frame->rect.id = g_strdup (id);
497
498         frame->rect.w = w;
499         frame->rect.h = h;
500         frame->rect.r = r;
501         frame->rect.x_waste = x_waste;
502         frame->rect.y_waste = y_waste;
503
504         return frame;
505 }
506
507 /*****************************************************************************/
508 /* Create a new label type structure for a round label.                      */
509 /*****************************************************************************/
510 lglTemplateFrame *
511 lgl_template_frame_round_new (const gchar         *id,
512                               gdouble              r,
513                               gdouble              waste)
514 {
515         lglTemplateFrame *frame;
516
517         frame = g_new0 (lglTemplateFrame, 1);
518
519         frame->shape = LGL_TEMPLATE_FRAME_SHAPE_ROUND;
520         frame->round.id = g_strdup (id);
521
522         frame->round.r = r;
523         frame->round.waste = waste;
524
525         return frame;
526 }
527                                                                                
528 /*****************************************************************************/
529 /* Create a new label type structure for a CD/DVD label.                     */
530 /*****************************************************************************/
531 lglTemplateFrame *
532 lgl_template_frame_cd_new (const gchar         *id,
533                            gdouble              r1,
534                            gdouble              r2,
535                            gdouble              w,
536                            gdouble              h,
537                            gdouble              waste)
538 {
539         lglTemplateFrame *frame;
540
541         frame = g_new0 (lglTemplateFrame, 1);
542
543         frame->shape = LGL_TEMPLATE_FRAME_SHAPE_CD;
544         frame->cd.id = g_strdup (id);
545
546         frame->cd.r1 = r1;
547         frame->cd.r2 = r2;
548         frame->cd.w  = w;
549         frame->cd.h  = h;
550         frame->cd.waste = waste;
551
552         return frame;
553 }
554
555 /*****************************************************************************/
556 /* Add a layout to a label type.                                             */
557 /*****************************************************************************/
558 void
559 lgl_template_add_layout (lglTemplateFrame   *frame,
560                          lglTemplateLayout  *layout)
561 {
562         g_return_if_fail (frame);
563         g_return_if_fail (layout);
564
565         frame->all.layouts = g_list_append (frame->all.layouts, layout);
566 }
567  
568 /*****************************************************************************/
569 /* Add a markup item to a label type.                                        */
570 /*****************************************************************************/
571 void
572 lgl_template_add_markup (lglTemplateFrame   *frame,
573                          lglTemplateMarkup  *markup)
574 {
575         g_return_if_fail (frame);
576         g_return_if_fail (markup);
577
578         frame->all.markups = g_list_append (frame->all.markups, markup);
579 }
580  
581 /*****************************************************************************/
582 /* Create new layout structure.                                              */
583 /*****************************************************************************/
584 lglTemplateLayout *
585 lgl_template_layout_new (gint    nx,
586                          gint    ny,
587                          gdouble x0,
588                          gdouble y0,
589                          gdouble dx,
590                          gdouble dy)
591 {
592         lglTemplateLayout *layout;
593
594         layout = g_new0 (lglTemplateLayout, 1);
595
596         layout->nx = nx;
597         layout->ny = ny;
598         layout->x0 = x0;
599         layout->y0 = y0;
600         layout->dx = dx;
601         layout->dy = dy;
602
603         return layout;
604 }
605
606 /*****************************************************************************/
607 /* Create new margin markup structure.                                       */
608 /*****************************************************************************/
609 lglTemplateMarkup *
610 lgl_template_markup_margin_new (gdouble size)
611 {
612         lglTemplateMarkup *markup;
613
614         markup = g_new0 (lglTemplateMarkup, 1);
615
616         markup->type        = LGL_TEMPLATE_MARKUP_MARGIN;
617         markup->margin.size = size;
618
619         return markup;
620 }
621
622 /*****************************************************************************/
623 /* Create new markup line structure.                                         */
624 /*****************************************************************************/
625 lglTemplateMarkup *
626 lgl_template_markup_line_new (gdouble x1,
627                               gdouble y1,
628                               gdouble x2,
629                               gdouble y2)
630 {
631         lglTemplateMarkup *markup;
632
633         markup = g_new0 (lglTemplateMarkup, 1);
634
635         markup->type        = LGL_TEMPLATE_MARKUP_LINE;
636         markup->line.x1     = x1;
637         markup->line.y1     = y1;
638         markup->line.x2     = x2;
639         markup->line.y2     = y2;
640
641         return markup;
642 }
643
644 /*****************************************************************************/
645 /* Create new markup circle structure.                                       */
646 /*****************************************************************************/
647 lglTemplateMarkup *
648 lgl_template_markup_circle_new (gdouble x0,
649                                 gdouble y0,
650                                 gdouble r)
651 {
652         lglTemplateMarkup *markup;
653
654         markup = g_new0 (lglTemplateMarkup, 1);
655
656         markup->type        = LGL_TEMPLATE_MARKUP_CIRCLE;
657         markup->circle.x0   = x0;
658         markup->circle.y0   = y0;
659         markup->circle.r    = r;
660
661         return markup;
662 }
663
664 /*****************************************************************************/
665 /* Create new markup rect structure.                                         */
666 /*****************************************************************************/
667 lglTemplateMarkup *
668 lgl_template_markup_rect_new (gdouble x1,
669                               gdouble y1,
670                               gdouble w,
671                               gdouble h,
672                               gdouble r)
673 {
674         lglTemplateMarkup *markup;
675
676         markup = g_new0 (lglTemplateMarkup, 1);
677
678         markup->type        = LGL_TEMPLATE_MARKUP_RECT;
679         markup->rect.x1     = x1;
680         markup->rect.y1     = y1;
681         markup->rect.w      = w;
682         markup->rect.h      = h;
683         markup->rect.r      = r;
684
685         return markup;
686 }
687
688
689 /*****************************************************************************/
690 /* Copy a template.                                                          */
691 /*****************************************************************************/
692 lglTemplate *
693 lgl_template_dup (const lglTemplate *orig_template)
694 {
695         lglTemplate         *template;
696         GList               *p;
697         lglTemplateFrame    *frame;
698
699         g_return_val_if_fail (orig_template, NULL);
700
701         template = lgl_template_new (orig_template->name,
702                                      orig_template->description,
703                                      orig_template->page_size,
704                                      orig_template->page_width,
705                                      orig_template->page_height);
706
707         for ( p=orig_template->categories; p != NULL; p=p->next ) {
708
709                 lgl_template_add_category (template, p->data);
710
711         }
712
713         for ( p=orig_template->frames; p != NULL; p=p->next ) {
714
715                 frame = (lglTemplateFrame *)p->data;
716
717                 lgl_template_add_frame (template, lgl_template_frame_dup (frame));
718         }
719
720         for ( p=orig_template->aliases; p != NULL; p=p->next ) {
721
722                 if (g_strcasecmp (template->name, p->data) != 0) {
723                         lgl_template_add_alias (template, p->data);
724                 }
725
726         }
727
728         return template;
729 }
730
731 /*****************************************************************************/
732 /* Free up a template.                                                       */
733 /*****************************************************************************/
734 void
735 lgl_template_free (lglTemplate *template)
736 {
737         GList            *p;
738         lglTemplateFrame *frame;
739
740         if ( template != NULL ) {
741
742                 g_free (template->name);
743                 template->name = NULL;
744
745                 g_free (template->description);
746                 template->description = NULL;
747
748                 g_free (template->page_size);
749                 template->page_size = NULL;
750
751                 for ( p=template->categories; p != NULL; p=p->next ) {
752
753                         g_free (p->data);
754                         p->data = NULL;
755
756                 }
757                 g_list_free (template->categories);
758                 template->categories = NULL;
759
760                 for ( p=template->frames; p != NULL; p=p->next ) {
761
762                         frame = (lglTemplateFrame *)p->data;
763
764                         lgl_template_frame_free (frame);
765                         p->data = NULL;
766                 }
767                 g_list_free (template->frames);
768                 template->frames = NULL;
769
770                 for ( p=template->aliases; p != NULL; p=p->next ) {
771
772                         g_free (p->data);
773                         p->data = NULL;
774
775                 }
776                 g_list_free (template->aliases);
777                 template->aliases = NULL;
778
779                 g_free (template);
780
781         }
782
783 }
784
785 /*****************************************************************************/
786 /* Copy a template label type.                                               */
787 /*****************************************************************************/
788 lglTemplateFrame *
789 lgl_template_frame_dup (const lglTemplateFrame *orig_frame)
790 {
791         lglTemplateFrame    *frame;
792         GList               *p;
793         lglTemplateLayout   *layout;
794         lglTemplateMarkup   *markup;
795
796         g_return_val_if_fail (orig_frame, NULL);
797
798         switch (orig_frame->shape) {
799
800         case LGL_TEMPLATE_FRAME_SHAPE_RECT:
801                 frame =
802                         lgl_template_frame_rect_new (orig_frame->all.id,
803                                                      orig_frame->rect.w,
804                                                      orig_frame->rect.h,
805                                                      orig_frame->rect.r,
806                                                      orig_frame->rect.x_waste,
807                                                      orig_frame->rect.y_waste);
808                 break;
809
810         case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
811                 frame =
812                         lgl_template_frame_round_new (orig_frame->all.id,
813                                                       orig_frame->round.r,
814                                                       orig_frame->round.waste);
815                 break;
816
817         case LGL_TEMPLATE_FRAME_SHAPE_CD:
818                 frame =
819                         lgl_template_frame_cd_new (orig_frame->all.id,
820                                                    orig_frame->cd.r1,
821                                                    orig_frame->cd.r2,
822                                                    orig_frame->cd.w,
823                                                    orig_frame->cd.h,
824                                                    orig_frame->cd.waste);
825                 break;
826
827         default:
828                 return NULL;
829                 break;
830         }
831
832         for ( p=orig_frame->all.layouts; p != NULL; p=p->next ) {
833
834                 layout = (lglTemplateLayout *)p->data;
835
836                 lgl_template_add_layout (frame, lgl_template_layout_dup (layout));
837         }
838
839         for ( p=orig_frame->all.markups; p != NULL; p=p->next ) {
840
841                 markup = (lglTemplateMarkup *)p->data;
842
843                 lgl_template_add_markup (frame, lgl_template_markup_dup (markup));
844         }
845
846         return frame;
847 }
848
849 /*****************************************************************************/
850 /* Free up a template label type.                                            */
851 /*****************************************************************************/
852 void
853 lgl_template_frame_free (lglTemplateFrame *frame)
854 {
855         GList                *p;
856         lglTemplateLayout    *layout;
857         lglTemplateMarkup    *markup;
858
859         if ( frame != NULL ) {
860
861                 g_free (frame->all.id);
862                 frame->all.id = NULL;
863
864                 for ( p=frame->all.layouts; p != NULL; p=p->next ) {
865
866                         layout = (lglTemplateLayout *)p->data;
867
868                         lgl_template_layout_free (layout);
869                         p->data = NULL;
870                 }
871                 g_list_free (frame->all.layouts);
872                 frame->all.layouts = NULL;
873
874                 for ( p=frame->all.markups; p != NULL; p=p->next ) {
875
876                         markup = (lglTemplateMarkup *)p->data;
877
878                         lgl_template_markup_free (markup);
879                         p->data = NULL;
880                 }
881                 g_list_free (frame->all.markups);
882                 frame->all.markups = NULL;
883
884                 g_free (frame);
885
886         }
887
888 }
889
890 /*****************************************************************************/
891 /* Duplicate layout structure.                                               */
892 /*****************************************************************************/
893 lglTemplateLayout *
894 lgl_template_layout_dup (const lglTemplateLayout *orig_layout)
895 {
896         lglTemplateLayout *layout;
897
898         g_return_val_if_fail (orig_layout, NULL);
899
900         layout = g_new0 (lglTemplateLayout, 1);
901
902         /* copy contents */
903         *layout = *orig_layout;
904
905         return layout;
906 }
907
908 /*****************************************************************************/
909 /* Free layout structure.                                                    */
910 /*****************************************************************************/
911 void
912 lgl_template_layout_free (lglTemplateLayout *layout)
913 {
914         g_free (layout);
915 }
916
917 /*****************************************************************************/
918 /* Duplicate markup structure.                                               */
919 /*****************************************************************************/
920 lglTemplateMarkup *
921 lgl_template_markup_dup (const lglTemplateMarkup *orig_markup)
922 {
923         lglTemplateMarkup *markup;
924
925         g_return_val_if_fail (orig_markup, NULL);
926
927         markup = g_new0 (lglTemplateMarkup, 1);
928
929         *markup = *orig_markup;
930
931         return markup;
932 }
933
934 /*****************************************************************************/
935 /* Free markup structure.                                                    */
936 /*****************************************************************************/
937 void
938 lgl_template_markup_free (lglTemplateMarkup *markup)
939 {
940         g_free (markup);
941 }
942
943 /*--------------------------------------------------------------------------*/
944 /* PRIVATE.  Make a template for a full page of the given page size.        */
945 /*--------------------------------------------------------------------------*/
946 static lglTemplate *
947 template_full_page (const gchar *page_size)
948 {
949         lglPaper              *paper = NULL;
950         lglTemplate           *template = NULL;
951         lglTemplateFrame      *frame = NULL;
952         gchar                 *name;
953
954         g_return_val_if_fail (page_size, NULL);
955
956         paper = lgl_paper_from_id (page_size);
957         if ( paper == NULL ) {
958                 return NULL;
959         }
960
961         name         = g_strdup_printf (_("Generic %s full page"), page_size);
962
963         template = lgl_template_new (name,
964                                      FULL_PAGE,
965                                      page_size,
966                                      paper->width,
967                                      paper->height);
968
969
970         frame = lgl_template_frame_rect_new ("0",
971                                              paper->width,
972                                              paper->height,
973                                              0.0,
974                                              0.0,
975                                              0.0);
976         lgl_template_add_frame (template, frame);
977
978         lgl_template_add_layout (frame, lgl_template_layout_new (1, 1, 0., 0., 0., 0.));
979
980         lgl_template_add_markup (frame, lgl_template_markup_margin_new (9.0));
981
982         g_free (name);
983         name = NULL;
984         lgl_paper_free (paper);
985         paper = NULL;
986
987         return template;
988 }
989
990 /*--------------------------------------------------------------------------*/
991 /* PRIVATE.  Read templates from various  files.                            */
992 /*--------------------------------------------------------------------------*/
993 static GList *
994 read_templates (void)
995 {
996         gchar *data_dir;
997         GList *templates = NULL;
998
999         data_dir = LGL_SYSTEM_DATA_DIR;
1000         templates = read_template_files_from_dir (templates, data_dir);
1001         g_free (data_dir);
1002
1003         data_dir = LGL_USER_DATA_DIR;
1004         templates = read_template_files_from_dir (templates, data_dir);
1005         g_free (data_dir);
1006
1007         if (templates == NULL) {
1008                 g_critical (_("Unable to locate any template files.  Libglabels may not be installed correctly!"));
1009         }
1010
1011         return templates;
1012 }
1013
1014 /*--------------------------------------------------------------------------*/
1015 /* PRIVATE.  Read all template files from given directory.  Append to list. */
1016 /*--------------------------------------------------------------------------*/
1017 static GList *
1018 read_template_files_from_dir (GList       *templates,
1019                               const gchar *dirname)
1020 {
1021         GDir        *dp;
1022         const gchar *filename, *extension, *extension2;
1023         gchar       *full_filename = NULL;
1024         GError      *gerror = NULL;
1025         GList       *new_templates = NULL;
1026
1027         if (dirname == NULL)
1028                 return templates;
1029
1030         if (!g_file_test (dirname, G_FILE_TEST_EXISTS)) {
1031                 return templates;
1032         }
1033
1034         dp = g_dir_open (dirname, 0, &gerror);
1035         if (gerror != NULL) {
1036                 g_message ("cannot open data directory: %s", gerror->message );
1037                 return templates;
1038         }
1039
1040         while ((filename = g_dir_read_name (dp)) != NULL) {
1041
1042                 extension = strrchr (filename, '.');
1043                 extension2 = strrchr (filename, '-');
1044
1045                 if ( (extension && (g_strcasecmp (extension, ".template") == 0)) ||
1046                      (extension2 && (g_strcasecmp (extension2, "-templates.xml") == 0)) ) {
1047
1048                         full_filename = g_build_filename (dirname, filename, NULL);
1049                         new_templates =
1050                                 lgl_xml_template_read_templates_from_file (full_filename);
1051                         g_free (full_filename);
1052
1053                         templates = g_list_concat (templates, new_templates);
1054                         new_templates = NULL;
1055                 }
1056
1057         }
1058
1059         g_dir_close (dp);
1060
1061         return templates;
1062 }
1063
1064 /*--------------------------------------------------------------------------*/
1065 /* PRIVATE.  Sort origins comparison function, first by y then by x.        */
1066 /*--------------------------------------------------------------------------*/
1067 static gint
1068 compare_origins (gconstpointer a,
1069                  gconstpointer b,
1070                  gpointer      user_data)
1071 {
1072         const lglTemplateOrigin *a_origin = a, *b_origin = b;
1073
1074         if ( a_origin->y < b_origin->y ) {
1075                 return -1;
1076         } else if ( a_origin->y > b_origin->y ) {
1077                 return +1;
1078         } else {
1079                 if ( a_origin->x < b_origin->x ) {
1080                         return -1;
1081                 } else if ( a_origin->x > b_origin->x ) {
1082                         return +1;
1083                 } else {
1084                         return 0; /* hopefully 2 labels won't have the same origin */
1085                 }
1086         }
1087 }
1088
1089 /*****************************************************************************/
1090 /* Print all known templates (for debugging purposes).                       */
1091 /*****************************************************************************/
1092 void
1093 lgl_template_print_known_templates (void)
1094 {
1095         GList       *p;
1096         lglTemplate *template;
1097
1098         g_print ("%s():\n", __FUNCTION__);
1099         for (p=templates; p!=NULL; p=p->next) {
1100                 template = (lglTemplate *)p->data;
1101
1102                 g_print("TEMPLATE name=\"%s\", description=\"%s\"\n",
1103                         template->name, template->description);
1104
1105         }
1106         g_print ("\n");
1107
1108 }
1109
1110 /*****************************************************************************/
1111 /* Print all aliases of a template (for debugging purposes).                 */
1112 /*****************************************************************************/
1113 void
1114 lgl_template_print_aliases (const lglTemplate *template)
1115 {
1116         GList *p;
1117
1118         g_print ("%s():\n", __FUNCTION__);
1119         for (p=template->aliases; p!=NULL; p=p->next) {
1120                 
1121                 g_print("Alias = \"%s\"\n", (gchar *)p->data);
1122
1123         }
1124         g_print ("\n");
1125
1126 }
1127