xml-io.c 55 KB
Newer Older
1 2 3
/*
 * xml-io.c: save/read gnumeric Sheets using an XML encoding.
 *
4 5 6
 * Authors:
 *   Daniel Veillard <Daniel.Veillard@w3.org>
 *   Miguel de Icaza <miguel@gnu.org>
7
 *
8
 * $Id$
9 10 11 12 13
 */

#include <config.h>
#include <stdio.h>
#include <gnome.h>
14
#include <locale.h>
15
#include <math.h>
16
#include "gnumeric.h"
17 18
#include "gnome-xml/tree.h"
#include "gnome-xml/parser.h"
19
#include "gnome-xml/xmlmemory.h"
20
#include "color.h"
21
#include "border.h"
22
#include "sheet-object.h"
23
#include "sheet-object-graphic.h"
24
#include "print-info.h"
25
#include "xml-io.h"
26
#include "file.h"
27 28 29 30

/*
 * A parsing context.
 */
31 32 33 34 35 36
typedef struct {
	xmlDocPtr doc;		/* Xml document */
	xmlNsPtr ns;		/* Main name space */
	xmlNodePtr parent;	/* used only for g_hash_table_foreach callbacks */
	Sheet *sheet;		/* the associated sheet */
	Workbook *wb;		/* the associated sheet */
37
	GHashTable *style_table;/* old style styles compatibility */
38 39
} parse_xml_context_t;

40 41 42
/*
 * Internal stuff: xml helper functions.
 */
43 44 45 46

/*
 * Get a value for a node either carried as an attibute or as
 * the content of a child.
47 48
 *
 * Returns a g_malloc'ed string.  Caller must free.
49
 */
50
static char *
51
xml_value_get (xmlNodePtr node, const char *name)
52
{
53
	char *ret, *val;
54 55
	xmlNodePtr child;

56 57 58 59
	val = (char *) xmlGetProp (node, name);
	if (val != NULL) {
		ret = g_strdup (val);
		xmlFree (val);
Morten Welinder's avatar
Morten Welinder committed
60
		return ret;
61
	}
62 63 64
	child = node->childs;

	while (child != NULL) {
65 66 67 68
		if (!strcmp (child->name, name)) {
		        /*
			 * !!! Inefficient, but ...
			 */
69 70 71 72 73 74
			val = xmlNodeGetContent(child);
			if (val != NULL) {
				ret = g_strdup (val);
				xmlFree (val);
				return ret;
			}
75
		}
76 77 78 79
		child = child->next;
	}

	return NULL;
80 81
}

82
#if 0
83 84 85 86
/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
87
static String *
88
xml_get_value_string (xmlNodePtr node, const char *name)
89
{
90
	char *val;
91 92
	String *ret;

93 94 95 96 97
	val = xml_value_get (node, name);
	if (val == NULL) return NULL;
        ret = string_get (val);
	g_free (val);
	return ret;
98
}
99
#endif
100

101 102 103 104
/*
 * Get an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
105
static int
106
xml_get_value_int (xmlNodePtr node, const char *name, int *val)
107
{
108
	char *ret;
109
	int i;
110
	int res;
111

112
	ret = xml_value_get (node, name);
113
	if (ret == NULL) return 0;
114
	res = sscanf (ret, "%d", &i);
115 116
	g_free (ret);

117 118
	if (res == 1) {
	        *val = i;
119 120 121
		return 1;
	}
	return 0;
122 123
}

124
#if 0
125 126 127 128
/*
 * Get a float value for a node either carried as an attibute or as
 * the content of a child.
 */
129
static int
130
xml_get_value_float (xmlNodePtr node, const char *name, float *val)
131
{
132 133
	int res;
	char *ret;
134 135
	float f;

136
	ret = xml_value_get (node, name);
137
	if (ret == NULL) return 0;
138
	res = sscanf (ret, "%f", &f);
139 140
	g_free (ret);

141 142
	if (res == 1) {
	        *val = f;
143 144 145
		return 1;
	}
	return 0;
146
}
147
#endif
148 149 150 151 152

/*
 * Get a double value for a node either carried as an attibute or as
 * the content of a child.
 */
153
static int
154
xml_get_value_double (xmlNodePtr node, const char *name, double *val)
155
{
156 157
	int res;
	char *ret;
158

159
	ret = xml_value_get (node, name);
160
	if (ret == NULL) return 0;
161
	res = sscanf (ret, "%lf", val);
162
	g_free (ret);
163

164
	return (res == 1);
165 166
}

167
#if 0
168 169 170
/*
 * Get a set of coodinates for a node, carried as the content of a child.
 */
