xml-io.c 71.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
 *
8
 * $Id$
9 10 11 12 13
 */

#include <config.h>
#include <stdio.h>
#include <gnome.h>
14
#include <locale.h>
15
#include <math.h>
16
#include "gnumeric.h"
17
#include "gnome-xml/parser.h"
Daniel Veillard's avatar
Daniel Veillard committed
18
#include "gnome-xml/parserInternals.h"
19
#include "gnome-xml/xmlmemory.h"
20
#include "color.h"
21
#include "border.h"
22
#include "sheet-object.h"
23
#include "sheet-object-graphic.h"
24
#include "print-info.h"
25
#include "xml-io.h"
26
#include "file.h"
27
#include "expr.h"
28
#include "expr-name.h"
29
#include "cell.h"
30
#include "workbook.h"
31 32
#include "workbook-view.h"
#include "selection.h"
33
#include "command-context.h"
34 35 36 37

/*
 * A parsing context.
 */
38 39 40 41 42 43
typedef struct {
	xmlDocPtr doc;		/* Xml document */
	xmlNsPtr ns;		/* Main name space */
	xmlNodePtr parent;	/* used only for g_hash_table_foreach callbacks */
	Sheet *sheet;		/* the associated sheet */
	Workbook *wb;		/* the associated sheet */
44
	GHashTable *style_table;/* old style styles compatibility */
45 46
} parse_xml_context_t;

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

51 52 53 54
static void
xml_arg_set (GtkArg *arg, gchar *string)
{
	switch (arg->type) {
JP Rosevear's avatar
JP Rosevear committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
	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:
		if (!strcmp (string, "TRUE")) 
			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;
88 89 90 91 92 93 94
	}
}

static char *
xml_arg_get (GtkArg *arg)
{
	switch (arg->type) {
JP Rosevear's avatar
JP Rosevear committed
95 96 97 98 99 100 101 102 103 104 105 106 107 108
	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
109
		return g_strdup_printf("%li", GTK_VALUE_LONG (*arg));
JP Rosevear's avatar
JP Rosevear committed
110
	case GTK_TYPE_ULONG:
Jon Kåre Hellan's avatar
Jon Kåre Hellan committed
111
		return g_strdup_printf("%lu", GTK_VALUE_ULONG (*arg));
JP Rosevear's avatar
JP Rosevear committed
112 113 114 115 116 117
	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));
118 119 120 121 122
	}

	return NULL;
}
 
123 124 125
/*
 * Get a value for a node either carried as an attibute or as
 * the content of a child.
126 127
 *
 * Returns a g_malloc'ed string.  Caller must free.
128
 */
129
static char *
130
xml_value_get (xmlNodePtr node, const char *name)
131
{
132
	char *ret, *val;
133 134
	xmlNodePtr child;

135 136 137 138
	val = (char *) xmlGetProp (node, name);
	if (val != NULL) {
		ret = g_strdup (val);
		xmlFree (val);
Morten Welinder's avatar
Morten Welinder committed
139
		return ret;
140
	}
141 142 143
	child = node->childs;

	while (child != NULL) {
144 145 146 147
		if (!strcmp (child->name, name)) {
		        /*
			 * !!! Inefficient, but ...
			 */
148 149 150 151 152 153
			val = xmlNodeGetContent(child);
			if (val != NULL) {
				ret = g_strdup (val);
				xmlFree (val);
				return ret;
			}
154
		}
155 156 157 158
		child = child->next;
	}

	return NULL;
159 160
}

161 162 163 164
/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
165
static String *
166
xml_get_value_string (xmlNodePtr node, const char *name)
167
{
168
	char *val;
169 170
	String *ret;

171 172 173 174 175
	val = xml_value_get (node, name);
	if (val == NULL) return NULL;
        ret = string_get (val);
	g_free (val);
	return ret;
176 177
}

178 179 180 181
/*
 * Get an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
182
static int
183
xml_get_value_int (xmlNodePtr node, const char *name, int *val)
184
{
185
	char *ret;
186
	int i;
187
	int res;
188

189
	ret = xml_value_get (node, name);
190
	if (ret == NULL) return 0;
191
	res = sscanf (ret, "%d", &i);
192 193
	g_free (ret);

194 195
	if (res == 1) {
	        *val = i;
196 197 198
		return 1;
	}
	return 0;
199 200
}

201
#if 0
202 203 204 205
/*
 * Get a float value for a node either carried as an attibute or as
 * the content of a child.
 */
