]> git.sur5r.net Git - glabels/blob - glabels1/src/template.c
2009-09-22 Jim Evins <evins@snaught.com>
[glabels] / glabels1 / src / template.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  template.c:  template module
5  *
6  *  Copyright (C) 2001-2002  Jim Evins <evins@snaught.com>.
7  *
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.
12  *
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.
17  *
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
21  */
22
23 #include <config.h>
24
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <dirent.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30
31
32 #include "template.h"
33
34 #include "debug.h"
35
36 #ifdef PACKAGE_DATA_DIR
37 #define GL_DATA_DIR (PACKAGE_DATA_DIR G_DIR_SEPARATOR_S "glabels")
38 #else
39 #define GL_DATA_DIR gnome_datadir_file("glabels")
40 #endif
41
42 /*===========================================*/
43 /* Private types                             */
44 /*===========================================*/
45
46 /*===========================================*/
47 /* Private globals                           */
48 /*===========================================*/
49
50 static GList *templates = NULL;
51
52 /*===========================================*/
53 /* Local function prototypes                 */
54 /*===========================================*/
55 static GList *read_templates (void);
56
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);
62
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_alias (xmlNodePtr alias_node, glTemplate * template);
66
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_alias (gchar *name, xmlNodePtr root, xmlNsPtr ns);
70
71 /*****************************************************************************/
72 /* Initialize module.                                                        */
73 /*****************************************************************************/
74 void
75 gl_template_init (void)
76 {
77         templates = read_templates ();
78 }
79
80 /*****************************************************************************/
81 /* Get a list of valid template names for given page size                    */
82 /*****************************************************************************/
83 GList *
84 gl_template_get_name_list (const gchar * page_size)
85 {
86         GList *p_tmplt, *p_name;
87         glTemplate *template;
88         gchar *str;
89         GList *names = NULL;
90
91         for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) {
92                 template = (glTemplate *) p_tmplt->data;
93                 if (g_strcasecmp (page_size, template->page_size) == 0) {
94                         for (p_name = template->name; p_name != NULL;
95                              p_name = p_name->next) {
96                                 str = g_strdup_printf("%s: %s",
97                                                       (gchar *) p_name->data,
98                                                       template->description);
99                                 names = g_list_insert_sorted (names, str,
100                                                              (GCompareFunc)g_strcasecmp);
101                         }
102                 }
103         }
104
105         return names;
106 }
107
108 /*****************************************************************************/
109 /* Free a list of template names.                                            */
110 /*****************************************************************************/
111 void
112 gl_template_free_name_list (GList ** names)
113 {
114         GList *p_name;
115
116         for (p_name = *names; p_name != NULL; p_name = p_name->next) {
117                 g_free (p_name->data);
118                 p_name->data = NULL;
119         }
120
121         g_list_free (*names);
122         *names = NULL;
123 }
124
125 /*****************************************************************************/
126 /* Return a template structure from a name.                                  */
127 /*****************************************************************************/
128 glTemplate *
129 gl_template_from_name (const gchar * name)
130 {
131         GList *p_tmplt, *p_name;
132         glTemplate *template;
133         gchar **split_name;
134
135         if (name == NULL) {
136                 /* If no name, return first template as a default */
137                 return (glTemplate *) templates->data;
138         }
139
140         split_name = g_strsplit (name, ":", 2);
141
142         for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) {
143                 template = (glTemplate *) p_tmplt->data;
144                 for (p_name = template->name; p_name != NULL;
145                      p_name = p_name->next) {
146                         if (g_strcasecmp (p_name->data, split_name[0]) == 0) {
147                                 g_strfreev (split_name);
148                                 return gl_template_copy(template);
149                         }
150                 }
151         }
152
153         g_strfreev (split_name);
154
155         return NULL;
156 }
157
158 /*****************************************************************************/
159 /* Copy a template.                                                          */
160 /*****************************************************************************/
161 glTemplate *gl_template_copy (const glTemplate *orig_template)
162 {
163         glTemplate *template;
164         GList *p;
165
166         template = g_new0 (glTemplate,1);
167
168         /* Shallow copy first */
169         *template = *orig_template;
170
171         /* Now the deep stuff */
172         template->name = NULL;
173         for ( p=orig_template->name; p != NULL; p=p->next ) {
174                 template->name = g_list_append (template->name,
175                                                 g_strdup (p->data));
176         }
177         template->description = g_strdup (orig_template->description);
178         template->page_size = g_strdup (orig_template->page_size);
179
180         return template;
181 }
182
183 /*****************************************************************************/
184 /* Free up a template.                                                       */
185 /*****************************************************************************/
186 void gl_template_free (glTemplate **template)
187 {
188         GList *p;
189
190         for ( p=(*template)->name; p != NULL; p=p->next ) {
191                 g_free (p->data);
192                 p->data = NULL;
193         }
194         g_list_free ((*template)->name);
195         (*template)->name = NULL;
196
197         g_free ((*template)->description);
198         (*template)->description = NULL;
199
200         g_free ((*template)->page_size);
201         (*template)->page_size = NULL;
202
203         g_free (*template);
204         *template = NULL;
205 }
206
207 /*--------------------------------------------------------------------------*/
208 /* PRIVATE.  Read templates from various  files.                            */
209 /*--------------------------------------------------------------------------*/
210 static GList *
211 read_templates (void)
212 {
213         gchar *home_data_dir = get_home_data_dir ();
214         GList *templates = NULL;
215
216         LIBXML_TEST_VERSION;
217
218         templates = read_template_files_from_dir (templates, GL_DATA_DIR);
219         templates = read_template_files_from_dir (templates, home_data_dir);
220
221         g_free (home_data_dir);
222
223         if (templates == NULL) {
224                 WARN (_("No template files found!"));
225         }
226
227         return templates;
228 }
229
230 /*--------------------------------------------------------------------------*/
231 /* PRIVATE.  get '~/.glabels' directory path.                               */
232 /*--------------------------------------------------------------------------*/
233 static gchar *
234 get_home_data_dir (void)
235 {
236         gchar *dir = gnome_util_prepend_user_home (".glabels");
237
238         /* Try to create ~/.glabels directory.  If it exists, no problem. */
239         mkdir (dir, 0775);
240
241         return dir;
242 }
243
244 /*--------------------------------------------------------------------------*/
245 /* PRIVATE.  Read all template files from given directory.  Append to list. */
246 /*--------------------------------------------------------------------------*/
247 static GList *
248 read_template_files_from_dir (GList * templates,
249                               const gchar * dirname)
250 {
251         DIR *dp;
252         struct dirent *d_entry;
253         gchar *filename, *extension;
254         gchar *full_filename = NULL;
255
256         if (dirname == NULL)
257                 return templates;
258
259         dp = opendir (dirname);
260         if (dp == NULL)
261                 return templates;
262
263         while ((d_entry = readdir (dp)) != NULL) {
264
265                 filename = d_entry->d_name;
266                 extension = strrchr (filename, '.');
267
268                 if (extension != NULL) {
269
270                         if (strcasecmp (extension, ".template") == 0) {
271
272                                 full_filename =
273                                     g_concat_dir_and_file (dirname, filename);
274                                 templates =
275                                     read_templates_from_file (templates,
276                                                               full_filename);
277                                 g_free (full_filename);
278
279                         }
280
281                 }
282
283         }
284
285         closedir (dp);
286
287         return templates;
288 }
289
290 /*--------------------------------------------------------------------------*/
291 /* PRIVATE.  Read templates from template file.                             */
292 /*--------------------------------------------------------------------------*/
293 static GList *
294 read_templates_from_file (GList * templates,
295                           gchar * xml_filename)
296 {
297         xmlDocPtr doc;
298         xmlNodePtr root, node;
299         glTemplate *template;
300
301         doc = xmlParseFile (xml_filename);
302         if (!doc) {
303                 WARN ("\"%s\" is not a glabels template file (not XML)",
304                       xml_filename);
305                 return templates;
306         }
307
308         root = xmlDocGetRootElement (doc);
309         if (!root || !root->name) {
310                 WARN ("\"%s\" is not a glabels template file (no root node)",
311                       xml_filename);
312                 xmlFreeDoc (doc);
313                 return templates;
314         }
315         if (g_strcasecmp (root->name, "glabels-templates") != 0) {
316                 WARN ("\"%s\" is not a glabels template file (wrong root node)",
317                       xml_filename);
318                 xmlFreeDoc (doc);
319                 return templates;
320         }
321
322         for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
323
324                 if (g_strcasecmp (node->name, "Sheet") == 0) {
325                         template = g_new0 (glTemplate, 1);
326                         gl_template_xml_parse_sheet (template, node);
327                         templates = g_list_append (templates, template);
328                 } else {
329                         if (g_strcasecmp (node->name, "text") != 0) {
330                                 WARN ("bad node =  \"%s\"", node->name);
331                         }
332                 }
333         }
334
335         xmlFreeDoc (doc);
336
337         return templates;
338 }
339
340 /*****************************************************************************/
341 /* Parse XML template Node.                                                  */
342 /*****************************************************************************/
343 void
344 gl_template_xml_parse_sheet (glTemplate * template,
345                              xmlNodePtr sheet_node)
346 {
347         xmlNodePtr node;
348
349         template->name = g_list_append (template->name,
350                                         xmlGetProp (sheet_node, "name"));
351         template->page_size = xmlGetProp (sheet_node, "size");
352         template->description = xmlGetProp (sheet_node, "description");
353
354         for (node = sheet_node->xmlChildrenNode; node != NULL;
355              node = node->next) {
356                 if (g_strcasecmp (node->name, "Label") == 0) {
357                         xml_parse_label (node, template);
358                 } else if (g_strcasecmp (node->name, "Alias") == 0) {
359                         xml_parse_alias (node, template);
360                 } else {
361                         if (g_strcasecmp (node->name, "text") != 0) {
362                                 WARN ("bad node =  \"%s\"", node->name);
363                         }
364                 }
365         }
366
367 }
368
369 /*--------------------------------------------------------------------------*/
370 /* PRIVATE.  Parse XML Sheet->Label Node.                                   */
371 /*--------------------------------------------------------------------------*/
372 static void
373 xml_parse_label (xmlNodePtr label_node,
374                  glTemplate * template)
375 {
376         xmlNodePtr node;
377         gchar *style;
378
379         style = xmlGetProp (label_node, "style");
380         if (g_strcasecmp (style, "rectangle") == 0) {
381                 template->style = GL_TEMPLATE_STYLE_RECT;
382         } else if (g_strcasecmp (style, "round") == 0) {
383                 template->style = GL_TEMPLATE_STYLE_ROUND;
384         } else if (g_strcasecmp (style, "cd") == 0) {
385                 template->style = GL_TEMPLATE_STYLE_CD;
386         } else {
387                 WARN ("Unknown label style in template");
388         }
389
390         if (template->style == GL_TEMPLATE_STYLE_RECT) {
391                 template->label_width =
392                     g_strtod (xmlGetProp (label_node, "width"), NULL);
393                 template->label_height =
394                     g_strtod (xmlGetProp (label_node, "height"), NULL);
395                 template->label_round =
396                     g_strtod (xmlGetProp (label_node, "round"), NULL);
397         } else if (template->style == GL_TEMPLATE_STYLE_ROUND) {
398                 template->label_radius =
399                     g_strtod (xmlGetProp (label_node, "radius"), NULL);
400                 template->label_width = 2.0 * template->label_radius;
401                 template->label_height = 2.0 * template->label_radius;
402         } else if (template->style == GL_TEMPLATE_STYLE_CD) {
403                 template->label_radius =
404                     g_strtod (xmlGetProp (label_node, "radius"), NULL);
405                 template->label_hole =
406                     g_strtod (xmlGetProp (label_node, "hole"), NULL);
407                 template->label_width = 2.0 * template->label_radius;
408                 template->label_height = 2.0 * template->label_radius;
409         }
410
411         template->label_margin =
412             g_strtod (xmlGetProp (label_node, "margin"), NULL);
413
414         for (node = label_node->xmlChildrenNode; node != NULL;
415              node = node->next) {
416                 if (g_strcasecmp (node->name, "Layout") == 0) {
417                         xml_parse_layout (node, template);
418                 } else {
419                         if (g_strcasecmp (node->name, "text") != 0) {
420                                 WARN ("bad node =  \"%s\"", node->name);
421                         }
422                 }
423         }
424
425 }
426
427 /*--------------------------------------------------------------------------*/
428 /* PRIVATE.  Parse XML Sheet->Label->Layout Node.                           */
429 /*--------------------------------------------------------------------------*/
430 static void
431 xml_parse_layout (xmlNodePtr layout_node,
432                   glTemplate * template)
433 {
434         xmlNodePtr node;
435
436         sscanf (xmlGetProp (layout_node, "nx"), "%d", &(template->nx));
437         sscanf (xmlGetProp (layout_node, "ny"), "%d", &(template->ny));
438         template->x0 = g_strtod (xmlGetProp (layout_node, "x0"), NULL);
439         template->y0 = g_strtod (xmlGetProp (layout_node, "y0"), NULL);
440         template->dx = g_strtod (xmlGetProp (layout_node, "dx"), NULL);
441         template->dy = g_strtod (xmlGetProp (layout_node, "dy"), NULL);
442
443         for (node = layout_node->xmlChildrenNode; node != NULL;
444              node = node->next) {
445                 if (g_strcasecmp (node->name, "text") != 0) {
446                         WARN ("bad node =  \"%s\"", node->name);
447                 }
448         }
449
450 }
451
452 /*--------------------------------------------------------------------------*/
453 /* PRIVATE.  Parse XML Sheet->Alias Node.                                   */
454 /*--------------------------------------------------------------------------*/
455 static void
456 xml_parse_alias (xmlNodePtr alias_node,
457                  glTemplate * template)
458 {
459         template->name = g_list_append (template->name,
460                                         xmlGetProp (alias_node, "name"));
461 }
462
463 /****************************************************************************/
464 /* Add XML Template Node                                                    */
465 /****************************************************************************/
466 void
467 gl_template_xml_add_sheet (glTemplate * template,
468                            xmlNodePtr root,
469                            xmlNsPtr ns)
470 {
471         xmlNodePtr node;
472         GList *p;
473
474         node = xmlNewChild (root, ns, "Sheet", NULL);
475
476         xmlSetProp (node, "name", template->name->data);
477         xmlSetProp (node, "size", template->page_size);
478         xmlSetProp (node, "description", template->description);
479
480         xml_add_label (template, node, ns);
481
482         for ( p=template->name->next; p != NULL; p=p->next ) {
483                 xml_add_alias( p->data, node, ns );
484         }
485 }
486
487 /*--------------------------------------------------------------------------*/
488 /* PRIVATE.  Add XML Sheet->Label Node.                                     */
489 /*--------------------------------------------------------------------------*/
490 static void
491 xml_add_label (glTemplate *template,
492                xmlNodePtr root,
493                xmlNsPtr ns)
494 {
495         xmlNodePtr node;
496         gchar *string;
497
498         node = xmlNewChild(root, ns, "Label", NULL);
499         string = g_strdup_printf ("%g", template->label_margin);
500         xmlSetProp (node, "margin", string);
501         g_free (string);
502         switch (template->style) {
503         case GL_TEMPLATE_STYLE_RECT:
504                 xmlSetProp (node, "style", "rectangle");
505                 string = g_strdup_printf ("%g", template->label_width);
506                 xmlSetProp (node, "width", string);
507                 g_free (string);
508                 string = g_strdup_printf ("%g", template->label_height);
509                 xmlSetProp (node, "height", string);
510                 g_free (string);
511                 string = g_strdup_printf ("%g", template->label_round);
512                 xmlSetProp (node, "round", string);
513                 g_free (string);
514                 break;
515         case GL_TEMPLATE_STYLE_ROUND:
516                 xmlSetProp (node, "style", "round");
517                 string = g_strdup_printf ("%g", template->label_radius);
518                 xmlSetProp (node, "radius", string);
519                 g_free (string);
520                 break;
521         case GL_TEMPLATE_STYLE_CD:
522                 xmlSetProp (node, "style", "cd");
523                 string = g_strdup_printf ("%g", template->label_radius);
524                 xmlSetProp (node, "radius", string);
525                 g_free (string);
526                 string = g_strdup_printf ("%g", template->label_hole);
527                 xmlSetProp (node, "hole", string);
528                 g_free (string);
529                 break;
530         default:
531                 WARN ("Unknown label style");
532                 break;
533         }
534
535         xml_add_layout (template, node, ns);
536
537 }
538
539 /*--------------------------------------------------------------------------*/
540 /* PRIVATE.  Add XML Sheet->Label->Layout Node.                             */
541 /*--------------------------------------------------------------------------*/
542 static void
543 xml_add_layout (glTemplate *template,
544                 xmlNodePtr root,
545                 xmlNsPtr ns)
546 {
547         xmlNodePtr node;
548         gchar *string;
549
550         node = xmlNewChild(root, ns, "Layout", NULL);
551         string = g_strdup_printf ("%d", template->nx);
552         xmlSetProp (node, "nx", string);
553         g_free (string);
554         string = g_strdup_printf ("%d", template->ny);
555         xmlSetProp (node, "ny", string);
556         g_free (string);
557         string = g_strdup_printf ("%g", template->x0);
558         xmlSetProp (node, "x0", string);
559         g_free (string);
560         string = g_strdup_printf ("%g", template->y0);
561         xmlSetProp (node, "y0", string);
562         g_free (string);
563         string = g_strdup_printf ("%g", template->dx);
564         xmlSetProp (node, "dx", string);
565         g_free (string);
566         string = g_strdup_printf ("%g", template->dy);
567         xmlSetProp (node, "dy", string);
568         g_free (string);
569 }
570
571 /*--------------------------------------------------------------------------*/
572 /* PRIVATE.  Add XML Sheet->Alias Node.                                     */
573 /*--------------------------------------------------------------------------*/
574 static void
575 xml_add_alias (gchar *name,
576                xmlNodePtr root,
577                xmlNsPtr ns)
578 {
579         xmlNodePtr node;
580
581         node = xmlNewChild (root, ns, "Alias", NULL);
582         xmlSetProp (node, "name", name);
583 }
584