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

#include <config.h>
#include <stdio.h>
#include <gnome.h>
#include "gnumeric.h"
15 16
#include "gnome-xml/tree.h"
#include "gnome-xml/parser.h"
17
#include "color.h"
18
#include "sheet-object.h"
19
#include "sheet-object-graphic.h"
20
#include "xml-io.h"
21
#include "file.h"
22 23 24 25

/*
 * A parsing context.
 */
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
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 */
	GHashTable *style_table;/* to generate the styles and then the links to it */
	int style_count;        /* A style number */
	xmlNodePtr style_node;  /* The node where we insert the styles */
} parse_xml_context_t;

static Sheet      *xml_sheet_read     (parse_xml_context_t *ctxt, xmlNodePtr tree);
static xmlNodePtr  xml_sheet_write    (parse_xml_context_t *ctxt, Sheet *sheet);
static Workbook   *xml_workbook_read  (parse_xml_context_t *ctxt, xmlNodePtr tree);
static xmlNodePtr  xml_workbook_write (parse_xml_context_t *ctxt, Workbook *wb);
41

42 43 44
/*
 * Internal stuff: xml helper functions.
 */
45 46 47 48 49

/*
 * Get a value for a node either carried as an attibute or as
 * the content of a child.
 */
50
static char *
51
xml_value_get (xmlNodePtr node, const char *name)
52
{
53
	char *ret;
54 55
	xmlNodePtr child;

56
	ret = (char *) xmlGetProp (node, name);
57
	if (ret != NULL)
Morten Welinder's avatar
Morten Welinder committed
58
		return ret;
59 60 61
	child = node->childs;

	while (child != NULL) {
62 63 64 65 66 67 68 69
		if (!strcmp (child->name, name)) {
		        /*
			 * !!! Inefficient, but ...
			 */
			ret = xmlNodeGetContent(child);
			if (ret != NULL)
			    return (ret);
		}
70 71 72 73
		child = child->next;
	}

	return NULL;
74 75
}

76
#if 0
77 78 79 80
/*
 * Get a String value for a node either carried as an attibute or as
 * the content of a child.
 */
81
static String *
82
xml_get_value_string (xmlNodePtr node, const char *name)
83
{
84
	char *val;
85 86
	String *ret;

87
	val = xml_value_get(node, name);
88 89 90 91
	if (val == NULL) return(NULL);
        ret = string_get(val);
	free(val);
	return(ret);
92
}
93
#endif
94

95 96 97 98
/*
 * Get an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
99
static int
100
xml_get_value_int (xmlNodePtr node, const char *name, int *val)
101
{
102
	char *ret;
103
	int i;
104
	int res;
105

106
	ret = xml_value_get (node, name);
107 108 109 110 111 112
	if (ret == NULL) return(0);
	res = sscanf (ret, "%d", &i);
	free(ret);
	
	if (res == 1) {
	        *val = i;
113 114 115
		return 1;
	}
	return 0;
116 117
}

118
#if 0
119 120 121 122
/*
 * Get a float value for a node either carried as an attibute or as
 * the content of a child.
 */
123
static int
124
xml_get_value_float (xmlNodePtr node, const char *name, float *val)
125
{
126 127
	int res;
	char *ret;
128 129
	float f;

130
	ret = xml_value_get (node, name);
131 132 133 134 135 136
	if (ret == NULL) return(0);
	res = sscanf (ret, "%f", &f);
	free(ret);
	
	if (res == 1) {
	        *val = f;
137 138 139
		return 1;
	}
	return 0;
140
}
141
#endif
142 143 144 145 146

/*
 * Get a double value for a node either carried as an attibute or as
 * the content of a child.
 */
147
static int
148
xml_get_value_double (xmlNodePtr node, const char *name, double *val)
149
{
150 151
	int res;
	char *ret;
152

153
	ret = xml_value_get (node, name);
154
	if (ret == NULL) return(0);
155
	res = sscanf (ret, "%lf", val);
156
	free(ret);
157

158
	return (res == 1);
159 160
}

161
#if 0
162 163 164
/*
 * Get a set of coodinates for a node, carried as the content of a child.
 */