171
static int
172
xml_get_coordinate (xmlNodePtr node, const char *name, double *x, double *y)
173
{
174 175
	int res;
	char *ret;
176
	float X, Y;
177

178
	ret = xml_value_get (node, name);
179
	if (ret == NULL) return 0;
180
	res = sscanf (ret, "(%lf %lf)", x, y)
181
	g_free (ret);
182 183

	return (res == 2)
184
}
185
#endif
186 187 188 189 190

/*
 * Get a pair of coodinates for a node, carried as the content of a child.
 */

191
static int
192
xml_get_coordinates (xmlNodePtr node, const char *name,
193 194
		   double *x1, double *y1, double *x2, double *y2)
{
195 196
	int res;
	char *ret;
197

198
	ret = xml_value_get (node, name);
199
	if (ret == NULL) return 0;
200
	res = sscanf (ret, "(%lf %lf)(%lf %lf)", x1, y1, x2, y2);
201 202 203
	g_free (ret);

	if (res == 4)
204
		return 1;
205

206
	return 0;
207 208
}

209
#if 0
210 211 212
/*
 * Get a GnomeCanvasPoints for a node, carried as the content of a child.
 */
213
static GnomeCanvasPoints *
214
xml_get_gnome_canvas_points (xmlNodePtr node, const char *name)
215
{
216
	char *val;
217 218 219 220
	GnomeCanvasPoints *ret = NULL;
	int res;
	const char *ptr;
	int index = 0, i;
221
	float coord[20];	/* TODO: must be dynamic !!!! */
222

223
	val = xml_value_get (node, name);
224
	if (val == NULL) return NULL;
225 226 227 228 229
	ptr = val;
	do {
		while ((*ptr) && (*ptr != '('))
			ptr++;
		if (*ptr == 0)
230
			break;
231
		res = sscanf (ptr, "(%lf %lf)", &coord[index], &coord[index + 1]);
232 233 234 235 236
		if (res != 2)
			break;
		index += 2;
		ptr++;
	} while (res > 0);
237
	g_free (val);
238 239 240 241 242 243 244

	if (index >= 2)
		ret = gnome_canvas_points_new (index / 2);
	if (ret == NULL)
		return NULL;
	for (i = 0; i < index; i++)
		ret->coords[i] = coord[i];
245
	return ret;
246
}
247
#endif
248 249 250 251 252

/*
 * Set a string value for a node either carried as an attibute or as
 * the content of a child.
 */
253
static void
254
xml_set_gnome_canvas_points (xmlNodePtr node, const char *name,
255
			     GnomeCanvasPoints *val)
256 257 258
{
	xmlNodePtr child;
	char *str, *base;
259
	char *tstr;
260 261 262 263 264 265
	int i;

	if (val == NULL)
		return;
	if ((val->num_points < 0) || (val->num_points > 5000))
		return;
266
	base = str = g_malloc (val->num_points * 30 * sizeof (char) + 1);
267 268 269
	if (str == NULL)
		return;
	for (i = 0; i < val->num_points; i++){
270 271 272
		sprintf (str, "(%f %f)", val->coords[2 * i],
			 val->coords[2 * i + 1]);
		str += strlen (str);
273
	}
274
	*str = 0;
275 276 277 278 279

	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, base);
280
			g_free (base);
281 282 283 284
			return;
		}
		child = child->next;
	}
285 286 287 288

	tstr = xmlEncodeEntitiesReentrant (node->doc, base);
	xmlNewChild (node, NULL, name, tstr);
	if (tstr) xmlFree (tstr);
289
	g_free (base);
290 291
}

292 293 294 295
/*
 * Set a string value for a node either carried as an attibute or as
 * the content of a child.
 */
296 297
static void
xml_set_value (xmlNodePtr node, const char *name, const char *val)
298
{
299
	char *ret;
300 301 302 303
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
	if (ret != NULL){
304
		xmlFree (ret);
305 306 307 308 309 310 311 312 313 314 315 316
		xmlSetProp (node, name, val);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, val);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, val);
317 318
}

319 320 321 322
/*
 * Set a String value for a node either carried as an attibute or as
 * the content of a child.
 */
