xml-io.c 81.3 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
 *   Jody Goldberg <jgoldberg@home.com>
8 9
 */
#include <config.h>
10
#include <gal/util/e-xml-utils.h>
11
#include <gnome.h>
12
#include <locale.h>
13
#include <math.h>
14
#include <limits.h>
15
#include "gnumeric.h"
16
#include "gnome-xml/parser.h"
Daniel Veillard's avatar
Daniel Veillard committed
17
#include "gnome-xml/parserInternals.h"
18
#include "gnome-xml/xmlmemory.h"
19
#include "style-color.h"
20
#include "style-border.h"
21
#include "style.h"
Jody Goldberg's avatar
Jody Goldberg committed
22 23
#include "sheet.h"
#include "sheet-style.h"
24
#include "sheet-object.h"
25
#include "sheet-object-cell-comment.h"
26
#include "print-info.h"
27
#include "xml-io.h"
28
#include "file.h"
29
#include "expr.h"
30
#include "expr-name.h"
31
#include "cell.h"
32
#include "sheet-merge.h"
33 34 35
#include "io-context.h"
#include "command-context.h"
#include "workbook-control.h"
36
#include "workbook-view.h"
37
#include "workbook.h"
38
#include "selection.h"
39
#include "clipboard.h"
Jody Goldberg's avatar
Jody Goldberg committed
40
#include "format.h"
Jody Goldberg's avatar
Jody Goldberg committed
41
#include "ranges.h"
Chyla Zbigniew's avatar
Chyla Zbigniew committed
42
#include "file.h"
43

44 45 46
/* Precision to use when saving point measures. */
#define POINT_SIZE_PRECISION 3

47 48
static FileOpener *xml_opener = NULL;
static FileSaver  *xml_saver = NULL;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
49

50 51
FileOpener *
gnumeric_xml_get_opener (void)
Chyla Zbigniew's avatar
Chyla Zbigniew committed
52
{
53
	return xml_opener;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
54 55
}

56 57
FileSaver *
gnumeric_xml_get_saver (void)
Chyla Zbigniew's avatar
Chyla Zbigniew committed
58
{
59
	return xml_saver;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
60 61
}

62 63 64
XmlParseContext *
xml_parse_ctx_new_full (xmlDocPtr             doc,
			xmlNsPtr              ns,
Michael Meeks's avatar
Michael Meeks committed
65
			GnumericXMLVersion    version,
66 67 68 69 70 71
			XmlSheetObjectReadFn  read_fn,
			XmlSheetObjectWriteFn write_fn,
			gpointer              user_data)
{
	XmlParseContext *ctxt = g_new0 (XmlParseContext, 1);

Michael Meeks's avatar
Michael Meeks committed
72
	ctxt->version   = version;
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
	ctxt->doc       = doc;
	ctxt->ns        = ns;
	ctxt->expr_map  = g_hash_table_new (g_direct_hash, g_direct_equal);

	ctxt->write_fn  = write_fn;
	ctxt->read_fn   = read_fn;
	ctxt->user_data = user_data;

	return ctxt;
}

XmlParseContext *
xml_parse_ctx_new (xmlDocPtr doc,
		   xmlNsPtr  ns)
{
Michael Meeks's avatar
Michael Meeks committed
88
	return xml_parse_ctx_new_full (
Jody Goldberg's avatar
Jody Goldberg committed
89
		doc, ns, GNUM_XML_V6, NULL, NULL, NULL);
90
}
91

92 93 94 95 96 97 98 99
void
xml_parse_ctx_destroy (XmlParseContext *ctxt)
{
	g_return_if_fail (ctxt != NULL);

	g_hash_table_destroy (ctxt->expr_map);
	g_free (ctxt);
}
100

101 102 103
/*
 * Internal stuff: xml helper functions.
 */
104