165
static int
166
xml_get_coordinate (xmlNodePtr node, const char *name, double *x, double *y)
167
{
168 169
	int res;
	char *ret;
170
	float X, Y;
171

172
	ret = xml_value_get (node, name);
173
	if (ret == NULL) return(0);
174
	res = sscanf (ret, "(%lf %lf)", x, y)
175
	free(ret);
176 177

	return (res == 2)
178
}
179
#endif
180 181 182 183 184

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

185
static int
186
xml_get_coordinates (xmlNodePtr node, const char *name,
187 188
		   double *x1, double *y1, double *x2, double *y2)
{
189 190
	int res;
	char *ret;
191

192
	ret = xml_value_get (node, name);
193
	if (ret == NULL) return(0);
194
	res = sscanf (ret, "(%lf %lf)(%lf %lf)", x1, y1, x2, y2);
195 196
	free(ret);
	
197
	if (res == 4) 
198
		return 1;
199

200
	return 0;
201 202
}

203
#if 0
204 205 206
/*
 * Get a GnomeCanvasPoints for a node, carried as the content of a child.
 */
207
static GnomeCanvasPoints *
208
xml_get_gnome_canvas_points (xmlNodePtr node, const char *name)
209
{
210
	char *val;
211 212 213 214
	GnomeCanvasPoints *ret = NULL;
	int res;
	const char *ptr;
	int index = 0, i;
215
	float coord[20];	/* TODO: must be dynamic !!!! */
216

217
	val = xml_value_get (node, name);
218
	if (val == NULL) return(NULL);
219 220 221 222 223
	ptr = val;
	do {
		while ((*ptr) && (*ptr != '('))
			ptr++;
		if (*ptr == 0)
224
			break;
225
		res = sscanf (ptr, "(%lf %lf)", &coord[index], &coord[index + 1]);
226 227 228 229 230 231 232 233 234 235 236 237 238
		if (res != 2)
			break;
		index += 2;
		ptr++;
	} while (res > 0);
	free(val);

	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];
239
	return ret;
240
}
241
#endif
242 243 244 245 246

/*
 * Set a string value for a node either carried as an attibute or as
 * the content of a child.
 */
247
static void
248
xml_set_gnome_canvas_points (xmlNodePtr node, const char *name,
249 250 251 252 253 254 255 256 257 258
			 GnomeCanvasPoints *val)
{
	xmlNodePtr child;
	char *str, *base;
	int i;

	if (val == NULL)
		return;
	if ((val->num_points < 0) || (val->num_points > 5000))
		return;
259
	base = str = g_malloc (val->num_points * 30 * sizeof (char));
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
	if (str == NULL)
		return;
	for (i = 0; i < val->num_points; i++){
		str += sprintf (str, "(%f %f)", val->coords[2 * i],
				val->coords[2 * i + 1]);
	}

	child = node->childs;
	while (child != NULL){
		if (!strcmp (child->name, name)){
			xmlNodeSetContent (child, base);
			free (base);
			return;
		}
		child = child->next;
	}
276
	xmlNewChild (node, NULL, name, xmlEncodeEntities(node->doc, base));
277
	g_free (base);
278 279 280
}


281 282 283 284
/*
 * Set a string value for a node either carried as an attibute or as
 * the content of a child.
 */
285 286
static void
xml_set_value (xmlNodePtr node, const char *name, const char *val)
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
{
	const char *ret;
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
	if (ret != NULL){
		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);
305 306
}

307 308 309 310
/*
 * Set a String value for a node either carried as an attibute or as
 * the content of a child.
 */
311 312
static void
xml_set_value_string (xmlNodePtr node, const char *name, String *val)
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
{
	const char *ret;
	xmlNodePtr child;

	ret = xmlGetProp (node, name);
	if (ret != NULL){
		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);
331 332
}

333 334 335 336
/*
 * Set an integer value for a node either carried as an attibute or as
 * the content of a child.
 */
337
static void
338
xml_set_value_int (xmlNodePtr node, const char *name, int val)
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
{
	const char *ret;
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%d", val);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
		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);
359 360
}

361
#if 0
362 363 364 365
/*
 * Set a float value for a node either carried as an attibute or as
 * the content of a child.
 */
366
static void
367
xml_set_value_float (xmlNodePtr node, const char *name, float val)
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
{
	const char *ret;
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%f", val);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
		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);