206
static int
207
xml_get_value_float (xmlNodePtr node, const char *name, float *val)
208
{
209 210
	int res;
	char *ret;
211 212
	float f;

213
	ret = xml_value_get (node, name);
214
	if (ret == NULL) return 0;
215
	res = sscanf (ret, "%f", &f);
216 217
	g_free (ret);

218 219
	if (res == 1) {
	        *val = f;
220 221 222
		return 1;
	}
	return 0;
223
}
224
#endif
225 226 227 228 229

/*
 * Get a double value for a node either carried as an attibute or as
 * the content of a child.
 */
230
static int
231
xml_get_value_double (xmlNodePtr node, const char *name, double *val)
232
{
233 234
	int res;
	char *ret;
235

236
	ret = xml_value_get (node, name);
237
	if (ret == NULL) return 0;
238
	res = sscanf (ret, "%lf", val);
239
	g_free (ret);
240

241
	return (res == 1);
242 243
}

244
#if 0
245 246 247
/*
 * Get a set of coodinates for a node, carried as the content of a child.
 */
248
static int
249
xml_get_coordinate (xmlNodePtr node, const char *name, double *x, double *y)
250
{
251 252
	int res;
	char *ret;
253
	float X, Y;
254

255
	ret = xml_value_get (node, name);
256
	if (ret == NULL) return 0;
257
	res = sscanf (ret, "(%lf %lf)", x, y)
258
	g_free (ret);
259 260

	return (res == 2)
261
}
262
#endif
263 264 265 266 267

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

268
static int
269
xml_get_coordinates (xmlNodePtr node, const char *name,
270 271
		   double *x1, double *y1, double *x2, double *y2)
{
272 273
	int res;
	char *ret;
274

275
	ret = xml_value_get (node, name);
276
	if (ret == NULL) return 0;
277
	res = sscanf (ret, "(%lf %lf)(%lf %lf)", x1, y1, x2, y2);
278 279 280
	g_free (ret);

	if (res == 4)
281
		return 1;
282

283
	return 0;
284 285
}

286
#if 0
287 288 289
/*
 * Get a GnomeCanvasPoints for a node, carried as the content of a child.
 */
290
static GnomeCanvasPoints *
291
xml_get_gnome_canvas_points (xmlNodePtr node, const char *name)
292
{
293
	char *val;
294 295 296 297
	GnomeCanvasPoints *ret = NULL;
	int res;
	const char *ptr;
	int index = 0, i;
298
	float coord[20];	/* TODO: must be dynamic !!!! */
299

300
	val = xml_value_get (node, name);
301
	if (val == NULL) return NULL;
302 303 304 305 306
	ptr = val;
	do {
		while ((*ptr) && (*ptr != '('))
			ptr++;
		if (*ptr == 0)
307
			break;
308
		res = sscanf (ptr, "(%lf %lf)", &coord[index], &coord[index + 1]);
309 310 311 312 313
		if (res != 2)
			break;
		index += 2;
		ptr++;
	} while (res > 0);
314
	g_free (val);
315 316 317 318 319 320 321

	if (index >= 2)
		ret = gnome_canvas_points_new (index / 2);
	if (ret == NULL)
		return NULL;
	for (i = 0; i < index; i++)
		ret->coords[i] = coord[i];
322
	return ret;
323
}
324
#endif
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
static void
331
xml_set_gnome_canvas_points (xmlNodePtr node, const char *name,
332
			     GnomeCanvasPoints *val)
333 334 335
{
	xmlNodePtr child;
	char *str, *base;
336
	char *tstr;
337 338 339 340 341 342
	int i;

	if (val == NULL)
		return;
	if ((val->num_points < 0) || (val->num_points > 5000))
		return;
343
	base = str = g_malloc (val->num_points * 30 * sizeof (char) + 1);
344 345 346
	if (str == NULL)
		return;
	for (i = 0; i < val->num_points; i++){
347 348 349
		sprintf (str, "(%f %f)", val->coords[2 * i],
			 val->coords[2 * i + 1]);
		str += strlen (str);
350
	}
351
	*str = 0;
352 353 354 355 356

	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, base);
357
			g_free (base);
358 359 360 361
			return;
		}
		child = child->next;
	}
362 363 364 365

	tstr = xmlEncodeEntitiesReentrant (node->doc, base);
	xmlNewChild (node, NULL, name, tstr);
	if (tstr) xmlFree (tstr);