105 106 107 108
static void
xml_arg_set (GtkArg *arg, gchar *string)
{
	switch (arg->type) {
JP Rosevear's avatar
JP Rosevear committed
109 110 111 112 113 114 115
	case GTK_TYPE_CHAR:
		GTK_VALUE_CHAR (*arg) = string[0];
		break;
	case GTK_TYPE_UCHAR:
		GTK_VALUE_UCHAR (*arg) = string[0];
		break;
	case GTK_TYPE_BOOL:
Jody Goldberg's avatar
Jody Goldberg committed
116
		if (!strcmp (string, "TRUE"))
JP Rosevear's avatar
JP Rosevear committed
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
			GTK_VALUE_BOOL (*arg) = TRUE;
		else
			GTK_VALUE_BOOL (*arg) = FALSE;
		break;
	case GTK_TYPE_INT:
		GTK_VALUE_INT (*arg) = atoi (string);
		break;
	case GTK_TYPE_UINT:
		GTK_VALUE_UINT (*arg) = atoi (string);
		break;
	case GTK_TYPE_LONG:
		GTK_VALUE_LONG (*arg) = atol (string);
		break;
	case GTK_TYPE_ULONG:
		GTK_VALUE_ULONG (*arg) = atol (string);
		break;
	case GTK_TYPE_FLOAT:
		GTK_VALUE_FLOAT (*arg) = atof (string);
		break;
	case GTK_TYPE_DOUBLE:
		GTK_VALUE_DOUBLE (*arg) = atof (string);
		break;
	case GTK_TYPE_STRING:
		GTK_VALUE_STRING (*arg) = g_strdup (string);
		break;
142 143 144 145 146 147 148
	}
}

static char *
xml_arg_get (GtkArg *arg)
{
	switch (arg->type) {
JP Rosevear's avatar
JP Rosevear committed
149 150 151 152 153 154 155 156 157 158 159 160 161 162
	case GTK_TYPE_CHAR:
		return g_strdup (&GTK_VALUE_CHAR (*arg));
	case GTK_TYPE_UCHAR:
		return g_strdup (&GTK_VALUE_UCHAR (*arg));
	case GTK_TYPE_BOOL:
		if (GTK_VALUE_BOOL (*arg))
			return g_strdup ("TRUE");
		else
			return g_strdup ("FALSE");
	case GTK_TYPE_INT:
		return g_strdup_printf("%i", GTK_VALUE_INT (*arg));
	case GTK_TYPE_UINT:
		return g_strdup_printf("%u", GTK_VALUE_UINT (*arg));
	case GTK_TYPE_LONG:
Jon Kåre Hellan's avatar
Jon Kåre Hellan committed
163
		return g_strdup_printf("%li", GTK_VALUE_LONG (*arg));
JP Rosevear's avatar
JP Rosevear committed
164
	case GTK_TYPE_ULONG:
Jon Kåre Hellan's avatar
Jon Kåre Hellan committed
165
		return g_strdup_printf("%lu", GTK_VALUE_ULONG (*arg));
JP Rosevear's avatar
JP Rosevear committed
166 167 168 169 170 171
	case GTK_TYPE_FLOAT:
		return g_strdup_printf("%f", GTK_VALUE_FLOAT (*arg));
	case GTK_TYPE_DOUBLE:
		return g_strdup_printf("%f", GTK_VALUE_DOUBLE (*arg));
	case GTK_TYPE_STRING:
		return g_strdup (GTK_VALUE_STRING (*arg));
172 173 174 175
	}

	return NULL;
}
Jody Goldberg's avatar
Jody Goldberg committed
176

177 178 179
/*
 * Get a value for a node either carried as an attibute or as
 * the content of a child.
180 181
 *
 * Returns a g_malloc'ed string.  Caller must free.
182
 */
183
static char *
184
xml_value_get (xmlNodePtr node, const char *name)
185
{
186
	char *ret, *val;
187 188
	xmlNodePtr child;

189 190 191 192
	val = (char *) xmlGetProp (node, name);
	if (val != NULL) {
		ret = g_strdup (val);
		xmlFree (val);
Morten Welinder's avatar
Morten Welinder committed
193
		return ret;
194
	}
195
	child = node->xmlChildrenNode;
196 197

	while (child != NULL) {
198 199 200 201
		if (!strcmp (child->name, name)) {
		        /*
			 * !!! Inefficient, but ...
			 */
202 203 204 205 206 207
			val = xmlNodeGetContent(child);
			if (val != NULL) {
				ret = g_strdup (val);
				xmlFree (val);
				return ret;
			}
208
		}
209 210 211 212
		child = child->next;
	}

	return NULL;
213 214
}