388
}
389
#endif
390 391 392 393 394

/*
 * Set a double value for a node either carried as an attibute or as
 * the content of a child.
 */
395
static void
396
xml_set_value_double (xmlNodePtr node, const char *name, double val)
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
{
	const char *ret;
	xmlNodePtr child;
	char str[101];

	snprintf (str, 100, "%f", (float) val);
	ret = xmlGetProp (node, name);
	if (ret != NULL){
		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);
417 418 419 420 421
}

/*
 * Search a child by name, if needed go down the tree to find it. 
 */
422 423
static xmlNodePtr
xml_search_child (xmlNodePtr node, const char *name)
424 425 426 427 428 429 430 431 432 433 434 435
{
	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){
436
		ret = xml_search_child (child, name);
437 438 439 440 441
		if (ret != NULL)
			return ret;
		child = child->next;
	}
	return NULL;
442 443 444 445 446 447 448 449 450 451
}

/*
 * 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 ...
 */
452
static int
453
xml_get_color_value (xmlNodePtr node, const char *name, StyleColor **color)
454
{
455
	char *ret;
456 457
	int red, green, blue;

458
	ret = xml_value_get (node, name);
459 460
	if (ret == NULL) return(0);
	if (sscanf (ret, "%X:%X:%X", &red, &green, &blue) == 3){
461
		*color = style_color_new (red, green, blue);
462
		free(ret);
463 464 465
		return 1;
	}
	return 0;
466 467 468 469 470 471
}

/*
 * Set a color value for a node either carried as an attibute or as
 * the content of a child.
 */
472 473
static void
xml_set_color_value (xmlNodePtr node, const char *name, StyleColor *val)
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
{
	const char *ret;
	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){
		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);
494
}
495 496 497 498 499

/**
 **
 ** Private functions : mapping between in-memory structure and XML tree
 **
500
 **/
501

502 503
static int
style_is_default_fore (StyleColor *color)
504
{
505 506
	if (!color)
		return TRUE;
507

508 509 510 511
	if (color->color.red == 0 && color->color.green == 0 && color->color.blue == 0)
		return TRUE;
	else
		return FALSE;
512 513
}

514 515
static int
style_is_default_back (StyleColor *color)
516
{
517 518
	if (!color)
		return TRUE;
519

520 521 522 523
	if (color->color.red == 0xffff && color->color.green == 0xffff && color->color.blue == 0xffff)
		return TRUE;
	else
		return FALSE;
524 525 526 527 528
}

/*
 * Create an XML subtree of doc equivalent to the given StyleBorder.
 */
529 530 531
static char *BorderTypes[8] =
{
	"none",
532 533 534 535 536 537 538
 	"thin",
 	"medium",
 	"dashed",
 	"dotted",
 	"thick",
 	"double",
	"hair"
539 540
};

541 542 543 544 545 546
static char *StyleSideNames[4] =
{
 	"Top",
 	"Bottom",
 	"Left",
 	"Right"
Arturo Espinosa's avatar
Arturo Espinosa committed
547
};
548

549
static xmlNodePtr
550
xml_write_style_border (parse_xml_context_t *ctxt, StyleBorder *border)
551 552 553
{
	xmlNodePtr cur;
	xmlNodePtr side;
Arturo Espinosa's avatar
Arturo Espinosa committed
554
	int lp;
555
       
Arturo Espinosa's avatar
Arturo Espinosa committed
556 557 558
	for (lp = 3; lp >= 0; lp--)
		if (border->type [lp] != BORDER_NONE)
			break;
559
	if (lp < 0)
Arturo Espinosa's avatar
Arturo Espinosa committed
560
		return NULL;
561

562
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "StyleBorder", NULL);
563
	
564 565 566 567
	for (lp = 0; lp < 4; lp++){
 		if (border->type[lp] != BORDER_NONE){
 			side = xmlNewChild (cur, ctxt->ns, StyleSideNames [lp],
 					    BorderTypes [border->type [lp]]);
568
 			xml_set_color_value (side, "Color", border->color [lp]);
569
 		}
570 571
	}
	return cur;
572 573 574 575 576
}

/*
 * Create a StyleBorder equivalent to the XML subtree of doc.
 */