323 324
static void
xml_set_value_string (xmlNodePtr node, const char *name, String *val)
325
{
326
	char *ret;
327 328 329 330
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
	if (ret != NULL){
331
		xmlFree (ret);
332 333 334 335 336 337 338 339 340 341 342 343
		xmlSetProp (node, name, val->str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, val->str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, val->str);
344 345
}

346 347 348 349
/*
 * Set an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
350
static void
351
xml_set_value_int (xmlNodePtr node, const char *name, int val)
352
{
353
	char *ret;
354 355 356 357 358 359
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%d", val);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
360
		xmlFree (ret);
361 362 363 364 365 366 367 368 369 370 371 372
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
373 374
}

375
#if 0
376 377 378 379
/*
 * Set a float value for a node either carried as an attibute or as
 * the content of a child.
 */
380
static void
381
xml_set_value_float (xmlNodePtr node, const char *name, float val)
382
{
383
	char *ret;
384 385 386 387 388 389
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%f", val);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
390
		xmlFree (ret);
391 392 393 394 395 396 397 398 399 400 401 402
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
403
}
404
#endif
405 406 407 408 409

/*
 * Set a double value for a node either carried as an attibute or as
 * the content of a child.
 */
410
static void
411
xml_set_value_double (xmlNodePtr node, const char *name, double val)
412
{
413
	char *ret;
414
	xmlNodePtr child;
415
	char str[101 + DBL_DIG];
416

417 418 419 420
	if (fabs (val) < 1e9 && fabs (val) > 1e-5)
		snprintf (str, 100 + DBL_DIG, "%.*g", DBL_DIG, val);
	else
		snprintf (str, 100 + DBL_DIG, "%f", val);
421

422 423
	ret = xmlGetProp (node, name);
	if (ret != NULL){
424
		xmlFree (ret);
425 426 427 428 429 430 431 432 433 434 435 436
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
437 438
}

439 440 441 442 443
static void
xml_set_print_unit (xmlNodePtr node, const char *name,
		    const PrintUnit * const pu)
{
	xmlNodePtr  child;
Jody Goldberg's avatar
Jody Goldberg committed
444
	char       *txt = "points";
445
	char       *tstr;
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464

	if (pu == NULL || name == NULL)
		return;

	switch (pu->desired_display) {
	case UNIT_POINTS:
		txt = "points";
		break;
	case UNIT_MILLIMETER:
		txt = "mm";
		break;
	case UNIT_CENTIMETER:
		txt = "cm";
		break;
	case UNIT_INCH:
		txt = "in";
		break;
	}

465 466 467 468
	tstr = xmlEncodeEntitiesReentrant (node->doc, name);
	child = xmlNewChild (node, NULL, "PrintUnit", tstr);
	if (tstr) xmlFree (tstr);

469
	xml_set_value_double (child, "Points", pu->points);
470 471 472 473

	tstr = xmlEncodeEntitiesReentrant (node->doc, txt);
	xml_set_value (child, "PrefUnit", tstr);
	if (tstr) xmlFree (tstr);
474 475 476 477 478 479
}

static void
xml_get_print_unit (xmlNodePtr node, PrintUnit * const pu)
{
	char       *txt;
480

481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
	g_return_if_fail (pu != NULL);
	g_return_if_fail (node != NULL);
	g_return_if_fail (node->childs != NULL);

	xml_get_value_double (node, "Points", &pu->points);
	txt = xml_value_get  (node, "PrefUnit");
	if (txt) {
		if (!g_strcasecmp (txt, "points"))
			pu->desired_display = UNIT_POINTS;
		else if (!g_strcasecmp (txt, "mm"))
			pu->desired_display = UNIT_MILLIMETER;
		else if (!g_strcasecmp (txt, "cm"))
			pu->desired_display = UNIT_CENTIMETER;
		else if (!g_strcasecmp (txt, "in"))
			pu->desired_display = UNIT_INCH;
496
		g_free (txt);
497 498 499
	}
}

500
/*
501
 * Search a child by name, if needed go down the tree to find it.
502
 */
503 504
static xmlNodePtr
xml_search_child (xmlNodePtr node, const char *name)
505 506 507 508 509 510 511 512 513 514 515 516
{
	xmlNodePtr ret;
	xmlNodePtr child;

	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name))
			return child;
		child = child->next;
	}
	child = node->childs;
	while (child != NULL){
517
		ret = xml_search_child (child, name);
518 519 520 521 522
		if (ret != NULL)
			return ret;
		child = child->next;
	}
	return NULL;
523 524 525 526 527 528 529 530 531 532
}

/*
 * Get a color value for a node either carried as an attibute or as
 * the content of a child.
 *
 * TODO PBM: at parse time one doesn't have yet a widget, so we have
 *           to retrieve the default colormap, but this may be a bad
 *           option ...
 */
533
static int
534
xml_get_color_value (xmlNodePtr node, const char *name, StyleColor **color)
535
{
536
	char *ret;
537 538
	int red, green, blue;

539
	ret = xml_value_get (node, name);
540
	if (ret == NULL) return 0;
541
	if (sscanf (ret, "%X:%X:%X", &red, &green, &blue) == 3){
542
		*color = style_color_new (red, green, blue);
543
		g_free (ret);
544 545
		return 1;
	}
546
	g_free (ret);
547
	return 0;
548 549 550 551 552 553
}