215 216 217 218
/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
219
String *
220
xml_get_value_string (xmlNodePtr node, const char *name)
221
{
222
	char *val;
223 224
	String *ret;

225 226 227 228 229
	val = xml_value_get (node, name);
	if (val == NULL) return NULL;
        ret = string_get (val);
	g_free (val);
	return ret;
230 231
}

232 233 234 235
/*
 * Get an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
236
gboolean
237
xml_get_value_int (xmlNodePtr node, const char *name, int *val)
238
{
239
	char *ret;
240
	int i;
241
	int res;
242

243
	ret = xml_value_get (node, name);
244
	if (ret == NULL) return 0;
245
	res = sscanf (ret, "%d", &i);
246 247
	g_free (ret);

248 249
	if (res == 1) {
	        *val = i;
250
		return TRUE;
251
	}
252
	return FALSE;
253 254
}

255
#if 0
256 257 258 259
/*
 * Get a float value for a node either carried as an attibute or as
 * the content of a child.
 */
260
static int
261
xml_get_value_float (xmlNodePtr node, const char *name, float *val)
262
{
263 264
	int res;
	char *ret;
265 266
	float f;

267
	ret = xml_value_get (node, name);
268
	if (ret == NULL) return 0;
269
	res = sscanf (ret, "%f", &f);
270 271
	g_free (ret);

272 273
	if (res == 1) {
	        *val = f;
274 275 276
		return 1;
	}
	return 0;
277
}
278
#endif
279 280 281 282 283

/*
 * Get a double value for a node either carried as an attibute or as
 * the content of a child.
 */
284
static int
285
xml_get_value_double (xmlNodePtr node, const char *name, double *val)
286
{
287 288
	int res;
	char *ret;
289

290
	ret = xml_value_get (node, name);
291
	if (ret == NULL) return 0;
292
	res = sscanf (ret, "%lf", val);
293
	g_free (ret);
294

295
	return (res == 1);
296 297 298 299 300 301
}

/*
 * Set a string value for a node either carried as an attibute or as
 * the content of a child.
 */
302 303
void
xml_set_value_cstr (xmlNodePtr node, const char *name, const char *val)
304
{
305
	char *ret;
306 307 308 309
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
	if (ret != NULL){
310
		xmlFree (ret);
311 312 313
		xmlSetProp (node, name, val);
		return;
	}
314
	child = node->xmlChildrenNode;
315 316 317 318 319 320 321 322
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, val);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, val);
323 324
}

325 326 327 328
/*
 * Set a String value for a node either carried as an attibute or as
 * the content of a child.
 */
329
void
330
xml_set_value_string (xmlNodePtr node, const char *name, const String *val)
331
{
332
	char *ret;
333 334 335
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
336
	if (ret != NULL) {
337
		xmlFree (ret);
338 339 340
		xmlSetProp (node, name, val->str);
		return;
	}
341
	child = node->xmlChildrenNode;
342 343 344 345 346 347 348 349
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, val->str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, val->str);
350 351
}

352 353 354 355
/*
 * Set an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
356
void
357
xml_set_value_int (xmlNodePtr node, const char *name, int val)
358
{
359
	char *ret;
360
	xmlNodePtr child;
361
	char str[4 * sizeof (int)];
362

363
	sprintf (str, "%d", val);
364 365
	ret = xmlGetProp (node, name);
	if (ret != NULL){
366
		xmlFree (ret);
367 368 369
		xmlSetProp (node, name, str);
		return;
	}
370
	child = node->xmlChildrenNode;
371 372 373 374 375 376 377 378
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
379 380 381 382 383 384
}

/*
 * Set a double value for a node either carried as an attibute or as
 * the content of a child.
 */
