xml-io.c 54 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"
Daniel Veillard's avatar
Daniel Veillard committed
19
#include "gnome-xml/parserInternals.h"
20
#include "gnome-xml/xmlmemory.h"
21
#include "color.h"
22
#include "border.h"
23
#include "sheet-object.h"
24
#include "sheet-object-graphic.h"
25
#include "print-info.h"
26
#include "xml-io.h"
27
#include "file.h"
28
#include "workbook.h"
29 30
#include "workbook-view.h"
#include "selection.h"
31
#include "command-context.h"
32 33 34 35

/*
 * A parsing context.
 */
36 37 38 39 40 41
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 */
42
	GHashTable *style_table;/* old style styles compatibility */
43 44
} parse_xml_context_t;

45 46 47
/*
 * Internal stuff: xml helper functions.
 */
48 49 50 51

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

61 62 63 64
	val = (char *) xmlGetProp (node, name);
	if (val != NULL) {
		ret = g_strdup (val);
		xmlFree (val);
Morten Welinder's avatar
Morten Welinder committed
65
		return ret;
66
	}
67 68 69
	child = node->childs;

	while (child != NULL) {
70 71 72 73
		if (!strcmp (child->name, name)) {
		        /*
			 * !!! Inefficient, but ...
			 */
74 75 76 77 78 79
			val = xmlNodeGetContent(child);
			if (val != NULL) {
				ret = g_strdup (val);
				xmlFree (val);
				return ret;
			}
80
		}
81 82 83 84
		child = child->next;
	}

	return NULL;
85 86
}

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

98 99 100 101 102
	val = xml_value_get (node, name);
	if (val == NULL) return NULL;
        ret = string_get (val);
	g_free (val);
	return ret;
103
}
104
#endif
105

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

117
	ret = xml_value_get (node, name);
118
	if (ret == NULL) return 0;
119
	res = sscanf (ret, "%d", &i);
120 121
	g_free (ret);

122 123
	if (res == 1) {
	        *val = i;
124 125 126
		return 1;
	}
	return 0;
127 128
}

129 130 131 132 133 134 135 136 137 138
static gboolean
xml_get_range (xmlNodePtr tree, Range *res)
{
	return 
	    xml_get_value_int (tree, "startCol", &res->start.col) &&
	    xml_get_value_int (tree, "startRow", &res->start.row) &&
	    xml_get_value_int (tree, "endCol",   &res->end.col) &&
	    xml_get_value_int (tree, "endRow",   &res->end.row);
}

139
#if 0
140 141 142 143
/*
 * Get a float value for a node either carried as an attibute or as
 * the content of a child.
 */
144
static int
145
xml_get_value_float (xmlNodePtr node, const char *name, float *val)
146
{
147 148
	int res;
	char *ret;
149 150
	float f;

151
	ret = xml_value_get (node, name);
152
	if (ret == NULL) return 0;
153
	res = sscanf (ret, "%f", &f);
154 155
	g_free (ret);

156 157
	if (res == 1) {
	        *val = f;
158 159 160
		return 1;
	}
	return 0;
161
}
162
#endif
163 164 165 166 167

/*
 * Get a double value for a node either carried as an attibute or as
 * the content of a child.
 */
168
static int
169
xml_get_value_double (xmlNodePtr node, const char *name, double *val)
170
{
171 172
	int res;
	char *ret;
173

174
	ret = xml_value_get (node, name);
175
	if (ret == NULL) return 0;
176
	res = sscanf (ret, "%lf", val);
177
	g_free (ret);
178

179
	return (res == 1);
180 181
}

182
#if 0
183 184 185
/*
 * Get a set of coodinates for a node, carried as the content of a child.
 */
186
static int
187
xml_get_coordinate (xmlNodePtr node, const char *name, double *x, double *y)
188
{
189 190
	int res;
	char *ret;
191
	float X, Y;
192

193
	ret = xml_value_get (node, name);
194
	if (ret == NULL) return 0;
195
	res = sscanf (ret, "(%lf %lf)", x, y)
196
	g_free (ret);
197 198

	return (res == 2)
199
}
200
#endif
201 202 203 204 205

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

206
static int
207
xml_get_coordinates (xmlNodePtr node, const char *name,
208 209
		   double *x1, double *y1, double *x2, double *y2)
{
210 211
	int res;
	char *ret;
212

213
	ret = xml_value_get (node, name);
214
	if (ret == NULL) return 0;
215
	res = sscanf (ret, "(%lf %lf)(%lf %lf)", x1, y1, x2, y2);
216 217 218
	g_free (ret);

	if (res == 4)
219
		return 1;
220

221
	return 0;
222 223
}