577
static StyleBorder *
578
xml_read_style_border (parse_xml_context_t *ctxt, xmlNodePtr tree)
579 580
{
	StyleBorder *ret;
Arturo Espinosa's avatar
Arturo Espinosa committed
581
 	StyleBorderType style [4] = { BORDER_NONE, BORDER_NONE, BORDER_NONE, BORDER_NONE };
582
	StyleColor *color [4] = { NULL, NULL, NULL, NULL };
583
	xmlNodePtr side;
Arturo Espinosa's avatar
Arturo Espinosa committed
584
	int lp;
585 586 587

	if (strcmp (tree->name, "StyleBorder")){
		fprintf (stderr,
588
			 "xml_read_style_border: invalid element type %s, 'StyleBorder' expected`\n",
589 590
			 tree->name);
	}
591

Arturo Espinosa's avatar
Arturo Espinosa committed
592
 	for (lp = 0; lp < 4; lp++)
593
 	{
594
 		if ((side = xml_search_child (tree, StyleSideNames [lp])) != NULL)
595 596
 		{
 			/* FIXME: need to read the proper type */
Arturo Espinosa's avatar
Arturo Espinosa committed
597
 			style [lp] = BORDER_THICK ;
598
 			xml_get_color_value (side, "Color", &color [lp]);
599
 		}
600
	}
601
	
Arturo Espinosa's avatar
Arturo Espinosa committed
602
	ret = style_border_new (style, color);
603

604
	return NULL;
605 606 607 608 609
}

/*
 * Create an XML subtree of doc equivalent to the given Style.
 */
610
static xmlNodePtr
611
xml_write_style (parse_xml_context_t *ctxt, Style *style, int style_idx)
612 613 614 615 616 617 618 619
{
	xmlNodePtr cur, child;

	if ((style->halign == 0) && (style->valign == 0) &&
	    (style->orientation == 0) && (style->format == NULL) &&
	    (style->font == NULL) && (style->border == NULL))
		return NULL;

620
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Style", NULL);
621 622 623 624 625 626 627 628
	if (style_idx != -1)
		xml_set_value_int (cur, "No", style_idx);
	
	xml_set_value_int (cur, "HAlign", style->halign);
	xml_set_value_int (cur, "VAlign", style->valign);
	xml_set_value_int (cur, "Fit", style->fit_in_cell);
	xml_set_value_int (cur, "Orient", style->orientation);
	xml_set_value_int (cur, "Shade", style->pattern);
629 630

	if (!style_is_default_fore (style->fore_color))
631
		xml_set_color_value (cur, "Fore", style->fore_color);
632 633

	if (!style_is_default_back (style->back_color))
634
		xml_set_color_value (cur, "Back", style->back_color);
635 636

	if (style->format != NULL){
637
		xml_set_value (cur, "Format", style->format->format);
638 639 640
	}

	if (style->font != NULL){
641 642 643 644 645 646 647
		child = xmlNewChild (cur, ctxt->ns, "Font", 
				     xmlEncodeEntities(ctxt->doc,
						       style->font->font_name));
		xml_set_value_double (child, "Unit", style->font->size);
		xml_set_value_int (child, "Bold", style->font->is_bold);
		xml_set_value_int (child, "Italic", style->font->is_italic);

648 649 650
	}

	if (style->border != NULL){
651
		child = xml_write_style_border (ctxt, style->border);
652 653 654 655 656
		if (child)
			xmlAddChild (cur, child);
	}

	return cur;
657 658
}

659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
static const char *
font_component (const char *fontname, int idx)
{
	int i = 0;
	const char *p = fontname;
	
	for (; *p && i < idx; p++){
		if (*p == '-')
			i++;
	}
	if (*p == '-')
		p++;

	return p;
}

/**
 * style_font_new_from_x11:
 * @fontname: an X11-like font name.
 * @scale: scale desired
 *
 * Tries to guess the fontname, the weight and italization parameters
 * to invoke style_font_new
 *
 * Returns: A valid style font.
 */
