1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
4 * (LIBGLABELS) Template library for GLABELS
6 * template.c: template module
8 * Copyright (C) 2001-2006 Jim Evins <evins@snaught.com>.
10 * This file is part of the LIBGLABELS library.
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.
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.
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,
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>
38 #include <sys/types.h>
40 #include "libglabels-private.h"
42 #include "xml-template.h"
45 #define FULL_PAGE "Full-page"
47 /*===========================================*/
49 /*===========================================*/
51 /*===========================================*/
53 /*===========================================*/
55 static GList *templates = NULL;
57 /*===========================================*/
58 /* Local function prototypes */
59 /*===========================================*/
60 static lglTemplate *template_full_page (const gchar *page_size);
62 static GList *read_templates (void);
64 static GList *read_template_files_from_dir (GList *templates,
65 const gchar *dirname);
67 static gint compare_origins (gconstpointer a,
71 /*****************************************************************************/
72 /* Initialize module. */
73 /*****************************************************************************/
75 lgl_template_init (void)
77 GList *page_sizes, *p;
80 return; /* Already initialized */
83 templates = read_templates ();
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));
92 lgl_paper_free_id_list (page_sizes);
95 /*****************************************************************************/
96 /* Register template: if not in current list, add it. */
97 /*****************************************************************************/
99 lgl_template_register (const lglTemplate *template)
101 GList *p_tmplt, *pa1;
102 lglTemplate *template1;
105 lgl_template_init ();
108 for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) {
109 template1 = (lglTemplate *) p_tmplt->data;
111 for (pa1=template1->aliases; pa1!=NULL; pa1=pa1->next) {
113 if (g_strcasecmp (template->name, pa1->data) == 0) {
115 /* FIXME: make sure templates are really identical */
116 /* if not, apply hash to name to make unique. */
124 if (lgl_paper_is_id_known (template->page_size)) {
126 gchar *dir, *filename, *abs_filename;
128 templates = g_list_append (templates,
129 lgl_template_dup (template));
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);
139 g_free (abs_filename);
142 g_message ("Cannot register new template with unknown page size.");
147 /*********************************************************************************/
148 /* Get a list of valid names of unique templates for given page size */
149 /*********************************************************************************/
151 lgl_template_get_name_list_unique (const gchar *page_size,
152 const gchar *category)
155 lglTemplate *template;
160 lgl_template_init ();
163 for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next)
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))
169 names = g_list_insert_sorted (names, g_strdup (template->name),
170 (GCompareFunc)g_strcasecmp);
177 /*********************************************************************************/
178 /* Get a list of all valid template names for given page size (includes aliases) */
179 /*********************************************************************************/
181 lgl_template_get_name_list_all (const gchar *page_size,
182 const gchar *category)
184 GList *p_tmplt, *p_alias;
185 lglTemplate *template;
191 lgl_template_init ();
194 for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next)
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))
200 for (p_alias = template->aliases; p_alias != NULL;
201 p_alias = p_alias->next)
203 str = g_strdup ((gchar *) p_alias->data);
204 names = g_list_insert_sorted (names, str,
205 (GCompareFunc)g_strcasecmp);
213 /*****************************************************************************/
214 /* Free a list of template names. */
215 /*****************************************************************************/
217 lgl_template_free_name_list (GList *names)
221 for (p_name = names; p_name != NULL; p_name = p_name->next) {
222 g_free (p_name->data);
229 /*****************************************************************************/
230 /* Return a template structure from a name. */
231 /*****************************************************************************/
233 lgl_template_from_name (const gchar *name)
235 GList *p_tmplt, *p_alias;
236 lglTemplate *template;
239 lgl_template_init ();
243 /* If no name, return first template as a default */
244 return lgl_template_dup ((lglTemplate *) templates->data);
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) {
253 return lgl_template_dup (template);
258 /* No matching template has been found so return the first template */
259 return lgl_template_dup ((lglTemplate *) templates->data);
262 /*****************************************************************************/
263 /* Get first label type in template. */
264 /*****************************************************************************/
265 const lglTemplateFrame *
266 lgl_template_get_first_frame (const lglTemplate *template)
268 g_return_val_if_fail (template, NULL);
270 return (lglTemplateFrame *)template->frames->data;
273 /****************************************************************************/
274 /* Get raw label size (width and height). */
275 /****************************************************************************/
277 lgl_template_frame_get_size (const lglTemplateFrame *frame,
281 g_return_if_fail (frame);
283 switch (frame->shape) {
284 case LGL_TEMPLATE_FRAME_SHAPE_RECT:
288 case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
289 *w = 2.0 * frame->round.r;
290 *h = 2.0 * frame->round.r;
292 case LGL_TEMPLATE_FRAME_SHAPE_CD:
293 if (frame->cd.w == 0.0) {
294 *w = 2.0 * frame->cd.r1;
298 if (frame->cd.h == 0.0) {
299 *h = 2.0 * frame->cd.r1;
311 /****************************************************************************/
312 /* Get total number of labels per sheet of a label type. */
313 /****************************************************************************/
315 lgl_template_frame_get_n_labels (const lglTemplateFrame *frame)
319 lglTemplateLayout *layout;
321 g_return_val_if_fail (frame, 0);
323 for ( p=frame->all.layouts; p != NULL; p=p->next ) {
324 layout = (lglTemplateLayout *)p->data;
326 n_labels += layout->nx * layout->ny;
332 /****************************************************************************/
333 /* Get array of origins of individual labels. */
334 /****************************************************************************/
336 lgl_template_frame_get_origins (const lglTemplateFrame *frame)
338 gint i_label, n_labels, ix, iy;
339 lglTemplateOrigin *origins;
341 lglTemplateLayout *layout;
343 g_return_val_if_fail (frame, NULL);
345 n_labels = lgl_template_frame_get_n_labels (frame);
346 origins = g_new0 (lglTemplateOrigin, n_labels);
349 for ( p=frame->all.layouts; p != NULL; p=p->next ) {
350 layout = (lglTemplateLayout *)p->data;
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;
360 g_qsort_with_data (origins, n_labels, sizeof(lglTemplateOrigin),
361 compare_origins, NULL);
366 /*****************************************************************************/
367 /* Create a new template with given properties. */
368 /*****************************************************************************/
370 lgl_template_new (const gchar *name,
371 const gchar *description,
372 const gchar *page_size,
376 lglTemplate *template;
378 template = g_new0 (lglTemplate,1);
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;
386 /* Always include primary name in alias list. */
387 template->aliases = NULL;
388 template->aliases = g_list_append (template->aliases, g_strdup (name));
393 /*****************************************************************************/
394 /* Does page size match given id? */
395 /*****************************************************************************/
397 lgl_template_does_page_size_match (const lglTemplate *template,
398 const gchar *page_size)
400 g_return_val_if_fail (template, FALSE);
402 /* NULL matches everything. */
403 if (page_size == NULL)
408 return g_strcasecmp(page_size, template->page_size) == 0;
411 /*****************************************************************************/
412 /* Does category match given id? */
413 /*****************************************************************************/
415 lgl_template_does_category_match (const lglTemplate *template,
416 const gchar *category)
420 g_return_val_if_fail (template, FALSE);
422 /* NULL matches everything. */
423 if (category == NULL)
428 for ( p=template->categories; p != NULL; p=p->next )
430 if (g_strcasecmp(category, p->data) == 0)
439 /*****************************************************************************/
440 /* Add category to category list of template. */
441 /*****************************************************************************/
443 lgl_template_add_category (lglTemplate *template,
444 const gchar *category)
446 g_return_if_fail (template);
447 g_return_if_fail (category);
449 template->categories = g_list_append (template->categories,
450 g_strdup (category));
453 /*****************************************************************************/
454 /* Add label type structure to label type list of template. */
455 /*****************************************************************************/
457 lgl_template_add_frame (lglTemplate *template,
458 lglTemplateFrame *frame)
460 g_return_if_fail (template);
461 g_return_if_fail (frame);
463 template->frames = g_list_append (template->frames, frame);
466 /*****************************************************************************/
467 /* Add alias to alias list of template. */
468 /*****************************************************************************/
470 lgl_template_add_alias (lglTemplate *template,
473 g_return_if_fail (template);
474 g_return_if_fail (alias);
476 template->aliases = g_list_append (template->aliases,
480 /*****************************************************************************/
481 /* Create a new label type structure for a rectangular label. */
482 /*****************************************************************************/
484 lgl_template_frame_rect_new (const gchar *id,
491 lglTemplateFrame *frame;
493 frame = g_new0 (lglTemplateFrame, 1);
495 frame->shape = LGL_TEMPLATE_FRAME_SHAPE_RECT;
496 frame->rect.id = g_strdup (id);
501 frame->rect.x_waste = x_waste;
502 frame->rect.y_waste = y_waste;
507 /*****************************************************************************/
508 /* Create a new label type structure for a round label. */
509 /*****************************************************************************/
511 lgl_template_frame_round_new (const gchar *id,
515 lglTemplateFrame *frame;
517 frame = g_new0 (lglTemplateFrame, 1);
519 frame->shape = LGL_TEMPLATE_FRAME_SHAPE_ROUND;
520 frame->round.id = g_strdup (id);
523 frame->round.waste = waste;
528 /*****************************************************************************/
529 /* Create a new label type structure for a CD/DVD label. */
530 /*****************************************************************************/
532 lgl_template_frame_cd_new (const gchar *id,
539 lglTemplateFrame *frame;
541 frame = g_new0 (lglTemplateFrame, 1);
543 frame->shape = LGL_TEMPLATE_FRAME_SHAPE_CD;
544 frame->cd.id = g_strdup (id);
550 frame->cd.waste = waste;
555 /*****************************************************************************/
556 /* Add a layout to a label type. */
557 /*****************************************************************************/
559 lgl_template_add_layout (lglTemplateFrame *frame,
560 lglTemplateLayout *layout)
562 g_return_if_fail (frame);
563 g_return_if_fail (layout);
565 frame->all.layouts = g_list_append (frame->all.layouts, layout);
568 /*****************************************************************************/
569 /* Add a markup item to a label type. */
570 /*****************************************************************************/
572 lgl_template_add_markup (lglTemplateFrame *frame,
573 lglTemplateMarkup *markup)
575 g_return_if_fail (frame);
576 g_return_if_fail (markup);
578 frame->all.markups = g_list_append (frame->all.markups, markup);
581 /*****************************************************************************/
582 /* Create new layout structure. */
583 /*****************************************************************************/
585 lgl_template_layout_new (gint nx,
592 lglTemplateLayout *layout;
594 layout = g_new0 (lglTemplateLayout, 1);
606 /*****************************************************************************/
607 /* Create new margin markup structure. */
608 /*****************************************************************************/
610 lgl_template_markup_margin_new (gdouble size)
612 lglTemplateMarkup *markup;
614 markup = g_new0 (lglTemplateMarkup, 1);
616 markup->type = LGL_TEMPLATE_MARKUP_MARGIN;
617 markup->margin.size = size;
622 /*****************************************************************************/
623 /* Create new markup line structure. */
624 /*****************************************************************************/
626 lgl_template_markup_line_new (gdouble x1,
631 lglTemplateMarkup *markup;
633 markup = g_new0 (lglTemplateMarkup, 1);
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;
644 /*****************************************************************************/
645 /* Create new markup circle structure. */
646 /*****************************************************************************/
648 lgl_template_markup_circle_new (gdouble x0,
652 lglTemplateMarkup *markup;
654 markup = g_new0 (lglTemplateMarkup, 1);
656 markup->type = LGL_TEMPLATE_MARKUP_CIRCLE;
657 markup->circle.x0 = x0;
658 markup->circle.y0 = y0;
659 markup->circle.r = r;
664 /*****************************************************************************/
665 /* Create new markup rect structure. */
666 /*****************************************************************************/
668 lgl_template_markup_rect_new (gdouble x1,
674 lglTemplateMarkup *markup;
676 markup = g_new0 (lglTemplateMarkup, 1);
678 markup->type = LGL_TEMPLATE_MARKUP_RECT;
679 markup->rect.x1 = x1;
680 markup->rect.y1 = y1;
689 /*****************************************************************************/
690 /* Copy a template. */
691 /*****************************************************************************/
693 lgl_template_dup (const lglTemplate *orig_template)
695 lglTemplate *template;
697 lglTemplateFrame *frame;
699 g_return_val_if_fail (orig_template, NULL);
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);
707 for ( p=orig_template->categories; p != NULL; p=p->next ) {
709 lgl_template_add_category (template, p->data);
713 for ( p=orig_template->frames; p != NULL; p=p->next ) {
715 frame = (lglTemplateFrame *)p->data;
717 lgl_template_add_frame (template, lgl_template_frame_dup (frame));
720 for ( p=orig_template->aliases; p != NULL; p=p->next ) {
722 if (g_strcasecmp (template->name, p->data) != 0) {
723 lgl_template_add_alias (template, p->data);
731 /*****************************************************************************/
732 /* Free up a template. */
733 /*****************************************************************************/
735 lgl_template_free (lglTemplate *template)
738 lglTemplateFrame *frame;
740 if ( template != NULL ) {
742 g_free (template->name);
743 template->name = NULL;
745 g_free (template->description);
746 template->description = NULL;
748 g_free (template->page_size);
749 template->page_size = NULL;
751 for ( p=template->categories; p != NULL; p=p->next ) {
757 g_list_free (template->categories);
758 template->categories = NULL;
760 for ( p=template->frames; p != NULL; p=p->next ) {
762 frame = (lglTemplateFrame *)p->data;
764 lgl_template_frame_free (frame);
767 g_list_free (template->frames);
768 template->frames = NULL;
770 for ( p=template->aliases; p != NULL; p=p->next ) {
776 g_list_free (template->aliases);
777 template->aliases = NULL;
785 /*****************************************************************************/
786 /* Copy a template label type. */
787 /*****************************************************************************/
789 lgl_template_frame_dup (const lglTemplateFrame *orig_frame)
791 lglTemplateFrame *frame;
793 lglTemplateLayout *layout;
794 lglTemplateMarkup *markup;
796 g_return_val_if_fail (orig_frame, NULL);
798 switch (orig_frame->shape) {
800 case LGL_TEMPLATE_FRAME_SHAPE_RECT:
802 lgl_template_frame_rect_new (orig_frame->all.id,
806 orig_frame->rect.x_waste,
807 orig_frame->rect.y_waste);
810 case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
812 lgl_template_frame_round_new (orig_frame->all.id,
814 orig_frame->round.waste);
817 case LGL_TEMPLATE_FRAME_SHAPE_CD:
819 lgl_template_frame_cd_new (orig_frame->all.id,
824 orig_frame->cd.waste);
832 for ( p=orig_frame->all.layouts; p != NULL; p=p->next ) {
834 layout = (lglTemplateLayout *)p->data;
836 lgl_template_add_layout (frame, lgl_template_layout_dup (layout));
839 for ( p=orig_frame->all.markups; p != NULL; p=p->next ) {
841 markup = (lglTemplateMarkup *)p->data;
843 lgl_template_add_markup (frame, lgl_template_markup_dup (markup));
849 /*****************************************************************************/
850 /* Free up a template label type. */
851 /*****************************************************************************/
853 lgl_template_frame_free (lglTemplateFrame *frame)
856 lglTemplateLayout *layout;
857 lglTemplateMarkup *markup;
859 if ( frame != NULL ) {
861 g_free (frame->all.id);
862 frame->all.id = NULL;
864 for ( p=frame->all.layouts; p != NULL; p=p->next ) {
866 layout = (lglTemplateLayout *)p->data;
868 lgl_template_layout_free (layout);
871 g_list_free (frame->all.layouts);
872 frame->all.layouts = NULL;
874 for ( p=frame->all.markups; p != NULL; p=p->next ) {
876 markup = (lglTemplateMarkup *)p->data;
878 lgl_template_markup_free (markup);
881 g_list_free (frame->all.markups);
882 frame->all.markups = NULL;
890 /*****************************************************************************/
891 /* Duplicate layout structure. */
892 /*****************************************************************************/
894 lgl_template_layout_dup (const lglTemplateLayout *orig_layout)
896 lglTemplateLayout *layout;
898 g_return_val_if_fail (orig_layout, NULL);
900 layout = g_new0 (lglTemplateLayout, 1);
903 *layout = *orig_layout;
908 /*****************************************************************************/
909 /* Free layout structure. */
910 /*****************************************************************************/
912 lgl_template_layout_free (lglTemplateLayout *layout)
917 /*****************************************************************************/
918 /* Duplicate markup structure. */
919 /*****************************************************************************/
921 lgl_template_markup_dup (const lglTemplateMarkup *orig_markup)
923 lglTemplateMarkup *markup;
925 g_return_val_if_fail (orig_markup, NULL);
927 markup = g_new0 (lglTemplateMarkup, 1);
929 *markup = *orig_markup;
934 /*****************************************************************************/
935 /* Free markup structure. */
936 /*****************************************************************************/
938 lgl_template_markup_free (lglTemplateMarkup *markup)
943 /*--------------------------------------------------------------------------*/
944 /* PRIVATE. Make a template for a full page of the given page size. */
945 /*--------------------------------------------------------------------------*/
947 template_full_page (const gchar *page_size)
949 lglPaper *paper = NULL;
950 lglTemplate *template = NULL;
951 lglTemplateFrame *frame = NULL;
954 g_return_val_if_fail (page_size, NULL);
956 paper = lgl_paper_from_id (page_size);
957 if ( paper == NULL ) {
961 name = g_strdup_printf (_("Generic %s full page"), page_size);
963 template = lgl_template_new (name,
970 frame = lgl_template_frame_rect_new ("0",
976 lgl_template_add_frame (template, frame);
978 lgl_template_add_layout (frame, lgl_template_layout_new (1, 1, 0., 0., 0., 0.));
980 lgl_template_add_markup (frame, lgl_template_markup_margin_new (9.0));
984 lgl_paper_free (paper);
990 /*--------------------------------------------------------------------------*/
991 /* PRIVATE. Read templates from various files. */
992 /*--------------------------------------------------------------------------*/
994 read_templates (void)
997 GList *templates = NULL;
999 data_dir = LGL_SYSTEM_DATA_DIR;
1000 templates = read_template_files_from_dir (templates, data_dir);
1003 data_dir = LGL_USER_DATA_DIR;
1004 templates = read_template_files_from_dir (templates, data_dir);
1007 if (templates == NULL) {
1008 g_critical (_("Unable to locate any template files. Libglabels may not be installed correctly!"));
1014 /*--------------------------------------------------------------------------*/
1015 /* PRIVATE. Read all template files from given directory. Append to list. */
1016 /*--------------------------------------------------------------------------*/
1018 read_template_files_from_dir (GList *templates,
1019 const gchar *dirname)
1022 const gchar *filename, *extension, *extension2;
1023 gchar *full_filename = NULL;
1024 GError *gerror = NULL;
1025 GList *new_templates = NULL;
1027 if (dirname == NULL)
1030 if (!g_file_test (dirname, G_FILE_TEST_EXISTS)) {
1034 dp = g_dir_open (dirname, 0, &gerror);
1035 if (gerror != NULL) {
1036 g_message ("cannot open data directory: %s", gerror->message );
1040 while ((filename = g_dir_read_name (dp)) != NULL) {
1042 extension = strrchr (filename, '.');
1043 extension2 = strrchr (filename, '-');
1045 if ( (extension && (g_strcasecmp (extension, ".template") == 0)) ||
1046 (extension2 && (g_strcasecmp (extension2, "-templates.xml") == 0)) ) {
1048 full_filename = g_build_filename (dirname, filename, NULL);
1050 lgl_xml_template_read_templates_from_file (full_filename);
1051 g_free (full_filename);
1053 templates = g_list_concat (templates, new_templates);
1054 new_templates = NULL;
1064 /*--------------------------------------------------------------------------*/
1065 /* PRIVATE. Sort origins comparison function, first by y then by x. */
1066 /*--------------------------------------------------------------------------*/
1068 compare_origins (gconstpointer a,
1072 const lglTemplateOrigin *a_origin = a, *b_origin = b;
1074 if ( a_origin->y < b_origin->y ) {
1076 } else if ( a_origin->y > b_origin->y ) {
1079 if ( a_origin->x < b_origin->x ) {
1081 } else if ( a_origin->x > b_origin->x ) {
1084 return 0; /* hopefully 2 labels won't have the same origin */
1089 /*****************************************************************************/
1090 /* Print all known templates (for debugging purposes). */
1091 /*****************************************************************************/
1093 lgl_template_print_known_templates (void)
1096 lglTemplate *template;
1098 g_print ("%s():\n", __FUNCTION__);
1099 for (p=templates; p!=NULL; p=p->next) {
1100 template = (lglTemplate *)p->data;
1102 g_print("TEMPLATE name=\"%s\", description=\"%s\"\n",
1103 template->name, template->description);
1110 /*****************************************************************************/
1111 /* Print all aliases of a template (for debugging purposes). */
1112 /*****************************************************************************/
1114 lgl_template_print_aliases (const lglTemplate *template)
1118 g_print ("%s():\n", __FUNCTION__);
1119 for (p=template->aliases; p!=NULL; p=p->next) {
1121 g_print("Alias = \"%s\"\n", (gchar *)p->data);