/*
 * Set a color value for a node either carried as an attibute or as
 * the content of a child.
 */
554 555
static void
xml_set_color_value (xmlNodePtr node, const char *name, StyleColor *val)
556
{
557
	char *ret;
558 559 560 561 562 563
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%X:%X:%X", val->color.red, val->color.green, val->color.blue);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
564
		xmlFree (ret);
565 566 567 568 569 570 571 572 573 574 575 576
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
577
}
578 579 580 581 582

/**
 **
 ** Private functions : mapping between in-memory structure and XML tree
 **
583
 **/
584

585 586
static int
style_is_default_fore (StyleColor *color)
587
{
588 589
	if (!color)
		return TRUE;
590

591 592 593 594
	if (color->color.red == 0 && color->color.green == 0 && color->color.blue == 0)
		return TRUE;
	else
		return FALSE;
595 596
}

597 598
static int
style_is_default_back (StyleColor *color)
599
{
600 601
	if (!color)
		return TRUE;
602

603 604 605 606
	if (color->color.red == 0xffff && color->color.green == 0xffff && color->color.blue == 0xffff)
		return TRUE;
	else
		return FALSE;
607 608 609 610 611
}

/*
 * Create an XML subtree of doc equivalent to the given StyleBorder.
 */
612

Michael Meeks's avatar
Michael Meeks committed
613
static char *StyleSideNames[6] =
614 615 616 617
{
 	"Top",
 	"Bottom",
 	"Left",
Michael Meeks's avatar
Michael Meeks committed
618 619 620
 	"Right",
	"Diagonal",
	"Rev-Diagonal"
Arturo Espinosa's avatar
Arturo Espinosa committed
621
};
622

623
static xmlNodePtr
624 625
xml_write_style_border (parse_xml_context_t *ctxt,
			const MStyle *style)
626 627 628
{
	xmlNodePtr cur;
	xmlNodePtr side;
629
	int        i;
630

631 632 633 634 635
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
		MStyleBorder const *border;
		if (mstyle_is_element_set (style, i) &&
		    NULL != (border = mstyle_get_border (style, i)) &&
		    border->line_type != STYLE_BORDER_NONE) {
Arturo Espinosa's avatar
Arturo Espinosa committed
636
			break;
637
		}
638
	}
639
	if (i > MSTYLE_BORDER_REV_DIAGONAL)
Arturo Espinosa's avatar
Arturo Espinosa committed
640
		return NULL;
641

642
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "StyleBorder", NULL);
643

Michael Meeks's avatar
Michael Meeks committed
644
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
Jody Goldberg's avatar
Jody Goldberg committed
645 646
		MStyleBorder const *border;
		if (mstyle_is_element_set (style, i) &&
647 648
		    NULL != (border = mstyle_get_border (style, i)) &&
		    border->line_type != STYLE_BORDER_NONE) {
Jody Goldberg's avatar
Jody Goldberg committed
649 650
			StyleBorderType t = border->line_type;
			StyleColor *col   = border->color;
651 652
 			side = xmlNewChild (cur, ctxt->ns,
					    StyleSideNames [i - MSTYLE_BORDER_TOP],
653
 					    NULL);
654
 			xml_set_color_value (side, "Color", col);
655
			xml_set_value_int (side, "Style", t);
656
 		}
657 658
	}
	return cur;
659 660 661 662 663
}

/*
 * Create a StyleBorder equivalent to the XML subtree of doc.
 */
664
static void
665
xml_read_style_border (parse_xml_context_t *ctxt, xmlNodePtr tree, MStyle *mstyle)
666 667
{
	xmlNodePtr side;
668
	int        i;
669 670 671

	if (strcmp (tree->name, "StyleBorder")){
		fprintf (stderr,
672
			 "xml_read_style_border: invalid element type %s, 'StyleBorder' expected`\n",
673 674
			 tree->name);
	}
675

Michael Meeks's avatar
Michael Meeks committed
676
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
677 678
 		if ((side = xml_search_child (tree,
					      StyleSideNames [i - MSTYLE_BORDER_TOP])) != NULL) {
679 680 681 682 683
			int		 t;
			StyleColor      *color = NULL;
			MStyleBorder    *border;
			xml_get_value_int (side, "Style", &t);
			xml_get_color_value (side, "Color", &color);
684
			border = style_border_fetch ((StyleBorderType)t, color,
Michael Meeks's avatar
Michael Meeks committed
685
						     style_border_get_orientation (i));
686 687
			if (border)
				mstyle_set_border (mstyle, i, border);
688
 		}
689
	}