385
static void
386 387
xml_set_value_double (xmlNodePtr node, const char *name, double val,
		      int precision)
388
{
389
	char *ret;
390
	xmlNodePtr child;
391
	char str[101 + DBL_DIG];
392

393 394
	if (precision < 0 || precision > DBL_DIG)
		precision = DBL_DIG;
395

396
	if (fabs (val) < 1e9 && fabs (val) > 1e-5)
397
		snprintf (str, 100 + DBL_DIG, "%.*g", precision, val);
398 399
	else
		snprintf (str, 100 + DBL_DIG, "%f", val);
400

401 402
	ret = xmlGetProp (node, name);
	if (ret != NULL){
403
		xmlFree (ret);
404 405 406
		xmlSetProp (node, name, str);
		return;
	}
407
	child = node->xmlChildrenNode;
408 409 410 411 412 413 414 415
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
416 417
}

418 419 420 421 422 423 424 425 426
/*
 * Set a double value for a node with POINT_SIZE_PRECISION digits precision.
 */
static void
xml_set_value_points (xmlNodePtr node, const char *name, double val)
{
	xml_set_value_double (node, name, val, POINT_SIZE_PRECISION);
}

427 428 429 430 431
static void
xml_set_print_unit (xmlNodePtr node, const char *name,
		    const PrintUnit * const pu)
{
	xmlNodePtr  child;
Jody Goldberg's avatar
Jody Goldberg committed
432
	char       *txt = "points";
433
	char       *tstr;
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452

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

453
	child = xmlNewChild (node, NULL, name, NULL);
454

455
	xml_set_value_points (child, "Points", pu->points);
456 457

	tstr = xmlEncodeEntitiesReentrant (node->doc, txt);
458
	xml_set_value_cstr (child, "PrefUnit", tstr);
459
	if (tstr) xmlFree (tstr);
460 461 462 463 464 465
}

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

467 468 469 470 471 472 473 474 475 476 477 478 479 480
	g_return_if_fail (pu != NULL);
	g_return_if_fail (node != 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;
481
		g_free (txt);
482 483 484
	}
}

485
static gboolean
486
xml_read_range (xmlNodePtr tree, Range *r)
487
{
488 489 490 491 492 493 494 495 496 497 498 499
	gboolean res =
	    xml_get_value_int (tree, "startCol", &r->start.col) &&
	    xml_get_value_int (tree, "startRow", &r->start.row) &&
	    xml_get_value_int (tree, "endCol",   &r->end.col) &&
	    xml_get_value_int (tree, "endRow",   &r->end.row);

	/* Add some silent sanity checking to cleanup problems
	 * with older versions of gnumeric that had some boundary problems
	 */
	range_check_sanity (r);

	return res;
500 501 502
}

static void
503
xml_write_range (xmlNodePtr tree, const Range *value)
504 505 506 507 508 509 510 511
{
	xml_set_value_int (tree, "startCol", value->start.col);
	xml_set_value_int (tree, "startRow", value->start.row);
	xml_set_value_int (tree, "endCol",   value->end.col);
	xml_set_value_int (tree, "endRow",   value->end.row);
}

static void
512
xml_read_selection_info (XmlParseContext *ctxt, Sheet *sheet, xmlNodePtr tree)
513 514 515
{
	Range r;
	int row, col;
516
	xmlNodePtr sel, selections = e_xml_get_child_by_name (tree, "Selections");
517 518 519
	if (selections == NULL)
		return;

520
	sheet_selection_reset (sheet);
521
	for (sel = selections->xmlChildrenNode; sel; sel = sel->next) {
522
		if (xml_read_range (sel, &r))
523 524 525 526
			sheet_selection_add_range (sheet,
						   r.start.col, r.start.row,
						   r.start.col, r.start.row,
						   r.end.col, r.end.row);
527 528 529 530 531 532 533 534
	}

	if (xml_get_value_int (tree, "CursorCol", &col) &&
	    xml_get_value_int (tree, "CursorRow", &row))
		sheet_cursor_set (sheet, col, row, col, row, col, row);
}

