]> git.sur5r.net Git - glabels/blob - glabels1/src/label.c
c33f97cb1b7cfb6962987f419963ad5985f48727
[glabels] / glabels1 / src / label.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  label.c:  GLabels label 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 <gnome.h>
26
27 /* LibXML */
28 #include <tree.h>
29 #include <parser.h>
30
31 #include "label.h"
32 #include "template.h"
33
34 #include "debug.h"
35
36 #define NAME_SPACE "http://snaught.com/glabels/0.4/"
37 #define COMPAT01_NAME_SPACE "http://snaught.com/glabels/0.1/"
38
39 static glLabelStatus xml_doc_to_label (xmlDocPtr doc, glLabel ** label);
40 static gboolean xml_parse_media_description (xmlNodePtr node, glLabel * label);
41 static void xml_parse_object(xmlNodePtr node, glLabelObject * object,
42                              gboolean compat01_flag);
43 static void xml_parse_text_props (xmlNodePtr node, glLabelObject * object);
44 static void xml_parse_text_props_compat01( xmlNodePtr node,
45                                            glLabelObject *object );
46 static void xml_parse_box_props (xmlNodePtr node, glLabelObject * object);
47 static void xml_parse_line_props (xmlNodePtr node, glLabelObject * object);
48 static void xml_parse_ellipse_props (xmlNodePtr node, glLabelObject * object);
49 static void xml_parse_image_props (xmlNodePtr node, glLabelObject * object);
50 static void xml_parse_barcode_props (xmlNodePtr node, glLabelObject * object);
51 static void xml_parse_merge_properties (xmlNodePtr node, glLabel * label);
52
53 static glLabelStatus xml_label_to_doc (glLabel * label, xmlDocPtr * doc);
54 static void xml_create_media_description (xmlNodePtr root, xmlNsPtr ns,
55                                        glLabel * label);
56 static void xml_create_object (xmlNodePtr root, xmlNsPtr ns,
57                                glLabelObject * object);
58 static void xml_create_text_props (xmlNodePtr root, xmlNsPtr ns,
59                                  glLabelObject * object);
60 static void xml_create_box_props (xmlNodePtr root, xmlNsPtr ns,
61                                 glLabelObject * object);
62 static void xml_create_line_props (xmlNodePtr root, xmlNsPtr ns,
63                                  glLabelObject * object);
64 static void xml_create_ellipse_props (xmlNodePtr root, xmlNsPtr ns,
65                                     glLabelObject * object);
66 static void xml_create_image_props (xmlNodePtr root, xmlNsPtr ns,
67                                   glLabelObject * object);
68 static void xml_create_barcode_props (xmlNodePtr root, xmlNsPtr ns,
69                                     glLabelObject * object);
70 static void xml_create_merge_properties (xmlNodePtr root, xmlNsPtr ns,
71                                       glLabel * label);
72
73 static const gchar *just_to_text (GtkJustification just);
74 static GtkJustification text_to_just (const gchar * text);
75
76 static const gchar *weight_to_text (GnomeFontWeight weight);
77 static GnomeFontWeight text_to_weight (const gchar * text);
78 \f
79 /****************************************************************************/
80 /* Create a new label.                                                      */
81 /****************************************************************************/
82 glLabel *
83 gl_label_new (void)
84 {
85         glLabel *label;
86
87         label = g_new0 (glLabel, 1);
88
89         return label;
90 }
91
92 /****************************************************************************/
93 /* Create a new label.                                                      */
94 /****************************************************************************/
95 glLabel *
96 gl_label_new_with_template (const gchar * tmplt_name,
97                             gboolean rotate_flag)
98 {
99         glLabel *label;
100         glTemplate *template;
101
102         label = gl_label_new ();
103
104         label->template_name = g_strdup (tmplt_name);
105         label->template = template = gl_template_from_name (tmplt_name);
106         label->rotate_flag = rotate_flag;
107
108         switch (template->style) {
109
110         case GL_TEMPLATE_STYLE_RECT:
111                 if (!rotate_flag) {
112                         label->width = template->label_width;
113                         label->height = template->label_height;
114                 } else {
115                         label->width = template->label_height;
116                         label->height = template->label_width;
117                 }
118                 break;
119
120         case GL_TEMPLATE_STYLE_ROUND:
121         case GL_TEMPLATE_STYLE_CD:
122                 label->width = label->height = 2.0 * template->label_radius;
123                 break;
124
125         default:
126                 WARN ("Unknown template label style");
127                 break;
128         }
129
130         label->objects = NULL;
131
132         return label;
133 }
134
135 /****************************************************************************/
136 /* Free a previously allocated label.                                       */
137 /****************************************************************************/
138 void
139 gl_label_free (glLabel ** label)
140 {
141         GList *p, *p_next;
142         glLabelObject *object;
143
144         if (*label != NULL) {
145                 g_free ((*label)->template_name);
146                 (*label)->template_name = NULL;
147
148                 gl_template_free (&(*label)->template);
149
150                 for (p = (*label)->objects; p != NULL; p = p_next) {
151                         p_next = p->next;       /* NOTE: p will be left dangling */
152                         object = (glLabelObject *) p->data;
153                         gl_label_object_free (&object);
154                 }
155
156                 g_free (*label);
157                 *label = NULL;
158         }
159 }
160
161 /****************************************************************************/
162 /* Open and read label from xml file.                                       */
163 /****************************************************************************/
164 glLabelStatus
165 gl_label_open_xml (glLabel ** label,
166                    const gchar * filename)
167 {
168         xmlDocPtr doc;
169         glLabelStatus status;
170
171         xmlUseNewParser (TRUE);
172         doc = xmlParseFile (filename);
173         if (!doc) {
174                 WARN (_("xmlParseFile error"));
175                 *label = NULL;
176                 return LABEL_ERROR_OPEN_XML_PARSE;
177         }
178
179         status = xml_doc_to_label (doc, label);
180
181         xmlFreeDoc (doc);
182
183         return status;
184 }
185
186 /****************************************************************************/
187 /* Read label from xml buffer.                                              */
188 /****************************************************************************/
189 glLabelStatus
190 gl_label_open_xml_buffer (glLabel ** label,
191                           const gchar * buffer)
192 {
193         xmlDocPtr doc;
194         glLabelStatus status;
195
196         xmlUseNewParser (TRUE);
197         doc = xmlParseDoc ((xmlChar *) buffer);
198         if (!doc) {
199                 WARN (_("xmlParseFile error"));
200                 *label = NULL;
201                 return LABEL_ERROR_OPEN_XML_PARSE;
202         }
203
204         status = xml_doc_to_label (doc, label);
205
206         xmlFreeDoc (doc);
207
208         return status;
209 }
210
211 /*--------------------------------------------------------------------------*/
212 /* PRIVATE.  Parse xml doc structure and create label.                      */
213 /*--------------------------------------------------------------------------*/
214 static glLabelStatus
215 xml_doc_to_label (xmlDocPtr doc,
216                   glLabel ** label)
217 {
218         xmlNodePtr root, node;
219         xmlNsPtr ns;
220         glLabelObject *object;
221         glLabelStatus status = LABEL_OK;
222         gboolean compat01_flag = FALSE;
223
224         LIBXML_TEST_VERSION;
225
226         gl_label_free (label);
227
228         root = xmlDocGetRootElement (doc);
229         if (!root || !root->name) {
230                 WARN (_("No document root"));
231                 return LABEL_ERROR_OPEN_XML_PARSE;
232         }
233         ns = xmlSearchNsByHref (doc, root, NAME_SPACE);
234         if (ns == NULL) {
235                 /* Try compatability mode */
236                 ns = xmlSearchNsByHref (doc, root, COMPAT01_NAME_SPACE);
237                 if (ns != NULL) compat01_flag = TRUE;
238         }
239         if (ns == NULL) {
240                 WARN (_
241                       ("document of the wrong type, glabels Namespace not found"));
242                 return LABEL_ERROR_OPEN_XML_PARSE;
243         }
244
245         if (g_strcasecmp (root->name, "Label") != 0) {
246                 WARN (_("Bad root node = \"%s\""), root->name);
247                 return LABEL_ERROR_OPEN_XML_PARSE;
248         }
249
250         *label = gl_label_new ();
251
252         (*label)->rotate_flag =
253             !(g_strcasecmp (xmlGetProp (root, "rotate"), "false") == 0);
254         (*label)->width = g_strtod (xmlGetProp (root, "width"), NULL);
255         (*label)->height = g_strtod (xmlGetProp (root, "height"), NULL);
256
257         for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
258
259                 if (g_strcasecmp (node->name, "Media_Type") == 0) {
260                         if (!xml_parse_media_description (node, *label)) {
261                                 status = LABEL_UNKNOWN_MEDIA;
262                         }
263                 } else if (g_strcasecmp (node->name, "Text") == 0) {
264                         object =
265                             gl_label_object_new (*label, GL_LABEL_OBJECT_TEXT);
266                         xml_parse_object (node, object, compat01_flag);
267                 } else if (g_strcasecmp (node->name, "Box") == 0) {
268                         object =
269                             gl_label_object_new (*label, GL_LABEL_OBJECT_BOX);
270                         xml_parse_object (node, object, compat01_flag);
271                 } else if (g_strcasecmp (node->name, "Line") == 0) {
272                         object =
273                             gl_label_object_new (*label, GL_LABEL_OBJECT_LINE);
274                         xml_parse_object (node, object, compat01_flag);
275                 } else if (g_strcasecmp (node->name, "Ellipse") == 0) {
276                         object =
277                             gl_label_object_new (*label,
278                                                  GL_LABEL_OBJECT_ELLIPSE);
279                         xml_parse_object (node, object, compat01_flag);
280                 } else if (g_strcasecmp (node->name, "Image") == 0) {
281                         object =
282                             gl_label_object_new (*label, GL_LABEL_OBJECT_IMAGE);
283                         xml_parse_object (node, object, compat01_flag);
284                 } else if (g_strcasecmp (node->name, "Barcode") == 0) {
285                         object =
286                             gl_label_object_new (*label,
287                                                  GL_LABEL_OBJECT_BARCODE);
288                         xml_parse_object (node, object, compat01_flag);
289                 } else if (g_strcasecmp (node->name, "Merge_Properties") == 0) {
290                         xml_parse_merge_properties (node, *label);
291                 } else {
292                         if (!xmlNodeIsText (node)) {
293                                 WARN (_("bad node =  \"%s\""), node->name);
294                         }
295                 }
296         }
297
298         return status;
299 }
300
301 /*--------------------------------------------------------------------------*/
302 /* PRIVATE.  Parse Media Description node.                                  */
303 /*--------------------------------------------------------------------------*/
304 static gboolean
305 xml_parse_media_description (xmlNodePtr node,
306                              glLabel * label)
307 {
308         label->template_name = xmlNodeGetContent (node);
309         label->template = gl_template_from_name (label->template_name);
310         if (label->template == NULL) {
311                 WARN ("Undefined template \"%s\"", label->template_name);
312                 /* Get a default */
313                 label->template = gl_template_from_name (NULL);
314                 return FALSE;
315         }
316         return TRUE;
317 }
318
319 /*--------------------------------------------------------------------------*/
320 /* PRIVATE.  Parse XML Object Node                                          */
321 /*--------------------------------------------------------------------------*/
322 static void
323 xml_parse_object (xmlNodePtr object_node,
324                   glLabelObject * object,
325                   gboolean compat01_flag)
326 {
327         object->x = g_strtod (xmlGetProp (object_node, "x"), NULL);
328         object->y = g_strtod (xmlGetProp (object_node, "y"), NULL);
329
330         switch (object->type) {
331         case GL_LABEL_OBJECT_TEXT:
332                 if (compat01_flag) {
333                         xml_parse_text_props_compat01 (object_node, object);
334                 } else {
335                         xml_parse_text_props (object_node, object);
336                 }
337                 break;
338         case GL_LABEL_OBJECT_BOX:
339                 xml_parse_box_props (object_node, object);
340                 break;
341         case GL_LABEL_OBJECT_LINE:
342                 xml_parse_line_props (object_node, object);
343                 break;
344         case GL_LABEL_OBJECT_ELLIPSE:
345                 xml_parse_ellipse_props (object_node, object);
346                 break;
347         case GL_LABEL_OBJECT_IMAGE:
348                 xml_parse_image_props (object_node, object);
349                 break;
350         case GL_LABEL_OBJECT_BARCODE:
351                 xml_parse_barcode_props (object_node, object);
352                 break;
353         default:
354         }
355
356 }
357
358 /*--------------------------------------------------------------------------*/
359 /* PRIVATE.  Parse XML Label->Text Node Properties                          */
360 /*--------------------------------------------------------------------------*/
361 static void
362 xml_parse_text_props (xmlNodePtr object_node,
363                        glLabelObject * object)
364 {
365         xmlNodePtr line_node, text_node;
366         glTextNode *node_text;
367         GList *nodes;
368
369         object->arg.text.font_family = xmlGetProp (object_node, "font_family");
370         object->arg.text.font_size =
371             g_strtod (xmlGetProp (object_node, "font_size"), NULL);
372         object->arg.text.font_weight =
373             text_to_weight (xmlGetProp (object_node, "font_weight"));
374         object->arg.text.font_italic_flag =
375             !(g_strcasecmp (xmlGetProp (object_node, "font_italic"), "false") ==
376               0);
377
378         object->arg.text.just =
379             text_to_just (xmlGetProp (object_node, "justify"));
380
381         sscanf (xmlGetProp (object_node, "color"), "%x",
382                 &object->arg.text.color);
383
384         object->arg.text.lines = NULL;
385         for (line_node = object_node->xmlChildrenNode; line_node != NULL;
386              line_node = line_node->next) {
387
388                 if (g_strcasecmp (line_node->name, "Line") == 0) {
389
390                         nodes = NULL;
391                         for (text_node = line_node->xmlChildrenNode;
392                              text_node != NULL; text_node = text_node->next) {
393
394                                 if (g_strcasecmp (text_node->name, "Field") ==
395                                     0) {
396                                         node_text = g_new0 (glTextNode, 1);
397                                         node_text->field_flag = TRUE;
398                                         node_text->data =
399                                             xmlGetProp (text_node, "name");
400                                         nodes =
401                                             g_list_append (nodes, node_text);
402                                 } else if (xmlNodeIsText (text_node)) {
403                                         node_text = g_new0 (glTextNode, 1);
404                                         node_text->field_flag = FALSE;
405                                         node_text->data =
406                                             xmlNodeGetContent (text_node);
407                                         nodes =
408                                             g_list_append (nodes, node_text);
409                                 } else {
410                                         WARN ("Unexpected Text Line child: \"%s\"",
411                                               text_node->name);
412                                 }
413
414                         }
415                         object->arg.text.lines =
416                             g_list_append (object->arg.text.lines, nodes);
417
418                 } else {
419                         WARN ("Unexpected Text child: \"%s\"", line_node->name);
420                 }
421
422         }
423
424 }
425
426 /*--------------------------------------------------------------------------*/
427 /* PRIVATE.  Parse XML label->Text node (Compatability with 0.1 version)    */
428 /*--------------------------------------------------------------------------*/
429 static void
430 xml_parse_text_props_compat01( xmlNodePtr node, glLabelObject *object )
431 {
432         gchar *text;
433
434         text = xmlNodeGetContent( node );
435         object->arg.text.lines = gl_text_node_lines_new_from_text( text );
436         g_free( text );
437
438         object->arg.text.font_family = xmlGetProp( node, "font_family" );
439         object->arg.text.font_size = g_strtod( xmlGetProp( node, "font_size" ),
440                                                NULL );
441         object->arg.text.font_weight =
442                 text_to_weight( xmlGetProp( node, "font_weight" ) );
443         object->arg.text.font_italic_flag =
444                 !( g_strcasecmp( xmlGetProp( node, "font_italic" ),
445                                  "false" ) == 0 );
446
447         object->arg.text.just = text_to_just( xmlGetProp( node, "justify" ) );
448
449         sscanf( xmlGetProp( node, "color" ), "%x", &object->arg.text.color );
450 }
451
452 /*--------------------------------------------------------------------------*/
453 /* PRIVATE.  Parse XML Label->Box Node Properties                           */
454 /*--------------------------------------------------------------------------*/
455 static void
456 xml_parse_box_props (xmlNodePtr node,
457                       glLabelObject * object)
458 {
459         object->arg.box.w = g_strtod (xmlGetProp (node, "w"), NULL);
460         object->arg.box.h = g_strtod (xmlGetProp (node, "h"), NULL);
461
462         object->arg.box.line_width = g_strtod (xmlGetProp (node, "line_width"),
463                                                NULL);
464
465         sscanf (xmlGetProp (node, "line_color"), "%x",
466                 &object->arg.box.line_color);
467         sscanf (xmlGetProp (node, "fill_color"), "%x",
468                 &object->arg.box.fill_color);
469 }
470
471 /*--------------------------------------------------------------------------*/
472 /* PRIVATE.  Parse XML Label->Line Node Properties                          */
473 /*--------------------------------------------------------------------------*/
474 static void
475 xml_parse_line_props (xmlNodePtr node,
476                        glLabelObject * object)
477 {
478         object->arg.line.dx = g_strtod (xmlGetProp (node, "dx"), NULL);
479         object->arg.line.dy = g_strtod (xmlGetProp (node, "dy"), NULL);
480
481         object->arg.line.line_width = g_strtod (xmlGetProp (node, "line_width"),
482                                                 NULL);
483
484         sscanf (xmlGetProp (node, "line_color"), "%x",
485                 &object->arg.line.line_color);
486
487 }
488
489 /*--------------------------------------------------------------------------*/
490 /* PRIVATE.  Parse XML Label->Ellipse Node Properties                       */
491 /*--------------------------------------------------------------------------*/
492 static void
493 xml_parse_ellipse_props (xmlNodePtr node,
494                           glLabelObject * object)
495 {
496         object->arg.ellipse.w = g_strtod (xmlGetProp (node, "w"), NULL);
497         object->arg.ellipse.h = g_strtod (xmlGetProp (node, "h"), NULL);
498
499         object->arg.ellipse.line_width =
500             g_strtod (xmlGetProp (node, "line_width"), NULL);
501
502         sscanf (xmlGetProp (node, "line_color"), "%x",
503                 &object->arg.ellipse.line_color);
504         sscanf (xmlGetProp (node, "fill_color"), "%x",
505                 &object->arg.ellipse.fill_color);
506 }
507
508 /*--------------------------------------------------------------------------*/
509 /* PRIVATE.  Parse XML Label->Image Node Properties                         */
510 /*--------------------------------------------------------------------------*/
511 static void
512 xml_parse_image_props (xmlNodePtr node,
513                         glLabelObject * object)
514 {
515         object->arg.image.w = g_strtod (xmlGetProp (node, "w"), NULL);
516         object->arg.image.h = g_strtod (xmlGetProp (node, "h"), NULL);
517
518         object->arg.image.filename = xmlGetProp (node, "filename");
519
520         object->arg.image.image =
521             gdk_pixbuf_new_from_file (object->arg.image.filename);
522 }
523
524 /*--------------------------------------------------------------------------*/
525 /* PRIVATE.  Parse XML Label->Barcode Node Properties                       */
526 /*--------------------------------------------------------------------------*/
527 static void
528 xml_parse_barcode_props (xmlNodePtr node,
529                           glLabelObject * object)
530 {
531         xmlNodePtr child;
532
533         sscanf (xmlGetProp (node, "color"), "%x", &object->arg.barcode.color);
534
535         object->arg.barcode.style =
536             gl_barcode_text_to_style (xmlGetProp (node, "style"));
537
538         object->arg.barcode.text_flag =
539             !(g_strcasecmp (xmlGetProp (node, "text"), "false") == 0);
540
541         object->arg.barcode.scale =
542                 g_strtod (xmlGetProp (node, "scale"), NULL);
543         if (object->arg.barcode.scale == 0.0) {
544                 object->arg.barcode.scale = 0.5; /* Set to a valid value */
545         }
546
547         child = node->xmlChildrenNode;
548         object->arg.barcode.text_node = g_new0 (glTextNode, 1);
549         if (g_strcasecmp (child->name, "Field") == 0) {
550                 object->arg.barcode.text_node->field_flag = TRUE;
551                 object->arg.barcode.text_node->data =
552                         xmlGetProp (child, "name");
553         } else if (xmlNodeIsText (child)) {
554                 object->arg.barcode.text_node->field_flag = FALSE;
555                 object->arg.barcode.text_node->data =
556                         xmlNodeGetContent (child);
557         } else {
558                 WARN ("Unexpected Barcode child: \"%s\"", child->name);
559         }
560 }
561
562 /*--------------------------------------------------------------------------*/
563 /* PRIVATE.  Parse XML merge properties tag.                                */
564 /*--------------------------------------------------------------------------*/
565 static void
566 xml_parse_merge_properties (xmlNodePtr node,
567                             glLabel * label)
568 {
569         xmlNodePtr child;
570         glMergeFieldDefinition *field_def;
571
572         label->merge_type = gl_merge_text_to_type (xmlGetProp (node, "type"));
573         label->merge_src = xmlGetProp (node, "src");
574
575         for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
576
577                 if (g_strcasecmp (child->name, "Field") == 0) {
578                         field_def = g_new0 (glMergeFieldDefinition, 1);
579                         field_def->key = xmlGetProp (child, "key");
580                         field_def->loc = xmlGetProp (child, "loc");
581                         label->merge_fields =
582                             g_list_append (label->merge_fields, field_def);
583                 } else {
584                         WARN ("Unexpected Merge_Properties child: \"%s\"",
585                               child->name);
586                 }
587
588         }
589
590 }
591
592 /****************************************************************************/
593 /* Save label to xml label file.                                            */
594 /****************************************************************************/
595 glLabelStatus
596 gl_label_save_xml (glLabel * label,
597                    const gchar * filename)
598 {
599         xmlDocPtr doc;
600         glLabelStatus status;
601         gint xml_ret;
602
603         status = xml_label_to_doc (label, &doc);
604
605         xml_ret = xmlSaveFile (filename, doc);
606         xmlFreeDoc (doc);
607         if (xml_ret == -1) {
608                 WARN (_("Problem saving xml file."));
609                 return LABEL_ERROR_SAVE_XML_FILE;
610         }
611
612         return status;
613 }
614
615 /****************************************************************************/
616 /* Save label to xml buffer.                                                */
617 /****************************************************************************/
618 glLabelStatus
619 gl_label_save_xml_buffer (glLabel * label,
620                           gchar ** buffer)
621 {
622         xmlDocPtr doc;
623         glLabelStatus status;
624         gint size;
625
626         status = xml_label_to_doc (label, &doc);
627
628         xmlDocDumpMemory (doc, (xmlChar **) buffer, &size);
629         xmlFreeDoc (doc);
630
631         return status;
632 }
633
634 /*--------------------------------------------------------------------------*/
635 /* PRIVATE.  Convert label to xml doc structure.                            */
636 /*--------------------------------------------------------------------------*/
637 static glLabelStatus
638 xml_label_to_doc (glLabel * label,
639                   xmlDocPtr * doc)
640 {
641         xmlNsPtr ns;
642         gchar *string;
643         GList *p;
644         glLabelObject *object;
645
646         LIBXML_TEST_VERSION;
647
648         *doc = xmlNewDoc ("1.0");
649         (*doc)->xmlRootNode = xmlNewDocNode (*doc, NULL, "Label", NULL);
650
651         ns = xmlNewNs ((*doc)->xmlRootNode, NAME_SPACE, "glabels");
652         xmlSetNs ((*doc)->xmlRootNode, ns);
653
654         xmlSetProp ((*doc)->xmlRootNode, "rotate",
655                     label->rotate_flag ? "True" : "False");
656
657         string = g_strdup_printf ("%g", label->width);
658         xmlSetProp ((*doc)->xmlRootNode, "width", string);
659         g_free (string);
660
661         string = g_strdup_printf ("%g", label->height);
662         xmlSetProp ((*doc)->xmlRootNode, "height", string);
663         g_free (string);
664
665         xml_create_media_description ((*doc)->xmlRootNode, ns, label);
666
667         for (p = label->objects; p != NULL; p = p->next) {
668                 object = (glLabelObject *) p->data;
669                 xml_create_object ((*doc)->xmlRootNode, ns, object);
670         }
671
672         if (label->merge_type != GL_MERGE_NONE) {
673                 xml_create_merge_properties ((*doc)->xmlRootNode, ns, label);
674         }
675
676         return LABEL_OK;
677 }
678
679 /*--------------------------------------------------------------------------*/
680 /* PRIVATE.  Parse XML Label->Text Node                                     */
681 /*--------------------------------------------------------------------------*/
682 static void
683 xml_create_media_description (xmlNodePtr root,
684                            xmlNsPtr ns,
685                            glLabel * label)
686 {
687         xmlNodePtr node;
688
689         node = xmlNewTextChild (root, ns, "Media_Type", label->template_name);
690 }
691
692 /*--------------------------------------------------------------------------*/
693 /* PRIVATE.  Add XML label object Node                                      */
694 /*--------------------------------------------------------------------------*/
695 static void
696 xml_create_object (xmlNodePtr root,
697                    xmlNsPtr ns,
698                    glLabelObject * object)
699 {
700         xmlNodePtr object_node;
701         gchar *string;
702
703         object_node = xmlNewChild (root, ns, "Object", NULL);
704
705         string = g_strdup_printf ("%g", object->x);
706         xmlSetProp (object_node, "x", string);
707         g_free (string);
708
709         string = g_strdup_printf ("%g", object->y);
710         xmlSetProp (object_node, "y", string);
711         g_free (string);
712
713         switch (object->type) {
714         case GL_LABEL_OBJECT_TEXT:
715                 xml_create_text_props (object_node, ns, object);
716                 break;
717         case GL_LABEL_OBJECT_BOX:
718                 xml_create_box_props (object_node, ns, object);
719                 break;
720         case GL_LABEL_OBJECT_LINE:
721                 xml_create_line_props (object_node, ns, object);
722                 break;
723         case GL_LABEL_OBJECT_ELLIPSE:
724                 xml_create_ellipse_props (object_node, ns, object);
725                 break;
726         case GL_LABEL_OBJECT_IMAGE:
727                 xml_create_image_props (object_node, ns, object);
728                 break;
729         case GL_LABEL_OBJECT_BARCODE:
730                 xml_create_barcode_props (object_node, ns, object);
731                 break;
732         default:
733                 WARN ("Unknown label object");
734         }
735 }
736
737 /*--------------------------------------------------------------------------*/
738 /* PRIVATE.  Add XML Label->Text Node Properties                            */
739 /*--------------------------------------------------------------------------*/
740 static void
741 xml_create_text_props (xmlNodePtr object_node,
742                        xmlNsPtr ns,
743                        glLabelObject * object)
744 {
745         xmlNodePtr line_node, field_node;
746         gchar *string;
747         GList *p_line, *p_node;
748         glTextNode *node_text;
749
750         xmlNodeSetName (object_node, "Text");
751
752         xmlSetProp (object_node, "font_family", object->arg.text.font_family);
753
754         string = g_strdup_printf ("%g", object->arg.text.font_size);
755         xmlSetProp (object_node, "font_size", string);
756         g_free (string);
757
758         xmlSetProp (object_node, "font_weight",
759                     weight_to_text (object->arg.text.font_weight));
760
761         if (object->arg.text.font_italic_flag) {
762                 xmlSetProp (object_node, "font_italic", "True");
763         } else {
764                 xmlSetProp (object_node, "font_italic", "False");
765         }
766
767         xmlSetProp (object_node, "justify",
768                     just_to_text (object->arg.text.just));
769
770         string = g_strdup_printf ("0x%08x", object->arg.text.color);
771         xmlSetProp (object_node, "color", string);
772         g_free (string);
773
774         for (p_line = object->arg.text.lines; p_line != NULL;
775              p_line = p_line->next) {
776                 line_node = xmlNewChild (object_node, ns, "Line", NULL);
777
778                 for (p_node = (GList *) p_line->data; p_node != NULL;
779                      p_node = p_node->next) {
780                         node_text = (glTextNode *) p_node->data;
781
782                         if (node_text->field_flag) {
783                                 field_node =
784                                     xmlNewChild (line_node, ns, "Field", NULL);
785                                 xmlSetProp (field_node, "name",
786                                             node_text->data);
787                         } else {
788                                 xmlNodeAddContent (line_node, node_text->data);
789                         }
790
791                 }
792
793         }
794
795 }
796
797 /*--------------------------------------------------------------------------*/
798 /* PRIVATE.  Add XML Label->Box Node Properties                             */
799 /*--------------------------------------------------------------------------*/
800 static void
801 xml_create_box_props (xmlNodePtr object_node,
802                       xmlNsPtr ns,
803                       glLabelObject * object)
804 {
805         gchar *string;
806
807         xmlNodeSetName (object_node, "Box");
808
809         string = g_strdup_printf ("%g", object->arg.box.w);
810         xmlSetProp (object_node, "w", string);
811         g_free (string);
812
813         string = g_strdup_printf ("%g", object->arg.box.h);
814         xmlSetProp (object_node, "h", string);
815         g_free (string);
816
817         string = g_strdup_printf ("%g", object->arg.box.line_width);
818         xmlSetProp (object_node, "line_width", string);
819         g_free (string);
820
821         string = g_strdup_printf ("0x%08x", object->arg.box.line_color);
822         xmlSetProp (object_node, "line_color", string);
823         g_free (string);
824
825         string = g_strdup_printf ("0x%08x", object->arg.box.fill_color);
826         xmlSetProp (object_node, "fill_color", string);
827         g_free (string);
828
829 }
830
831 /*--------------------------------------------------------------------------*/
832 /* PRIVATE.  Add XML Label->Line Node Properties                            */
833 /*--------------------------------------------------------------------------*/
834 static void
835 xml_create_line_props (xmlNodePtr object_node,
836                        xmlNsPtr ns,
837                        glLabelObject * object)
838 {
839         gchar *string;
840
841         xmlNodeSetName (object_node, "Line");
842
843         string = g_strdup_printf ("%g", object->arg.line.dx);
844         xmlSetProp (object_node, "dx", string);
845         g_free (string);
846
847         string = g_strdup_printf ("%g", object->arg.line.dy);
848         xmlSetProp (object_node, "dy", string);
849         g_free (string);
850
851         string = g_strdup_printf ("%g", object->arg.line.line_width);
852         xmlSetProp (object_node, "line_width", string);
853         g_free (string);
854
855         string = g_strdup_printf ("0x%08x", object->arg.line.line_color);
856         xmlSetProp (object_node, "line_color", string);
857         g_free (string);
858
859 }
860
861 /*--------------------------------------------------------------------------*/
862 /* PRIVATE.  Add XML Label->Ellipse Node Properties                         */
863 /*--------------------------------------------------------------------------*/
864 static void
865 xml_create_ellipse_props (xmlNodePtr object_node,
866                           xmlNsPtr ns,
867                           glLabelObject * object)
868 {
869         gchar *string;
870
871         xmlNodeSetName (object_node, "Ellipse");
872
873         string = g_strdup_printf ("%g", object->arg.ellipse.w);
874         xmlSetProp (object_node, "w", string);
875         g_free (string);
876
877         string = g_strdup_printf ("%g", object->arg.ellipse.h);
878         xmlSetProp (object_node, "h", string);
879         g_free (string);
880
881         string = g_strdup_printf ("%g", object->arg.ellipse.line_width);
882         xmlSetProp (object_node, "line_width", string);
883         g_free (string);
884
885         string = g_strdup_printf ("0x%08x", object->arg.ellipse.line_color);
886         xmlSetProp (object_node, "line_color", string);
887         g_free (string);
888
889         string = g_strdup_printf ("0x%08x", object->arg.ellipse.fill_color);
890         xmlSetProp (object_node, "fill_color", string);
891         g_free (string);
892
893 }
894
895 /*--------------------------------------------------------------------------*/
896 /* PRIVATE.  Add XML Label->Image Node Properties                           */
897 /*--------------------------------------------------------------------------*/
898 static void
899 xml_create_image_props (xmlNodePtr object_node,
900                         xmlNsPtr ns,
901                         glLabelObject * object)
902 {
903         gchar *string;
904
905         xmlNodeSetName (object_node, "Image");
906
907         string = g_strdup_printf ("%g", object->arg.image.w);
908         xmlSetProp (object_node, "w", string);
909         g_free (string);
910
911         string = g_strdup_printf ("%g", object->arg.image.h);
912         xmlSetProp (object_node, "h", string);
913         g_free (string);
914
915         xmlSetProp (object_node, "filename", object->arg.image.filename);
916
917 }
918
919 /*--------------------------------------------------------------------------*/
920 /* PRIVATE.  Add XML Label->Barcode Node Properties                         */
921 /*--------------------------------------------------------------------------*/
922 static void
923 xml_create_barcode_props (xmlNodePtr object_node,
924                           xmlNsPtr ns,
925                           glLabelObject * object)
926 {
927         xmlNodePtr child;
928         gchar *string;
929
930         xmlNodeSetName (object_node, "Barcode");
931
932         string = g_strdup_printf ("0x%08x", object->arg.barcode.color);
933         xmlSetProp (object_node, "color", string);
934         g_free (string);
935
936         xmlSetProp (object_node, "style",
937                     gl_barcode_style_to_text (object->arg.barcode.style));
938
939         if (object->arg.barcode.text_flag) {
940                 xmlSetProp (object_node, "text", "True");
941         } else {
942                 xmlSetProp (object_node, "text", "False");
943         }
944
945         string = g_strdup_printf ("%g", object->arg.barcode.scale);
946         xmlSetProp (object_node, "scale", string);
947         g_free (string);
948
949         if (object->arg.barcode.text_node->field_flag) {
950                 child = xmlNewChild (object_node, ns, "Field", NULL);
951                 xmlSetProp (child, "name",
952                             object->arg.barcode.text_node->data);
953         } else {
954                 xmlNodeSetContent (object_node,
955                                    object->arg.barcode.text_node->data);
956         }
957
958 }
959
960 /*--------------------------------------------------------------------------*/
961 /* PRIVATE.  Add XML Label Merge Properties Node                            */
962 /*--------------------------------------------------------------------------*/
963 static void
964 xml_create_merge_properties (xmlNodePtr root,
965                              xmlNsPtr ns,
966                              glLabel * label)
967 {
968         xmlNodePtr node, child;
969         gchar *string;
970         GList *p;
971         glMergeFieldDefinition *field_def;
972
973         node = xmlNewChild (root, ns, "Merge_Properties", NULL);
974
975         string = gl_merge_type_to_text (label->merge_type);
976         xmlSetProp (node, "type", string);
977         g_free (string);
978
979         xmlSetProp (node, "src", label->merge_src);
980
981         for (p = label->merge_fields; p != NULL; p = p->next) {
982                 field_def = (glMergeFieldDefinition *) p->data;
983
984                 child = xmlNewChild (node, ns, "Field", NULL);
985                 xmlSetProp (child, "key", field_def->key);
986                 xmlSetProp (child, "loc", field_def->loc);
987         }
988
989 }
990
991 /****************************************************************************/
992 /* Create a new label object of the given type.                             */
993 /****************************************************************************/
994 glLabelObject *
995 gl_label_object_new (glLabel * label,
996                      glLabelObjectType type)
997 {
998         glLabelObject *object;
999
1000         object = g_new0 (glLabelObject, 1);
1001         object->parent = label;
1002         object->type = type;
1003
1004         if (label != NULL) {
1005                 label->objects = g_list_append (label->objects, object);
1006         }
1007
1008         return object;
1009 }
1010
1011 /****************************************************************************/
1012 /* Create a new label object from an existing object                        */
1013 /****************************************************************************/
1014 glLabelObject *
1015 gl_label_object_new_from_object (glLabel * label,
1016                                  glLabelObject * src_object)
1017 {
1018         glLabelObject *object;
1019         GList *p_line, *nodes, *p_node;
1020         glTextNode *node, *src_node;
1021
1022         object = g_new0 (glLabelObject, 1);
1023         *object = *src_object;
1024
1025         /* deep copy */
1026         switch (object->type) {
1027
1028         case GL_LABEL_OBJECT_TEXT:
1029                 /* deep copy */
1030                 gl_text_node_lines_print (src_object->arg.text.lines);
1031                 object->arg.text.lines = NULL;
1032                 for (p_line = src_object->arg.text.lines; p_line != NULL;
1033                      p_line = p_line->next) {
1034                         nodes = NULL;
1035                         for (p_node = (GList *) p_line->data; p_node != NULL;
1036                              p_node = p_node->next) {
1037                                 src_node = (glTextNode *) p_node->data;
1038                                 node = g_new0 (glTextNode, 1);
1039                                 node->field_flag = src_node->field_flag;
1040                                 node->data = g_strdup (src_node->data);
1041                                 nodes = g_list_append (nodes, node);
1042                         }
1043                         object->arg.text.lines =
1044                             g_list_append (object->arg.text.lines, nodes);
1045                 }
1046                 object->arg.text.font_family =
1047                     g_strdup (src_object->arg.text.font_family);
1048                 break;
1049
1050         case GL_LABEL_OBJECT_IMAGE:
1051                 object->arg.image.filename
1052                     = g_strdup (src_object->arg.image.filename);
1053                 object->arg.image.image
1054                     = gdk_pixbuf_copy (src_object->arg.image.image);
1055                 break;
1056
1057         case GL_LABEL_OBJECT_BARCODE:
1058                 object->arg.barcode.text_node = g_new0 (glTextNode, 1);
1059                 object->arg.barcode.text_node->field_flag =
1060                     src_object->arg.barcode.text_node->field_flag;
1061                 object->arg.barcode.text_node->data =
1062                     g_strdup (src_object->arg.barcode.text_node->data);
1063                 break;
1064
1065         default:
1066                 break;
1067
1068         }
1069
1070         /* set parent */
1071         object->parent = label;
1072         if (label != NULL) {
1073                 label->objects = g_list_append (label->objects, object);
1074         }
1075
1076         return object;
1077 }
1078
1079 /****************************************************************************/
1080 /* Free a previously allocated label object.                                */
1081 /****************************************************************************/
1082 void
1083 gl_label_object_free (glLabelObject ** object)
1084 {
1085         glLabel *label;
1086
1087         switch ((*object)->type) {
1088
1089         case GL_LABEL_OBJECT_TEXT:
1090                 gl_text_node_lines_free (&((*object)->arg.text.lines));
1091                 g_free ((*object)->arg.text.font_family);
1092                 (*object)->arg.text.font_family = NULL;
1093                 break;
1094
1095         case GL_LABEL_OBJECT_IMAGE:
1096                 g_free ((*object)->arg.image.filename);
1097                 (*object)->arg.image.filename = NULL;
1098                 gdk_pixbuf_unref ((*object)->arg.image.image);
1099                 (*object)->arg.image.image = NULL;
1100                 break;
1101
1102         case GL_LABEL_OBJECT_BARCODE:
1103                 gl_text_node_free (&((*object)->arg.barcode.text_node));
1104                 break;
1105
1106         default:
1107                 break;
1108
1109         }
1110
1111         label = (*object)->parent;
1112         if (label != NULL) {
1113                 label->objects = g_list_remove (label->objects, *object);
1114         }
1115
1116         g_free (*object);
1117         *object = NULL;
1118 }
1119
1120 /****************************************************************************/
1121 /* Bring label object to front/top.                                         */
1122 /****************************************************************************/
1123 void
1124 gl_label_object_raise_to_front (glLabelObject * object)
1125 {
1126         glLabel *label;
1127
1128         label = object->parent;
1129
1130         /* Move to end of list, representing front most object */
1131         label->objects = g_list_remove (label->objects, object);
1132         label->objects = g_list_append (label->objects, object);
1133 }
1134
1135 /****************************************************************************/
1136 /* Send label object to rear/bottom.                                        */
1137 /****************************************************************************/
1138 void
1139 gl_label_object_lower_to_back (glLabelObject * object)
1140 {
1141         glLabel *label;
1142
1143         label = object->parent;
1144
1145         /* Move to front of list, representing rear most object */
1146         label->objects = g_list_remove (label->objects, object);
1147         label->objects = g_list_prepend (label->objects, object);
1148 }
1149
1150 /*--------------------------------------------------------------------------*/
1151 /* PRIVATE.  Utilities to deal with GTK_JUSTIFICATION types                 */
1152 /*--------------------------------------------------------------------------*/
1153 static const gchar *
1154 just_to_text (GtkJustification just)
1155 {
1156         switch (just) {
1157         case GTK_JUSTIFY_LEFT:
1158                 return "Left";
1159         case GTK_JUSTIFY_CENTER:
1160                 return "Center";
1161         case GTK_JUSTIFY_RIGHT:
1162                 return "Right";
1163         default:
1164                 return "?";
1165         }
1166 }
1167
1168 static GtkJustification
1169 text_to_just (const gchar * text)
1170 {
1171
1172         if (g_strcasecmp (text, "Left") == 0) {
1173                 return GTK_JUSTIFY_LEFT;
1174         } else if (g_strcasecmp (text, "Center") == 0) {
1175                 return GTK_JUSTIFY_CENTER;
1176         } else if (g_strcasecmp (text, "Right") == 0) {
1177                 return GTK_JUSTIFY_RIGHT;
1178         } else {
1179                 return GTK_JUSTIFY_LEFT;
1180         }
1181
1182 }
1183
1184 /*--------------------------------------------------------------------------*/
1185 /* PRIVATE.  Utilities to deal with GNOME_FONT_WEIGHT types                 */
1186 /*--------------------------------------------------------------------------*/
1187 static const gchar *
1188 weight_to_text (GnomeFontWeight weight)
1189 {
1190         switch (weight) {
1191         case GNOME_FONT_BOOK:
1192                 return "Regular";
1193         case GNOME_FONT_BOLD:
1194                 return "Bold";
1195         default:
1196                 return "?";
1197         }
1198 }
1199
1200 static GnomeFontWeight
1201 text_to_weight (const gchar * text)
1202 {
1203
1204         if (g_strcasecmp (text, "Regular") == 0) {
1205                 return GNOME_FONT_BOOK;
1206         } else if (g_strcasecmp (text, "Bold") == 0) {
1207                 return GNOME_FONT_BOLD;
1208         } else {
1209                 return GNOME_FONT_BOOK;
1210         }
1211
1212 }