xml-io.c 85.6 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>
Jody Goldberg's avatar
Jody Goldberg committed
10
#include "xml-io.h"
11
#include "style-color.h"
12
#include "style-border.h"
13
#include "style.h"
Jody Goldberg's avatar
Jody Goldberg committed
14 15
#include "sheet.h"
#include "sheet-style.h"
16
#include "sheet-object.h"
17
#include "sheet-object-cell-comment.h"
18
#include "print-info.h"
19
#include "file.h"
20
#include "expr.h"
21
#include "expr-name.h"
22
#include "cell.h"
23
#include "value.h"
24
#include "sheet-merge.h"
25 26 27
#include "io-context.h"
#include "command-context.h"
#include "workbook-control.h"
28
#include "workbook-view.h"
29
#include "workbook.h"
30
#include "selection.h"
31
#include "clipboard.h"
Jody Goldberg's avatar
Jody Goldberg committed
32
#include "format.h"
Jody Goldberg's avatar
Jody Goldberg committed
33
#include "ranges.h"
Chyla Zbigniew's avatar
Chyla Zbigniew committed
34
#include "file.h"
Jody Goldberg's avatar
Jody Goldberg committed
35
#include "str.h"
36
#include "plugin-util.h"
Jody Goldberg's avatar
Jody Goldberg committed
37

Jody Goldberg's avatar
Jody Goldberg committed
38 39 40
#include <gnome-xml/parser.h>
#include <gnome-xml/parserInternals.h>
#include <gnome-xml/xmlmemory.h>
41 42 43
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
44
#include <errno.h>
45
#include <zlib.h>
Jody Goldberg's avatar
Jody Goldberg committed
46 47 48 49 50
#include <gal/util/e-xml-utils.h>
#include <gnome.h>
#include <locale.h>
#include <math.h>
#include <limits.h>
51

52 53 54
/* Precision to use when saving point measures. */
#define POINT_SIZE_PRECISION 3

55
/* FIXME - tune the values below */
56 57
#define XML_INPUT_BUFFER_SIZE      4096
#define N_ELEMENTS_BETWEEN_UPDATES 20
58

59 60
static GnumFileOpener *xml_opener = NULL;
static GnumFileSaver  *xml_saver = NULL;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
61

62
GnumFileOpener *
63
gnumeric_xml_get_opener (void)
Chyla Zbigniew's avatar
Chyla Zbigniew committed
64
{
65
	return xml_opener;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
66 67
}

68
GnumFileSaver *
69
gnumeric_xml_get_saver (void)
Chyla Zbigniew's avatar
Chyla Zbigniew committed
70
{
71
	return xml_saver;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
72 73
}

74 75 76
XmlParseContext *
xml_parse_ctx_new_full (xmlDocPtr             doc,
			xmlNsPtr              ns,
Michael Meeks's avatar
Michael Meeks committed
77
			GnumericXMLVersion    version,
78 79 80 81 82 83
			XmlSheetObjectReadFn  read_fn,
			XmlSheetObjectWriteFn write_fn,
			gpointer              user_data)
{
	XmlParseContext *ctxt = g_new0 (XmlParseContext, 1);

Michael Meeks's avatar
Michael Meeks committed
84
	ctxt->version   = version;
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
	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
100
	return xml_parse_ctx_new_full (
Jody Goldberg's avatar
Jody Goldberg committed
101
		doc, ns, GNUM_XML_V6, NULL, NULL, NULL);
102
}
103

