1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * xml-sax-write.c : export .gnumeric and the clipboard subset using the sax
5 * like wrappers in libgsf
7 * Copyright (C) 2003-2007 Jody Goldberg (jody@gnome.org)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) version 3.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
25 /*****************************************************************************/
27 #include <gnumeric-config.h>
29 #include <glib/gi18n-lib.h>
31 #include <workbook-view.h>
32 #include <gnm-format.h>
34 #include <workbook-priv.h> /* Workbook::names */
37 #include <sheet-view.h>
38 #include <sheet-style.h>
39 #include <style-color.h>
40 #include <style-conditions.h>
42 #include <expr-name.h>
46 #include <style-border.h>
47 #include <validation.h>
49 #include <input-msg.h>
50 #include <tools/gnm-solver.h>
51 #include <sheet-filter.h>
52 #include <sheet-object-impl.h>
53 #include <sheet-object-cell-comment.h>
54 #include <print-info.h>
56 #include <clipboard.h>
57 #include <tools/scenarios.h>
58 #include <gnumeric-conf.h>
60 #include <goffice/goffice.h>
61 #include <gsf/gsf-libxml.h>
62 #include <gsf/gsf-output-gzip.h>
63 #include <gsf/gsf-doc-meta-data.h>
64 #include <gsf/gsf-opendoc-utils.h>
65 #include <gsf/gsf-utils.h>
68 WorkbookView
const *wb_view
; /* View for the new workbook */
69 Workbook
const *wb
; /* The new workbook */
71 GnmConventions
*convs
;
73 GString
*cell_str
; /* Scratch pad. */
75 // Do we write result values? For now this is clipboard only
76 gboolean write_value_result
;
83 /* Precision to use when saving point measures. */
84 #define POINT_SIZE_PRECISION 4
87 gnm_xml_out_add_gocolor (GsfXMLOut
*o
, char const *id
, GOColor c
)
90 * This uses format "rrrr:gggg:bbbb" or "rrrr:gggg:bbbb:aaaa"
91 * using hex numbers, i.e., the numbers are in the range from
94 * Note, that while go_xml_out_add_color exists, we cannot use
95 * it as it using a 0-255 scaling and always includes alpha.
98 char buf
[4 * 4 * sizeof (unsigned int) + 1];
100 GO_COLOR_TO_RGBA (c
, &r
, &g
, &b
, &a
);
102 sprintf (buf
, "%X:%X:%X%c%X",
103 r
* 0x101, g
* 0x101, b
* 0x101,
104 (a
== 0xff ? 0 : ':'),
106 gsf_xml_out_add_cstr_unchecked (o
, id
, buf
);
110 gnm_xml_out_add_color (GsfXMLOut
*o
, char const *id
, GnmColor
const *c
)
112 gnm_xml_out_add_gocolor (o
, id
, c
->go_color
);
116 gnm_xml_out_add_cellpos (GsfXMLOut
*o
, char const *id
, GnmCellPos
const *p
)
118 g_return_if_fail (p
!= NULL
);
119 gsf_xml_out_add_cstr_unchecked (o
, id
, cellpos_as_string (p
));
123 xml_out_add_range (GsfXMLOut
*xml
, GnmRange
const *r
)
125 g_return_if_fail (range_is_sane (r
));
127 gsf_xml_out_add_int (xml
, "startCol", r
->start
.col
);
128 gsf_xml_out_add_int (xml
, "startRow", r
->start
.row
);
129 gsf_xml_out_add_int (xml
, "endCol", r
->end
.col
);
130 gsf_xml_out_add_int (xml
, "endRow", r
->end
.row
);
134 xml_out_add_points (GsfXMLOut
*xml
, char const *name
, double val
)
136 gsf_xml_out_add_float (xml
, name
, val
, POINT_SIZE_PRECISION
);
140 xml_write_boolean_attribute (GnmOutputXML
*state
, char const *name
, gboolean value
)
142 gsf_xml_out_start_element (state
->output
, GNM
"Attribute");
143 gsf_xml_out_simple_element (state
->output
, GNM
"name", name
);
144 gsf_xml_out_simple_element (state
->output
, GNM
"value", value
? "TRUE" : "FALSE");
145 gsf_xml_out_end_element (state
->output
); /* </Attribute> */
149 xml_write_version (GnmOutputXML
*state
)
151 gsf_xml_out_start_element (state
->output
, GNM
"Version");
152 gsf_xml_out_add_int (state
->output
, "Epoch", GNM_VERSION_EPOCH
);
153 gsf_xml_out_add_int (state
->output
, "Major", GNM_VERSION_MAJOR
);
154 gsf_xml_out_add_int (state
->output
, "Minor", GNM_VERSION_MINOR
);
155 gsf_xml_out_add_cstr_unchecked (state
->output
, "Full", GNM_VERSION_FULL
);
156 gsf_xml_out_end_element (state
->output
); /* </Version> */
160 xml_write_attributes (GnmOutputXML
*state
)
162 gsf_xml_out_start_element (state
->output
, GNM
"Attributes");
163 xml_write_boolean_attribute
164 (state
, "WorkbookView::show_horizontal_scrollbar",
165 state
->wb_view
->show_horizontal_scrollbar
);
166 xml_write_boolean_attribute
167 (state
, "WorkbookView::show_vertical_scrollbar",
168 state
->wb_view
->show_vertical_scrollbar
);
169 xml_write_boolean_attribute
170 (state
, "WorkbookView::show_notebook_tabs",
171 state
->wb_view
->show_notebook_tabs
);
172 xml_write_boolean_attribute
173 (state
, "WorkbookView::do_auto_completion",
174 state
->wb_view
->do_auto_completion
);
175 xml_write_boolean_attribute
176 (state
, "WorkbookView::is_protected",
177 state
->wb_view
->is_protected
);
178 gsf_xml_out_end_element (state
->output
); /* </Attributes> */
182 xml_write_meta_data (GnmOutputXML
*state
)
184 gsf_doc_meta_data_write_to_odf (go_doc_get_meta_data (GO_DOC (state
->wb
)),
188 /* DEPRECATED in 1.7.11 */
190 xml_write_conventions (GnmOutputXML
*state
)
192 GODateConventions
const *conv
= workbook_date_conv (state
->wb
);
194 gsf_xml_out_simple_element (state
->output
, GNM
"DateConvention", "1904");
198 xml_write_sheet_names (GnmOutputXML
*state
)
200 int i
, n
= workbook_sheet_count (state
->wb
);
203 gsf_xml_out_start_element (state
->output
, GNM
"SheetNameIndex");
204 for (i
= 0 ; i
< n
; i
++) {
205 sheet
= workbook_sheet_by_index (state
->wb
, i
);
206 gsf_xml_out_start_element (state
->output
, GNM
"SheetName");
209 * Note, that we explicitly namespace these attributes.
210 * That is not wrong, per se, but note that Gnumeric until
211 * 1.12.22 will not read files without this explicit name-
212 * space and that the abbreviation must be "gnm".
214 if (sheet
->sheet_type
== GNM_SHEET_OBJECT
)
215 gsf_xml_out_add_cstr (state
->output
, GNM
"SheetType", "object");
216 gsf_xml_out_add_int (state
->output
, GNM
"Cols",
217 gnm_sheet_get_max_cols (sheet
));
218 gsf_xml_out_add_int (state
->output
, GNM
"Rows",
219 gnm_sheet_get_max_rows (sheet
));
220 gsf_xml_out_add_cstr (state
->output
, NULL
, sheet
->name_unquoted
);
221 gsf_xml_out_end_element (state
->output
); /* </gnm:SheetName> */
223 gsf_xml_out_end_element (state
->output
); /* </gnm:SheetNameIndex> */
227 xml_write_name (GnmOutputXML
*state
, GnmNamedExpr
*nexpr
)
231 g_return_if_fail (nexpr
!= NULL
);
233 gsf_xml_out_start_element (state
->output
, GNM
"Name");
234 gsf_xml_out_simple_element (state
->output
, GNM
"name",
235 expr_name_name (nexpr
));
236 expr_str
= expr_name_as_string (nexpr
, NULL
, state
->convs
);
237 gsf_xml_out_simple_element (state
->output
, GNM
"value", expr_str
);
239 gsf_xml_out_simple_element (state
->output
, GNM
"position",
240 cellpos_as_string (&nexpr
->pos
.eval
));
241 gsf_xml_out_end_element (state
->output
); /* </gnm:Name> */
245 xml_write_named_expressions (GnmOutputXML
*state
, GnmNamedExprCollection
*scope
)
248 g_slist_sort (gnm_named_expr_collection_list (scope
),
249 (GCompareFunc
)expr_name_cmp_by_name
);
255 gsf_xml_out_start_element (state
->output
, GNM
"Names");
256 for (p
= names
; p
; p
= p
->next
) {
257 GnmNamedExpr
*nexpr
= p
->data
;
258 xml_write_name (state
, nexpr
);
260 gsf_xml_out_end_element (state
->output
); /* </gnm:Names> */
261 g_slist_free (names
);
265 xml_write_geometry (GnmOutputXML
*state
)
267 if (state
->wb_view
->preferred_width
> 0 ||
268 state
->wb_view
->preferred_height
> 0) {
269 gsf_xml_out_start_element (state
->output
, GNM
"Geometry");
270 gsf_xml_out_add_int (state
->output
, "Width", state
->wb_view
->preferred_width
);
271 gsf_xml_out_add_int (state
->output
, "Height", state
->wb_view
->preferred_height
);
272 gsf_xml_out_end_element (state
->output
); /* </gnm:Geometry> */
277 xml_write_print_unit (GnmOutputXML
*state
, char const *name
,
278 double points
, GtkUnit unit
)
280 gsf_xml_out_start_element (state
->output
, name
);
281 xml_out_add_points (state
->output
, "Points", points
);
282 gsf_xml_out_add_cstr_unchecked (state
->output
, "PrefUnit",
283 unit_to_unit_name (unit
));
284 gsf_xml_out_end_element (state
->output
);
288 xml_write_print_repeat_range (GnmOutputXML
*state
,
292 if (range
&& *range
) {
293 gsf_xml_out_start_element (state
->output
, name
);
294 gsf_xml_out_add_cstr_unchecked (state
->output
, "value", range
);
295 gsf_xml_out_end_element (state
->output
);
300 xml_write_print_hf (GnmOutputXML
*state
, char const *name
,
301 GnmPrintHF
const *hf
)
303 gsf_xml_out_start_element (state
->output
, name
);
304 gsf_xml_out_add_cstr (state
->output
, "Left", hf
->left_format
);
305 gsf_xml_out_add_cstr (state
->output
, "Middle", hf
->middle_format
);
306 gsf_xml_out_add_cstr (state
->output
, "Right", hf
->right_format
);
307 gsf_xml_out_end_element (state
->output
);
312 xml_write_breaks (GnmOutputXML
*state
, GnmPageBreaks
*breaks
)
314 GArray
const *details
= breaks
->details
;
315 GnmPageBreak
const *binfo
;
318 gsf_xml_out_start_element (state
->output
,
319 (breaks
->is_vert
) ? GNM
"vPageBreaks" : GNM
"hPageBreaks");
320 gsf_xml_out_add_int (state
->output
, "count", details
->len
);
322 for (i
= 0 ; i
< details
->len
; i
++) {
323 binfo
= &g_array_index (details
, GnmPageBreak
, i
);
324 gsf_xml_out_start_element (state
->output
, GNM
"break");
325 gsf_xml_out_add_int (state
->output
, "pos", binfo
->pos
);
326 if (binfo
->type
== GNM_PAGE_BREAK_MANUAL
)
327 gsf_xml_out_add_cstr_unchecked (state
->output
, "type", "manual");
328 else if (binfo
->type
== GNM_PAGE_BREAK_DATA_SLICE
)
329 gsf_xml_out_add_cstr_unchecked (state
->output
, "type", "data-slice");
330 else if (binfo
->type
== GNM_PAGE_BREAK_AUTO
)
331 gsf_xml_out_add_cstr_unchecked (state
->output
, "type", "auto");
332 gsf_xml_out_end_element (state
->output
); /* </break> */
334 gsf_xml_out_end_element (state
->output
);
338 xml_write_print_info (GnmOutputXML
*state
, GnmPrintInformation
*pi
)
346 double edge_to_above_footer
;
347 double edge_to_below_header
;
348 GtkPageOrientation orient
;
350 g_return_if_fail (pi
!= NULL
);
352 gsf_xml_out_start_element (state
->output
, GNM
"PrintInformation");
354 gsf_xml_out_start_element (state
->output
, GNM
"Margins");
356 print_info_get_margins (pi
, &header
, &footer
, &left
, &right
,
357 &edge_to_below_header
, &edge_to_above_footer
);
358 xml_write_print_unit (state
, GNM
"top", edge_to_below_header
,
359 pi
->desired_display
.header
);
360 xml_write_print_unit (state
, GNM
"bottom", edge_to_above_footer
,
361 pi
->desired_display
.footer
);
362 xml_write_print_unit (state
, GNM
"left", left
,
363 pi
->desired_display
.left
);
364 xml_write_print_unit (state
, GNM
"right", right
,
365 pi
->desired_display
.right
);
366 xml_write_print_unit (state
, GNM
"header", header
,
367 pi
->desired_display
.top
);
368 xml_write_print_unit (state
, GNM
"footer", footer
,
369 pi
->desired_display
.bottom
);
370 gsf_xml_out_end_element (state
->output
);
372 gsf_xml_out_start_element (state
->output
, GNM
"Scale");
373 if (pi
->scaling
.type
== PRINT_SCALE_PERCENTAGE
) {
374 gsf_xml_out_add_cstr_unchecked (state
->output
, "type", "percentage");
375 go_xml_out_add_double (state
->output
, "percentage", pi
->scaling
.percentage
.x
);
377 gsf_xml_out_add_cstr_unchecked (state
->output
, "type", "size_fit");
378 go_xml_out_add_double (state
->output
, "cols", pi
->scaling
.dim
.cols
);
379 go_xml_out_add_double (state
->output
, "rows", pi
->scaling
.dim
.rows
);
381 gsf_xml_out_end_element (state
->output
);
383 gsf_xml_out_start_element (state
->output
, GNM
"vcenter");
384 gsf_xml_out_add_int (state
->output
, "value", pi
->center_vertically
);
385 gsf_xml_out_end_element (state
->output
);
387 gsf_xml_out_start_element (state
->output
, GNM
"hcenter");
388 gsf_xml_out_add_int (state
->output
, "value", pi
->center_horizontally
);
389 gsf_xml_out_end_element (state
->output
);
391 gsf_xml_out_start_element (state
->output
, GNM
"grid");
392 gsf_xml_out_add_int (state
->output
, "value", pi
->print_grid_lines
);
393 gsf_xml_out_end_element (state
->output
);
395 gsf_xml_out_start_element (state
->output
, GNM
"even_if_only_styles");
396 gsf_xml_out_add_int (state
->output
, "value", pi
->print_even_if_only_styles
);
397 gsf_xml_out_end_element (state
->output
);
399 gsf_xml_out_start_element (state
->output
, GNM
"monochrome");
400 gsf_xml_out_add_int (state
->output
, "value", pi
->print_black_and_white
);
401 gsf_xml_out_end_element (state
->output
);
403 gsf_xml_out_start_element (state
->output
, GNM
"draft");
404 gsf_xml_out_add_int (state
->output
, "value", pi
->print_as_draft
);
405 gsf_xml_out_end_element (state
->output
);
407 gsf_xml_out_start_element (state
->output
, GNM
"titles");
408 gsf_xml_out_add_int (state
->output
, "value", pi
->print_titles
);
409 gsf_xml_out_end_element (state
->output
);
411 gsf_xml_out_start_element (state
->output
, GNM
"do_not_print");
412 gsf_xml_out_add_int (state
->output
, "value", pi
->do_not_print
);
413 gsf_xml_out_end_element (state
->output
);
415 gsf_xml_out_start_element (state
->output
, GNM
"print_range");
416 gsf_xml_out_add_enum (state
->output
, "value",
417 GNM_PRINT_RANGE_TYPE
,
418 print_info_get_printrange (pi
) );
419 gsf_xml_out_end_element (state
->output
);
421 xml_write_print_repeat_range (state
, GNM
"repeat_top", pi
->repeat_top
);
422 xml_write_print_repeat_range (state
, GNM
"repeat_left", pi
->repeat_left
);
424 /* this was once an enum, hence the silly strings */
425 gsf_xml_out_simple_element (state
->output
, GNM
"order",
426 pi
->print_across_then_down
? "r_then_d" :"d_then_r");
428 orient
= print_info_get_paper_orientation (pi
);
429 gsf_xml_out_simple_element (state
->output
, GNM
"orientation",
430 (orient
== GTK_PAGE_ORIENTATION_PORTRAIT
431 || orient
== GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT
)
432 ? "portrait" : "landscape");
433 #warning TODO: we should also handle inversion
435 xml_write_print_hf (state
, GNM
"Header", pi
->header
);
436 xml_write_print_hf (state
, GNM
"Footer", pi
->footer
);
438 paper_name
= print_info_get_paper (pi
);
440 gsf_xml_out_simple_element (state
->output
, GNM
"paper",
444 uri
= print_info_get_printtofile_uri (pi
);
446 gsf_xml_out_simple_element (state
->output
, GNM
"print-to-uri",
449 if (NULL
!= pi
->page_breaks
.v
)
450 xml_write_breaks (state
, pi
->page_breaks
.v
);
451 if (NULL
!= pi
->page_breaks
.h
)
452 xml_write_breaks (state
, pi
->page_breaks
.h
);
454 gsf_xml_out_start_element (state
->output
, GNM
"comments");
455 gsf_xml_out_add_enum (state
->output
, "placement",
456 GNM_PRINT_COMMENT_PLACEMENT_TYPE
,
457 pi
->comment_placement
);
458 gsf_xml_out_end_element (state
->output
);
460 gsf_xml_out_start_element (state
->output
, GNM
"errors");
461 gsf_xml_out_add_enum (state
->output
, "PrintErrorsAs",
462 GNM_PRINT_ERRORS_TYPE
,
464 gsf_xml_out_end_element (state
->output
);
466 gsf_xml_out_end_element (state
->output
);
470 xml_write_style (GnmOutputXML
*state
, GnmStyle
const *style
)
472 static char const *border_names
[] = {
480 GnmValidation
const *v
;
482 GnmInputMsg
const *im
;
483 GnmStyleConditions
const *sc
;
484 GnmStyleBorderType t
;
488 gsf_xml_out_start_element (state
->output
, GNM
"Style");
490 if (gnm_style_is_element_set (style
, MSTYLE_ALIGN_H
))
491 gsf_xml_out_add_enum (state
->output
, "HAlign",
493 gnm_style_get_align_h (style
));
494 if (gnm_style_is_element_set (style
, MSTYLE_ALIGN_V
))
495 gsf_xml_out_add_enum (state
->output
, "VAlign",
497 gnm_style_get_align_v (style
));
498 if (gnm_style_is_element_set (style
, MSTYLE_WRAP_TEXT
))
499 gsf_xml_out_add_bool (state
->output
, "WrapText",
500 gnm_style_get_wrap_text (style
));
501 if (gnm_style_is_element_set (style
, MSTYLE_SHRINK_TO_FIT
))
502 gsf_xml_out_add_bool (state
->output
, "ShrinkToFit",
503 gnm_style_get_shrink_to_fit (style
));
504 if (gnm_style_is_element_set (style
, MSTYLE_ROTATION
))
505 gsf_xml_out_add_int (state
->output
, "Rotation",
506 gnm_style_get_rotation (style
));
507 if (gnm_style_is_element_set (style
, MSTYLE_PATTERN
))
508 gsf_xml_out_add_int (state
->output
, "Shade",
509 gnm_style_get_pattern (style
));
510 if (gnm_style_is_element_set (style
, MSTYLE_INDENT
))
511 gsf_xml_out_add_int (state
->output
, "Indent", gnm_style_get_indent (style
));
512 if (gnm_style_is_element_set (style
, MSTYLE_CONTENTS_LOCKED
))
513 gsf_xml_out_add_bool (state
->output
, "Locked",
514 gnm_style_get_contents_locked (style
));
515 if (gnm_style_is_element_set (style
, MSTYLE_CONTENTS_HIDDEN
))
516 gsf_xml_out_add_bool (state
->output
, "Hidden",
517 gnm_style_get_contents_hidden (style
));
518 if (gnm_style_is_element_set (style
, MSTYLE_FONT_COLOR
))
519 gnm_xml_out_add_color (state
->output
, "Fore",
520 gnm_style_get_font_color (style
));
521 if (gnm_style_is_element_set (style
, MSTYLE_COLOR_BACK
))
522 gnm_xml_out_add_color (state
->output
, "Back",
523 gnm_style_get_back_color (style
));
524 if (gnm_style_is_element_set (style
, MSTYLE_COLOR_PATTERN
))
525 gnm_xml_out_add_color (state
->output
, "PatternColor",
526 gnm_style_get_pattern_color (style
));
527 if (gnm_style_is_element_set (style
, MSTYLE_FORMAT
)) {
528 const char *fmt
= go_format_as_XL (gnm_style_get_format (style
));
529 gsf_xml_out_add_cstr (state
->output
, "Format", fmt
);
532 if (gnm_style_is_element_set (style
, MSTYLE_FONT_NAME
) ||
533 gnm_style_is_element_set (style
, MSTYLE_FONT_SIZE
) ||
534 gnm_style_is_element_set (style
, MSTYLE_FONT_BOLD
) ||
535 gnm_style_is_element_set (style
, MSTYLE_FONT_ITALIC
) ||
536 gnm_style_is_element_set (style
, MSTYLE_FONT_UNDERLINE
) ||
537 gnm_style_is_element_set (style
, MSTYLE_FONT_STRIKETHROUGH
) ||
538 gnm_style_is_element_set (style
, MSTYLE_FONT_SCRIPT
)) {
539 gsf_xml_out_start_element (state
->output
, GNM
"Font");
541 if (gnm_style_is_element_set (style
, MSTYLE_FONT_SIZE
))
542 xml_out_add_points (state
->output
, "Unit", gnm_style_get_font_size (style
));
543 if (gnm_style_is_element_set (style
, MSTYLE_FONT_BOLD
))
544 gsf_xml_out_add_int (state
->output
, "Bold", gnm_style_get_font_bold (style
));
545 if (gnm_style_is_element_set (style
, MSTYLE_FONT_ITALIC
))
546 gsf_xml_out_add_int (state
->output
, "Italic", gnm_style_get_font_italic (style
));
547 if (gnm_style_is_element_set (style
, MSTYLE_FONT_UNDERLINE
))
548 gsf_xml_out_add_int (state
->output
, "Underline", (int)gnm_style_get_font_uline (style
));
549 if (gnm_style_is_element_set (style
, MSTYLE_FONT_STRIKETHROUGH
))
550 gsf_xml_out_add_int (state
->output
, "StrikeThrough", gnm_style_get_font_strike (style
));
551 if (gnm_style_is_element_set (style
, MSTYLE_FONT_SCRIPT
))
552 gsf_xml_out_add_int (state
->output
, "Script", (int)gnm_style_get_font_script (style
));
554 if (gnm_style_is_element_set (style
, MSTYLE_FONT_NAME
)) {
555 const char *fontname
= gnm_style_get_font_name (style
);
556 gsf_xml_out_add_cstr (state
->output
, NULL
, fontname
);
559 gsf_xml_out_end_element (state
->output
);
562 if (gnm_style_is_element_set (style
, MSTYLE_HLINK
) &&
563 NULL
!= (lnk
= gnm_style_get_hlink (style
))) {
564 gsf_xml_out_start_element (state
->output
, GNM
"HyperLink");
565 gsf_xml_out_add_cstr (state
->output
, "type", g_type_name (G_OBJECT_TYPE (lnk
)));
566 gsf_xml_out_add_cstr (state
->output
, "target", gnm_hlink_get_target (lnk
));
567 if (gnm_hlink_get_tip (lnk
) != NULL
)
568 gsf_xml_out_add_cstr (state
->output
, "tip", gnm_hlink_get_tip (lnk
));
569 gsf_xml_out_end_element (state
->output
);
572 if (gnm_style_is_element_set (style
, MSTYLE_VALIDATION
) &&
573 NULL
!= (v
= gnm_style_get_validation (style
))) {
577 gsf_xml_out_start_element (state
->output
, GNM
"Validation");
578 gsf_xml_out_add_enum (state
->output
, "Style",
579 GNM_VALIDATION_STYLE_TYPE
, v
->style
);
580 gsf_xml_out_add_enum (state
->output
, "Type",
581 GNM_VALIDATION_TYPE_TYPE
, v
->type
);
584 case GNM_VALIDATION_TYPE_AS_INT
:
585 case GNM_VALIDATION_TYPE_AS_NUMBER
:
586 case GNM_VALIDATION_TYPE_AS_DATE
:
587 case GNM_VALIDATION_TYPE_AS_TIME
:
588 case GNM_VALIDATION_TYPE_TEXT_LENGTH
:
589 gsf_xml_out_add_enum (state
->output
, "Operator",
590 GNM_VALIDATION_OP_TYPE
, v
->op
);
596 gsf_xml_out_add_bool (state
->output
, "AllowBlank", v
->allow_blank
);
597 gsf_xml_out_add_bool (state
->output
, "UseDropdown", v
->use_dropdown
);
599 if (v
->title
!= NULL
&& v
->title
->str
[0] != '\0')
600 gsf_xml_out_add_cstr (state
->output
, "Title", v
->title
->str
);
601 if (v
->msg
!= NULL
&& v
->msg
->str
[0] != '\0')
602 gsf_xml_out_add_cstr (state
->output
, "Message", v
->msg
->str
);
604 parse_pos_init_sheet (&pp
, (Sheet
*)state
->sheet
);
606 if (v
->deps
[0].texpr
!= NULL
&&
607 (tmp
= gnm_expr_top_as_string (v
->deps
[0].texpr
, &pp
, state
->convs
)) != NULL
) {
608 gsf_xml_out_simple_element (state
->output
, GNM
"Expression0", tmp
);
611 if (v
->deps
[1].texpr
!= NULL
&&
612 (tmp
= gnm_expr_top_as_string (v
->deps
[1].texpr
, &pp
, state
->convs
)) != NULL
) {
613 gsf_xml_out_simple_element (state
->output
, GNM
"Expression1", tmp
);
616 gsf_xml_out_end_element (state
->output
); /* </Validation> */
619 if (gnm_style_is_element_set (style
, MSTYLE_INPUT_MSG
) &&
620 NULL
!= (im
= gnm_style_get_input_msg (style
))) {
622 gsf_xml_out_start_element (state
->output
, GNM
"InputMessage");
623 if (NULL
!= (txt
= gnm_input_msg_get_title (im
)))
624 gsf_xml_out_add_cstr (state
->output
, "Title", txt
);
625 if (NULL
!= (txt
= gnm_input_msg_get_msg (im
)))
626 gsf_xml_out_add_cstr (state
->output
, "Message", txt
);
627 gsf_xml_out_end_element (state
->output
); /* </InputMessage> */
630 if (gnm_style_is_element_set (style
, MSTYLE_CONDITIONS
) &&
631 NULL
!= (sc
= gnm_style_get_conditions (style
))) {
632 GPtrArray
const *conds
= gnm_style_conditions_details (sc
);
635 parse_pos_init_sheet (&pp
, (Sheet
*)state
->sheet
);
637 for (i
= 0 ; i
< conds
->len
; i
++) {
639 GnmStyleCond
const *cond
=
640 g_ptr_array_index (conds
, i
);
641 gsf_xml_out_start_element (state
->output
, GNM
"Condition");
642 gsf_xml_out_add_int (state
->output
, "Operator", cond
->op
);
643 for (ui
= 0; ui
< 2; ui
++) {
644 GnmExprTop
const *texpr
= gnm_style_cond_get_expr (cond
, ui
);
646 ? gnm_expr_top_as_string (texpr
, &pp
, state
->convs
)
648 const char *attr
= (ui
== 0)
652 gsf_xml_out_simple_element (state
->output
, attr
, tmp
);
656 xml_write_style (state
, cond
->overlay
);
657 gsf_xml_out_end_element (state
->output
); /* </Condition> */
663 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; i
++) {
664 GnmBorder
const *border
;
665 if (gnm_style_is_element_set (style
, i
) &&
666 NULL
!= (border
= gnm_style_get_border (style
, i
)) &&
667 GNM_STYLE_BORDER_NONE
!= (t
= border
->line_type
)) {
668 GnmColor
const *col
= border
->color
;
671 gsf_xml_out_start_element (state
->output
, GNM
"StyleBorder");
675 gsf_xml_out_start_element (state
->output
,
676 border_names
[i
- MSTYLE_BORDER_TOP
]);
677 gsf_xml_out_add_int (state
->output
, "Style", t
);
678 gnm_xml_out_add_color (state
->output
, "Color", col
);
679 gsf_xml_out_end_element (state
->output
);
683 gsf_xml_out_end_element (state
->output
);
685 gsf_xml_out_end_element (state
->output
);
689 xml_write_style_region (GnmOutputXML
*state
, GnmStyleRegion
const *region
)
691 gsf_xml_out_start_element (state
->output
, GNM
"StyleRegion");
692 xml_out_add_range (state
->output
, ®ion
->range
);
693 if (region
->style
!= NULL
)
694 xml_write_style (state
, region
->style
);
695 gsf_xml_out_end_element (state
->output
);
699 cb_sheet_style_order (GnmStyleRegion
const *a
, GnmStyleRegion
const *b
)
701 GnmRange
const *ra
= &a
->range
;
702 GnmRange
const *rb
= &b
->range
;
705 res
= ra
->start
.col
- rb
->start
.col
;
708 res
= ra
->start
.row
- rb
->start
.row
;
714 xml_write_styles (GnmOutputXML
*state
)
716 GnmStyleList
*styles
=
717 g_slist_sort (sheet_style_get_range (state
->sheet
, NULL
),
718 (GCompareFunc
)cb_sheet_style_order
);
719 if (styles
!= NULL
) {
722 gsf_xml_out_start_element (state
->output
, GNM
"Styles");
723 for (ptr
= styles
; ptr
; ptr
= ptr
->next
)
724 xml_write_style_region (state
, ptr
->data
);
725 gsf_xml_out_end_element (state
->output
);
726 style_list_free (styles
);
734 int prev_pos
, rle_count
;
735 GnmCellRegion
const *cr
;
736 } closure_write_colrow
;
739 xml_write_colrow_info (GnmColRowIter
const *iter
, closure_write_colrow
*closure
)
741 ColRowInfo
const *prev
= &closure
->prev
;
742 GsfXMLOut
*output
= closure
->state
->output
;
743 ColRowInfo
const *def
=
744 sheet_colrow_get_default (closure
->state
->sheet
,
747 closure
->rle_count
++;
748 if (NULL
!= iter
&& col_row_info_equal (prev
, iter
->cri
))
751 if (closure
->prev_pos
!= -1 && !col_row_info_equal (prev
, def
)) {
752 if (closure
->is_column
)
753 gsf_xml_out_start_element (output
, GNM
"ColInfo");
755 gsf_xml_out_start_element (output
, GNM
"RowInfo");
757 gsf_xml_out_add_int (output
, "No", closure
->prev_pos
);
758 xml_out_add_points (output
, "Unit", prev
->size_pts
);
760 gsf_xml_out_add_bool (output
, "HardSize", TRUE
);
762 gsf_xml_out_add_bool (output
, "Hidden", TRUE
);
763 if (prev
->is_collapsed
)
764 gsf_xml_out_add_bool (output
, "Collapsed", TRUE
);
765 if (prev
->outline_level
> 0)
766 gsf_xml_out_add_int (output
, "OutlineLevel", prev
->outline_level
);
768 if (closure
->rle_count
> 1)
769 gsf_xml_out_add_int (output
, "Count", closure
->rle_count
);
770 gsf_xml_out_end_element (output
);
773 closure
->rle_count
= 0;
775 closure
->prev
= *iter
->cri
;
776 closure
->prev_pos
= iter
->pos
;
783 xml_write_cols_rows (GnmOutputXML
*state
, GnmCellRegion
const *cr
)
785 const Sheet
*sheet
= state
->sheet
;
788 for (i
= 0; i
< 2; i
++) {
789 closure_write_colrow closure
;
790 gboolean is_cols
= (i
== 0);
792 gsf_xml_out_start_element (state
->output
,
793 is_cols
? GNM
"Cols" : GNM
"Rows");
797 (state
->output
, "DefaultSizePts",
798 sheet_colrow_get_default (sheet
, is_cols
)->size_pts
);
800 closure
.state
= state
;
802 closure
.is_column
= is_cols
;
803 memset (&closure
.prev
, 0, sizeof (closure
.prev
));
804 closure
.prev_pos
= -1;
805 closure
.rle_count
= 0;
807 colrow_state_list_foreach
808 (is_cols
? cr
->col_state
: cr
->row_state
,
810 is_cols
? cr
->base
.col
: cr
->base
.row
,
811 (ColRowHandler
)&xml_write_colrow_info
,
815 (sheet
, is_cols
, 0, -1,
816 (ColRowHandler
)&xml_write_colrow_info
,
818 xml_write_colrow_info (NULL
, &closure
); /* flush */
819 gsf_xml_out_end_element (state
->output
); /* </gnm:Cols> */
824 xml_write_selection_info (GnmOutputXML
*state
)
827 SheetView
const *sv
= sheet_get_view (state
->sheet
, state
->wb_view
);
828 if (!sv
) return; /* Hidden. */
830 gsf_xml_out_start_element (state
->output
, GNM
"Selections");
831 gsf_xml_out_add_int (state
->output
, "CursorCol", sv
->edit_pos_real
.col
);
832 gsf_xml_out_add_int (state
->output
, "CursorRow", sv
->edit_pos_real
.row
);
834 /* Insert the selections in REVERSE order */
835 copy
= g_slist_reverse (g_slist_copy (sv
->selections
));
836 for (ptr
= copy
; ptr
; ptr
= ptr
->next
) {
837 GnmRange
const *r
= ptr
->data
;
838 gsf_xml_out_start_element (state
->output
, GNM
"Selection");
839 xml_out_add_range (state
->output
, r
);
840 gsf_xml_out_end_element (state
->output
); /* </gnm:Selection> */
844 gsf_xml_out_end_element (state
->output
); /* </gnm:Selections> */
848 xml_write_cell_and_position (GnmOutputXML
*state
,
849 GnmExprTop
const *texpr
, GnmValue
const *val
,
850 GnmParsePos
const *pp
)
852 gboolean write_contents
= TRUE
;
853 gboolean
const is_shared_expr
= (texpr
!= NULL
) &&
854 gnm_expr_top_is_shared (texpr
);
856 /* Only the top left corner of an array needs to be saved (>= 0.53) */
857 if (texpr
&& gnm_expr_top_is_array_elem (texpr
, NULL
, NULL
))
858 return; /* DOM version would write <Cell Col= Row=/> */
860 gsf_xml_out_start_element (state
->output
, GNM
"Cell");
861 gsf_xml_out_add_int (state
->output
, "Row", pp
->eval
.row
);
862 gsf_xml_out_add_int (state
->output
, "Col", pp
->eval
.col
);
864 /* As of version 0.53 we save the ID of shared expressions */
865 if (is_shared_expr
) {
866 gpointer id
= g_hash_table_lookup (state
->expr_map
, (gpointer
) texpr
);
869 id
= GINT_TO_POINTER (g_hash_table_size (state
->expr_map
) + 1);
870 g_hash_table_insert (state
->expr_map
, (gpointer
)texpr
, id
);
872 write_contents
= FALSE
;
874 gsf_xml_out_add_int (state
->output
, "ExprID", GPOINTER_TO_INT (id
));
877 /* As of version 0.53 we save the size of the array as attributes */
878 /* As of version 0.57 the attributes are in the Cell not the Content */
879 if (texpr
&& gnm_expr_top_is_array_corner (texpr
)) {
881 gnm_expr_top_get_array_size (texpr
, &cols
, &rows
);
882 gsf_xml_out_add_int (state
->output
, "Rows", rows
);
883 gsf_xml_out_add_int (state
->output
, "Cols", cols
);
886 if (write_contents
) {
887 gboolean write_value
= !texpr
|| state
->write_value_result
;
888 GString
*str
= state
->cell_str
;
890 g_string_truncate (str
, 0);
894 gsf_xml_out_add_int (state
->output
, "ValueType", val
->v_any
.type
);
895 if (VALUE_FMT (val
) != NULL
) {
896 const char *fmt
= go_format_as_XL (VALUE_FMT (val
));
897 gsf_xml_out_add_cstr (state
->output
, "ValueFormat", fmt
);
899 value_get_as_gstring (val
, str
, state
->convs
);
901 gsf_xml_out_add_cstr (state
->output
, "Value", str
->str
);
902 g_string_truncate (str
, 0);
905 g_warning ("%s has no value ?", cellpos_as_string (&pp
->eval
));
910 GnmConventionsOut out
;
913 out
.convs
= state
->convs
;
915 g_string_append_c (str
, '=');
916 gnm_expr_top_as_gstring (texpr
, &out
);
919 gsf_xml_out_add_cstr (state
->output
, NULL
, str
->str
);
921 gsf_xml_out_end_element (state
->output
); /* </gnm:Cell> */
925 cb_write_cell (GnmCellIter
const *iter
, GnmOutputXML
*state
)
927 GnmExprTop
const *texpr
= iter
->cell
->base
.texpr
;
928 GnmValue
const *value
= iter
->cell
->value
;
930 if (texpr
== NULL
&& VALUE_IS_EMPTY (value
))
933 xml_write_cell_and_position (state
, texpr
, value
, &iter
->pp
);
938 xml_write_cells (GnmOutputXML
*state
)
940 gsf_xml_out_start_element (state
->output
, GNM
"Cells");
941 sheet_foreach_cell_in_region ((Sheet
*)state
->sheet
,
942 CELL_ITER_IGNORE_NONEXISTENT
,
944 (CellIterFunc
) cb_write_cell
, state
);
945 gsf_xml_out_end_element (state
->output
); /* </gnm:Cells> */
949 xml_write_merged_regions (GnmOutputXML
*state
)
951 GSList
*ptr
= state
->sheet
->list_merged
;
954 gsf_xml_out_start_element (state
->output
, GNM
"MergedRegions");
955 for (; ptr
!= NULL
; ptr
= ptr
->next
)
956 gsf_xml_out_simple_element (state
->output
,
957 GNM
"Merge", range_as_string (ptr
->data
));
958 gsf_xml_out_end_element (state
->output
); /* </gnm:MergedRegions> */
962 xml_write_sheet_layout (GnmOutputXML
*state
)
964 SheetView
const *sv
= sheet_get_view (state
->sheet
, state
->wb_view
);
965 if (!sv
) return; /* Hidden. */
967 gsf_xml_out_start_element (state
->output
, GNM
"SheetLayout");
968 gnm_xml_out_add_cellpos (state
->output
, "TopLeft", &sv
->initial_top_left
);
970 if (gnm_sheet_view_is_frozen (sv
)) {
971 gsf_xml_out_start_element (state
->output
, GNM
"FreezePanes");
972 gnm_xml_out_add_cellpos (state
->output
, "FrozenTopLeft", &sv
->frozen_top_left
);
973 gnm_xml_out_add_cellpos (state
->output
, "UnfrozenTopLeft", &sv
->unfrozen_top_left
);
974 gsf_xml_out_end_element (state
->output
); /* </gnm:FreezePanes> */
976 gsf_xml_out_end_element (state
->output
); /* </gnm:SheetLayout> */
980 xml_write_filter_expr (GnmOutputXML
*state
,
981 GnmFilterCondition
const *cond
, unsigned i
)
983 static char const *filter_cond_name
[] = { "eq", "gt", "lt", "gte", "lte", "ne" };
985 * WARNING WARNING WARING
986 * Value and ValueType are _reversed !!!
988 static struct { char const *op
, *valtype
, *val
; } filter_expr_attrs
[] = {
989 { "Op0", "Value0", "ValueType0" },
990 { "Op1", "Value1", "ValueType1" }
993 GString
*text
= g_string_new (NULL
);
994 value_get_as_gstring (cond
->value
[i
], text
, state
->convs
);
995 gsf_xml_out_add_cstr_unchecked (state
->output
,
996 filter_expr_attrs
[i
].op
, filter_cond_name
[cond
->op
[i
]]);
997 gsf_xml_out_add_int (state
->output
,
998 filter_expr_attrs
[i
].valtype
, cond
->value
[i
]->v_any
.type
);
999 gsf_xml_out_add_cstr (state
->output
,
1000 filter_expr_attrs
[i
].val
, text
->str
);
1001 g_string_free (text
, TRUE
);
1005 xml_write_filter_field (GnmOutputXML
*state
,
1006 GnmFilterCondition
const *cond
, unsigned i
)
1008 gsf_xml_out_start_element (state
->output
, GNM
"Field");
1009 gsf_xml_out_add_int (state
->output
, "Index", i
);
1011 switch (GNM_FILTER_OP_TYPE_MASK
& cond
->op
[0]) {
1012 case 0: gsf_xml_out_add_cstr_unchecked (state
->output
, "Type", "expr");
1013 xml_write_filter_expr (state
, cond
, 0);
1014 if (cond
->op
[1] != GNM_FILTER_UNUSED
) {
1015 xml_write_filter_expr (state
, cond
, 1);
1016 gsf_xml_out_add_bool (state
->output
, "IsAnd", cond
->is_and
);
1019 case GNM_FILTER_OP_BLANKS
:
1020 gsf_xml_out_add_cstr_unchecked (state
->output
, "Type", "blanks");
1022 case GNM_FILTER_OP_NON_BLANKS
:
1023 gsf_xml_out_add_cstr_unchecked (state
->output
, "Type", "nonblanks");
1025 case GNM_FILTER_OP_TOP_N
:
1026 gsf_xml_out_add_cstr_unchecked (state
->output
, "Type", "bucket");
1027 gsf_xml_out_add_bool (state
->output
, "top",
1028 cond
->op
[0] & 1 ? TRUE
: FALSE
);
1029 gsf_xml_out_add_bool (state
->output
, "items",
1030 cond
->op
[0] & 2 ? TRUE
: FALSE
);
1031 go_xml_out_add_double (state
->output
, "count", cond
->count
);
1035 gsf_xml_out_end_element (state
->output
); /* </gnm:Field> */
1039 xml_write_sheet_filters (GnmOutputXML
*state
)
1043 GnmFilterCondition
const *cond
;
1046 if (state
->sheet
->filters
== NULL
)
1049 gsf_xml_out_start_element (state
->output
, GNM
"Filters");
1051 for (ptr
= state
->sheet
->filters
; ptr
!= NULL
; ptr
= ptr
->next
) {
1053 gsf_xml_out_start_element (state
->output
, GNM
"Filter");
1054 gsf_xml_out_add_cstr_unchecked (state
->output
, "Area",
1055 range_as_string (&filter
->r
));
1057 for (i
= filter
->fields
->len
; i
-- > 0 ; ) {
1058 cond
= gnm_filter_get_condition (filter
, i
);
1059 if (cond
!= NULL
&& cond
->op
[0] != GNM_FILTER_UNUSED
)
1060 xml_write_filter_field (state
, cond
, i
);
1063 gsf_xml_out_end_element (state
->output
); /* </gnm:Filter> */
1066 gsf_xml_out_end_element (state
->output
); /* </gnm:Filters> */
1070 xml_write_solver (GnmOutputXML
*state
)
1072 GnmSolverParameters
*param
= state
->sheet
->solver_parameters
;
1074 GnmCellRef
const *target
;
1075 GnmValue
const *input
;
1080 gsf_xml_out_start_element (state
->output
, GNM
"Solver");
1082 target
= gnm_solver_param_get_target (param
);
1083 if (target
!= NULL
) {
1084 GnmExpr
const *expr
= gnm_expr_new_cellref (target
);
1086 char *txt
= gnm_expr_as_string
1088 parse_pos_init_sheet (&pp
, state
->sheet
),
1090 gsf_xml_out_add_cstr (state
->output
, "Target", txt
);
1092 gnm_expr_free (expr
);
1095 gsf_xml_out_add_int (state
->output
, "ModelType", param
->options
.model_type
);
1096 gsf_xml_out_add_int (state
->output
, "ProblemType", param
->problem_type
);
1097 input
= gnm_solver_param_get_input (param
);
1099 gsf_xml_out_add_cstr (state
->output
, "Inputs",
1100 value_peek_string (input
));
1101 gsf_xml_out_add_int (state
->output
, "MaxTime",
1102 param
->options
.max_time_sec
);
1103 gsf_xml_out_add_int (state
->output
, "MaxIter",
1104 param
->options
.max_iter
);
1105 gsf_xml_out_add_bool (state
->output
, "NonNeg",
1106 param
->options
.assume_non_negative
);
1107 gsf_xml_out_add_bool (state
->output
, "Discr",
1108 param
->options
.assume_discrete
);
1109 gsf_xml_out_add_bool (state
->output
, "AutoScale",
1110 param
->options
.automatic_scaling
);
1111 gsf_xml_out_add_bool (state
->output
, "ProgramR",
1112 param
->options
.program_report
);
1113 gsf_xml_out_add_bool (state
->output
, "SensitivityR",
1114 param
->options
.sensitivity_report
);
1116 for (ptr
= param
->constraints
; ptr
!= NULL
; ptr
= ptr
->next
) {
1117 GnmSolverConstraint
const *c
= ptr
->data
;
1119 GString
*str
= g_string_new (NULL
);
1121 /* Historical values. Not a bit field. */
1123 default: type
= 0; break;
1124 case GNM_SOLVER_LE
: type
= 1; break;
1125 case GNM_SOLVER_GE
: type
= 2; break;
1126 case GNM_SOLVER_EQ
: type
= 4; break;
1127 case GNM_SOLVER_INTEGER
: type
= 8; break;
1128 case GNM_SOLVER_BOOLEAN
: type
= 16; break;
1131 gsf_xml_out_start_element (state
->output
, GNM
"Constr");
1132 gsf_xml_out_add_int (state
->output
, "Type", type
);
1134 gnm_solver_constraint_side_as_str (c
, state
->sheet
, str
, TRUE
);
1135 gsf_xml_out_add_cstr (state
->output
, "lhs", str
->str
);
1137 if (gnm_solver_constraint_has_rhs (c
)) {
1138 g_string_truncate (str
, 0);
1139 gnm_solver_constraint_side_as_str (c
, state
->sheet
,
1141 gsf_xml_out_add_cstr (state
->output
, "rhs", str
->str
);
1144 gsf_xml_out_end_element (state
->output
); /* </gnm:Constr> */
1146 g_string_free (str
, TRUE
);
1149 gsf_xml_out_end_element (state
->output
); /* </gnm:Solver> */
1153 xml_write_scenario (GnmOutputXML
*state
, GnmScenario
const *sc
)
1158 parse_pos_init_sheet (&pp
, sc
->sheet
);
1160 gsf_xml_out_start_element (state
->output
, GNM
"Scenario");
1162 gsf_xml_out_add_cstr (state
->output
, "Name", sc
->name
);
1164 gsf_xml_out_add_cstr (state
->output
, "Comment", sc
->comment
);
1166 for (l
= sc
->items
; l
; l
= l
->next
) {
1167 GnmScenarioItem
const *sci
= l
->data
;
1168 GnmValue
const *val
= sci
->value
;
1170 GnmConventionsOut out
;
1172 if (!gnm_scenario_item_valid (sci
, NULL
))
1175 str
= g_string_new (NULL
);
1176 gsf_xml_out_start_element (state
->output
, GNM
"Item");
1180 out
.convs
= state
->convs
;
1182 gnm_expr_top_as_gstring (sci
->dep
.texpr
, &out
);
1183 gsf_xml_out_add_cstr (state
->output
, "Range", str
->str
);
1186 gsf_xml_out_add_int (state
->output
,
1189 if (VALUE_FMT (val
) != NULL
) {
1190 const char *fmt
= go_format_as_XL (VALUE_FMT (val
));
1191 gsf_xml_out_add_cstr (state
->output
, "ValueFormat", fmt
);
1193 g_string_truncate (str
, 0);
1194 value_get_as_gstring (val
, str
, state
->convs
);
1195 gsf_xml_out_add_cstr (state
->output
, NULL
, str
->str
);
1198 gsf_xml_out_end_element (state
->output
); /* </gnm:Item> */
1199 g_string_free (str
, TRUE
);
1202 gsf_xml_out_end_element (state
->output
); /* </gnm:Scenario> */
1207 xml_write_scenarios (GnmOutputXML
*state
)
1211 if (state
->sheet
->scenarios
== NULL
)
1214 gsf_xml_out_start_element (state
->output
, GNM
"Scenarios");
1216 for (ptr
= state
->sheet
->scenarios
; ptr
!= NULL
; ptr
= ptr
->next
) {
1217 GnmScenario
const *sc
= ptr
->data
;
1218 xml_write_scenario (state
, sc
);
1221 gsf_xml_out_end_element (state
->output
); /* </gnm:Scenarios> */
1225 so_by_pos (SheetObject
*a
, SheetObject
*b
)
1227 GnmRange
const *ra
= &a
->anchor
.cell_bound
;
1228 GnmRange
const *rb
= &b
->anchor
.cell_bound
;
1230 i
= ra
->start
.col
- rb
->start
.col
;
1231 if (!i
) i
= ra
->start
.row
- rb
->start
.row
;
1232 if (!i
) i
= ra
->end
.col
- rb
->end
.col
;
1233 if (!i
) i
= ra
->end
.row
- rb
->end
.row
;
1238 xml_write_objects (GnmOutputXML
*state
, GSList
*objects
)
1240 gboolean needs_container
= TRUE
;
1241 char buffer
[4*(DBL_DIG
+10)];
1242 char const *type_name
;
1245 GSList
*with_zorder
= NULL
;
1246 GSList
*without_zorder
= NULL
;
1249 * Most objects are selectable and the order therefore matters.
1250 * We write those in reverse order because sheet_object_set_sheet
1251 * will reverse them on input.
1253 * Cell comments are separated out and sorted. This helps
1256 * Yet other objects have no export method and we drop those on
1259 for (ptr
= objects
;ptr
!= NULL
; ptr
= ptr
->next
) {
1260 SheetObject
*so
= ptr
->data
;
1261 SheetObjectClass
*klass
= GNM_SO_CLASS (G_OBJECT_GET_CLASS (so
));
1262 if (klass
== NULL
|| klass
->write_xml_sax
== NULL
)
1265 if (GNM_IS_CELL_COMMENT (so
))
1266 without_zorder
= g_slist_prepend (without_zorder
, so
);
1268 with_zorder
= g_slist_prepend (with_zorder
, so
);
1270 without_zorder
= g_slist_sort (without_zorder
, (GCompareFunc
)so_by_pos
);
1271 objects
= g_slist_concat (without_zorder
, with_zorder
);
1273 for (ptr
= objects
;ptr
!= NULL
; ptr
= ptr
->next
) {
1274 SheetObject
*so
= ptr
->data
;
1275 SheetObjectClass
*klass
= GNM_SO_CLASS (G_OBJECT_GET_CLASS (so
));
1276 GnmRange cell_bound
= so
->anchor
.cell_bound
;
1278 switch (so
->anchor
.mode
) {
1279 case GNM_SO_ANCHOR_TWO_CELLS
:
1281 case GNM_SO_ANCHOR_ONE_CELL
:
1282 cell_bound
.end
= cell_bound
.start
;
1284 case GNM_SO_ANCHOR_ABSOLUTE
:
1285 range_init (&cell_bound
, 0, 0, 0, 0);
1288 g_assert_not_reached ();
1291 if (needs_container
) {
1292 needs_container
= FALSE
;
1293 gsf_xml_out_start_element (state
->output
, GNM
"Objects");
1296 /* A hook so that things can sometimes change names */
1297 type_name
= klass
->xml_export_name
;
1298 if (type_name
== NULL
)
1299 type_name
= G_OBJECT_TYPE_NAME (so
);
1301 tmp
= g_strconcat (GNM
, type_name
, NULL
);
1302 gsf_xml_out_start_element (state
->output
, tmp
);
1304 gsf_xml_out_add_cstr (state
->output
, "Name", so
->name
);
1305 if (so
->anchor
.mode
!= GNM_SO_ANCHOR_ABSOLUTE
)
1306 gsf_xml_out_add_cstr (state
->output
, "ObjectBound", range_as_string (&cell_bound
));
1307 if (so
->anchor
.mode
!= GNM_SO_ANCHOR_TWO_CELLS
)
1308 gsf_xml_out_add_enum (state
->output
,
1310 GNM_SHEET_OBJECT_ANCHOR_MODE_TYPE
,
1312 snprintf (buffer
, sizeof (buffer
), "%.3g %.3g %.3g %.3g",
1313 so
->anchor
.offset
[0], so
->anchor
.offset
[1],
1314 so
->anchor
.offset
[2], so
->anchor
.offset
[3]);
1315 gsf_xml_out_add_cstr (state
->output
, "ObjectOffset", buffer
);
1317 gsf_xml_out_add_int (state
->output
, "Direction",
1318 so
->anchor
.base
.direction
);
1320 (state
->output
, "Print",
1321 (so
->flags
& SHEET_OBJECT_PRINT
) ? 1 : 0);
1323 (*klass
->write_xml_sax
) (so
, state
->output
, state
->convs
);
1325 gsf_xml_out_end_element (state
->output
); /* </gnm:{typename}> */
1328 g_slist_free (objects
);
1330 if (!needs_container
)
1331 gsf_xml_out_end_element (state
->output
); /* </gnm:Objects> */
1335 xml_write_sheet (GnmOutputXML
*state
, Sheet
const *sheet
)
1339 state
->sheet
= sheet
;
1340 gsf_xml_out_start_element (state
->output
, GNM
"Sheet");
1342 gsf_xml_out_add_bool (state
->output
,
1343 "DisplayFormulas", sheet
->display_formulas
);
1344 gsf_xml_out_add_bool (state
->output
,
1345 "HideZero", sheet
->hide_zero
);
1346 gsf_xml_out_add_bool (state
->output
,
1347 "HideGrid", sheet
->hide_grid
);
1348 gsf_xml_out_add_bool (state
->output
,
1349 "HideColHeader", sheet
->hide_col_header
);
1350 gsf_xml_out_add_bool (state
->output
,
1351 "HideRowHeader", sheet
->hide_row_header
);
1352 gsf_xml_out_add_bool (state
->output
,
1353 "DisplayOutlines", sheet
->display_outlines
);
1354 gsf_xml_out_add_bool (state
->output
,
1355 "OutlineSymbolsBelow", sheet
->outline_symbols_below
);
1356 gsf_xml_out_add_bool (state
->output
,
1357 "OutlineSymbolsRight", sheet
->outline_symbols_right
);
1358 if (sheet
->text_is_rtl
)
1359 gsf_xml_out_add_bool (state
->output
,
1360 "RTL_Layout", sheet
->text_is_rtl
);
1361 if (sheet
->is_protected
)
1362 gsf_xml_out_add_bool (state
->output
,
1363 "Protected", sheet
->is_protected
);
1365 /* TODO : Make this an enum internally eventually */
1366 if (sheet
->convs
->r1c1_addresses
)
1367 gsf_xml_out_add_cstr_unchecked (state
->output
,
1368 "ExprConvention", "gnumeric:R1C1");
1370 gsf_xml_out_add_enum (state
->output
,
1371 "Visibility", GNM_SHEET_VISIBILITY_TYPE
, sheet
->visibility
);
1373 if (sheet
->tab_color
!= NULL
)
1374 gnm_xml_out_add_color (state
->output
, "TabColor", sheet
->tab_color
);
1375 if (sheet
->tab_text_color
!= NULL
)
1376 gnm_xml_out_add_color (state
->output
, "TabTextColor", sheet
->tab_text_color
);
1377 if (NULL
!= (c
= sheet_style_get_auto_pattern_color (sheet
))) {
1378 gnm_xml_out_add_color (state
->output
, "GridColor", c
);
1379 style_color_unref (c
);
1382 gsf_xml_out_simple_element (state
->output
,
1383 GNM
"Name", sheet
->name_unquoted
);
1384 gsf_xml_out_simple_int_element (state
->output
,
1385 GNM
"MaxCol", sheet
->cols
.max_used
);
1386 gsf_xml_out_simple_int_element (state
->output
,
1387 GNM
"MaxRow", sheet
->rows
.max_used
);
1388 gsf_xml_out_simple_float_element (state
->output
,
1389 GNM
"Zoom", sheet
->last_zoom_factor_used
, 4);
1391 xml_write_named_expressions (state
, sheet
->names
);
1392 xml_write_print_info (state
, sheet
->print_info
);
1393 xml_write_styles (state
);
1394 xml_write_cols_rows (state
, NULL
);
1395 xml_write_selection_info (state
);
1396 xml_write_objects (state
, sheet
->sheet_objects
);
1397 xml_write_cells (state
);
1399 xml_write_merged_regions (state
);
1400 xml_write_sheet_layout (state
);
1401 xml_write_sheet_filters (state
);
1402 xml_write_solver (state
);
1403 xml_write_scenarios (state
);
1405 gsf_xml_out_end_element (state
->output
); /* </gnm:Sheet> */
1406 state
->sheet
= NULL
;
1410 xml_write_sheets (GnmOutputXML
*state
)
1412 int i
, n
= workbook_sheet_count (state
->wb
);
1413 gsf_xml_out_start_element (state
->output
, GNM
"Sheets");
1414 for (i
= 0 ; i
< n
; i
++)
1415 xml_write_sheet (state
, workbook_sheet_by_index (state
->wb
, i
));
1416 gsf_xml_out_end_element (state
->output
); /* </gnm:Sheets> */
1420 xml_write_uidata (GnmOutputXML
*state
)
1422 gsf_xml_out_start_element (state
->output
, GNM
"UIData");
1423 gsf_xml_out_add_int (state
->output
, "SelectedTab",
1424 wb_view_cur_sheet (state
->wb_view
)->index_in_wb
);
1425 gsf_xml_out_end_element (state
->output
); /* </gnm:UIData> */
1429 xml_write_date_conventions_as_attr (GnmOutputXML
*state
,
1430 GODateConventions
const *conv
)
1433 gsf_xml_out_add_cstr_unchecked (state
->output
,
1434 GNM
"DateConvention", "Apple:1904");
1438 xml_write_number_system (GnmOutputXML
*state
)
1441 * These numbers define how to interpret decimal values in the
1442 * file. They are not yet used, but should be used when the
1443 * number system of the loading Gnumeric is different from the
1444 * number system of the saving Gnumeric.
1446 gsf_xml_out_add_int (state
->output
, "FloatRadix", FLT_RADIX
);
1447 gsf_xml_out_add_int (state
->output
, "FloatDigits", GNM_MANT_DIG
);
1452 xml_write_calculation (GnmOutputXML
*state
)
1454 gsf_xml_out_start_element (state
->output
, GNM
"Calculation");
1455 gsf_xml_out_add_bool (state
->output
,
1456 "ManualRecalc", !state
->wb
->recalc_auto
);
1457 gsf_xml_out_add_bool (state
->output
,
1458 "EnableIteration", state
->wb
->iteration
.enabled
);
1459 gsf_xml_out_add_int (state
->output
,
1460 "MaxIterations", state
->wb
->iteration
.max_number
);
1461 go_xml_out_add_double (state
->output
,
1462 "IterationTolerance", state
->wb
->iteration
.tolerance
);
1463 xml_write_date_conventions_as_attr (state
,
1464 workbook_date_conv (state
->wb
));
1465 xml_write_number_system (state
);
1466 gsf_xml_out_end_element (state
->output
); /* </gnm:Calculation> */
1470 gnm_xml_io_conventions (void)
1472 GnmConventions
*res
= gnm_conventions_new ();
1475 res
->decimal_sep_dot
= TRUE
;
1476 res
->input
.range_ref
= rangeref_parse
;
1477 res
->output
.range_ref
= gnm_1_0_rangeref_as_string
;
1478 res
->range_sep_colon
= TRUE
;
1480 res
->array_col_sep
= ',';
1481 res
->array_row_sep
= ';';
1482 res
->output
.translated
= FALSE
;
1484 l10
= gnm_log10 (FLT_RADIX
);
1485 res
->output
.decimal_digits
= (int)gnm_ceil (GNM_MANT_DIG
* l10
) +
1486 (l10
== (int)l10
? 0 : 1);
1492 gnm_xml_file_save_full (G_GNUC_UNUSED GOFileSaver
const *fs
,
1493 G_GNUC_UNUSED GOIOContext
*io_context
,
1494 GoView
const *view
, GsfOutput
*output
,
1498 GsfOutput
*gzout
= NULL
;
1500 WorkbookView
*wb_view
= GNM_WORKBOOK_VIEW (view
);
1503 gzout
= gsf_output_gzip_new (output
, NULL
);
1507 state
.wb_view
= wb_view
;
1508 state
.wb
= wb_view_get_workbook (wb_view
);
1510 state
.output
= gsf_xml_out_new (output
);
1511 state
.convs
= gnm_xml_io_conventions ();
1512 state
.expr_map
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1513 state
.cell_str
= g_string_new (NULL
);
1514 state
.write_value_result
= FALSE
;
1515 go_doc_init_write (GO_DOC (state
.wb
), state
.output
);
1517 locale
= gnm_push_C_locale ();
1519 gsf_xml_out_start_element (state
.output
, GNM
"Workbook");
1522 * As long as we want older versions of Gnumeric to be able to read
1523 * the files we produce, we should not increase the version number
1524 * in the file we write. Until 1.12.21, v10 was the highest listed
1525 * xml-sax-read.c's content_ns.
1527 gsf_xml_out_add_cstr_unchecked (state
.output
, "xmlns:gnm",
1528 "http://www.gnumeric.org/v10.dtd");
1529 #if 0 /* seems to break meta data */
1530 /* default namespace added for 1.8 */
1531 gsf_xml_out_add_cstr_unchecked (state
.output
, "xmlns",
1532 "http://www.gnumeric.org/v10.dtd");
1534 gsf_xml_out_add_cstr_unchecked (state
.output
, "xmlns:xsi",
1535 "http://www.w3.org/2001/XMLSchema-instance");
1536 gsf_xml_out_add_cstr_unchecked (state
.output
, "xsi:schemaLocation",
1537 "http://www.gnumeric.org/v9.xsd");
1539 xml_write_version (&state
);
1540 xml_write_attributes (&state
);
1541 xml_write_meta_data (&state
);
1542 xml_write_conventions (&state
); /* DEPRECATED, moved to Calculation */
1543 xml_write_calculation (&state
);
1544 xml_write_sheet_names (&state
);
1545 xml_write_named_expressions (&state
, state
.wb
->names
);
1546 xml_write_geometry (&state
);
1547 xml_write_sheets (&state
);
1548 xml_write_uidata (&state
);
1549 go_doc_write (GO_DOC (state
.wb
), state
.output
);
1551 gsf_xml_out_end_element (state
.output
); /* </Workbook> */
1553 gnm_pop_C_locale (locale
);
1555 g_hash_table_destroy (state
.expr_map
);
1556 g_string_free (state
.cell_str
, TRUE
);
1557 gnm_conventions_unref (state
.convs
);
1558 g_object_unref (state
.output
);
1561 gsf_output_close (gzout
);
1562 g_object_unref (gzout
);
1567 gnm_xml_file_save (GOFileSaver
const *fs
, GOIOContext
*io_context
,
1568 GoView
const *view
, GsfOutput
*output
)
1571 char const *extension
= NULL
;
1573 /* If the suffix is .xml disable compression */
1574 if (NULL
!= gsf_output_name (output
))
1575 extension
= gsf_extension_pointer (gsf_output_name (output
));
1576 if (NULL
!= extension
&& g_ascii_strcasecmp (extension
, "xml") == 0)
1579 compress
= (gnm_conf_get_core_xml_compression_level () > 0);
1581 gnm_xml_file_save_full (fs
, io_context
, view
, output
, compress
);
1585 gnm_xml_file_save_xml (GOFileSaver
const *fs
, GOIOContext
*io_context
,
1586 GoView
const *view
, GsfOutput
*output
)
1588 gnm_xml_file_save_full (fs
, io_context
, view
, output
, FALSE
);
1591 /**************************************************************************/
1595 GnmCellRegion
const *cr
;
1600 cb_xml_write_cell_region_cells (GnmCellCopy
*cc
,
1601 G_GNUC_UNUSED gconstpointer ignore
,
1602 XMLCellCopyState
*state
)
1604 state
->pp
.eval
.col
= state
->cr
->base
.col
+ cc
->offset
.col
;
1605 state
->pp
.eval
.row
= state
->cr
->base
.row
+ cc
->offset
.row
;
1606 xml_write_cell_and_position (&state
->state
,
1607 cc
->texpr
, cc
->val
, &state
->pp
);
1611 * gnm_cellregion_to_xml:
1612 * @cr: the content to store.
1614 * Returns: (transfer full): %NULL on error
1617 gnm_cellregion_to_xml (GnmCellRegion
const *cr
)
1619 XMLCellCopyState state
;
1620 GnmStyleList
*s_ptr
;
1622 GsfOutput
*buf
= gsf_output_memory_new ();
1626 g_return_val_if_fail (cr
!= NULL
, NULL
);
1627 g_return_val_if_fail (IS_SHEET (cr
->origin_sheet
), NULL
);
1629 state
.state
.wb_view
= NULL
;
1630 state
.state
.wb
= NULL
;
1631 state
.state
.sheet
= cr
->origin_sheet
;
1632 state
.state
.output
= gsf_xml_out_new (buf
);
1633 state
.state
.convs
= gnm_xml_io_conventions ();
1634 state
.state
.expr_map
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1635 state
.state
.cell_str
= g_string_new (NULL
);
1636 state
.state
.write_value_result
= TRUE
;
1638 locale
= gnm_push_C_locale ();
1639 if (cr
->origin_sheet
) {
1640 /* hoping this always occur */
1641 doc
= GO_DOC (cr
->origin_sheet
->workbook
);
1642 go_doc_init_write (doc
, state
.state
.output
);
1645 gsf_xml_out_start_element (state
.state
.output
, GNM
"ClipboardRange");
1647 /* backwards compat, must be first */
1648 gsf_xml_out_add_cstr_unchecked (state
.state
.output
, "xmlns:gnm",
1649 "http://www.gnumeric.org/v10.dtd");
1650 /* default namespace added for 1.8 */
1651 gsf_xml_out_add_cstr_unchecked (state
.state
.output
, "xmlns",
1652 "http://www.gnumeric.org/v10.dtd");
1654 gsf_xml_out_add_int (state
.state
.output
, "Cols", cr
->cols
);
1655 gsf_xml_out_add_int (state
.state
.output
, "Rows", cr
->rows
);
1656 gsf_xml_out_add_int (state
.state
.output
, "BaseCol", cr
->base
.col
);
1657 gsf_xml_out_add_int (state
.state
.output
, "BaseRow", cr
->base
.row
);
1658 if (cr
->origin_sheet
)
1659 xml_write_date_conventions_as_attr
1661 sheet_date_conv (cr
->origin_sheet
));
1662 xml_write_number_system (&state
.state
);
1663 if (cr
->not_as_contents
)
1664 gsf_xml_out_add_bool (state
.state
.output
, "NotAsContent", TRUE
);
1666 xml_write_cols_rows (&state
.state
, cr
);
1668 if (cr
->styles
!= NULL
) {
1669 gsf_xml_out_start_element (state
.state
.output
, GNM
"Styles");
1670 for (s_ptr
= cr
->styles
; s_ptr
!= NULL
; s_ptr
= s_ptr
->next
)
1671 xml_write_style_region (&state
.state
, s_ptr
->data
);
1672 gsf_xml_out_end_element (state
.state
.output
); /* </Styles> */
1675 if (cr
->merged
!= NULL
) {
1676 gsf_xml_out_start_element (state
.state
.output
, GNM
"MergedRegions");
1677 for (ptr
= cr
->merged
; ptr
!= NULL
; ptr
= ptr
->next
) {
1678 gsf_xml_out_start_element (state
.state
.output
, GNM
"Merge");
1679 gsf_xml_out_add_cstr_unchecked (state
.state
.output
, NULL
,
1680 range_as_string (ptr
->data
));
1681 gsf_xml_out_end_element (state
.state
.output
); /* </Merge> */
1683 gsf_xml_out_end_element (state
.state
.output
); /* </gnm:MergedRegions> */
1686 /* NOTE SNEAKY : ensure that sheet names have explicit workbooks */
1688 state
.pp
.sheet
= cr
->origin_sheet
;
1690 if (cr
->cell_content
!= NULL
) {
1691 gsf_xml_out_start_element (state
.state
.output
, GNM
"Cells");
1692 g_hash_table_foreach (cr
->cell_content
,
1693 (GHFunc
) cb_xml_write_cell_region_cells
, &state
);
1694 gsf_xml_out_end_element (state
.state
.output
); /* </Cells> */
1697 xml_write_objects (&state
.state
, cr
->objects
);
1700 go_doc_write (doc
, state
.state
.output
);
1701 gsf_xml_out_end_element (state
.state
.output
); /* </ClipboardRange> */
1703 gnm_pop_C_locale (locale
);
1705 g_hash_table_destroy (state
.state
.expr_map
);
1706 g_string_free (state
.state
.cell_str
, TRUE
);
1707 gnm_conventions_unref (state
.state
.convs
);
1708 g_object_unref (state
.state
.output
);
1710 gsf_output_close (buf
);
1712 return GSF_OUTPUT_MEMORY (buf
);
1715 #define XML_SAX_ID "Gnumeric_XmlIO:sax"
1716 #define XML_SAX_ID_0 "Gnumeric_XmlIO:sax:0"
1719 gnm_xml_sax_write_init (void)
1721 GOFileSaver
*saver
= go_file_saver_new
1724 _("Gnumeric XML (*.gnumeric)"),
1725 GO_FILE_FL_AUTO
, gnm_xml_file_save
);
1726 g_object_set (G_OBJECT (saver
),
1727 "mime-type", "application/x-gnumeric",
1730 go_file_saver_register_as_default (saver
, 50);
1731 g_object_unref (saver
);
1733 saver
= go_file_saver_new
1736 _("Gnumeric XML uncompressed (*.xml)"),
1737 GO_FILE_FL_AUTO
, gnm_xml_file_save_xml
);
1738 g_object_set (G_OBJECT (saver
),
1739 "mime-type", "application/xml",
1742 go_file_saver_register (saver
);
1743 g_object_unref (saver
);
1747 gnm_xml_sax_write_shutdown (void)
1749 go_file_saver_unregister (go_file_saver_for_id (XML_SAX_ID
));
1750 go_file_saver_unregister (go_file_saver_for_id (XML_SAX_ID_0
));