224
#if 0
225 226 227
/*
 * Get a GnomeCanvasPoints for a node, carried as the content of a child.
 */
228
static GnomeCanvasPoints *
229
xml_get_gnome_canvas_points (xmlNodePtr node, const char *name)
230
{
231
	char *val;
232 233 234 235
	GnomeCanvasPoints *ret = NULL;
	int res;
	const char *ptr;
	int index = 0, i;
236
	float coord[20];	/* TODO: must be dynamic !!!! */
237

238
	val = xml_value_get (node, name);
239
	if (val == NULL) return NULL;
240 241 242 243 244
	ptr = val;
	do {
		while ((*ptr) && (*ptr != '('))
			ptr++;
		if (*ptr == 0)
245
			break;
246
		res = sscanf (ptr, "(%lf %lf)", &coord[index], &coord[index + 1]);
247 248 249 250 251
		if (res != 2)
			break;
		index += 2;
		ptr++;
	} while (res > 0);
252
	g_free (val);
253 254 255 256 257 258 259

	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];
260
	return ret;
261
}
262
#endif
263 264 265 266 267

/*
 * Set a string value for a node either carried as an attibute or as
 * the content of a child.
 */
268
static void
269
xml_set_gnome_canvas_points (xmlNodePtr node, const char *name,
270
			     GnomeCanvasPoints *val)
271 272 273
{
	xmlNodePtr child;
	char *str, *base;
274
	char *tstr;
275 276 277 278 279 280
	int i;

	if (val == NULL)
		return;
	if ((val->num_points < 0) || (val->num_points > 5000))
		return;
281
	base = str = g_malloc (val->num_points * 30 * sizeof (char) + 1);
282 283 284
	if (str == NULL)
		return;
	for (i = 0; i < val->num_points; i++){
285 286 287
		sprintf (str, "(%f %f)", val->coords[2 * i],
			 val->coords[2 * i + 1]);
		str += strlen (str);
288
	}
289
	*str = 0;
290 291 292 293 294

	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, base);
295
			g_free (base);
296 297 298 299
			return;
		}
		child = child->next;
	}
300 301 302 303

	tstr = xmlEncodeEntitiesReentrant (node->doc, base);
	xmlNewChild (node, NULL, name, tstr);
	if (tstr) xmlFree (tstr);
304
	g_free (base);
305 306
}

307 308 309 310
/*
 * Set a string value for a node either carried as an attibute or as
 * the content of a child.
 */
311 312
static void
xml_set_value (xmlNodePtr node, const char *name, const char *val)
313
{
314
	char *ret;
315 316 317 318
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
	if (ret != NULL){
319
		xmlFree (ret);
320 321 322 323 324 325 326 327 328 329 330 331
		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);
332 333
}

334 335 336 337
/*
 * Set a String value for a node either carried as an attibute or as
 * the content of a child.
 */
338 339
static void
xml_set_value_string (xmlNodePtr node, const char *name, String *val)
340
{
341
	char *ret;
342 343 344 345
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
	if (ret != NULL){
346
		xmlFree (ret);
347 348 349 350 351 352 353 354 355 356 357 358
		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);
359 360
}

361 362 363 364
/*
 * Set an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
365
static void
366
xml_set_value_int (xmlNodePtr node, const char *name, int val)
367
{
368
	char *ret;
369 370 371 372 373 374
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%d", val);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
375
		xmlFree (ret);
376 377 378 379 380 381 382 383 384 385 386 387
		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);
388 389
}

390
#if 0
391 392 393 394
/*
 * Set a float value for a node either carried as an attibute or as
 * the content of a child.
 */
395
static void
396
xml_set_value_float (xmlNodePtr node, const char *name, float val)
397
{
398
	char *ret;
399 400 401 402 403 404
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%f", val);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
405
		xmlFree (ret);
406 407 408 409 410 411 412 413 414 415 416 417
		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);
418
}
419
#endif
420 421 422 423 424

/*
 * Set a double value for a node either carried as an attibute or as
 * the content of a child.
 */
425
static void
426
xml_set_value_double (xmlNodePtr node, const char *name, double val)
427
{
428
	char *ret;
429
	xmlNodePtr child;
430
	char str[101 + DBL_DIG];
431

432 433 434 435
	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);
436

437 438
	ret = xmlGetProp (node, name);
	if (ret != NULL){
439
		xmlFree (ret);
440 441 442 443 444 445 446 447 448 449 450 451
		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);
452 453
}