static StyleFont *
style_font_new_from_x11 (const char *fontname, double units, double scale)
{
	StyleFont *sf;
	char *typeface = "Helvetica";
	int is_bold = 0;
	int is_italic = 0;
	const char *c;

	/*
	 * FIXME: we should do something about the typeface instead
	 * of hardcoding it to helvetica.
	 */
	
	c = font_component (fontname, 2);
	if (strncmp (c, "bold", 4) == 0)
		is_bold = 1;

	c = font_component (fontname, 3);
	if (strncmp (c, "o", 1) == 0)
		is_italic = 1;
	if (strncmp (c, "i", 1) == 0)
		is_italic = 1;

	sf = style_font_new (typeface, units, scale, is_bold, is_italic);
	if (sf == NULL)
		sf = style_font_new_from (gnumeric_default_font, scale);

	return sf;
}

716 717 718
/*
 * Create a Style equivalent to the XML subtree of doc.
 */
719
static Style *
720
xml_read_style (parse_xml_context_t *ctxt, xmlNodePtr tree, Style * ret)
721 722
{
	xmlNodePtr child;
Morten Welinder's avatar
Morten Welinder committed
723
	char *prop;
724 725 726 727 728
	int val;
	StyleColor *c;

	if (strcmp (tree->name, "Style")){
		fprintf (stderr,
729
			 "xml_read_style: invalid element type %s, 'Style' expected\n",
730 731 732 733 734 735 736 737
			 tree->name);
	}
	if (ret == NULL)
		ret = style_new_empty ();
	
	if (ret == NULL)
		return NULL;

738
	if (xml_get_value_int (tree, "HAlign", &val)){
739 740 741
		ret->halign = val;
		ret->valid_flags |= STYLE_ALIGN;
	}
742
	if (xml_get_value_int (tree, "Fit", &val)){
743 744 745
		ret->fit_in_cell = val;
		ret->valid_flags |= STYLE_ALIGN;
	}
746
	if (xml_get_value_int (tree, "VAlign", &val)){
747 748 749
		ret->valign = val;
		ret->valid_flags |= STYLE_ALIGN;
	}
750
	if (xml_get_value_int (tree, "Orient", &val)){
751 752 753
		ret->orientation = val;
		ret->valid_flags |= STYLE_ALIGN;
	}
754
	if (xml_get_value_int (tree, "Shade", &val)){
755 756 757
		ret->pattern = val;
		ret->valid_flags |= STYLE_PATTERN;
	}
758
	if (xml_get_color_value (tree, "Fore", &c)){
759 760 761
		ret->fore_color = c;
		ret->valid_flags |= STYLE_FORE_COLOR;
	}
762
	if (xml_get_color_value (tree, "Back", &c)){
763 764 765
		ret->back_color = c;
		ret->valid_flags |= STYLE_BACK_COLOR;
	}
766
	prop = xml_value_get (tree, "Format");
767 768
	if (prop != NULL){
		if (ret->format == NULL){
Morten Welinder's avatar
Morten Welinder committed
769
			ret->format = style_format_new ((const char *) prop);
770
			ret->valid_flags |= STYLE_FORMAT;
771
		}
Morten Welinder's avatar
Morten Welinder committed
772
		free (prop);
773
	}
774

775 776 777
	child = tree->childs;
	while (child != NULL){
		if (!strcmp (child->name, "Font")){
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
			char *font;
			double units = 14;
			int is_bold = 0;
			int is_italic = 0;
			int t;
				
			xml_get_value_double (child, "Unit", &units);

			if (xml_get_value_int (child, "Bold", &t))
				is_bold = t;
			if (xml_get_value_int (child, "Italic", &t))
				is_italic = t;
			
			font = xmlNodeGetContent(child);
			if (font != NULL) {
				StyleFont *sf;

				if (*font == '-'){
					sf = style_font_new_from_x11 (font, units, 1.0);
				} else
					sf = style_font_new (font, units, 1.0, is_bold, is_italic);

				ret->font = sf;
				free(font);
			}
			if (ret->font){
				ret->valid_flags |= STYLE_FONT;
805 806 807 808
			}
		} else if (!strcmp (child->name, "StyleBorder")){
			StyleBorder *sb;

809
			sb = xml_read_style_border (ctxt, child);
810
		} else {
811
			fprintf (stderr, "xml_read_style: unknown type '%s'\n",
812 813 814 815 816 817 818
				 child->name);
		}
		child = child->next;
	}

	/* Now add defaults to any style that was not loaded */
	return ret;
819 820
}