104 105 106 107 108 109 110 111
void
xml_parse_ctx_destroy (XmlParseContext *ctxt)
{
	g_return_if_fail (ctxt != NULL);

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

113 114 115
/*
 * Internal stuff: xml helper functions.
 */
116

117 118 119 120
static void
xml_arg_set (GtkArg *arg, gchar *string)
{
	switch (arg->type) {
JP Rosevear's avatar
JP Rosevear committed
121 122 123 124 125 126 127
	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
128
		if (!strcmp (string, "TRUE"))
JP Rosevear's avatar
JP Rosevear committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
			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;
154 155 156 157 158 159 160
	}
}

static char *
xml_arg_get (GtkArg *arg)
{
	switch (arg->type) {
JP Rosevear's avatar
JP Rosevear committed
161 162 163 164 165 166 167 168 169 170 171 172 173 174
	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
175
		return g_strdup_printf("%li", GTK_VALUE_LONG (*arg));
JP Rosevear's avatar
JP Rosevear committed
176
	case GTK_TYPE_ULONG:
Jon Kåre Hellan's avatar
Jon Kåre Hellan committed
177
		return g_strdup_printf("%lu", GTK_VALUE_ULONG (*arg));
JP Rosevear's avatar
JP Rosevear committed
178 179 180 181 182 183
	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));
184 185 186 187
	}

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

189 190 191
/*
 * Get a value for a node either carried as an attibute or as
 * the content of a child.
192 193
 *
 * Returns a g_malloc'ed string.  Caller must free.
194
 */
195
static char *
196
xml_value_get (xmlNodePtr node, const char *name)
197
{
198
	char *ret, *val;
199 200
	xmlNodePtr child;

201 202 203 204
	val = (char *) xmlGetProp (node, name);
	if (val != NULL) {
		ret = g_strdup (val);
		xmlFree (val);
Morten Welinder's avatar
Morten Welinder committed
205
		return ret;
206
	}
207
	child = node->xmlChildrenNode;
208 209

	while (child != NULL) {
210 211 212 213
		if (!strcmp (child->name, name)) {
		        /*
			 * !!! Inefficient, but ...
			 */
214 215 216 217 218 219
			val = xmlNodeGetContent(child);
			if (val != NULL) {
				ret = g_strdup (val);
				xmlFree (val);
				return ret;
			}
220
		}
221 222 223 224
		child = child->next;
	}

	return NULL;
225 226
}

227 228 229 230
/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
231
String *
232
xml_get_value_string (xmlNodePtr node, const char *name)
233
{
234
	char *val;
235 236
	String *ret;

237 238 239 240 241
	val = xml_value_get (node, name);
	if (val == NULL) return NULL;
        ret = string_get (val);
	g_free (val);
	return ret;
242 243
}

244 245 246 247
/*
 * Get an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
248
gboolean
249
xml_get_value_int (xmlNodePtr node, const char *name, int *val)
250
{
251
	char *ret;
252
	int i;
253
	int res;
254

255
	ret = xml_value_get (node, name);
256
	if (ret == NULL) return 0;
257
	res = sscanf (ret, "%d", &i);
258 259
	g_free (ret);

260 261
	if (res == 1) {
	        *val = i;
262
		return TRUE;
263
	}
264
	return FALSE;
265 266
}

267
#if 0
268 269 270 271
/*
 * Get a float value for a node either carried as an attibute or as
 * the content of a child.
 */
272
static int
273
xml_get_value_float (xmlNodePtr node, const char *name, float *val)
274
{
275 276
	int res;
	char *ret;
277 278
	float f;

279
	ret = xml_value_get (node, name);
280
	if (ret == NULL) return 0;
281
	res = sscanf (ret, "%f", &f);
282 283
	g_free (ret);

284 285
	if (res == 1) {
	        *val = f;
286 287 288
		return 1;
	}
	return 0;
289
}
290
#endif
291 292 293 294 295

/*
 * Get a double value for a node either carried as an attibute or as
 * the content of a child.
 */
296
static int
297
xml_get_value_double (xmlNodePtr node, const char *name, double *val)
298
{
299 300
	int res;
	char *ret;
301

302
	ret = xml_value_get (node, name);
303
	if (ret == NULL) return 0;
304
	res = sscanf (ret, "%lf", val);
305
	g_free (ret);
306

307
	return (res == 1);
308 309 310 311 312 313
}

/*
 * Set a string value for a node either carried as an attibute or as
 * the content of a child.
 */