static void
535
xml_write_selection_info (XmlParseContext *ctxt, Sheet const *sheet, xmlNodePtr tree)
536 537 538 539 540 541 542 543
{
	GList *ptr, *copy;
	tree = xmlNewChild (tree, ctxt->ns, "Selections", NULL);

	/* Insert the selections in REVERSE order */
	copy = g_list_copy (sheet->selections);
	ptr = g_list_reverse (copy);
	for (; ptr != NULL ; ptr = ptr->next) {
544
		Range const *r = ptr->data;
545
		xmlNodePtr child = xmlNewChild (tree, ctxt->ns, "Selection", NULL);
546
		xml_write_range (child, r);
547 548 549
	}
	g_list_free (copy);

550 551
	xml_set_value_int (tree, "CursorCol", sheet->edit_pos.col);
	xml_set_value_int (tree, "CursorRow", sheet->edit_pos.row);
552 553
}

554 555 556 557 558 559 560 561
/*
 * 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 ...
 */
562
static int
563
xml_get_color_value (xmlNodePtr node, const char *name, StyleColor **color)
564
{
565
	char *ret;
566 567
	int red, green, blue;

568
	ret = xml_value_get (node, name);
569
	if (ret == NULL) return 0;
570
	if (sscanf (ret, "%X:%X:%X", &red, &green, &blue) == 3){
571
		*color = style_color_new (red, green, blue);
572
		g_free (ret);
573 574
		return 1;
	}
575
	g_free (ret);
576
	return 0;
577 578 579 580 581 582
}

/*
 * Set a color value for a node either carried as an attibute or as
 * the content of a child.
 */
583 584
static void
xml_set_color_value (xmlNodePtr node, const char *name, StyleColor *val)
585
{
586
	char *ret;
587
	xmlNodePtr child;
588
	char str[4 * sizeof (val->color)];
589

590
	sprintf (str, "%X:%X:%X", val->color.red, val->color.green, val->color.blue);
591 592
	ret = xmlGetProp (node, name);
	if (ret != NULL){
593
		xmlFree (ret);
594 595 596
		xmlSetProp (node, name, str);
		return;
	}
597
	child = node->xmlChildrenNode;
598 599 600 601 602 603 604 605
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
606
}
607 608 609 610 611

/**
 **
 ** Private functions : mapping between in-memory structure and XML tree
 **
612
 **/
613
#if 0
614 615
static int
style_is_default_fore (StyleColor *color)
616
{
617 618
	if (!color)
		return TRUE;
619

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

626 627
static int
style_is_default_back (StyleColor *color)
628
{
629 630
	if (!color)
		return TRUE;
631

632 633 634 635
	if (color->color.red == 0xffff && color->color.green == 0xffff && color->color.blue == 0xffff)
		return TRUE;
	else
		return FALSE;
636
}
637
#endif
638 639 640 641

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

Michael Meeks's avatar
Michael Meeks committed
643
static char *StyleSideNames[6] =
644 645 646 647
{
 	"Top",
 	"Bottom",
 	"Left",
Michael Meeks's avatar
Michael Meeks committed
648 649 650
 	"Right",
	"Diagonal",
	"Rev-Diagonal"
Arturo Espinosa's avatar
Arturo Espinosa committed
651
};
652

653
static xmlNodePtr
654
xml_write_style_border (XmlParseContext *ctxt,
655
			const MStyle *style)
656 657 658
{
	xmlNodePtr cur;
	xmlNodePtr side;
659
	int        i;
660

661
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_DIAGONAL; i++) {
Jody Goldberg's avatar
Jody Goldberg committed
662
		StyleBorder const *border;
663
		if (mstyle_is_element_set (style, i) &&
664
		    NULL != (border = mstyle_get_border (style, i))) {
Arturo Espinosa's avatar
Arturo Espinosa committed
665
			break;
666
		}
667
	}
668
	if (i > MSTYLE_BORDER_DIAGONAL)
Arturo Espinosa's avatar
Arturo Espinosa committed
669
		return NULL;
670

671
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "StyleBorder", NULL);
672

