2 * (GLABELS) Label and Business Card Creation program for GNOME
4 * template.c: template module
6 * Copyright (C) 2001-2002 Jim Evins <evins@snaught.com>.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <libgnomeprint/gnome-print-paper.h>
32 #define GL_DATA_DIR gnome_program_locate_file (NULL,\
33 GNOME_FILE_DOMAIN_APP_DATADIR,\
37 #define FULL_PAGE "Full-page"
39 /*===========================================*/
41 /*===========================================*/
43 /*===========================================*/
45 /*===========================================*/
47 static GList *templates = NULL;
49 /*===========================================*/
50 /* Local function prototypes */
51 /*===========================================*/
52 static glTemplate *template_full_page (const gchar *page_size);
54 static GList *read_templates (void);
56 static gchar *get_home_data_dir (void);
57 static GList *read_template_files_from_dir (GList * templates,
58 const gchar * dirname);
59 static GList *read_templates_from_file (GList * templates,
60 gchar * xml_filename);
62 static void xml_parse_label (xmlNodePtr label_node, glTemplate * template);
63 static void xml_parse_layout (xmlNodePtr layout_node, glTemplate * template);
64 static void xml_parse_markup (xmlNodePtr markup_node, glTemplate * template);
65 static void xml_parse_alias (xmlNodePtr alias_node, glTemplate * template);
67 static void xml_add_label (glTemplate *template, xmlNodePtr root, xmlNsPtr ns);
68 static void xml_add_layout (glTemplate *template, xmlNodePtr root, xmlNsPtr ns);
69 static void xml_add_markup_margin (glTemplate *template, xmlNodePtr root, xmlNsPtr ns);
70 static void xml_add_alias (gchar *name, xmlNodePtr root, xmlNsPtr ns);
72 /*****************************************************************************/
73 /* Initialize module. */
74 /*****************************************************************************/
76 gl_template_init (void)
78 GList *page_sizes, *p;
80 gl_debug (DEBUG_TEMPLATE, "START");
82 templates = read_templates ();
84 page_sizes = gl_template_get_page_size_list ();
85 for ( p=page_sizes; p != NULL; p=p->next ) {
86 templates = g_list_append (templates,
87 template_full_page (p->data));
89 gl_template_free_page_size_list (&page_sizes);
91 gl_debug (DEBUG_TEMPLATE, "END");
94 /*****************************************************************************/
95 /* Get a list of valid page size names */
96 /*****************************************************************************/
98 gl_template_get_page_size_list (void)
101 GList *p, *paper_list;
102 GnomePrintPaper *paper;
104 gl_debug (DEBUG_TEMPLATE, "START");
106 paper_list = gnome_print_paper_get_list();
107 for ( p=paper_list; p != NULL; p=p->next ) {
108 paper = (GnomePrintPaper *)p->data;
109 if ( g_strcasecmp(paper->name, "custom") != 0 ) {
110 names = g_list_append (names, g_strdup (paper->name));
114 gl_debug (DEBUG_TEMPLATE, "END");
118 /*****************************************************************************/
119 /* Free a list of page size names. */
120 /*****************************************************************************/
122 gl_template_free_page_size_list (GList ** names)
126 gl_debug (DEBUG_TEMPLATE, "START");
128 for (p_name = *names; p_name != NULL; p_name = p_name->next) {
129 g_free (p_name->data);
133 g_list_free (*names);
136 gl_debug (DEBUG_TEMPLATE, "END");
139 /*****************************************************************************/
140 /* Get a list of valid template names for given page size */
141 /*****************************************************************************/
143 gl_template_get_name_list (const gchar * page_size)
145 GList *p_tmplt, *p_name;
146 glTemplate *template;
150 gl_debug (DEBUG_TEMPLATE, "START");
152 for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) {
153 template = (glTemplate *) p_tmplt->data;
154 if (g_strcasecmp (page_size, template->page_size) == 0) {
155 for (p_name = template->name; p_name != NULL;
156 p_name = p_name->next) {
157 str = g_strdup_printf("%s: %s",
158 (gchar *) p_name->data,
159 template->description);
160 names = g_list_insert_sorted (names, str,
161 (GCompareFunc)g_strcasecmp);
166 gl_debug (DEBUG_TEMPLATE, "templates = %p", templates);
167 gl_debug (DEBUG_TEMPLATE, "names = %p", names);
169 gl_debug (DEBUG_TEMPLATE, "END");
173 /*****************************************************************************/
174 /* Free a list of template names. */
175 /*****************************************************************************/
177 gl_template_free_name_list (GList ** names)
181 gl_debug (DEBUG_TEMPLATE, "START");
183 for (p_name = *names; p_name != NULL; p_name = p_name->next) {
184 g_free (p_name->data);
188 g_list_free (*names);
191 gl_debug (DEBUG_TEMPLATE, "END");
194 /*****************************************************************************/
195 /* Return a template structure from a name. */
196 /*****************************************************************************/
198 gl_template_from_name (const gchar * name)
200 GList *p_tmplt, *p_name;
201 glTemplate *template;
204 gl_debug (DEBUG_TEMPLATE, "START");
207 /* If no name, return first template as a default */
208 return (glTemplate *) templates->data;
211 split_name = g_strsplit (name, ":", 2);
213 for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) {
214 template = (glTemplate *) p_tmplt->data;
215 for (p_name = template->name; p_name != NULL;
216 p_name = p_name->next) {
217 if (g_strcasecmp (p_name->data, split_name[0]) == 0) {
218 g_strfreev (split_name);
219 gl_debug (DEBUG_TEMPLATE, "END");
220 return gl_template_dup (template);
225 g_strfreev (split_name);
227 gl_debug (DEBUG_TEMPLATE, "END");
231 /*****************************************************************************/
232 /* Copy a template. */
233 /*****************************************************************************/
234 glTemplate *gl_template_dup (const glTemplate *orig_template)
236 glTemplate *template;
239 gl_debug (DEBUG_TEMPLATE, "START");
241 template = g_new0 (glTemplate,1);
243 /* Shallow copy first */
244 *template = *orig_template;
246 /* Now the deep stuff */
247 template->name = NULL;
248 for ( p=orig_template->name; p != NULL; p=p->next ) {
249 template->name = g_list_append (template->name,
252 template->description = g_strdup (orig_template->description);
253 template->page_size = g_strdup (orig_template->page_size);
255 gl_debug (DEBUG_TEMPLATE, "END");
259 /*****************************************************************************/
260 /* Free up a template. */
261 /*****************************************************************************/
262 void gl_template_free (glTemplate **template)
266 gl_debug (DEBUG_TEMPLATE, "START");
268 if ( *template != NULL ) {
270 for ( p=(*template)->name; p != NULL; p=p->next ) {
274 g_list_free ((*template)->name);
275 (*template)->name = NULL;
277 g_free ((*template)->description);
278 (*template)->description = NULL;
280 g_free ((*template)->page_size);
281 (*template)->page_size = NULL;
288 gl_debug (DEBUG_TEMPLATE, "END");
291 /*--------------------------------------------------------------------------*/
292 /* PRIVATE. Make a template for a full page of the given page size. */
293 /*--------------------------------------------------------------------------*/
295 template_full_page (const gchar *page_size)
297 const GnomePrintPaper *paper;
298 glTemplate *template;
300 paper = gnome_print_paper_get_by_name (page_size);
301 if ( paper == NULL ) {
305 template = g_new0 (glTemplate, 1);
307 template->name = g_list_append (template->name,
308 g_strdup_printf("*%s", page_size));
309 template->page_size = g_strdup(page_size);
310 template->description = g_strdup(FULL_PAGE);
312 template->style = GL_TEMPLATE_STYLE_RECT;
317 template->label_width = paper->width;
318 template->label_height = paper->height;
319 template->label_round = 0.0;
321 template->label_margin = 5.0;
326 /*--------------------------------------------------------------------------*/
327 /* PRIVATE. Read templates from various files. */
328 /*--------------------------------------------------------------------------*/
330 read_templates (void)
332 gchar *home_data_dir = get_home_data_dir ();
333 GList *templates = NULL;
335 gl_debug (DEBUG_TEMPLATE, "START");
339 templates = read_template_files_from_dir (templates, GL_DATA_DIR);
340 templates = read_template_files_from_dir (templates, home_data_dir);
342 g_free (home_data_dir);
344 if (templates == NULL) {
345 g_warning (_("No template files found!"));
348 gl_debug (DEBUG_TEMPLATE, "END");
352 /*--------------------------------------------------------------------------*/
353 /* PRIVATE. get '~/.glabels' directory path. */
354 /*--------------------------------------------------------------------------*/
356 get_home_data_dir (void)
358 gchar *dir = gnome_util_prepend_user_home (".glabels");
360 gl_debug (DEBUG_TEMPLATE, "START");
362 /* Try to create ~/.glabels directory. If it exists, no problem. */
365 gl_debug (DEBUG_TEMPLATE, "END");
369 /*--------------------------------------------------------------------------*/
370 /* PRIVATE. Read all template files from given directory. Append to list. */
371 /*--------------------------------------------------------------------------*/
373 read_template_files_from_dir (GList * templates,
374 const gchar * dirname)
377 const gchar *filename, *extension;
378 gchar *full_filename = NULL;
379 GError *gerror = NULL;
381 gl_debug (DEBUG_TEMPLATE, "START");
386 dp = g_dir_open (dirname, 0, &gerror);
387 if (gerror != NULL) {
388 g_warning ("cannot open data directory: %s", gerror->message );
389 gl_debug (DEBUG_TEMPLATE, "END");
393 while ((filename = g_dir_read_name (dp)) != NULL) {
395 extension = strrchr (filename, '.');
397 if (extension != NULL) {
399 if (strcasecmp (extension, ".template") == 0) {
402 g_build_filename (dirname, filename, NULL);
404 read_templates_from_file (templates,
406 g_free (full_filename);
416 gl_debug (DEBUG_TEMPLATE, "END");
420 /*--------------------------------------------------------------------------*/
421 /* PRIVATE. Read templates from template file. */
422 /*--------------------------------------------------------------------------*/
424 read_templates_from_file (GList * templates,
425 gchar * xml_filename)
428 xmlNodePtr root, node;
429 glTemplate *template;
431 gl_debug (DEBUG_TEMPLATE, "START");
433 doc = xmlParseFile (xml_filename);
435 g_warning ("\"%s\" is not a glabels template file (not XML)",
440 root = xmlDocGetRootElement (doc);
441 if (!root || !root->name) {
442 g_warning ("\"%s\" is not a glabels template file (no root node)",
447 if (g_strcasecmp (root->name, "glabels-templates") != 0) {
448 g_warning ("\"%s\" is not a glabels template file (wrong root node)",
454 for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
456 if (g_strcasecmp (node->name, "Sheet") == 0) {
457 template = gl_template_xml_parse_sheet (node);
458 templates = g_list_append (templates, template);
460 if ( !xmlNodeIsText(node) ) {
461 if (g_strcasecmp (node->name,"comment") != 0) {
462 g_warning ("bad node = \"%s\"",node->name);
470 gl_debug (DEBUG_TEMPLATE, "END");
474 /*****************************************************************************/
475 /* Parse XML template Node. */
476 /*****************************************************************************/
478 gl_template_xml_parse_sheet (xmlNodePtr sheet_node)
480 glTemplate *template;
483 gl_debug (DEBUG_TEMPLATE, "START");
485 template = g_new0 (glTemplate, 1);
487 template->name = g_list_append (template->name,
488 xmlGetProp (sheet_node, "name"));
489 template->page_size = xmlGetProp (sheet_node, "size");
490 if ( strcmp (template->page_size,"US-Letter") == 0 ) {
491 /* Compatibility with old pre-1.0 template files.*/
492 template->page_size = "US Letter";
494 template->description = xmlGetProp (sheet_node, "description");
496 for (node = sheet_node->xmlChildrenNode; node != NULL;
498 if (g_strcasecmp (node->name, "Label") == 0) {
499 xml_parse_label (node, template);
500 } else if (g_strcasecmp (node->name, "Alias") == 0) {
501 xml_parse_alias (node, template);
503 if (g_strcasecmp (node->name, "text") != 0) {
504 g_warning ("bad node = \"%s\"", node->name);
509 gl_debug (DEBUG_TEMPLATE, "END");
514 /*--------------------------------------------------------------------------*/
515 /* PRIVATE. Parse XML Sheet->Label Node. */
516 /*--------------------------------------------------------------------------*/
518 xml_parse_label (xmlNodePtr label_node,
519 glTemplate * template)
524 gl_debug (DEBUG_TEMPLATE, "START");
526 style = xmlGetProp (label_node, "style");
527 if (g_strcasecmp (style, "rectangle") == 0) {
528 template->style = GL_TEMPLATE_STYLE_RECT;
529 } else if (g_strcasecmp (style, "round") == 0) {
530 template->style = GL_TEMPLATE_STYLE_ROUND;
531 } else if (g_strcasecmp (style, "cd") == 0) {
532 template->style = GL_TEMPLATE_STYLE_CD;
534 g_warning ("Unknown label style in template");
537 if (template->style == GL_TEMPLATE_STYLE_RECT) {
538 template->label_width =
539 g_strtod (xmlGetProp (label_node, "width"), NULL);
540 template->label_height =
541 g_strtod (xmlGetProp (label_node, "height"), NULL);
542 template->label_round =
543 g_strtod (xmlGetProp (label_node, "round"), NULL);
544 } else if (template->style == GL_TEMPLATE_STYLE_ROUND) {
545 template->label_radius =
546 g_strtod (xmlGetProp (label_node, "radius"), NULL);
547 template->label_width = 2.0 * template->label_radius;
548 template->label_height = 2.0 * template->label_radius;
549 } else if (template->style == GL_TEMPLATE_STYLE_CD) {
550 template->label_radius =
551 g_strtod (xmlGetProp (label_node, "radius"), NULL);
552 template->label_hole =
553 g_strtod (xmlGetProp (label_node, "hole"), NULL);
554 template->label_width = 2.0 * template->label_radius;
555 template->label_height = 2.0 * template->label_radius;
558 for (node = label_node->xmlChildrenNode; node != NULL;
560 if (g_strcasecmp (node->name, "Layout") == 0) {
561 xml_parse_layout (node, template);
562 } else if (g_strcasecmp (node->name, "Markup") == 0) {
563 xml_parse_markup (node, template);
564 } else if (g_strcasecmp (node->name, "text") != 0) {
565 g_warning ("bad node = \"%s\"", node->name);
569 gl_debug (DEBUG_TEMPLATE, "END");
572 /*--------------------------------------------------------------------------*/
573 /* PRIVATE. Parse XML Sheet->Label->Layout Node. */
574 /*--------------------------------------------------------------------------*/
576 xml_parse_layout (xmlNodePtr layout_node,
577 glTemplate * template)
581 gl_debug (DEBUG_TEMPLATE, "START");
583 sscanf (xmlGetProp (layout_node, "nx"), "%d", &(template->nx));
584 sscanf (xmlGetProp (layout_node, "ny"), "%d", &(template->ny));
585 template->x0 = g_strtod (xmlGetProp (layout_node, "x0"), NULL);
586 template->y0 = g_strtod (xmlGetProp (layout_node, "y0"), NULL);
587 template->dx = g_strtod (xmlGetProp (layout_node, "dx"), NULL);
588 template->dy = g_strtod (xmlGetProp (layout_node, "dy"), NULL);
590 for (node = layout_node->xmlChildrenNode; node != NULL;
592 if (g_strcasecmp (node->name, "text") != 0) {
593 g_warning ("bad node = \"%s\"", node->name);
597 gl_debug (DEBUG_TEMPLATE, "END");
600 /*--------------------------------------------------------------------------*/
601 /* PRIVATE. Parse XML Sheet->Label->Markup Node. */
602 /*--------------------------------------------------------------------------*/
604 xml_parse_markup (xmlNodePtr markup_node,
605 glTemplate * template)
610 gl_debug (DEBUG_TEMPLATE, "START");
612 type = xmlGetProp (markup_node, "type");
613 if (g_strcasecmp (type, "margin") == 0) {
614 template->label_margin =
615 g_strtod (xmlGetProp (markup_node, "size"), NULL);
618 for (node = markup_node->xmlChildrenNode; node != NULL;
620 if (g_strcasecmp (node->name, "text") != 0) {
621 g_warning ("bad node = \"%s\"", node->name);
625 gl_debug (DEBUG_TEMPLATE, "END");
628 /*--------------------------------------------------------------------------*/
629 /* PRIVATE. Parse XML Sheet->Alias Node. */
630 /*--------------------------------------------------------------------------*/
632 xml_parse_alias (xmlNodePtr alias_node,
633 glTemplate * template)
635 gl_debug (DEBUG_TEMPLATE, "START");
637 template->name = g_list_append (template->name,
638 xmlGetProp (alias_node, "name"));
640 gl_debug (DEBUG_TEMPLATE, "END");
643 /****************************************************************************/
644 /* Add XML Template Node */
645 /****************************************************************************/
647 gl_template_xml_add_sheet (glTemplate * template,
654 gl_debug (DEBUG_TEMPLATE, "START");
656 node = xmlNewChild (root, ns, "Sheet", NULL);
658 xmlSetProp (node, "name", template->name->data);
659 xmlSetProp (node, "size", template->page_size);
660 xmlSetProp (node, "description", template->description);
662 xml_add_label (template, node, ns);
664 for ( p=template->name->next; p != NULL; p=p->next ) {
665 xml_add_alias( p->data, node, ns );
668 gl_debug (DEBUG_TEMPLATE, "END");
671 /*--------------------------------------------------------------------------*/
672 /* PRIVATE. Add XML Sheet->Label Node. */
673 /*--------------------------------------------------------------------------*/
675 xml_add_label (glTemplate *template,
682 gl_debug (DEBUG_TEMPLATE, "START");
684 node = xmlNewChild(root, ns, "Label", NULL);
686 xmlSetProp (node, "id", "0");
688 switch (template->style) {
689 case GL_TEMPLATE_STYLE_RECT:
690 xmlSetProp (node, "style", "rectangle");
691 string = g_strdup_printf ("%g", template->label_width);
692 xmlSetProp (node, "width", string);
694 string = g_strdup_printf ("%g", template->label_height);
695 xmlSetProp (node, "height", string);
697 string = g_strdup_printf ("%g", template->label_round);
698 xmlSetProp (node, "round", string);
701 case GL_TEMPLATE_STYLE_ROUND:
702 xmlSetProp (node, "style", "round");
703 string = g_strdup_printf ("%g", template->label_radius);
704 xmlSetProp (node, "radius", string);
707 case GL_TEMPLATE_STYLE_CD:
708 xmlSetProp (node, "style", "cd");
709 string = g_strdup_printf ("%g", template->label_radius);
710 xmlSetProp (node, "radius", string);
712 string = g_strdup_printf ("%g", template->label_hole);
713 xmlSetProp (node, "hole", string);
717 g_warning ("Unknown label style");
721 xml_add_markup_margin (template, node, ns);
722 xml_add_layout (template, node, ns);
724 gl_debug (DEBUG_TEMPLATE, "END");
727 /*--------------------------------------------------------------------------*/
728 /* PRIVATE. Add XML Sheet->Label->Layout Node. */
729 /*--------------------------------------------------------------------------*/
731 xml_add_layout (glTemplate *template,
738 gl_debug (DEBUG_TEMPLATE, "START");
740 node = xmlNewChild(root, ns, "Layout", NULL);
741 string = g_strdup_printf ("%d", template->nx);
742 xmlSetProp (node, "nx", string);
744 string = g_strdup_printf ("%d", template->ny);
745 xmlSetProp (node, "ny", string);
747 string = g_strdup_printf ("%g", template->x0);
748 xmlSetProp (node, "x0", string);
750 string = g_strdup_printf ("%g", template->y0);
751 xmlSetProp (node, "y0", string);
753 string = g_strdup_printf ("%g", template->dx);
754 xmlSetProp (node, "dx", string);
756 string = g_strdup_printf ("%g", template->dy);
757 xmlSetProp (node, "dy", string);
760 gl_debug (DEBUG_TEMPLATE, "END");
763 /*--------------------------------------------------------------------------*/
764 /* PRIVATE. Add XML Sheet->Label->Markup Node. */
765 /*--------------------------------------------------------------------------*/
767 xml_add_markup_margin (glTemplate *template,
774 gl_debug (DEBUG_TEMPLATE, "START");
776 node = xmlNewChild(root, ns, "Markup", NULL);
777 xmlSetProp (node, "type", "margin");
779 string = g_strdup_printf ("%g", template->label_margin);
780 xmlSetProp (node, "size", string);
783 gl_debug (DEBUG_TEMPLATE, "END");
786 /*--------------------------------------------------------------------------*/
787 /* PRIVATE. Add XML Sheet->Alias Node. */
788 /*--------------------------------------------------------------------------*/
790 xml_add_alias (gchar *name,
796 gl_debug (DEBUG_TEMPLATE, "START");
798 node = xmlNewChild (root, ns, "Alias", NULL);
799 xmlSetProp (node, "name", name);
801 gl_debug (DEBUG_TEMPLATE, "END");