821
#if 0
822 823 824
/*
 * Create an XML subtree of doc equivalent to the given StyleRegion.
 */
825
static xmlNodePtr
826
xml_write_style_region (parse_xml_context_t *ctxt, StyleRegion *region)
827 828 829
{
	xmlNodePtr cur, child;

830
	cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "StyleRegion", NULL);
831 832 833 834
	xml_set_value_int (cur, "startCol", region->range.start_col);
	xml_set_value_int (cur, "endCol", region->range.end_col);
	xml_set_value_int (cur, "startRow", region->range.start_row);
	xml_set_value_int (cur, "endRow", region->range.end_row);
835 836

	if (region->style != NULL){
837
		child = xml_write_style (ctxt, region->style);
838 839 840 841
		if (child)
			xmlAddChild (cur, child);
	}
	return cur;
842
}
843
#endif
844 845 846 847

/*
 * Create a StyleRegion equivalent to the XML subtree of doc.
 */
848
static void
849
xml_read_style_region (parse_xml_context_t *ctxt, xmlNodePtr tree)
850 851 852 853 854 855 856
{
	xmlNodePtr child;
	Style *style = NULL;
	int start_col = 0, start_row = 0, end_col = 0, end_row = 0;

	if (strcmp (tree->name, "StyleRegion")){
		fprintf (stderr,
857
			 "xml_read_style_region: invalid element type %s, 'StyleRegion' expected`\n",
858 859 860
			 tree->name);
		return;
	}
861 862 863 864
	xml_get_value_int (tree, "startCol", &start_col);
	xml_get_value_int (tree, "startRow", &start_row);
	xml_get_value_int (tree, "endCol", &end_col);
	xml_get_value_int (tree, "endRow", &end_row);
865 866
	child = tree->childs;
	if (child != NULL)
867
		style = xml_read_style (ctxt, child, NULL);
868 869 870
	if (style != NULL)
		sheet_style_attach (ctxt->sheet, start_col, start_row, end_col,
				    end_row, style);
871 872 873

}

874 875 876
/*
 * Create an XML subtree of doc equivalent to the given ColRowInfo.
 */
877
static xmlNodePtr
878
xml_write_colrow_info (parse_xml_context_t *ctxt, ColRowInfo *info, int col)
879 880 881 882
{
	xmlNodePtr cur;

	if (col)
883
		cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "ColInfo", NULL);
884
	else
885
		cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "RowInfo", NULL);
886

887 888 889 890 891
	xml_set_value_int (cur, "No", info->pos);
	xml_set_value_double (cur, "Unit", info->units);
	xml_set_value_double (cur, "MarginA", info->margin_a_pt);
	xml_set_value_double (cur, "MarginB", info->margin_b);
	xml_set_value_int (cur, "HardSize", info->hard_size);
892 893

	return cur;
894 895 896 897 898
}

/*
 * Create a ColRowInfo equivalent to the XML subtree of doc.
 */
899
static ColRowInfo *
900
xml_read_colrow_info (parse_xml_context_t *ctxt, xmlNodePtr tree, ColRowInfo *ret)
901 902 903 904 905 906 907 908 909 910
{
	int col = 0;
	int val;

	if (!strcmp (tree->name, "ColInfo")){
		col = 1;
	} else if (!strcmp (tree->name, "RowInfo")){
		col = 0;
	} else {
		fprintf (stderr,
911
			 "xml_read_colrow_info: invalid element type %s, 'ColInfo/RowInfo' expected`\n",
912 913 914 915 916 917 918 919 920 921 922
			 tree->name);
		return NULL;
	}
	if (ret == NULL){
		if (col)
			ret = sheet_col_new (ctxt->sheet);
		else
			ret = sheet_row_new (ctxt->sheet);
	}
	if (ret == NULL)
		return NULL;
923

924 925 926 927 928
	xml_get_value_int (tree, "No", &ret->pos);
	xml_get_value_double (tree, "Unit", &ret->units);
	xml_get_value_double (tree, "MarginA", &ret->margin_a_pt);
	xml_get_value_double (tree, "MarginB", &ret->margin_b_pt);
	if (xml_get_value_int (tree, "HardSize", &val))
929
		ret->hard_size = val;
930

931
	return ret;
932 933
}

934 935 936
/*
 * Create an XML subtree of doc equivalent to the given Object.
 */