673
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_DIAGONAL; i++) {
Jody Goldberg's avatar
Jody Goldberg committed
674
		StyleBorder const *border;
Jody Goldberg's avatar
Jody Goldberg committed
675
		if (mstyle_is_element_set (style, i) &&
676
		    NULL != (border = mstyle_get_border (style, i))) {
Jody Goldberg's avatar
Jody Goldberg committed
677 678
			StyleBorderType t = border->line_type;
			StyleColor *col   = border->color;
679 680
 			side = xmlNewChild (cur, ctxt->ns,
					    StyleSideNames [i - MSTYLE_BORDER_TOP],
681 682
 					    NULL);
			xml_set_value_int (side, "Style", t);
683 684
			if (t != STYLE_BORDER_NONE)
				xml_set_color_value (side, "Color", col);
685
 		}
686 687
	}
	return cur;
688 689 690 691 692
}

/*
 * Create a StyleBorder equivalent to the XML subtree of doc.
 */
693
static void
694
xml_read_style_border (XmlParseContext *ctxt, xmlNodePtr tree, MStyle *mstyle)
695 696
{
	xmlNodePtr side;
697
	int        i;
698 699 700

	if (strcmp (tree->name, "StyleBorder")){
		fprintf (stderr,
701
			 "xml_read_style_border: invalid element type %s, 'StyleBorder' expected`\n",
702 703
			 tree->name);
	}
704

705
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_DIAGONAL; i++) {
706
 		if ((side = e_xml_get_child_by_name (tree,
707
					      StyleSideNames [i - MSTYLE_BORDER_TOP])) != NULL) {
708 709
			int		 t;
			StyleColor      *color = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
710
			StyleBorder    *border;
711
			xml_get_value_int (side, "Style", &t);
712 713
			if (t != STYLE_BORDER_NONE)
				xml_get_color_value (side, "Color", &color);
714
			border = style_border_fetch ((StyleBorderType)t, color,
Michael Meeks's avatar
Michael Meeks committed
715
						     style_border_get_orientation (i));
716
			mstyle_set_border (mstyle, i, border);
717
 		}
718
	}
719 720 721 722 723
}

/*
 * Create an XML subtree of doc equivalent to the given Style.
 */
724
xmlNodePtr
725
xml_write_style (XmlParseContext *ctxt,
726
		 MStyle *style)
727
{
728
	xmlNodePtr  cur, child;
729
	char       *tstr;
730

731
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Style", NULL);
732

733 734 735 736
	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));
737 738
	if (mstyle_is_element_set (style, MSTYLE_WRAP_TEXT))
		xml_set_value_int (cur, "WrapText", mstyle_get_wrap_text (style));
739 740 741 742
	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));
Jody Goldberg's avatar
Jody Goldberg committed
743 744
	if (mstyle_is_element_set (style, MSTYLE_INDENT))
		xml_set_value_int (cur, "Indent", mstyle_get_indent (style));
745 746

	if (mstyle_is_element_set (style, MSTYLE_COLOR_FORE)) {
747
/*		if (!style_is_default_fore (mstyle_get_color (style, MSTYLE_COLOR_FORE)))*/
748 749 750
			xml_set_color_value (cur, "Fore", mstyle_get_color (style, MSTYLE_COLOR_FORE));
	}
	if (mstyle_is_element_set (style, MSTYLE_COLOR_BACK)) {
751
/*		if (!style_is_default_back (mstyle_get_color (style, MSTYLE_COLOR_BACK)))*/
752 753
			xml_set_color_value (cur, "Back", mstyle_get_color (style, MSTYLE_COLOR_BACK));
	}
754
	if (mstyle_is_element_set (style, MSTYLE_COLOR_PATTERN)) {
755
/*		if (!style_is_default_back (mstyle_get_color (style, MSTYLE_COLOR_PATTERN)))*/
756 757
			xml_set_color_value (cur, "PatternColor", mstyle_get_color (style, MSTYLE_COLOR_PATTERN));
	}