690 691 692 693 694
}

/*
 * Create an XML subtree of doc equivalent to the given Style.
 */
695
static xmlNodePtr
696 697
xml_write_style (parse_xml_context_t *ctxt,
		 MStyle *style)
698
{
699
	xmlNodePtr  cur, child;
700
	char       *tstr;
701

702
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Style", NULL);
703

704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
	if (mstyle_is_element_set (style, MSTYLE_ALIGN_H))
		xml_set_value_int (cur, "HAlign", mstyle_get_align_h (style));
	if (mstyle_is_element_set (style, MSTYLE_ALIGN_V))
		xml_set_value_int (cur, "VAlign", mstyle_get_align_v (style));
	if (mstyle_is_element_set (style, MSTYLE_FIT_IN_CELL))
		xml_set_value_int (cur, "Fit", mstyle_get_fit_in_cell (style));
	if (mstyle_is_element_set (style, MSTYLE_ORIENTATION))
		xml_set_value_int (cur, "Orient", mstyle_get_orientation (style));
	if (mstyle_is_element_set (style, MSTYLE_PATTERN))
		xml_set_value_int (cur, "Shade", mstyle_get_pattern (style));

	if (mstyle_is_element_set (style, MSTYLE_COLOR_FORE)) {
		if (!style_is_default_fore (mstyle_get_color (style, MSTYLE_COLOR_FORE)))
			xml_set_color_value (cur, "Fore", mstyle_get_color (style, MSTYLE_COLOR_FORE));
	}
	if (mstyle_is_element_set (style, MSTYLE_COLOR_BACK)) {
720
		if (!style_is_default_back (mstyle_get_color (style, MSTYLE_COLOR_BACK)))
721 722
			xml_set_color_value (cur, "Back", mstyle_get_color (style, MSTYLE_COLOR_BACK));
	}
723 724 725 726
	if (mstyle_is_element_set (style, MSTYLE_COLOR_PATTERN)) {
		if (!style_is_default_back (mstyle_get_color (style, MSTYLE_COLOR_PATTERN)))
			xml_set_color_value (cur, "PatternColor", mstyle_get_color (style, MSTYLE_COLOR_PATTERN));
	}
727 728 729 730 731 732 733 734 735 736 737 738 739
	if (mstyle_is_element_set (style, MSTYLE_FORMAT))
		xml_set_value (cur, "Format", mstyle_get_format (style)->format);

	if (mstyle_is_element_set (style, MSTYLE_FONT_NAME) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_BOLD) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_ITALIC) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_SIZE)) {
		const char *fontname;

		if (mstyle_is_element_set (style, MSTYLE_FONT_NAME))
			fontname = mstyle_get_font_name (style);
		else /* backwards compatibility */
			fontname = "Helvetica";
740

741 742 743 744
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, fontname);
		child = xmlNewChild (cur, ctxt->ns, "Font", tstr);
		if (tstr) xmlFree (tstr);

745 746 747 748 749 750 751 752 753 754 755 756 757 758
		if (mstyle_is_element_set (style, MSTYLE_FONT_SIZE))
			xml_set_value_double (child, "Unit",
					      mstyle_get_font_size (style));
		if (mstyle_is_element_set (style, MSTYLE_FONT_BOLD))
			xml_set_value_int (child, "Bold",
					   mstyle_get_font_bold (style));
		if (mstyle_is_element_set (style, MSTYLE_FONT_ITALIC))
			xml_set_value_int (child, "Italic",
					   mstyle_get_font_italic (style));
	}

	child = xml_write_style_border (ctxt, style);
	if (child)
		xmlAddChild (cur, child);
759 760

	return cur;
761 762
}

763
static xmlNodePtr
764
xml_write_names (parse_xml_context_t *ctxt, GList *names)
765
{
766
	xmlNodePtr  cur;
767
	char       *tstr;
768 769 770 771 772 773 774 775 776 777 778 779 780 781

	if (!names)
		return NULL;

	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Names", NULL);

	while (names) {
		xmlNodePtr   tmp;
		ExprName    *expr_name = names->data;
		char        *text;

		g_return_val_if_fail (expr_name != NULL, NULL);

		tmp = xmlNewDocNode (ctxt->doc, ctxt->ns, "Name", NULL);
782 783 784
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, expr_name->name->str);
		xmlNewChild (tmp, ctxt->ns, "name", tstr);
		if (tstr) xmlFree (tstr);
785 786

		text = expr_name_value (expr_name);
787 788 789
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
		xmlNewChild (tmp, ctxt->ns, "value", tstr);
		if (tstr) xmlFree (tstr);
790 791 792 793 794
		g_free (text);

		xmlAddChild (cur, tmp);
		names = g_list_next (names);
	}
