xml-io.c 82.1 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 "value.h"
33
#include "sheet-merge.h"
34 35 36
#include "io-context.h"
#include "command-context.h"
#include "workbook-control.h"
37
#include "workbook-view.h"
38
#include "workbook.h"
39
#include "selection.h"
40
#include "clipboard.h"
Jody Goldberg's avatar
Jody Goldberg committed
41
#include "format.h"
Jody Goldberg's avatar
Jody Goldberg committed
42
#include "ranges.h"
Chyla Zbigniew's avatar
Chyla Zbigniew committed
43
#include "file.h"
44

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return NULL;
214 215
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

486
static gboolean
487
xml_read_range (xmlNodePtr tree, Range *r)
488
{
489 490 491 492 493 494 495 496 497 498 499 500
	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;
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 531 532 533 534 535
	}

	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
536
xml_write_selection_info (XmlParseContext *ctxt, Sheet const *sheet, xmlNodePtr tree)
537 538 539 540 541 542 543 544
{
	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) {
545
		Range const *r = ptr->data;
546
		xmlNodePtr child = xmlNewChild (tree, ctxt->ns, "Selection", NULL);
547
		xml_write_range (child, r);
548 549 550
	}
	g_list_free (copy);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return cur;
804 805
}

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

812 813 814 815
#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
	   */
816 817
	if (!names)
		return NULL;
818
#endif
819 820 821 822 823

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

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

		g_return_val_if_fail (expr_name != NULL, NULL);

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

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

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

844 845 846 847
	return cur;
}

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

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

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

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

865 866 867
				if (!strcmp (bits->name, "name")) {
					name = xmlNodeGetContent (bits);
				} else {
868
					char     *txt;
869
					ParseError  perr;
870 871 872 873 874 875
					g_return_if_fail (name != NULL);

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

876 877 878
					if (!expr_name_create (wb, sheet, name, txt, &perr))
						g_warning (perr.message);
					parse_error_free (&perr);
879

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

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

896
	if (!summary_info)
897 898
		return NULL;

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

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

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

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

942 943 944
	g_return_if_fail (ctxt != NULL);
	g_return_if_fail (tree != NULL);
	g_return_if_fail (summary_info != NULL);
945

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

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

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

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

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

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

Michael Meeks's avatar
Michael Meeks committed
986 987 988 989 990 991 992 993 994 995
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);
996 997 998
	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
999 1000 1001
}

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

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

	txt = xml_value_get (node, "Left");