454 455 456 457 458
static void
xml_set_print_unit (xmlNodePtr node, const char *name,
		    const PrintUnit * const pu)
{
	xmlNodePtr  child;
Jody Goldberg's avatar
Jody Goldberg committed
459
	char       *txt = "points";
460
	char       *tstr;
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479

	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;
	}

480 481 482 483
	tstr = xmlEncodeEntitiesReentrant (node->doc, name);
	child = xmlNewChild (node, NULL, "PrintUnit", tstr);
	if (tstr) xmlFree (tstr);

484
	xml_set_value_double (child, "Points", pu->points);
485 486 487 488

	tstr = xmlEncodeEntitiesReentrant (node->doc, txt);
	xml_set_value (child, "PrefUnit", tstr);
	if (tstr) xmlFree (tstr);
489 490 491 492 493 494
}

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

496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
	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;
511
		g_free (txt);
512 513 514
	}
}

515
/*
516
 * Search a child by name, if needed go down the tree to find it.
517
 */
518 519
static xmlNodePtr
xml_search_child (xmlNodePtr node, const char *name)
520 521 522 523 524 525 526 527 528 529 530 531
{
	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){
532
		ret = xml_search_child (child, name);
533 534 535 536 537
		if (ret != NULL)
			return ret;
		child = child->next;
	}
	return NULL;
538 539 540 541 542 543 544 545 546 547
}

/*
 * 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 ...
 */
548
static int
549
xml_get_color_value (xmlNodePtr node, const char *name, StyleColor **color)
550
{
551
	char *ret;
552 553
	int red, green, blue;

554
	ret = xml_value_get (node, name);
555
	if (ret == NULL) return 0;
556
	if (sscanf (ret, "%X:%X:%X", &red, &green, &blue) == 3){
557
		*color = style_color_new (red, green, blue);
558
		g_free (ret);
559 560
		return 1;
	}
561
	g_free (ret);
562
	return 0;
563 564 565 566 567 568
}

/*
 * Set a color value for a node either carried as an attibute or as
 * the content of a child.
 */
569 570
static void
xml_set_color_value (xmlNodePtr node, const char *name, StyleColor *val)
571
{
572
	char *ret;
573 574 575 576 577 578
	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){
579
		xmlFree (ret);
580 581 582 583 584 585 586 587 588 589 590 591
		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);
592
}
593 594 595 596 597

/**
 **
 ** Private functions : mapping between in-memory structure and XML tree
 **
598
 **/
599

600 601
static int
style_is_default_fore (StyleColor *color)
602
{
603 604
	if (!color)
		return TRUE;
605

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

612 613
static int
style_is_default_back (StyleColor *color)
614
{
615 616
	if (!color)
		return TRUE;
617

618 619 620 621
	if (color->color.red == 0xffff && color->color.green == 0xffff && color->color.blue == 0xffff)
		return TRUE;
	else
		return FALSE;
622 623 624 625 626
}

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

Michael Meeks's avatar
Michael Meeks committed
628
static char *StyleSideNames[6] =
629 630 631 632
{
 	"Top",
 	"Bottom",
 	"Left",
Michael Meeks's avatar
Michael Meeks committed
633 634 635
 	"Right",
	"Diagonal",
	"Rev-Diagonal"
Arturo Espinosa's avatar
Arturo Espinosa committed
636
};
637

638
static xmlNodePtr
639 640
xml_write_style_border (parse_xml_context_t *ctxt,
			const MStyle *style)
641 642 643
{
	xmlNodePtr cur;
	xmlNodePtr side;
644
	int        i;
645

646 647 648
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
		MStyleBorder const *border;
		if (mstyle_is_element_set (style, i) &&
649
		    NULL != (border = mstyle_get_border (style, i))) {
Arturo Espinosa's avatar
Arturo Espinosa committed
650
			break;
651
		}
652
	}
653
	if (i > MSTYLE_BORDER_REV_DIAGONAL)
Arturo Espinosa's avatar
Arturo Espinosa committed
654
		return NULL;
655

656
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "StyleBorder", NULL);
657

Michael Meeks's avatar
Michael Meeks committed
658
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
Jody Goldberg's avatar
Jody Goldberg committed
659 660
		MStyleBorder const *border;
		if (mstyle_is_element_set (style, i) &&
661
		    NULL != (border = mstyle_get_border (style, i))) {
Jody Goldberg's avatar
Jody Goldberg committed
662 663
			StyleBorderType t = border->line_type;
			StyleColor *col   = border->color;
664 665
 			side = xmlNewChild (cur, ctxt->ns,
					    StyleSideNames [i - MSTYLE_BORDER_TOP],
666
 					    NULL);
667
 			xml_set_color_value (side, "Color", col);
668
			xml_set_value_int (side, "Style", t);
669
 		}