314 315
void
xml_set_value_cstr (xmlNodePtr node, const char *name, const char *val)
316
{
317
	char *ret;
318 319 320 321
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
	if (ret != NULL){
322
		xmlFree (ret);
323 324 325
		xmlSetProp (node, name, val);
		return;
	}
326
	child = node->xmlChildrenNode;
327 328 329 330 331 332 333 334
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, val);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, val);
335 336
}

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

	ret = xmlGetProp (node, name);
348
	if (ret != NULL) {
349
		xmlFree (ret);
350 351 352
		xmlSetProp (node, name, val->str);
		return;
	}
353
	child = node->xmlChildrenNode;
354 355 356 357 358 359 360 361
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, val->str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, val->str);
362 363
}

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

375
	sprintf (str, "%d", val);
376 377
	ret = xmlGetProp (node, name);
	if (ret != NULL){
378
		xmlFree (ret);
379 380 381
		xmlSetProp (node, name, str);
		return;
	}
382
	child = node->xmlChildrenNode;
383 384 385 386 387 388 389 390
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
391 392 393 394 395 396
}

/*
 * Set a double value for a node either carried as an attibute or as
 * the content of a child.
 */
397
static void
398 399
xml_set_value_double (xmlNodePtr node, const char *name, double val,
		      int precision)
400
{
401
	char *ret;
402
	xmlNodePtr child;
403
	char str[101 + DBL_DIG];
404

405 406
	if (precision < 0 || precision > DBL_DIG)
		precision = DBL_DIG;
407

408
	if (fabs (val) < 1e9 && fabs (val) > 1e-5)
409
		snprintf (str, 100 + DBL_DIG, "%.*g", precision, val);
410 411
	else
		snprintf (str, 100 + DBL_DIG, "%f", val);
412

413 414
	ret = xmlGetProp (node, name);
	if (ret != NULL){
415
		xmlFree (ret);
416 417 418
		xmlSetProp (node, name, str);
		return;
	}
419
	child = node->xmlChildrenNode;
420 421 422 423 424 425 426 427
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
428 429
}

430 431 432 433 434 435 436 437 438
/*
 * 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);
}

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
	child = xmlNewChild (node, NULL, name, NULL);
466

467
	xml_set_value_points (child, "Points", pu->points);
468 469

	tstr = xmlEncodeEntitiesReentrant (node->doc, txt);
470
	xml_set_value_cstr (child, "PrefUnit", tstr);
471
	if (tstr) xmlFree (tstr);
472 473 474 475 476 477
}

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

479 480 481 482 483 484 485 486
	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;
Jody Goldberg's avatar
Doh!  
Jody Goldberg committed
487
		else if (!strcmp (txt, "mm"))
488
			pu->desired_display = UNIT_MILLIMETER;
Jody Goldberg's avatar
Doh!  
Jody Goldberg committed
489
		else if (!strcmp (txt, "cm"))
490
			pu->desired_display = UNIT_CENTIMETER;
Jody Goldberg's avatar
Doh!  
Jody Goldberg committed
491
		else if (!strcmp (txt, "in"))
492
			pu->desired_display = UNIT_INCH;
493
		g_free (txt);
494 495 496
	}
}

497
static gboolean
498
xml_read_range (xmlNodePtr tree, Range *r)
499
{
500 501 502 503 504 505
	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);

506 507
	/* Older versions of gnumeric had some boundary problems */
	range_ensure_sanity (r);
508 509

	return res;
510 511 512
}

static void
Jody Goldberg's avatar
Jody Goldberg committed
513
xml_write_range (xmlNodePtr tree, Range const *r)
514
{
Jody Goldberg's avatar
Jody Goldberg committed
515 516 517 518 519 520
	g_return_if_fail (range_is_sane (r));

	xml_set_value_int (tree, "startCol", r->start.col);
	xml_set_value_int (tree, "startRow", r->start.row);
	xml_set_value_int (tree, "endCol",   r->end.col);
	xml_set_value_int (tree, "endRow",   r->end.row);
521 522 523
}