795

796 797 798 799
	return cur;
}

static void
800 801
xml_read_names (parse_xml_context_t *ctxt, xmlNodePtr tree, Workbook *wb,
		Sheet *sheet)
802 803 804 805 806 807 808 809
{
	xmlNodePtr child;

	g_return_if_fail (ctxt != NULL);
	g_return_if_fail (tree != NULL);

	child = tree->childs;
	while (child) {
810
		char *name  = NULL;
811 812 813 814 815
		if (child->name && !strcmp (child->name, "Name")) {
			xmlNodePtr bits;

			bits = child->childs;
			while (bits) {
816

817 818 819 820 821 822 823 824 825 826 827
				if (!strcmp (bits->name, "name")) {
					name = xmlNodeGetContent (bits);
				} else {
					char     *txt;
					char     *error;
					g_return_if_fail (name != NULL);

					txt = xmlNodeGetContent (bits);
					g_return_if_fail (txt != NULL);
					g_return_if_fail (!strcmp (bits->name, "value"));

828
					if (!expr_name_create (wb, sheet, name, txt, &error))
829 830 831 832
						g_warning (error);

					g_free (txt);
				}
833
				bits = bits->next;
834 835 836 837 838 839
			}
		}
		child = child->next;
	}
}

840
static xmlNodePtr
841
xml_write_summary (parse_xml_context_t *ctxt, SummaryInfo *summary_info)
842 843
{
	GList *items, *m;
844
	char *tstr;
845 846
	xmlNodePtr cur;

847
	if (!summary_info)
848 849
		return NULL;

850
	m = items = summary_info_as_list (summary_info);
851 852 853 854 855 856 857 858 859 860 861 862 863

	if (!items)
		return NULL;

	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Summary", NULL);

	while (items) {
		xmlNodePtr   tmp;
		SummaryItem *sit = items->data;
		if (sit) {
			char *text;

			tmp = xmlNewDocNode (ctxt->doc, ctxt->ns, "Item", NULL);
864 865 866
			tstr = xmlEncodeEntitiesReentrant (ctxt->doc, sit->name);
			xmlNewChild (tmp, ctxt->ns, "name", tstr);
			if (tstr) xmlFree (tstr);
867 868 869

			if (sit->type == SUMMARY_INT) {
				text = g_strdup_printf ("%d", sit->v.i);
870 871 872
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
				xmlNewChild (tmp, ctxt->ns, "val-int", tstr);
				if (tstr) xmlFree (tstr);
873 874
			} else {
				text = summary_item_as_text (sit);
875 876 877
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
				xmlNewChild (tmp, ctxt->ns, "val-string", tstr);
				if (tstr) xmlFree (tstr);
878 879
			}
			g_free (text);
880
			xmlAddChild (cur, tmp);
881 882 883 884 885 886 887 888
		}
		items = g_list_next (items);
	}
	g_list_free (m);
	return cur;
}

static void
889
xml_read_summary (parse_xml_context_t *ctxt, xmlNodePtr tree, SummaryInfo *summary_info)
890
{
891
	xmlNodePtr child;
892

893 894 895
	g_return_if_fail (ctxt != NULL);
	g_return_if_fail (tree != NULL);
	g_return_if_fail (summary_info != NULL);
896 897 898

	child = tree->childs;
	while (child) {
899
		char *name = NULL;
Miguel de Icaza's avatar
Miguel de Icaza committed
900

901 902 903 904 905 906
		if (child->name && !strcmp (child->name, "Item")) {
			xmlNodePtr bits;

			bits = child->childs;
			while (bits) {
				SummaryItem *sit = NULL;
907

908
				if (!strcmp (bits->name, "name")) {
909
					name = xmlNodeGetContent (bits);
910 911 912 913 914
				} else {
					char *txt;
					g_return_if_fail (name);

					txt = xmlNodeGetContent (bits);
915 916 917 918
					if (txt != NULL){
						if (!strcmp (bits->name, "val-string"))
							sit = summary_item_new_string (name, txt);
						else if (!strcmp (bits->name, "val-int"))
Miguel de Icaza's avatar
Miguel de Icaza committed
919
							sit = summary_item_new_int (name, atoi (txt));
920

921
						if (sit)
922
							summary_info_add (summary_info, sit);
923 924
						g_free (txt);
					}
925
				}
926
				bits = bits->next;
927 928
			}
		}
Miguel de Icaza's avatar
Miguel de Icaza committed
929
		if (name){
930
			xmlFree (name);
Miguel de Icaza's avatar
Miguel de Icaza committed
931 932
			name = NULL;
		}
933 934 935 936
		child = child->next;
	}
}