670 671
	}
	return cur;
672 673 674 675 676
}

/*
 * Create a StyleBorder equivalent to the XML subtree of doc.
 */
677
static void
678
xml_read_style_border (parse_xml_context_t *ctxt, xmlNodePtr tree, MStyle *mstyle)
679 680
{
	xmlNodePtr side;
681
	int        i;
682 683 684

	if (strcmp (tree->name, "StyleBorder")){
		fprintf (stderr,
685
			 "xml_read_style_border: invalid element type %s, 'StyleBorder' expected`\n",
686 687
			 tree->name);
	}
688

Michael Meeks's avatar
Michael Meeks committed
689
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
690 691
 		if ((side = xml_search_child (tree,
					      StyleSideNames [i - MSTYLE_BORDER_TOP])) != NULL) {
692 693 694 695 696
			int		 t;
			StyleColor      *color = NULL;
			MStyleBorder    *border;
			xml_get_value_int (side, "Style", &t);
			xml_get_color_value (side, "Color", &color);
697
			border = style_border_fetch ((StyleBorderType)t, color,
Michael Meeks's avatar
Michael Meeks committed
698
						     style_border_get_orientation (i));
699 700
			if (border)
				mstyle_set_border (mstyle, i, border);
701
 		}
702
	}
703 704 705 706 707
}

/*
 * Create an XML subtree of doc equivalent to the given Style.
 */
708
static xmlNodePtr
709 710
xml_write_style (parse_xml_context_t *ctxt,
		 MStyle *style)
711
{
712
	xmlNodePtr  cur, child;
713
	char       *tstr;
714

715
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Style", NULL);
716

717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
	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)) {
733
		if (!style_is_default_back (mstyle_get_color (style, MSTYLE_COLOR_BACK)))
734 735
			xml_set_color_value (cur, "Back", mstyle_get_color (style, MSTYLE_COLOR_BACK));
	}
736 737 738 739
	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));
	}
740 741 742 743 744 745 746 747 748 749 750 751 752
	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";
753

754 755 756 757
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, fontname);
		child = xmlNewChild (cur, ctxt->ns, "Font", tstr);
		if (tstr) xmlFree (tstr);

758 759 760 761 762 763 764 765 766 767 768 769 770 771
		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);
772 773

	return cur;
774 775
}

776
static xmlNodePtr
777
xml_write_names (parse_xml_context_t *ctxt, GList *names)
778
{
779
	xmlNodePtr  cur;
780
	char       *tstr;
781 782 783 784 785 786 787 788 789 790 791 792 793 794

	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);
795 796 797
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, expr_name->name->str);
		xmlNewChild (tmp, ctxt->ns, "name", tstr);
		if (tstr) xmlFree (tstr);
798 799

		text = expr_name_value (expr_name);
800 801 802
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
		xmlNewChild (tmp, ctxt->ns, "value", tstr);
		if (tstr) xmlFree (tstr);
803 804 805 806 807
		g_free (text);

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

809 810 811 812
	return cur;
}

static void
813 814
xml_read_names (parse_xml_context_t *ctxt, xmlNodePtr tree, Workbook *wb,
		Sheet *sheet)
815 816 817 818 819 820 821 822
{
	xmlNodePtr child;

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

	child = tree->childs;
	while (child) {
823
		char *name  = NULL;
824 825 826 827 828
		if (child->name && !strcmp (child->name, "Name")) {
			xmlNodePtr bits;

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

830 831 832 833 834 835 836 837 838 839 840
				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"));

841
					if (!expr_name_create (wb, sheet, name, txt, &error))
842 843
						g_warning (error);

Daniel Veillard's avatar
Daniel Veillard committed
844
					xmlFree (txt);
845
				}
846
				bits = bits->next;
847 848 849 850 851 852
			}
		}
		child = child->next;
	}
}

853
static xmlNodePtr
854
xml_write_summary (parse_xml_context_t *ctxt, SummaryInfo *summary_info)
855 856
{
	GList *items, *m;
857
	char *tstr;
858 859
	xmlNodePtr cur;

860
	if (!summary_info)
861 862
		return NULL;

863
	m = items = summary_info_as_list (summary_info);
864 865 866 867 868 869 870 871 872 873 874 875 876

	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);
877 878 879
			tstr = xmlEncodeEntitiesReentrant (ctxt->doc, sit->name);
			xmlNewChild (tmp, ctxt->ns, "name", tstr);
			if (tstr) xmlFree (tstr);