static void
524
xml_read_selection_info (XmlParseContext *ctxt, Sheet *sheet, xmlNodePtr tree)
525 526 527
{
	Range r;
	int row, col;
528
	xmlNodePtr sel, selections = e_xml_get_child_by_name (tree, "Selections");
529 530 531
	if (selections == NULL)
		return;

532
	sheet_selection_reset (sheet);
533
	for (sel = selections->xmlChildrenNode; sel; sel = sel->next)
534
		if (xml_read_range (sel, &r))
535 536 537 538
			sheet_selection_add_range (sheet,
						   r.start.col, r.start.row,
						   r.start.col, r.start.row,
						   r.end.col, r.end.row);
539

540 541
	if (xml_get_value_int (selections, "CursorCol", &col) &&
	    xml_get_value_int (selections, "CursorRow", &row))
542
		sheet_set_edit_pos (sheet, col, row);
543 544 545
}

static void
546
xml_write_selection_info (XmlParseContext *ctxt, Sheet const *sheet, xmlNodePtr tree)
547 548 549 550 551 552 553 554
{
	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) {
555
		Range const *r = ptr->data;
556
		xmlNodePtr child = xmlNewChild (tree, ctxt->ns, "Selection", NULL);
557
		xml_write_range (child, r);
558 559 560
	}
	g_list_free (copy);

561 562
	xml_set_value_int (tree, "CursorCol", sheet->edit_pos_real.col);
	xml_set_value_int (tree, "CursorRow", sheet->edit_pos_real.row);
563 564
}

565 566 567 568 569 570 571 572
/*
 * 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 ...
 */
573
static int
574
xml_get_color_value (xmlNodePtr node, const char *name, StyleColor **color)
575
{
576
	char *ret;
577 578
	int red, green, blue;

579
	ret = xml_value_get (node, name);
580
	if (ret == NULL) return 0;
581
	if (sscanf (ret, "%X:%X:%X", &red, &green, &blue) == 3){
582
		*color = style_color_new (red, green, blue);
583
		g_free (ret);
584 585
		return 1;
	}
586
	g_free (ret);
587
	return 0;
588 589 590 591 592 593
}

/*
 * Set a color value for a node either carried as an attibute or as
 * the content of a child.
 */
594 595
static void
xml_set_color_value (xmlNodePtr node, const char *name, StyleColor *val)
596
{
597
	char *ret;
598
	xmlNodePtr child;
599
	char str[4 * sizeof (val->color)];
600

601
	sprintf (str, "%X:%X:%X", val->color.red, val->color.green, val->color.blue);
602 603
	ret = xmlGetProp (node, name);
	if (ret != NULL){
604
		xmlFree (ret);
605 606 607
		xmlSetProp (node, name, str);
		return;
	}
608
	child = node->xmlChildrenNode;
609 610 611 612 613 614 615 616
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
617
}
618 619 620 621 622

/**
 **
 ** Private functions : mapping between in-memory structure and XML tree
 **
623
 **/
624
#if 0
625 626
static int
style_is_default_fore (StyleColor *color)
627
{
628 629
	if (!color)
		return TRUE;
630

631 632 633 634
	if (color->color.red == 0 && color->color.green == 0 && color->color.blue == 0)
		return TRUE;
	else
		return FALSE;
635 636
}

637 638
static int
style_is_default_back (StyleColor *color)
639
{
640 641
	if (!color)
		return TRUE;
642

643 644 645 646
	if (color->color.red == 0xffff && color->color.green == 0xffff && color->color.blue == 0xffff)
		return TRUE;
	else
		return FALSE;
647
}
648
#endif
649 650 651 652

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

Michael Meeks's avatar
Michael Meeks committed
654
static char *StyleSideNames[6] =
655 656 657 658
{
 	"Top",
 	"Bottom",
 	"Left",
Michael Meeks's avatar
Michael Meeks committed
659 660 661
 	"Right",
	"Diagonal",
	"Rev-Diagonal"
Arturo Espinosa's avatar
Arturo Espinosa committed
662
};
663