366
	g_free (base);
367 368
}

369 370 371 372
/*
 * Set a string value for a node either carried as an attibute or as
 * the content of a child.
 */
373 374
static void
xml_set_value (xmlNodePtr node, const char *name, const char *val)
375
{
376
	char *ret;
377 378 379 380
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
	if (ret != NULL){
381
		xmlFree (ret);
382 383 384 385 386 387 388 389 390 391 392 393
		xmlSetProp (node, name, val);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, val);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, val);
394 395
}

396 397 398 399
/*
 * Set a String value for a node either carried as an attibute or as
 * the content of a child.
 */
400 401
static void
xml_set_value_string (xmlNodePtr node, const char *name, String *val)
402
{
403
	char *ret;
404 405 406 407
	xmlNodePtr child;

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

423 424 425 426
/*
 * Set an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
427
static void
428
xml_set_value_int (xmlNodePtr node, const char *name, int val)
429
{
430
	char *ret;
431 432 433 434 435 436
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%d", val);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
437
		xmlFree (ret);
438 439 440 441 442 443 444 445 446 447 448 449
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
450 451
}

452
#if 0
453 454 455 456
/*
 * Set a float value for a node either carried as an attibute or as
 * the content of a child.
 */
457
static void
458
xml_set_value_float (xmlNodePtr node, const char *name, float val)
459
{
460
	char *ret;
461 462 463 464 465 466
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%f", val);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
467
		xmlFree (ret);
468 469 470 471 472 473 474 475 476 477 478 479
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
480
}
481
#endif
482 483 484 485 486

/*
 * Set a double value for a node either carried as an attibute or as
 * the content of a child.
 */
487
static void
488
xml_set_value_double (xmlNodePtr node, const char *name, double val)
489
{
490
	char *ret;
491
	xmlNodePtr child;
492
	char str[101 + DBL_DIG];
493

494 495 496 497
	if (fabs (val) < 1e9 && fabs (val) > 1e-5)
		snprintf (str, 100 + DBL_DIG, "%.*g", DBL_DIG, val);
	else
		snprintf (str, 100 + DBL_DIG, "%f", val);
498

499 500
	ret = xmlGetProp (node, name);
	if (ret != NULL){
501
		xmlFree (ret);
502 503 504 505 506 507 508 509 510 511 512 513
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
514 515
}

516 517 518 519 520
static void
xml_set_print_unit (xmlNodePtr node, const char *name,
		    const PrintUnit * const pu)
{
	xmlNodePtr  child;
Jody Goldberg's avatar
Jody Goldberg committed
521
	char       *txt = "points";
522
	char       *tstr;
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541

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

542 543 544 545
	tstr = xmlEncodeEntitiesReentrant (node->doc, name);
	child = xmlNewChild (node, NULL, "PrintUnit", tstr);
	if (tstr) xmlFree (tstr);

546
	xml_set_value_double (child, "Points", pu->points);
547 548 549 550

	tstr = xmlEncodeEntitiesReentrant (node->doc, txt);
	xml_set_value (child, "PrefUnit", tstr);
	if (tstr) xmlFree (tstr);
551 552 553 554 555 556
}

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

558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
	g_return_if_fail (pu != NULL);
	g_return_if_fail (node != NULL);
	g_return_if_fail (node->childs != NULL);

	xml_get_value_double (node, "Points", &pu->points);
	txt = xml_value_get  (node, "PrefUnit");
	if (txt) {
		if (!g_strcasecmp (txt, "points"))
			pu->desired_display = UNIT_POINTS;
		else if (!g_strcasecmp (txt, "mm"))
			pu->desired_display = UNIT_MILLIMETER;
		else if (!g_strcasecmp (txt, "cm"))
			pu->desired_display = UNIT_CENTIMETER;
		else if (!g_strcasecmp (txt, "in"))
			pu->desired_display = UNIT_INCH;
573
		g_free (txt);
574 575 576
	}
}

577
/*
578
 * Search a child by name, if needed go down the tree to find it.
579
 */
580 581
static xmlNodePtr
xml_search_child (xmlNodePtr node, const char *name)
582 583 584 585 586 587 588 589 590 591 592 593
{
	xmlNodePtr ret;
	xmlNodePtr child;

	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name))
			return child;
		child = child->next;
	}
	child = node->childs;
	while (child != NULL){
594
		ret = xml_search_child (child, name);
595 596 597 598 599
		if (ret != NULL)
			return ret;
		child = child->next;
	}
	return NULL;
