3 * xml-sax-write.c : export .gnumeric and the clipboard subset using the sax
4 * like wrappers in libgsf
6 * Copyright (C) 2003-2007 Jody Goldberg (jody@gnome.org)
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) version 3.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
24 /*****************************************************************************/
26 #include <gnumeric-config.h>
28 #include <glib/gi18n-lib.h>
30 #include <workbook-view.h>
31 #include <gnm-format.h>
33 #include <workbook-priv.h> /* Workbook::names */
36 #include <sheet-view.h>
37 #include <sheet-style.h>
38 #include <style-color.h>
39 #include <style-conditions.h>
41 #include <expr-name.h>
45 #include <style-border.h>
46 #include <validation.h>
48 #include <input-msg.h>
49 #include <tools/gnm-solver.h>
50 #include <sheet-filter.h>
51 #include <sheet-object-impl.h>
52 #include <sheet-object-cell-comment.h>
53 #include <print-info.h>
55 #include <clipboard.h>
56 #include <tools/scenarios.h>
57 #include <gnumeric-conf.h>
59 #include <goffice/goffice.h>
60 #include <gsf/gsf-libxml.h>
61 #include <gsf/gsf-output-gzip.h>
62 #include <gsf/gsf-doc-meta-data.h>
63 #include <gsf/gsf-opendoc-utils.h>
64 #include <gsf/gsf-utils.h>
67 WorkbookView
const *wb_view
; /* View for the new workbook */
68 Workbook
const *wb
; /* The new workbook */
70 GnmConventions
*convs
;
72 GString
*cell_str
; /* Scratch pad. */
74 // Do we write result values? For now this is clipboard only
75 gboolean write_value_result
;
82 /* Precision to use when saving point measures. */
83 #define POINT_SIZE_PRECISION 4
86 gnm_xml_out_add_gocolor (GsfXMLOut
*o
, char const *id
, GOColor c
)
89 * This uses format "rrrr:gggg:bbbb" or "rrrr:gggg:bbbb:aaaa"
90 * using hex numbers, i.e., the numbers are in the range from
93 * Note, that while go_xml_out_add_color exists, we cannot use
94 * it as it using a 0-255 scaling and always includes alpha.
97 char buf
[4 * 4 * sizeof (unsigned int) + 1];
99 GO_COLOR_TO_RGBA (c
, &r
, &g
, &b
, &a
);
101 sprintf (buf
, "%X:%X:%X%c%X",
102 r
* 0x101, g
* 0x101, b
* 0x101,
103 (a
== 0xff ? 0 : ':'),
105 gsf_xml_out_add_cstr_unchecked (o
, id
, buf
);
109 gnm_xml_out_add_color (GsfXMLOut
*o
, char const *id
, GnmColor
const *c
)
111 gnm_xml_out_add_gocolor (o
, id
, c
->go_color
);
115 gnm_xml_out_add_cellpos (GsfXMLOut
*o
, char const *id
, GnmCellPos
const *p
)
117 g_return_if_fail (p
!= NULL
);
118 gsf_xml_out_add_cstr_unchecked (o
, id
, cellpos_as_string (p
));
122 xml_out_add_range (GsfXMLOut
*xml
, GnmRange
const *r
)
124 g_return_if_fail (range_is_sane (r
));
126 gsf_xml_out_add_int (xml
, "startCol", r
->start
.col
);
127 gsf_xml_out_add_int (xml
, "startRow", r
->start
.row
);
128 gsf_xml_out_add_int (xml
, "endCol", r
->end
.col
);
129 gsf_xml_out_add_int (xml
, "endRow", r
->end
.row
);
133 xml_out_add_points (GsfXMLOut
*xml
, char const *name
, double val
)
135 gsf_xml_out_add_float (xml
, name
, val
, POINT_SIZE_PRECISION
);
139 xml_write_boolean_attribute (GnmOutputXML
*state
, char const *name
, gboolean value
)
141 gsf_xml_out_start_element (state
->output
, GNM
"Attribute");
142 gsf_xml_out_simple_element (state
->output
, GNM
"name", name
);
143 gsf_xml_out_simple_element (state
->output
, GNM
"value", value
? "TRUE" : "FALSE");
144 gsf_xml_out_end_element (state
->output
); /* </Attribute> */
148 xml_write_version (GnmOutputXML
*state
)
150 gsf_xml_out_start_element (state
->output
, GNM
"Version");
151 gsf_xml_out_add_int (state
->output
, "Epoch", GNM_VERSION_EPOCH
);
152 gsf_xml_out_add_int (state
->output
, "Major", GNM_VERSION_MAJOR
);
153 gsf_xml_out_add_int (state
->output
, "Minor", GNM_VERSION_MINOR
);
154 gsf_xml_out_add_cstr_unchecked (state
->output
, "Full", GNM_VERSION_FULL
);
155 gsf_xml_out_end_element (state
->output
); /* </Version> */
159 xml_write_attributes (GnmOutputXML
*state
)
161 gsf_xml_out_start_element (state
->output
, GNM
"Attributes");
162 xml_write_boolean_attribute
163 (state
, "WorkbookView::show_horizontal_scrollbar",
164 state
->wb_view
->show_horizontal_scrollbar
);
165 xml_write_boolean_attribute
166 (state
, "WorkbookView::show_vertical_scrollbar",
167 state
->wb_view
->show_vertical_scrollbar
);
168 xml_write_boolean_attribute
169 (state
, "WorkbookView::show_notebook_tabs",
170 state
->wb_view
->show_notebook_tabs
);
171 xml_write_boolean_attribute
172 (state
, "WorkbookView::do_auto_completion",
173 state
->wb_view
->do_auto_completion
);
174 xml_write_boolean_attribute
175 (state
, "WorkbookView::is_protected",
176 state
->wb_view
->is_protected
);
177 gsf_xml_out_end_element (state
->output
); /* </Attributes> */
181 xml_write_meta_data (GnmOutputXML
*state
)
183 gsf_doc_meta_data_write_to_odf (go_doc_get_meta_data (GO_DOC (state
->wb
)),
187 /* DEPRECATED in 1.7.11 */
189 xml_write_conventions (GnmOutputXML
*state
)
191 GODateConventions
const *conv
= workbook_date_conv (state
->wb
);
193 gsf_xml_out_simple_element (state
->output
, GNM
"DateConvention", "1904");
197 xml_write_sheet_names (GnmOutputXML
*state
)
199 int i
, n
= workbook_sheet_count (state
->wb
);
202 gsf_xml_out_start_element (state
->output
, GNM
"SheetNameIndex");
203 for (i
= 0 ; i
< n
; i
++) {
204 sheet
= workbook_sheet_by_index (state
->wb
, i
);
205 gsf_xml_out_start_element (state
->output
, GNM
"SheetName");
208 * Note, that we explicitly namespace these attributes.
209 * That is not wrong, per se, but note that Gnumeric until
210 * 1.12.22 will not read files without this explicit name-
211 * space and that the abbreviation must be "gnm".
213 if (sheet
->sheet_type
== GNM_SHEET_OBJECT
)
214 gsf_xml_out_add_cstr (state
->output
, GNM
"SheetType", "object");
215 gsf_xml_out_add_int (state
->output
, GNM
"Cols",
216 gnm_sheet_get_max_cols (sheet
));
217 gsf_xml_out_add_int (state
->output
, GNM
"Rows",
218 gnm_sheet_get_max_rows (sheet
));
219 gsf_xml_out_add_cstr (state
->output
, NULL
, sheet
->name_unquoted
);
220 gsf_xml_out_end_element (state
->output
); /* </gnm:SheetName> */
222 gsf_xml_out_end_element (state
->output
); /* </gnm:SheetNameIndex> */
226 xml_write_name (GnmOutputXML
*state
, GnmNamedExpr
*nexpr
)
230 g_return_if_fail (nexpr
!= NULL
);
232 gsf_xml_out_start_element (state
->output
, GNM
"Name");
233 gsf_xml_out_simple_element (state
->output
, GNM
"name",
234 expr_name_name (nexpr
));
235 expr_str
= expr_name_as_string (nexpr
, NULL
, state
->convs
);
236 gsf_xml_out_simple_element (state
->output
, GNM
"value", expr_str
);
238 gsf_xml_out_simple_element (state
->output
, GNM
"position",
239 cellpos_as_string (&nexpr
->pos
.eval
));
240 gsf_xml_out_end_element (state
->output
); /* </gnm:Name> */
244 xml_write_named_expressions (GnmOutputXML
*state
, GnmNamedExprCollection
*scope
)
247 g_slist_sort (gnm_named_expr_collection_list (scope
),
248 (GCompareFunc
)expr_name_cmp_by_name
);
254 gsf_xml_out_start_element (state
->output
, GNM
"Names");
255 for (p
= names
; p
; p
= p
->next
) {
256 GnmNamedExpr
*nexpr
= p
->data
;
257 xml_write_name (state
, nexpr
);
259 gsf_xml_out_end_element (state
->output
); /* </gnm:Names> */
260 g_slist_free (names
);
264 xml_write_geometry (GnmOutputXML
*state
)
266 if (state
->wb_view
->preferred_width
> 0 ||
267 state
->wb_view
->preferred_height
> 0) {
268 gsf_xml_out_start_element (state
->output
, GNM
"Geometry");
269 gsf_xml_out_add_int (state
->output
, "Width", state
->wb_view
->preferred_width
);
270 gsf_xml_out_add_int (state
->output
, "Height", state
->wb_view
->preferred_height
);
271 gsf_xml_out_end_element (state
->output
); /* </gnm:Geometry> */
276 xml_write_print_unit (GnmOutputXML
*state
, char const *name
,
277 double points
, GtkUnit unit
)
279 gsf_xml_out_start_element (state
->output
, name
);
280 xml_out_add_points (state
->output
, "Points", points
);
281 gsf_xml_out_add_cstr_unchecked (state
->output
, "PrefUnit",
282 unit_to_unit_name (unit
));
283 gsf_xml_out_end_element (state
->output
);
287 xml_write_print_repeat_range (GnmOutputXML
*state
,
291 if (range
&& *range
) {
292 gsf_xml_out_start_element (state
->output
, name
);
293 gsf_xml_out_add_cstr_unchecked (state
->output
, "value", range
);
294 gsf_xml_out_end_element (state
->output
);
299 xml_write_print_hf (GnmOutputXML
*state
, char const *name
,
300 GnmPrintHF
const *hf
)
302 gsf_xml_out_start_element (state
->output
, name
);
303 gsf_xml_out_add_cstr (state
->output
, "Left", hf
->left_format
);
304 gsf_xml_out_add_cstr (state
->output
, "Middle", hf
->middle_format
);
305 gsf_xml_out_add_cstr (state
->output
, "Right", hf
->right_format
);
306 gsf_xml_out_end_element (state
->output
);
311 xml_write_breaks (GnmOutputXML
*state
, GnmPageBreaks
*breaks
)
313 GArray
const *details
= breaks
->details
;
314 GnmPageBreak
const *binfo
;
317 gsf_xml_out_start_element (state
->output
,
318 (breaks
->is_vert
) ? GNM
"vPageBreaks" : GNM
"hPageBreaks");
319 gsf_xml_out_add_int (state
->output
, "count", details
->len
);
321 for (i
= 0 ; i
< details
->len
; i
++) {
322 binfo
= &g_array_index (details
, GnmPageBreak
, i
);
323 gsf_xml_out_start_element (state
->output
, GNM
"break");
324 gsf_xml_out_add_int (state
->output
, "pos", binfo
->pos
);
325 if (binfo
->type
== GNM_PAGE_BREAK_MANUAL
)
326 gsf_xml_out_add_cstr_unchecked (state
->output
, "type", "manual");
327 else if (binfo
->type
== GNM_PAGE_BREAK_DATA_SLICE
)
328 gsf_xml_out_add_cstr_unchecked (state
->output
, "type", "data-slice");
329 else if (binfo
->type
== GNM_PAGE_BREAK_AUTO
)
330 gsf_xml_out_add_cstr_unchecked (state
->output
, "type", "auto");
331 gsf_xml_out_end_element (state
->output
); /* </break> */
333 gsf_xml_out_end_element (state
->output
);
337 xml_write_print_info (GnmOutputXML
*state
, GnmPrintInformation
*pi
)
345 double edge_to_above_footer
;
346 double edge_to_below_header
;
347 GtkPageOrientation orient
;
349 g_return_if_fail (pi
!= NULL
);
351 gsf_xml_out_start_element (state
->output
, GNM
"PrintInformation");
353 gsf_xml_out_start_element (state
->output
, GNM
"Margins");
355 print_info_get_margins (pi
, &header
, &footer
, &left
, &right
,
356 &edge_to_below_header
, &edge_to_above_footer
);
357 xml_write_print_unit (state
, GNM
"top", edge_to_below_header
,
358 pi
->desired_display
.header
);
359 xml_write_print_unit (state
, GNM
"bottom", edge_to_above_footer
,
360 pi
->desired_display
.footer
);
361 xml_write_print_unit (state
, GNM
"left", left
,
362 pi
->desired_display
.left
);
363 xml_write_print_unit (state
, GNM
"right", right
,
364 pi
->desired_display
.right
);
365 xml_write_print_unit (state
, GNM
"header", header
,
366 pi
->desired_display
.top
);
367 xml_write_print_unit (state
, GNM
"footer", footer
,
368 pi
->desired_display
.bottom
);
369 gsf_xml_out_end_element (state
->output
);
371 gsf_xml_out_start_element (state
->output
, GNM
"Scale");
372 if (pi
->scaling
.type
== PRINT_SCALE_PERCENTAGE
) {
373 gsf_xml_out_add_cstr_unchecked (state
->output
, "type", "percentage");
374 go_xml_out_add_double (state
->output
, "percentage", pi
->scaling
.percentage
.x
);
376 gsf_xml_out_add_cstr_unchecked (state
->output
, "type", "size_fit");
377 go_xml_out_add_double (state
->output
, "cols", pi
->scaling
.dim
.cols
);
378 go_xml_out_add_double (state
->output
, "rows", pi
->scaling
.dim
.rows
);
380 gsf_xml_out_end_element (state
->output
);
382 gsf_xml_out_start_element (state
->output
, GNM
"vcenter");
383 gsf_xml_out_add_int (state
->output
, "value", pi
->center_vertically
);
384 gsf_xml_out_end_element (state
->output
);
386 gsf_xml_out_start_element (state
->output
, GNM
"hcenter");
387 gsf_xml_out_add_int (state
->output
, "value", pi
->center_horizontally
);
388 gsf_xml_out_end_element (state
->output
);
390 gsf_xml_out_start_element (state
->output
, GNM
"grid");
391 gsf_xml_out_add_int (state
->output
, "value", pi
->print_grid_lines
);
392 gsf_xml_out_end_element (state
->output
);
394 gsf_xml_out_start_element (state
->output
, GNM
"even_if_only_styles");
395 gsf_xml_out_add_int (state
->output
, "value", pi
->print_even_if_only_styles
);
396 gsf_xml_out_end_element (state
->output
);
398 gsf_xml_out_start_element (state
->output
, GNM
"monochrome");
399 gsf_xml_out_add_int (state
->output
, "value", pi
->print_black_and_white
);
400 gsf_xml_out_end_element (state
->output
);
402 gsf_xml_out_start_element (state
->output
, GNM
"draft");
403 gsf_xml_out_add_int (state
->output
, "value", pi
->print_as_draft
);
404 gsf_xml_out_end_element (state
->output
);
406 gsf_xml_out_start_element (state
->output
, GNM
"titles");
407 gsf_xml_out_add_int (state
->output
, "value", pi
->print_titles
);
408 gsf_xml_out_end_element (state
->output
);
410 gsf_xml_out_start_element (state
->output
, GNM
"do_not_print");
411 gsf_xml_out_add_int (state
->output
, "value", pi
->do_not_print
);
412 gsf_xml_out_end_element (state
->output
);
414 gsf_xml_out_start_element (state
->output
, GNM
"print_range");
415 gsf_xml_out_add_enum (state
->output
, "value",
416 GNM_PRINT_RANGE_TYPE
,
417 print_info_get_printrange (pi
) );
418 gsf_xml_out_end_element (state
->output
);
420 xml_write_print_repeat_range (state
, GNM
"repeat_top", pi
->repeat_top
);
421 xml_write_print_repeat_range (state
, GNM
"repeat_left", pi
->repeat_left
);
423 /* this was once an enum, hence the silly strings */
424 gsf_xml_out_simple_element (state
->output
, GNM
"order",
425 pi
->print_across_then_down
? "r_then_d" :"d_then_r");
427 orient
= print_info_get_paper_orientation (pi
);
428 gsf_xml_out_simple_element (state
->output
, GNM
"orientation",
429 (orient
== GTK_PAGE_ORIENTATION_PORTRAIT
430 || orient
== GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT
)
431 ? "portrait" : "landscape");
432 #warning TODO: we should also handle inversion
434 xml_write_print_hf (state
, GNM
"Header", pi
->header
);
435 xml_write_print_hf (state
, GNM
"Footer", pi
->footer
);
437 paper_name
= print_info_get_paper (pi
);
439 gsf_xml_out_simple_element (state
->output
, GNM
"paper",
443 uri
= print_info_get_printtofile_uri (pi
);
445 gsf_xml_out_simple_element (state
->output
, GNM
"print-to-uri",
448 if (NULL
!= pi
->page_breaks
.v
)
449 xml_write_breaks (state
, pi
->page_breaks
.v
);
450 if (NULL
!= pi
->page_breaks
.h
)
451 xml_write_breaks (state
, pi
->page_breaks
.h
);
453 gsf_xml_out_start_element (state
->output
, GNM
"comments");
454 gsf_xml_out_add_enum (state
->output
, "placement",
455 GNM_PRINT_COMMENT_PLACEMENT_TYPE
,
456 pi
->comment_placement
);
457 gsf_xml_out_end_element (state
->output
);
459 gsf_xml_out_start_element (state
->output
, GNM
"errors");
460 gsf_xml_out_add_enum (state
->output
, "PrintErrorsAs",
461 GNM_PRINT_ERRORS_TYPE
,
463 gsf_xml_out_end_element (state
->output
);
465 gsf_xml_out_end_element (state
->output
);
469 xml_write_style (GnmOutputXML
*state
, GnmStyle
const *style
)
471 static char const *border_names
[] = {
479 GnmValidation
const *v
;
481 GnmInputMsg
const *im
;
482 GnmStyleConditions
const *sc
;
483 GnmStyleBorderType t
;
487 gsf_xml_out_start_element (state
->output
, GNM
"Style");
489 if (gnm_style_is_element_set (style
, MSTYLE_ALIGN_H
))
490 gsf_xml_out_add_enum (state
->output
, "HAlign",
492 gnm_style_get_align_h (style
));
493 if (gnm_style_is_element_set (style
, MSTYLE_ALIGN_V
))
494 gsf_xml_out_add_enum (state
->output
, "VAlign",
496 gnm_style_get_align_v (style
));
497 if (gnm_style_is_element_set (style
, MSTYLE_WRAP_TEXT
))
498 gsf_xml_out_add_bool (state
->output
, "WrapText",
499 gnm_style_get_wrap_text (style
));
500 if (gnm_style_is_element_set (style
, MSTYLE_SHRINK_TO_FIT
))
501 gsf_xml_out_add_bool (state
->output
, "ShrinkToFit",
502 gnm_style_get_shrink_to_fit (style
));
503 if (gnm_style_is_element_set (style
, MSTYLE_ROTATION
))
504 gsf_xml_out_add_int (state
->output
, "Rotation",
505 gnm_style_get_rotation (style
));
506 if (gnm_style_is_element_set (style
, MSTYLE_PATTERN
))
507 gsf_xml_out_add_int (state
->output
, "Shade",
508 gnm_style_get_pattern (style
));
509 if (gnm_style_is_element_set (style
, MSTYLE_INDENT
))
510 gsf_xml_out_add_int (state
->output
, "Indent", gnm_style_get_indent (style
));
511 if (gnm_style_is_element_set (style
, MSTYLE_CONTENTS_LOCKED
))
512 gsf_xml_out_add_bool (state
->output
, "Locked",
513 gnm_style_get_contents_locked (style
));
514 if (gnm_style_is_element_set (style
, MSTYLE_CONTENTS_HIDDEN
))
515 gsf_xml_out_add_bool (state
->output
, "Hidden",
516 gnm_style_get_contents_hidden (style
));
517 if (gnm_style_is_element_set (style
, MSTYLE_FONT_COLOR
))
518 gnm_xml_out_add_color (state
->output
, "Fore",
519 gnm_style_get_font_color (style
));
520 if (gnm_style_is_element_set (style
, MSTYLE_COLOR_BACK
))
521 gnm_xml_out_add_color (state
->output
, "Back",
522 gnm_style_get_back_color (style
));
523 if (gnm_style_is_element_set (style
, MSTYLE_COLOR_PATTERN
))
524 gnm_xml_out_add_color (state
->output
, "PatternColor",
525 gnm_style_get_pattern_color (style
));
526 if (gnm_style_is_element_set (style
, MSTYLE_FORMAT
)) {
527 const char *fmt
= go_format_as_XL (gnm_style_get_format (style
));
528 gsf_xml_out_add_cstr (state
->output
, "Format", fmt
);
531 if (gnm_style_is_element_set (style
, MSTYLE_FONT_NAME
) ||
532 gnm_style_is_element_set (style
, MSTYLE_FONT_SIZE
) ||
533 gnm_style_is_element_set (style
, MSTYLE_FONT_BOLD
) ||
534 gnm_style_is_element_set (style
, MSTYLE_FONT_ITALIC
) ||
535 gnm_style_is_element_set (style
, MSTYLE_FONT_UNDERLINE
) ||
536 gnm_style_is_element_set (style
, MSTYLE_FONT_STRIKETHROUGH
) ||
537 gnm_style_is_element_set (style
, MSTYLE_FONT_SCRIPT
)) {
538 gsf_xml_out_start_element (state
->output
, GNM
"Font");
540 if (gnm_style_is_element_set (style
, MSTYLE_FONT_SIZE
))
541 xml_out_add_points (state
->output
, "Unit", gnm_style_get_font_size (style
));
542 if (gnm_style_is_element_set (style
, MSTYLE_FONT_BOLD
))
543 gsf_xml_out_add_int (state
->output
, "Bold", gnm_style_get_font_bold (style
));
544 if (gnm_style_is_element_set (style
, MSTYLE_FONT_ITALIC
))
545 gsf_xml_out_add_int (state
->output
, "Italic", gnm_style_get_font_italic (style
));
546 if (gnm_style_is_element_set (style
, MSTYLE_FONT_UNDERLINE
))
547 gsf_xml_out_add_int (state
->output
, "Underline", (int)gnm_style_get_font_uline (style
));
548 if (gnm_style_is_element_set (style
, MSTYLE_FONT_STRIKETHROUGH
))
549 gsf_xml_out_add_int (state
->output
, "StrikeThrough", gnm_style_get_font_strike (style
));
550 if (gnm_style_is_element_set (style
, MSTYLE_FONT_SCRIPT
))
551 gsf_xml_out_add_int (state
->output
, "Script", (int)gnm_style_get_font_script (style
));
553 if (gnm_style_is_element_set (style
, MSTYLE_FONT_NAME
)) {
554 const char *fontname
= gnm_style_get_font_name (style
);
555 gsf_xml_out_add_cstr (state
->output
, NULL
, fontname
);
558 gsf_xml_out_end_element (state
->output
);
561 if (gnm_style_is_element_set (style
, MSTYLE_HLINK
) &&
562 NULL
!= (lnk
= gnm_style_get_hlink (style
))) {
563 gsf_xml_out_start_element (state
->output
, GNM
"HyperLink");
564 gsf_xml_out_add_cstr (state
->output
, "type", g_type_name (G_OBJECT_TYPE (lnk
)));
565 gsf_xml_out_add_cstr (state
->output
, "target", gnm_hlink_get_target (lnk
));
566 if (gnm_hlink_get_tip (lnk
) != NULL
)
567 gsf_xml_out_add_cstr (state
->output
, "tip", gnm_hlink_get_tip (lnk
));
568 gsf_xml_out_end_element (state
->output
);
571 if (gnm_style_is_element_set (style
, MSTYLE_VALIDATION
) &&
572 NULL
!= (v
= gnm_style_get_validation (style
))) {
576 gsf_xml_out_start_element (state
->output
, GNM
"Validation");
577 gsf_xml_out_add_enum (state
->output
, "Style",
578 GNM_VALIDATION_STYLE_TYPE
, v
->style
);
579 gsf_xml_out_add_enum (state
->output
, "Type",
580 GNM_VALIDATION_TYPE_TYPE
, v
->type
);
583 case GNM_VALIDATION_TYPE_AS_INT
:
584 case GNM_VALIDATION_TYPE_AS_NUMBER
:
585 case GNM_VALIDATION_TYPE_AS_DATE
:
586 case GNM_VALIDATION_TYPE_AS_TIME
:
587 case GNM_VALIDATION_TYPE_TEXT_LENGTH
:
588 gsf_xml_out_add_enum (state
->output
, "Operator",
589 GNM_VALIDATION_OP_TYPE
, v
->op
);
595 gsf_xml_out_add_bool (state
->output
, "AllowBlank", v
->allow_blank
);
596 gsf_xml_out_add_bool (state
->output
, "UseDropdown", v
->use_dropdown
);
598 if (v
->title
!= NULL
&& v
->title
->str
[0] != '\0')
599 gsf_xml_out_add_cstr (state
->output
, "Title", v
->title
->str
);
600 if (v
->msg
!= NULL
&& v
->msg
->str
[0] != '\0')
601 gsf_xml_out_add_cstr (state
->output
, "Message", v
->msg
->str
);
603 parse_pos_init_sheet (&pp
, (Sheet
*)state
->sheet
);
605 if (v
->deps
[0].texpr
!= NULL
&&
606 (tmp
= gnm_expr_top_as_string (v
->deps
[0].texpr
, &pp
, state
->convs
)) != NULL
) {
607 gsf_xml_out_simple_element (state
->output
, GNM
"Expression0", tmp
);
610 if (v
->deps
[1].texpr
!= NULL
&&
611 (tmp
= gnm_expr_top_as_string (v
->deps
[1].texpr
, &pp
, state
->convs
)) != NULL
) {
612 gsf_xml_out_simple_element (state
->output
, GNM
"Expression1", tmp
);
615 gsf_xml_out_end_element (state
->output
); /* </Validation> */
618 if (gnm_style_is_element_set (style
, MSTYLE_INPUT_MSG
) &&
619 NULL
!= (im
= gnm_style_get_input_msg (style
))) {
621 gsf_xml_out_start_element (state
->output
, GNM
"InputMessage");
622 if (NULL
!= (txt
= gnm_input_msg_get_title (im
)))
623 gsf_xml_out_add_cstr (state
->output
, "Title", txt
);
624 if (NULL
!= (txt
= gnm_input_msg_get_msg (im
)))
625 gsf_xml_out_add_cstr (state
->output
, "Message", txt
);
626 gsf_xml_out_end_element (state
->output
); /* </InputMessage> */
629 if (gnm_style_is_element_set (style
, MSTYLE_CONDITIONS
) &&
630 NULL
!= (sc
= gnm_style_get_conditions (style
))) {
631 GPtrArray
const *conds
= gnm_style_conditions_details (sc
);
634 parse_pos_init_sheet (&pp
, (Sheet
*)state
->sheet
);
636 for (i
= 0 ; i
< conds
->len
; i
++) {
638 GnmStyleCond
const *cond
=
639 g_ptr_array_index (conds
, i
);
640 gsf_xml_out_start_element (state
->output
, GNM
"Condition");
641 gsf_xml_out_add_int (state
->output
, "Operator", cond
->op
);
642 for (ui
= 0; ui
< 2; ui
++) {
643 GnmExprTop
const *texpr
= gnm_style_cond_get_expr (cond
, ui
);
645 ? gnm_expr_top_as_string (texpr
, &pp
, state
->convs
)
647 const char *attr
= (ui
== 0)
651 gsf_xml_out_simple_element (state
->output
, attr
, tmp
);
655 xml_write_style (state
, cond
->overlay
);
656 gsf_xml_out_end_element (state
->output
); /* </Condition> */
662 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; i
++) {
663 GnmBorder
const *border
;
664 if (gnm_style_is_element_set (style
, i
) &&
665 NULL
!= (border
= gnm_style_get_border (style
, i
)) &&
666 GNM_STYLE_BORDER_NONE
!= (t
= border
->line_type
)) {
667 GnmColor
const *col
= border
->color
;
670 gsf_xml_out_start_element (state
->output
, GNM
"StyleBorder");
674 gsf_xml_out_start_element (state
->output
,
675 border_names
[i
- MSTYLE_BORDER_TOP
]);
676 gsf_xml_out_add_int (state
->output
, "Style", t
);
677 gnm_xml_out_add_color (state
->output
, "Color", col
);
678 gsf_xml_out_end_element (state
->output
);
682 gsf_xml_out_end_element (state
->output
);
684 gsf_xml_out_end_element (state
->output
);
688 xml_write_style_region (GnmOutputXML
*state
, GnmStyleRegion
const *region
)
690 gsf_xml_out_start_element (state
->output
, GNM
"StyleRegion");
691 xml_out_add_range (state
->output
, ®ion
->range
);
692 if (region
->style
!= NULL
)
693 xml_write_style (state
, region
->style
);
694 gsf_xml_out_end_element (state
->output
);
698 cb_sheet_style_order (GnmStyleRegion
const *a
, GnmStyleRegion
const *b
)
700 GnmRange
const *ra
= &a
->range
;
701 GnmRange
const *rb
= &b
->range
;
704 res
= ra
->start
.col
- rb
->start
.col
;
707 res
= ra
->start
.row
- rb
->start
.row
;
713 xml_write_styles (GnmOutputXML
*state
)
715 GnmStyleList
*styles
=
716 g_slist_sort (sheet_style_get_range (state
->sheet
, NULL
),
717 (GCompareFunc
)cb_sheet_style_order
);
718 if (styles
!= NULL
) {
721 gsf_xml_out_start_element (state
->output
, GNM
"Styles");
722 for (ptr
= styles
; ptr
; ptr
= ptr
->next
)
723 xml_write_style_region (state
, ptr
->data
);
724 gsf_xml_out_end_element (state
->output
);
725 style_list_free (styles
);
733 int prev_pos
, rle_count
;
734 GnmCellRegion
const *cr
;
735 } closure_write_colrow
;
738 xml_write_colrow_info (GnmColRowIter
const *iter
, closure_write_colrow
*closure
)
740 ColRowInfo
const *prev
= &closure
->prev
;
741 GsfXMLOut
*output
= closure
->state
->output
;
742 ColRowInfo
const *def
=
743 sheet_colrow_get_default (closure
->state
->sheet
,
746 closure
->rle_count
++;
747 if (NULL
!= iter
&& col_row_info_equal (prev
, iter
->cri
))
750 if (closure
->prev_pos
!= -1 && !col_row_info_equal (prev
, def
)) {
751 if (closure
->is_column
)
752 gsf_xml_out_start_element (output
, GNM
"ColInfo");
754 gsf_xml_out_start_element (output
, GNM
"RowInfo");
756 gsf_xml_out_add_int (output
, "No", closure
->prev_pos
);
757 xml_out_add_points (output
, "Unit", prev
->size_pts
);
759 gsf_xml_out_add_bool (output
, "HardSize", TRUE
);
761 gsf_xml_out_add_bool (output
, "Hidden", TRUE
);
762 if (prev
->is_collapsed
)
763 gsf_xml_out_add_bool (output
, "Collapsed", TRUE
);
764 if (prev
->outline_level
> 0)
765 gsf_xml_out_add_int (output
, "OutlineLevel", prev
->outline_level
);
767 if (closure
->rle_count
> 1)
768 gsf_xml_out_add_int (output
, "Count", closure
->rle_count
);
769 gsf_xml_out_end_element (output
);
772 closure
->rle_count
= 0;
774 closure
->prev
= *iter
->cri
;
775 closure
->prev_pos
= iter
->pos
;
782 xml_write_cols_rows (GnmOutputXML
*state
, GnmCellRegion
const *cr
)
784 const Sheet
*sheet
= state
->sheet
;
787 for (i
= 0; i
< 2; i
++) {
788 closure_write_colrow closure
;
789 gboolean is_cols
= (i
== 0);
791 gsf_xml_out_start_element (state
->output
,
792 is_cols
? GNM
"Cols" : GNM
"Rows");
796 (state
->output
, "DefaultSizePts",
797 sheet_colrow_get_default (sheet
, is_cols
)->size_pts
);
799 closure
.state
= state
;
801 closure
.is_column
= is_cols
;
802 memset (&closure
.prev
, 0, sizeof (closure
.prev
));
803 closure
.prev_pos
= -1;
804 closure
.rle_count
= 0;
806 colrow_state_list_foreach
807 (is_cols
? cr
->col_state
: cr
->row_state
,
809 is_cols
? cr
->base
.col
: cr
->base
.row
,
810 (ColRowHandler
)&xml_write_colrow_info
,
814 (sheet
, is_cols
, 0, -1,
815 (ColRowHandler
)&xml_write_colrow_info
,
817 xml_write_colrow_info (NULL
, &closure
); /* flush */
818 gsf_xml_out_end_element (state
->output
); /* </gnm:Cols> */
823 xml_write_selection_info (GnmOutputXML
*state
)
826 SheetView
const *sv
= sheet_get_view (state
->sheet
, state
->wb_view
);
827 if (!sv
) return; /* Hidden. */
829 gsf_xml_out_start_element (state
->output
, GNM
"Selections");
830 gsf_xml_out_add_int (state
->output
, "CursorCol", sv
->edit_pos_real
.col
);
831 gsf_xml_out_add_int (state
->output
, "CursorRow", sv
->edit_pos_real
.row
);
833 /* Insert the selections in REVERSE order */
834 copy
= g_slist_reverse (g_slist_copy (sv
->selections
));
835 for (ptr
= copy
; ptr
; ptr
= ptr
->next
) {
836 GnmRange
const *r
= ptr
->data
;
837 gsf_xml_out_start_element (state
->output
, GNM
"Selection");
838 xml_out_add_range (state
->output
, r
);
839 gsf_xml_out_end_element (state
->output
); /* </gnm:Selection> */
843 gsf_xml_out_end_element (state
->output
); /* </gnm:Selections> */
847 xml_write_cell_and_position (GnmOutputXML
*state
,
848 GnmExprTop
const *texpr
, GnmValue
const *val
,
849 GnmParsePos
const *pp
)
851 gboolean write_contents
= TRUE
;
852 gboolean
const is_shared_expr
= (texpr
!= NULL
) &&
853 gnm_expr_top_is_shared (texpr
);
855 /* Only the top left corner of an array needs to be saved (>= 0.53) */
856 if (texpr
&& gnm_expr_top_is_array_elem (texpr
, NULL
, NULL
))
857 return; /* DOM version would write <Cell Col= Row=/> */
859 gsf_xml_out_start_element (state
->output
, GNM
"Cell");
860 gsf_xml_out_add_int (state
->output
, "Row", pp
->eval
.row
);
861 gsf_xml_out_add_int (state
->output
, "Col", pp
->eval
.col
);
863 /* As of version 0.53 we save the ID of shared expressions */
864 if (is_shared_expr
) {
865 gpointer id
= g_hash_table_lookup (state
->expr_map
, (gpointer
) texpr
);
868 id
= GINT_TO_POINTER (g_hash_table_size (state
->expr_map
) + 1);
869 g_hash_table_insert (state
->expr_map
, (gpointer
)texpr
, id
);
871 write_contents
= FALSE
;
873 gsf_xml_out_add_int (state
->output
, "ExprID", GPOINTER_TO_INT (id
));
876 /* As of version 0.53 we save the size of the array as attributes */
877 /* As of version 0.57 the attributes are in the Cell not the Content */
878 if (texpr
&& gnm_expr_top_is_array_corner (texpr
)) {
880 gnm_expr_top_get_array_size (texpr
, &cols
, &rows
);
881 gsf_xml_out_add_int (state
->output
, "Rows", rows
);
882 gsf_xml_out_add_int (state
->output
, "Cols", cols
);
885 if (write_contents
) {
886 gboolean write_value
= !texpr
|| state
->write_value_result
;
887 GString
*str
= state
->cell_str
;
889 g_string_truncate (str
, 0);
893 gsf_xml_out_add_int (state
->output
, "ValueType", val
->v_any
.type
);
894 if (VALUE_FMT (val
) != NULL
) {
895 const char *fmt
= go_format_as_XL (VALUE_FMT (val
));
896 gsf_xml_out_add_cstr (state
->output
, "ValueFormat", fmt
);
898 value_get_as_gstring (val
, str
, state
->convs
);
900 gsf_xml_out_add_cstr (state
->output
, "Value", str
->str
);
901 g_string_truncate (str
, 0);
904 g_warning ("%s has no value ?", cellpos_as_string (&pp
->eval
));
909 GnmConventionsOut out
;
912 out
.convs
= state
->convs
;
914 g_string_append_c (str
, '=');
915 gnm_expr_top_as_gstring (texpr
, &out
);
918 gsf_xml_out_add_cstr (state
->output
, NULL
, str
->str
);
920 gsf_xml_out_end_element (state
->output
); /* </gnm:Cell> */
924 cb_write_cell (GnmCellIter
const *iter
, GnmOutputXML
*state
)
926 GnmExprTop
const *texpr
= iter
->cell
->base
.texpr
;
927 GnmValue
const *value
= iter
->cell
->value
;
929 if (texpr
== NULL
&& VALUE_IS_EMPTY (value
))
932 xml_write_cell_and_position (state
, texpr
, value
, &iter
->pp
);
937 xml_write_cells (GnmOutputXML
*state
)
939 gsf_xml_out_start_element (state
->output
, GNM
"Cells");
940 sheet_foreach_cell_in_region ((Sheet
*)state
->sheet
,
941 CELL_ITER_IGNORE_NONEXISTENT
,
943 (CellIterFunc
) cb_write_cell
, state
);
944 gsf_xml_out_end_element (state
->output
); /* </gnm:Cells> */
948 xml_write_merged_regions (GnmOutputXML
*state
)
950 GSList
*ptr
= state
->sheet
->list_merged
;
953 gsf_xml_out_start_element (state
->output
, GNM
"MergedRegions");
954 for (; ptr
!= NULL
; ptr
= ptr
->next
)
955 gsf_xml_out_simple_element (state
->output
,
956 GNM
"Merge", range_as_string (ptr
->data
));
957 gsf_xml_out_end_element (state
->output
); /* </gnm:MergedRegions> */
961 xml_write_sheet_layout (GnmOutputXML
*state
)
963 SheetView
const *sv
= sheet_get_view (state
->sheet
, state
->wb_view
);
964 if (!sv
) return; /* Hidden. */
966 gsf_xml_out_start_element (state
->output
, GNM
"SheetLayout");
967 gnm_xml_out_add_cellpos (state
->output
, "TopLeft", &sv
->initial_top_left
);
969 if (gnm_sheet_view_is_frozen (sv
)) {
970 gsf_xml_out_start_element (state
->output
, GNM
"FreezePanes");
971 gnm_xml_out_add_cellpos (state
->output
, "FrozenTopLeft", &sv
->frozen_top_left
);
972 gnm_xml_out_add_cellpos (state
->output
, "UnfrozenTopLeft", &sv
->unfrozen_top_left
);
973 gsf_xml_out_end_element (state
->output
); /* </gnm:FreezePanes> */
975 gsf_xml_out_end_element (state
->output
); /* </gnm:SheetLayout> */
979 xml_write_filter_expr (GnmOutputXML
*state
,
980 GnmFilterCondition
const *cond
, unsigned i
)
982 static char const *filter_cond_name
[] = { "eq", "gt", "lt", "gte", "lte", "ne" };
984 * WARNING WARNING WARING
985 * Value and ValueType are _reversed !!!
987 static struct { char const *op
, *valtype
, *val
; } filter_expr_attrs
[] = {
988 { "Op0", "Value0", "ValueType0" },
989 { "Op1", "Value1", "ValueType1" }
992 GString
*text
= g_string_new (NULL
);
993 value_get_as_gstring (cond
->value
[i
], text
, state
->convs
);
994 gsf_xml_out_add_cstr_unchecked (state
->output
,
995 filter_expr_attrs
[i
].op
, filter_cond_name
[cond
->op
[i
]]);
996 gsf_xml_out_add_int (state
->output
,
997 filter_expr_attrs
[i
].valtype
, cond
->value
[i
]->v_any
.type
);
998 gsf_xml_out_add_cstr (state
->output
,
999 filter_expr_attrs
[i
].val
, text
->str
);
1000 g_string_free (text
, TRUE
);
1004 xml_write_filter_field (GnmOutputXML
*state
,
1005 GnmFilterCondition
const *cond
, unsigned i
)
1007 gsf_xml_out_start_element (state
->output
, GNM
"Field");
1008 gsf_xml_out_add_int (state
->output
, "Index", i
);
1010 switch (GNM_FILTER_OP_TYPE_MASK
& cond
->op
[0]) {
1011 case 0: gsf_xml_out_add_cstr_unchecked (state
->output
, "Type", "expr");
1012 xml_write_filter_expr (state
, cond
, 0);
1013 if (cond
->op
[1] != GNM_FILTER_UNUSED
) {
1014 xml_write_filter_expr (state
, cond
, 1);
1015 gsf_xml_out_add_bool (state
->output
, "IsAnd", cond
->is_and
);
1018 case GNM_FILTER_OP_BLANKS
:
1019 gsf_xml_out_add_cstr_unchecked (state
->output
, "Type", "blanks");
1021 case GNM_FILTER_OP_NON_BLANKS
:
1022 gsf_xml_out_add_cstr_unchecked (state
->output
, "Type", "nonblanks");
1024 case GNM_FILTER_OP_TOP_N
:
1025 gsf_xml_out_add_cstr_unchecked (state
->output
, "Type", "bucket");
1026 gsf_xml_out_add_bool (state
->output
, "top",
1027 cond
->op
[0] & 1 ? TRUE
: FALSE
);
1028 gsf_xml_out_add_bool (state
->output
, "items",
1029 cond
->op
[0] & 2 ? TRUE
: FALSE
);
1030 go_xml_out_add_double (state
->output
, "count", cond
->count
);
1034 gsf_xml_out_end_element (state
->output
); /* </gnm:Field> */
1038 xml_write_sheet_filters (GnmOutputXML
*state
)
1042 GnmFilterCondition
const *cond
;
1045 if (state
->sheet
->filters
== NULL
)
1048 gsf_xml_out_start_element (state
->output
, GNM
"Filters");
1050 for (ptr
= state
->sheet
->filters
; ptr
!= NULL
; ptr
= ptr
->next
) {
1052 gsf_xml_out_start_element (state
->output
, GNM
"Filter");
1053 gsf_xml_out_add_cstr_unchecked (state
->output
, "Area",
1054 range_as_string (&filter
->r
));
1056 for (i
= filter
->fields
->len
; i
-- > 0 ; ) {
1057 cond
= gnm_filter_get_condition (filter
, i
);
1058 if (cond
!= NULL
&& cond
->op
[0] != GNM_FILTER_UNUSED
)
1059 xml_write_filter_field (state
, cond
, i
);
1062 gsf_xml_out_end_element (state
->output
); /* </gnm:Filter> */
1065 gsf_xml_out_end_element (state
->output
); /* </gnm:Filters> */
1069 xml_write_solver (GnmOutputXML
*state
)
1071 GnmSolverParameters
*param
= state
->sheet
->solver_parameters
;
1073 GnmCellRef
const *target
;
1074 GnmValue
const *input
;
1079 gsf_xml_out_start_element (state
->output
, GNM
"Solver");
1081 target
= gnm_solver_param_get_target (param
);
1082 if (target
!= NULL
) {
1083 GnmExpr
const *expr
= gnm_expr_new_cellref (target
);
1085 char *txt
= gnm_expr_as_string
1087 parse_pos_init_sheet (&pp
, state
->sheet
),
1089 gsf_xml_out_add_cstr (state
->output
, "Target", txt
);
1091 gnm_expr_free (expr
);
1094 gsf_xml_out_add_int (state
->output
, "ModelType", param
->options
.model_type
);
1095 gsf_xml_out_add_int (state
->output
, "ProblemType", param
->problem_type
);
1096 input
= gnm_solver_param_get_input (param
);
1098 gsf_xml_out_add_cstr (state
->output
, "Inputs",
1099 value_peek_string (input
));
1100 gsf_xml_out_add_int (state
->output
, "MaxTime",
1101 param
->options
.max_time_sec
);
1102 gsf_xml_out_add_int (state
->output
, "MaxIter",
1103 param
->options
.max_iter
);
1104 gsf_xml_out_add_bool (state
->output
, "NonNeg",
1105 param
->options
.assume_non_negative
);
1106 gsf_xml_out_add_bool (state
->output
, "Discr",
1107 param
->options
.assume_discrete
);
1108 gsf_xml_out_add_bool (state
->output
, "AutoScale",
1109 param
->options
.automatic_scaling
);
1110 gsf_xml_out_add_bool (state
->output
, "ProgramR",
1111 param
->options
.program_report
);
1112 gsf_xml_out_add_bool (state
->output
, "SensitivityR",
1113 param
->options
.sensitivity_report
);
1115 for (ptr
= param
->constraints
; ptr
!= NULL
; ptr
= ptr
->next
) {
1116 GnmSolverConstraint
const *c
= ptr
->data
;
1118 GString
*str
= g_string_new (NULL
);
1120 /* Historical values. Not a bit field. */
1122 default: type
= 0; break;
1123 case GNM_SOLVER_LE
: type
= 1; break;
1124 case GNM_SOLVER_GE
: type
= 2; break;
1125 case GNM_SOLVER_EQ
: type
= 4; break;
1126 case GNM_SOLVER_INTEGER
: type
= 8; break;
1127 case GNM_SOLVER_BOOLEAN
: type
= 16; break;
1130 gsf_xml_out_start_element (state
->output
, GNM
"Constr");
1131 gsf_xml_out_add_int (state
->output
, "Type", type
);
1133 gnm_solver_constraint_side_as_str (c
, state
->sheet
, str
, TRUE
);
1134 gsf_xml_out_add_cstr (state
->output
, "lhs", str
->str
);
1136 if (gnm_solver_constraint_has_rhs (c
)) {
1137 g_string_truncate (str
, 0);
1138 gnm_solver_constraint_side_as_str (c
, state
->sheet
,
1140 gsf_xml_out_add_cstr (state
->output
, "rhs", str
->str
);
1143 gsf_xml_out_end_element (state
->output
); /* </gnm:Constr> */
1145 g_string_free (str
, TRUE
);
1148 gsf_xml_out_end_element (state
->output
); /* </gnm:Solver> */
1152 xml_write_scenario (GnmOutputXML
*state
, GnmScenario
const *sc
)
1157 parse_pos_init_sheet (&pp
, sc
->sheet
);
1159 gsf_xml_out_start_element (state
->output
, GNM
"Scenario");
1161 gsf_xml_out_add_cstr (state
->output
, "Name", sc
->name
);
1163 gsf_xml_out_add_cstr (state
->output
, "Comment", sc
->comment
);
1165 for (l
= sc
->items
; l
; l
= l
->next
) {
1166 GnmScenarioItem
const *sci
= l
->data
;
1167 GnmValue
const *val
= sci
->value
;
1169 GnmConventionsOut out
;
1171 if (!gnm_scenario_item_valid (sci
, NULL
))
1174 str
= g_string_new (NULL
);
1175 gsf_xml_out_start_element (state
->output
, GNM
"Item");
1179 out
.convs
= state
->convs
;
1181 gnm_expr_top_as_gstring (sci
->dep
.texpr
, &out
);
1182 gsf_xml_out_add_cstr (state
->output
, "Range", str
->str
);
1185 gsf_xml_out_add_int (state
->output
,
1188 if (VALUE_FMT (val
) != NULL
) {
1189 const char *fmt
= go_format_as_XL (VALUE_FMT (val
));
1190 gsf_xml_out_add_cstr (state
->output
, "ValueFormat", fmt
);
1192 g_string_truncate (str
, 0);
1193 value_get_as_gstring (val
, str
, state
->convs
);
1194 gsf_xml_out_add_cstr (state
->output
, NULL
, str
->str
);
1197 gsf_xml_out_end_element (state
->output
); /* </gnm:Item> */
1198 g_string_free (str
, TRUE
);
1201 gsf_xml_out_end_element (state
->output
); /* </gnm:Scenario> */
1206 xml_write_scenarios (GnmOutputXML
*state
)
1210 if (state
->sheet
->scenarios
== NULL
)
1213 gsf_xml_out_start_element (state
->output
, GNM
"Scenarios");
1215 for (ptr
= state
->sheet
->scenarios
; ptr
!= NULL
; ptr
= ptr
->next
) {
1216 GnmScenario
const *sc
= ptr
->data
;
1217 xml_write_scenario (state
, sc
);
1220 gsf_xml_out_end_element (state
->output
); /* </gnm:Scenarios> */
1224 so_by_pos (SheetObject
*a
, SheetObject
*b
)
1226 GnmRange
const *ra
= &a
->anchor
.cell_bound
;
1227 GnmRange
const *rb
= &b
->anchor
.cell_bound
;
1229 i
= ra
->start
.col
- rb
->start
.col
;
1230 if (!i
) i
= ra
->start
.row
- rb
->start
.row
;
1231 if (!i
) i
= ra
->end
.col
- rb
->end
.col
;
1232 if (!i
) i
= ra
->end
.row
- rb
->end
.row
;
1237 xml_write_objects (GnmOutputXML
*state
, GSList
*objects
)
1239 gboolean needs_container
= TRUE
;
1240 char buffer
[4*(DBL_DIG
+10)];
1241 char const *type_name
;
1244 GSList
*with_zorder
= NULL
;
1245 GSList
*without_zorder
= NULL
;
1248 * Most objects are selectable and the order therefore matters.
1249 * We write those in reverse order because sheet_object_set_sheet
1250 * will reverse them on input.
1252 * Cell comments are separated out and sorted. This helps
1255 * Yet other objects have no export method and we drop those on
1258 for (ptr
= objects
;ptr
!= NULL
; ptr
= ptr
->next
) {
1259 SheetObject
*so
= ptr
->data
;
1260 SheetObjectClass
*klass
= GNM_SO_CLASS (G_OBJECT_GET_CLASS (so
));
1261 if (klass
== NULL
|| klass
->write_xml_sax
== NULL
)
1264 if (GNM_IS_CELL_COMMENT (so
))
1265 without_zorder
= g_slist_prepend (without_zorder
, so
);
1267 with_zorder
= g_slist_prepend (with_zorder
, so
);
1269 without_zorder
= g_slist_sort (without_zorder
, (GCompareFunc
)so_by_pos
);
1270 objects
= g_slist_concat (without_zorder
, with_zorder
);
1272 for (ptr
= objects
;ptr
!= NULL
; ptr
= ptr
->next
) {
1273 SheetObject
*so
= ptr
->data
;
1274 SheetObjectClass
*klass
= GNM_SO_CLASS (G_OBJECT_GET_CLASS (so
));
1275 GnmRange cell_bound
= so
->anchor
.cell_bound
;
1277 switch (so
->anchor
.mode
) {
1278 case GNM_SO_ANCHOR_TWO_CELLS
:
1280 case GNM_SO_ANCHOR_ONE_CELL
:
1281 cell_bound
.end
= cell_bound
.start
;
1283 case GNM_SO_ANCHOR_ABSOLUTE
:
1284 range_init (&cell_bound
, 0, 0, 0, 0);
1287 g_assert_not_reached ();
1290 if (needs_container
) {
1291 needs_container
= FALSE
;
1292 gsf_xml_out_start_element (state
->output
, GNM
"Objects");
1295 /* A hook so that things can sometimes change names */
1296 type_name
= klass
->xml_export_name
;
1297 if (type_name
== NULL
)
1298 type_name
= G_OBJECT_TYPE_NAME (so
);
1300 tmp
= g_strconcat (GNM
, type_name
, NULL
);
1301 gsf_xml_out_start_element (state
->output
, tmp
);
1303 gsf_xml_out_add_cstr (state
->output
, "Name", so
->name
);
1304 if (so
->anchor
.mode
!= GNM_SO_ANCHOR_ABSOLUTE
)
1305 gsf_xml_out_add_cstr (state
->output
, "ObjectBound", range_as_string (&cell_bound
));
1306 if (so
->anchor
.mode
!= GNM_SO_ANCHOR_TWO_CELLS
)
1307 gsf_xml_out_add_enum (state
->output
,
1309 GNM_SHEET_OBJECT_ANCHOR_MODE_TYPE
,
1311 snprintf (buffer
, sizeof (buffer
), "%.3g %.3g %.3g %.3g",
1312 so
->anchor
.offset
[0], so
->anchor
.offset
[1],
1313 so
->anchor
.offset
[2], so
->anchor
.offset
[3]);
1314 gsf_xml_out_add_cstr (state
->output
, "ObjectOffset", buffer
);
1316 gsf_xml_out_add_int (state
->output
, "Direction",
1317 so
->anchor
.base
.direction
);
1319 (state
->output
, "Print",
1320 (so
->flags
& SHEET_OBJECT_PRINT
) ? 1 : 0);
1322 (*klass
->write_xml_sax
) (so
, state
->output
, state
->convs
);
1324 gsf_xml_out_end_element (state
->output
); /* </gnm:{typename}> */
1327 g_slist_free (objects
);
1329 if (!needs_container
)
1330 gsf_xml_out_end_element (state
->output
); /* </gnm:Objects> */
1334 xml_write_sheet (GnmOutputXML
*state
, Sheet
const *sheet
)
1338 state
->sheet
= sheet
;
1339 gsf_xml_out_start_element (state
->output
, GNM
"Sheet");
1341 gsf_xml_out_add_bool (state
->output
,
1342 "DisplayFormulas", sheet
->display_formulas
);
1343 gsf_xml_out_add_bool (state
->output
,
1344 "HideZero", sheet
->hide_zero
);
1345 gsf_xml_out_add_bool (state
->output
,
1346 "HideGrid", sheet
->hide_grid
);
1347 gsf_xml_out_add_bool (state
->output
,
1348 "HideColHeader", sheet
->hide_col_header
);
1349 gsf_xml_out_add_bool (state
->output
,
1350 "HideRowHeader", sheet
->hide_row_header
);
1351 gsf_xml_out_add_bool (state
->output
,
1352 "DisplayOutlines", sheet
->display_outlines
);
1353 gsf_xml_out_add_bool (state
->output
,
1354 "OutlineSymbolsBelow", sheet
->outline_symbols_below
);
1355 gsf_xml_out_add_bool (state
->output
,
1356 "OutlineSymbolsRight", sheet
->outline_symbols_right
);
1357 if (sheet
->text_is_rtl
)
1358 gsf_xml_out_add_bool (state
->output
,
1359 "RTL_Layout", sheet
->text_is_rtl
);
1360 if (sheet
->is_protected
)
1361 gsf_xml_out_add_bool (state
->output
,
1362 "Protected", sheet
->is_protected
);
1364 /* TODO : Make this an enum internally eventually */
1365 if (sheet
->convs
->r1c1_addresses
)
1366 gsf_xml_out_add_cstr_unchecked (state
->output
,
1367 "ExprConvention", "gnumeric:R1C1");
1369 gsf_xml_out_add_enum (state
->output
,
1370 "Visibility", GNM_SHEET_VISIBILITY_TYPE
, sheet
->visibility
);
1372 if (sheet
->tab_color
!= NULL
)
1373 gnm_xml_out_add_color (state
->output
, "TabColor", sheet
->tab_color
);
1374 if (sheet
->tab_text_color
!= NULL
)
1375 gnm_xml_out_add_color (state
->output
, "TabTextColor", sheet
->tab_text_color
);
1376 if (NULL
!= (c
= sheet_style_get_auto_pattern_color (sheet
))) {
1377 gnm_xml_out_add_color (state
->output
, "GridColor", c
);
1378 style_color_unref (c
);
1381 gsf_xml_out_simple_element (state
->output
,
1382 GNM
"Name", sheet
->name_unquoted
);
1383 gsf_xml_out_simple_int_element (state
->output
,
1384 GNM
"MaxCol", sheet
->cols
.max_used
);
1385 gsf_xml_out_simple_int_element (state
->output
,
1386 GNM
"MaxRow", sheet
->rows
.max_used
);
1387 gsf_xml_out_simple_float_element (state
->output
,
1388 GNM
"Zoom", sheet
->last_zoom_factor_used
, 4);
1390 xml_write_named_expressions (state
, sheet
->names
);
1391 xml_write_print_info (state
, sheet
->print_info
);
1392 xml_write_styles (state
);
1393 xml_write_cols_rows (state
, NULL
);
1394 xml_write_selection_info (state
);
1395 xml_write_objects (state
, sheet
->sheet_objects
);
1396 xml_write_cells (state
);
1398 xml_write_merged_regions (state
);
1399 xml_write_sheet_layout (state
);
1400 xml_write_sheet_filters (state
);
1401 xml_write_solver (state
);
1402 xml_write_scenarios (state
);
1404 gsf_xml_out_end_element (state
->output
); /* </gnm:Sheet> */
1405 state
->sheet
= NULL
;
1409 xml_write_sheets (GnmOutputXML
*state
)
1411 int i
, n
= workbook_sheet_count (state
->wb
);
1412 gsf_xml_out_start_element (state
->output
, GNM
"Sheets");
1413 for (i
= 0 ; i
< n
; i
++)
1414 xml_write_sheet (state
, workbook_sheet_by_index (state
->wb
, i
));
1415 gsf_xml_out_end_element (state
->output
); /* </gnm:Sheets> */
1419 xml_write_uidata (GnmOutputXML
*state
)
1421 gsf_xml_out_start_element (state
->output
, GNM
"UIData");
1422 gsf_xml_out_add_int (state
->output
, "SelectedTab",
1423 wb_view_cur_sheet (state
->wb_view
)->index_in_wb
);
1424 gsf_xml_out_end_element (state
->output
); /* </gnm:UIData> */
1428 xml_write_date_conventions_as_attr (GnmOutputXML
*state
,
1429 GODateConventions
const *conv
)
1432 gsf_xml_out_add_cstr_unchecked (state
->output
,
1433 GNM
"DateConvention", "Apple:1904");
1437 xml_write_number_system (GnmOutputXML
*state
)
1440 * These numbers define how to interpret decimal values in the
1441 * file. They are not yet used, but should be used when the
1442 * number system of the loading Gnumeric is different from the
1443 * number system of the saving Gnumeric.
1445 gsf_xml_out_add_int (state
->output
, "FloatRadix", FLT_RADIX
);
1446 gsf_xml_out_add_int (state
->output
, "FloatDigits", GNM_MANT_DIG
);
1451 xml_write_calculation (GnmOutputXML
*state
)
1453 gsf_xml_out_start_element (state
->output
, GNM
"Calculation");
1454 gsf_xml_out_add_bool (state
->output
,
1455 "ManualRecalc", !state
->wb
->recalc_auto
);
1456 gsf_xml_out_add_bool (state
->output
,
1457 "EnableIteration", state
->wb
->iteration
.enabled
);
1458 gsf_xml_out_add_int (state
->output
,
1459 "MaxIterations", state
->wb
->iteration
.max_number
);
1460 go_xml_out_add_double (state
->output
,
1461 "IterationTolerance", state
->wb
->iteration
.tolerance
);
1462 xml_write_date_conventions_as_attr (state
,
1463 workbook_date_conv (state
->wb
));
1464 xml_write_number_system (state
);
1465 gsf_xml_out_end_element (state
->output
); /* </gnm:Calculation> */
1469 gnm_xml_io_conventions (void)
1471 GnmConventions
*res
= gnm_conventions_new ();
1474 res
->decimal_sep_dot
= TRUE
;
1475 res
->input
.range_ref
= rangeref_parse
;
1476 res
->output
.range_ref
= gnm_1_0_rangeref_as_string
;
1477 res
->range_sep_colon
= TRUE
;
1479 res
->array_col_sep
= ',';
1480 res
->array_row_sep
= ';';
1481 res
->output
.translated
= FALSE
;
1483 l10
= gnm_log10 (FLT_RADIX
);
1484 res
->output
.decimal_digits
= (int)gnm_ceil (GNM_MANT_DIG
* l10
) +
1485 (l10
== (int)l10
? 0 : 1);
1491 gnm_xml_file_save_full (G_GNUC_UNUSED GOFileSaver
const *fs
,
1492 G_GNUC_UNUSED GOIOContext
*io_context
,
1493 GoView
const *view
, GsfOutput
*output
,
1497 GsfOutput
*gzout
= NULL
;
1499 WorkbookView
*wb_view
= GNM_WORKBOOK_VIEW (view
);
1502 gzout
= gsf_output_gzip_new (output
, NULL
);
1506 state
.wb_view
= wb_view
;
1507 state
.wb
= wb_view_get_workbook (wb_view
);
1509 state
.output
= gsf_xml_out_new (output
);
1510 state
.convs
= gnm_xml_io_conventions ();
1511 state
.expr_map
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1512 state
.cell_str
= g_string_new (NULL
);
1513 state
.write_value_result
= FALSE
;
1514 go_doc_init_write (GO_DOC (state
.wb
), state
.output
);
1516 locale
= gnm_push_C_locale ();
1518 gsf_xml_out_start_element (state
.output
, GNM
"Workbook");
1521 * As long as we want older versions of Gnumeric to be able to read
1522 * the files we produce, we should not increase the version number
1523 * in the file we write. Until 1.12.21, v10 was the highest listed
1524 * xml-sax-read.c's content_ns.
1526 gsf_xml_out_add_cstr_unchecked (state
.output
, "xmlns:gnm",
1527 "http://www.gnumeric.org/v10.dtd");
1528 #if 0 /* seems to break meta data */
1529 /* default namespace added for 1.8 */
1530 gsf_xml_out_add_cstr_unchecked (state
.output
, "xmlns",
1531 "http://www.gnumeric.org/v10.dtd");
1533 gsf_xml_out_add_cstr_unchecked (state
.output
, "xmlns:xsi",
1534 "http://www.w3.org/2001/XMLSchema-instance");
1535 gsf_xml_out_add_cstr_unchecked (state
.output
, "xsi:schemaLocation",
1536 "http://www.gnumeric.org/v9.xsd");
1538 xml_write_version (&state
);
1539 xml_write_attributes (&state
);
1540 xml_write_meta_data (&state
);
1541 xml_write_conventions (&state
); /* DEPRECATED, moved to Calculation */
1542 xml_write_calculation (&state
);
1543 xml_write_sheet_names (&state
);
1544 xml_write_named_expressions (&state
, state
.wb
->names
);
1545 xml_write_geometry (&state
);
1546 xml_write_sheets (&state
);
1547 xml_write_uidata (&state
);
1548 go_doc_write (GO_DOC (state
.wb
), state
.output
);
1550 gsf_xml_out_end_element (state
.output
); /* </Workbook> */
1552 gnm_pop_C_locale (locale
);
1554 g_hash_table_destroy (state
.expr_map
);
1555 g_string_free (state
.cell_str
, TRUE
);
1556 gnm_conventions_unref (state
.convs
);
1557 g_object_unref (state
.output
);
1560 gsf_output_close (gzout
);
1561 g_object_unref (gzout
);
1566 gnm_xml_file_save (GOFileSaver
const *fs
, GOIOContext
*io_context
,
1567 GoView
const *view
, GsfOutput
*output
)
1570 char const *extension
= NULL
;
1572 /* If the suffix is .xml disable compression */
1573 if (NULL
!= gsf_output_name (output
))
1574 extension
= gsf_extension_pointer (gsf_output_name (output
));
1575 if (NULL
!= extension
&& g_ascii_strcasecmp (extension
, "xml") == 0)
1578 compress
= (gnm_conf_get_core_xml_compression_level () > 0);
1580 gnm_xml_file_save_full (fs
, io_context
, view
, output
, compress
);
1584 gnm_xml_file_save_xml (GOFileSaver
const *fs
, GOIOContext
*io_context
,
1585 GoView
const *view
, GsfOutput
*output
)
1587 gnm_xml_file_save_full (fs
, io_context
, view
, output
, FALSE
);
1590 /**************************************************************************/
1594 GnmCellRegion
const *cr
;
1599 cb_xml_write_cell_region_cells (GnmCellCopy
*cc
,
1600 G_GNUC_UNUSED gconstpointer ignore
,
1601 XMLCellCopyState
*state
)
1603 state
->pp
.eval
.col
= state
->cr
->base
.col
+ cc
->offset
.col
;
1604 state
->pp
.eval
.row
= state
->cr
->base
.row
+ cc
->offset
.row
;
1605 xml_write_cell_and_position (&state
->state
,
1606 cc
->texpr
, cc
->val
, &state
->pp
);
1610 * gnm_cellregion_to_xml:
1611 * @cr: the content to store.
1613 * Returns: (transfer full): %NULL on error
1616 gnm_cellregion_to_xml (GnmCellRegion
const *cr
)
1618 XMLCellCopyState state
;
1619 GnmStyleList
*s_ptr
;
1621 GsfOutput
*buf
= gsf_output_memory_new ();
1625 g_return_val_if_fail (cr
!= NULL
, NULL
);
1626 g_return_val_if_fail (IS_SHEET (cr
->origin_sheet
), NULL
);
1628 state
.state
.wb_view
= NULL
;
1629 state
.state
.wb
= NULL
;
1630 state
.state
.sheet
= cr
->origin_sheet
;
1631 state
.state
.output
= gsf_xml_out_new (buf
);
1632 state
.state
.convs
= gnm_xml_io_conventions ();
1633 state
.state
.expr_map
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1634 state
.state
.cell_str
= g_string_new (NULL
);
1635 state
.state
.write_value_result
= TRUE
;
1637 locale
= gnm_push_C_locale ();
1638 if (cr
->origin_sheet
) {
1639 /* hoping this always occur */
1640 doc
= GO_DOC (cr
->origin_sheet
->workbook
);
1641 go_doc_init_write (doc
, state
.state
.output
);
1644 gsf_xml_out_start_element (state
.state
.output
, GNM
"ClipboardRange");
1646 /* backwards compat, must be first */
1647 gsf_xml_out_add_cstr_unchecked (state
.state
.output
, "xmlns:gnm",
1648 "http://www.gnumeric.org/v10.dtd");
1649 /* default namespace added for 1.8 */
1650 gsf_xml_out_add_cstr_unchecked (state
.state
.output
, "xmlns",
1651 "http://www.gnumeric.org/v10.dtd");
1653 gsf_xml_out_add_int (state
.state
.output
, "Cols", cr
->cols
);
1654 gsf_xml_out_add_int (state
.state
.output
, "Rows", cr
->rows
);
1655 gsf_xml_out_add_int (state
.state
.output
, "BaseCol", cr
->base
.col
);
1656 gsf_xml_out_add_int (state
.state
.output
, "BaseRow", cr
->base
.row
);
1657 if (cr
->origin_sheet
)
1658 xml_write_date_conventions_as_attr
1660 sheet_date_conv (cr
->origin_sheet
));
1661 xml_write_number_system (&state
.state
);
1662 if (cr
->not_as_contents
)
1663 gsf_xml_out_add_bool (state
.state
.output
, "NotAsContent", TRUE
);
1665 xml_write_cols_rows (&state
.state
, cr
);
1667 if (cr
->styles
!= NULL
) {
1668 gsf_xml_out_start_element (state
.state
.output
, GNM
"Styles");
1669 for (s_ptr
= cr
->styles
; s_ptr
!= NULL
; s_ptr
= s_ptr
->next
)
1670 xml_write_style_region (&state
.state
, s_ptr
->data
);
1671 gsf_xml_out_end_element (state
.state
.output
); /* </Styles> */
1674 if (cr
->merged
!= NULL
) {
1675 gsf_xml_out_start_element (state
.state
.output
, GNM
"MergedRegions");
1676 for (ptr
= cr
->merged
; ptr
!= NULL
; ptr
= ptr
->next
) {
1677 gsf_xml_out_start_element (state
.state
.output
, GNM
"Merge");
1678 gsf_xml_out_add_cstr_unchecked (state
.state
.output
, NULL
,
1679 range_as_string (ptr
->data
));
1680 gsf_xml_out_end_element (state
.state
.output
); /* </Merge> */
1682 gsf_xml_out_end_element (state
.state
.output
); /* </gnm:MergedRegions> */
1685 /* NOTE SNEAKY : ensure that sheet names have explicit workbooks */
1687 state
.pp
.sheet
= cr
->origin_sheet
;
1689 if (cr
->cell_content
!= NULL
) {
1690 gsf_xml_out_start_element (state
.state
.output
, GNM
"Cells");
1691 g_hash_table_foreach (cr
->cell_content
,
1692 (GHFunc
) cb_xml_write_cell_region_cells
, &state
);
1693 gsf_xml_out_end_element (state
.state
.output
); /* </Cells> */
1696 xml_write_objects (&state
.state
, cr
->objects
);
1699 go_doc_write (doc
, state
.state
.output
);
1700 gsf_xml_out_end_element (state
.state
.output
); /* </ClipboardRange> */
1702 gnm_pop_C_locale (locale
);
1704 g_hash_table_destroy (state
.state
.expr_map
);
1705 g_string_free (state
.state
.cell_str
, TRUE
);
1706 gnm_conventions_unref (state
.state
.convs
);
1707 g_object_unref (state
.state
.output
);
1709 gsf_output_close (buf
);
1711 return GSF_OUTPUT_MEMORY (buf
);
1714 #define XML_SAX_ID "Gnumeric_XmlIO:sax"
1715 #define XML_SAX_ID_0 "Gnumeric_XmlIO:sax:0"
1718 gnm_xml_sax_write_init (void)
1720 GOFileSaver
*saver
= go_file_saver_new
1723 _("Gnumeric XML (*.gnumeric)"),
1724 GO_FILE_FL_AUTO
, gnm_xml_file_save
);
1725 g_object_set (G_OBJECT (saver
),
1726 "mime-type", "application/x-gnumeric",
1729 go_file_saver_register_as_default (saver
, 50);
1730 g_object_unref (saver
);
1732 saver
= go_file_saver_new
1735 _("Gnumeric XML uncompressed (*.xml)"),
1736 GO_FILE_FL_AUTO
, gnm_xml_file_save_xml
);
1737 g_object_set (G_OBJECT (saver
),
1738 "mime-type", "application/xml",
1741 go_file_saver_register (saver
);
1742 g_object_unref (saver
);
1746 gnm_xml_sax_write_shutdown (void)
1748 go_file_saver_unregister (go_file_saver_for_id (XML_SAX_ID
));
1749 go_file_saver_unregister (go_file_saver_for_id (XML_SAX_ID_0
));