664
static xmlNodePtr
665
xml_write_style_border (XmlParseContext *ctxt,
666
			const MStyle *style)
667 668 669
{
	xmlNodePtr cur;
	xmlNodePtr side;
670
	int        i;
671

672
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_DIAGONAL; i++) {
Jody Goldberg's avatar
Jody Goldberg committed
673
		StyleBorder const *border;
674
		if (mstyle_is_element_set (style, i) &&
675
		    NULL != (border = mstyle_get_border (style, i))) {
Arturo Espinosa's avatar
Arturo Espinosa committed
676
			break;
677
		}
678
	}
679
	if (i > MSTYLE_BORDER_DIAGONAL)
Arturo Espinosa's avatar
Arturo Espinosa committed
680
		return NULL;
681

682
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "StyleBorder", NULL);
683

684
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_DIAGONAL; i++) {
Jody Goldberg's avatar
Jody Goldberg committed
685
		StyleBorder const *border;
Jody Goldberg's avatar
Jody Goldberg committed
686
		if (mstyle_is_element_set (style, i) &&
687
		    NULL != (border = mstyle_get_border (style, i))) {
Jody Goldberg's avatar
Jody Goldberg committed
688 689
			StyleBorderType t = border->line_type;
			StyleColor *col   = border->color;
690 691
 			side = xmlNewChild (cur, ctxt->ns,
					    StyleSideNames [i - MSTYLE_BORDER_TOP],
692 693
 					    NULL);
			xml_set_value_int (side, "Style", t);
694 695
			if (t != STYLE_BORDER_NONE)
				xml_set_color_value (side, "Color", col);
696
 		}
697 698
	}
	return cur;
699 700 701 702 703
}

/*
 * Create a StyleBorder equivalent to the XML subtree of doc.
 */
704
static void
705
xml_read_style_border (XmlParseContext *ctxt, xmlNodePtr tree, MStyle *mstyle)
706 707
{
	xmlNodePtr side;
708
	int        i;
709 710 711

	if (strcmp (tree->name, "StyleBorder")){
		fprintf (stderr,
712
			 "xml_read_style_border: invalid element type %s, 'StyleBorder' expected`\n",
713 714
			 tree->name);
	}
715

716
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_DIAGONAL; i++) {
717
 		if ((side = e_xml_get_child_by_name (tree,
718
					      StyleSideNames [i - MSTYLE_BORDER_TOP])) != NULL) {
719 720
			int		 t;
			StyleColor      *color = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
721
			StyleBorder    *border;
722
			xml_get_value_int (side, "Style", &t);
723 724
			if (t != STYLE_BORDER_NONE)
				xml_get_color_value (side, "Color", &color);
725
			border = style_border_fetch ((StyleBorderType)t, color,
Michael Meeks's avatar
Michael Meeks committed
726
						     style_border_get_orientation (i));
727
			mstyle_set_border (mstyle, i, border);
728
 		}
729
	}
730 731 732 733 734
}

/*
 * Create an XML subtree of doc equivalent to the given Style.
 */
735
xmlNodePtr
736
xml_write_style (XmlParseContext *ctxt,
737
		 MStyle *style)
738
{
739
	xmlNodePtr  cur, child;
740
	char       *tstr;
741

742
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Style", NULL);
743

744 745 746 747
	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));
748 749
	if (mstyle_is_element_set (style, MSTYLE_WRAP_TEXT))
		xml_set_value_int (cur, "WrapText", mstyle_get_wrap_text (style));
750 751 752 753
	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
754 755
	if (mstyle_is_element_set (style, MSTYLE_INDENT))
		xml_set_value_int (cur, "Indent", mstyle_get_indent (style));