600 601
}

602 603 604
static gboolean
xml_read_range (xmlNodePtr tree, Range *res)
{
Jody Goldberg's avatar
Jody Goldberg committed
605
	return
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
	    xml_get_value_int (tree, "startCol", &res->start.col) &&
	    xml_get_value_int (tree, "startRow", &res->start.row) &&
	    xml_get_value_int (tree, "endCol",   &res->end.col) &&
	    xml_get_value_int (tree, "endRow",   &res->end.row);
}

static void
xml_write_range (xmlNodePtr tree, Range *value)
{
	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
xml_read_selection_info (parse_xml_context_t *ctxt, Sheet *sheet, xmlNodePtr tree)
{
	Range r;
	int row, col;
	xmlNodePtr sel, selections = xml_search_child (tree, "Selections");
	if (selections == NULL)
		return;

	sheet_selection_reset_only (sheet);
	for (sel = selections->childs; sel; sel = sel->next) {
		if (xml_read_range (sel, &r))
633 634 635 636
			sheet_selection_add_range (sheet,
						   r.start.col, r.start.row,
						   r.start.col, r.start.row,
						   r.end.col, r.end.row);
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
	}

	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
xml_write_selection_info (parse_xml_context_t *ctxt, Sheet *sheet, xmlNodePtr tree)
{
	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) {
		SheetSelection *sel = ptr->data;
		xmlNodePtr child = xmlNewChild (tree, ctxt->ns, "Selection", NULL);
		xml_write_range (child, &sel->user);
	}
	g_list_free (copy);

660 661
	xml_set_value_int (tree, "CursorCol", sheet->cursor.edit_pos.col);
	xml_set_value_int (tree, "CursorRow", sheet->cursor.edit_pos.row);
662 663
}

664 665 666 667 668 669 670 671
/*
 * 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 ...
 */
672
static int
673
xml_get_color_value (xmlNodePtr node, const char *name, StyleColor **color)
674
{
675
	char *ret;
676 677
	int red, green, blue;

678
	ret = xml_value_get (node, name);
679
	if (ret == NULL) return 0;
680
	if (sscanf (ret, "%X:%X:%X", &red, &green, &blue) == 3){
681
		*color = style_color_new (red, green, blue);
682
		g_free (ret);
683 684
		return 1;
	}
685
	g_free (ret);
686
	return 0;
687 688 689 690 691 692
}

/*
 * Set a color value for a node either carried as an attibute or as
 * the content of a child.
 */
693 694
static void
xml_set_color_value (xmlNodePtr node, const char *name, StyleColor *val)
695
{
696
	char *ret;
697 698 699 700 701 702
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%X:%X:%X", val->color.red, val->color.green, val->color.blue);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
703
		xmlFree (ret);
704 705 706 707 708 709 710 711 712 713 714 715
		xmlSetProp (node, name, str);
		return;
	}
	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, str);
			return;
		}
		child = child->next;
	}
	xmlSetProp (node, name, str);
716
}
717 718 719 720 721

/**
 **
 ** Private functions : mapping between in-memory structure and XML tree
 **
722
 **/
723
#if 0
724 725
static int
style_is_default_fore (StyleColor *color)
726
{
727 728
	if (!color)
		return TRUE;
729

730 731 732 733
	if (color->color.red == 0 && color->color.green == 0 && color->color.blue == 0)
		return TRUE;
	else
		return FALSE;
734 735
}

736 737
static int
style_is_default_back (StyleColor *color)
738
{
739 740
	if (!color)
		return TRUE;
741

742 743 744 745
	if (color->color.red == 0xffff && color->color.green == 0xffff && color->color.blue == 0xffff)
		return TRUE;
	else
		return FALSE;
746
}
747
#endif
748 749 750 751

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

Michael Meeks's avatar
Michael Meeks committed
753
static char *StyleSideNames[6] =
754 755 756 757
{
 	"Top",
 	"Bottom",
 	"Left",
Michael Meeks's avatar
Michael Meeks committed
758 759 760
 	"Right",
	"Diagonal",
	"Rev-Diagonal"
Arturo Espinosa's avatar
Arturo Espinosa committed
761
};
762

763
static xmlNodePtr
764 765
xml_write_style_border (parse_xml_context_t *ctxt,
			const MStyle *style)