880 881 882

			if (sit->type == SUMMARY_INT) {
				text = g_strdup_printf ("%d", sit->v.i);
883 884 885
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
				xmlNewChild (tmp, ctxt->ns, "val-int", tstr);
				if (tstr) xmlFree (tstr);
886 887
			} else {
				text = summary_item_as_text (sit);
888 889 890
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
				xmlNewChild (tmp, ctxt->ns, "val-string", tstr);
				if (tstr) xmlFree (tstr);
891 892
			}
			g_free (text);
893
			xmlAddChild (cur, tmp);
894 895 896 897 898 899 900 901
		}
		items = g_list_next (items);
	}
	g_list_free (m);
	return cur;
}

static void
902
xml_read_summary (parse_xml_context_t *ctxt, xmlNodePtr tree, SummaryInfo *summary_info)
903
{
904
	xmlNodePtr child;
905

906 907 908
	g_return_if_fail (ctxt != NULL);
	g_return_if_fail (tree != NULL);
	g_return_if_fail (summary_info != NULL);
909 910 911

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

914 915 916 917 918 919
		if (child->name && !strcmp (child->name, "Item")) {
			xmlNodePtr bits;

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

921
				if (!strcmp (bits->name, "name")) {
922
					name = xmlNodeGetContent (bits);
923 924 925 926 927
				} else {
					char *txt;
					g_return_if_fail (name);

					txt = xmlNodeGetContent (bits);
928 929 930 931
					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
932
							sit = summary_item_new_int (name, atoi (txt));
933

934
						if (sit)
935
							summary_info_add (summary_info, sit);
Daniel Veillard's avatar
Daniel Veillard committed
936
						xmlFree (txt);
937
					}
938
				}
939
				bits = bits->next;
940 941
			}
		}
Miguel de Icaza's avatar
Miguel de Icaza committed
942
		if (name){
943
			xmlFree (name);
Miguel de Icaza's avatar
Miguel de Icaza committed
944 945
			name = NULL;
		}
946 947 948 949
		child = child->next;
	}
}

Michael Meeks's avatar
Michael Meeks committed
950 951 952 953 954 955 956 957 958 959
static void
xml_set_print_hf (xmlNodePtr node, const char *name,
		  const PrintHF * const hf)
{
	xmlNodePtr  child;

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

	child = xmlNewChild (node, NULL, name, NULL);
960 961 962
	xml_set_value (child, "Left", hf->left_format);
	xml_set_value (child, "Middle", hf->middle_format);
	xml_set_value (child, "Right", hf->right_format);
Michael Meeks's avatar
Michael Meeks committed
963 964 965
}

static void
Arturo Espinosa's avatar
Arturo Espinosa committed
966
xml_get_print_hf (xmlNodePtr node, PrintHF *const hf)
Michael Meeks's avatar
Michael Meeks committed
967 968
{
	char *txt;
969

Michael Meeks's avatar
Michael Meeks committed
970 971 972 973
	g_return_if_fail (hf != NULL);
	g_return_if_fail (node != NULL);

	txt = xml_value_get (node, "Left");
974
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
975 976
		if (hf->left_format)
			g_free (hf->left_format);
977
		hf->left_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
978
	}
979

Michael Meeks's avatar
Michael Meeks committed
980
	txt = xml_value_get (node, "Middle");
981
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
982 983
		if (hf->middle_format)
			g_free (hf->middle_format);
984
		hf->middle_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
985
	}
Michael Meeks's avatar
Michael Meeks committed
986 987

	txt = xml_value_get (node, "Right");
988
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
989 990
		if (hf->right_format)
			g_free (hf->right_format);
991
		hf->right_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
992
	}
Michael Meeks's avatar
Michael Meeks committed
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 1028 1029 1030 1031
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
1032 1033 1034 1035
	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");
1036 1037
	xmlAddChild (cur, child);

Michael Meeks's avatar
Michael Meeks committed
1038 1039 1040 1041
	if (pi->orientation == PRINT_ORIENT_VERTICAL)
		child = xmlNewDocNode (ctxt->doc, ctxt->ns, "orientation", "portrait");
	else
		child = xmlNewDocNode (ctxt->doc, ctxt->ns, "orientation", "landscape");
1042 1043
	xmlAddChild (cur, child);

Michael Meeks's avatar
Michael Meeks committed
1044 1045 1046
	xml_set_print_hf (cur, "Header", pi->header);
	xml_set_print_hf (cur, "Footer", pi->footer);

1047 1048
	child = xmlNewDocNode (ctxt->doc, ctxt->ns, "paper", gnome_paper_name (pi->paper));
	xmlAddChild (cur, child);
1049

1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
	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;
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 1102 1103 1104 1105
	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);
	}
1106

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

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