756 757

	if (mstyle_is_element_set (style, MSTYLE_COLOR_FORE)) {
758
/*		if (!style_is_default_fore (mstyle_get_color (style, MSTYLE_COLOR_FORE)))*/
759 760 761
			xml_set_color_value (cur, "Fore", mstyle_get_color (style, MSTYLE_COLOR_FORE));
	}
	if (mstyle_is_element_set (style, MSTYLE_COLOR_BACK)) {
762
/*		if (!style_is_default_back (mstyle_get_color (style, MSTYLE_COLOR_BACK)))*/
763 764
			xml_set_color_value (cur, "Back", mstyle_get_color (style, MSTYLE_COLOR_BACK));
	}
765
	if (mstyle_is_element_set (style, MSTYLE_COLOR_PATTERN)) {
766
/*		if (!style_is_default_back (mstyle_get_color (style, MSTYLE_COLOR_PATTERN)))*/
767 768
			xml_set_color_value (cur, "PatternColor", mstyle_get_color (style, MSTYLE_COLOR_PATTERN));
	}
Jody Goldberg's avatar
Jody Goldberg committed
769 770
	if (mstyle_is_element_set (style, MSTYLE_FORMAT)) {
		char *fmt = style_format_as_XL (mstyle_get_format (style), FALSE);
771
		xml_set_value_cstr (cur, "Format", fmt);
Jody Goldberg's avatar
Jody Goldberg committed
772 773
		g_free (fmt);
	}
774 775

	if (mstyle_is_element_set (style, MSTYLE_FONT_NAME) ||
776
	    mstyle_is_element_set (style, MSTYLE_FONT_SIZE) ||
777 778
	    mstyle_is_element_set (style, MSTYLE_FONT_BOLD) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_ITALIC) ||
779 780
	    mstyle_is_element_set (style, MSTYLE_FONT_UNDERLINE) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_STRIKETHROUGH)) {
781 782 783 784 785 786
		const char *fontname;

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

788 789 790 791
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, fontname);
		child = xmlNewChild (cur, ctxt->ns, "Font", tstr);
		if (tstr) xmlFree (tstr);

792
		if (mstyle_is_element_set (style, MSTYLE_FONT_SIZE))
793
			xml_set_value_points (child, "Unit",
794 795 796 797 798 799 800
					      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
801 802 803
		if (mstyle_is_element_set (style, MSTYLE_FONT_UNDERLINE))
			xml_set_value_int (child, "Underline",
					   (int)mstyle_get_font_uline (style));
804 805 806
		if (mstyle_is_element_set (style, MSTYLE_FONT_STRIKETHROUGH))
			xml_set_value_int (child, "StrikeThrough",
					   mstyle_get_font_strike (style));
807 808 809 810 811
	}

	child = xml_write_style_border (ctxt, style);
	if (child)
		xmlAddChild (cur, child);
812 813

	return cur;
814 815
}

816
static xmlNodePtr
817
xml_write_names (XmlParseContext *ctxt, GList *names)
818
{
819
	xmlNodePtr  cur;
820
	char       *tstr;
821

822 823 824 825
#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
	   */
826 827
	if (!names)
		return NULL;
828
#endif
829 830 831 832 833

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

	while (names) {
		xmlNodePtr   tmp;
834
		NamedExpression    *expr_name = names->data;
835 836 837 838 839
		char        *text;

		g_return_val_if_fail (expr_name != NULL, NULL);

		tmp = xmlNewDocNode (ctxt->doc, ctxt->ns, "Name", NULL);
840 841 842
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, expr_name->name->str);
		xmlNewChild (tmp, ctxt->ns, "name", tstr);
		if (tstr) xmlFree (tstr);
843 844

		text = expr_name_value (expr_name);
845 846 847
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
		xmlNewChild (tmp, ctxt->ns, "value", tstr);
		if (tstr) xmlFree (tstr);
848 849 850 851 852
		g_free (text);

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

854 855 856 857
	return cur;
}

static void
858
xml_read_names (XmlParseContext *ctxt, xmlNodePtr tree, Workbook *wb,
859
		Sheet *sheet)
860 861 862 863 864 865
{
	xmlNodePtr child;

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

866
	child = tree->xmlChildrenNode;
867
	while (child) {