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 #ifdef PACKAGE_DATA_DIR
33 #define GL_DATA_DIR (PACKAGE_DATA_DIR G_DIR_SEPARATOR_S "glabels")
35 #define GL_DATA_DIR gnome_datadir_file("glabels")
38 #define FULL_PAGE "Full-page"
40 /*===========================================*/
42 /*===========================================*/
44 /*===========================================*/
46 /*===========================================*/
48 static GList *templates = NULL;
50 /*===========================================*/
51 /* Local function prototypes */
52 /*===========================================*/
53 static glTemplate *template_full_page (const gchar *page_size);
55 static GList *read_templates (void);
57 static gchar *get_home_data_dir (void);
58 static GList *read_template_files_from_dir (GList * templates,
59 const gchar * dirname);
60 static GList *read_templates_from_file (GList * templates,
61 gchar * xml_filename);
63 static void xml_parse_label (xmlNodePtr label_node, glTemplate * template);
64 static void xml_parse_layout (xmlNodePtr layout_node, glTemplate * template);
65 static void xml_parse_markup (xmlNodePtr markup_node, glTemplate * template);
66 static void xml_parse_alias (xmlNodePtr alias_node, glTemplate * template);
68 static void xml_add_label (glTemplate *template, xmlNodePtr root, xmlNsPtr ns);
69 static void xml_add_layout (glTemplate *template, xmlNodePtr root, xmlNsPtr ns);
70 static void xml_add_markup_margin (glTemplate *template, xmlNodePtr root, xmlNsPtr ns);
71 static void xml_add_alias (gchar *name, xmlNodePtr root, xmlNsPtr ns);
73 /*****************************************************************************/
74 /* Initialize module. */
75 /*****************************************************************************/
77 gl_template_init (void)
79 GList *page_sizes, *p;
81 gl_debug (DEBUG_TEMPLATE, "START");
83 templates = read_templates ();
85 page_sizes = gl_template_get_page_size_list ();
86 for ( p=page_sizes; p != NULL; p=p->next ) {
87 templates = g_list_append (templates,
88 template_full_page (p->data));
90 gl_template_free_page_size_list (&page_sizes);
92 gl_debug (DEBUG_TEMPLATE, "END");
95 /*****************************************************************************/
96 /* Get a list of valid page size names */
97 /*****************************************************************************/
99 gl_template_get_page_size_list (void)
102 GList *p, *paper_list;
103 GnomePrintPaper *paper;
105 gl_debug (DEBUG_TEMPLATE, "START");
107 paper_list = gnome_print_paper_get_list();
108 for ( p=paper_list; p != NULL; p=p->next ) {
109 paper = (GnomePrintPaper *)p->data;
110 if ( g_strcasecmp(paper->name, "custom") != 0 ) {
111 names = g_list_append (names, g_strdup (paper->name));
115 gl_debug (DEBUG_TEMPLATE, "END");
119 /*****************************************************************************/
120 /* Free a list of page size names. */
121 /*****************************************************************************/
123 gl_template_free_page_size_list (GList ** names)
127 gl_debug (DEBUG_TEMPLATE, "START");
129 for (p_name = *names; p_name != NULL; p_name = p_name->next) {
130 g_free (p_name->data);
134 g_list_free (*names);
137 gl_debug (DEBUG_TEMPLATE, "END");
140 /*****************************************************************************/
141 /* Get a list of valid template names for given page size */
142 /*****************************************************************************/
144 gl_template_get_name_list (const gchar * page_size)
146 GList *p_tmplt, *p_name;
147 glTemplate *template;
151 gl_debug (DEBUG_TEMPLATE, "START");
153 for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) {
154 template = (glTemplate *) p_tmplt->data;
155 if (g_strcasecmp (page_size, template->page_size) == 0) {
156 for (p_name = template->name; p_name != NULL;
157 p_name = p_name->next) {
158 str = g_strdup_printf("%s: %s",
159 (gchar *) p_name->data,
160 template->description);
161 names = g_list_insert_sorted (names, str,
162 (GCompareFunc)g_strcasecmp);
167 gl_debug (DEBUG_TEMPLATE, "templates = %p", templates);
168 gl_debug (DEBUG_TEMPLATE, "names = %p", names);
170 gl_debug (DEBUG_TEMPLATE, "END");
174 /*****************************************************************************/
175 /* Free a list of template names. */
176 /*****************************************************************************/
178 gl_template_free_name_list (GList ** names)
182 gl_debug (DEBUG_TEMPLATE, "START");
184 for (p_name = *names; p_name != NULL; p_name = p_name->next) {
185 g_free (p_name->data);
189 g_list_free (*names);
192 gl_debug (DEBUG_TEMPLATE, "END");
195 /*****************************************************************************/
196 /* Return a template structure from a name. */
197 /*****************************************************************************/
199 gl_template_from_name (const gchar * name)
201 GList *p_tmplt, *p_name;
202 glTemplate *template;
205 gl_debug (DEBUG_TEMPLATE, "START");
208 /* If no name, return first template as a default */
209 return (glTemplate *) templates->data;
212 split_name = g_strsplit (name, ":", 2);
214 for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) {
215 template = (glTemplate *) p_tmplt->data;
216 for (p_name = template->name; p_name != NULL;
217 p_name = p_name->next) {
218 if (g_strcasecmp (p_name->data, split_name[0]) == 0) {
219 g_strfreev (split_name);
220 gl_debug (DEBUG_TEMPLATE, "END");
221 return gl_template_dup (template);
226 g_strfreev (split_name);
228 gl_debug (DEBUG_TEMPLATE, "END");
232 /*****************************************************************************/
233 /* Copy a template. */
234 /*****************************************************************************/
235 glTemplate *gl_template_dup (const glTemplate *orig_template)
237 glTemplate *template;
240 gl_debug (DEBUG_TEMPLATE, "START");
242 template = g_new0 (glTemplate,1);
244 /* Shallow copy first */
245 *template = *orig_template;
247 /* Now the deep stuff */
248 template->name = NULL;
249 for ( p=orig_template->name; p != NULL; p=p->next ) {
250 template->name = g_list_append (template->name,
253 template->description = g_strdup (orig_template->description);
254 template->page_size = g_strdup (orig_template->page_size);
256 gl_debug (DEBUG_TEMPLATE, "END");
260 /*****************************************************************************/
261 /* Free up a template. */
262 /*****************************************************************************/
263 void gl_template_free (glTemplate **template)
267 gl_debug (DEBUG_TEMPLATE, "START");
269 if ( *template != NULL ) {
271 for ( p=(*template)->name; p != NULL; p=p->next ) {
275 g_list_free ((*template)->name);
276 (*template)->name = NULL;
278 g_free ((*template)->description);
279 (*template)->description = NULL;
281 g_free ((*template)->page_size);
282 (*template)->page_size = NULL;
289 gl_debug (DEBUG_TEMPLATE, "END");
292 /*--------------------------------------------------------------------------*/
293 /* PRIVATE. Make a template for a full page of the given page size. */
294 /*--------------------------------------------------------------------------*/
296 template_full_page (const gchar *page_size)
298 const GnomePrintPaper *paper;
299 glTemplate *template;
301 paper = gnome_print_paper_get_by_name (page_size);
302 if ( paper == NULL ) {
306 template = g_new0 (glTemplate, 1);
308 template->name = g_list_append (template->name,
309 g_strdup_printf("*%s", page_size));
310 template->page_size = g_strdup(page_size);
311 template->description = g_strdup(FULL_PAGE);
313 template->style = GL_TEMPLATE_STYLE_RECT;
318 template->label_width = paper->width;
319 template->label_height = paper->height;
320 template->label_round = 0.0;
322 template->label_margin = 5.0;
327 /*--------------------------------------------------------------------------*/
328 /* PRIVATE. Read templates from various files. */
329 /*--------------------------------------------------------------------------*/
331 read_templates (void)
333 gchar *home_data_dir = get_home_data_dir ();
334 GList *templates = NULL;
336 gl_debug (DEBUG_TEMPLATE, "START");
340 templates = read_template_files_from_dir (templates, GL_DATA_DIR);
341 templates = read_template_files_from_dir (templates, home_data_dir);
343 g_free (home_data_dir);
345 if (templates == NULL) {
346 g_warning (_("No template files found!"));
349 gl_debug (DEBUG_TEMPLATE, "END");
353 /*--------------------------------------------------------------------------*/
354 /* PRIVATE. get '~/.glabels' directory path. */
355 /*--------------------------------------------------------------------------*/
357 get_home_data_dir (void)
359 gchar *dir = gnome_util_prepend_user_home (".glabels");
361 gl_debug (DEBUG_TEMPLATE, "START");
363 /* Try to create ~/.glabels directory. If it exists, no problem. */
366 gl_debug (DEBUG_TEMPLATE, "END");
370 /*--------------------------------------------------------------------------*/
371 /* PRIVATE. Read all template files from given directory. Append to list. */
372 /*--------------------------------------------------------------------------*/
374 read_template_files_from_dir (GList * templates,
375 const gchar * dirname)
378 const gchar *filename, *extension;
379 gchar *full_filename = NULL;
380 GError *gerror = NULL;
382 gl_debug (DEBUG_TEMPLATE, "START");
387 dp = g_dir_open (dirname, 0, &gerror);
388 if (gerror != NULL) {
389 g_warning ("cannot open data directory: %s", gerror->message );
390 gl_debug (DEBUG_TEMPLATE, "END");
394 while ((filename = g_dir_read_name (dp)) != NULL) {
396 extension = strrchr (filename, '.');
398 if (extension != NULL) {
400 if (strcasecmp (extension, ".template") == 0) {
403 g_build_filename (dirname, filename, NULL);
405 read_templates_from_file (templates,
407 g_free (full_filename);
417 gl_debug (DEBUG_TEMPLATE, "END");
421 /*--------------------------------------------------------------------------*/
422 /* PRIVATE. Read templates from template file. */
423 /*--------------------------------------------------------------------------*/
425 read_templates_from_file (GList * templates,
426 gchar * xml_filename)
429 xmlNodePtr root, node;
430 glTemplate *template;
432 gl_debug (DEBUG_TEMPLATE, "START");
434 doc = xmlParseFile (xml_filename);
436 g_warning ("\"%s\" is not a glabels template file (not XML)",
441 root = xmlDocGetRootElement (doc);
442 if (!root || !root->name) {
443 g_warning ("\"%s\" is not a glabels template file (no root node)",
448 if (g_strcasecmp (root->name, "glabels-templates") != 0) {
449 g_warning ("\"%s\" is not a glabels template file (wrong root node)",
455 for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
457 if (g_strcasecmp (node->name, "Sheet") == 0) {
458 template = gl_template_xml_parse_sheet (node);
459 templates = g_list_append (templates, template);
461 if ( !xmlNodeIsText(node) ) {
462 if (g_strcasecmp (node->name,"comment") != 0) {
463 g_warning ("bad node = \"%s\"",node->name);
471 gl_debug (DEBUG_TEMPLATE, "END");
475 /*****************************************************************************/
476 /* Parse XML template Node. */
477 /*****************************************************************************/
479 gl_template_xml_parse_sheet (xmlNodePtr sheet_node)
481 glTemplate *template;
484 gl_debug (DEBUG_TEMPLATE, "START");
486 template = g_new0 (glTemplate, 1);
488 template->name = g_list_append (template->name,
489 xmlGetProp (sheet_node, "name"));
490 template->page_size = xmlGetProp (sheet_node, "size");
491 if ( strcmp (template->page_size,"US-Letter") == 0 ) {
492 /* Compatibility with old pre-1.0 template files.*/
493 template->page_size = "US Letter";
495 template->description = xmlGetProp (sheet_node, "description");
497 for (node = sheet_node->xmlChildrenNode; node != NULL;
499 if (g_strcasecmp (node->name, "Label") == 0) {
500 xml_parse_label (node, template);
501 } else if (g_strcasecmp (node->name, "Alias") == 0) {
502 xml_parse_alias (node, template);
504 if (g_strcasecmp (node->name, "text") != 0) {
505 g_warning ("bad node = \"%s\"", node->name);
510 gl_debug (DEBUG_TEMPLATE, "END");
515 /*--------------------------------------------------------------------------*/
516 /* PRIVATE. Parse XML Sheet->Label Node. */
517 /*--------------------------------------------------------------------------*/
519 xml_parse_label (xmlNodePtr label_node,
520 glTemplate * template)
525 gl_debug (DEBUG_TEMPLATE, "START");
527 style = xmlGetProp (label_node, "style");
528 if (g_strcasecmp (style, "rectangle") == 0) {
529 template->style = GL_TEMPLATE_STYLE_RECT;
530 } else if (g_strcasecmp (style, "round") == 0) {
531 template->style = GL_TEMPLATE_STYLE_ROUND;
532 } else if (g_strcasecmp (style, "cd") == 0) {
533 template->style = GL_TEMPLATE_STYLE_CD;
535 g_warning ("Unknown label style in template");
538 if (template->style == GL_TEMPLATE_STYLE_RECT) {
539 template->label_width =
540 g_strtod (xmlGetProp (label_node, "width"), NULL);
541 template->label_height =
542 g_strtod (xmlGetProp (label_node, "height"), NULL);
543 template->label_round =
544 g_strtod (xmlGetProp (label_node, "round"), NULL);
545 } else if (template->style == GL_TEMPLATE_STYLE_ROUND) {
546 template->label_radius =
547 g_strtod (xmlGetProp (label_node, "radius"), NULL);
548 template->label_width = 2.0 * template->label_radius;
549 template->label_height = 2.0 * template->label_radius;
550 } else if (template->style == GL_TEMPLATE_STYLE_CD) {
551 template->label_radius =
552 g_strtod (xmlGetProp (label_node, "radius"), NULL);
553 template->label_hole =
554 g_strtod (xmlGetProp (label_node, "hole"), NULL);
555 template->label_width = 2.0 * template->label_radius;
556 template->label_height = 2.0 * template->label_radius;
559 for (node = label_node->xmlChildrenNode; node != NULL;
561 if (g_strcasecmp (node->name, "Layout") == 0) {
562 xml_parse_layout (node, template);
563 } else if (g_strcasecmp (node->name, "Markup") == 0) {
564 xml_parse_markup (node, template);
565 } else if (g_strcasecmp (node->name, "text") != 0) {
566 g_warning ("bad node = \"%s\"", node->name);
570 gl_debug (DEBUG_TEMPLATE, "END");
573 /*--------------------------------------------------------------------------*/
574 /* PRIVATE. Parse XML Sheet->Label->Layout Node. */
575 /*--------------------------------------------------------------------------*/
577 xml_parse_layout (xmlNodePtr layout_node,
578 glTemplate * template)
582 gl_debug (DEBUG_TEMPLATE, "START");
584 sscanf (xmlGetProp (layout_node, "nx"), "%d", &(template->nx));
585 sscanf (xmlGetProp (layout_node, "ny"), "%d", &(template->ny));
586 template->x0 = g_strtod (xmlGetProp (layout_node, "x0"), NULL);
587 template->y0 = g_strtod (xmlGetProp (layout_node, "y0"), NULL);
588 template->dx = g_strtod (xmlGetProp (layout_node, "dx"), NULL);
589 template->dy = g_strtod (xmlGetProp (layout_node, "dy"), NULL);
591 for (node = layout_node->xmlChildrenNode; node != NULL;
593 if (g_strcasecmp (node->name, "text") != 0) {
594 g_warning ("bad node = \"%s\"", node->name);
598 gl_debug (DEBUG_TEMPLATE, "END");
601 /*--------------------------------------------------------------------------*/
602 /* PRIVATE. Parse XML Sheet->Label->Markup Node. */
603 /*--------------------------------------------------------------------------*/
605 xml_parse_markup (xmlNodePtr markup_node,
606 glTemplate * template)
611 gl_debug (DEBUG_TEMPLATE, "START");
613 type = xmlGetProp (markup_node, "type");
614 if (g_strcasecmp (type, "margin") == 0) {
615 template->label_margin =
616 g_strtod (xmlGetProp (markup_node, "size"), NULL);
619 for (node = markup_node->xmlChildrenNode; node != NULL;
621 if (g_strcasecmp (node->name, "text") != 0) {
622 g_warning ("bad node = \"%s\"", node->name);
626 gl_debug (DEBUG_TEMPLATE, "END");
629 /*--------------------------------------------------------------------------*/
630 /* PRIVATE. Parse XML Sheet->Alias Node. */
631 /*--------------------------------------------------------------------------*/
633 xml_parse_alias (xmlNodePtr alias_node,
634 glTemplate * template)
636 gl_debug (DEBUG_TEMPLATE, "START");
638 template->name = g_list_append (template->name,
639 xmlGetProp (alias_node, "name"));
641 gl_debug (DEBUG_TEMPLATE, "END");
644 /****************************************************************************/
645 /* Add XML Template Node */
646 /****************************************************************************/
648 gl_template_xml_add_sheet (glTemplate * template,
655 gl_debug (DEBUG_TEMPLATE, "START");
657 node = xmlNewChild (root, ns, "Sheet", NULL);
659 xmlSetProp (node, "name", template->name->data);
660 xmlSetProp (node, "size", template->page_size);
661 xmlSetProp (node, "description", template->description);
663 xml_add_label (template, node, ns);
665 for ( p=template->name->next; p != NULL; p=p->next ) {
666 xml_add_alias( p->data, node, ns );
669 gl_debug (DEBUG_TEMPLATE, "END");
672 /*--------------------------------------------------------------------------*/
673 /* PRIVATE. Add XML Sheet->Label Node. */
674 /*--------------------------------------------------------------------------*/
676 xml_add_label (glTemplate *template,
683 gl_debug (DEBUG_TEMPLATE, "START");
685 node = xmlNewChild(root, ns, "Label", NULL);
687 xmlSetProp (node, "id", "0");
689 switch (template->style) {
690 case GL_TEMPLATE_STYLE_RECT:
691 xmlSetProp (node, "style", "rectangle");
692 string = g_strdup_printf ("%g", template->label_width);
693 xmlSetProp (node, "width", string);
695 string = g_strdup_printf ("%g", template->label_height);
696 xmlSetProp (node, "height", string);
698 string = g_strdup_printf ("%g", template->label_round);
699 xmlSetProp (node, "round", string);
702 case GL_TEMPLATE_STYLE_ROUND:
703 xmlSetProp (node, "style", "round");
704 string = g_strdup_printf ("%g", template->label_radius);
705 xmlSetProp (node, "radius", string);
708 case GL_TEMPLATE_STYLE_CD:
709 xmlSetProp (node, "style", "cd");
710 string = g_strdup_printf ("%g", template->label_radius);
711 xmlSetProp (node, "radius", string);
713 string = g_strdup_printf ("%g", template->label_hole);
714 xmlSetProp (node, "hole", string);
718 g_warning ("Unknown label style");
722 xml_add_markup_margin (template, node, ns);
723 xml_add_layout (template, node, ns);
725 gl_debug (DEBUG_TEMPLATE, "END");
728 /*--------------------------------------------------------------------------*/
729 /* PRIVATE. Add XML Sheet->Label->Layout Node. */
730 /*--------------------------------------------------------------------------*/
732 xml_add_layout (glTemplate *template,
739 gl_debug (DEBUG_TEMPLATE, "START");
741 node = xmlNewChild(root, ns, "Layout", NULL);
742 string = g_strdup_printf ("%d", template->nx);
743 xmlSetProp (node, "nx", string);
745 string = g_strdup_printf ("%d", template->ny);
746 xmlSetProp (node, "ny", string);
748 string = g_strdup_printf ("%g", template->x0);
749 xmlSetProp (node, "x0", string);
751 string = g_strdup_printf ("%g", template->y0);
752 xmlSetProp (node, "y0", string);
754 string = g_strdup_printf ("%g", template->dx);
755 xmlSetProp (node, "dx", string);
757 string = g_strdup_printf ("%g", template->dy);
758 xmlSetProp (node, "dy", string);
761 gl_debug (DEBUG_TEMPLATE, "END");
764 /*--------------------------------------------------------------------------*/
765 /* PRIVATE. Add XML Sheet->Label->Markup Node. */
766 /*--------------------------------------------------------------------------*/
768 xml_add_markup_margin (glTemplate *template,
775 gl_debug (DEBUG_TEMPLATE, "START");
777 node = xmlNewChild(root, ns, "Markup", NULL);
778 xmlSetProp (node, "type", "margin");
780 string = g_strdup_printf ("%g", template->label_margin);
781 xmlSetProp (node, "size", string);
784 gl_debug (DEBUG_TEMPLATE, "END");
787 /*--------------------------------------------------------------------------*/
788 /* PRIVATE. Add XML Sheet->Alias Node. */
789 /*--------------------------------------------------------------------------*/
791 xml_add_alias (gchar *name,
797 gl_debug (DEBUG_TEMPLATE, "START");
799 node = xmlNewChild (root, ns, "Alias", NULL);
800 xmlSetProp (node, "name", name);
802 gl_debug (DEBUG_TEMPLATE, "END");