766 767 768
{
	xmlNodePtr cur;
	xmlNodePtr side;
769
	int        i;
770

771 772 773
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
		MStyleBorder const *border;
		if (mstyle_is_element_set (style, i) &&
774
		    NULL != (border = mstyle_get_border (style, i))) {
Arturo Espinosa's avatar
Arturo Espinosa committed
775
			break;
776
		}
777
	}
778
	if (i > MSTYLE_BORDER_REV_DIAGONAL)
Arturo Espinosa's avatar
Arturo Espinosa committed
779
		return NULL;
780

781
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "StyleBorder", NULL);
782

Michael Meeks's avatar
Michael Meeks committed
783
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
Jody Goldberg's avatar
Jody Goldberg committed
784 785
		MStyleBorder const *border;
		if (mstyle_is_element_set (style, i) &&
786
		    NULL != (border = mstyle_get_border (style, i))) {
Jody Goldberg's avatar
Jody Goldberg committed
787 788
			StyleBorderType t = border->line_type;
			StyleColor *col   = border->color;
789 790
 			side = xmlNewChild (cur, ctxt->ns,
					    StyleSideNames [i - MSTYLE_BORDER_TOP],
791
 					    NULL);
792
 			xml_set_color_value (side, "Color", col);
793
			xml_set_value_int (side, "Style", t);
794
 		}
795 796
	}
	return cur;
797 798 799 800 801
}

/*
 * Create a StyleBorder equivalent to the XML subtree of doc.
 */
802
static void
803
xml_read_style_border (parse_xml_context_t *ctxt, xmlNodePtr tree, MStyle *mstyle)
804 805
{
	xmlNodePtr side;
806
	int        i;
807 808 809

	if (strcmp (tree->name, "StyleBorder")){
		fprintf (stderr,
810
			 "xml_read_style_border: invalid element type %s, 'StyleBorder' expected`\n",
811 812
			 tree->name);
	}
813

Michael Meeks's avatar
Michael Meeks committed
814
	for (i = MSTYLE_BORDER_TOP; i <= MSTYLE_BORDER_REV_DIAGONAL; i++) {
815 816
 		if ((side = xml_search_child (tree,
					      StyleSideNames [i - MSTYLE_BORDER_TOP])) != NULL) {
817 818 819 820 821
			int		 t;
			StyleColor      *color = NULL;
			MStyleBorder    *border;
			xml_get_value_int (side, "Style", &t);
			xml_get_color_value (side, "Color", &color);
822
			border = style_border_fetch ((StyleBorderType)t, color,
Michael Meeks's avatar
Michael Meeks committed
823
						     style_border_get_orientation (i));
824 825
			if (border)
				mstyle_set_border (mstyle, i, border);
826
 		}
827
	}
828 829 830 831 832
}

/*
 * Create an XML subtree of doc equivalent to the given Style.
 */
833
static xmlNodePtr
834 835
xml_write_style (parse_xml_context_t *ctxt,
		 MStyle *style)
836
{
837
	xmlNodePtr  cur, child;
838
	char       *tstr;
839

840
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Style", NULL);
841

842 843 844 845 846 847 848 849 850 851 852 853
	if (mstyle_is_element_set (style, MSTYLE_ALIGN_H))
		xml_set_value_int (cur, "HAlign", mstyle_get_align_h (style));
	if (mstyle_is_element_set (style, MSTYLE_ALIGN_V))
		xml_set_value_int (cur, "VAlign", mstyle_get_align_v (style));
	if (mstyle_is_element_set (style, MSTYLE_FIT_IN_CELL))
		xml_set_value_int (cur, "Fit", mstyle_get_fit_in_cell (style));
	if (mstyle_is_element_set (style, MSTYLE_ORIENTATION))
		xml_set_value_int (cur, "Orient", mstyle_get_orientation (style));
	if (mstyle_is_element_set (style, MSTYLE_PATTERN))
		xml_set_value_int (cur, "Shade", mstyle_get_pattern (style));

	if (mstyle_is_element_set (style, MSTYLE_COLOR_FORE)) {
854
/*		if (!style_is_default_fore (mstyle_get_color (style, MSTYLE_COLOR_FORE)))*/
855 856 857
			xml_set_color_value (cur, "Fore", mstyle_get_color (style, MSTYLE_COLOR_FORE));
	}
	if (mstyle_is_element_set (style, MSTYLE_COLOR_BACK)) {
858
/*		if (!style_is_default_back (mstyle_get_color (style, MSTYLE_COLOR_BACK)))*/
859 860
			xml_set_color_value (cur, "Back", mstyle_get_color (style, MSTYLE_COLOR_BACK));
	}
861
	if (mstyle_is_element_set (style, MSTYLE_COLOR_PATTERN)) {
862
/*		if (!style_is_default_back (mstyle_get_color (style, MSTYLE_COLOR_PATTERN)))*/
863 864
			xml_set_color_value (cur, "PatternColor", mstyle_get_color (style, MSTYLE_COLOR_PATTERN));
	}
865 866 867 868 869 870 871 872 873 874 875 876 877
	if (mstyle_is_element_set (style, MSTYLE_FORMAT))
		xml_set_value (cur, "Format", mstyle_get_format (style)->format);

	if (mstyle_is_element_set (style, MSTYLE_FONT_NAME) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_BOLD) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_ITALIC) ||
	    mstyle_is_element_set (style, MSTYLE_FONT_SIZE)) {
		const char *fontname;

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

879 880 881 882
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, fontname);
		child = xmlNewChild (cur, ctxt->ns, "Font", tstr);
		if (tstr) xmlFree (tstr);