Michael Meeks's avatar
Michael Meeks committed
937 938 939 940 941
static void
xml_set_print_hf (xmlNodePtr node, const char *name,
		  const PrintHF * const hf)
{
	xmlNodePtr  child;
942
	char *tstr;
Michael Meeks's avatar
Michael Meeks committed
943 944 945 946 947

	if (hf == NULL || name == NULL)
		return;

	child = xmlNewChild (node, NULL, name, NULL);
948 949 950 951 952 953 954 955 956 957 958
	tstr = xmlEncodeEntitiesReentrant (node->doc, hf->left_format);
	xml_set_value (child, "Left", tstr);
	if (tstr) xmlFree (tstr);

	tstr = xmlEncodeEntitiesReentrant (node->doc, hf->middle_format);
	xml_set_value (child, "Middle", tstr);
	if (tstr) xmlFree (tstr);

	tstr = xmlEncodeEntitiesReentrant (node->doc, hf->right_format);
	xml_set_value (child, "Right", tstr);
	if (tstr) xmlFree (tstr);
Michael Meeks's avatar
Michael Meeks committed
959 960 961
}

static void
Arturo Espinosa's avatar
Arturo Espinosa committed
962
xml_get_print_hf (xmlNodePtr node, PrintHF *const hf)
Michael Meeks's avatar
Michael Meeks committed
963 964
{
	char *txt;
965

Michael Meeks's avatar
Michael Meeks committed
966 967 968 969
	g_return_if_fail (hf != NULL);
	g_return_if_fail (node != NULL);

	txt = xml_value_get (node, "Left");
970
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
971 972
		if (hf->left_format)
			g_free (hf->left_format);
973
		hf->left_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
974
	}
975

Michael Meeks's avatar
Michael Meeks committed
976
	txt = xml_value_get (node, "Middle");
977
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
978 979
		if (hf->middle_format)
			g_free (hf->middle_format);
980
		hf->middle_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
981
	}
Michael Meeks's avatar
Michael Meeks committed
982 983

	txt = xml_value_get (node, "Right");
984
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
985 986
		if (hf->right_format)
			g_free (hf->right_format);
987
		hf->right_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
988
	}
Michael Meeks's avatar
Michael Meeks committed
989 990
}

991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
static xmlNodePtr
xml_write_print_info (parse_xml_context_t *ctxt, PrintInformation *pi)
{
	xmlNodePtr cur, child;

	g_return_val_if_fail (pi != NULL, NULL);

	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "PrintInformation", NULL);

	xml_set_print_unit (cur, "top",    &pi->margins.top);
	xml_set_print_unit (cur, "bottom", &pi->margins.bottom);
	xml_set_print_unit (cur, "left",   &pi->margins.left);
	xml_set_print_unit (cur, "right",  &pi->margins.right);
	xml_set_print_unit (cur, "header", &pi->margins.header);
	xml_set_print_unit (cur, "footer", &pi->margins.footer);


	child = xmlNewDocNode (ctxt->doc, ctxt->ns, "vcenter", NULL);
	xml_set_value_int  (child, "value", pi->center_vertically);
	xmlAddChild (cur, child);
	child = xmlNewDocNode (ctxt->doc, ctxt->ns, "hcenter", NULL);
	xml_set_value_int  (child, "value", pi->center_horizontally);
	xmlAddChild (cur, child);

	child = xmlNewDocNode (ctxt->doc, ctxt->ns, "grid", NULL);
	xml_set_value_int  (child, "value",    pi->print_line_divisions);
	xmlAddChild (cur, child);
	child = xmlNewDocNode (ctxt->doc, ctxt->ns, "monochrome", NULL);
	xml_set_value_int  (child, "value",    pi->print_black_and_white);
	xmlAddChild (cur, child);
	child = xmlNewDocNode (ctxt->doc, ctxt->ns, "draft", NULL);
	xml_set_value_int  (child, "value",    pi->print_as_draft);
	xmlAddChild (cur, child);
	child = xmlNewDocNode (ctxt->doc, ctxt->ns, "titles", NULL);
	xml_set_value_int  (child, "value",    pi->print_titles);
	xmlAddChild (cur, child);

Michael Meeks's avatar
Michael Meeks committed
1028 1029 1030 1031
	if (pi->print_order == PRINT_ORDER_DOWN_THEN_RIGHT)
		child = xmlNewDocNode (ctxt->doc, ctxt->ns, "order", "d_then_r");
	else
		child = xmlNewDocNode (ctxt->doc, ctxt->ns, "order", "r_then_d");
1032 1033
	xmlAddChild (cur, child);