Jody Goldberg's avatar
Jody Goldberg committed
758 759
	if (mstyle_is_element_set (style, MSTYLE_FORMAT)) {
		char *fmt = style_format_as_XL (mstyle_get_format (style), FALSE);
760
		xml_set_value_cstr (cur, "Format", fmt);
Jody Goldberg's avatar
Jody Goldberg committed
761 762
		g_free (fmt);
	}
763 764

	if (mstyle_is_element_set (style, MSTYLE_FONT_NAME) ||
765
	    mstyle_is_element_set (style, MSTYLE_FONT_SIZE) ||
766 767
	    mstyle_is_element_set (style, MSTYLE_FONT_BOLD) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_ITALIC) ||
768 769
	    mstyle_is_element_set (style, MSTYLE_FONT_UNDERLINE) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_STRIKETHROUGH)) {
770 771 772 773 774 775
		const char *fontname;

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

777 778 779 780
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, fontname);
		child = xmlNewChild (cur, ctxt->ns, "Font", tstr);
		if (tstr) xmlFree (tstr);

781
		if (mstyle_is_element_set (style, MSTYLE_FONT_SIZE))
782
			xml_set_value_points (child, "Unit",
783 784 785 786 787 788 789
					      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));
Jody Goldberg's avatar
Jody Goldberg committed
790 791 792
		if (mstyle_is_element_set (style, MSTYLE_FONT_UNDERLINE))
			xml_set_value_int (child, "Underline",
					   (int)mstyle_get_font_uline (style));
793 794 795
		if (mstyle_is_element_set (style, MSTYLE_FONT_STRIKETHROUGH))
			xml_set_value_int (child, "StrikeThrough",
					   mstyle_get_font_strike (style));
796 797 798 799 800
	}

	child = xml_write_style_border (ctxt, style);
	if (child)
		xmlAddChild (cur, child);
801 802

	return cur;
803 804
}

805
static xmlNodePtr
806
xml_write_names (XmlParseContext *ctxt, GList *names)
807
{
808
	xmlNodePtr  cur;
809
	char       *tstr;
810

811 812 813 814
#if 0  /* Don't return, We need to have a names node in the worksheet
	   * all the time becasue xml_search_child looks for a node down the
	   * tree and it will find the first "Names" node in the sheet #1
	   */
815 816
	if (!names)
		return NULL;
817
#endif
818 819 820 821 822

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

	while (names) {
		xmlNodePtr   tmp;
823
		NamedExpression    *expr_name = names->data;
824 825 826 827 828
		char        *text;

		g_return_val_if_fail (expr_name != NULL, NULL);

		tmp = xmlNewDocNode (ctxt->doc, ctxt->ns, "Name", NULL);
829 830 831
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, expr_name->name->str);
		xmlNewChild (tmp, ctxt->ns, "name", tstr);
		if (tstr) xmlFree (tstr);
832 833

		text = expr_name_value (expr_name);
834 835 836
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
		xmlNewChild (tmp, ctxt->ns, "value", tstr);
		if (tstr) xmlFree (tstr);
837 838 839 840 841
		g_free (text);

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

843 844 845 846
	return cur;
}

static void
847
xml_read_names (XmlParseContext *ctxt, xmlNodePtr tree, Workbook *wb,
848
		Sheet *sheet)
849 850 851 852 853 854
{
	xmlNodePtr child;

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

855
	child = tree->xmlChildrenNode;
856
	while (child) {
857
		char *name  = NULL;
858 859 860
		if (child->name && !strcmp (child->name, "Name")) {
			xmlNodePtr bits;

861
			bits = child->xmlChildrenNode;
862
			while (bits) {
863

864 865 866 867 868 869 870 871 872 873 874
				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"));

875
					if (!expr_name_create (wb, sheet, name, txt, &error))
876 877
						g_warning (error);

Daniel Veillard's avatar
Daniel Veillard committed
878
					xmlFree (txt);
879
				}
880
				bits = bits->next;
881 882 883 884 885 886
			}
		}
		child = child->next;
	}
}