883 884 885 886 887 888 889 890 891
		if (mstyle_is_element_set (style, MSTYLE_FONT_SIZE))
			xml_set_value_double (child, "Unit",
					      mstyle_get_font_size (style));
		if (mstyle_is_element_set (style, MSTYLE_FONT_BOLD))
			xml_set_value_int (child, "Bold",
					   mstyle_get_font_bold (style));
		if (mstyle_is_element_set (style, MSTYLE_FONT_ITALIC))
			xml_set_value_int (child, "Italic",
					   mstyle_get_font_italic (style));
Jody Goldberg's avatar
Jody Goldberg committed
892 893 894
		if (mstyle_is_element_set (style, MSTYLE_FONT_UNDERLINE))
			xml_set_value_int (child, "Underline",
					   (int)mstyle_get_font_uline (style));
895 896 897
		if (mstyle_is_element_set (style, MSTYLE_FONT_STRIKETHROUGH))
			xml_set_value_int (child, "StrikeThrough",
					   mstyle_get_font_strike (style));
898 899 900 901 902
	}

	child = xml_write_style_border (ctxt, style);
	if (child)
		xmlAddChild (cur, child);
903 904

	return cur;
905 906
}

907
static xmlNodePtr
908
xml_write_names (parse_xml_context_t *ctxt, GList *names)
909
{
910
	xmlNodePtr  cur;
911
	char       *tstr;
912 913 914 915 916 917 918 919 920 921 922 923 924 925

	if (!names)
		return NULL;

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

	while (names) {
		xmlNodePtr   tmp;
		ExprName    *expr_name = names->data;
		char        *text;

		g_return_val_if_fail (expr_name != NULL, NULL);

		tmp = xmlNewDocNode (ctxt->doc, ctxt->ns, "Name", NULL);
926 927 928
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, expr_name->name->str);
		xmlNewChild (tmp, ctxt->ns, "name", tstr);
		if (tstr) xmlFree (tstr);
929 930

		text = expr_name_value (expr_name);
931 932 933
		tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
		xmlNewChild (tmp, ctxt->ns, "value", tstr);
		if (tstr) xmlFree (tstr);
934 935 936 937 938
		g_free (text);

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

940 941 942 943
	return cur;
}

static void
944 945
xml_read_names (parse_xml_context_t *ctxt, xmlNodePtr tree, Workbook *wb,
		Sheet *sheet)
946 947 948 949 950 951 952 953
{
	xmlNodePtr child;

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

	child = tree->childs;
	while (child) {
954
		char *name  = NULL;
955 956 957 958 959
		if (child->name && !strcmp (child->name, "Name")) {
			xmlNodePtr bits;

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

961 962 963 964 965 966 967 968 969 970 971
				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"));

972
					if (!expr_name_create (wb, sheet, name, txt, &error))
973 974
						g_warning (error);

Daniel Veillard's avatar
Daniel Veillard committed
975
					xmlFree (txt);
976
				}
977
				bits = bits->next;
978 979 980 981 982 983
			}
		}
		child = child->next;
	}
}