Michael Meeks's avatar
Michael Meeks committed
1034 1035 1036 1037
	if (pi->orientation == PRINT_ORIENT_VERTICAL)
		child = xmlNewDocNode (ctxt->doc, ctxt->ns, "orientation", "portrait");
	else
		child = xmlNewDocNode (ctxt->doc, ctxt->ns, "orientation", "landscape");
1038 1039
	xmlAddChild (cur, child);

Michael Meeks's avatar
Michael Meeks committed
1040 1041 1042
	xml_set_print_hf (cur, "Header", pi->header);
	xml_set_print_hf (cur, "Footer", pi->footer);

1043 1044
	child = xmlNewDocNode (ctxt->doc, ctxt->ns, "paper", gnome_paper_name (pi->paper));
	xmlAddChild (cur, child);
1045

1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
	return cur;
}

static void
xml_read_print_info (parse_xml_context_t *ctxt, xmlNodePtr tree)
{
	xmlNodePtr child;
	PrintInformation *pi;
	int b;

	g_return_if_fail (ctxt != NULL);
	g_return_if_fail (tree != NULL);
	g_return_if_fail (ctxt->sheet != NULL);

	pi = ctxt->sheet->print_info;
1061

1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
	g_return_if_fail (pi != NULL);

	if ((child = xml_search_child (tree, "top")))
		xml_get_print_unit (child, &pi->margins.top);
	if ((child = xml_search_child (tree, "bottom")))
		xml_get_print_unit (child, &pi->margins.bottom);
	if ((child = xml_search_child (tree, "left")))
		xml_get_print_unit (child, &pi->margins.left);
	if ((child = xml_search_child (tree, "right")))
		xml_get_print_unit (child, &pi->margins.right);
	if ((child = xml_search_child (tree, "header")))
		xml_get_print_unit (child, &pi->margins.header);
	if ((child = xml_search_child (tree, "footer")))
		xml_get_print_unit (child, &pi->margins.footer);

	if ((child = xml_search_child (tree, "vcenter"))) {
		xml_get_value_int  (child, "value", &b);
		pi->center_vertically   = (b == 1);
	}
	if ((child = xml_search_child (tree, "hcenter"))) {
		xml_get_value_int  (child, "value", &b);
		pi->center_horizontally = (b == 1);
	}

	if ((child = xml_search_child (tree, "grid"))) {
		xml_get_value_int  (child, "value",    &b);
		pi->print_line_divisions  = (b == 1);
	}
	if ((child = xml_search_child (tree, "monochrome"))) {
		xml_get_value_int  (child, "value", &b);
		pi->print_black_and_white = (b == 1);
	}
	if ((child = xml_search_child (tree, "draft"))) {
		xml_get_value_int  (child, "value",   &b);
		pi->print_as_draft        = (b == 1);
	}
	if ((child = xml_search_child (tree, "titles"))) {
		xml_get_value_int  (child, "value",  &b);
		pi->print_titles          = (b == 1);
	}
1102

Michael Meeks's avatar
Michael Meeks committed
1103
	if ((child = xml_search_child (tree, "order"))) {
1104 1105 1106
		char *txt;
		txt = xmlNodeGetContent (child);
		if (!strcmp (txt, "d_then_r"))
Michael Meeks's avatar
Michael Meeks committed
1107 1108 1109
			pi->print_order = PRINT_ORDER_DOWN_THEN_RIGHT;
		else
			pi->print_order = PRINT_ORDER_RIGHT_THEN_DOWN;
1110
		xmlFree (txt);
Michael Meeks's avatar
Michael Meeks committed
1111 1112 1113
	}

	if ((child = xml_search_child (tree, "orientation"))) {
1114 1115 1116
		char *txt;
		txt = xmlNodeGetContent (child);
		if (!strcmp (txt, "portrait"))
Michael Meeks's avatar
Michael Meeks committed
1117 1118 1119
			pi->orientation = PRINT_ORIENT_VERTICAL;
		else
			pi->orientation = PRINT_ORIENT_HORIZONTAL;
1120
		xmlFree (txt);
Michael Meeks's avatar
Michael Meeks committed
1121
	}
1122

Michael Meeks's avatar
Michael Meeks committed
1123 1124 1125 1126 1127
	if ((child = xml_search_child (tree, "Header")))
		xml_get_print_hf (child, pi->header);
	if ((child = xml_search_child (tree, "Footer")))
		xml_get_print_hf (child, pi->header);

1128 1129 1130 1131 1132
	if ((child = xml_search_child (tree, "paper"))) {
		char *txt = xmlNodeGetContent (child);
		pi->paper = gnome_paper_with_name (txt);
		xmlFree (txt);
	}
1133 1134
}