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

#include <gal/util/e-xml-utils.h>
#include <gnome.h>
#include <locale.h>
#include <math.h>
#include <limits.h>
46

47 48 49
/* Precision to use when saving point measures. */
#define POINT_SIZE_PRECISION 3

50 51
static GnumFileOpener *xml_opener = NULL;
static GnumFileSaver  *xml_saver = NULL;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
52

53
GnumFileOpener *
54
gnumeric_xml_get_opener (void)
Chyla Zbigniew's avatar
Chyla Zbigniew committed
55
{
56
	return xml_opener;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
57 58
}

59
GnumFileSaver *
60
gnumeric_xml_get_saver (void)
Chyla Zbigniew's avatar
Chyla Zbigniew committed
61
{
62
	return xml_saver;
Chyla Zbigniew's avatar
Chyla Zbigniew committed
63 64
}

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

Michael Meeks's avatar
Michael Meeks committed
75
	ctxt->version   = version;
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
	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
91
	return xml_parse_ctx_new_full (
Jody Goldberg's avatar
Jody Goldberg committed
92
		doc, ns, GNUM_XML_V6, NULL, NULL, NULL);
93
}
94

95 96 97 98 99 100 101 102
void
xml_parse_ctx_destroy (XmlParseContext *ctxt)
{
	g_return_if_fail (ctxt != NULL);

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

104 105 106
/*
 * Internal stuff: xml helper functions.
 */
107

108 109 110 111
static void
xml_arg_set (GtkArg *arg, gchar *string)
{
	switch (arg->type) {
JP Rosevear's avatar
JP Rosevear committed
112 113 114 115 116 117 118
	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
119
		if (!strcmp (string, "TRUE"))
JP Rosevear's avatar
JP Rosevear committed
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
			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;
145 146 147 148 149 150 151
	}
}

static char *
xml_arg_get (GtkArg *arg)
{
	switch (arg->type) {
JP Rosevear's avatar
JP Rosevear committed
152 153 154 155 156 157 158 159 160 161 162 163 164 165
	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
166
		return g_strdup_printf("%li", GTK_VALUE_LONG (*arg));
JP Rosevear's avatar
JP Rosevear committed
167
	case GTK_TYPE_ULONG:
Jon Kåre Hellan's avatar
Jon Kåre Hellan committed
168
		return g_strdup_printf("%lu", GTK_VALUE_ULONG (*arg));
JP Rosevear's avatar
JP Rosevear committed
169 170 171 172 173 174
	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));
175 176 177 178
	}

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

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

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

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

	return NULL;
216 217
}

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

228 229 230 231 232
	val = xml_value_get (node, name);
	if (val == NULL) return NULL;
        ret = string_get (val);
	g_free (val);
	return ret;
233 234
}

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

246
	ret = xml_value_get (node, name);
247
	if (ret == NULL) return 0;
248
	res = sscanf (ret, "%d", &i);
249 250
	g_free (ret);

251 252
	if (res == 1) {
	        *val = i;
253
		return TRUE;
254
	}
255
	return FALSE;
256 257
}

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

270
	ret = xml_value_get (node, name);
271
	if (ret == NULL) return 0;
272
	res = sscanf (ret, "%f", &f);
273 274
	g_free (ret);

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

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

293
	ret = xml_value_get (node, name);
294
	if (ret == NULL) return 0;
295
	res = sscanf (ret, "%lf", val);
296
	g_free (ret);
297

298
	return (res == 1);
299 300 301 302 303 304
}

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

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

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

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

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

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

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

396 397
	if (precision < 0 || precision > DBL_DIG)
		precision = DBL_DIG;
398

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

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

421 422 423 424 425 426 427 428 429
/*
 * 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);
}

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

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

456
	child = xmlNewChild (node, NULL, name, NULL);
457

458
	xml_set_value_points (child, "Points", pu->points);
459 460

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

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

470 471 472 473 474 475 476 477
	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
478
		else if (!strcmp (txt, "mm"))
479
			pu->desired_display = UNIT_MILLIMETER;
Jody Goldberg's avatar
Doh!  
Jody Goldberg committed
480
		else if (!strcmp (txt, "cm"))
481
			pu->desired_display = UNIT_CENTIMETER;
Jody Goldberg's avatar
Doh!  
Jody Goldberg committed
482
		else if (!strcmp (txt, "in"))
483
			pu->desired_display = UNIT_INCH;
484
		g_free (txt);
485 486 487
	}
}

488
static gboolean
489
xml_read_range (xmlNodePtr tree, Range *r)
490
{
491 492 493 494 495 496
	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);

497 498
	/* Older versions of gnumeric had some boundary problems */
	range_ensure_sanity (r);
499 500

	return res;
501 502 503
}

static void
504
xml_write_range (xmlNodePtr tree, const Range *value)
505 506 507 508 509 510 511 512
{
	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
513
xml_read_selection_info (XmlParseContext *ctxt, Sheet *sheet, xmlNodePtr tree)
514 515 516
{
	Range r;
	int row, col;
517
	xmlNodePtr sel, selections = e_xml_get_child_by_name (tree, "Selections");
518 519 520
	if (selections == NULL)
		return;

521
	sheet_selection_reset (sheet);
522
	for (sel = selections->xmlChildrenNode; sel; sel = sel->next)
523
		if (xml_read_range (sel, &r))
524 525 526 527
			sheet_selection_add_range (sheet,
						   r.start.col, r.start.row,
						   r.start.col, r.start.row,
						   r.end.col, r.end.row);
528

529 530
	if (xml_get_value_int (selections, "CursorCol", &col) &&
	    xml_get_value_int (selections, "CursorRow", &row))
531
		sheet_set_edit_pos (sheet, col, row);
532 533 534
}

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_real.col);
	xml_set_value_int (tree, "CursorRow", sheet->edit_pos_real.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