984
static xmlNodePtr
985
xml_write_summary (parse_xml_context_t *ctxt, SummaryInfo *summary_info)
986 987
{
	GList *items, *m;
988
	char *tstr;
989 990
	xmlNodePtr cur;

991
	if (!summary_info)
992 993
		return NULL;

994
	m = items = summary_info_as_list (summary_info);
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007

	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);
1008 1009 1010
			tstr = xmlEncodeEntitiesReentrant (ctxt->doc, sit->name);
			xmlNewChild (tmp, ctxt->ns, "name", tstr);
			if (tstr) xmlFree (tstr);
1011 1012 1013

			if (sit->type == SUMMARY_INT) {
				text = g_strdup_printf ("%d", sit->v.i);
1014 1015 1016
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
				xmlNewChild (tmp, ctxt->ns, "val-int", tstr);
				if (tstr) xmlFree (tstr);
1017 1018
			} else {
				text = summary_item_as_text (sit);
1019 1020 1021
				tstr = xmlEncodeEntitiesReentrant (ctxt->doc, text);
				xmlNewChild (tmp, ctxt->ns, "val-string", tstr);
				if (tstr) xmlFree (tstr);
1022 1023
			}
			g_free (text);
1024
			xmlAddChild (cur, tmp);
1025 1026 1027 1028 1029 1030 1031 1032
		}
		items = g_list_next (items);
	}
	g_list_free (m);
	return cur;
}

static void
1033
xml_read_summary (parse_xml_context_t *ctxt, xmlNodePtr tree, SummaryInfo *summary_info)
1034
{
1035
	xmlNodePtr child;
1036

1037 1038 1039
	g_return_if_fail (ctxt != NULL);
	g_return_if_fail (tree != NULL);
	g_return_if_fail (summary_info != NULL);
1040 1041 1042

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

1045 1046 1047 1048 1049 1050
		if (child->name && !strcmp (child->name, "Item")) {
			xmlNodePtr bits;

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

1052
				if (!strcmp (bits->name, "name")) {
1053
					name = xmlNodeGetContent (bits);
1054 1055 1056 1057 1058
				} else {
					char *txt;
					g_return_if_fail (name);

					txt = xmlNodeGetContent (bits);
1059 1060 1061 1062
					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
1063
							sit = summary_item_new_int (name, atoi (txt));
1064

1065
						if (sit)
1066
							summary_info_add (summary_info, sit);
Daniel Veillard's avatar
Daniel Veillard committed
1067
						xmlFree (txt);
1068
					}
1069
				}
1070
				bits = bits->next;
1071 1072
			}
		}
Miguel de Icaza's avatar
Miguel de Icaza committed
1073
		if (name){
1074
			xmlFree (name);
Miguel de Icaza's avatar
Miguel de Icaza committed
1075 1076
			name = NULL;
		}
1077 1078 1079 1080
		child = child->next;
	}
}

Michael Meeks's avatar
Michael Meeks committed
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
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);
1091 1092 1093
	xml_set_value (child, "Left", hf->left_format);
	xml_set_value (child, "Middle", hf->middle_format);
	xml_set_value (child, "Right", hf->right_format);
Michael Meeks's avatar
Michael Meeks committed
1094 1095 1096
}

static void
Arturo Espinosa's avatar
Arturo Espinosa committed
1097
xml_get_print_hf (xmlNodePtr node, PrintHF *const hf)
Michael Meeks's avatar
Michael Meeks committed
1098 1099
{
	char *txt;
1100

Michael Meeks's avatar
Michael Meeks committed
1101 1102 1103 1104
	g_return_if_fail (hf != NULL);
	g_return_if_fail (node != NULL);

	txt = xml_value_get (node, "Left");
1105
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
1106 1107
		if (hf->left_format)
			g_free (hf->left_format);
1108
		hf->left_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
1109
	}
1110

Michael Meeks's avatar
Michael Meeks committed
1111
	txt = xml_value_get (node, "Middle");
1112
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
1113 1114
		if (hf->middle_format)
			g_free (hf->middle_format);
1115
		hf->middle_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
1116
	}
Michael Meeks's avatar
Michael Meeks committed
1117 1118

	txt = xml_value_get (node, "Right");
1119
	if (txt) {
Arturo Espinosa's avatar
Arturo Espinosa committed
1120 1121
		if (hf->right_format)
			g_free (hf->right_format);
1122
		hf->right_format = txt;
Arturo Espinosa's avatar
Arturo Espinosa committed
1123
	}