937
static xmlNodePtr
938
xml_write_sheet_object (parse_xml_context_t *ctxt, SheetObject *object)
939
{
940
	SheetObjectGraphic *sog = SHEET_OBJECT_GRAPHIC (object);
941 942
	xmlNodePtr cur = NULL;

943
	switch (sog->type){
944
	case SHEET_OBJECT_RECTANGLE:{
945
			SheetObjectFilled *sof = SHEET_OBJECT_FILLED (object);
946

947
			cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Rectangle", NULL);
948
			if (sof->fill_color != NULL)
949 950
				xml_set_value_string (cur, "FillColor", sof->fill_color);
			xml_set_value_int (cur, "Pattern", sof->pattern);
951 952
			break;
		}
953

954
	case SHEET_OBJECT_ELLIPSE:{
955
			SheetObjectFilled *sof = SHEET_OBJECT_FILLED (object);
956

957
			cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Ellipse", NULL);
958
			if (sof->fill_color != NULL)
959 960
				xml_set_value_string (cur, "FillColor", sof->fill_color);
			xml_set_value_int (cur, "Pattern", sof->pattern);
961 962
			break;
		}
963

964
	case SHEET_OBJECT_ARROW:
965
		cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Arrow", NULL);
966
		break;
967

968
	case SHEET_OBJECT_LINE:
969
		cur = xmlNewDocNode (ctxt->doc, ctxt->ns, "Line", NULL);
970 971 972 973 974
		break;
	}
	if (cur == NULL)
		return NULL;
	
975 976 977
	xml_set_gnome_canvas_points (cur, "Points", object->bbox_points);
	xml_set_value_int (cur, "Width", sog->width);
	xml_set_value_string (cur, "Color", sog->color);
978

979
	return cur;
980 981 982 983 984
}

/*
 * Create a Object equivalent to the XML subtree of doc.
 */
985
static SheetObject *
986
xml_read_sheet_object (parse_xml_context_t *ctxt, xmlNodePtr tree)
987 988
{
	SheetObject *ret;
989
	SheetObjectFilled *sof;
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
	char *color;
	char *fill_color;
	int type;
	double x1, y1, x2, y2;
	int width = 1;
	int pattern;

	if (!strcmp (tree->name, "Rectangle")){
		type = SHEET_OBJECT_RECTANGLE;
	} else if (!strcmp (tree->name, "Ellipse")){
		type = SHEET_OBJECT_ELLIPSE;
	} else if (!strcmp (tree->name, "Arrow")){
		type = SHEET_OBJECT_ARROW;
	} else if (!strcmp (tree->name, "Line")){
		type = SHEET_OBJECT_LINE;
	} else {
		fprintf (stderr,
1007
			 "xml_read_sheet_object: invalid element type %s, 'Rectangle/Ellipse ...' expected`\n",
1008 1009 1010 1011
			 tree->name);
		return NULL;
	}
	
1012 1013 1014
	color = (char *) xml_value_get (tree, "Color");
	xml_get_coordinates (tree, "Points", &x1, &y1, &x2, &y2);
	xml_get_value_int (tree, "Width", &width);
1015 1016
	if ((type == SHEET_OBJECT_RECTANGLE) ||
	    (type == SHEET_OBJECT_ELLIPSE)){
1017 1018
		fill_color = (char *) xml_value_get (tree, "FillColor");
		xml_get_value_int (tree, "Pattern", &pattern);
1019 1020 1021
		ret = sheet_object_create_filled (
			ctxt->sheet, type,
			x1, y1, x2, y2, fill_color, color, width);
1022
		if (ret != NULL){
1023 1024
			sof = SHEET_OBJECT_FILLED (ret);
			sof->pattern = pattern;
1025 1026
		}
	} else {
1027 1028 1029
		ret = sheet_object_create_line (
			ctxt->sheet, type,
			x1, y1, x2, y2, color, width);
1030
	}
1031
	sheet_object_realize (ret);
1032
	return ret;
1033 1034
}

1035 1036 1037
/*
 * Create an XML subtree of doc equivalent to the given Cell.
 */
1038
static xmlNodePtr
1039
xml_write_cell (parse_xml_context_t *ctxt, Cell *cell)
1040
{