887
static xmlNodePtr
888
xml_write_summary (XmlParseContext *ctxt, SummaryInfo *summary_info)
889 890
{
	GList *items, *m;
891
	char *tstr;
892 893
	xmlNodePtr cur;

894
	if (!summary_info)
895 896
		return NULL;

897
	m = items = summary_info_as_list (summary_info);
898 899 900 901 902 903 904 905 906 907 908 909 910

	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);
911 912 913
			tstr = xmlEncodeEntitiesReentrant (ctxt->doc, sit->name);
			xmlNewChild (tmp, ctxt->ns, "name", tstr);
			if (tstr) xmlFree (tstr);
914 915 916

			if (sit->type == SUMMARY_INT) {
				text = g_strdup_printf ("%d", sit->v.i);
917 918 919
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
				xmlNewChild (tmp, ctxt->ns, "val-int", tstr);
				if (tstr) xmlFree (tstr);
920 921
			} else {
				text = summary_item_as_text (sit);
922 923 924
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
				xmlNewChild (tmp, ctxt->ns, "val-string", tstr);
				if (tstr) xmlFree (tstr);
925 926
			}
			g_free (text);
927
			xmlAddChild (cur, tmp);
928 929 930 931 932 933 934 935
		}
		items = g_list_next (items);
	}
	g_list_free (m);
	return cur;
}

static void
936
xml_read_summary (XmlParseContext *ctxt, xmlNodePtr tree, SummaryInfo *summary_info)
937
{
938
	xmlNodePtr child;
939

940 941 942
	g_return_if_fail (ctxt != NULL);
	g_return_if_fail (tree != NULL);
	g_return_if_fail (summary_info != NULL);
943

944
	child = tree->xmlChildrenNode;
945
	while (child) {
946
		char *name = NULL;
Miguel de Icaza's avatar
Miguel de Icaza committed
947

948 949 950
		if (child->name && !strcmp (child->name, "Item")) {
			xmlNodePtr bits;

951
			bits = child->xmlChildrenNode;
952 953
			while (bits) {
				SummaryItem *sit = NULL;
954

955
				if (!strcmp (bits->name, "name")) {
956
					name = xmlNodeGetContent (bits);
957 958 959 960 961
				} else {
					char *txt;
					g_return_if_fail (name);

					txt = xmlNodeGetContent (bits);
962 963 964 965
					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
966
							sit = summary_item_new_int (name, atoi (txt));
967

968
						if (sit)
969
							summary_info_add (summary_info, sit);
Daniel Veillard's avatar
Daniel Veillard committed
970
						xmlFree (txt);
971
					}
972
				}
973
				bits = bits->next;
974 975
			}
		}
Miguel de Icaza's avatar
Miguel de Icaza committed
976
		if (name){
977
			xmlFree (name);
Miguel de Icaza's avatar
Miguel de Icaza committed
978 979
			name = NULL;
		}
980 981 982 983
		child = child->next;
	}
}

Michael Meeks's avatar
Michael Meeks committed
984 985 986 987 988 989 990 991 992 993
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);
994 995 996
	xml_set_value_cstr (child, "Left", hf->left_format);
	xml_set_value_cstr (child, "Middle", hf->middle_format);
	xml_set_value_cstr (child, "Right", hf->right_format);
Michael Meeks's avatar
Michael Meeks committed
997 998 999
}

static void
Arturo Espinosa's avatar
Arturo Espinosa committed
1000
xml_get_print_hf (xmlNodePtr node, PrintHF *const hf)
Michael Meeks's avatar
Michael Meeks committed
1001 1002
{
	char *txt;
1003

Michael Meeks's avatar
Michael Meeks committed
1004 1005 1006 1007
	g_return_if_fail (hf != NULL);
	g_return_if_fail (node != NULL);

	txt = xml_value_get (node, "Left");
1008
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
1009 1010
		if (hf->left_format)
			g_free (hf->left_format);
1011
		hf->left_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
1012
	}
1013

Michael Meeks's avatar
Michael Meeks committed
1014
	txt = xml_value_get (node, "Middle");
1015
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
1016 1017
		if (hf->middle_format)
			g_free (hf->middle_format);