1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * openoffice-write.c : export OpenOffice OASIS .ods files
6 * Copyright (C) 2004-2006 Jody Goldberg (jody@gnome.org)
8 * Copyright (C) 2006-2011 Andreas J. Guelzow (aguelzow@pyrshep.ca)
10 * Copyright (C) 2005 INdT - Instituto Nokia de Tecnologia
11 * Author: Luciano Wolf (luciano.wolf@indt.org.br)
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of the
16 * License, or (at your option) version 3.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
29 /*****************************************************************************/
31 #include <gnumeric-config.h>
33 #include <workbook-view.h>
34 #include <goffice/goffice.h>
35 #include <gnm-format.h>
37 #include <workbook-priv.h> /* Workbook::names */
41 #include <print-info.h>
42 #include <sheet-view.h>
43 #include <sheet-style.h>
44 #include <sheet-merge.h>
45 #include <style-color.h>
47 #include <expr-impl.h>
48 #include <expr-name.h>
53 #include <input-msg.h>
54 #include <style-border.h>
55 #include <validation.h>
56 #include <validation-combo.h>
58 #include <sheet-filter.h>
59 #include <print-info.h>
60 #include <parse-util.h>
61 #include <tools/dao.h>
63 #include <style-conditions.h>
65 #include <sheet-object.h>
66 #include <sheet-object-graph.h>
67 #include <sheet-object-cell-comment.h>
68 #include <sheet-object-image.h>
69 #include <sheet-object-widget.h>
70 #include <gnm-so-filled.h>
71 #include <gnm-so-line.h>
72 #include <gnm-so-path.h>
73 #include <sheet-filter-combo.h>
76 #include <gsf/gsf-libxml.h>
77 #include <gsf/gsf-output.h>
78 #include <gsf/gsf-outfile.h>
79 #include <gsf/gsf-outfile-zip.h>
80 #include <gsf/gsf-utils.h>
81 #include <gsf/gsf-opendoc-utils.h>
82 #include <gsf/gsf-doc-meta-data.h>
83 #include <gsf/gsf-meta-names.h>
87 #include <glib/gi18n-lib.h>
89 #define MANIFEST "manifest:"
90 #define OFFICE "office:"
91 #define STYLE "style:"
92 #define TABLE "table:"
94 #define DUBLINCORE "dc:"
96 #define NUMBER "number:"
98 #define CHART "chart:"
100 #define XLINK "xlink:"
101 #define CONFIG "config:"
103 #define SCRIPT "script:"
105 #define TABLEOOO "tableooo:"
108 #define LOEXT "loext:"
109 #define CALCEXT "calcext:"
110 #define GNMSTYLE "gnm:" /* We use this for attributes and elements not supported by ODF */
116 WorkbookView
const *wbv
;
119 GnmConventions
*conv
;
120 GHashTable
*openformula_namemap
;
121 GHashTable
*openformula_handlermap
;
124 GHashTable
*cell_styles
;
125 GHashTable
*named_cell_styles
;
126 GHashTable
*named_cell_style_regions
;
127 GHashTable
*so_styles
;
128 GHashTable
*xl_styles
;
129 GHashTable
*style_names
[10];
130 GnmStyleRegion
*default_style_region
;
131 ColRowInfo
const *row_default
;
132 ColRowInfo
const *column_default
;
134 GHashTable
*graph_dashes
;
135 GHashTable
*graph_hatches
;
136 GHashTable
*graph_fill_images
;
137 GHashTable
*graph_gradients
;
138 GHashTable
*chart_props_hash
;
139 GHashTable
*arrow_markers
;
141 GHashTable
*controls
;
142 GHashTable
*text_colours
;
143 GHashTable
*font_sizes
;
145 gboolean with_extension
;
147 char *odf_version_string
;
148 GOFormat
const *time_fmt
;
149 GOFormat
const *date_fmt
;
150 GOFormat
const *date_long_fmt
;
152 char const *object_name
;
155 /* for the manifest */
156 GSList
*fill_image_files
; /* image/png */
159 float graph_progress
;
160 float sheet_progress
;
171 ColRowInfo
const *ci
;
178 { "xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0" },
179 { "xmlns:style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0"},
180 { "xmlns:text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0" },
181 { "xmlns:table", "urn:oasis:names:tc:opendocument:xmlns:table:1.0" },
182 { "xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" },
183 { "xmlns:fo", "urn:oasis:names:tc:opendocument:xmlns:" "xsl-fo-compatible:1.0"},
184 { "xmlns:xlink", "http://www.w3.org/1999/xlink" },
185 { "xmlns:dc", "http://purl.org/dc/elements/1.1/" },
186 { "xmlns:meta", "urn:oasis:names:tc:opendocument:xmlns:meta:1.0" },
187 { "xmlns:number", "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" },
188 { "xmlns:svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" },
189 { "xmlns:chart", "urn:oasis:names:tc:opendocument:xmlns:chart:1.0" },
190 { "xmlns:dr3d", "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" },
191 { "xmlns:config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0"},
192 { "xmlns:math", "http://www.w3.org/1998/Math/MathML" },
193 { "xmlns:form", "urn:oasis:names:tc:opendocument:xmlns:form:1.0" },
194 { "xmlns:script", "urn:oasis:names:tc:opendocument:xmlns:script:1.0" },
195 { "xmlns:ooo", "http://openoffice.org/2004/office" },
196 { "xmlns:ooow", "http://openoffice.org/2004/writer" },
197 { "xmlns:oooc", "http://openoffice.org/2004/calc" },
198 { "xmlns:tableooo", "http://openoffice.org/2009/table" },
199 { "xmlns:of", "urn:oasis:names:tc:opendocument:xmlns:of:1.2" },
200 { "xmlns:dom", "http://www.w3.org/2001/xml-events" },
201 { "xmlns:xforms", "http://www.w3.org/2002/xforms" },
202 { "xmlns:xsd", "http://www.w3.org/2001/XMLSchema" },
203 { "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" },
204 { "xmlns:gnm", "http://www.gnumeric.org/odf-extension/1.0"},
205 { "xmlns:css3t", "http://www.w3.org/TR/css3-text/"},
206 { "xmlns:loext", "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"},
207 { "xmlns:calcext", "urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"},
210 /*****************************************************************************/
212 static void odf_write_fill_images_info (GOImage
*image
, char const *name
, GnmOOExport
*state
);
213 static void odf_write_gradient_info (GOStyle
const *style
, char const *name
, GnmOOExport
*state
);
214 static void odf_write_hatch_info (GOPattern
*pattern
, char const *name
, GnmOOExport
*state
);
215 static void odf_write_dash_info (char const *name
, gpointer data
, GnmOOExport
*state
);
216 static void odf_write_arrow_marker_info (GOArrow
const *arrow
, char const *name
, GnmOOExport
*state
);
218 static void odf_write_gog_style_graphic (GnmOOExport
*state
, GOStyle
const *style
, gboolean write_border
);
219 static void odf_write_gog_style_text (GnmOOExport
*state
, GOStyle
const *style
);
222 /*****************************************************************************/
224 #define PROGRESS_STEPS 500
226 odf_update_progress (GnmOOExport
*state
, float delta
)
228 int old
= state
->last_progress
;
231 state
->last_progress
+= delta
;
232 new = state
->last_progress
;
235 go_io_value_progress_update (state
->ioc
, new);
238 /*****************************************************************************/
242 OO_ITEM_TABLE_MASTER_PAGE_STYLE
,
244 OO_ITEM_UNSTYLED_GRAPH_OBJECT
,
246 OO_ITEM_SHEET_OBJECT
,
247 OO_ITEM_SHEET_OBJECT_LINE
,
255 oo_item_name (GnmOOExport
*state
, OONamedItemType typ
, gconstpointer ptr
)
257 static const char * const
258 prefixes
[G_N_ELEMENTS (state
->style_names
)] = {
272 g_return_val_if_fail ((size_t)typ
<= G_N_ELEMENTS (prefixes
), NULL
);
274 name
= g_hash_table_lookup (state
->style_names
[typ
], ptr
);
276 if (!g_str_has_prefix (name
, prefixes
[typ
]))
277 g_warning ("Style name confusion.");
279 name
= g_strdup_printf
280 ("%s-%u", prefixes
[typ
],
281 g_hash_table_size (state
->style_names
[typ
]));
282 g_hash_table_replace (state
->style_names
[typ
],
286 return g_strdup (name
);
291 table_style_name (GnmOOExport
*state
, Sheet
const *sheet
)
293 return oo_item_name (state
, OO_ITEM_TABLE_STYLE
, sheet
);
297 table_master_page_style_name (GnmOOExport
*state
, Sheet
const *sheet
)
299 return oo_item_name (state
, OO_ITEM_TABLE_MASTER_PAGE_STYLE
, sheet
);
303 page_layout_name (GnmOOExport
*state
, GnmPrintInformation
*pi
)
305 return oo_item_name (state
, OO_ITEM_PAGE_LAYOUT
, pi
);
309 /*****************************************************************************/
312 odf_write_mimetype (G_GNUC_UNUSED GnmOOExport
*state
, GsfOutput
*child
)
314 gsf_output_puts (child
, "application/vnd.oasis.opendocument.spreadsheet");
317 /*****************************************************************************/
320 odf_add_range (GnmOOExport
*state
, GnmRange
const *r
)
322 g_return_if_fail (range_is_sane (r
));
324 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"start-col", r
->start
.col
);
325 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"start-row", r
->start
.row
);
326 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"end-col", r
->end
.col
);
327 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"end-row", r
->end
.row
);
331 odf_add_font_weight (GnmOOExport
*state
, int weight
)
333 weight
= ((weight
+50)/100)*100;
339 /* MS Excel 2007/2010 is badly confused about which weights are normal */
340 /* and/or bold, so we don't just save numbers. See */
341 /* http://msdn.microsoft.com/en-us/library/ff528991%28v=office.12%29.aspx */
342 /* although ODF refers to */
343 /* http://www.w3.org/TR/2001/REC-xsl-20011015/slice7.html#font-weight */
344 /* where it is clear that 400 == normal and 700 == bold */
345 if (weight
== PANGO_WEIGHT_NORMAL
)
346 gsf_xml_out_add_cstr_unchecked (state
->xml
, FOSTYLE
"font-weight",
348 else if (weight
== PANGO_WEIGHT_BOLD
)
349 gsf_xml_out_add_cstr_unchecked (state
->xml
, FOSTYLE
"font-weight",
352 gsf_xml_out_add_int (state
->xml
, FOSTYLE
"font-weight", weight
);
357 odf_add_chars_non_white (GnmOOExport
*state
, char const *text
, int len
)
361 g_return_if_fail (len
> 0);
363 str
= g_strndup (text
, len
);
364 gsf_xml_out_add_cstr (state
->xml
, NULL
, str
);
369 odf_add_chars (GnmOOExport
*state
, char const *text
, int len
, gboolean
*white_written
)
371 int nw
= strcspn(text
, " \n\t");
374 odf_add_chars_non_white (state
, text
, len
);
375 *white_written
= FALSE
;
380 odf_add_chars_non_white (state
, text
, nw
);
383 *white_written
= FALSE
;
389 int white
= strspn(text
, " ");
391 if (!*white_written
) {
392 gsf_xml_out_add_cstr (state
->xml
, NULL
, " ");
396 *white_written
= TRUE
;
399 gsf_xml_out_start_element (state
->xml
, TEXT
"s");
401 gsf_xml_out_add_int (state
->xml
, TEXT
"c", white
);
402 gsf_xml_out_end_element (state
->xml
);
409 gsf_xml_out_start_element (state
->xml
, TEXT
"line-break");
410 gsf_xml_out_end_element (state
->xml
);
415 gsf_xml_out_start_element (state
->xml
, TEXT
"tab");
416 gsf_xml_out_end_element (state
->xml
);
421 /* This really shouldn't happen */
422 g_warning ("How can we get here?");
427 odf_add_chars (state
, text
, len
, white_written
);
431 odf_attrs_as_string (GnmOOExport
*state
, PangoAttribute
*a
)
435 switch (a
->klass
->type
) {
436 case PANGO_ATTR_FAMILY
:
438 case PANGO_ATTR_SIZE
:
441 gint size
= ((PangoAttrInt
*)a
)->value
/PANGO_SCALE
;
442 str
= g_strdup_printf ("NS-font-size%i", size
);
444 gsf_xml_out_start_element (state
->xml
, TEXT
"span");
445 gsf_xml_out_add_cstr (state
->xml
, TEXT
"style-name", str
);
446 g_hash_table_insert (state
->font_sizes
,
447 str
, GINT_TO_POINTER (size
));
450 case PANGO_ATTR_RISE
:
451 gsf_xml_out_start_element (state
->xml
, TEXT
"span");
452 if (((PangoAttrInt
*)a
)->value
!= 0) {
453 gsf_xml_out_add_cstr (state
->xml
, TEXT
"style-name",
454 (((PangoAttrInt
*)a
)->value
< 0)
455 ? "AC-subscript" : "AC-superscript");
457 gsf_xml_out_add_cstr (state
->xml
, TEXT
"style-name", "AC-script");
460 case PANGO_ATTR_STYLE
:
462 gsf_xml_out_start_element (state
->xml
, TEXT
"span");
463 gsf_xml_out_add_cstr (state
->xml
, TEXT
"style-name",
464 (((PangoAttrInt
*)a
)->value
465 == PANGO_STYLE_ITALIC
)
466 ? "AC-italic" : "AC-roman");
468 case PANGO_ATTR_WEIGHT
:
470 char * str
= g_strdup_printf ("AC-weight%i",
471 ((((PangoAttrInt
*)a
)->value
474 gsf_xml_out_start_element (state
->xml
, TEXT
"span");
475 gsf_xml_out_add_cstr (state
->xml
, TEXT
"style-name", str
);
479 case PANGO_ATTR_STRIKETHROUGH
:
481 gsf_xml_out_start_element (state
->xml
, TEXT
"span");
482 gsf_xml_out_add_cstr (state
->xml
, TEXT
"style-name",
483 ((PangoAttrInt
*)a
)->value
484 ? "AC-strikethrough-solid"
485 : "AC-strikethrough-none");
487 case PANGO_ATTR_UNDERLINE
:
489 char const *name
= NULL
;
490 switch (((PangoAttrInt
*)a
)->value
) {
491 case PANGO_UNDERLINE_NONE
:
492 name
= "AC-underline-none";
494 case PANGO_UNDERLINE_SINGLE
:
495 name
= "AC-underline-single";
497 case PANGO_UNDERLINE_DOUBLE
:
498 name
= "AC-underline-double";
500 case PANGO_UNDERLINE_LOW
:
501 name
= "AC-underline-low";
503 case PANGO_UNDERLINE_ERROR
:
504 name
= "AC-underline-error";
510 gsf_xml_out_start_element (state
->xml
, TEXT
"span");
511 gsf_xml_out_add_cstr (state
->xml
, TEXT
"style-name", name
);
514 case PANGO_ATTR_FOREGROUND
:
520 c
= &((PangoAttrColor
*)a
)->color
;
521 c_str
= g_strdup_printf ("#%02x%02x%02x",
522 ((c
->red
& 0xff00) >> 8),
523 ((c
->green
& 0xff00) >> 8),
524 ((c
->blue
& 0xff00) >> 8));
525 name
= g_strdup_printf ("NS-colour-%s", c_str
+ 1);
526 gsf_xml_out_start_element (state
->xml
, TEXT
"span");
527 gsf_xml_out_add_cstr (state
->xml
, TEXT
"style-name", name
);
529 g_hash_table_insert (state
->text_colours
, name
, c_str
);
533 if (a
->klass
->type
==
534 go_pango_attr_subscript_get_attr_type ()) {
535 gsf_xml_out_start_element (state
->xml
, TEXT
"span");
536 gsf_xml_out_add_cstr (state
->xml
, TEXT
"style-name",
537 ((GOPangoAttrSubscript
*)a
)->val
?
538 "AC-subscript" : "AC-script");
540 } else if (a
->klass
->type
==
541 go_pango_attr_superscript_get_attr_type ()) {
542 gsf_xml_out_start_element (state
->xml
, TEXT
"span");
543 gsf_xml_out_add_cstr (state
->xml
, TEXT
"style-name",
544 ((GOPangoAttrSuperscript
*)a
)->val
?
545 "AC-superscript" : "AC-script");
548 break; /* ignored otherwise */
555 odf_new_markup (GnmOOExport
*state
, const PangoAttrList
*markup
, char const *text
)
558 PangoAttrIterator
* iter
;
560 int len
= text
? strlen (text
) : 0;
561 /* Since whitespace at the beginning of a <text:p> will be deleted upon */
562 /* reading, we need to behave as if we have already written whitespace and */
563 /* use <text:s> if necessary */
564 gboolean white_written
= TRUE
;
568 if (markup
== NULL
) {
569 odf_add_chars (state
, text
, len
, &white_written
);
573 iter
= pango_attr_list_get_iterator ((PangoAttrList
*) markup
);
579 pango_attr_iterator_range (iter
, &from
, &to
);
580 to
= (to
> len
) ? len
: to
; /* Since "to" can be really big! */
581 from
= (from
> len
) ? len
: from
; /* Since "from" can also be really big! */
583 odf_add_chars (state
, text
+ handled
, from
- handled
, &white_written
);
584 list
= pango_attr_iterator_get_attrs (iter
);
585 for (l
= list
; l
!= NULL
; l
= l
->next
) {
586 PangoAttribute
*a
= l
->data
;
587 spans
+= odf_attrs_as_string (state
, a
);
588 pango_attribute_destroy (a
);
592 odf_add_chars (state
, text
+ from
, to
- from
, &white_written
);
595 gsf_xml_out_end_element (state
->xml
); /* </text:span> */
597 } while (pango_attr_iterator_next (iter
));
599 pango_attr_iterator_destroy (iter
);
605 /*****************************************************************************/
608 odf_add_bool (GsfXMLOut
*xml
, char const *id
, gboolean val
)
610 gsf_xml_out_add_cstr_unchecked (xml
, id
, val
? "true" : "false");
614 odf_add_angle (GsfXMLOut
*xml
, char const *id
, int val
)
618 gsf_xml_out_add_int (xml
, id
, val
);
622 odf_add_percent (GsfXMLOut
*xml
, char const *id
, double val
)
624 GString
*str
= g_string_new (NULL
);
626 g_string_append_printf (str
, "%.2f%%", val
* 100.);
627 gsf_xml_out_add_cstr_unchecked (xml
, id
, str
->str
);
628 g_string_free (str
, TRUE
);
633 odf_add_pt (GsfXMLOut
*xml
, char const *id
, double l
)
635 GString
*str
= g_string_new (NULL
);
636 go_dtoa (str
, "!g", l
);
637 g_string_append (str
, "pt");
638 gsf_xml_out_add_cstr_unchecked (xml
, id
, str
->str
);
639 g_string_free (str
, TRUE
);
643 odf_go_color_to_string (GOColor color
)
645 return g_strdup_printf ("#%.2x%.2x%.2x",
646 GO_COLOR_UINT_R (color
),
647 GO_COLOR_UINT_G (color
),
648 GO_COLOR_UINT_B (color
));
652 odf_go_color_opacity (GOColor color
)
654 return (GO_COLOR_UINT_A (color
)/255.);
658 gnm_xml_out_add_hex_color (GsfXMLOut
*o
, char const *id
, GnmColor
const *c
, int pattern
)
660 g_return_if_fail (c
!= NULL
);
663 gsf_xml_out_add_cstr_unchecked (o
, id
, "transparent");
666 color
= odf_go_color_to_string (c
->go_color
);
667 gsf_xml_out_add_cstr_unchecked (o
, id
, color
);
673 odf_write_plot_style_int (GsfXMLOut
*xml
, GogObject
const *plot
,
674 char const *property
, char const *id
)
677 if (gnm_object_has_readable_prop (plot
, property
, G_TYPE_INT
, &i
))
678 gsf_xml_out_add_int (xml
, id
, i
);
682 odf_write_plot_style_uint (GsfXMLOut
*xml
, GogObject
const *plot
,
683 char const *property
, char const *id
)
686 if (gnm_object_has_readable_prop (plot
, property
, G_TYPE_UINT
, &ui
))
687 gsf_xml_out_add_uint (xml
, id
, ui
);
691 odf_write_plot_style_double (GsfXMLOut
*xml
, GogObject
const *plot
,
692 char const *property
, char const *id
)
695 if (gnm_object_has_readable_prop (plot
, property
, G_TYPE_DOUBLE
, &d
))
696 go_xml_out_add_double (xml
, id
, d
);
700 odf_write_plot_style_double_percent (GsfXMLOut
*xml
, GogObject
const *plot
,
701 char const *property
, char const *id
)
704 if (gnm_object_has_readable_prop (plot
, property
, G_TYPE_DOUBLE
, &d
))
705 odf_add_percent (xml
, id
, d
);
709 odf_write_plot_style_bool (GsfXMLOut
*xml
, GogObject
const *plot
,
710 char const *property
, char const *id
)
713 if (gnm_object_has_readable_prop (plot
, property
, G_TYPE_BOOLEAN
, &b
))
714 odf_add_bool (xml
, id
, b
);
718 odf_write_plot_style_from_bool (GsfXMLOut
*xml
, GogObject
const *plot
,
719 char const *property
, char const *id
,
720 char const *t_val
, char const *f_val
)
723 if (gnm_object_has_readable_prop (plot
, property
, G_TYPE_BOOLEAN
, &b
))
724 gsf_xml_out_add_cstr (xml
, id
, b
? t_val
: f_val
);
728 odf_start_style (GsfXMLOut
*xml
, char const *name
, char const *family
)
730 gsf_xml_out_start_element (xml
, STYLE
"style");
731 gsf_xml_out_add_cstr_unchecked (xml
, STYLE
"name", name
);
732 gsf_xml_out_add_cstr_unchecked (xml
, STYLE
"family", family
);
736 odf_write_table_style (GnmOOExport
*state
, Sheet
const *sheet
)
738 char *name
= table_style_name (state
, sheet
);
739 char *mp_name
= table_master_page_style_name (state
, sheet
);
741 odf_start_style (state
->xml
, name
, "table");
742 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"master-page-name", mp_name
);
744 gsf_xml_out_start_element (state
->xml
, STYLE
"table-properties");
745 odf_add_bool (state
->xml
, TABLE
"display",
746 sheet
->visibility
== GNM_SHEET_VISIBILITY_VISIBLE
);
747 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"writing-mode",
748 sheet
->text_is_rtl
? "rl-tb" : "lr-tb");
749 if (state
->with_extension
) {
750 if (state
->odf_version
< 103) {
751 if (sheet
->tab_color
&& !sheet
->tab_color
->is_auto
) {
752 gnm_xml_out_add_hex_color (state
->xml
, GNMSTYLE
"tab-color",
753 sheet
->tab_color
, 1);
754 gnm_xml_out_add_hex_color (state
->xml
, TABLEOOO
"tab-color",
755 sheet
->tab_color
, 1);
757 if (sheet
->tab_text_color
&& !sheet
->tab_text_color
->is_auto
) {
758 gnm_xml_out_add_hex_color (state
->xml
,
759 GNMSTYLE
"tab-text-color",
760 sheet
->tab_text_color
, 1);
763 odf_add_bool (state
->xml
, GNMSTYLE
"display-formulas", sheet
->display_formulas
);
764 odf_add_bool (state
->xml
, GNMSTYLE
"display-col-header", !sheet
->hide_col_header
);
765 odf_add_bool (state
->xml
, GNMSTYLE
"display-row-header", !sheet
->hide_row_header
);
767 if (state
->odf_version
>= 103)
768 gnm_xml_out_add_hex_color (state
->xml
, TABLE
"tab-color",
769 sheet
->tab_color
, 1);
770 gsf_xml_out_end_element (state
->xml
); /* </style:table-properties> */
772 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
779 odf_get_gog_style_name (GnmOOExport
*state
,
780 GOStyle
const *style
, GogObject
const *obj
)
783 return oo_item_name (state
, OO_ITEM_UNSTYLED_GRAPH_OBJECT
, obj
);
785 return oo_item_name (state
, OO_ITEM_GRAPH_STYLE
, style
);
789 odf_get_gog_style_name_from_obj (GnmOOExport
*state
, GogObject
const *obj
)
791 GOStyle
*style
= NULL
;
793 if (gnm_object_has_readable_prop (obj
, "style", G_TYPE_NONE
, &style
)) {
794 char *name
= odf_get_gog_style_name (state
, style
, obj
);
795 g_object_unref (style
);
798 return odf_get_gog_style_name (state
, NULL
, obj
);
802 xl_find_format_xl (GnmOOExport
*state
, char const *xl
)
804 char *found
= g_hash_table_lookup (state
->xl_styles
, xl
);
807 found
= g_strdup_printf ("ND-%d",
808 g_hash_table_size (state
->xl_styles
));
809 g_hash_table_insert (state
->xl_styles
, g_strdup (xl
), found
);
815 xl_find_format (GnmOOExport
*state
, GOFormat
const *format
)
817 return xl_find_format_xl (state
, go_format_as_XL (format
));
821 odf_write_table_styles (GnmOOExport
*state
)
825 for (i
= 0; i
< workbook_sheet_count (state
->wb
); i
++) {
826 Sheet
const *sheet
= workbook_sheet_by_index (state
->wb
, i
);
827 odf_write_table_style (state
, sheet
);
832 odf_match_arrow_markers (GOArrow
const *old
, GOArrow
const *new)
834 return (old
->typ
== new->typ
&&
841 odf_get_arrow_marker_name (GnmOOExport
*state
, GOArrow
*arrow
)
843 gchar
const *name
= g_hash_table_lookup (state
->arrow_markers
,
849 new_name
= g_strdup_printf ("gnm-arrow-%i-%.2f-%.2f-%.2f-%i",
854 g_hash_table_size (state
->arrow_markers
));
855 g_hash_table_insert (state
->arrow_markers
,
856 (gpointer
) arrow
, new_name
);
862 odf_write_sheet_object_style (GnmOOExport
*state
, SheetObject
*so
)
864 char *name
= oo_item_name (state
, OO_ITEM_SHEET_OBJECT
, so
);
865 GOStyle
*style
= NULL
;
867 (void)gnm_object_has_readable_prop (so
, "style", G_TYPE_NONE
, &style
);
869 odf_start_style (state
->xml
, name
, "graphic");
870 gsf_xml_out_start_element (state
->xml
, STYLE
"graphic-properties");
871 odf_write_gog_style_graphic (state
, style
, FALSE
);
872 gsf_xml_out_end_element (state
->xml
); /* </style:graphic-properties> */
873 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
874 odf_write_gog_style_text (state
, style
);
875 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
876 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
879 g_object_unref (style
);
884 odf_write_sheet_object_line_style (GnmOOExport
*state
, SheetObject
*so
)
886 char *name
= oo_item_name (state
, OO_ITEM_SHEET_OBJECT_LINE
, so
);
887 GOStyle
*style
= NULL
;
888 GOArrow
*start
= NULL
, *end
= NULL
;
889 char const *start_arrow_name
= NULL
;
890 char const *end_arrow_name
= NULL
;
892 g_object_get (G_OBJECT (so
),
894 "start-arrow", &start
,
895 "end-arrow", &end
, NULL
);
897 if (start
!= NULL
&& start
->typ
!= GO_ARROW_NONE
)
898 start_arrow_name
= odf_get_arrow_marker_name (state
, start
);
901 if (end
!= NULL
&& end
->typ
!= GO_ARROW_NONE
)
902 end_arrow_name
= odf_get_arrow_marker_name (state
, end
);
906 odf_start_style (state
->xml
, name
, "graphic");
907 gsf_xml_out_start_element (state
->xml
, STYLE
"graphic-properties");
908 if (start_arrow_name
!= NULL
)
909 gsf_xml_out_add_cstr (state
->xml
, DRAW
"marker-start", start_arrow_name
);
910 if (end_arrow_name
!= NULL
)
911 gsf_xml_out_add_cstr (state
->xml
, DRAW
"marker-end", end_arrow_name
);
912 odf_write_gog_style_graphic (state
, style
, FALSE
);
913 gsf_xml_out_end_element (state
->xml
); /* </style:graphic-properties> */
914 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
917 g_object_unref (style
);
922 odf_write_sheet_object_styles (GnmOOExport
*state
)
926 for (i
= 0; i
< workbook_sheet_count (state
->wb
); i
++) {
927 Sheet
const *sheet
= workbook_sheet_by_index (state
->wb
, i
);
928 GSList
*objects
= sheet_objects_get (sheet
, NULL
, GNM_SO_FILLED_TYPE
), *l
;
929 for (l
= objects
; l
!= NULL
; l
= l
->next
) {
930 SheetObject
*so
= GNM_SO (l
->data
);
931 char *name
= odf_write_sheet_object_style (state
, so
);
932 g_hash_table_replace (state
->so_styles
, so
, name
);
934 g_slist_free (objects
);
935 objects
= sheet_objects_get (sheet
, NULL
, GNM_SO_LINE_TYPE
);
936 for (l
= objects
; l
!= NULL
; l
= l
->next
) {
937 SheetObject
*so
= GNM_SO (l
->data
);
938 char *name
= odf_write_sheet_object_line_style (state
, so
);
939 g_hash_table_replace (state
->so_styles
, so
, name
);
941 g_slist_free (objects
);
942 objects
= sheet_objects_get (sheet
, NULL
, GNM_SO_PATH_TYPE
);
943 for (l
= objects
; l
!= NULL
; l
= l
->next
) {
944 SheetObject
*so
= GNM_SO (l
->data
);
945 char *name
= odf_write_sheet_object_style (state
, so
);
946 g_hash_table_replace (state
->so_styles
, so
, name
);
948 g_slist_free (objects
);
953 odf_write_gog_position_pts (GnmOOExport
*state
, GogObject
const *title
)
955 gboolean is_position_manual
= TRUE
;
957 g_object_get (G_OBJECT (title
),
958 "is-position-manual", &is_position_manual
,
961 if (is_position_manual
) {
962 GogView
*view
= gog_view_find_child_view (state
->root_view
, title
);
963 odf_add_pt (state
->xml
, SVG
"x", view
->allocation
.x
);
964 odf_add_pt (state
->xml
, SVG
"y", view
->allocation
.y
);
969 odf_write_gog_position (GnmOOExport
*state
, GogObject
const *obj
)
971 gboolean is_position_manual
= TRUE
;
972 gchar
*position
= NULL
, *anchor
= NULL
, *compass
= NULL
;
974 if (!state
->with_extension
)
977 (void)gnm_object_has_readable_prop (obj
, "compass",
978 G_TYPE_NONE
, &compass
);
979 g_object_get (G_OBJECT (obj
),
980 "is-position-manual", &is_position_manual
,
981 "position", &position
,
984 odf_add_bool (state
->xml
, GNMSTYLE
"is-position-manual", is_position_manual
);
985 if (is_position_manual
) {
987 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"position", position
);
989 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"anchor", anchor
);
991 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"compass", position
);
999 odf_write_gog_plot_area_position (GnmOOExport
*state
, GogObject
const *obj
)
1001 gboolean is_position_manual
= TRUE
;
1002 gchar
*position
= NULL
;
1004 if (!state
->with_extension
)
1007 g_object_get (G_OBJECT (obj
),
1008 "is-plot-area-manual", &is_position_manual
,
1009 "plot-area", &position
,
1011 odf_add_bool (state
->xml
, GNMSTYLE
"is-position-manual", is_position_manual
);
1012 if (is_position_manual
&& position
)
1013 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"position", position
);
1019 odf_get_border_format (GnmBorder
*border
)
1021 GString
*str
= g_string_new (NULL
);
1022 double w
= gnm_style_border_get_width (border
->line_type
);
1023 GnmColor
*color
= border
->color
;
1024 char const *border_type
;
1026 switch (border
->line_type
) {
1027 case GNM_STYLE_BORDER_THIN
:
1029 border_type
= "solid";
1031 case GNM_STYLE_BORDER_MEDIUM
:
1032 border_type
= "solid";
1034 case GNM_STYLE_BORDER_DASHED
:
1035 border_type
= "dashed";
1037 case GNM_STYLE_BORDER_DOTTED
:
1038 border_type
= "dotted";
1040 case GNM_STYLE_BORDER_THICK
:
1041 border_type
= "solid";
1043 case GNM_STYLE_BORDER_DOUBLE
:
1044 border_type
= "double";
1046 case GNM_STYLE_BORDER_HAIR
:
1048 border_type
= "solid";
1050 case GNM_STYLE_BORDER_MEDIUM_DASH
:
1051 border_type
= "dashed";
1053 case GNM_STYLE_BORDER_DASH_DOT
:
1054 border_type
= "dashed";
1056 case GNM_STYLE_BORDER_MEDIUM_DASH_DOT
:
1057 border_type
= "dashed";
1059 case GNM_STYLE_BORDER_DASH_DOT_DOT
:
1060 border_type
= "dotted";
1062 case GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT
:
1063 border_type
= "dotted";
1065 case GNM_STYLE_BORDER_SLANTED_DASH_DOT
:
1066 border_type
= "dotted";
1068 case GNM_STYLE_BORDER_NONE
:
1071 border_type
= "none";
1075 w
= GO_PT_TO_CM (w
);
1076 g_string_append_printf (str
, "%.3fcm ", w
);
1077 g_string_append (str
, border_type
);
1078 g_string_append_printf (str
, " #%.2x%.2x%.2x",
1079 GO_COLOR_UINT_R (color
->go_color
),
1080 GO_COLOR_UINT_G (color
->go_color
),
1081 GO_COLOR_UINT_B (color
->go_color
));
1082 return g_string_free (str
, FALSE
);
1086 odf_get_gnm_border_format (GnmBorder
*border
)
1088 char const *border_type
= NULL
;
1090 switch (border
->line_type
) {
1091 case GNM_STYLE_BORDER_HAIR
:
1092 border_type
= "hair";
1094 case GNM_STYLE_BORDER_MEDIUM_DASH
:
1095 border_type
= "medium-dash";
1097 case GNM_STYLE_BORDER_DASH_DOT
:
1098 border_type
= "dash-dot";
1100 case GNM_STYLE_BORDER_MEDIUM_DASH_DOT
:
1101 border_type
= "medium-dash-dot";
1103 case GNM_STYLE_BORDER_DASH_DOT_DOT
:
1104 border_type
= "dash-dot-dot";
1106 case GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT
:
1107 border_type
= "medium-dash-dot-dot";
1109 case GNM_STYLE_BORDER_SLANTED_DASH_DOT
:
1110 border_type
= "slanted-dash-dot";
1119 /* ODF write style */
1121 /* We have to write our style information and map them to ODF expectations */
1122 /* This is supposed to match how we read the styles again in openoffice-read.c */
1123 /* Note that we are introducing foreign elemetns as required for round tripping */
1126 #define BORDERSTYLE(msbw, msbwstr, msbwstr_wth, msbwstr_gnm) if (gnm_style_is_element_set (style, msbw)) { \
1127 GnmBorder *border = gnm_style_get_border (style, msbw); \
1128 if (border != NULL) { \
1129 char *border_style = odf_get_border_format (border); \
1130 char const *gnm_border_style = odf_get_gnm_border_format (border); \
1131 gsf_xml_out_add_cstr_unchecked (state->xml, msbwstr, border_style); \
1132 g_free (border_style); \
1133 if (gnm_border_style != NULL && state->with_extension) \
1134 gsf_xml_out_add_cstr_unchecked (state->xml, msbwstr_gnm, gnm_border_style); \
1135 if (border->line_type == GNM_STYLE_BORDER_DOUBLE) \
1136 gsf_xml_out_add_cstr_unchecked (state->xml, msbwstr_wth, "0.03cm 0.03cm 0.03cm "); \
1140 #define UNDERLINESPECS(type, style, width, low) gsf_xml_out_add_cstr (state->xml, \
1141 STYLE "text-underline-type", type); \
1142 gsf_xml_out_add_cstr (state->xml, \
1143 STYLE "text-underline-style", style); \
1144 gsf_xml_out_add_cstr (state->xml, \
1145 STYLE "text-underline-width", width); \
1146 gsf_xml_out_add_cstr_unchecked (state->xml, \
1147 STYLE "text-underline-color", "font-color"); \
1148 gsf_xml_out_add_cstr_unchecked (state->xml, \
1149 STYLE "text-underline-mode", "continuous"); \
1150 if (low && state->with_extension) \
1151 gsf_xml_out_add_cstr_unchecked (state->xml, \
1152 GNMSTYLE "text-underline-placement", "low"); \
1155 odf_write_style_cell_properties (GnmOOExport
*state
, GnmStyle
const *style
)
1157 gboolean test1
, test2
;
1159 gsf_xml_out_start_element (state
->xml
, STYLE
"table-cell-properties");
1160 /* Background Color */
1161 if (gnm_style_is_element_set (style
, MSTYLE_COLOR_BACK
)) {
1162 gboolean pattern_set
= gnm_style_is_element_set (style
, MSTYLE_PATTERN
);
1163 int pattern
= pattern_set
? gnm_style_get_pattern (style
) : 1;
1165 gnm_xml_out_add_hex_color (state
->xml
, FOSTYLE
"background-color",
1166 gnm_style_get_back_color (style
), pattern
);
1167 if (state
->with_extension
) {
1168 /* We save this to retain as much state as possible. */
1169 gnm_xml_out_add_hex_color (state
->xml
, GNMSTYLE
"background-colour",
1170 gnm_style_get_back_color (style
), 1);
1171 if (gnm_style_is_element_set (style
, MSTYLE_COLOR_PATTERN
))
1172 gnm_xml_out_add_hex_color (state
->xml
, GNMSTYLE
"pattern-colour",
1173 gnm_style_get_pattern_color (style
), 1);
1174 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"pattern", pattern
);
1178 BORDERSTYLE(MSTYLE_BORDER_TOP
,FOSTYLE
"border-top", STYLE
"border-line-width-top", GNMSTYLE
"border-line-style-top");
1179 BORDERSTYLE(MSTYLE_BORDER_BOTTOM
,FOSTYLE
"border-bottom", STYLE
"border-line-width-bottom", GNMSTYLE
"border-line-style-bottom");
1180 BORDERSTYLE(MSTYLE_BORDER_LEFT
,FOSTYLE
"border-left", STYLE
"border-line-width-left", GNMSTYLE
"border-line-style-left");
1181 BORDERSTYLE(MSTYLE_BORDER_RIGHT
,FOSTYLE
"border-right", STYLE
"border-line-width-right", GNMSTYLE
"border-line-style-right");
1182 BORDERSTYLE(MSTYLE_BORDER_DIAGONAL
,STYLE
"diagonal-bl-tr", STYLE
"diagonal-bl-tr-widths", GNMSTYLE
"diagonal-bl-tr-line-style");
1183 BORDERSTYLE(MSTYLE_BORDER_REV_DIAGONAL
,STYLE
"diagonal-tl-br", STYLE
"diagonal-tl-br-widths", GNMSTYLE
"diagonal-tl-br-line-style");
1184 /* note that we are at this time not setting any of:
1186 fo:padding-bottom 18.210,
1187 fo:padding-left 18.211,
1188 fo:padding-right 18.212,
1189 fo:padding-top 18.213,
1190 style:shadow 18.347,
1193 /* Vertical Alignment */
1194 if (gnm_style_is_element_set (style
, MSTYLE_ALIGN_V
)) {
1195 GnmVAlign align
= gnm_style_get_align_v (style
);
1196 char const *alignment
= NULL
;
1197 gboolean gnum_specs
= FALSE
;
1199 case GNM_VALIGN_TOP
:
1202 case GNM_VALIGN_BOTTOM
:
1203 alignment
= "bottom";
1205 case GNM_VALIGN_CENTER
:
1206 alignment
= "middle";
1208 case GNM_VALIGN_JUSTIFY
:
1209 case GNM_VALIGN_DISTRIBUTED
:
1211 alignment
= "automatic";
1215 gsf_xml_out_add_cstr (state
->xml
, STYLE
"vertical-align", alignment
);
1216 if (gnum_specs
&& state
->with_extension
)
1217 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"GnmVAlign", align
);
1221 if (gnm_style_is_element_set (style
, MSTYLE_WRAP_TEXT
))
1222 gsf_xml_out_add_cstr (state
->xml
, FOSTYLE
"wrap-option",
1223 gnm_style_get_wrap_text (style
) ? "wrap" : "no-wrap");
1226 if (gnm_style_is_element_set (style
, MSTYLE_SHRINK_TO_FIT
))
1227 odf_add_bool (state
->xml
, STYLE
"shrink-to-fit",
1228 gnm_style_get_shrink_to_fit (style
));
1230 /* Text Direction */
1231 /* Note that fo:direction, style:writing-mode and style:writing-mode-automatic interact. */
1232 /* style:writing-mode-automatic is set in the paragraph properties below. */
1233 if (gnm_style_is_element_set (style
, MSTYLE_TEXT_DIR
)) {
1234 char const *writing_mode
= NULL
;
1235 char const *direction
= NULL
;
1236 switch (gnm_style_get_text_dir (style
)) {
1237 case GNM_TEXT_DIR_RTL
:
1238 writing_mode
= "rl-tb";
1240 case GNM_TEXT_DIR_LTR
:
1241 writing_mode
= "lr-tb";
1244 case GNM_TEXT_DIR_CONTEXT
:
1245 writing_mode
= "page";
1246 /* Note that we will be setting style:writing-mode-automatic below */
1249 if (state
->odf_version
> 101)
1250 gsf_xml_out_add_cstr (state
->xml
, STYLE
"writing-mode", writing_mode
);
1251 if (direction
!= NULL
)
1252 gsf_xml_out_add_cstr (state
->xml
, FOSTYLE
"direction", direction
);
1253 gsf_xml_out_add_cstr (state
->xml
, STYLE
"glyph-orientation-vertical", "auto");
1256 /* Cell Protection */
1257 test1
= gnm_style_is_element_set (style
, MSTYLE_CONTENTS_HIDDEN
);
1258 test2
= gnm_style_is_element_set (style
, MSTYLE_CONTENTS_LOCKED
);
1259 if (test1
|| test2
) {
1260 gboolean hidden
= test1
&& gnm_style_get_contents_hidden (style
);
1261 gboolean
protected = test2
&& gnm_style_get_contents_locked (style
);
1265 label
= protected ? "hidden-and-protected" : "formula-hidden";
1267 label
= protected ? "protected" : "none";
1268 gsf_xml_out_add_cstr (state
->xml
, STYLE
"cell-protect", label
);
1272 if (gnm_style_is_element_set (style
, MSTYLE_ROTATION
)) {
1273 gsf_xml_out_add_cstr (state
->xml
, STYLE
"rotation-align", "none");
1274 odf_add_angle (state
->xml
, STYLE
"rotation-angle", gnm_style_get_rotation (style
));
1278 odf_add_bool (state
->xml
, STYLE
"print-content", TRUE
);
1280 /* Decimal Places (this is the maximum number of decimal places shown if not otherwise specified.) */
1281 /* Only interpreted in a default style. */
1282 gsf_xml_out_add_int (state
->xml
, STYLE
"decimal-places", 13);
1284 /* Horizontal Alignment */
1285 if (gnm_style_is_element_set (style
, MSTYLE_ALIGN_H
)) {
1286 GnmHAlign align
= gnm_style_get_align_h (style
);
1287 char const *source
= NULL
;
1288 gboolean rep_content
= FALSE
;
1291 case GNM_HALIGN_DISTRIBUTED
:
1292 case GNM_HALIGN_LEFT
:
1293 case GNM_HALIGN_RIGHT
:
1294 case GNM_HALIGN_CENTER
:
1295 case GNM_HALIGN_JUSTIFY
:
1296 case GNM_HALIGN_CENTER_ACROSS_SELECTION
:
1299 case GNM_HALIGN_FILL
:
1301 case GNM_HALIGN_GENERAL
:
1303 /* Note that since source is value-type, alignment should be ignored */
1304 /*(but isn't by OOo) */
1305 source
= "value-type";
1308 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-align-source", source
);
1309 /* Repeat Content */
1310 odf_add_bool (state
->xml
, STYLE
"repeat-content", rep_content
);
1313 gsf_xml_out_end_element (state
->xml
); /* </style:table-cell-properties */
1317 odf_write_style_paragraph_properties (GnmOOExport
*state
, GnmStyle
const *style
)
1319 gsf_xml_out_start_element (state
->xml
, STYLE
"paragraph-properties");
1320 /* Text Direction */
1321 /* Note that fo:direction, style:writing-mode and style:writing-mode-automatic interact. */
1322 /* fo:direction and style:writing-mode may have been set in the cell properties above. */
1323 if (gnm_style_is_element_set (style
, MSTYLE_TEXT_DIR
))
1324 odf_add_bool (state
->xml
, STYLE
"writing-mode-automatic",
1325 (gnm_style_get_text_dir (style
) == GNM_TEXT_DIR_CONTEXT
));
1327 /* Horizontal Alignment */
1328 if (gnm_style_is_element_set (style
, MSTYLE_ALIGN_H
)) {
1329 GnmHAlign align
= gnm_style_get_align_h (style
);
1330 char const *alignment
= NULL
;
1331 gboolean gnum_specs
= FALSE
;
1333 case GNM_HALIGN_LEFT
:
1336 case GNM_HALIGN_RIGHT
:
1339 case GNM_HALIGN_CENTER
:
1340 alignment
= "center";
1342 case GNM_HALIGN_JUSTIFY
:
1343 alignment
= "justify";
1345 case GNM_HALIGN_DISTRIBUTED
:
1346 alignment
= "justify";
1349 case GNM_HALIGN_FILL
:
1350 /* handled by repeat-content */
1352 case GNM_HALIGN_CENTER_ACROSS_SELECTION
:
1353 alignment
= "center";
1356 case GNM_HALIGN_GENERAL
:
1358 /* Note that since source is value-type, alignment should be ignored */
1359 /*(but isn't by OOo) */
1360 alignment
= "start";
1364 if (align
!= GNM_HALIGN_GENERAL
&& align
!= GNM_HALIGN_FILL
)
1365 gsf_xml_out_add_cstr (state
->xml
, FOSTYLE
"text-align", alignment
);
1366 if (state
->with_extension
) {
1368 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"GnmHAlign", align
);
1369 if (align
== GNM_HALIGN_DISTRIBUTED
)
1370 gsf_xml_out_add_cstr (state
->xml
, CSS
"text-justify", "distribute");
1375 if (gnm_style_is_element_set (style
, MSTYLE_INDENT
))
1376 odf_add_pt (state
->xml
, FOSTYLE
"margin-left", gnm_style_get_indent (style
));
1378 gsf_xml_out_end_element (state
->xml
); /* </style:paragraph-properties */
1384 odf_write_style_text_properties (GnmOOExport
*state
, GnmStyle
const *style
)
1386 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1389 if (gnm_style_is_element_set (style
, MSTYLE_CONTENTS_HIDDEN
)) {
1390 char const *label
= gnm_style_get_contents_hidden (style
) ?
1392 gsf_xml_out_add_cstr (state
->xml
, TEXT
"display", label
);
1396 if (gnm_style_is_element_set (style
, MSTYLE_FONT_BOLD
))
1397 odf_add_font_weight (state
,
1398 gnm_style_get_font_bold (style
)
1400 : PANGO_WEIGHT_NORMAL
);
1401 /* Font Style (Italic vs Roman) */
1402 if (gnm_style_is_element_set (style
, MSTYLE_FONT_ITALIC
))
1403 gsf_xml_out_add_cstr (state
->xml
, FOSTYLE
"font-style",
1404 gnm_style_get_font_italic (style
)
1405 ? "italic" : "normal");
1407 if (gnm_style_is_element_set (style
, MSTYLE_FONT_STRIKETHROUGH
)) {
1408 if (gnm_style_get_font_strike (style
)) {
1409 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-line-through-type", "single");
1410 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-line-through-style", "solid");
1412 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-line-through-type", "none");
1413 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-line-through-style", "none");
1417 if (gnm_style_is_element_set (style
, MSTYLE_FONT_UNDERLINE
))
1418 switch (gnm_style_get_font_uline (style
)) {
1419 case UNDERLINE_NONE
:
1420 UNDERLINESPECS("none", "none", "auto", FALSE
);
1422 case UNDERLINE_SINGLE
:
1423 UNDERLINESPECS("single", "solid", "auto", FALSE
);
1425 case UNDERLINE_DOUBLE
:
1426 UNDERLINESPECS("double", "solid", "auto", FALSE
);
1428 case UNDERLINE_SINGLE_LOW
:
1429 UNDERLINESPECS("single", "dash", "auto", TRUE
);
1431 case UNDERLINE_DOUBLE_LOW
:
1432 UNDERLINESPECS("double", "dash", "auto", TRUE
);
1435 /* Superscript/Subscript */
1436 if (gnm_style_is_element_set (style
, MSTYLE_FONT_SCRIPT
))
1437 switch (gnm_style_get_font_script (style
)) {
1438 case GO_FONT_SCRIPT_SUB
:
1439 gsf_xml_out_add_cstr (state
->xml
,
1440 STYLE
"text-position", "sub 80%");
1442 case GO_FONT_SCRIPT_STANDARD
:
1443 gsf_xml_out_add_cstr (state
->xml
,
1444 STYLE
"text-position", "0% 100%");
1446 case GO_FONT_SCRIPT_SUPER
:
1447 gsf_xml_out_add_cstr (state
->xml
,
1448 STYLE
"text-position", "super 80%");
1452 if (gnm_style_is_element_set (style
, MSTYLE_FONT_SIZE
))
1453 odf_add_pt (state
->xml
, FOSTYLE
"font-size",
1454 gnm_style_get_font_size (style
));
1455 /* Foreground Color */
1456 if (gnm_style_is_element_set (style
, MSTYLE_FONT_COLOR
))
1457 gnm_xml_out_add_hex_color (state
->xml
, FOSTYLE
"color",
1458 gnm_style_get_font_color (style
), 1);
1460 if (gnm_style_is_element_set (style
, MSTYLE_FONT_NAME
))
1461 gsf_xml_out_add_cstr (state
->xml
, FOSTYLE
"font-family",
1462 gnm_style_get_font_name (style
));
1464 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1469 odf_write_style_goformat_name (GnmOOExport
*state
, GOFormat
const *gof
)
1473 if ((gof
== NULL
) || go_format_is_markup (gof
))
1476 if (go_format_is_general (gof
))
1479 name
= xl_find_format (state
, gof
);
1481 gsf_xml_out_add_cstr (state
->xml
, STYLE
"data-style-name", name
);
1485 odf_find_style (GnmOOExport
*state
, GnmStyle
const *style
)
1487 char const *found
= g_hash_table_lookup (state
->named_cell_styles
, style
);
1489 if (found
== NULL
) {
1490 found
= g_hash_table_lookup (state
->cell_styles
, style
);
1493 if (found
== NULL
) {
1494 g_printerr ("Could not find style %p\n", style
);
1502 odf_save_style_map_single_f (GnmOOExport
*state
, GString
*str
, GnmExprTop
const *texpr
, GnmParsePos
*pp
)
1506 formula
= gnm_expr_top_as_string (texpr
, pp
, state
->conv
);
1507 g_string_append (str
, formula
);
1513 odf_save_style_map_double_f (GnmOOExport
*state
, GString
*str
, GnmStyleCond
const *cond
, GnmParsePos
*pp
)
1515 g_string_append_c (str
, '(');
1516 odf_save_style_map_single_f (state
, str
, gnm_style_cond_get_expr (cond
, 0), pp
);
1517 g_string_append_c (str
, ',');
1518 odf_save_style_map_single_f (state
, str
, gnm_style_cond_get_expr (cond
, 1), pp
);
1519 g_string_append_c (str
, ')');
1523 odf_strip_brackets (char *string
)
1526 closing
= strrchr(string
, ']');
1527 if (closing
!= NULL
&& *(closing
+1) == '\0')
1529 return ((*string
== '[') ? (string
+ 1) : string
);
1533 odf_determine_base (GnmOOExport
*state
, GnmRange
*r
, GnmParsePos
*pp
)
1536 parse_pos_init (pp
, (Workbook
*) state
->wb
, state
->sheet
, r
->start
.col
, r
->start
.row
);
1538 g_warning ("Unable to determine an appropriate base cell address.");
1539 parse_pos_init (pp
, (Workbook
*) state
->wb
, state
->sheet
, 0, 0);
1544 odf_save_style_map (GnmOOExport
*state
, GnmStyleCond
const *cond
, GnmRange
*r
)
1546 char const *name
= odf_find_style (state
, cond
->overlay
);
1549 GnmExprTop
const *texpr
= NULL
;
1552 GnmStyleCondOp op
= cond
->op
;
1554 g_return_if_fail (name
!= NULL
);
1556 str
= g_string_new (NULL
);
1559 case GNM_STYLE_COND_CONTAINS_STR
:
1560 case GNM_STYLE_COND_NOT_CONTAINS_STR
:
1561 case GNM_STYLE_COND_BEGINS_WITH_STR
:
1562 case GNM_STYLE_COND_NOT_BEGINS_WITH_STR
:
1563 case GNM_STYLE_COND_ENDS_WITH_STR
:
1564 case GNM_STYLE_COND_NOT_ENDS_WITH_STR
:
1565 case GNM_STYLE_COND_CONTAINS_ERR
:
1566 case GNM_STYLE_COND_NOT_CONTAINS_ERR
:
1567 case GNM_STYLE_COND_CONTAINS_BLANKS
:
1568 case GNM_STYLE_COND_NOT_CONTAINS_BLANKS
:
1569 texpr
= gnm_style_cond_get_alternate_expr (cond
);
1570 op
= GNM_STYLE_COND_CUSTOM
;
1577 case GNM_STYLE_COND_BETWEEN
:
1578 odf_determine_base (state
, r
, &pp
);
1579 g_string_append (str
, "of:cell-content-is-between");
1580 odf_save_style_map_double_f (state
, str
, cond
, &pp
);
1582 case GNM_STYLE_COND_NOT_BETWEEN
:
1583 odf_determine_base (state
, r
, &pp
);
1584 g_string_append (str
, "of:cell-content-is-not-between");
1585 odf_save_style_map_double_f (state
, str
, cond
, &pp
);
1587 case GNM_STYLE_COND_EQUAL
:
1588 odf_determine_base (state
, r
, &pp
);
1589 g_string_append (str
, "of:cell-content()=");
1590 odf_save_style_map_single_f (state
, str
, gnm_style_cond_get_expr (cond
, 0), &pp
);
1592 case GNM_STYLE_COND_NOT_EQUAL
:
1593 odf_determine_base (state
, r
, &pp
);
1594 g_string_append (str
, "of:cell-content()!=");
1595 odf_save_style_map_single_f (state
, str
, gnm_style_cond_get_expr (cond
, 0), &pp
);
1597 case GNM_STYLE_COND_GT
:
1598 odf_determine_base (state
, r
, &pp
);
1599 g_string_append (str
, "of:cell-content()>");
1600 odf_save_style_map_single_f (state
, str
, gnm_style_cond_get_expr (cond
, 0), &pp
);
1602 case GNM_STYLE_COND_LT
:
1603 odf_determine_base (state
, r
, &pp
);
1604 g_string_append (str
, "of:cell-content()<");
1605 odf_save_style_map_single_f (state
, str
, gnm_style_cond_get_expr (cond
, 0), &pp
);
1607 case GNM_STYLE_COND_GTE
:
1608 odf_determine_base (state
, r
, &pp
);
1609 g_string_append (str
, "of:cell-content()>=");
1610 odf_save_style_map_single_f (state
, str
, gnm_style_cond_get_expr (cond
, 0), &pp
);
1612 case GNM_STYLE_COND_LTE
:
1613 odf_determine_base (state
, r
, &pp
);
1614 g_string_append (str
, "of:cell-content()<=");
1615 odf_save_style_map_single_f (state
, str
, gnm_style_cond_get_expr (cond
, 0), &pp
);
1617 case GNM_STYLE_COND_CUSTOM
:
1618 odf_determine_base (state
, r
, &pp
);
1619 g_string_append (str
, "of:is-true-formula(");
1620 odf_save_style_map_single_f (state
, str
, texpr
? texpr
: gnm_style_cond_get_expr (cond
, 0), &pp
);
1621 g_string_append (str
, ")");
1624 g_string_free (str
, TRUE
);
1625 g_warning ("Unknown style condition %d", op
);
1630 gnm_expr_top_unref (texpr
);
1634 gsf_xml_out_start_element (state
->xml
, STYLE
"map");
1636 gsf_xml_out_add_cstr (state
->xml
, STYLE
"apply-style-name", name
);
1637 gsf_xml_out_add_cstr (state
->xml
, STYLE
"condition", str
->str
);
1639 /* ODF 1.2 requires a sheet name for the base-cell-address */
1640 /* This is really only needed if we include a formula */
1641 gnm_cellref_init (&ref
, (Sheet
*)state
->sheet
,
1642 pp
.eval
.col
, pp
.eval
.row
, FALSE
);
1643 texpr
= gnm_expr_top_new (gnm_expr_new_cellref (&ref
));
1644 parse_pos_init_sheet (&pp
, state
->sheet
);
1645 address
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
1646 gsf_xml_out_add_cstr (state
->xml
, STYLE
"base-cell-address", odf_strip_brackets (address
));
1648 gnm_expr_top_unref (texpr
);
1650 gsf_xml_out_end_element (state
->xml
); /* </style:map> */
1652 g_string_free (str
, TRUE
);
1656 odf_write_style (GnmOOExport
*state
, GnmStyle
const *style
, GnmRange
*r
, gboolean is_default
)
1658 GnmStyleConditions
const *sc
;
1659 GPtrArray
const *conds
;
1662 if ((!is_default
) && gnm_style_is_element_set (style
, MSTYLE_FORMAT
)) {
1663 GOFormat
const *format
= gnm_style_get_format(style
);
1665 odf_write_style_goformat_name (state
, format
);
1668 odf_write_style_cell_properties (state
, style
);
1669 odf_write_style_paragraph_properties (state
, style
);
1670 odf_write_style_text_properties (state
, style
);
1672 if (gnm_style_is_element_set (style
, MSTYLE_CONDITIONS
) &&
1673 NULL
!= (sc
= gnm_style_get_conditions (style
)) &&
1674 NULL
!= (conds
= gnm_style_conditions_details (sc
))) {
1675 for (i
= 0 ; i
< conds
->len
; i
++) {
1676 GnmStyleCond
const *cond
= g_ptr_array_index (conds
, i
);
1677 odf_save_style_map (state
, cond
, r
);
1681 /* MSTYLE_VALIDATION validations need to be written at a different place and time in ODF */
1682 /* MSTYLE_HLINK hyperlinks can not be attached to styles but need to be attached to the cell content */
1685 #undef UNDERLINESPECS
1689 odf_compare_ci (gconstpointer a
, gconstpointer b
)
1691 col_row_styles_t
const *old_style
= a
;
1692 ColRowInfo
const *new_style
= b
;
1694 return !colrow_equal (new_style
, old_style
->ci
);
1698 col_row_styles_free (gpointer data
)
1700 col_row_styles_t
*style
= data
;
1703 g_free (style
->name
);
1709 odf_write_row_style (GnmOOExport
*state
, ColRowInfo
const *ci
)
1711 gsf_xml_out_start_element (state
->xml
, STYLE
"table-row-properties");
1712 odf_add_pt (state
->xml
, STYLE
"row-height", ci
->size_pts
);
1713 odf_add_bool (state
->xml
, STYLE
"use-optimal-row-height",
1715 gsf_xml_out_end_element (state
->xml
); /* </style:table-row-properties> */
1719 odf_find_row_style (GnmOOExport
*state
, ColRowInfo
const *ci
, gboolean write
)
1721 col_row_styles_t
*new_style
;
1722 GSList
*found
= g_slist_find_custom (state
->row_styles
, ci
, odf_compare_ci
);
1725 new_style
= found
->data
;
1726 return new_style
->name
;
1729 new_style
= g_new0 (col_row_styles_t
,1);
1731 new_style
->name
= g_strdup_printf ("AROW-%i", g_slist_length (state
->row_styles
));
1732 state
->row_styles
= g_slist_prepend (state
->row_styles
, new_style
);
1733 odf_start_style (state
->xml
, new_style
->name
, "table-row");
1735 odf_write_row_style (state
, ci
);
1736 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1737 return new_style
->name
;
1739 g_warning("We forgot to export a required row style!");
1740 return "Missing-Row-Style";
1746 odf_write_col_style (GnmOOExport
*state
, ColRowInfo
const *ci
)
1748 gsf_xml_out_start_element (state
->xml
, STYLE
"table-column-properties");
1749 odf_add_pt (state
->xml
, STYLE
"column-width", ci
->size_pts
);
1750 odf_add_bool (state
->xml
, STYLE
"use-optimal-column-width",
1752 gsf_xml_out_end_element (state
->xml
); /* </style:table-column-properties> */
1756 odf_find_col_style (GnmOOExport
*state
, ColRowInfo
const *ci
, gboolean write
)
1758 col_row_styles_t
*new_style
;
1759 GSList
*found
= g_slist_find_custom (state
->col_styles
, ci
, odf_compare_ci
);
1762 new_style
= found
->data
;
1763 return new_style
->name
;
1766 new_style
= g_new0 (col_row_styles_t
,1);
1768 new_style
->name
= g_strdup_printf ("ACOL-%i", g_slist_length (state
->col_styles
));
1769 state
->col_styles
= g_slist_prepend (state
->col_styles
, new_style
);
1770 odf_start_style (state
->xml
, new_style
->name
, "table-column");
1772 odf_write_col_style (state
, ci
);
1773 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1774 return new_style
->name
;
1776 g_warning("We forgot to export a required column style!");
1777 return "Missing-Column-Style";
1783 odf_save_this_style_with_name (GnmStyleRegion
*sr
, char const *name
, GnmOOExport
*state
)
1785 odf_start_style (state
->xml
, name
, "table-cell");
1786 odf_write_style (state
, sr
->style
, &sr
->range
, FALSE
);
1787 gsf_xml_out_end_element (state
->xml
); /* </style:style */
1791 odf_store_this_named_style (GnmStyle
*style
, char const *name
, GnmRange
*r
, GnmOOExport
*state
)
1794 GnmStyleConditions
const *sc
;
1797 int i
= g_hash_table_size (state
->named_cell_styles
);
1798 /* All styles referenced by a style:map need to be named, so in that case */
1799 /* we make up a name, that ought to look nice */
1800 real_name
= g_strdup_printf ("Gnumeric-%i", i
);
1802 real_name
= g_strdup (name
);
1804 g_hash_table_insert (state
->named_cell_styles
, style
, real_name
);
1805 g_hash_table_insert (state
->named_cell_style_regions
, gnm_style_region_new (r
, style
),
1806 g_strdup (real_name
));
1808 if (gnm_style_is_element_set (style
, MSTYLE_CONDITIONS
) &&
1809 NULL
!= (sc
= gnm_style_get_conditions (style
))) {
1810 GPtrArray
const *conds
= gnm_style_conditions_details (sc
);
1811 if (conds
!= NULL
) {
1813 for (i
= 0 ; i
< conds
->len
; i
++) {
1814 GnmStyleCond
const *cond
=
1815 g_ptr_array_index (conds
, i
);
1816 odf_store_this_named_style (cond
->overlay
, NULL
, r
, state
);
1823 odf_save_this_style (G_GNUC_UNUSED gconstpointer dummy
, GnmStyleRegion
*sr
, GnmOOExport
*state
)
1826 GnmStyleConditions
const *sc
;
1828 if (NULL
!= g_hash_table_lookup (state
->cell_styles
, sr
->style
))
1831 name
= oo_item_name (state
, OO_ITEM_MSTYLE
, sr
->style
);
1832 g_hash_table_insert (state
->cell_styles
, sr
->style
, name
);
1834 if (gnm_style_is_element_set (sr
->style
, MSTYLE_CONDITIONS
) &&
1835 NULL
!= (sc
= gnm_style_get_conditions (sr
->style
))) {
1836 GPtrArray
const *conds
= gnm_style_conditions_details (sc
);
1837 if (conds
!= NULL
) {
1839 for (i
= 0 ; i
< conds
->len
; i
++) {
1840 GnmStyleCond
const *cond
=
1841 g_ptr_array_index (conds
, i
);
1842 odf_store_this_named_style (cond
->overlay
, NULL
, &sr
->range
, state
);
1847 odf_save_this_style_with_name (sr
, name
, state
);
1851 odf_write_text_colours (char const *name
, G_GNUC_UNUSED gpointer data
, GnmOOExport
*state
)
1853 char const *colour
= data
;
1854 char *display
= g_strdup_printf ("Font Color %s", colour
);
1855 odf_start_style (state
->xml
, name
, "text");
1856 gsf_xml_out_add_cstr (state
->xml
, STYLE
"display-name", display
);
1857 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1858 gsf_xml_out_add_cstr (state
->xml
, FOSTYLE
"color", colour
);
1859 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1860 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1865 odf_write_font_sizes (gpointer key
, gpointer value
, gpointer user_data
)
1867 GnmOOExport
*state
= user_data
;
1868 gint i
= GPOINTER_TO_INT (value
);
1870 char *display
= g_strdup_printf ("Font Size %ipt", i
);
1871 odf_start_style (state
->xml
, str
, "text");
1872 gsf_xml_out_add_cstr (state
->xml
, STYLE
"display-name", display
);
1873 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1874 odf_add_pt (state
->xml
, FOSTYLE
"font-size", (double) i
);
1875 odf_add_pt (state
->xml
, STYLE
"font-size-asian", (double) i
);
1876 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1877 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1882 odf_write_character_styles (GnmOOExport
*state
)
1886 for (i
= 100; i
<= 1000; i
+=100) {
1887 char * str
= g_strdup_printf ("AC-weight%i", i
);
1888 odf_start_style (state
->xml
, str
, "text");
1889 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1890 odf_add_font_weight (state
, i
);
1891 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1892 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1896 odf_start_style (state
->xml
, "AC-italic", "text");
1897 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1898 gsf_xml_out_add_cstr (state
->xml
, FOSTYLE
"font-style", "italic");
1899 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1900 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1902 odf_start_style (state
->xml
, "AC-roman", "text");
1903 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1904 gsf_xml_out_add_cstr (state
->xml
, FOSTYLE
"font-style", "normal");
1905 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1906 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1908 odf_start_style (state
->xml
, "AC-subscript", "text");
1909 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1910 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-position", "sub 83%");
1911 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1912 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1914 odf_start_style (state
->xml
, "AC-superscript", "text");
1915 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1916 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-position", "super 83%");
1917 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1918 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1920 odf_start_style (state
->xml
, "AC-script", "text");
1921 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1922 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-position", "0% 100%");
1923 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1924 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1926 odf_start_style (state
->xml
, "AC-strikethrough-solid", "text");
1927 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1928 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-line-through-type", "single");
1929 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-line-through-style", "solid");
1930 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1931 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1933 odf_start_style (state
->xml
, "AC-strikethrough-none", "text");
1934 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1935 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-line-through-type", "none");
1936 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-line-through-style", "none");
1937 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1938 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1940 odf_start_style (state
->xml
, "AC-underline-none", "text");
1941 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1942 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-type", "none");
1943 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-style", "none");
1944 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-width", "auto");
1945 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1946 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1948 odf_start_style (state
->xml
, "AC-underline-single", "text");
1949 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1950 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-type", "single");
1951 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-style", "solid");
1952 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-width", "auto");
1953 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1954 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1956 odf_start_style (state
->xml
, "AC-underline-double", "text");
1957 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1958 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-type", "double");
1959 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-style", "solid");
1960 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-width", "auto");
1961 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1962 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1964 odf_start_style (state
->xml
, "AC-underline-low", "text");
1965 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1966 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-type", "single");
1967 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-style", "solid");
1968 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-width", "bold");
1969 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1970 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1972 odf_start_style (state
->xml
, "AC-underline-error", "text");
1973 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
1974 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-type", "single");
1975 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-style", "wave");
1976 gsf_xml_out_add_cstr (state
->xml
, STYLE
"text-underline-width", "auto");
1977 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
1978 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
1980 if (state
->row_default
!= NULL
)
1981 odf_find_row_style (state
, state
->row_default
, TRUE
);
1982 if (state
->column_default
!= NULL
)
1983 odf_find_col_style (state
, state
->column_default
, TRUE
);
1988 odf_write_cell_styles (GnmOOExport
*state
)
1991 for (i
= 0; i
< workbook_sheet_count (state
->wb
); i
++) {
1992 state
->sheet
= workbook_sheet_by_index (state
->wb
, i
);
1993 sheet_style_range_foreach (state
->sheet
, NULL
,
1994 (GHFunc
) odf_save_this_style
,
1997 state
->sheet
= NULL
;
2001 odf_write_column_styles (GnmOOExport
*state
)
2003 /* We have to figure out which automatic styles we need */
2004 /* This is really annoying since we have to scan through */
2005 /* all columnss. If we could store these styless in styles.xml */
2006 /* we could create them as we need them, but these styles */
2007 /* have to go into the beginning of content.xml. */
2010 for (j
= 0; j
< workbook_sheet_count (state
->wb
); j
++) {
2011 Sheet
const *sheet
= workbook_sheet_by_index (state
->wb
, j
);
2012 int max_cols
= gnm_sheet_get_max_cols (sheet
);
2014 ColRowInfo
const *last_ci
;
2016 odf_find_col_style (state
, &sheet
->cols
.default_style
, TRUE
);
2018 last_ci
= sheet_col_get (sheet
, 0);
2019 odf_find_col_style (state
, last_ci
, TRUE
);
2021 for (i
= 1; i
< max_cols
; i
++) {
2022 ColRowInfo
const *this_ci
= sheet_col_get (sheet
, i
);
2023 if (!colrow_equal (last_ci
, this_ci
))
2024 odf_find_col_style (state
, (last_ci
= this_ci
), TRUE
);
2032 odf_write_row_styles (GnmOOExport
*state
)
2034 /* We have to figure out which automatic styles we need */
2035 /* This is really annoying since we have to scan through */
2036 /* all rows. If we could store these styless in styles.xml */
2037 /* we could create them as we need them, but these styles */
2038 /* have to go into the beginning of content.xml. */
2041 for (j
= 0; j
< workbook_sheet_count (state
->wb
); j
++) {
2042 Sheet
const *sheet
= workbook_sheet_by_index (state
->wb
, j
);
2043 int max_rows
= gnm_sheet_get_max_rows (sheet
);
2045 ColRowInfo
const *last_ci
;
2047 odf_find_row_style (state
, &sheet
->rows
.default_style
, TRUE
);
2049 last_ci
= sheet_row_get (sheet
, 0);
2050 odf_find_row_style (state
, last_ci
, TRUE
);
2052 for (i
= 1; i
< max_rows
; i
++) {
2053 ColRowInfo
const *this_ci
= sheet_row_get (sheet
, i
);
2054 if (!colrow_equal (last_ci
, this_ci
))
2055 odf_find_row_style (state
, (last_ci
= this_ci
), TRUE
);
2063 odf_print_string (GnmConventionsOut
*out
, char const *str
, char quote
)
2065 GString
*target
= out
->accum
;
2067 /* Strings are surrounded by quote characters; a literal quote character '"'*/
2068 /* as string content is escaped by duplicating it. */
2070 g_string_append_c (target
, quote
);
2071 /* This loop should be UTF-8 safe. */
2072 for (; *str
; str
++) {
2073 g_string_append_c (target
, *str
);
2075 g_string_append_c (target
, quote
);
2077 g_string_append_c (target
, quote
);
2082 odf_cellref_as_string_base (GnmConventionsOut
*out
,
2083 GnmCellRef
const *cell_ref
,
2084 gboolean no_sheetname
)
2086 GString
*target
= out
->accum
;
2088 Sheet
const *sheet
= cell_ref
->sheet
;
2089 Sheet
const *size_sheet
= eval_sheet (sheet
, out
->pp
->sheet
);
2090 GnmSheetSize
const *ss
=
2091 gnm_sheet_get_size2 (size_sheet
, out
->pp
->wb
);
2093 if (sheet
!= NULL
&& !no_sheetname
) {
2094 if (NULL
!= out
->pp
->wb
&& sheet
->workbook
!= out
->pp
->wb
) {
2095 char const *ext_ref
;
2096 ext_ref
= go_doc_get_uri ((GODoc
*)(sheet
->workbook
));
2097 odf_print_string (out
, ext_ref
, '\'');
2098 g_string_append_c (target
, '#');
2100 g_string_append_c (target
, '$');
2101 odf_print_string (out
, sheet
->name_unquoted
, '\'');
2103 g_string_append_c (target
, '.');
2105 gnm_cellpos_init_cellref_ss (&pos
, cell_ref
, &out
->pp
->eval
, ss
);
2107 if (!cell_ref
->col_relative
)
2108 g_string_append_c (target
, '$');
2109 g_string_append (target
, col_name (pos
.col
));
2111 if (!cell_ref
->row_relative
)
2112 g_string_append_c (target
, '$');
2113 g_string_append (target
, row_name (pos
.row
));
2118 odf_cellref_as_string (GnmConventionsOut
*out
,
2119 GnmCellRef
const *cell_ref
,
2120 gboolean no_sheetname
)
2122 g_string_append (out
->accum
, "[");
2123 odf_cellref_as_string_base (out
, cell_ref
, no_sheetname
);
2124 g_string_append (out
->accum
, "]");
2128 odf_rangeref_as_string (GnmConventionsOut
*out
, GnmRangeRef
const *ref
)
2130 g_string_append (out
->accum
, "[");
2131 odf_cellref_as_string_base (out
, &(ref
->a
), FALSE
);
2132 g_string_append_c (out
->accum
, ':');
2133 odf_cellref_as_string_base (out
, &(ref
->b
), ref
->b
.sheet
== ref
->a
.sheet
);
2134 g_string_append (out
->accum
, "]");
2138 odf_func_r_dchisq_handler (GnmConventionsOut
*out
, GnmExprFunction
const *func
)
2140 if (func
->argc
== 2) {
2141 GString
*target
= out
->accum
;
2142 GnmExprConstPtr
const *ptr
= func
->argv
;
2143 g_string_append (target
, "CHISQDIST(");
2144 gnm_expr_as_gstring (ptr
[0], out
);
2145 g_string_append_c (out
->accum
, ';');
2146 gnm_expr_as_gstring (ptr
[1], out
);
2147 g_string_append (out
->accum
, ";FALSE())");
2154 odf_func_r_pchisq_handler (GnmConventionsOut
*out
, GnmExprFunction
const *func
)
2156 if (func
->argc
== 2) {
2157 GString
*target
= out
->accum
;
2158 g_string_append (target
, "CHISQDIST");
2159 gnm_expr_list_as_string (func
->argc
, func
->argv
, out
);
2166 odf_func_r_qchisq_handler (GnmConventionsOut
*out
, GnmExprFunction
const *func
)
2168 if (func
->argc
== 2) {
2169 GString
*target
= out
->accum
;
2170 g_string_append (target
, "CHISQINV");
2171 gnm_expr_list_as_string (func
->argc
, func
->argv
, out
);
2178 odf_func_floor_ceiling_handler (GnmConventionsOut
*out
, GnmExprFunction
const *func
)
2180 GString
*target
= out
->accum
;
2181 GnmExprConstPtr
const *ptr
= func
->argv
;
2182 g_string_append (target
, func
->func
->name
);
2183 g_string_append_c (target
, '(');
2184 if (func
->argc
> 0) {
2185 gnm_expr_as_gstring (ptr
[0], out
);
2186 g_string_append_c (target
, ';');
2188 gnm_expr_as_gstring (ptr
[1], out
);
2190 g_string_append (target
, "SIGN(");
2191 gnm_expr_as_gstring (ptr
[0], out
);
2192 g_string_append_c (target
, ')');
2194 g_string_append (target
, ";1)");
2196 g_string_append (target
, func
->func
->name
);
2197 g_string_append (target
, "()");
2203 odf_func_eastersunday_handler (GnmConventionsOut
*out
, GnmExprFunction
const *func
)
2205 if (func
->argc
== 1) {
2206 GString
*target
= out
->accum
;
2207 GnmExprConstPtr
const *ptr
= func
->argv
;
2208 /* OOo incorrectly stores this without an ORG.OPENOFFICE. prefix. */
2209 g_string_append (target
, "EASTERSUNDAY(");
2210 gnm_expr_as_gstring (ptr
[0], out
);
2211 g_string_append (out
->accum
, ")");
2218 odf_expr_func_handler (GnmConventionsOut
*out
, GnmExprFunction
const *func
)
2221 char const *gnm_name
;
2223 } const sc_func_handlers
[] = {
2224 {"CEILING", odf_func_floor_ceiling_handler
},
2225 {"FLOOR", odf_func_floor_ceiling_handler
},
2226 {"R.QCHISQ", odf_func_r_qchisq_handler
},
2227 {"R.DCHISQ", odf_func_r_dchisq_handler
},
2228 {"R.PCHISQ", odf_func_r_pchisq_handler
},
2229 {"EASTERSUNDAY", odf_func_eastersunday_handler
},
2234 char const *gnm_name
;
2235 char const *odf_name
;
2236 } const sc_func_renames
[] = {
2238 /* The default behaviour is to precede each function name with */
2239 /* ORG.GNUMERIC. So we need not list gnumeric unique names or those that */
2240 /* come from unknown plugins */
2242 /* The following are functions that exist in OpenFormula or with another */
2243 /* known prefix. This listing is */
2244 /* alphabetical by the second entry, the OpenFormula or foreign name (w/o prefix). */
2247 { "ACCRINT","ACCRINT" },
2248 { "ACCRINTM","ACCRINTM" },
2250 { "ACOSH","ACOSH" },
2252 { "ACOTH","ACOTH" },
2253 { "ADDRESS","ADDRESS" },
2254 { "AMORDEGRC","AMORDEGRC" },
2255 { "AMORLINC","AMORLINC" },
2257 { "ARABIC","ARABIC" },
2258 { "AREAS","AREAS" },
2261 { "ASINH","ASINH" },
2263 { "ATAN2","ATAN2" },
2264 { "ATANH","ATANH" },
2265 { "AVEDEV","AVEDEV" },
2266 { "AVERAGE","AVERAGE" },
2267 { "AVERAGEA","AVERAGEA" },
2268 { "AVERAGEIF","AVERAGEIF" },
2269 { "AVERAGEIFS","AVERAGEIFS" },
2270 { "BINOM.DIST.RANGE","B" },
2272 { "BESSELI","BESSELI" },
2273 { "BESSELJ","BESSELJ" },
2274 { "BESSELK","BESSELK" },
2275 { "BESSELY","BESSELY" },
2276 { "BETADIST","BETADIST" },
2277 { "BETAINV","BETAINV" },
2278 { "BIN2DEC","BIN2DEC" },
2279 { "BIN2HEX","BIN2HEX" },
2280 { "BIN2OCT","BIN2OCT" },
2281 { "BINOMDIST","BINOMDIST" },
2282 { "BITAND","BITAND" },
2283 { "BITLSHIFT","BITLSHIFT" },
2284 { "BITOR","BITOR" },
2285 { "BITRSHIFT","BITRSHIFT" },
2286 { "BITXOR","BITXOR" },
2287 { "CEIL", "CEILING" },
2288 /* { "ODF.CEILING","CEILING" }, see the handler code for CEILING*/
2291 /* { "ODF.CHISQDIST","CHISQDIST" }, we have related r.*chisq functions */
2292 /* { "ODF.CHISQINV","CHISQINV" }, we have related r.*chisq functions */
2293 { "CHOOSE","CHOOSE" },
2294 { "CLEAN","CLEAN" },
2296 { "COLUMN","COLUMN" },
2297 { "COLUMNS","COLUMNS" },
2298 { "CONFIDENCE.T","COM.MICROSOFT.CONFIDENCE.T" },
2299 { "COMBIN","COMBIN" },
2300 { "COMBINA","COMBINA" },
2301 { "COMPLEX","COMPLEX" },
2302 { "CONCAT","COM.MICROSOFT.CONCAT" },
2303 { "CONCATENATE","COM.MICROSOFT.CONCAT" },
2304 { "CONFIDENCE","CONFIDENCE" },
2305 { "CONVERT","CONVERT" },
2306 { "CORREL","CORREL" },
2311 { "COUNT","COUNT" },
2312 { "COUNTA","COUNTA" },
2313 { "COUNTBLANK","COUNTBLANK" },
2314 { "COUNTIF","COUNTIF" },
2315 { "COUNTIFS","COUNTIFS" },
2316 { "COUPDAYBS","COUPDAYBS" },
2317 { "COUPDAYS","COUPDAYS" },
2318 { "COUPDAYSNC","COUPDAYSNC" },
2319 { "COUPNCD","COUPNCD" },
2320 { "COUPNUM","COUPNUM" },
2321 { "COUPPCD","COUPPCD" },
2322 { "COVAR","COVAR" },
2323 { "CRITBINOM","CRITBINOM" },
2326 { "CUMIPMT","CUMIPMT" },
2327 { "CUMPRINC","CUMPRINC" },
2329 { "DATEDIF","DATEDIF" },
2330 { "DATEVALUE","DATEVALUE" },
2331 { "DAVERAGE","DAVERAGE" },
2334 { "DAYS360","DAYS360" },
2336 { "DCOUNT","DCOUNT" },
2337 { "DCOUNTA","DCOUNTA" },
2339 /* { "DDE","DDE" }, not implemented */
2340 { "DEC2BIN","DEC2BIN" },
2341 { "DEC2HEX","DEC2HEX" },
2342 { "DEC2OCT","DEC2OCT" },
2343 { "DECIMAL","DECIMAL" },
2344 { "DEGREES","DEGREES" },
2345 { "DELTA","DELTA" },
2346 { "DEVSQ","DEVSQ" },
2351 { "DOLLAR","DOLLAR" },
2352 { "DOLLARDE","DOLLARDE" },
2353 { "DOLLARFR","DOLLARFR" },
2354 { "DPRODUCT","DPRODUCT" },
2355 { "DSTDEV","DSTDEV" },
2356 { "DSTDEVP","DSTDEVP" },
2358 { "DURATION","DURATION" },
2360 { "DVARP","DVARP" },
2361 { "EDATE","EDATE" },
2362 { "EFFECT","EFFECT" },
2363 { "EOMONTH","EOMONTH" },
2366 { "ERROR.TYPE","ERROR.TYPE" },
2367 { "EUROCONVERT","EUROCONVERT" },
2369 { "EXACT","EXACT" },
2371 { "EXPONDIST","EXPONDIST" },
2373 { "FACTDOUBLE","FACTDOUBLE" },
2374 { "FALSE","FALSE" },
2376 { "FINDB","FINDB" },
2377 { "FISHER","FISHER" },
2378 { "FISHERINV","FISHERINV" },
2379 { "FIXED","FIXED" },
2380 { "FLOOR","FLOOR" },
2381 { "FORECAST","FORECAST" },
2382 { "GET.FORMULA","FORMULA" },
2383 { "FREQUENCY","FREQUENCY" },
2384 { "FTEST","FTEST" },
2386 { "FVSCHEDULE","FVSCHEDULE" },
2387 { "GAMMA","GAMMA" },
2388 { "GAMMADIST","GAMMADIST" },
2389 { "GAMMAINV","GAMMAINV" },
2390 { "GAMMALN","GAMMALN" },
2391 /* { "GAUSS","GAUSS" }, converted to ERF on import */
2393 { "GEOMEAN","GEOMEAN" },
2394 { "GESTEP","GESTEP" },
2395 { "GETPIVOTDATA","GETPIVOTDATA" },
2396 { "GROWTH","GROWTH" },
2397 { "HARMEAN","HARMEAN" },
2398 { "HEX2BIN","HEX2BIN" },
2399 { "HEX2DEC","HEX2DEC" },
2400 { "HEX2OCT","HEX2OCT" },
2401 { "HLOOKUP","HLOOKUP" },
2403 { "HYPERLINK","HYPERLINK" },
2404 { "HYPGEOMDIST","HYPGEOMDIST" },
2406 { "IFERROR","IFERROR" },
2408 { "IFS","COM.MICROSOFT.IFS" },
2409 { "IMABS","IMABS" },
2410 { "IMAGINARY","IMAGINARY" },
2411 { "IMARGUMENT","IMARGUMENT" },
2412 { "IMCONJUGATE","IMCONJUGATE" },
2413 { "IMCOS","IMCOS" },
2414 { "IMCOT","IMCOT" },
2415 { "IMCSC","IMCSC" },
2416 { "IMCSCH","IMCSCH" },
2417 { "IMDIV","IMDIV" },
2418 { "IMEXP","IMEXP" },
2420 { "IMLOG10","IMLOG10" },
2421 { "IMLOG2","IMLOG2" },
2422 { "IMPOWER","IMPOWER" },
2423 { "IMPRODUCT","IMPRODUCT" },
2424 { "IMREAL","IMREAL" },
2425 { "IMSEC","IMSEC" },
2426 { "IMSECH","IMSECH" },
2427 { "IMSIN","IMSIN" },
2428 { "IMSQRT","IMSQRT" },
2429 { "IMSUB","IMSUB" },
2430 { "IMSUM","IMSUM" },
2431 { "IMTAN","IMTAN" },
2432 { "INDEX","INDEX" },
2433 { "INDIRECT","INDIRECT" },
2436 { "INTERCEPT","INTERCEPT" },
2437 { "INTRATE","INTRATE" },
2440 { "ISBLANK","ISBLANK" },
2441 { "ISERR","ISERR" },
2442 { "ISERROR","ISERROR" },
2443 { "ISEVEN","ISEVEN" },
2444 { "ISFORMULA","ISFORMULA" },
2445 { "ISLOGICAL","ISLOGICAL" },
2447 { "ISNONTEXT","ISNONTEXT" },
2448 { "ISNUMBER","ISNUMBER" },
2449 { "ISODD","ISODD" },
2450 { "ISOWEEKNUM","ISOWEEKNUM" },
2451 { "ISPMT","ISPMT" },
2452 { "ISREF","ISREF" },
2453 { "ISTEXT","ISTEXT" },
2456 { "LARGE","LARGE" },
2459 { "LEFTB","LEFTB" },
2460 { "CHIDIST","LEGACY.CHIDIST" },
2461 { "CHIINV","LEGACY.CHIINV" },
2462 { "CHITEST","LEGACY.CHITEST" },
2463 { "FDIST","LEGACY.FDIST" },
2464 { "FINV","LEGACY.FINV" },
2465 { "NORMSDIST","LEGACY.NORMSDIST" },
2466 { "NORMSINV","LEGACY.NORMSINV" },
2467 { "TDIST","LEGACY.TDIST" },
2470 { "LINEST","LINEST" },
2473 { "LOG10","LOG10" },
2474 { "LOGEST","LOGEST" },
2475 { "LOGINV","LOGINV" },
2476 { "LOGNORMDIST","LOGNORMDIST" },
2477 { "LOOKUP","LOOKUP" },
2478 { "LOWER","LOWER" },
2479 { "MATCH","MATCH" },
2482 { "MAXIFS","COM.MICROSOFT.MAXIFS" },
2483 { "MDETERM","MDETERM" },
2484 { "MDURATION","MDURATION" },
2485 { "MEDIAN","MEDIAN" },
2490 { "MINIFS","COM.MICROSOFT.MINIFS" },
2491 { "MINUTE","MINUTE" },
2492 { "MINVERSE","MINVERSE" },
2494 { "MMULT","MMULT" },
2497 { "MODE.MULT","COM.MICROSOFT.MODE.MULT" },
2498 { "MONTH","MONTH" },
2499 { "MROUND","MROUND" },
2500 { "MULTINOMIAL","MULTINOMIAL" },
2501 /* { "MULTIPLE.OPERATIONS","MULTIPLE.OPERATIONS" }, not implemented */
2502 { "MUNIT","MUNIT" },
2505 { "NEGBINOMDIST","NEGBINOMDIST" },
2506 { "NETWORKDAYS","NETWORKDAYS" },
2507 { "NOMINAL","NOMINAL" },
2508 { "NORMDIST","NORMDIST" },
2509 { "NORMINV","NORMINV" },
2514 { "NUMBERVALUE","NUMBERVALUE" },
2515 { "OCT2BIN","OCT2BIN" },
2516 { "OCT2DEC","OCT2DEC" },
2517 { "OCT2HEX","OCT2HEX" },
2519 { "ODDFPRICE","ODDFPRICE" },
2520 { "ODDFYIELD","ODDFYIELD" },
2521 { "ODDLPRICE","ODDLPRICE" },
2522 { "ODDLYIELD","ODDLYIELD" },
2523 { "OFFSET","OFFSET" },
2525 { "G_DURATION","PDURATION" },
2526 { "PEARSON","PEARSON" },
2527 { "PERCENTILE","PERCENTILE" },
2528 { "PERCENTILE.EXC","COM.MICROSOFT.PERCENTILE.EXC" },
2529 { "PERCENTRANK","PERCENTRANK" },
2530 { "PERCENTRANK.EXC","COM.MICROSOFT.PERCENTRANK.EXC" },
2531 { "PERMUT","PERMUT" },
2532 { "PERMUTATIONA","PERMUTATIONA" },
2533 /* { "PHI","PHI" }, converted to NORMDIST on import */
2536 { "POISSON","POISSON" },
2537 { "POWER","POWER" },
2539 { "PRICE","PRICE" },
2540 { "PRICEDISC","PRICEDISC" },
2541 { "PRICEMAT","PRICEMAT" },
2543 { "PRODUCT","PRODUCT" },
2544 { "PROPER","PROPER" },
2546 { "QUARTILE","QUARTILE" },
2547 { "QUARTILE.EXC","COM.MICROSOFT.QUARTILE.EXC" },
2548 { "QUOTIENT","QUOTIENT" },
2549 { "RADIANS","RADIANS" },
2551 { "RANDBETWEEN","RANDBETWEEN" },
2553 { "RANK.AVG","COM.MICROSOFT.RANK.AVG" },
2555 { "RECEIVED","RECEIVED" },
2556 { "REPLACE","REPLACE" },
2557 { "REPLACEB","REPLACEB" },
2559 { "RIGHT","RIGHT" },
2560 { "RIGHTB","RIGHTB" },
2561 { "ROMAN","ROMAN" },
2562 { "ROUND","ROUND" },
2563 { "ROUNDDOWN","ROUNDDOWN" },
2564 { "ROUNDUP","ROUNDUP" },
2569 { "SEARCH","SEARCH" },
2570 { "SEARCHB","SEARCHB" },
2573 { "SECOND","SECOND" },
2574 { "SERIESSUM","SERIESSUM" },
2575 { "SHEET","SHEET" },
2576 { "SHEETS","SHEETS" },
2581 { "SKEWP","SKEWP" },
2583 { "SLOPE","SLOPE" },
2584 { "SMALL","SMALL" },
2586 { "SQRTPI","SQRTPI" },
2587 { "STANDARDIZE","STANDARDIZE" },
2588 { "STDEV","STDEV" },
2589 { "STDEVA","STDEVA" },
2590 { "STDEVP","STDEVP" },
2591 { "STDEVPA","STDEVPA" },
2592 { "STEYX","STEYX" },
2593 { "SUBSTITUTE","SUBSTITUTE" },
2594 { "SUBTOTAL","SUBTOTAL" },
2596 { "SUMIF","SUMIF" },
2597 { "SUMIFS","SUMIFS" },
2598 { "ODF.SUMPRODUCT","SUMPRODUCT" },
2599 { "SUMSQ","SUMSQ" },
2600 { "SUMX2MY2","SUMX2MY2" },
2601 { "SUMX2PY2","SUMX2PY2" },
2602 { "SUMXMY2","SUMXMY2" },
2603 { "SWITCH", "COM.MICROSOFT.SWITCH" },
2608 { "TBILLEQ","TBILLEQ" },
2609 { "TBILLPRICE","TBILLPRICE" },
2610 { "TBILLYIELD","TBILLYIELD" },
2612 { "TEXTJOIN","COM.MICROSOFT.TEXTJOIN" },
2613 { "ODF.TIME","TIME" },
2614 { "TIMEVALUE","TIMEVALUE" },
2616 { "TODAY","TODAY" },
2617 { "TRANSPOSE","TRANSPOSE" },
2618 { "TREND","TREND" },
2620 { "TRIMMEAN","TRIMMEAN" },
2622 { "TRUNC","TRUNC" },
2623 { "TTEST","TTEST" },
2625 { "UNICHAR","UNICHAR" },
2626 { "UNICODE","UNICODE" },
2627 /* { "USDOLLAR","USDOLLAR" }, this is a synonym to DOLLAR */
2628 { "UPPER","UPPER" },
2629 { "VALUE","VALUE" },
2633 { "VARPA","VARPA" },
2635 { "VLOOKUP","VLOOKUP" },
2636 { "WEEKDAY","WEEKDAY" },
2637 { "WEEKNUM","WEEKNUM" },
2638 { "WEIBULL","WEIBULL" },
2639 { "WORKDAY","WORKDAY" },
2644 { "YEARFRAC","YEARFRAC" },
2645 { "YIELD","YIELD" },
2646 { "YIELDDISC","YIELDDISC" },
2647 { "YIELDMAT","YIELDMAT" },
2648 { "ZTEST","ZTEST" },
2651 ODFConventions
*oconv
= (ODFConventions
*)(out
->convs
);
2652 GHashTable
*namemap
;
2653 GHashTable
*handlermap
;
2655 char const *name
= gnm_func_get_name (func
->func
, FALSE
);
2656 gboolean (*handler
) (GnmConventionsOut
*out
, GnmExprFunction
const *func
);
2658 if (NULL
== oconv
->state
->openformula_namemap
) {
2660 namemap
= g_hash_table_new (go_ascii_strcase_hash
,
2661 go_ascii_strcase_equal
);
2662 for (i
= 0; sc_func_renames
[i
].gnm_name
; i
++)
2663 g_hash_table_insert (namemap
,
2664 (gchar
*) sc_func_renames
[i
].gnm_name
,
2665 (gchar
*) sc_func_renames
[i
].odf_name
);
2666 oconv
->state
->openformula_namemap
= namemap
;
2668 namemap
= oconv
->state
->openformula_namemap
;
2670 if (NULL
== oconv
->state
->openformula_handlermap
) {
2672 handlermap
= g_hash_table_new (go_ascii_strcase_hash
,
2673 go_ascii_strcase_equal
);
2674 for (i
= 0; sc_func_handlers
[i
].gnm_name
; i
++)
2675 g_hash_table_insert (handlermap
,
2676 (gchar
*) sc_func_handlers
[i
].gnm_name
,
2677 sc_func_handlers
[i
].handler
);
2678 oconv
->state
->openformula_handlermap
= handlermap
;
2680 handlermap
= oconv
->state
->openformula_handlermap
;
2682 handler
= g_hash_table_lookup (handlermap
, name
);
2684 if (handler
== NULL
|| !handler (out
, func
)) {
2685 char const *new_name
= g_hash_table_lookup (namemap
, name
);
2686 GString
*target
= out
->accum
;
2688 if (new_name
== NULL
) {
2689 if (0 == g_ascii_strncasecmp (name
, "ODF.", 4)) {
2691 new_u_name
= g_ascii_strup (name
+ 4, -1);
2692 g_string_append (target
, new_u_name
);
2693 g_free (new_u_name
);
2696 g_string_append (target
, "ORG.GNUMERIC.");
2697 new_u_name
= g_ascii_strup (name
, -1);
2698 g_string_append (target
, new_u_name
);
2699 g_free (new_u_name
);
2703 g_string_append (target
, new_name
);
2705 gnm_expr_list_as_string (func
->argc
, func
->argv
, out
);
2711 odf_string_handler (GnmConventionsOut
*out
, GOString
const *str
)
2713 /* Constant strings are surrounded by double-quote characters */
2714 /* (QUOTATION MARK, U+0022); a literal double-quote character '"'*/
2715 /* (QUOTATION MARK, U+0022) as */
2716 /* string content is escaped by duplicating it. */
2718 odf_print_string (out
, str
->str
, '"');
2722 odf_boolean_handler (GnmConventionsOut
*out
, gboolean val
)
2724 g_string_append (out
->accum
, val
? "TRUE()" : "FALSE()");
2728 static GnmConventions
*
2729 odf_expr_conventions_new (GnmOOExport
*state
)
2731 GnmConventions
*conv
= gnm_conventions_new_full
2732 (sizeof (ODFConventions
));
2733 ODFConventions
*oconv
= (ODFConventions
*)conv
;
2736 conv
->sheet_name_sep
= '.';
2737 conv
->arg_sep
= ';';
2738 conv
->array_col_sep
= ';';
2739 conv
->array_row_sep
= '|';
2740 conv
->intersection_char
= '!';
2741 conv
->decimal_sep_dot
= TRUE
;
2742 conv
->output
.string
= odf_string_handler
;
2743 conv
->output
.cell_ref
= odf_cellref_as_string
;
2744 conv
->output
.range_ref
= odf_rangeref_as_string
;
2745 conv
->output
.func
= odf_expr_func_handler
;
2746 conv
->output
.boolean
= odf_boolean_handler
;
2748 l10
= gnm_log10 (FLT_RADIX
);
2749 conv
->output
.decimal_digits
= (int)gnm_ceil (GNM_MANT_DIG
* l10
) +
2750 (l10
== (int)l10
? 0 : 1);
2752 oconv
->state
= state
;
2758 odf_cell_is_covered (G_GNUC_UNUSED Sheet
const *sheet
,
2759 G_GNUC_UNUSED GnmCell
*current_cell
,
2760 int col
, int row
, GnmRange
const *merge_range
,
2761 GSList
**merge_ranges
)
2765 if (merge_range
!= NULL
) {
2766 GnmRange
*new_range
= g_new(GnmRange
, 1);
2767 *new_range
= *merge_range
;
2768 (*merge_ranges
) = g_slist_prepend (*merge_ranges
, new_range
);
2772 if ((*merge_ranges
) == NULL
)
2775 *merge_ranges
= g_slist_remove_all (*merge_ranges
, NULL
);
2777 for (l
= *merge_ranges
; l
!= NULL
; l
= g_slist_next(l
)) {
2778 GnmRange
*r
= l
->data
;
2779 if (r
->end
.row
< row
) {
2780 /* We do not need this range anymore */
2785 /* no need to check for beginning rows */
2786 /* we have to check for column range */
2787 if ((r
->start
.col
<= col
) && (col
<= r
->end
.col
))
2794 odf_write_comment (GnmOOExport
*state
, GnmComment
const *cc
)
2796 char *author
= NULL
;
2798 PangoAttrList
* markup
= NULL
;
2801 g_object_get (G_OBJECT (state
->xml
), "pretty-print", &pp
, NULL
);
2803 g_object_get (G_OBJECT (cc
), "text", &text
,
2804 "markup", &markup
, "author", &author
, NULL
);
2806 gsf_xml_out_start_element (state
->xml
, OFFICE
"annotation");
2807 if (author
!= NULL
) {
2808 gsf_xml_out_start_element (state
->xml
, DUBLINCORE
"creator");
2809 gsf_xml_out_add_cstr (state
->xml
, NULL
, author
);
2810 gsf_xml_out_end_element (state
->xml
); /* DUBLINCORE "creator" */;
2814 g_object_set (G_OBJECT (state
->xml
), "pretty-print", FALSE
, NULL
);
2815 gsf_xml_out_start_element (state
->xml
, TEXT
"p");
2816 odf_new_markup (state
, markup
, text
);
2817 gsf_xml_out_end_element (state
->xml
); /* p */
2820 pango_attr_list_unref (markup
);
2823 g_object_set (G_OBJECT (state
->xml
), "pretty-print", pp
, NULL
);
2824 gsf_xml_out_end_element (state
->xml
); /* OFFICE "annotation" */
2828 odf_graph_get_series (GnmOOExport
*state
, GogGraph
*sog
, GnmParsePos
*pp
)
2830 GSList
*list
= gog_graph_get_data (sog
);
2831 GString
*str
= g_string_new (NULL
);
2833 for (;list
!= NULL
; list
= list
->next
) {
2834 GOData
*dat
= list
->data
;
2835 GnmExprTop
const *texpr
= gnm_go_data_get_expr (dat
);
2836 if (texpr
!= NULL
&& gnm_expr_top_is_rangeref (texpr
)) {
2837 char *formula
= gnm_expr_top_as_string (texpr
, pp
, state
->conv
);
2838 g_string_append (str
, odf_strip_brackets (formula
));
2839 g_string_append_c (str
, ' ');
2844 return g_string_free (str
, FALSE
);
2848 odf_write_frame_size (GnmOOExport
*state
, SheetObject
*so
)
2850 SheetObjectAnchor
const *anchor
= sheet_object_get_anchor (so
);
2851 double res_pts
[4] = {0.,0.,0.,0.};
2852 GnmRange
const *r
= &anchor
->cell_bound
;
2854 GnmExprTop
const *texpr
;
2859 sheet_object_anchor_to_offset_pts (anchor
, state
->sheet
, res_pts
);
2861 switch (anchor
->mode
) {
2862 case GNM_SO_ANCHOR_TWO_CELLS
:
2863 odf_add_pt (state
->xml
, SVG
"x", res_pts
[0]);
2864 odf_add_pt (state
->xml
, SVG
"y", res_pts
[1]);
2865 odf_add_pt (state
->xml
, TABLE
"end-x", res_pts
[2]);
2866 odf_add_pt (state
->xml
, TABLE
"end-y", res_pts
[3]);
2867 /* The next 3 lines should not be needed, but older versions of Gnumeric used the */
2868 /* width and height. */
2869 sheet_object_anchor_to_pts (anchor
, state
->sheet
, res_pts
);
2870 odf_add_pt (state
->xml
, SVG
"width", res_pts
[2] - res_pts
[0]);
2871 odf_add_pt (state
->xml
, SVG
"height", res_pts
[3] - res_pts
[1]);
2873 gnm_cellref_init (&ref
, (Sheet
*) state
->sheet
, r
->end
.col
, r
->end
.row
, TRUE
);
2874 texpr
= gnm_expr_top_new (gnm_expr_new_cellref (&ref
));
2875 parse_pos_init_sheet (&pp
, state
->sheet
);
2876 formula
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
2877 gnm_expr_top_unref (texpr
);
2878 gsf_xml_out_add_cstr (state
->xml
, TABLE
"end-cell-address",
2879 odf_strip_brackets (formula
));
2882 case GNM_SO_ANCHOR_ONE_CELL
:
2883 odf_add_pt (state
->xml
, SVG
"x", res_pts
[0]);
2884 odf_add_pt (state
->xml
, SVG
"y", res_pts
[1]);
2885 odf_add_pt (state
->xml
, SVG
"width", anchor
->offset
[2]);
2886 odf_add_pt (state
->xml
, SVG
"height", anchor
->offset
[3]);
2888 case GNM_SO_ANCHOR_ABSOLUTE
:
2889 odf_add_pt (state
->xml
, SVG
"x", anchor
->offset
[0]);
2890 odf_add_pt (state
->xml
, SVG
"y", anchor
->offset
[1]);
2891 odf_add_pt (state
->xml
, SVG
"width", anchor
->offset
[2]);
2892 odf_add_pt (state
->xml
, SVG
"height", anchor
->offset
[3]);
2896 sheet
= sheet_object_get_sheet (so
);
2899 z
= g_slist_length (sheet
->sheet_objects
)
2900 - sheet_object_get_stacking (so
);
2901 gsf_xml_out_add_int (state
->xml
, DRAW
"z-index", z
);
2906 odf_write_multi_chart_frame_size (GnmOOExport
*state
, SheetObject
*so
, GogObject
*obj
, guint tr
, guint tc
)
2908 SheetObjectAnchor
const *anchor
= sheet_object_get_anchor (so
);
2909 double abs_pts
[4] = {0.,0.,0.,0.};
2910 double off_pts
[4] = {0.,0.,0.,0.};
2911 double res_pts
[4] = {0.,0.,0.,0.};
2912 GnmRange
const *r
= &anchor
->cell_bound
;
2914 GnmExprTop
const *texpr
;
2917 Sheet
const *sheet
= state
->sheet
;
2918 unsigned int xpos
= 0, ypos
= 0, columns
= 1, rows
= 1;
2919 double height
, width
;
2921 if (!gog_chart_get_position (GOG_CHART (obj
),
2922 &xpos
, &ypos
, &columns
, &rows
)) {
2923 odf_write_frame_size (state
, so
);
2927 sheet_object_anchor_to_pts (anchor
, sheet
, abs_pts
);
2928 sheet_object_anchor_to_offset_pts (anchor
, sheet
, off_pts
);
2930 res_pts
[0] = off_pts
[0] + ((tc
== 0) ? 0 : (xpos
* (abs_pts
[2]-abs_pts
[0])/tc
));
2931 res_pts
[1] = off_pts
[1] + ((tr
== 0) ? 0 : (ypos
* (abs_pts
[3]-abs_pts
[1])/tr
));
2932 res_pts
[2] = off_pts
[0] + ((tc
== 0) ? (abs_pts
[2]-abs_pts
[0]) :
2933 ((xpos
+ columns
) * (abs_pts
[2]-abs_pts
[0])/tc
));
2934 res_pts
[3] = off_pts
[1] + ((tr
== 0) ? (abs_pts
[3]-abs_pts
[1]) :
2935 ((ypos
+ rows
) * (abs_pts
[3]-abs_pts
[1])/tr
));
2936 width
= res_pts
[2] - res_pts
[0];
2937 height
= res_pts
[3] - res_pts
[1];
2939 res_pts
[2] -= sheet_col_get_distance_pts (sheet
, r
->start
.col
,
2941 res_pts
[3] -= sheet_row_get_distance_pts (sheet
, r
->start
.row
,
2944 odf_add_pt (state
->xml
, SVG
"x", res_pts
[0]);
2945 odf_add_pt (state
->xml
, SVG
"y", res_pts
[1]);
2946 odf_add_pt (state
->xml
, TABLE
"end-x", res_pts
[2]);
2947 odf_add_pt (state
->xml
, TABLE
"end-y", res_pts
[3]);
2949 odf_add_pt (state
->xml
, SVG
"width", width
);
2950 odf_add_pt (state
->xml
, SVG
"height", height
);
2953 gnm_cellref_init (&ref
, (Sheet
*) sheet
, r
->end
.col
, r
->end
.row
, TRUE
);
2954 texpr
= gnm_expr_top_new (gnm_expr_new_cellref (&ref
));
2955 parse_pos_init_sheet (&pp
, state
->sheet
);
2956 formula
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
2957 gnm_expr_top_unref (texpr
);
2958 gsf_xml_out_add_cstr (state
->xml
, TABLE
"end-cell-address",
2959 odf_strip_brackets (formula
));
2964 z
= g_slist_length (sheet
->sheet_objects
)
2965 - sheet_object_get_stacking (so
);
2966 gsf_xml_out_add_int (state
->xml
, DRAW
"z-index", z
);
2971 odf_n_charts (GnmOOExport
*state
, SheetObject
*so
)
2973 GogGraph
const *graph
= sheet_object_graph_get_gog (so
);
2974 GogObjectRole
const *role
= gog_object_find_role_by_name (GOG_OBJECT (graph
), "Chart");
2975 GSList
*list
= gog_object_get_children (GOG_OBJECT (graph
), role
);
2976 guint n
= g_slist_length (list
);
2977 g_slist_free (list
);
2982 odf_write_graph (GnmOOExport
*state
, SheetObject
*so
, char const *name
)
2985 parse_pos_init_sheet (&pp
, state
->sheet
);
2988 GogGraph
*graph
= sheet_object_graph_get_gog (so
);
2989 GogObjectRole
const *role
= gog_object_find_role_by_name (GOG_OBJECT (graph
), "Chart");
2990 GSList
*list
= gog_object_get_children (GOG_OBJECT (graph
), role
);
2993 gboolean multichart
= (NULL
!= list
->next
);
2994 char *series_name
= odf_graph_get_series (state
, graph
, &pp
);
2995 guint i
= 0, total_rows
, total_columns
;
2998 total_columns
= gog_graph_num_cols (graph
);
2999 total_rows
= gog_graph_num_rows (graph
);
3003 char *full_name
= g_strdup_printf ("%s-%i/", name
, i
);
3004 gsf_xml_out_start_element (state
->xml
, DRAW
"frame");
3006 odf_write_multi_chart_frame_size (state
, so
, GOG_OBJECT (l
->data
),
3007 total_rows
, total_columns
);
3009 odf_write_frame_size (state
, so
);
3010 gsf_xml_out_start_element (state
->xml
, DRAW
"object");
3011 gsf_xml_out_add_cstr (state
->xml
, XLINK
"href", full_name
);
3013 gsf_xml_out_add_cstr (state
->xml
, XLINK
"type", "simple");
3014 gsf_xml_out_add_cstr (state
->xml
, XLINK
"show", "embed");
3015 gsf_xml_out_add_cstr (state
->xml
, XLINK
"actuate", "onLoad");
3016 gsf_xml_out_add_cstr (state
->xml
, DRAW
"notify-on-update-of-ranges",
3018 gsf_xml_out_end_element (state
->xml
); /* DRAW "object" */
3019 full_name
= g_strdup_printf ("Pictures/%s-%i", name
, i
);
3020 gsf_xml_out_start_element (state
->xml
, DRAW
"image");
3021 gsf_xml_out_add_cstr (state
->xml
, XLINK
"href", full_name
);
3023 gsf_xml_out_add_cstr (state
->xml
, XLINK
"type", "simple");
3024 gsf_xml_out_add_cstr (state
->xml
, XLINK
"show", "embed");
3025 gsf_xml_out_add_cstr (state
->xml
, XLINK
"actuate", "onLoad");
3026 gsf_xml_out_end_element (state
->xml
); /* DRAW "image" */
3027 full_name
= g_strdup_printf ("Pictures/%s-%i.png", name
,i
);
3028 gsf_xml_out_start_element (state
->xml
, DRAW
"image");
3029 gsf_xml_out_add_cstr (state
->xml
, XLINK
"href", full_name
);
3031 gsf_xml_out_add_cstr (state
->xml
, XLINK
"type", "simple");
3032 gsf_xml_out_add_cstr (state
->xml
, XLINK
"show", "embed");
3033 gsf_xml_out_add_cstr (state
->xml
, XLINK
"actuate", "onLoad");
3034 gsf_xml_out_end_element (state
->xml
); /* DRAW "image" */
3035 gsf_xml_out_end_element (state
->xml
); /* DRAW "frame" */
3039 g_free (series_name
);
3040 g_slist_free (list
);
3043 g_warning ("Graph is missing from hash.");
3047 odf_write_image (GnmOOExport
*state
, SheetObject
*so
, char const *name
)
3052 GOImage
*image
= NULL
;
3054 g_object_get (G_OBJECT (so
),
3055 "image-type", &image_type
,
3060 /* Write attribute for surrounding draw:frame */
3061 const char *image_name
= go_image_get_name (image
);
3063 gsf_xml_out_add_cstr (state
->xml
, DRAW
"name", image_name
);
3064 g_object_unref (image
);
3067 fullname
= g_strdup_printf ("Pictures/%s.%s", name
, image_type
);
3069 gsf_xml_out_start_element (state
->xml
, DRAW
"image");
3070 gsf_xml_out_add_cstr (state
->xml
, XLINK
"href", fullname
);
3071 gsf_xml_out_add_cstr (state
->xml
, XLINK
"type", "simple");
3072 gsf_xml_out_add_cstr (state
->xml
, XLINK
"show", "embed");
3073 gsf_xml_out_add_cstr (state
->xml
, XLINK
"actuate", "onLoad");
3074 gsf_xml_out_end_element (state
->xml
); /* DRAW "image" */
3077 g_free (image_type
);
3079 g_warning ("Image is missing from hash.");
3083 odf_write_frame (GnmOOExport
*state
, SheetObject
*so
)
3085 if (GNM_IS_SO_GRAPH (so
))
3086 odf_write_graph (state
, so
, g_hash_table_lookup (state
->graphs
, so
));
3087 else if (GNM_IS_SO_IMAGE (so
)) {
3088 gsf_xml_out_start_element (state
->xml
, DRAW
"frame");
3089 odf_write_frame_size (state
, so
);
3090 odf_write_image (state
, so
, g_hash_table_lookup (state
->images
, so
));
3091 gsf_xml_out_end_element (state
->xml
); /* DRAW "frame" */
3093 gsf_xml_out_start_element (state
->xml
, DRAW
"frame");
3094 odf_write_frame_size (state
, so
);
3095 gsf_xml_out_start_element (state
->xml
, DRAW
"text-box");
3096 gsf_xml_out_simple_element (state
->xml
, TEXT
"p",
3097 "Missing Framed Sheet Object");
3098 gsf_xml_out_end_element (state
->xml
); /* DRAW "text-box" */
3099 gsf_xml_out_end_element (state
->xml
); /* DRAW "frame" */
3104 custom_shape_path_collector (GOPath
*path
, GString
*gstr
)
3106 char *path_string
= NULL
;
3107 path_string
= go_path_to_svg (path
);
3108 g_string_append (gstr
, " N ");
3109 g_string_append (gstr
, path_string
);
3110 g_free (path_string
);
3114 odf_write_custom_shape (GnmOOExport
*state
, SheetObject
*so
)
3116 gchar
const *style_name
= g_hash_table_lookup (state
->so_styles
, so
);
3118 PangoAttrList
* markup
= NULL
;
3120 GOPath
*path
= NULL
;
3122 char *path_string
= NULL
;
3123 char *view_box
= NULL
;
3125 g_object_get (G_OBJECT (so
), "text", &text
, "markup", &markup
, "path", &path
,
3126 "paths", &paths
, "viewbox", &view_box
, NULL
);
3128 gsf_xml_out_start_element (state
->xml
, DRAW
"custom-shape");
3130 if (style_name
!= NULL
)
3131 gsf_xml_out_add_cstr (state
->xml
, DRAW
"style-name", style_name
);
3132 odf_write_frame_size (state
, so
);
3134 g_object_get (G_OBJECT (state
->xml
), "pretty-print", &pp
, NULL
);
3135 g_object_set (G_OBJECT (state
->xml
), "pretty-print", FALSE
, NULL
);
3136 gsf_xml_out_start_element (state
->xml
, TEXT
"p");
3137 odf_new_markup (state
, markup
, text
);
3138 gsf_xml_out_end_element (state
->xml
); /* p */
3139 g_object_set (G_OBJECT (state
->xml
), "pretty-print", pp
, NULL
);
3142 char *ps
= go_path_to_svg (path
);
3143 path_string
= g_strconcat (ps
, " N", NULL
);
3147 GString
*gstr
= g_string_new (path_string
);
3148 g_ptr_array_foreach (paths
, (GFunc
)custom_shape_path_collector
, gstr
);
3149 g_string_append (gstr
, " N");
3150 path_string
= g_string_free (gstr
, FALSE
);
3153 gsf_xml_out_start_element (state
->xml
, DRAW
"enhanced-geometry");
3154 gsf_xml_out_add_cstr (state
->xml
, SVG
"viewBox", view_box
);
3155 gsf_xml_out_add_cstr (state
->xml
, DRAW
"enhanced-path", path_string
);
3156 gsf_xml_out_end_element (state
->xml
); /* DRAW "enhanced-geometry" */
3158 gsf_xml_out_end_element (state
->xml
); /* DRAW "custom-shape" */
3161 g_free (path_string
);
3164 pango_attr_list_unref (markup
);
3166 g_ptr_array_unref (paths
);
3168 go_path_free (path
);
3173 odf_write_control (GnmOOExport
*state
, SheetObject
*so
, char const *id
)
3175 gsf_xml_out_start_element (state
->xml
, DRAW
"control");
3176 odf_write_frame_size (state
, so
);
3177 gsf_xml_out_add_cstr (state
->xml
, DRAW
"control", id
);
3178 gsf_xml_out_end_element (state
->xml
); /* DRAW "control" */
3182 odf_write_so_filled (GnmOOExport
*state
, SheetObject
*so
)
3184 char const *element
;
3185 gboolean is_oval
= FALSE
;
3187 PangoAttrList
* markup
= NULL
;
3188 gchar
const *style_name
= g_hash_table_lookup (state
->so_styles
, so
);
3191 g_object_get (G_OBJECT (so
), "is-oval", &is_oval
, "text", &text
, "markup", &markup
, NULL
);
3192 element
= is_oval
? DRAW
"ellipse" : DRAW
"rect";
3194 gsf_xml_out_start_element (state
->xml
, element
);
3195 if (style_name
!= NULL
)
3196 gsf_xml_out_add_cstr (state
->xml
, DRAW
"style-name", style_name
);
3197 odf_write_frame_size (state
, so
);
3199 g_object_get (G_OBJECT (state
->xml
), "pretty-print", &pp
, NULL
);
3200 g_object_set (G_OBJECT (state
->xml
), "pretty-print", FALSE
, NULL
);
3201 gsf_xml_out_start_element (state
->xml
, TEXT
"p");
3202 odf_new_markup (state
, markup
, text
);
3203 gsf_xml_out_end_element (state
->xml
); /* p */
3204 g_object_set (G_OBJECT (state
->xml
), "pretty-print", pp
, NULL
);
3208 pango_attr_list_unref (markup
);
3210 gsf_xml_out_end_element (state
->xml
); /* DRAW "rect" or "ellipse" */
3214 odf_write_line (GnmOOExport
*state
, SheetObject
*so
)
3216 SheetObjectAnchor
const *anchor
= sheet_object_get_anchor (so
);
3217 double res_pts
[4] = {0.,0.,0.,0.};
3218 GnmRange
const *r
= &anchor
->cell_bound
;
3220 GnmExprTop
const *texpr
;
3223 double x1
, y1
, x2
, y2
;
3224 gchar
const *style_name
= g_hash_table_lookup (state
->so_styles
, so
);
3227 gsf_xml_out_start_element (state
->xml
, DRAW
"line");
3228 if (style_name
!= NULL
)
3229 gsf_xml_out_add_cstr (state
->xml
, DRAW
"style-name", style_name
);
3230 z
= g_slist_length (state
->sheet
->sheet_objects
) -
3231 sheet_object_get_stacking (so
);
3232 gsf_xml_out_add_int (state
->xml
, DRAW
"z-index", z
);
3234 sheet_object_anchor_to_pts (anchor
, state
->sheet
, res_pts
);
3236 switch (anchor
->base
.direction
) {
3238 case GOD_ANCHOR_DIR_UNKNOWN
:
3239 case GOD_ANCHOR_DIR_UP_RIGHT
:
3245 case GOD_ANCHOR_DIR_DOWN_RIGHT
:
3251 case GOD_ANCHOR_DIR_UP_LEFT
:
3257 case GOD_ANCHOR_DIR_DOWN_LEFT
:
3265 odf_add_pt (state
->xml
, SVG
"x1", x1
);
3266 odf_add_pt (state
->xml
, SVG
"y1", y1
);
3267 odf_add_pt (state
->xml
, SVG
"x2", x2
);
3268 odf_add_pt (state
->xml
, SVG
"y2", y2
);
3270 if (anchor
->mode
== GNM_SO_ANCHOR_TWO_CELLS
) {
3271 sheet_object_anchor_to_offset_pts (anchor
, state
->sheet
, res_pts
);
3272 odf_add_pt (state
->xml
, TABLE
"end-x", res_pts
[2]);
3273 odf_add_pt (state
->xml
, TABLE
"end-y", res_pts
[3]);
3275 gnm_cellref_init (&ref
, (Sheet
*) state
->sheet
, r
->end
.col
, r
->end
.row
, TRUE
);
3276 texpr
= gnm_expr_top_new (gnm_expr_new_cellref (&ref
));
3277 parse_pos_init_sheet (&pp
, state
->sheet
);
3278 formula
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
3279 gnm_expr_top_unref (texpr
);
3280 gsf_xml_out_add_cstr (state
->xml
, TABLE
"end-cell-address",
3281 odf_strip_brackets (formula
));
3285 gsf_xml_out_end_element (state
->xml
); /* DRAW "line" */
3289 odf_write_objects (GnmOOExport
*state
, GSList
*objects
)
3293 for (l
= objects
; l
!= NULL
; l
= l
->next
) {
3294 SheetObject
*so
= l
->data
;
3295 char const *id
= g_hash_table_lookup (state
->controls
, so
);
3297 g_warning ("NULL sheet object encountered.");
3300 if (GNM_IS_FILTER_COMBO (so
) || GNM_IS_VALIDATION_COMBO(so
))
3303 odf_write_control (state
, so
, id
);
3304 else if (GNM_IS_CELL_COMMENT (so
))
3305 odf_write_comment (state
, GNM_CELL_COMMENT (so
));
3306 else if (GNM_IS_SO_FILLED (so
))
3307 odf_write_so_filled (state
, so
);
3308 else if (GNM_IS_SO_LINE (so
))
3309 odf_write_line (state
, so
);
3310 else if (GNM_IS_SO_PATH (so
))
3311 odf_write_custom_shape (state
, so
);
3313 odf_write_frame (state
, so
);
3319 odf_write_link_start (GnmOOExport
*state
, GnmHLink
*lnk
)
3321 GType
const t
= G_OBJECT_TYPE (lnk
);
3322 char *link_text
= NULL
;
3324 gsf_xml_out_start_element (state
->xml
, TEXT
"a");
3325 gsf_xml_out_add_cstr (state
->xml
, XLINK
"type", "simple");
3326 gsf_xml_out_add_cstr (state
->xml
, XLINK
"actuate", "onRequest");
3328 if (g_type_is_a (t
, gnm_hlink_url_get_type ())) {
3329 // This includes email
3330 link_text
= g_strdup (gnm_hlink_get_target (lnk
));
3331 } else if (g_type_is_a (t
, gnm_hlink_cur_wb_get_type ())) {
3332 GnmExprTop
const *texpr
= gnm_hlink_get_target_expr (lnk
);
3335 if (texpr
&& GNM_EXPR_GET_OPER (texpr
->expr
) == GNM_EXPR_OP_NAME
) {
3338 parse_pos_init_sheet (&pp
, gnm_hlink_get_sheet (lnk
));
3339 s
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
3340 link_text
= g_strconcat ("#", s
, NULL
);
3342 } else if (gnm_hlink_get_range_target (lnk
, &sr
)) {
3343 link_text
= g_strconcat
3345 sr
.sheet
->name_unquoted
, ".",
3346 range_as_string (&sr
.range
),
3350 g_warning ("Unexpected hyperlink type");
3353 gsf_xml_out_add_cstr (state
->xml
, XLINK
"href", link_text
? link_text
: "#");
3356 gsf_xml_out_add_cstr (state
->xml
, OFFICE
"title", gnm_hlink_get_tip (lnk
));
3360 odf_write_link_end (GnmOOExport
*state
, GnmHLink
*lnk
)
3362 gsf_xml_out_end_element (state
->xml
); /* a */
3367 odf_write_empty_cell (GnmOOExport
*state
, int num
, GnmStyle
const *style
, GSList
*objects
)
3370 gsf_xml_out_start_element (state
->xml
, TABLE
"table-cell");
3372 gsf_xml_out_add_int (state
->xml
,
3373 TABLE
"number-columns-repeated",
3375 if (style
!= NULL
) {
3376 char const * name
= odf_find_style (state
, style
);
3377 GnmValidation
const *val
= gnm_style_get_validation (style
);
3380 gsf_xml_out_add_cstr (state
->xml
,
3381 TABLE
"style-name", name
);
3383 char *vname
= oo_item_name (state
, OO_ITEM_VALIDATION
, val
);
3384 gsf_xml_out_add_cstr (state
->xml
,
3385 TABLE
"content-validation-name", vname
);
3387 } else if (NULL
!= (im
= gnm_style_get_input_msg (style
))) {
3388 char *vname
= oo_item_name (state
, OO_ITEM_INPUT_MSG
, im
);
3389 gsf_xml_out_add_cstr (state
->xml
,
3390 TABLE
"content-validation-name", vname
);
3395 odf_write_objects (state
, objects
);
3396 gsf_xml_out_end_element (state
->xml
); /* table-cell */
3401 odf_write_covered_cell (GnmOOExport
*state
, int *num
)
3404 gsf_xml_out_start_element (state
->xml
, TABLE
"covered-table-cell");
3406 gsf_xml_out_add_int (state
->xml
,
3407 TABLE
"number-columns-repeated",
3409 gsf_xml_out_end_element (state
->xml
); /* covered-table-cell */
3415 odf_cellspan_is_empty (int col
, GnmCell
const *ok_span_cell
)
3417 Sheet
*sheet
= ok_span_cell
->base
.sheet
;
3418 int row
= ok_span_cell
->pos
.row
;
3419 ColRowInfo
*ri
= sheet_row_get (sheet
, row
);
3420 CellSpanInfo
const *span
= row_span_get (ri
, col
);
3424 if (span
!= NULL
&& span
->cell
!= ok_span_cell
)
3429 if (gnm_sheet_merge_contains_pos (sheet
, &pos
) != NULL
)
3432 tmp
= sheet_cell_get (sheet
, col
, row
);
3434 return (tmp
== NULL
|| tmp
->value
== NULL
||
3435 (VALUE_IS_EMPTY (tmp
->value
) && !gnm_cell_has_expr(tmp
)));
3439 odf_write_cell (GnmOOExport
*state
, GnmCell
*cell
, GnmRange
const *merge_range
,
3440 GnmStyle
const *style
, GSList
*objects
)
3442 int rows_spanned
= 0, cols_spanned
= 0;
3443 GnmHLink
*lnk
= NULL
;
3444 gboolean col_spanned_fake
= FALSE
;
3446 if (merge_range
!= NULL
) {
3447 rows_spanned
= merge_range
->end
.row
- merge_range
->start
.row
+ 1;
3448 cols_spanned
= merge_range
->end
.col
- merge_range
->start
.col
+ 1;
3451 if (style
&& cell
&& cols_spanned
<= 1 && gnm_style_get_align_h (style
) == GNM_HALIGN_CENTER_ACROSS_SELECTION
) {
3452 /* We have to simulate GNM_HALIGN_CENTER_ACROSS_SELECTION by a merge */
3453 int cell_col
= cell
->pos
.col
;
3454 int cell_row
= cell
->pos
.row
;
3455 int max_col_spanned
= gnm_sheet_get_max_cols (state
->sheet
) - cell_col
;
3457 while (cols_spanned
< max_col_spanned
) {
3458 ColRowInfo
const *ci
;
3460 ci
= sheet_col_get_info (state
->sheet
, cell_col
);
3462 if (odf_cellspan_is_empty (cell_col
, cell
)) {
3463 GnmStyle
const * const cstyle
=
3464 sheet_style_get (state
->sheet
, cell_col
, cell_row
);
3465 if (gnm_style_get_align_h (cstyle
) != GNM_HALIGN_CENTER_ACROSS_SELECTION
)
3472 col_spanned_fake
= (cols_spanned
> 1);
3475 gsf_xml_out_start_element (state
->xml
, TABLE
"table-cell");
3477 if (cols_spanned
> 1) {
3478 gsf_xml_out_add_int (state
->xml
,
3479 TABLE
"number-columns-spanned", cols_spanned
);
3480 if (col_spanned_fake
&& state
->with_extension
)
3481 odf_add_bool (state
->xml
, GNMSTYLE
"columns-spanned-fake", TRUE
);
3483 if (rows_spanned
> 1)
3484 gsf_xml_out_add_int (state
->xml
,
3485 TABLE
"number-rows-spanned", rows_spanned
);
3487 char const * name
= odf_find_style (state
, style
);
3488 GnmValidation
const *val
= gnm_style_get_validation (style
);
3490 gsf_xml_out_add_cstr (state
->xml
,
3491 TABLE
"style-name", name
);
3493 char *vname
= oo_item_name (state
, OO_ITEM_VALIDATION
, val
);
3494 gsf_xml_out_add_cstr (state
->xml
,
3495 TABLE
"content-validation-name", vname
);
3498 lnk
= gnm_style_get_hlink (style
);
3502 if ((NULL
!= cell
->base
.texpr
) &&
3503 !gnm_expr_top_is_array_elem (cell
->base
.texpr
, NULL
, NULL
)) {
3504 char *formula
, *eq_formula
;
3507 if (gnm_cell_is_array (cell
)) {
3508 if (gnm_expr_top_is_array_corner (cell
->base
.texpr
)) {
3511 gnm_expr_top_get_array_size (cell
->base
.texpr
, &cols
, &rows
);
3512 gsf_xml_out_add_uint (state
->xml
,
3513 TABLE
"number-matrix-columns-spanned",
3514 (unsigned int)cols
);
3515 gsf_xml_out_add_uint (state
->xml
,
3516 TABLE
"number-matrix-rows-spanned",
3517 (unsigned int)rows
);
3521 parse_pos_init_cell (&pp
, cell
);
3522 formula
= gnm_expr_top_as_string (cell
->base
.texpr
,
3525 eq_formula
= g_strdup_printf ("of:=%s", formula
);
3527 gsf_xml_out_add_cstr (state
->xml
,
3531 g_free (eq_formula
);
3534 switch (cell
->value
->v_any
.type
) {
3538 gsf_xml_out_add_cstr_unchecked (state
->xml
,
3539 OFFICE
"value-type", "boolean");
3540 odf_add_bool (state
->xml
, OFFICE
"boolean-value",
3541 value_get_as_bool (cell
->value
, NULL
));
3544 GOFormat
const *fmt
= gnm_cell_get_format_given_style (cell
, style
);
3545 if (go_format_is_date (fmt
)) {
3547 gnm_float f
= value_get_as_float (cell
->value
);
3548 if (f
== gnm_floor (f
)) {
3549 gsf_xml_out_add_cstr_unchecked (state
->xml
,
3550 OFFICE
"value-type", "date");
3551 str
= format_value (state
->date_fmt
, cell
->value
, -1, workbook_date_conv (state
->wb
));
3552 gsf_xml_out_add_cstr (state
->xml
, OFFICE
"date-value", str
);
3554 gsf_xml_out_add_cstr_unchecked (state
->xml
,
3555 OFFICE
"value-type", "date");
3556 str
= format_value (state
->date_long_fmt
, cell
->value
, -1, workbook_date_conv (state
->wb
));
3557 gsf_xml_out_add_cstr (state
->xml
, OFFICE
"date-value", str
);
3560 } else if (go_format_is_time (fmt
) && (value_get_as_float (cell
->value
) >= 0.)) {
3562 gsf_xml_out_add_cstr_unchecked (state
->xml
,
3563 OFFICE
"value-type", "time");
3564 str
= format_value (state
->time_fmt
, cell
->value
, -1, workbook_date_conv (state
->wb
));
3565 gsf_xml_out_add_cstr (state
->xml
, OFFICE
"time-value", str
);
3568 GString
*str
= g_string_new (NULL
);
3570 gsf_xml_out_add_cstr_unchecked (state
->xml
,
3571 OFFICE
"value-type", "float");
3572 value_get_as_gstring (cell
->value
, str
, state
->conv
);
3573 gsf_xml_out_add_cstr (state
->xml
, OFFICE
"value", str
->str
);
3575 g_string_free (str
, TRUE
);
3580 if (NULL
== cell
->base
.texpr
) {
3581 /* see https://bugzilla.gnome.org/show_bug.cgi?id=610175 */
3582 /* this is the same that Excel does, OOo does not have */
3583 /* error literals. */
3584 char const *cv
= value_peek_string (cell
->value
);
3585 char *eq_formula
= g_strdup_printf ("of:=%s", cv
);
3587 if (state
->with_extension
)
3588 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"error-value", cv
);
3590 gsf_xml_out_add_cstr (state
->xml
,
3593 g_free (eq_formula
);
3595 gsf_xml_out_add_cstr_unchecked (state
->xml
,
3596 OFFICE
"value-type", "string");
3597 gsf_xml_out_add_cstr (state
->xml
,
3598 OFFICE
"string-value",
3599 value_peek_string (cell
->value
));
3602 gsf_xml_out_add_cstr_unchecked (state
->xml
,
3603 OFFICE
"value-type", "string");
3604 /* If this is a non-formula cell we show only the real formatted content */
3605 /* If the alignmnet type is 'FILL' we do need to give the string value! */
3606 if (NULL
!= cell
->base
.texpr
|| gnm_style_get_align_h (style
) == GNM_HALIGN_FILL
)
3607 gsf_xml_out_add_cstr (state
->xml
,
3608 OFFICE
"string-value",
3609 value_peek_string (cell
->value
));
3611 case VALUE_CELLRANGE
:
3618 odf_write_objects (state
, objects
);
3620 if (cell
!= NULL
&& cell
->value
!= NULL
) {
3621 gboolean pprint
= TRUE
;
3622 g_object_get (G_OBJECT (state
->xml
), "pretty-print", &pprint
, NULL
);
3623 g_object_set (G_OBJECT (state
->xml
), "pretty-print", FALSE
, NULL
);
3625 if ((VALUE_FMT (cell
->value
) == NULL
)
3626 || (!VALUE_IS_STRING (cell
->value
))
3627 || (!go_format_is_markup (VALUE_FMT (cell
->value
)))) {
3628 char *rendered_string
= gnm_cell_get_rendered_text (cell
);
3629 gboolean white_written
= TRUE
;
3631 gsf_xml_out_start_element (state
->xml
, TEXT
"p");
3632 if (lnk
) odf_write_link_start (state
, lnk
);
3633 if (*rendered_string
!= '\0')
3634 odf_add_chars (state
, rendered_string
, strlen (rendered_string
),
3636 if (lnk
) odf_write_link_end (state
, lnk
);
3637 gsf_xml_out_end_element (state
->xml
); /* p */
3638 g_free (rendered_string
);
3640 GString
*str
= g_string_new (NULL
);
3641 const PangoAttrList
* markup
;
3643 value_get_as_gstring (cell
->value
, str
, state
->conv
);
3644 markup
= go_format_get_markup (VALUE_FMT (cell
->value
));
3646 gsf_xml_out_start_element (state
->xml
, TEXT
"p");
3647 if (lnk
) odf_write_link_start (state
, lnk
);
3648 odf_new_markup (state
, markup
, str
->str
);
3649 if (lnk
) odf_write_link_end (state
, lnk
);
3650 gsf_xml_out_end_element (state
->xml
); /* p */
3652 g_string_free (str
, TRUE
);
3654 g_object_set (G_OBJECT (state
->xml
), "pretty-print", pprint
, NULL
);
3658 gsf_xml_out_end_element (state
->xml
); /* table-cell */
3662 filter_style (GnmStyle
*default_style
, GnmStyle
* this)
3664 return ((default_style
== this) ? NULL
: this);
3668 write_col_style (GnmOOExport
*state
, GnmStyle
*col_style
, ColRowInfo
const *ci
,
3673 if (col_style
!= NULL
) {
3674 name
= odf_find_style (state
, col_style
);
3676 gsf_xml_out_add_cstr (state
->xml
,
3677 TABLE
"default-cell-style-name", name
);
3679 name
= odf_find_col_style (state
,
3680 (ci
== NULL
) ? &sheet
->cols
.default_style
: ci
,
3683 gsf_xml_out_add_cstr (state
->xml
, TABLE
"style-name", name
);
3685 if (ci
!= NULL
&& !ci
->visible
)
3686 gsf_xml_out_add_cstr (state
->xml
, TABLE
"visibility", ci
->in_filter
? "filter" : "collapse");
3690 odf_write_formatted_columns (GnmOOExport
*state
, Sheet
const *sheet
, GnmStyle
**col_styles
, int from
, int to
)
3692 int number_cols_rep
;
3693 ColRowInfo
const *last_ci
;
3694 GnmStyle
*last_col_style
= NULL
;
3697 gsf_xml_out_start_element (state
->xml
, TABLE
"table-column");
3698 number_cols_rep
= 1;
3699 last_col_style
= filter_style (state
->default_style_region
->style
, col_styles
[0]);
3700 last_ci
= sheet_col_get (sheet
, 0);
3701 write_col_style (state
, last_col_style
, last_ci
, sheet
);
3703 for (i
= from
+1; i
< to
; i
++) {
3704 GnmStyle
*this_col_style
= filter_style (state
->default_style_region
->style
, col_styles
[i
]);
3705 ColRowInfo
const *this_ci
= sheet_col_get (sheet
, i
);
3707 if ((this_col_style
== last_col_style
) && colrow_equal (last_ci
, this_ci
))
3710 if (number_cols_rep
> 1)
3711 gsf_xml_out_add_int (state
->xml
, TABLE
"number-columns-repeated",
3713 gsf_xml_out_end_element (state
->xml
); /* table-column */
3715 gsf_xml_out_start_element (state
->xml
, TABLE
"table-column");
3716 number_cols_rep
= 1;
3717 last_col_style
= this_col_style
;
3719 write_col_style (state
, last_col_style
, last_ci
, sheet
);
3723 if (number_cols_rep
> 1)
3724 gsf_xml_out_add_int (state
->xml
, TABLE
"number-columns-repeated",
3726 gsf_xml_out_end_element (state
->xml
); /* table-column */
3730 write_row_style (GnmOOExport
*state
, ColRowInfo
const *ci
,
3735 name
= odf_find_row_style (state
,
3736 (ci
== NULL
) ? &sheet
->rows
.default_style
: ci
,
3739 gsf_xml_out_add_cstr (state
->xml
, TABLE
"style-name", name
);
3741 if (ci
!= NULL
&& !ci
->visible
)
3742 gsf_xml_out_add_cstr (state
->xml
, TABLE
"visibility", ci
->in_filter
? "filter" : "collapse");
3746 row_info_equal (GnmOOExport
*state
, Sheet
const *sheet
,
3747 ColRowInfo
const *ci1
, ColRowInfo
const *ci2
)
3753 odf_find_row_style (state
,
3754 (ci1
== NULL
) ? &sheet
->rows
.default_style
: ci1
,
3757 odf_find_row_style (state
,
3758 (ci2
== NULL
) ? &sheet
->rows
.default_style
: ci2
,
3760 return g_str_equal (n1
, n2
);
3765 compare_row_styles (const Sheet
*sheet
, GnmStyle
**styles
, int orow
)
3767 GnmStyle
**ostyles
= sheet_style_get_row2 (sheet
, orow
);
3770 res
= !memcmp (styles
, ostyles
,
3771 gnm_sheet_get_max_cols (sheet
) * sizeof (GnmStyle
*));
3779 odf_sheet_objects_get (Sheet
const *sheet
, GnmCellPos
const *pos
)
3784 g_return_val_if_fail (IS_SHEET (sheet
), NULL
);
3786 for (ptr
= sheet
->sheet_objects
; ptr
!= NULL
; ptr
= ptr
->next
) {
3787 SheetObject
*so
= GNM_SO (ptr
->data
);
3788 SheetObjectAnchor
const *anchor
= sheet_object_get_anchor (so
);
3789 if (anchor
->mode
== GNM_SO_ANCHOR_ABSOLUTE
) {
3791 res
= g_slist_prepend (res
, so
);
3792 } else if (pos
&& gnm_cellpos_equal (&anchor
->cell_bound
.start
, pos
))
3793 res
= g_slist_prepend (res
, so
);
3806 odf_write_content_rows (GnmOOExport
*state
, Sheet
const *sheet
, int from
, int to
,
3808 GSList
**sheet_merges
, GnmPageBreaks
*pb
, GnmStyle
**col_styles
)
3811 GPtrArray
*all_cells
;
3815 row_flags
= g_new0 (guint8
, gnm_sheet_get_max_rows (sheet
));
3817 /* Find out what rows have objects. */
3821 for (ptr
= sheet
->sheet_objects
; ptr
!= NULL
; ptr
= ptr
->next
) {
3822 SheetObject
*so
= GNM_SO (ptr
->data
);
3823 SheetObjectAnchor
const *anchor
= sheet_object_get_anchor (so
);
3824 int row
= anchor
->cell_bound
.start
.row
;
3825 row_flags
[row
] |= RF_OBJECT
;
3829 /* Find out what rows have page breaks. */
3830 for (row
= from
; row
< to
; row
++) {
3831 if (gnm_page_breaks_get_break (pb
, row
) != GNM_PAGE_BREAK_NONE
)
3832 row_flags
[row
] |= RF_PAGEBREAK
;
3835 /* Find out what rows have cells. */
3837 GnmRange fake_extent
;
3839 range_init_rows (&fake_extent
, sheet
, from
, to
- 1);
3840 all_cells
= sheet_cells ((Sheet
*)sheet
, &fake_extent
);
3841 for (ui
= 0; ui
< all_cells
->len
; ui
++) {
3842 GnmCell
*cell
= g_ptr_array_index (all_cells
, ui
);
3843 row_flags
[cell
->pos
.row
] |= RF_CELL
;
3845 /* Add a NULL to simplify code. */
3846 g_ptr_array_add (all_cells
, NULL
);
3849 /* Find out what rows have style not covered by column styles. */
3851 guint8
*non_defaults_rows
=
3852 sheet_style_get_nondefault_rows (sheet
, col_styles
);
3853 for (row
= from
; row
< to
; row
++)
3854 if (non_defaults_rows
[row
])
3855 row_flags
[row
] |= RF_STYLE
;
3856 g_free (non_defaults_rows
);
3859 for (row
= from
; row
< to
; /* nothing here */) {
3860 ColRowInfo
const *ci
= sheet_row_get (sheet
, row
);
3861 GnmStyle
const *null_style
= NULL
;
3863 int covered_cell
= 0;
3865 int repeat_count
= 1;
3866 guint8 rf
= row_flags
[row
];
3867 GnmStyle
**row_styles
= (rf
& RF_STYLE
)
3868 ? sheet_style_get_row2 (sheet
, row
)
3873 if (rf
& RF_PAGEBREAK
)
3874 gsf_xml_out_simple_element (state
->xml
,
3875 TEXT
"soft-page-break",
3878 gsf_xml_out_start_element (state
->xml
, TABLE
"table-row");
3879 write_row_style (state
, ci
, sheet
);
3881 if ((rf
& ~RF_STYLE
) == 0) {
3883 * We have nothing but style (possibly default) in this
3884 * row, so see if some rows following this one are
3888 while ((row2
= row
+ repeat_count
) < to
&&
3889 row_flags
[row2
] == rf
&&
3890 row_info_equal (state
, sheet
, ci
, sheet_row_get (sheet
, row2
)) &&
3891 (rf
== 0 || compare_row_styles (sheet
, row_styles
, row2
)))
3894 if (repeat_count
> 1)
3895 gsf_xml_out_add_int (state
->xml
, TABLE
"number-rows-repeated",
3902 for (col
= 0; col
< row_length
; col
++) {
3903 GnmCell
*current_cell
;
3904 GnmRange
const *merge_range
;
3906 GnmStyle
const *this_style
= row_styles
3910 current_cell
= g_ptr_array_index (all_cells
, cno
);
3912 current_cell
->pos
.row
== row
&&
3913 current_cell
->pos
.col
== col
)
3916 current_cell
= NULL
;
3920 merge_range
= gnm_sheet_merge_is_corner (sheet
, &pos
);
3922 if (odf_cell_is_covered (sheet
, current_cell
, col
, row
,
3923 merge_range
, sheet_merges
)) {
3924 odf_write_empty_cell (state
, null_cell
, null_style
, NULL
);
3930 objects
= (rf
& RF_OBJECT
)
3931 ? odf_sheet_objects_get (sheet
, &pos
)
3934 if ((!(current_cell
&& gnm_cell_has_expr(current_cell
))) &&
3935 (merge_range
== NULL
) && (objects
== NULL
) &&
3936 gnm_cell_is_empty (current_cell
) &&
3937 !gnm_style_get_hlink (this_style
)) {
3938 if ((null_cell
== 0) || (null_style
== this_style
)) {
3939 null_style
= this_style
;
3940 if (covered_cell
> 0)
3941 odf_write_covered_cell (state
, &covered_cell
);
3944 odf_write_empty_cell (state
, null_cell
, null_style
, NULL
);
3945 null_style
= this_style
;
3951 odf_write_empty_cell (state
, null_cell
, null_style
, NULL
);
3953 if (covered_cell
> 0)
3954 odf_write_covered_cell (state
, &covered_cell
);
3955 odf_write_cell (state
, current_cell
, merge_range
, this_style
, objects
);
3957 g_slist_free (objects
);
3961 null_cell
= row_length
;
3963 odf_write_empty_cell (state
, null_cell
, null_style
, NULL
);
3965 if (covered_cell
> 0)
3966 odf_write_covered_cell (state
, &covered_cell
);
3968 gsf_xml_out_end_element (state
->xml
); /* table-row */
3970 row
+= repeat_count
;
3971 g_free (row_styles
);
3974 g_ptr_array_free (all_cells
, TRUE
);
3979 odf_write_sheet (GnmOOExport
*state
)
3981 /* While ODF allows the TABLE "table-columns" wrapper, */
3982 /* and TABLE "table-rows" wrapper, */
3983 /* MS Excel 2010 stumbles over it */
3984 /* So we may not use them! */
3986 Sheet
const *sheet
= state
->sheet
;
3987 int max_cols
= gnm_sheet_get_max_cols (sheet
);
3988 int max_rows
= gnm_sheet_get_max_rows (sheet
);
3989 GnmStyle
**col_styles
;
3991 GSList
*sheet_merges
= NULL
;
3992 GnmPageBreaks
*pb
= sheet
->print_info
->page_breaks
.v
;
3994 col_styles
= sheet_style_most_common (sheet
, TRUE
);
3996 /* ODF does not allow us to mark soft page breaks between columns */
3997 if (print_load_repeat_range (sheet
->print_info
->repeat_left
, &r
, sheet
)) {
3998 int repeat_left_start
, repeat_left_end
;
3999 repeat_left_start
= r
.start
.col
;
4000 repeat_left_end
= r
.end
.col
;
4002 if (repeat_left_start
> 0)
4003 odf_write_formatted_columns (state
, sheet
, col_styles
,
4004 0, repeat_left_start
);
4005 gsf_xml_out_start_element
4006 (state
->xml
, TABLE
"table-header-columns");
4007 odf_write_formatted_columns (state
, sheet
, col_styles
,
4009 repeat_left_end
+ 1);
4010 gsf_xml_out_end_element (state
->xml
);
4011 if (repeat_left_end
< max_cols
)
4012 odf_write_formatted_columns (state
, sheet
, col_styles
,
4013 repeat_left_end
+ 1, max_cols
);
4015 odf_write_formatted_columns (state
, sheet
, col_styles
, 0, max_cols
);
4017 if (print_load_repeat_range (sheet
->print_info
->repeat_top
, &r
, sheet
)) {
4018 int repeat_top_start
, repeat_top_end
;
4019 repeat_top_start
= r
.start
.row
;
4020 repeat_top_end
= r
.end
.row
;
4021 if (repeat_top_start
> 0)
4022 odf_write_content_rows (state
, sheet
,
4023 0, repeat_top_start
,
4024 max_cols
, &sheet_merges
, pb
, col_styles
);
4025 gsf_xml_out_start_element
4026 (state
->xml
, TABLE
"table-header-rows");
4027 odf_write_content_rows (state
, sheet
,
4028 repeat_top_start
, repeat_top_end
+ 1,
4029 max_cols
, &sheet_merges
, pb
, col_styles
);
4030 gsf_xml_out_end_element (state
->xml
);
4031 if (repeat_top_end
< max_rows
)
4032 odf_write_content_rows (state
, sheet
,
4033 repeat_top_end
+ 1, max_rows
,
4034 max_cols
, &sheet_merges
, pb
, col_styles
);
4036 odf_write_content_rows (state
, sheet
,
4038 max_cols
, &sheet_merges
, pb
, col_styles
);
4040 g_slist_free_full (sheet_merges
, g_free
);
4041 g_free (col_styles
);
4046 odf_write_sheet_controls_get_id (GnmOOExport
*state
, SheetObject
*so
)
4048 char *id
= g_strdup_printf ("CTRL%.4i",g_hash_table_size (state
->controls
));
4049 g_hash_table_replace (state
->controls
, so
, id
);
4054 odf_write_sheet_control_content (GnmOOExport
*state
, GnmExprTop
const *texpr
)
4056 if (texpr
&& gnm_expr_top_is_rangeref (texpr
)) {
4060 parse_pos_init_sheet (&pp
, state
->sheet
);
4061 lnk
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
4063 if (state
->odf_version
> 101)
4064 gsf_xml_out_add_cstr (state
->xml
,
4065 FORM
"source-cell-range",
4066 odf_strip_brackets (lnk
));
4068 gsf_xml_out_add_cstr (state
->xml
,
4069 GNMSTYLE
"source-cell-range",
4070 odf_strip_brackets (lnk
));
4072 gnm_expr_top_unref (texpr
);
4077 odf_write_sheet_control_linked_cell (GnmOOExport
*state
, GnmExprTop
const *texpr
)
4079 if (texpr
&& gnm_expr_top_is_rangeref (texpr
)) {
4083 parse_pos_init_sheet (&pp
, state
->sheet
);
4084 lnk
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
4086 if (state
->odf_version
> 101)
4087 gsf_xml_out_add_cstr (state
->xml
, FORM
"linked-cell",
4088 odf_strip_brackets (lnk
));
4090 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"linked-cell",
4091 odf_strip_brackets (lnk
));
4093 gnm_expr_top_unref (texpr
);
4098 odf_sheet_control_start_element (GnmOOExport
*state
, SheetObject
*so
,
4099 char const *element
)
4101 char const *id
= odf_write_sheet_controls_get_id (state
, so
);
4102 gsf_xml_out_start_element (state
->xml
, element
);
4103 gsf_xml_out_add_cstr (state
->xml
, XML
"id", id
);
4104 gsf_xml_out_add_cstr (state
->xml
, FORM
"id", id
);
4109 odf_write_sheet_control_scrollbar (GnmOOExport
*state
, SheetObject
*so
,
4110 char const *implementation
)
4112 GtkAdjustment
*adj
= sheet_widget_adjustment_get_adjustment (so
);
4113 GnmExprTop
const *texpr
= sheet_widget_adjustment_get_link (so
);
4115 odf_sheet_control_start_element (state
, so
, FORM
"value-range");
4117 if (implementation
!= NULL
)
4118 gsf_xml_out_add_cstr (state
->xml
,
4119 FORM
"control-implementation",
4121 gsf_xml_out_add_cstr (state
->xml
, FORM
"orientation",
4122 sheet_widget_adjustment_get_horizontal (so
) ?
4123 "horizontal" : "vertical");
4124 go_xml_out_add_double (state
->xml
, FORM
"value", gtk_adjustment_get_value (adj
));
4125 go_xml_out_add_double (state
->xml
, FORM
"min-value", gtk_adjustment_get_lower (adj
));
4126 go_xml_out_add_double (state
->xml
, FORM
"max-value", gtk_adjustment_get_upper (adj
));
4127 gsf_xml_out_add_int (state
->xml
, FORM
"step-size",
4128 (int)(gtk_adjustment_get_step_increment (adj
) + 0.5));
4129 gsf_xml_out_add_int (state
->xml
, FORM
"page-step-size",
4130 (int)(gtk_adjustment_get_page_increment (adj
) + 0.5));
4131 /* OOo fails to import this control, but adding its control-implementation */
4133 /* gsf_xml_out_add_cstr (state->xml, FORM "control-implementation", */
4134 /* OOO "com.sun.star.form.component.ScrollBar"); */
4136 odf_write_sheet_control_linked_cell (state
, texpr
);
4137 gsf_xml_out_end_element (state
->xml
); /* form:value-range */
4141 odf_write_sheet_control_checkbox (GnmOOExport
*state
, SheetObject
*so
)
4143 GnmExprTop
const *texpr
= sheet_widget_checkbox_get_link (so
);
4145 gboolean active
= FALSE
;
4147 g_object_get (G_OBJECT (so
), "text", &label
, "active", &active
, NULL
);
4149 odf_sheet_control_start_element (state
, so
, FORM
"checkbox");
4151 gsf_xml_out_add_cstr (state
->xml
, FORM
"label", label
);
4152 gsf_xml_out_add_cstr (state
->xml
, FORM
"current-state", active
? "checked" : "unchecked");
4154 odf_write_sheet_control_linked_cell (state
, texpr
);
4156 gsf_xml_out_end_element (state
->xml
); /* form:checkbox */
4162 odf_write_sheet_control_frame (GnmOOExport
*state
, SheetObject
*so
)
4166 g_object_get (G_OBJECT (so
), "text", &label
, NULL
);
4168 odf_sheet_control_start_element (state
, so
, FORM
"generic-control");
4169 gsf_xml_out_add_cstr_unchecked (state
->xml
,
4170 FORM
"control-implementation",
4173 gsf_xml_out_start_element (state
->xml
, FORM
"properties");
4174 gsf_xml_out_start_element (state
->xml
, FORM
"property");
4176 gsf_xml_out_add_cstr_unchecked (state
->xml
, FORM
"property-name", GNMSTYLE
"label");
4177 gsf_xml_out_add_cstr_unchecked (state
->xml
, OFFICE
"value-type", "string");
4178 gsf_xml_out_add_cstr (state
->xml
, OFFICE
"string-value", label
);
4179 gsf_xml_out_end_element (state
->xml
); /* form:property */
4180 gsf_xml_out_end_element (state
->xml
); /* form:properties */
4182 gsf_xml_out_end_element (state
->xml
); /* form:generic-control */
4188 odf_write_sheet_control_list (GnmOOExport
*state
, SheetObject
*so
,
4189 char const *element
, gboolean is_listbox
)
4191 GnmExprTop
const *texpr
= sheet_widget_list_base_get_result_link (so
);
4192 gboolean as_index
= sheet_widget_list_base_result_type_is_index (so
);
4194 odf_sheet_control_start_element (state
, so
, element
);
4196 odf_write_sheet_control_linked_cell (state
, texpr
);
4198 texpr
= sheet_widget_list_base_get_content_link (so
);
4199 odf_write_sheet_control_content (state
, texpr
);
4201 if (state
->odf_version
> 101 && is_listbox
)
4202 gsf_xml_out_add_cstr_unchecked
4203 (state
->xml
, FORM
"list-linkage-type",
4204 as_index
? "selection-indices" : "selection");
4205 else if (state
->with_extension
)
4206 gsf_xml_out_add_cstr_unchecked
4207 (state
->xml
, GNMSTYLE
"list-linkage-type",
4208 as_index
? "selection-indices" : "selection");
4210 gsf_xml_out_add_int (state
->xml
, FORM
"bound-column", 1);
4211 gsf_xml_out_end_element (state
->xml
);
4215 odf_write_sheet_control_radio_button (GnmOOExport
*state
, SheetObject
*so
)
4217 GnmExprTop
const *texpr
= sheet_widget_radio_button_get_link (so
);
4218 GnmValue
const *val
= sheet_widget_radio_button_get_value (so
);
4220 gboolean active
= FALSE
;
4222 g_object_get (G_OBJECT (so
), "text", &label
, "active", &active
, NULL
);
4224 odf_sheet_control_start_element (state
, so
, FORM
"radio");
4226 gsf_xml_out_add_cstr (state
->xml
, FORM
"label", label
);
4227 odf_add_bool (state
->xml
, FORM
"current-selected", active
);
4230 switch (val
->v_any
.type
) {
4234 if (state
->with_extension
)
4235 gsf_xml_out_add_cstr_unchecked
4237 GNMSTYLE
"value-type",
4239 odf_add_bool (state
->xml
, FORM
"value",
4240 value_get_as_bool (val
, NULL
));
4243 GString
*str
= g_string_new (NULL
);
4244 if (state
->with_extension
)
4245 gsf_xml_out_add_cstr_unchecked
4247 GNMSTYLE
"value-type",
4249 value_get_as_gstring (val
, str
, state
->conv
);
4250 gsf_xml_out_add_cstr (state
->xml
, FORM
"value",
4252 g_string_free (str
, TRUE
);
4257 if (state
->with_extension
)
4258 gsf_xml_out_add_cstr_unchecked
4260 GNMSTYLE
"value-type",
4262 gsf_xml_out_add_cstr (state
->xml
,
4264 value_peek_string (val
));
4266 case VALUE_CELLRANGE
:
4273 odf_write_sheet_control_linked_cell (state
, texpr
);
4275 gsf_xml_out_end_element (state
->xml
); /* form:checkbox */
4281 odf_write_sheet_control_button (GnmOOExport
*state
, SheetObject
*so
)
4283 GnmExprTop
const *texpr
= sheet_widget_button_get_link (so
);
4286 odf_sheet_control_start_element (state
, so
, FORM
"button");
4288 g_object_get (G_OBJECT (so
), "text", &label
, NULL
);
4289 gsf_xml_out_add_cstr (state
->xml
, FORM
"label", label
);
4292 gsf_xml_out_add_cstr_unchecked (state
->xml
, FORM
"button-type", "push");
4294 if (texpr
!= NULL
) {
4295 char *lnk
= NULL
, *name
= NULL
;
4298 parse_pos_init_sheet (&pp
, state
->sheet
);
4299 lnk
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
4301 gsf_xml_out_start_element (state
->xml
, OFFICE
"event-listeners");
4303 gsf_xml_out_start_element (state
->xml
, SCRIPT
"event-listener");
4304 gsf_xml_out_add_cstr_unchecked (state
->xml
, SCRIPT
"event-name",
4306 gsf_xml_out_add_cstr_unchecked (state
->xml
, SCRIPT
"language",
4307 GNMSTYLE
"short-macro");
4308 name
= g_strdup_printf ("set-to-TRUE:%s", odf_strip_brackets (lnk
));
4309 gsf_xml_out_add_cstr (state
->xml
, SCRIPT
"macro-name", name
);
4311 gsf_xml_out_end_element (state
->xml
); /* script:event-listener */
4313 gsf_xml_out_start_element (state
->xml
, SCRIPT
"event-listener");
4314 gsf_xml_out_add_cstr_unchecked (state
->xml
, SCRIPT
"event-name",
4316 gsf_xml_out_add_cstr_unchecked (state
->xml
, SCRIPT
"language",
4317 GNMSTYLE
"short-macro");
4318 name
= g_strdup_printf ("set-to-FALSE:%s", odf_strip_brackets (lnk
));
4319 gsf_xml_out_add_cstr (state
->xml
, SCRIPT
"macro-name", name
);
4321 gsf_xml_out_end_element (state
->xml
); /* script:event-listener */
4323 gsf_xml_out_end_element (state
->xml
); /* office:event-listeners */
4326 gnm_expr_top_unref (texpr
);
4329 gsf_xml_out_end_element (state
->xml
); /* form:checkbox */
4333 odf_write_sheet_controls (GnmOOExport
*state
)
4335 Sheet
const *sheet
= state
->sheet
;
4336 GSList
*objects
= sheet
->sheet_objects
, *l
;
4338 gsf_xml_out_start_element (state
->xml
, OFFICE
"forms");
4339 odf_add_bool (state
->xml
, FORM
"automatic-focus", FALSE
);
4340 odf_add_bool (state
->xml
, FORM
"apply-design-mode", FALSE
);
4341 gsf_xml_out_start_element (state
->xml
, FORM
"form");
4343 for (l
= objects
; l
!= NULL
; l
= l
->next
) {
4344 SheetObject
*so
= l
->data
;
4346 if (GNM_IS_SOW_SCROLLBAR (so
))
4347 odf_write_sheet_control_scrollbar
4348 (state
, so
, GNMSTYLE
"scrollbar");
4349 else if (GNM_IS_SOW_SLIDER (so
))
4350 odf_write_sheet_control_scrollbar
4351 (state
, so
, GNMSTYLE
"slider");
4352 else if (GNM_IS_SOW_SPINBUTTON (so
))
4353 odf_write_sheet_control_scrollbar
4354 (state
, so
, GNMSTYLE
"spinbutton");
4355 else if (GNM_IS_SOW_CHECKBOX (so
))
4356 odf_write_sheet_control_checkbox (state
, so
);
4357 else if (GNM_IS_SOW_RADIO_BUTTON (so
))
4358 odf_write_sheet_control_radio_button (state
, so
);
4359 else if (GNM_IS_SOW_LIST (so
))
4360 odf_write_sheet_control_list (state
, so
,
4361 FORM
"listbox", TRUE
);
4362 else if (GNM_IS_SOW_COMBO (so
))
4363 odf_write_sheet_control_list (state
, so
,
4364 FORM
"combobox", FALSE
);
4365 else if (GNM_IS_SOW_BUTTON (so
))
4366 odf_write_sheet_control_button (state
, so
);
4367 else if (GNM_IS_SOW_FRAME (so
))
4368 odf_write_sheet_control_frame (state
, so
);
4371 gsf_xml_out_end_element (state
->xml
); /* form:form */
4372 gsf_xml_out_end_element (state
->xml
); /* office:forms */
4376 odf_write_filter_cond (GnmOOExport
*state
, GnmFilter
const *filter
, int i
)
4378 GnmFilterCondition
const *cond
= gnm_filter_get_condition (filter
, i
);
4379 char const *op
, *type
= NULL
;
4380 GString
*val_str
= NULL
;
4385 switch (cond
->op
[0]) {
4386 case GNM_FILTER_OP_EQUAL
: op
= "="; break;
4387 case GNM_FILTER_OP_GT
: op
= ">"; break;
4388 case GNM_FILTER_OP_LT
: op
= "<"; break;
4389 case GNM_FILTER_OP_GTE
: op
= ">="; break;
4390 case GNM_FILTER_OP_LTE
: op
= "<="; break;
4391 case GNM_FILTER_OP_NOT_EQUAL
: op
= "!="; break;
4392 case GNM_FILTER_OP_MATCH
: op
= "match"; break;
4393 case GNM_FILTER_OP_NO_MATCH
: op
= "!match"; break;
4395 case GNM_FILTER_OP_BLANKS
: op
= "empty"; break;
4396 case GNM_FILTER_OP_NON_BLANKS
: op
= "!empty"; break;
4397 case GNM_FILTER_OP_TOP_N
: op
= "top values"; break;
4398 case GNM_FILTER_OP_BOTTOM_N
: op
= "bottom values"; break;
4399 case GNM_FILTER_OP_TOP_N_PERCENT
: op
= "top percent"; break;
4400 case GNM_FILTER_OP_BOTTOM_N_PERCENT
: op
= "bottom percent"; break;
4401 /* remainder are not supported in ODF */
4406 if (GNM_FILTER_OP_TYPE_BUCKETS
== (cond
->op
[0] & GNM_FILTER_OP_TYPE_MASK
)) {
4407 val_str
= g_string_new (NULL
);
4409 g_string_printf (val_str
, "%g", cond
->count
);
4410 } else if (GNM_FILTER_OP_TYPE_BLANKS
!= (cond
->op
[0] & GNM_FILTER_OP_TYPE_MASK
)) {
4411 val_str
= g_string_new (NULL
);
4412 type
= VALUE_IS_FLOAT (cond
->value
[0]) ? "number" : "text";
4413 value_get_as_gstring (cond
->value
[0], val_str
, state
->conv
);
4416 gsf_xml_out_start_element (state
->xml
, TABLE
"filter-condition");
4417 gsf_xml_out_add_int (state
->xml
, TABLE
"field-number", i
);
4418 if (NULL
!= type
&& val_str
!= NULL
) {
4419 gsf_xml_out_add_cstr_unchecked (state
->xml
, TABLE
"data-type", type
);
4420 gsf_xml_out_add_cstr (state
->xml
, TABLE
"value", val_str
->str
);
4422 gsf_xml_out_add_cstr_unchecked (state
->xml
, TABLE
"operator", op
);
4423 gsf_xml_out_end_element (state
->xml
); /* </table:filter-condition> */
4426 g_string_free (val_str
, TRUE
);
4430 odf_write_autofilter (GnmOOExport
*state
, GnmFilter
const *filter
)
4435 gsf_xml_out_start_element (state
->xml
, TABLE
"database-range");
4437 /* manually create a ref string with no '[]' bracing */
4438 buf
= g_string_new (filter
->sheet
->name_quoted
);
4439 g_string_append_c (buf
, '.');
4440 g_string_append (buf
, cellpos_as_string (&filter
->r
.start
));
4441 g_string_append_c (buf
, ':');
4442 g_string_append (buf
, filter
->sheet
->name_quoted
);
4443 g_string_append_c (buf
, '.');
4444 g_string_append (buf
, cellpos_as_string (&filter
->r
.end
));
4445 gsf_xml_out_add_cstr (state
->xml
, TABLE
"target-range-address", buf
->str
);
4446 g_string_free (buf
, TRUE
);
4448 odf_add_bool (state
->xml
, TABLE
"display-filter-buttons", TRUE
);
4450 if (filter
->is_active
) {
4451 gsf_xml_out_start_element (state
->xml
, TABLE
"filter");
4452 if (filter
->fields
->len
> 1) {
4453 gsf_xml_out_start_element (state
->xml
, TABLE
"filter-and");
4454 for (i
= 0 ; i
< filter
->fields
->len
; i
++)
4455 odf_write_filter_cond (state
, filter
, i
);
4456 gsf_xml_out_end_element (state
->xml
); /* </table:filter-and> */
4457 } else if (filter
->fields
->len
== 1)
4458 odf_write_filter_cond (state
, filter
, 0);
4459 gsf_xml_out_end_element (state
->xml
); /* </table:filter> */
4462 gsf_xml_out_end_element (state
->xml
); /* </table:database-range> */
4466 odf_validation_general_attributes (GnmOOExport
*state
, GnmValidation
const *val
)
4468 odf_add_bool (state
->xml
, TABLE
"allow-empty-cell", val
->allow_blank
);
4469 gsf_xml_out_add_cstr (state
->xml
, TABLE
"display-list",
4470 val
->use_dropdown
? "unsorted" : "none");
4474 odf_validation_base_cell_address (GnmOOExport
*state
,
4475 Sheet
*sheet
, GnmStyleRegion
const *sr
,
4478 GnmExprTop
const *texpr
;
4482 gnm_cellref_init (&ref
, sheet
,
4483 sr
->range
.start
.col
,
4484 sr
->range
.start
.row
, TRUE
);
4485 texpr
= gnm_expr_top_new (gnm_expr_new_cellref (&ref
));
4486 parse_pos_init (pp
, (Workbook
*)state
->wb
, sheet
,
4487 sr
->range
.start
.col
,
4488 sr
->range
.start
.row
);
4489 formula
= gnm_expr_top_as_string (texpr
, pp
, state
->conv
);
4490 gsf_xml_out_add_cstr (state
->xml
, TABLE
"base-cell-address",
4491 odf_strip_brackets (formula
));
4493 gnm_expr_top_unref (texpr
);
4497 odf_validation_append_expression (GnmOOExport
*state
, GString
*str
, GnmExprTop
const *texpr
,
4502 formula
= gnm_expr_top_as_string (texpr
, pp
, state
->conv
);
4503 g_string_append (str
, formula
);
4508 odf_validation_append_expression_pair (GnmOOExport
*state
, GString
*str
,
4509 GnmValidation
const *val
,
4512 g_string_append_c (str
, '(');
4513 odf_validation_append_expression (state
, str
,
4514 val
->deps
[0].texpr
, pp
);
4515 g_string_append_c (str
, ',');
4516 odf_validation_append_expression (state
, str
,
4517 val
->deps
[1].texpr
, pp
);
4518 g_string_append_c (str
, ')');
4523 odf_validation_general (GnmOOExport
*state
, GnmValidation
const *val
,
4524 G_GNUC_UNUSED Sheet
*sheet
,
4525 G_GNUC_UNUSED GnmStyleRegion
const *sr
,
4526 char const *prefix
, GnmParsePos
*pp
)
4528 GString
*str
= g_string_new ("of:");
4530 g_string_append (str
, prefix
);
4533 case GNM_VALIDATION_OP_NONE
:
4534 g_string_append (str
, "is-true-formula(1)");
4536 case GNM_VALIDATION_OP_BETWEEN
:
4537 g_string_append (str
, "cell-content-is-between");
4538 odf_validation_append_expression_pair (state
, str
, val
, pp
);
4540 case GNM_VALIDATION_OP_NOT_BETWEEN
:
4541 g_string_append (str
, "cell-content-is-not-between");
4542 odf_validation_append_expression_pair (state
, str
, val
, pp
);
4544 case GNM_VALIDATION_OP_EQUAL
:
4545 g_string_append (str
, "cell-content() = ");
4546 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4548 case GNM_VALIDATION_OP_NOT_EQUAL
:
4549 g_string_append (str
, "cell-content() != ");
4550 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4552 case GNM_VALIDATION_OP_GT
:
4553 g_string_append (str
, "cell-content() > ");
4554 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4556 case GNM_VALIDATION_OP_LT
:
4557 g_string_append (str
, "cell-content() < ");
4558 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4560 case GNM_VALIDATION_OP_GTE
:
4561 g_string_append (str
, "cell-content() >= ");
4562 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4564 case GNM_VALIDATION_OP_LTE
:
4565 g_string_append (str
, "cell-content() <= ");
4566 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4570 gsf_xml_out_add_cstr (state
->xml
, TABLE
"condition", str
->str
);
4571 g_string_free (str
, TRUE
);
4575 odf_validation_length (GnmOOExport
*state
, GnmValidation
const *val
,
4576 G_GNUC_UNUSED Sheet
*sheet
,
4577 G_GNUC_UNUSED GnmStyleRegion
const *sr
, GnmParsePos
*pp
)
4579 GString
*str
= g_string_new ("of:");
4582 case GNM_VALIDATION_OP_NONE
:
4583 g_string_append (str
, "is-true-formula(1)");
4585 case GNM_VALIDATION_OP_BETWEEN
:
4586 g_string_append (str
, "cell-content-text-length-is-between");
4587 odf_validation_append_expression_pair (state
, str
, val
, pp
);
4589 case GNM_VALIDATION_OP_NOT_BETWEEN
:
4590 g_string_append (str
, "cell-content-text-length-is-not-between");
4591 odf_validation_append_expression_pair (state
, str
, val
, pp
);
4593 case GNM_VALIDATION_OP_EQUAL
:
4594 g_string_append (str
, "cell-content-text-length() = ");
4595 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4597 case GNM_VALIDATION_OP_NOT_EQUAL
:
4598 g_string_append (str
, "cell-content-text-length() != ");
4599 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4601 case GNM_VALIDATION_OP_GT
:
4602 g_string_append (str
, "cell-content-text-length() > ");
4603 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4605 case GNM_VALIDATION_OP_LT
:
4606 g_string_append (str
, "cell-content-text-length() < ");
4607 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4609 case GNM_VALIDATION_OP_GTE
:
4610 g_string_append (str
, "of:cell-content-text-length() >= ");
4611 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4613 case GNM_VALIDATION_OP_LTE
:
4614 g_string_append (str
, "cell-content-text-length() <= ");
4615 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4619 gsf_xml_out_add_cstr (state
->xml
, TABLE
"condition", str
->str
);
4620 g_string_free (str
, TRUE
);
4624 odf_validation_custom (GnmOOExport
*state
, GnmValidation
const *val
,
4625 G_GNUC_UNUSED Sheet
*sheet
,
4626 G_GNUC_UNUSED GnmStyleRegion
const *sr
, GnmParsePos
*pp
)
4628 GString
*str
= g_string_new (NULL
);
4630 g_string_append (str
, "of:is-true-formula(");
4631 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4632 g_string_append_c (str
, ')');
4634 gsf_xml_out_add_cstr (state
->xml
, TABLE
"condition", str
->str
);
4635 g_string_free (str
, TRUE
);
4639 odf_validation_in_list (GnmOOExport
*state
, GnmValidation
const *val
,
4640 G_GNUC_UNUSED Sheet
*sheet
,
4641 G_GNUC_UNUSED GnmStyleRegion
const *sr
, GnmParsePos
*pp
)
4645 str
= g_string_new ("of:cell-content-is-in-list(");
4646 odf_validation_append_expression (state
, str
, val
->deps
[0].texpr
, pp
);
4647 g_string_append_c (str
, ')');
4649 gsf_xml_out_add_cstr (state
->xml
, TABLE
"condition", str
->str
);
4650 g_string_free (str
, TRUE
);
4654 odf_print_spreadsheet_content_validations (GnmOOExport
*state
)
4656 gboolean element_written
= FALSE
;
4659 for (i
= 0; i
< workbook_sheet_count (state
->wb
); i
++) {
4660 Sheet
*sheet
= workbook_sheet_by_index (state
->wb
, i
);
4661 GnmStyleList
*list
, *l
;
4663 list
= sheet_style_collect_validations (sheet
, NULL
);
4665 for (l
= list
; l
!= NULL
; l
= l
->next
) {
4666 GnmStyleRegion
const *sr
= l
->data
;
4667 GnmValidation
const *val
= gnm_style_get_validation (sr
->style
);
4668 GnmInputMsg
const *msg
= gnm_style_get_input_msg (sr
->style
);
4670 char const *message_type
= NULL
;
4673 if (val
== NULL
&& msg
== NULL
) {
4674 g_warning ("Encountered NULL validation with NULL message!");
4678 if (!element_written
) {
4679 gsf_xml_out_start_element
4680 (state
->xml
, TABLE
"content-validations");
4681 element_written
= TRUE
;
4683 gsf_xml_out_start_element (state
->xml
,
4684 TABLE
"content-validation");
4687 ? oo_item_name (state
, OO_ITEM_VALIDATION
, val
)
4688 : oo_item_name (state
, OO_ITEM_INPUT_MSG
, msg
);
4689 gsf_xml_out_add_cstr (state
->xml
, TABLE
"name", name
);
4693 odf_validation_general_attributes (state
, val
);
4694 odf_validation_base_cell_address (state
, sheet
, sr
, &pp
);
4695 switch (val
->type
) {
4696 case GNM_VALIDATION_TYPE_ANY
:
4697 odf_validation_general (state
, val
, sheet
, sr
, "", &pp
);
4699 case GNM_VALIDATION_TYPE_AS_INT
:
4700 odf_validation_general (state
, val
, sheet
, sr
,
4701 "cell-content-is-whole-number() and ", &pp
);
4703 case GNM_VALIDATION_TYPE_AS_NUMBER
:
4704 odf_validation_general (state
, val
, sheet
, sr
,
4705 "cell-content-is-decimal-number() and ", &pp
);
4707 case GNM_VALIDATION_TYPE_AS_DATE
:
4708 odf_validation_general (state
, val
, sheet
, sr
,
4709 "cell-content-is-date() and ", &pp
);
4711 case GNM_VALIDATION_TYPE_AS_TIME
:
4712 odf_validation_general (state
, val
, sheet
, sr
,
4713 "cell-content-is-time() and ", &pp
);
4715 case GNM_VALIDATION_TYPE_IN_LIST
:
4716 odf_validation_in_list (state
, val
, sheet
, sr
, &pp
);
4718 case GNM_VALIDATION_TYPE_TEXT_LENGTH
:
4719 odf_validation_length (state
, val
, sheet
, sr
, &pp
);
4721 case GNM_VALIDATION_TYPE_CUSTOM
:
4722 odf_validation_custom (state
, val
, sheet
, sr
, &pp
);
4727 /* writing help message */
4729 char const * msg_content
= gnm_input_msg_get_msg (msg
);
4730 char const * msg_title
= gnm_input_msg_get_title (msg
);
4732 if (msg_content
!= NULL
|| msg_title
!= NULL
) {
4733 gsf_xml_out_start_element (state
->xml
,
4734 TABLE
"help-message");
4735 odf_add_bool (state
->xml
, TABLE
"display", TRUE
);
4736 if (msg_title
!= NULL
)
4737 gsf_xml_out_add_cstr (state
->xml
, TABLE
"title", msg_title
);
4739 if (msg_content
!= NULL
&& strlen (msg_content
) > 0) {
4740 gboolean white_written
= TRUE
;
4742 g_object_get (G_OBJECT (state
->xml
), "pretty-print", &pp
, NULL
);
4743 g_object_set (G_OBJECT (state
->xml
), "pretty-print", FALSE
, NULL
);
4744 gsf_xml_out_start_element (state
->xml
, TEXT
"p");
4745 odf_add_chars (state
, msg_content
, strlen (msg_content
),
4747 gsf_xml_out_end_element (state
->xml
); /* p */
4748 g_object_set (G_OBJECT (state
->xml
), "pretty-print", pp
, NULL
);
4751 gsf_xml_out_end_element (state
->xml
);
4752 /* help message written */
4757 /* writing error message */
4758 gsf_xml_out_start_element (state
->xml
,
4759 TABLE
"error-message");
4760 odf_add_bool (state
->xml
, TABLE
"display", TRUE
);
4761 switch (val
->style
) {
4762 case GNM_VALIDATION_STYLE_NONE
:
4763 case GNM_VALIDATION_STYLE_INFO
:
4764 case GNM_VALIDATION_STYLE_PARSE_ERROR
:
4765 message_type
= "information";
4767 case GNM_VALIDATION_STYLE_STOP
:
4768 message_type
= "stop";
4770 case GNM_VALIDATION_STYLE_WARNING
:
4771 message_type
= "warning";
4774 gsf_xml_out_add_cstr_unchecked (state
->xml
, TABLE
"message-type", message_type
);
4775 if (val
->title
!= NULL
)
4776 gsf_xml_out_add_cstr (state
->xml
, TABLE
"title", val
->title
->str
);
4778 if (val
->msg
!= NULL
&& go_string_get_len (val
->msg
) > 0) {
4779 gboolean white_written
= TRUE
;
4781 g_object_get (G_OBJECT (state
->xml
), "pretty-print", &pp
, NULL
);
4782 g_object_set (G_OBJECT (state
->xml
), "pretty-print", FALSE
, NULL
);
4783 gsf_xml_out_start_element (state
->xml
, TEXT
"p");
4784 odf_add_chars (state
, val
->msg
->str
, go_string_get_len (val
->msg
), &white_written
);
4785 gsf_xml_out_end_element (state
->xml
); /* p */
4786 g_object_set (G_OBJECT (state
->xml
), "pretty-print", pp
, NULL
);
4789 gsf_xml_out_end_element (state
->xml
);
4790 /* error message written */
4793 gsf_xml_out_end_element (state
->xml
);
4794 /* </table:content-validation> */
4797 style_list_free (list
);
4800 if (element_written
)
4801 gsf_xml_out_end_element (state
->xml
); /* </table:content-validations> */
4806 odf_print_spreadsheet_content_prelude (GnmOOExport
*state
)
4808 gsf_xml_out_start_element (state
->xml
, TABLE
"calculation-settings");
4809 gsf_xml_out_add_int (state
->xml
, TABLE
"null-year", 1930);
4810 odf_add_bool (state
->xml
, TABLE
"automatic-find-labels", FALSE
);
4811 odf_add_bool (state
->xml
, TABLE
"case-sensitive", FALSE
);
4812 odf_add_bool (state
->xml
, TABLE
"precision-as-shown", FALSE
);
4813 odf_add_bool (state
->xml
, TABLE
"search-criteria-must-apply-to-whole-cell", TRUE
);
4814 odf_add_bool (state
->xml
, TABLE
"use-regular-expressions", FALSE
);
4815 if (state
->odf_version
> 101)
4816 odf_add_bool (state
->xml
, TABLE
"use-wildcards", FALSE
);
4817 gsf_xml_out_start_element (state
->xml
, TABLE
"null-date");
4818 if (go_date_convention_base (workbook_date_conv (state
->wb
)) == 1900)
4819 /* As encouraged by the OpenFormula definition we "compensate" here. */
4820 gsf_xml_out_add_cstr_unchecked (state
->xml
, TABLE
"date-value", "1899-12-30");
4822 gsf_xml_out_add_cstr_unchecked (state
->xml
, TABLE
"date-value", "1904-1-1");
4823 gsf_xml_out_add_cstr_unchecked (state
->xml
, TABLE
"value-type", "date");
4824 gsf_xml_out_end_element (state
->xml
); /* </table:null-date> */
4825 gsf_xml_out_start_element (state
->xml
, TABLE
"iteration");
4826 go_xml_out_add_double (state
->xml
, TABLE
"maximum-difference",
4827 state
->wb
->iteration
.tolerance
);
4828 gsf_xml_out_add_cstr_unchecked (state
->xml
, TABLE
"status",
4829 state
->wb
->iteration
.enabled
? "enable" : "disable");
4830 gsf_xml_out_add_int (state
->xml
, TABLE
"steps", state
->wb
->iteration
.max_number
);
4831 gsf_xml_out_end_element (state
->xml
); /* </table:iteration> */
4832 gsf_xml_out_end_element (state
->xml
); /* </table:calculation-settings> */
4834 odf_print_spreadsheet_content_validations (state
);
4838 odf_write_named_expression (G_GNUC_UNUSED gpointer key
, GnmNamedExpr
*nexpr
,
4845 GnmExprTop
const *texpr
;
4848 g_return_if_fail (nexpr
!= NULL
);
4850 if (!expr_name_is_active (nexpr
))
4853 sheet
= nexpr
->pos
.sheet
;
4855 sheet
= workbook_sheet_by_index (state
->wb
, 0);
4857 name
= expr_name_name (nexpr
);
4858 is_range
= nexpr
->texpr
&& !expr_name_is_placeholder (nexpr
)
4859 && gnm_expr_top_is_rangeref (nexpr
->texpr
);
4862 gsf_xml_out_start_element (state
->xml
, TABLE
"named-range");
4863 gsf_xml_out_add_cstr (state
->xml
, TABLE
"name", name
);
4865 formula
= gnm_expr_top_as_string (nexpr
->texpr
,
4868 gsf_xml_out_add_cstr (state
->xml
, TABLE
"cell-range-address",
4869 odf_strip_brackets (formula
));
4872 gnm_cellref_init (&ref
, sheet
, nexpr
->pos
.eval
.col
,
4873 nexpr
->pos
.eval
.row
, FALSE
);
4874 texpr
= gnm_expr_top_new (gnm_expr_new_cellref (&ref
));
4875 formula
= gnm_expr_top_as_string (texpr
, &nexpr
->pos
, state
->conv
);
4876 gsf_xml_out_add_cstr (state
->xml
,
4877 TABLE
"base-cell-address",
4878 odf_strip_brackets (formula
));
4880 gnm_expr_top_unref (texpr
);
4883 // This would be the right thing to do per the spec, but
4884 // Excel ignores any name that has the attribute. LO does
4885 // not seem to write this.
4886 gsf_xml_out_add_cstr_unchecked
4887 (state
->xml
, TABLE
"range-usable-as",
4888 "print-range filter repeat-row repeat-column");
4891 if (nexpr
->pos
.sheet
!= NULL
&& state
->with_extension
4892 && (state
->odf_version
< 102))
4893 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"scope",
4894 nexpr
->pos
.sheet
->name_unquoted
);
4896 gsf_xml_out_end_element (state
->xml
); /* </table:named-range> */
4897 } else if (!expr_name_is_placeholder (nexpr
) && nexpr
->texpr
!= NULL
) {
4898 gsf_xml_out_start_element
4899 (state
->xml
, TABLE
"named-expression");
4900 gsf_xml_out_add_cstr (state
->xml
, TABLE
"name", name
);
4902 formula
= gnm_expr_top_as_string (nexpr
->texpr
,
4905 if (state
->odf_version
> 101) {
4906 char *eq_formula
= g_strdup_printf ("of:=%s", formula
);
4907 gsf_xml_out_add_cstr (state
->xml
, TABLE
"expression", eq_formula
);
4908 g_free (eq_formula
);
4910 gsf_xml_out_add_cstr (state
->xml
, TABLE
"expression", formula
);
4913 gnm_cellref_init (&ref
, sheet
, nexpr
->pos
.eval
.col
,
4914 nexpr
->pos
.eval
.row
, FALSE
);
4915 texpr
= gnm_expr_top_new (gnm_expr_new_cellref (&ref
));
4916 formula
= gnm_expr_top_as_string (texpr
, &nexpr
->pos
, state
->conv
);
4917 gsf_xml_out_add_cstr (state
->xml
,
4918 TABLE
"base-cell-address",
4919 odf_strip_brackets (formula
));
4921 gnm_expr_top_unref (texpr
);
4923 if (nexpr
->pos
.sheet
!= NULL
&& state
->with_extension
4924 && (state
->odf_version
< 102))
4925 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"scope",
4926 nexpr
->pos
.sheet
->name_unquoted
);
4928 gsf_xml_out_end_element (state
->xml
); /* </table:named-expression> */
4933 create_new_xml_child (G_GNUC_UNUSED GnmOOExport
*state
, GsfOutput
*child
)
4935 return g_object_new (GSF_ODF_OUT_TYPE
,
4937 "odf-version", state
->odf_version
,
4942 odf_write_content (GnmOOExport
*state
, GsfOutput
*child
)
4947 gboolean has_autofilters
= FALSE
;
4950 state
->xml
= create_new_xml_child (state
, child
);
4951 gsf_xml_out_set_doc_type (state
->xml
, "\n");
4952 gsf_xml_out_start_element (state
->xml
, OFFICE
"document-content");
4954 for (i
= 0 ; i
< (int)G_N_ELEMENTS (ns
) ; i
++)
4955 gsf_xml_out_add_cstr_unchecked (state
->xml
, ns
[i
].key
, ns
[i
].url
);
4956 gsf_xml_out_add_cstr_unchecked (state
->xml
, OFFICE
"version",
4957 state
->odf_version_string
);
4959 gsf_xml_out_simple_element (state
->xml
, OFFICE
"scripts", NULL
);
4961 gsf_xml_out_start_element (state
->xml
, OFFICE
"font-face-decls");
4962 gsf_xml_out_end_element (state
->xml
); /* </office:font-face-decls> */
4964 gsf_xml_out_start_element (state
->xml
, OFFICE
"automatic-styles");
4965 odf_write_table_styles (state
);
4966 odf_write_character_styles (state
);
4967 odf_write_cell_styles (state
);
4968 odf_write_column_styles (state
);
4969 odf_write_row_styles (state
);
4970 odf_write_sheet_object_styles (state
);
4971 gsf_xml_out_end_element (state
->xml
); /* </office:automatic-styles> */
4973 gsf_xml_out_start_element (state
->xml
, OFFICE
"body");
4974 gsf_xml_out_start_element (state
->xml
, OFFICE
"spreadsheet");
4976 odf_print_spreadsheet_content_prelude (state
);
4978 for (i
= 0; i
< workbook_sheet_count (state
->wb
); i
++) {
4979 Sheet
*sheet
= workbook_sheet_by_index (state
->wb
, i
);
4982 GSList
*l
, *graphs
, *images
;
4984 state
->sheet
= sheet
;
4986 graphs
= sheet_objects_get (sheet
, NULL
, GNM_SO_GRAPH_TYPE
);
4987 for (l
= graphs
; l
!= NULL
; l
= l
->next
)
4988 g_hash_table_insert (state
->graphs
, l
->data
,
4989 g_strdup_printf ("Graph%i", graph_n
++));
4990 g_slist_free (graphs
);
4992 images
= sheet_objects_get (sheet
, NULL
, GNM_SO_IMAGE_TYPE
);
4993 for (l
= images
; l
!= NULL
; l
= l
->next
)
4994 g_hash_table_insert (state
->images
, l
->data
,
4995 g_strdup_printf ("Image%i", image_n
++));
4996 g_slist_free (images
);
4998 gsf_xml_out_start_element (state
->xml
, TABLE
"table");
4999 gsf_xml_out_add_cstr (state
->xml
, TABLE
"name", sheet
->name_unquoted
);
5001 style_name
= table_style_name (state
, sheet
);
5002 gsf_xml_out_add_cstr (state
->xml
, TABLE
"style-name", style_name
);
5003 g_free (style_name
);
5005 odf_add_bool (state
->xml
, TABLE
"print", !sheet
->print_info
->do_not_print
);
5007 p_area
= sheet_get_nominal_printarea (sheet
);
5008 if (p_area
!= NULL
) {
5009 GnmValue
*v
= value_new_cellrange_r (sheet
, p_area
);
5010 GnmExprTop
const *texpr
;
5015 a
= &v
->v_range
.cell
.a
;
5016 b
= &v
->v_range
.cell
.b
;
5017 a
->col_relative
= b
->col_relative
= TRUE
;
5018 a
->row_relative
= b
->row_relative
= TRUE
;
5020 texpr
= gnm_expr_top_new_constant (v
);
5023 parse_pos_init_sheet (&pp
, sheet
);
5024 formula
= gnm_expr_top_as_string (texpr
,
5027 gnm_expr_top_unref (texpr
);
5028 gsf_xml_out_add_cstr (state
->xml
, TABLE
"print-ranges",
5029 odf_strip_brackets (formula
));
5033 /* writing shapes with absolute anchors */
5034 objects
= odf_sheet_objects_get (sheet
, NULL
);
5035 if (objects
!= NULL
) {
5036 gsf_xml_out_start_element (state
->xml
, TABLE
"shapes");
5037 odf_write_objects (state
, objects
);
5038 gsf_xml_out_end_element (state
->xml
);
5039 g_slist_free (objects
);
5042 odf_write_sheet_controls (state
);
5043 odf_write_sheet (state
);
5044 if (state
->odf_version
> 101 && sheet
->names
) {
5045 gsf_xml_out_start_element (state
->xml
, TABLE
"named-expressions");
5046 gnm_sheet_foreach_name (sheet
,
5047 (GHFunc
)&odf_write_named_expression
, state
);
5048 gsf_xml_out_end_element (state
->xml
); /* </table:named-expressions> */
5050 if (state
->with_extension
) {
5052 SheetView
const *sv
= sheet_get_view (sheet
, state
->wbv
);
5054 gsf_xml_out_start_element (state
->xml
, GNMSTYLE
"selections");
5055 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"cursor-col", sv
->edit_pos_real
.col
);
5056 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"cursor-row", sv
->edit_pos_real
.row
);
5058 /* Insert the selections in REVERSE order */
5059 copy
= g_slist_copy (sv
->selections
);
5060 ptr
= copy
= g_slist_reverse (copy
);
5061 for (; ptr
!= NULL
; ptr
= ptr
->next
) {
5062 GnmRange
const *r
= ptr
->data
;
5063 gsf_xml_out_start_element (state
->xml
, GNMSTYLE
"selection");
5064 odf_add_range (state
, r
);
5065 gsf_xml_out_end_element (state
->xml
); /* </gnm:selection> */
5067 g_slist_free (copy
);
5069 gsf_xml_out_end_element (state
->xml
); /* </gnm:selections> */
5072 gsf_xml_out_end_element (state
->xml
); /* </table:table> */
5074 has_autofilters
|= (sheet
->filters
!= NULL
);
5075 odf_update_progress (state
, state
->sheet_progress
);
5078 gsf_xml_out_start_element (state
->xml
, TABLE
"named-expressions");
5079 workbook_foreach_name
5080 (state
->wb
, (state
->odf_version
> 101),
5081 (GHFunc
)&odf_write_named_expression
, state
);
5082 gsf_xml_out_end_element (state
->xml
); /* </table:named-expressions> */
5084 if (has_autofilters
) {
5085 gsf_xml_out_start_element (state
->xml
, TABLE
"database-ranges");
5086 for (i
= 0; i
< workbook_sheet_count (state
->wb
); i
++) {
5087 Sheet
*sheet
= workbook_sheet_by_index (state
->wb
, i
);
5089 for (ptr
= sheet
->filters
; ptr
!= NULL
; ptr
= ptr
->next
)
5090 odf_write_autofilter (state
, ptr
->data
);
5093 gsf_xml_out_end_element (state
->xml
); /* </table:database-ranges> */
5096 gsf_xml_out_end_element (state
->xml
); /* </office:spreadsheet> */
5097 gsf_xml_out_end_element (state
->xml
); /* </office:body> */
5099 gsf_xml_out_end_element (state
->xml
); /* </office:document-content> */
5100 g_object_unref (state
->xml
);
5104 /*****************************************************************************/
5107 odf_write_xl_style (char const *xl
, char const *name
, GnmOOExport
*state
)
5112 format
= go_format_new_from_XL (xl
);
5113 go_format_output_to_odf (state
->xml
, format
, 0, name
,
5114 state
->with_extension
);
5115 go_format_unref (format
);
5119 odf_render_tab (GnmOOExport
*state
, G_GNUC_UNUSED
char const *args
)
5121 gsf_xml_out_simple_element (state
->xml
, TEXT
"sheet-name", NULL
);
5125 odf_render_page (GnmOOExport
*state
, G_GNUC_UNUSED
char const *args
)
5127 gsf_xml_out_start_element (state
->xml
, TEXT
"page-number");
5128 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"num-format", "1");
5129 /* odf_add_bool (state->xml, STYLE "num-letter-sync", TRUE); */
5130 gsf_xml_out_end_element (state
->xml
);
5134 odf_render_pages (GnmOOExport
*state
, G_GNUC_UNUSED
char const *args
)
5136 gsf_xml_out_start_element (state
->xml
, TEXT
"page-count");
5137 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"num-format", "1");
5138 /* odf_add_bool (state->xml, STYLE "num-letter-sync", TRUE); */
5139 gsf_xml_out_end_element (state
->xml
);
5143 odf_render_date (GnmOOExport
*state
, char const *args
)
5145 const char *style_name
= NULL
;
5148 style_name
= xl_find_format_xl (state
, args
);
5150 gsf_xml_out_start_element (state
->xml
, TEXT
"date");
5152 gsf_xml_out_add_cstr_unchecked
5153 (state
->xml
, STYLE
"data-style-name", style_name
);
5154 gsf_xml_out_end_element (state
->xml
);
5158 odf_render_date_to_xl (GnmOOExport
*state
, char const *args
)
5161 xl_find_format_xl (state
, args
);
5165 odf_render_time (GnmOOExport
*state
, char const *args
)
5167 const char *style_name
= NULL
;
5170 style_name
= xl_find_format_xl (state
, args
);
5172 gsf_xml_out_start_element (state
->xml
, TEXT
"time");
5174 gsf_xml_out_add_cstr_unchecked
5175 (state
->xml
, STYLE
"data-style-name", style_name
);
5176 gsf_xml_out_end_element (state
->xml
);
5179 odf_render_time_to_xl (GnmOOExport
*state
, char const *args
)
5182 xl_find_format_xl (state
, args
);
5186 odf_render_file (GnmOOExport
*state
, G_GNUC_UNUSED
char const *args
)
5188 gsf_xml_out_start_element (state
->xml
, TEXT
"file-name");
5189 gsf_xml_out_add_cstr_unchecked (state
->xml
, TEXT
"display", "name-and-extension");
5190 gsf_xml_out_end_element (state
->xml
);
5194 odf_render_path (GnmOOExport
*state
, G_GNUC_UNUSED
char const *args
)
5196 gsf_xml_out_start_element (state
->xml
, TEXT
"file-name");
5197 gsf_xml_out_add_cstr_unchecked (state
->xml
, TEXT
"display", "path");
5198 gsf_xml_out_end_element (state
->xml
);
5202 odf_render_cell (GnmOOExport
*state
, char const *args
)
5204 GnmExprTop
const *texpr
= NULL
;
5206 char *formula
, *full_formula
;
5207 GnmConventions
*convs
;
5210 convs
= gnm_xml_io_conventions ();
5211 parse_pos_init_sheet (&pp
, state
->sheet
);
5212 if (args
&& (g_str_has_prefix (args
, "rep|")))
5214 texpr
= gnm_expr_parse_str (args
, &pp
, GNM_EXPR_PARSE_DEFAULT
,
5216 gnm_conventions_unref (convs
);
5218 formula
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
5219 gnm_expr_top_unref (texpr
);
5220 full_formula
= g_strdup_printf ("of:=%s", formula
);
5224 gsf_xml_out_start_element (state
->xml
, TEXT
"expression");
5225 gsf_xml_out_add_cstr_unchecked (state
->xml
, TEXT
"display", "value");
5227 gsf_xml_out_add_cstr (state
->xml
, TEXT
"formula",
5229 g_free (full_formula
);
5232 gsf_xml_out_end_element (state
->xml
);
5237 void (*render
)(GnmOOExport
*state
, char const *args
);
5241 static render_ops_t odf_render_ops
[] = {
5242 { N_("tab"), odf_render_tab
, NULL
},
5243 { N_("page"), odf_render_page
, NULL
},
5244 { N_("pages"), odf_render_pages
, NULL
},
5245 { N_("date"), odf_render_date
, NULL
},
5246 { N_("time"), odf_render_time
, NULL
},
5247 { N_("file"), odf_render_file
, NULL
},
5248 { N_("path"), odf_render_path
, NULL
},
5249 { N_("cell"), odf_render_cell
, NULL
},
5250 { NULL
, NULL
, NULL
},
5253 static render_ops_t odf_render_ops_to_xl
[] = {
5254 { N_("tab"), NULL
, NULL
},
5255 { N_("page"), NULL
, NULL
},
5256 { N_("pages"), NULL
, NULL
},
5257 { N_("date"), odf_render_date_to_xl
, NULL
},
5258 { N_("time"), odf_render_time_to_xl
, NULL
},
5259 { N_("file"), NULL
, NULL
},
5260 { N_("path"), NULL
, NULL
},
5261 { N_("cell"), NULL
, NULL
},
5262 { NULL
, NULL
, NULL
},
5266 ods_render_ops_clear (render_ops_t
*render_ops
)
5270 for (i
= 0; render_ops
[i
].name
; i
++) {
5271 g_free (render_ops
[i
].name_trans
);
5272 render_ops
[i
].name_trans
= NULL
;
5277 * Renders an opcode. The opcodes can take an argument by adding trailing ':'
5278 * to the opcode and then a number format code
5281 odf_render_opcode (GnmOOExport
*state
, char /* non-const */ *opcode
,
5282 render_ops_t
*render_ops
)
5288 args
= g_utf8_strchr (opcode
, -1, ':');
5293 opcode_trans
= g_utf8_casefold (opcode
, -1);
5295 for (i
= 0; render_ops
[i
].name
; i
++) {
5296 if (render_ops
[i
].name_trans
== NULL
) {
5297 render_ops
[i
].name_trans
5298 = g_utf8_casefold (_(render_ops
[i
].name
), -1);
5301 if (((g_ascii_strcasecmp (render_ops
[i
].name
, opcode
) == 0) ||
5302 (g_utf8_collate (render_ops
[i
].name_trans
, opcode_trans
) == 0))
5303 && (render_ops
[i
].render
!= NULL
)){
5304 (*render_ops
[i
].render
)(state
, args
);
5307 g_free (opcode_trans
);
5311 odf_hf_region_to_xl_styles (GnmOOExport
*state
, char const *format
)
5318 for (p
= format
; *p
; p
= g_utf8_next_char(p
)) {
5319 if (*p
== '&' && p
[1] == '[') {
5324 while (*p
&& (*p
!= ']'))
5328 char *operation
= g_strndup (start
, p
- start
);
5329 odf_render_opcode (state
, operation
, odf_render_ops_to_xl
);
5338 * When we write the master styles we need certain data style. Here we are making
5339 * sure that those data styles were in fact written.
5342 odf_master_styles_to_xl_styles (GnmOOExport
*state
)
5346 for (i
= 0; i
< workbook_sheet_count (state
->wb
); i
++) {
5347 Sheet
const *sheet
= workbook_sheet_by_index (state
->wb
, i
);
5349 if (sheet
->print_info
->page_setup
== NULL
)
5350 gnm_print_info_load_defaults (sheet
->print_info
);
5352 if (sheet
->print_info
->header
!= NULL
) {
5353 odf_hf_region_to_xl_styles
5354 (state
, sheet
->print_info
->header
->left_format
);
5355 odf_hf_region_to_xl_styles
5356 (state
, sheet
->print_info
->header
->middle_format
);
5357 odf_hf_region_to_xl_styles
5358 (state
, sheet
->print_info
->header
->right_format
);
5360 if (sheet
->print_info
->footer
!= NULL
) {
5361 odf_hf_region_to_xl_styles
5362 (state
, sheet
->print_info
->footer
->left_format
);
5363 odf_hf_region_to_xl_styles
5364 (state
, sheet
->print_info
->footer
->middle_format
);
5365 odf_hf_region_to_xl_styles
5366 (state
, sheet
->print_info
->footer
->right_format
);
5372 odf_write_hf_region (GnmOOExport
*state
, char const *format
, char const *id
)
5381 gsf_xml_out_start_element (state
->xml
, id
);
5382 g_object_get (G_OBJECT (state
->xml
), "pretty-print", &pp
, NULL
);
5383 g_object_set (G_OBJECT (state
->xml
), "pretty-print", FALSE
, NULL
);
5384 gsf_xml_out_start_element (state
->xml
, TEXT
"p");
5386 text
= g_string_new (NULL
);
5387 for (p
= format
; *p
; p
= g_utf8_next_char(p
)) {
5388 if (*p
== '&' && p
[1] == '[') {
5393 while (*p
&& (*p
!= ']'))
5397 char *operation
= g_strndup (start
, p
- start
);
5398 if (text
->len
> 0) {
5399 gsf_xml_out_simple_element
5400 (state
->xml
, TEXT
"span", text
->str
);
5401 g_string_truncate (text
, 0);
5403 odf_render_opcode (state
, operation
, odf_render_ops
);
5408 g_string_append_len (text
, p
, g_utf8_next_char(p
) - p
);
5411 gsf_xml_out_simple_element (state
->xml
, TEXT
"span", text
->str
);
5412 g_string_free (text
, TRUE
);
5414 gsf_xml_out_end_element (state
->xml
); /* </text:p> */
5415 g_object_set (G_OBJECT (state
->xml
), "pretty-print", pp
, NULL
);
5416 gsf_xml_out_end_element (state
->xml
); /* id */
5420 odf_write_hf (GnmOOExport
*state
, GnmPrintInformation
*pi
, char const *id
, gboolean header
)
5422 GnmPrintHF
*hf
= header
? pi
->header
: pi
->footer
;
5425 GtkPageSetup
*gps
= gnm_print_info_get_page_setup (pi
);
5431 page_margin
= gtk_page_setup_get_top_margin (gps
, GTK_UNIT_POINTS
);
5432 hf_height
= pi
->edge_to_below_header
- page_margin
;
5434 page_margin
= gtk_page_setup_get_bottom_margin (gps
, GTK_UNIT_POINTS
);
5435 hf_height
= pi
->edge_to_above_footer
- page_margin
;
5438 gsf_xml_out_start_element (state
->xml
, id
);
5439 odf_add_bool (state
->xml
, STYLE
"display", hf_height
> 0.);
5441 odf_write_hf_region (state
, hf
->left_format
, STYLE
"region-left");
5442 odf_write_hf_region (state
, hf
->middle_format
, STYLE
"region-center");
5443 odf_write_hf_region (state
, hf
->right_format
, STYLE
"region-right");
5444 gsf_xml_out_end_element (state
->xml
); /* id */
5448 odf_store_data_style_for_style_with_name (GnmStyleRegion
*sr
, G_GNUC_UNUSED
char const *name
, GnmOOExport
*state
)
5450 GnmStyle
const *style
= sr
->style
;
5452 if (gnm_style_is_element_set (style
, MSTYLE_FORMAT
)) {
5453 GOFormat
const *format
= gnm_style_get_format(style
);
5454 if (format
!= NULL
&& !go_format_is_markup (format
) && !go_format_is_general (format
)) {
5455 xl_find_format (state
, format
);
5461 by_key_str (gpointer key_a
, G_GNUC_UNUSED gpointer val_a
,
5462 gpointer key_b
, G_GNUC_UNUSED gpointer val_b
,
5463 G_GNUC_UNUSED gpointer user
)
5465 return strcmp (key_a
, key_b
);
5469 by_value_str (G_GNUC_UNUSED gpointer key_a
, gpointer val_a
,
5470 G_GNUC_UNUSED gpointer key_b
, gpointer val_b
,
5471 G_GNUC_UNUSED gpointer user
)
5473 return strcmp (val_a
, val_b
);
5477 odf_write_office_styles (GnmOOExport
*state
)
5479 gsf_xml_out_start_element (state
->xml
, OFFICE
"styles");
5481 /* We need to make sure all the data styles for the named styles are included */
5482 g_hash_table_foreach (state
->named_cell_style_regions
, (GHFunc
) odf_store_data_style_for_style_with_name
, state
);
5484 gnm_hash_table_foreach_ordered
5486 (GHFunc
) odf_write_xl_style
,
5490 gnm_hash_table_foreach_ordered
5491 (state
->named_cell_style_regions
,
5492 (GHFunc
) odf_save_this_style_with_name
,
5496 gnm_hash_table_foreach_ordered
5498 (GHFunc
) odf_write_font_sizes
,
5502 gnm_hash_table_foreach_ordered
5503 (state
->text_colours
,
5504 (GHFunc
) odf_write_text_colours
,
5508 if (state
->default_style_region
->style
!= NULL
) {
5509 gsf_xml_out_start_element (state
->xml
, STYLE
"default-style");
5510 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"family", "table-cell");
5511 odf_write_style (state
, state
->default_style_region
->style
,
5512 &state
->default_style_region
->range
, TRUE
);
5513 gsf_xml_out_end_element (state
->xml
); /* </style:default-style */
5515 if (state
->column_default
!= NULL
) {
5516 gsf_xml_out_start_element (state
->xml
, STYLE
"default-style");
5517 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"family", "table-column");
5518 odf_write_col_style (state
, state
->column_default
);
5519 gsf_xml_out_end_element (state
->xml
); /* </style:default-style */
5521 if (state
->row_default
!= NULL
) {
5522 gsf_xml_out_start_element (state
->xml
, STYLE
"default-style");
5523 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"family", "table-row");
5524 odf_write_row_style (state
, state
->row_default
);
5525 gsf_xml_out_end_element (state
->xml
); /* </style:default-style */
5528 gnm_hash_table_foreach_ordered
5529 (state
->graph_dashes
,
5530 (GHFunc
) odf_write_dash_info
,
5534 gnm_hash_table_foreach_ordered
5535 (state
->graph_hatches
,
5536 (GHFunc
) odf_write_hatch_info
,
5540 gnm_hash_table_foreach_ordered
5541 (state
->graph_gradients
,
5542 (GHFunc
) odf_write_gradient_info
,
5546 gnm_hash_table_foreach_ordered
5547 (state
->graph_fill_images
,
5548 (GHFunc
) odf_write_fill_images_info
,
5552 gnm_hash_table_foreach_ordered
5553 (state
->arrow_markers
,
5554 (GHFunc
) odf_write_arrow_marker_info
,
5558 g_hash_table_remove_all (state
->graph_dashes
);
5559 g_hash_table_remove_all (state
->graph_hatches
);
5560 g_hash_table_remove_all (state
->graph_gradients
);
5561 g_hash_table_remove_all (state
->graph_fill_images
);
5562 g_hash_table_remove_all (state
->arrow_markers
);
5564 gsf_xml_out_end_element (state
->xml
); /* </office:styles> */
5568 odf_write_hf_style (GnmOOExport
*state
, GnmPrintInformation
*pi
, char const *id
, gboolean header
)
5570 GnmPrintHF
*hf
= header
? pi
->header
: pi
->footer
;
5573 GtkPageSetup
*gps
= gnm_print_info_get_page_setup (pi
);
5579 page_margin
= gtk_page_setup_get_top_margin (gps
, GTK_UNIT_POINTS
);
5580 hf_height
= pi
->edge_to_below_header
- page_margin
;
5582 page_margin
= gtk_page_setup_get_bottom_margin (gps
, GTK_UNIT_POINTS
);
5583 hf_height
= pi
->edge_to_above_footer
- page_margin
;
5586 gsf_xml_out_start_element (state
->xml
, id
);
5587 gsf_xml_out_start_element (state
->xml
, STYLE
"header-footer-properties");
5589 gsf_xml_out_add_cstr_unchecked (state
->xml
, FOSTYLE
"border", "none");
5590 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"shadow", "none");
5591 odf_add_pt (state
->xml
, FOSTYLE
"padding", 0.0);
5592 odf_add_pt (state
->xml
, FOSTYLE
"margin", 0.0);
5593 odf_add_pt (state
->xml
, FOSTYLE
"min-height", hf_height
);
5594 odf_add_pt (state
->xml
, SVG
"height", hf_height
);
5595 odf_add_bool (state
->xml
, STYLE
"dynamic-spacing", TRUE
);
5597 gsf_xml_out_end_element (state
->xml
); /* header-footer-properties */
5598 gsf_xml_out_end_element (state
->xml
); /* id */
5603 odf_write_page_layout (GnmOOExport
*state
, GnmPrintInformation
*pi
,
5606 static char const *centre_type
[] = {
5613 char *name
= page_layout_name (state
, pi
);
5614 GtkPageSetup
*gps
= gnm_print_info_get_page_setup (pi
);
5616 GtkPageOrientation orient
= gtk_page_setup_get_orientation (gps
);
5617 gboolean landscape
= !(orient
== GTK_PAGE_ORIENTATION_PORTRAIT
||
5618 orient
== GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT
);
5619 GString
*gstr
= g_string_new ("charts drawings objects");
5621 gsf_xml_out_start_element (state
->xml
, STYLE
"page-layout");
5622 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"name", name
);
5624 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"page-usage", "all");
5626 gsf_xml_out_start_element (state
->xml
, STYLE
"page-layout-properties");
5627 odf_add_pt (state
->xml
, FOSTYLE
"margin-top",
5628 gtk_page_setup_get_top_margin (gps
, GTK_UNIT_POINTS
));
5629 odf_add_pt (state
->xml
, FOSTYLE
"margin-bottom",
5630 gtk_page_setup_get_bottom_margin (gps
, GTK_UNIT_POINTS
));
5631 odf_add_pt (state
->xml
, FOSTYLE
"margin-left",
5632 gtk_page_setup_get_left_margin (gps
, GTK_UNIT_POINTS
));
5633 odf_add_pt (state
->xml
, FOSTYLE
"margin-right",
5634 gtk_page_setup_get_right_margin (gps
, GTK_UNIT_POINTS
));
5635 odf_add_pt (state
->xml
, FOSTYLE
"page-width",
5636 gtk_page_setup_get_paper_width (gps
, GTK_UNIT_POINTS
));
5637 odf_add_pt (state
->xml
, FOSTYLE
"page-height",
5638 gtk_page_setup_get_paper_height (gps
, GTK_UNIT_POINTS
));
5639 i
= (pi
->center_horizontally
? 1 : 0) | (pi
->center_vertically
? 2 : 0);
5640 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"table-centering",
5642 gsf_xml_out_add_cstr_unchecked
5643 (state
->xml
, STYLE
"print-page-order",
5644 pi
->print_across_then_down
? "ltr" : "ttb");
5645 gsf_xml_out_add_cstr_unchecked
5646 (state
->xml
, STYLE
"writing-mode",
5647 sheet
->text_is_rtl
? "rl-tb" : "lr-tb");
5648 gsf_xml_out_add_cstr_unchecked
5649 (state
->xml
, STYLE
"print-orientation",
5650 landscape
? "landscape" : "portrait");
5652 if (pi
->print_grid_lines
)
5653 g_string_append (gstr
, " grid");
5654 if (pi
->print_titles
)
5655 g_string_append (gstr
, " headers");
5656 if (pi
->comment_placement
!= GNM_PRINT_COMMENTS_NONE
)
5657 g_string_append (gstr
, " annotations");
5658 gsf_xml_out_add_cstr_unchecked
5659 (state
->xml
, STYLE
"print", gstr
->str
);
5661 switch (pi
->scaling
.type
) {
5662 case PRINT_SCALE_FIT_PAGES
: {
5663 int x
= pi
->scaling
.dim
.cols
;
5664 int y
= pi
->scaling
.dim
.rows
;
5665 if (state
->with_extension
) {
5666 /* LO uses style:scale-to-X and style:scale-to-Y but */
5667 /* these are not valid in the style: namespace */
5668 /* So to be understood by LO we would need to write */
5669 /* invalid ODF. They should be using one of their */
5670 /* extension namespace, but are not! */
5672 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"scale-to-X", x
);
5674 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"scale-to-Y", y
);
5676 /* ODF 1.2 only allows us to specify the total number of pages. */
5677 int x
= pi
->scaling
.dim
.cols
;
5678 int y
= pi
->scaling
.dim
.rows
;
5680 gsf_xml_out_add_int (state
->xml
, STYLE
"scale-to-pages", x
*y
);
5684 case PRINT_SCALE_PERCENTAGE
:
5685 odf_add_percent (state
->xml
, STYLE
"scale-to", pi
->scaling
.percentage
.x
/100);
5688 odf_add_percent (state
->xml
, STYLE
"scale-to", 1.);
5691 if (state
->with_extension
) {
5692 g_string_truncate (gstr
, 0);
5693 if (pi
->comment_placement
== GNM_PRINT_COMMENTS_AT_END
)
5694 g_string_append (gstr
, " annotations_at_end");
5695 if (pi
->print_black_and_white
)
5696 g_string_append (gstr
, " black_n_white");
5697 if (pi
->print_as_draft
)
5698 g_string_append (gstr
, " draft");
5699 if (pi
->print_even_if_only_styles
)
5700 g_string_append (gstr
, " print_even_if_only_styles");
5701 switch (pi
->error_display
) {
5702 case GNM_PRINT_ERRORS_AS_BLANK
:
5703 g_string_append (gstr
, " errors_as_blank");
5705 case GNM_PRINT_ERRORS_AS_DASHES
:
5706 g_string_append (gstr
, " errors_as_dashes");
5708 case GNM_PRINT_ERRORS_AS_NA
:
5709 g_string_append (gstr
, " errors_as_na");
5712 case GNM_PRINT_ERRORS_AS_DISPLAYED
:
5715 gsf_xml_out_add_cstr_unchecked
5716 (state
->xml
, GNMSTYLE
"style-print", gstr
->str
);
5719 g_string_free (gstr
, TRUE
);
5721 gsf_xml_out_end_element (state
->xml
); /* </style:page-layout-properties> */
5723 odf_write_hf_style (state
, pi
, STYLE
"header-style", TRUE
);
5724 odf_write_hf_style (state
, pi
, STYLE
"footer-style", FALSE
);
5727 gsf_xml_out_end_element (state
->xml
); /* </style:page-layout> */
5731 odf_write_automatic_styles (GnmOOExport
*state
)
5735 gsf_xml_out_start_element (state
->xml
, OFFICE
"automatic-styles");
5737 for (i
= 0; i
< workbook_sheet_count (state
->wb
); i
++) {
5738 Sheet
const *sheet
= workbook_sheet_by_index (state
->wb
, i
);
5739 odf_write_page_layout (state
, sheet
->print_info
, sheet
);
5742 gsf_xml_out_end_element (state
->xml
); /* </office:automatic-styles> */
5746 odf_write_master_styles (GnmOOExport
*state
)
5750 gsf_xml_out_start_element (state
->xml
, OFFICE
"master-styles");
5752 for (i
= 0; i
< workbook_sheet_count (state
->wb
); i
++) {
5753 Sheet
const *sheet
= workbook_sheet_by_index (state
->wb
, i
);
5754 char *mp_name
= table_master_page_style_name (state
, sheet
);
5755 char *name
= page_layout_name (state
, sheet
->print_info
);
5757 gsf_xml_out_start_element (state
->xml
, STYLE
"master-page");
5758 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"name", mp_name
);
5759 gsf_xml_out_add_cstr (state
->xml
, STYLE
"display-name", sheet
->name_unquoted
);
5760 gsf_xml_out_add_cstr_unchecked (state
->xml
, STYLE
"page-layout-name",
5763 odf_write_hf (state
, sheet
->print_info
, STYLE
"header", TRUE
);
5764 odf_write_hf (state
, sheet
->print_info
, STYLE
"footer", FALSE
);
5766 gsf_xml_out_end_element (state
->xml
); /* </master-page> */
5771 gsf_xml_out_end_element (state
->xml
); /* </master-styles> */
5775 odf_write_styles (GnmOOExport
*state
, GsfOutput
*child
)
5779 state
->xml
= create_new_xml_child (state
, child
);
5780 gsf_xml_out_start_element (state
->xml
, OFFICE
"document-styles");
5781 for (i
= 0 ; i
< (int)G_N_ELEMENTS (ns
) ; i
++)
5782 gsf_xml_out_add_cstr_unchecked (state
->xml
, ns
[i
].key
, ns
[i
].url
);
5783 gsf_xml_out_add_cstr_unchecked (state
->xml
, OFFICE
"version",
5784 state
->odf_version_string
);
5786 odf_master_styles_to_xl_styles (state
);
5788 odf_write_office_styles (state
);
5789 odf_write_automatic_styles (state
);
5790 odf_write_master_styles (state
);
5792 gsf_xml_out_end_element (state
->xml
); /* </office:document-styles> */
5794 g_object_unref (state
->xml
);
5798 /*****************************************************************************/
5801 odf_write_meta (GnmOOExport
*state
, GsfOutput
*child
)
5803 GsfXMLOut
*xml
= create_new_xml_child (state
, child
);
5804 GsfDocMetaData
*meta
= go_doc_get_meta_data (GO_DOC (state
->wb
));
5805 GValue
*val
= g_new0 (GValue
, 1);
5806 GsfDocProp
*prop
= gsf_doc_meta_data_steal (meta
, GSF_META_NAME_GENERATOR
);
5808 g_value_init (val
, G_TYPE_STRING
);
5809 g_value_set_string (val
, PACKAGE_NAME
"/" VERSION
);
5811 gsf_doc_meta_data_insert (meta
, g_strdup (GSF_META_NAME_GENERATOR
), val
);
5812 gsf_doc_meta_data_write_to_odf (meta
, xml
);
5813 gsf_doc_meta_data_remove (meta
,GSF_META_NAME_GENERATOR
);
5815 gsf_doc_meta_data_store (meta
, prop
);
5816 g_object_unref (xml
);
5820 odf_write_meta_graph (G_GNUC_UNUSED GnmOOExport
*state
, GsfOutput
*child
)
5822 GsfXMLOut
*xml
= create_new_xml_child (state
, child
);
5823 GsfDocMetaData
*meta
= gsf_doc_meta_data_new ();
5824 GValue
*val
= g_new0 (GValue
, 1);
5826 g_value_init (val
, G_TYPE_STRING
);
5827 g_value_set_string (val
, PACKAGE_NAME
"/" VERSION
);
5829 gsf_doc_meta_data_insert (meta
, g_strdup (GSF_META_NAME_GENERATOR
), val
);
5830 gsf_doc_meta_data_write_to_odf (meta
, xml
);
5832 g_object_unref (meta
);
5833 g_object_unref (xml
);
5835 /*****************************************************************************/
5838 odf_write_fill_images_info (GOImage
*image
, char const *name
, GnmOOExport
*state
)
5840 char const *display_name
= go_image_get_name (image
);
5841 char *href
= g_strdup_printf ("Pictures/%s.png", name
);
5843 gsf_xml_out_start_element (state
->xml
, DRAW
"fill-image");
5844 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"name", name
);
5845 gsf_xml_out_add_cstr (state
->xml
, DRAW
"display-name", display_name
);
5846 gsf_xml_out_add_cstr_unchecked (state
->xml
, XLINK
"type", "simple");
5847 gsf_xml_out_add_cstr_unchecked (state
->xml
, XLINK
"show", "embed");
5848 gsf_xml_out_add_cstr_unchecked (state
->xml
, XLINK
"actuate", "onLoad");
5849 gsf_xml_out_add_cstr (state
->xml
, XLINK
"href", href
);
5850 gsf_xml_out_end_element (state
->xml
); /* </draw:fill-image> */
5856 odf_write_arrow_marker_info (GOArrow
const *arrow
, char const *name
, GnmOOExport
*state
)
5858 gsf_xml_out_start_element (state
->xml
, DRAW
"marker");
5859 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"name", name
);
5861 if (state
->with_extension
) {
5862 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"arrow-type", arrow
->typ
);
5863 go_xml_out_add_double (state
->xml
, GNMSTYLE
"arrow-a", arrow
->a
);
5864 go_xml_out_add_double (state
->xml
, GNMSTYLE
"arrow-b", arrow
->b
);
5865 go_xml_out_add_double (state
->xml
, GNMSTYLE
"arrow-c", arrow
->c
);
5868 gsf_xml_out_add_cstr (state
->xml
, SVG
"viewBox", "0 0 20 30");
5869 gsf_xml_out_add_cstr (state
->xml
, SVG
"d", "m10 0-10 30h20z");
5871 gsf_xml_out_end_element (state
->xml
); /* </draw:marker> */
5875 odf_write_gradient_info (GOStyle
const *style
, char const *name
, GnmOOExport
*state
)
5878 char const *type
= "linear";
5885 {GO_GRADIENT_N_TO_S
,"linear", 180},
5886 {GO_GRADIENT_S_TO_N
, "linear", 0},
5887 {GO_GRADIENT_N_TO_S_MIRRORED
, "axial", 180},
5888 {GO_GRADIENT_S_TO_N_MIRRORED
, "axial", 0},
5889 {GO_GRADIENT_W_TO_E
, "linear", 270},
5890 {GO_GRADIENT_E_TO_W
, "linear", 90},
5891 {GO_GRADIENT_W_TO_E_MIRRORED
, "axial", 270},
5892 {GO_GRADIENT_E_TO_W_MIRRORED
, "axial", 90},
5893 {GO_GRADIENT_NW_TO_SE
, "linear", 225},
5894 {GO_GRADIENT_SE_TO_NW
, "linear", 45},
5895 {GO_GRADIENT_NW_TO_SE_MIRRORED
, "axial", 225},
5896 {GO_GRADIENT_SE_TO_NW_MIRRORED
, "axial", 45},
5897 {GO_GRADIENT_NE_TO_SW
, "linear", 135},
5898 {GO_GRADIENT_SW_TO_NE
, "linear", 315},
5899 {GO_GRADIENT_SW_TO_NE_MIRRORED
, "axial", 315},
5900 {GO_GRADIENT_NE_TO_SW_MIRRORED
, "axial", 135},
5904 gsf_xml_out_start_element (state
->xml
, DRAW
"gradient");
5905 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"name", name
);
5907 color
= odf_go_color_to_string (style
->fill
.pattern
.back
);
5908 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"start-color", color
);
5911 if (style
->fill
.gradient
.brightness
>= 0.0 && state
->with_extension
)
5912 go_xml_out_add_double (state
->xml
, GNMSTYLE
"brightness",
5913 style
->fill
.gradient
.brightness
);
5915 color
= odf_go_color_to_string (style
->fill
.pattern
.fore
);
5916 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"end-color", color
);
5919 for (i
= 0; i
< (int)G_N_ELEMENTS (gradients
); i
++) {
5920 if (gradients
[i
].dir
== style
->fill
.gradient
.dir
) {
5921 type
= gradients
[i
].type
;
5922 angle
= gradients
[i
].angle
;
5926 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"style", type
);
5927 gsf_xml_out_add_int (state
->xml
, DRAW
"angle", angle
);
5929 gsf_xml_out_end_element (state
->xml
); /* </draw:gradient> */
5933 odf_write_hatch_info (GOPattern
*pattern
, char const *name
, GnmOOExport
*state
)
5941 {GO_PATTERN_GREY75
, "double", 0, 1.0},
5942 {GO_PATTERN_GREY50
, "double", 0, 2.0},
5943 {GO_PATTERN_GREY25
, "double", 0, 3.0},
5944 {GO_PATTERN_GREY125
, "double", 0, 4.0},
5945 {GO_PATTERN_GREY625
, "double", 0, 5.0},
5946 {GO_PATTERN_HORIZ
, "single", 0, 2.0},
5947 {GO_PATTERN_VERT
, "single", 90, 2.0},
5948 {GO_PATTERN_REV_DIAG
, "single", -45, 2.0},
5949 {GO_PATTERN_DIAG
, "single", 45, 2.0},
5950 {GO_PATTERN_DIAG_CROSS
, "double", 45, 2.0},
5951 {GO_PATTERN_THICK_DIAG_CROSS
, "double", 45, 1.0},
5952 {GO_PATTERN_THIN_HORIZ
, "single", 0, 3.0},
5953 {GO_PATTERN_THIN_VERT
, "single", 90, 3.0},
5954 {GO_PATTERN_THIN_REV_DIAG
, "single", -45, 3.0},
5955 {GO_PATTERN_THIN_DIAG
, "single", 45, 3.0},
5956 {GO_PATTERN_THIN_HORIZ_CROSS
, "double", 0, 3.0},
5957 {GO_PATTERN_THIN_DIAG_CROSS
, "double", 45, 3.0},
5958 {GO_PATTERN_SMALL_CIRCLES
, "triple", 0, 2.0},
5959 {GO_PATTERN_SEMI_CIRCLES
, "triple", 45, 2.0},
5960 {GO_PATTERN_THATCH
, "triple", 90, 2.0},
5961 {GO_PATTERN_LARGE_CIRCLES
, "triple", 0, 3.0},
5962 {GO_PATTERN_BRICKS
, "triple", 45, 3.0},
5963 {GO_PATTERN_MAX
, "single", 0, 2.0}
5965 char *color
= odf_go_color_to_string (pattern
->fore
);
5968 gsf_xml_out_start_element (state
->xml
, DRAW
"hatch");
5969 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"name", name
);
5970 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"display-name", name
);
5971 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"color", color
);
5974 for (i
= 0; info
[i
].type
!= GO_PATTERN_MAX
; i
++)
5975 if (info
[i
].type
== pattern
->pattern
)
5978 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"style",
5980 odf_add_angle (state
->xml
, DRAW
"rotation", info
[i
].angle
);
5981 odf_add_pt (state
->xml
, DRAW
"distance", info
[i
].distance
);
5983 gsf_xml_out_end_element (state
->xml
); /* </draw:hatch> */
5987 odf_write_dash_info (char const *name
, gpointer data
, GnmOOExport
*state
)
5989 GOLineDashType type
= GPOINTER_TO_INT (data
);
5990 GOLineDashSequence
*lds
;
5992 gboolean
new = (state
->odf_version
> 101);
5994 gsf_xml_out_start_element (state
->xml
, DRAW
"stroke-dash");
5995 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"name", name
);
5996 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"display-name",
5997 go_line_dash_as_label (type
));
5998 gsf_xml_out_add_cstr_unchecked (state
->xml
, DRAW
"style", "rect");
6000 scale
= new ? 1 : 0.5;
6002 lds
= go_line_dash_get_sequence (type
, scale
);
6004 double dot_1
= lds
->dash
[0];
6009 odf_add_percent (state
->xml
, DRAW
"distance",
6010 (lds
->n_dash
> 1) ? lds
->dash
[1] : 1.);
6012 odf_add_pt (state
->xml
, DRAW
"distance",
6013 (lds
->n_dash
> 1) ? lds
->dash
[1] : 1.);
6015 for (; lds
->n_dash
> i
&& lds
->dash
[i
] == dot_1
; i
+= 2);
6016 gsf_xml_out_add_int (state
->xml
, DRAW
"dots1", n_1
);
6018 dot_1
= scale
* 0.2;
6020 odf_add_percent (state
->xml
, DRAW
"dots1-length", dot_1
);
6022 odf_add_pt (state
->xml
, DRAW
"dots1-length", dot_1
);
6023 if (lds
->n_dash
> i
) {
6024 dot_1
= lds
->dash
[i
];
6026 for (i
+= 2; lds
->n_dash
> i
6027 && lds
->dash
[i
] == dot_1
; i
+= 2);
6028 gsf_xml_out_add_int (state
->xml
, DRAW
"dots2", n_1
);
6030 dot_1
= scale
* 0.2;
6032 odf_add_percent (state
->xml
, DRAW
"dots2-length",
6035 odf_add_pt (state
->xml
, DRAW
"dots2-length",
6040 gsf_xml_out_end_element (state
->xml
); /* </draw:stroke-dash> */
6042 go_line_dash_sequence_free (lds
);
6046 odf_write_graph_styles (GnmOOExport
*state
, GsfOutput
*child
)
6050 state
->xml
= create_new_xml_child (state
, child
);
6051 gsf_xml_out_start_element (state
->xml
, OFFICE
"document-styles");
6052 for (i
= 0 ; i
< (int)G_N_ELEMENTS (ns
) ; i
++)
6053 gsf_xml_out_add_cstr_unchecked (state
->xml
, ns
[i
].key
, ns
[i
].url
);
6054 gsf_xml_out_add_cstr_unchecked (state
->xml
, OFFICE
"version",
6055 state
->odf_version_string
);
6056 gsf_xml_out_start_element (state
->xml
, OFFICE
"styles");
6058 gnm_hash_table_foreach_ordered
6059 (state
->graph_dashes
,
6060 (GHFunc
) odf_write_dash_info
,
6064 gnm_hash_table_foreach_ordered
6065 (state
->graph_hatches
,
6066 (GHFunc
) odf_write_hatch_info
,
6070 gnm_hash_table_foreach_ordered
6071 (state
->graph_gradients
,
6072 (GHFunc
) odf_write_gradient_info
,
6076 gnm_hash_table_foreach_ordered
6077 (state
->graph_fill_images
,
6078 (GHFunc
) odf_write_fill_images_info
,
6082 gnm_hash_table_foreach_ordered
6084 (GHFunc
) odf_write_xl_style
,
6088 gsf_xml_out_end_element (state
->xml
); /* </office:styles> */
6089 gsf_xml_out_end_element (state
->xml
); /* </office:document-styles> */
6091 g_object_unref (state
->xml
);
6095 /*****************************************************************************/
6098 odf_write_gnm_settings (GnmOOExport
*state
)
6100 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item-set");
6101 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", GNMSTYLE
"settings");
6102 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6103 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", GNMSTYLE
"has_foreign");
6104 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "boolean");
6105 odf_add_bool (state
->xml
, NULL
, state
->with_extension
);
6106 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6108 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6109 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", GNMSTYLE
"active-sheet");
6110 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "string");
6111 gsf_xml_out_add_cstr (state
->xml
, NULL
,
6112 (wb_view_cur_sheet (state
->wbv
))->name_unquoted
);
6113 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6115 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6116 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", GNMSTYLE
"geometry-width");
6117 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6118 gsf_xml_out_add_int (state
->xml
, NULL
,
6119 state
->wbv
->preferred_width
);
6120 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6122 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6123 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", GNMSTYLE
"geometry-height");
6124 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6125 gsf_xml_out_add_int (state
->xml
, NULL
,
6126 state
->wbv
->preferred_height
);
6127 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6129 gsf_xml_out_end_element (state
->xml
); /* </config:config-item-set> */
6133 odf_write_ooo_settings (GnmOOExport
*state
)
6137 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item-set");
6138 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", OOO
"view-settings");
6139 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item-map-indexed");
6140 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "Views");
6141 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item-map-entry");
6142 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6143 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "ViewId");
6144 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "string");
6145 gsf_xml_out_add_cstr (state
->xml
, NULL
, "View1");
6146 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6147 gsf_xml_out_start_element (state
->xml
,
6148 CONFIG
"config-item-map-named");
6149 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name",
6152 sheets
= workbook_sheets (state
->wb
);
6153 for (l
= sheets
; l
!= NULL
; l
= l
->next
) {
6154 Sheet
*sheet
= l
->data
;
6155 SheetView
*sv
= sheet_get_view (sheet
, state
->wbv
);
6156 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item-map-entry");
6157 gsf_xml_out_add_cstr (state
->xml
, CONFIG
"name", sheet
->name_unquoted
);
6158 if (state
->odf_version
< 103 && sheet
->tab_color
!= NULL
6159 && !sheet
->tab_color
->is_auto
) {
6160 /* Not used by LO 3.3.3 and later */
6161 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6162 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "TabColor");
6163 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6164 gsf_xml_out_add_int (state
->xml
, NULL
, sheet
->tab_color
->go_color
>> 8);
6165 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6167 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6168 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "CursorPositionX");
6169 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6170 gsf_xml_out_add_int (state
->xml
, NULL
, sv
->edit_pos
.col
);
6171 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6172 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6173 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "CursorPositionY");
6174 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6175 gsf_xml_out_add_int (state
->xml
, NULL
, sv
->edit_pos
.row
);
6176 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6178 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6179 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "ZoomValue");
6180 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6181 gsf_xml_out_add_int (state
->xml
, NULL
, (int) gnm_floor (sheet
->last_zoom_factor_used
* 100. + 0.5));
6182 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6184 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6185 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "ShowGrid");
6186 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "boolean");
6187 odf_add_bool (state
->xml
, NULL
, !sheet
->hide_grid
);
6188 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6190 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6191 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "HasColumnRowHeaders");
6192 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "boolean");
6193 odf_add_bool (state
->xml
, NULL
,
6194 (!sheet
->hide_col_header
) || !sheet
->hide_row_header
);
6195 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6197 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6198 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "ShowZeroValues");
6199 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "boolean");
6200 odf_add_bool (state
->xml
, NULL
, !sheet
->hide_zero
);
6201 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6203 if (sv_is_frozen (sv
)) {
6204 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6205 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "HorizontalSplitMode");
6206 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "short");
6207 gsf_xml_out_add_int (state
->xml
, NULL
, 2);
6208 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6209 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6210 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "VerticalSplitMode");
6211 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "short");
6212 gsf_xml_out_add_int (state
->xml
, NULL
, 2);
6213 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6214 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6215 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "HorizontalSplitPosition");
6216 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6217 gsf_xml_out_add_int (state
->xml
, NULL
, sv
->unfrozen_top_left
.col
);
6218 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6219 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6220 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "VerticalSplitPosition");
6221 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6222 gsf_xml_out_add_int (state
->xml
, NULL
, sv
->unfrozen_top_left
.row
);
6223 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6224 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6225 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "PositionLeft");
6226 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6227 gsf_xml_out_add_int (state
->xml
, NULL
, 0);
6228 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6229 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6230 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "PositionRight");
6231 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6232 gsf_xml_out_add_int (state
->xml
, NULL
, sv
->initial_top_left
.col
);
6233 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6235 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6236 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "PositionLeft");
6237 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6238 gsf_xml_out_add_int (state
->xml
, NULL
, sv
->initial_top_left
.col
);
6239 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6240 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6241 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "PositionRight");
6242 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6243 gsf_xml_out_add_int (state
->xml
, NULL
, 0);
6244 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6246 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6247 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "PositionTop");
6248 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6249 gsf_xml_out_add_int (state
->xml
, NULL
, 0);
6250 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6251 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6252 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "PositionBottom");
6253 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "int");
6254 gsf_xml_out_add_int (state
->xml
, NULL
, sv
->initial_top_left
.row
);
6255 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6257 gsf_xml_out_end_element (state
->xml
); /* </config:config-item-map-entry> */
6259 g_slist_free (sheets
);
6261 gsf_xml_out_end_element (state
->xml
); /* </config:config-item-map-named> */
6263 gsf_xml_out_start_element (state
->xml
, CONFIG
"config-item");
6264 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"name", "ActiveTable");
6265 gsf_xml_out_add_cstr_unchecked (state
->xml
, CONFIG
"type", "string");
6266 gsf_xml_out_add_cstr (state
->xml
, NULL
,
6267 (wb_view_cur_sheet (state
->wbv
))->name_unquoted
);
6268 gsf_xml_out_end_element (state
->xml
); /* </config:config-item> */
6270 gsf_xml_out_end_element (state
->xml
); /* </config:config-item-map-entry> */
6271 gsf_xml_out_end_element (state
->xml
); /* </config:config-item-map-indexed> */
6272 gsf_xml_out_end_element (state
->xml
); /* </config:config-item-set> */
6276 odf_write_settings (GnmOOExport
*state
, GsfOutput
*child
)
6280 state
->xml
= create_new_xml_child (state
, child
);
6281 gsf_xml_out_start_element (state
->xml
, OFFICE
"document-settings");
6282 for (i
= 0 ; i
< (int)G_N_ELEMENTS (ns
) ; i
++)
6283 gsf_xml_out_add_cstr_unchecked (state
->xml
, ns
[i
].key
, ns
[i
].url
);
6284 gsf_xml_out_add_cstr_unchecked (state
->xml
, OFFICE
"version",
6285 state
->odf_version_string
);
6287 gsf_xml_out_start_element (state
->xml
, OFFICE
"settings");
6289 odf_write_gnm_settings (state
);
6290 odf_write_ooo_settings (state
);
6292 gsf_xml_out_end_element (state
->xml
); /* </office:settings> */
6293 gsf_xml_out_end_element (state
->xml
); /* </office:document-settings> */
6294 g_object_unref (state
->xml
);
6298 /**********************************************************************************/
6301 odf_file_entry (GsfXMLOut
*out
, char const *type
, char const *name
)
6303 gsf_xml_out_start_element (out
, MANIFEST
"file-entry");
6304 gsf_xml_out_add_cstr (out
, MANIFEST
"media-type", type
);
6305 gsf_xml_out_add_cstr (out
, MANIFEST
"full-path", name
);
6306 gsf_xml_out_end_element (out
); /* </manifest:file-entry> */
6310 odf_write_graph_manifest (SheetObject
*graph
, char const *name
, GnmOOExport
*state
)
6312 guint i
, n
= odf_n_charts (state
, graph
);
6314 for (i
= 0; i
< n
; i
++) {
6315 char *realname
= g_strdup_printf ("%s-%i", name
, i
);
6316 char *fullname
= g_strdup_printf ("%s/", realname
);
6317 odf_file_entry (state
->xml
, "application/vnd.oasis.opendocument.chart", fullname
);
6319 fullname
= g_strdup_printf ("%s/content.xml", realname
);
6320 odf_file_entry (state
->xml
, "text/xml", fullname
);
6322 fullname
= g_strdup_printf ("%s/meta.xml", realname
);
6323 odf_file_entry (state
->xml
, "text/xml", fullname
);
6325 fullname
= g_strdup_printf ("%s/styles.xml", realname
);
6326 odf_file_entry (state
->xml
, "text/xml", fullname
);
6328 fullname
= g_strdup_printf ("Pictures/%s", realname
);
6329 odf_file_entry (state
->xml
, "image/svg+xml", fullname
);
6331 fullname
= g_strdup_printf ("Pictures/%s.png", realname
);
6332 odf_file_entry (state
->xml
, "image/png", fullname
);
6339 odf_write_image_manifest (SheetObject
*image
, char const *name
, GnmOOExport
*state
)
6345 g_object_get (G_OBJECT (image
), "image-type", &image_type
, NULL
);
6346 mime
= g_strdup_printf ("image/%s", image_type
);
6347 fullname
= g_strdup_printf ("Pictures/%s.%s", name
, image_type
);
6348 odf_file_entry (state
->xml
, mime
, fullname
);
6352 g_free (image_type
);
6357 odf_write_manifest (GnmOOExport
*state
, GsfOutput
*child
)
6359 GsfXMLOut
*xml
= create_new_xml_child (state
, child
);
6362 gsf_xml_out_set_doc_type (xml
, "\n");
6363 gsf_xml_out_start_element (xml
, MANIFEST
"manifest");
6364 gsf_xml_out_add_cstr_unchecked (xml
, "xmlns:manifest",
6365 "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0");
6366 if (state
->odf_version
> 101)
6367 gsf_xml_out_add_cstr_unchecked (xml
, MANIFEST
"version",
6368 state
->odf_version_string
);
6369 odf_file_entry (xml
, "application/vnd.oasis.opendocument.spreadsheet" ,"/");
6370 odf_file_entry (xml
, "text/xml", "content.xml");
6371 odf_file_entry (xml
, "text/xml", "styles.xml");
6372 odf_file_entry (xml
, "text/xml", "meta.xml");
6373 odf_file_entry (xml
, "text/xml", "settings.xml");
6376 gnm_hash_table_foreach_ordered
6378 (GHFunc
) odf_write_graph_manifest
,
6381 gnm_hash_table_foreach_ordered
6383 (GHFunc
) odf_write_image_manifest
,
6387 for (l
= state
->fill_image_files
; l
!= NULL
; l
= l
->next
)
6388 odf_file_entry (xml
, "image/png", l
->data
);
6389 g_slist_free_full (state
->fill_image_files
, g_free
);
6390 state
->fill_image_files
= NULL
;
6394 gsf_xml_out_end_element (xml
); /* </manifest:manifest> */
6395 g_object_unref (xml
);
6398 /**********************************************************************************/
6421 odf_write_label_cell_address (GnmOOExport
*state
, GOData
const *dat
)
6423 GnmExprTop
const *texpr
;
6428 texpr
= gnm_go_data_get_expr (dat
);
6429 if (texpr
!= NULL
) {
6432 parse_pos_init (&pp
, WORKBOOK (state
->wb
), NULL
, 0,0 );
6433 str
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
6434 if (gnm_expr_top_is_rangeref (texpr
))
6435 gsf_xml_out_add_cstr (state
->xml
, CHART
"label-cell-address",
6436 odf_strip_brackets (str
));
6437 else if (state
->with_extension
)
6438 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"label-cell-expression",
6439 odf_strip_brackets (str
));
6445 odf_write_series_lines (GnmOOExport
*state
, GogObject
const *series
)
6447 GogObjectRole
const *role
= gog_object_find_role_by_name (series
, "Series lines");
6450 GSList
*serieslines
= gog_object_get_children (series
, role
);
6451 if (serieslines
!= NULL
&& serieslines
->data
!= NULL
) {
6452 GogObject
*obj
= GOG_OBJECT (serieslines
->data
);
6453 char *style
= odf_get_gog_style_name_from_obj (state
, obj
);
6455 gsf_xml_out_start_element (state
->xml
, GNMSTYLE
"serieslines");
6456 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", style
);
6457 gsf_xml_out_end_element (state
->xml
); /* </gnm:serieslines> */
6461 g_slist_free (serieslines
);
6466 odf_write_drop_line (GnmOOExport
*state
, GogObject
const *series
, char const *drop
)
6468 GogObjectRole
const *role
= gog_object_find_role_by_name (series
, drop
);
6471 GSList
*drops
= gog_object_get_children
6473 if (drops
!= NULL
&& drops
->data
!= NULL
) {
6474 GogObject
*obj
= GOG_OBJECT (drops
->data
);
6475 char *style
= odf_get_gog_style_name_from_obj (state
, obj
);
6477 gsf_xml_out_start_element (state
->xml
, GNMSTYLE
"droplines");
6478 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", style
);
6479 gsf_xml_out_end_element (state
->xml
); /* </gnm:droplines> */
6483 g_slist_free (drops
);
6488 odf_write_data_element_range (GnmOOExport
*state
, GnmParsePos
*pp
, GnmExprTop
const *texpr
,
6489 char const *attribute
, char const *gnm_attribute
)
6493 switch (GNM_EXPR_GET_OPER (texpr
->expr
)) {
6494 case GNM_EXPR_OP_CONSTANT
:
6495 if (VALUE_IS_CELLRANGE (texpr
->expr
->constant
.value
)) {
6496 str
= gnm_expr_top_as_string (texpr
, pp
, state
->conv
);
6497 gsf_xml_out_add_cstr (state
->xml
, attribute
,
6498 odf_strip_brackets (str
));
6503 case GNM_EXPR_OP_SET
: {
6505 gboolean success
= TRUE
;
6506 GnmExpr
const *expr
= texpr
->expr
;
6507 GString
*gstr
= g_string_new (NULL
);
6508 for (i
= 0; i
< expr
->set
.argc
; i
++) {
6509 GnmExpr
const *expr_arg
= expr
->set
.argv
[i
];
6510 if ((GNM_EXPR_GET_OPER (expr_arg
) == GNM_EXPR_OP_CONSTANT
&&
6511 VALUE_IS_CELLRANGE (expr_arg
->constant
.value
)) ||
6512 (GNM_EXPR_GET_OPER (expr_arg
) == GNM_EXPR_OP_CELLREF
)) {
6513 char *str
= gnm_expr_as_string (expr_arg
, pp
, state
->conv
);
6515 g_string_append_c (gstr
, ' ');
6516 g_string_append (gstr
, odf_strip_brackets (str
));
6522 gsf_xml_out_add_cstr (state
->xml
, attribute
, gstr
->str
);
6523 g_string_free (gstr
, TRUE
);
6526 g_string_free (gstr
, TRUE
);
6529 case GNM_EXPR_OP_CELLREF
:
6530 str
= gnm_expr_top_as_string (texpr
, pp
, state
->conv
);
6531 gsf_xml_out_add_cstr (state
->xml
, attribute
,
6532 odf_strip_brackets (str
));
6539 /* ODF does not support anything but Gnumeric does */
6540 if (NULL
!= gnm_attribute
) {
6541 str
= gnm_expr_top_as_string (texpr
, pp
, state
->conv
);
6542 gsf_xml_out_add_cstr (state
->xml
, gnm_attribute
, str
);
6548 odf_write_data_element (GnmOOExport
*state
, GOData
const *data
, GnmParsePos
*pp
,
6549 char const *element
, char const *attribute
, char const *gnm_attribute
)
6551 GnmExprTop
const *texpr
= gnm_go_data_get_expr (data
);
6553 if (NULL
!= texpr
) {
6554 char *str
= gnm_expr_top_as_string (texpr
, pp
, state
->conv
);
6555 gsf_xml_out_start_element (state
->xml
, element
);
6556 odf_write_data_element_range (state
, pp
, texpr
, attribute
, gnm_attribute
);
6564 odf_write_data_attribute (GnmOOExport
*state
, GOData
const *data
, GnmParsePos
*pp
,
6565 char const *attribute
, char const *c_attribute
)
6567 GnmExprTop
const *texpr
= gnm_go_data_get_expr (data
);
6569 if (NULL
!= texpr
) {
6570 if (state
->with_extension
) {
6571 char *str
= gnm_expr_top_as_string (texpr
, pp
,
6573 gsf_xml_out_add_cstr (state
->xml
, attribute
,
6574 odf_strip_brackets (str
));
6577 if (NULL
!= c_attribute
) {
6578 GnmValue
const *v
= gnm_expr_top_get_constant (texpr
);
6579 if (NULL
!= v
&& VALUE_IS_STRING (v
))
6580 gsf_xml_out_add_cstr (state
->xml
, c_attribute
,
6581 value_peek_string (v
));
6582 if (NULL
!= v
&& VALUE_IS_FLOAT (v
))
6583 go_xml_out_add_double (state
->xml
, c_attribute
,
6584 value_get_as_float (v
));
6590 cmp_data_points (GObject
*a
, GObject
*b
)
6592 int ind_a
= 0, ind_b
= 0;
6594 g_object_get (a
, "index", &ind_a
, NULL
);
6595 g_object_get (b
, "index", &ind_b
, NULL
);
6599 else if (ind_a
> ind_b
)
6605 odf_write_regression_curve (GnmOOExport
*state
, GogObjectRole
const *role
, GogObject
const *series
, GnmParsePos
*pp
)
6607 GSList
*l
, *regressions
= gog_object_get_children
6611 for (l
= regressions
; l
!= NULL
&& l
->data
!= NULL
; l
= l
->next
) {
6613 GogObject
const *regression
= l
->data
;
6614 gboolean is_reg_curve
= GOG_IS_REG_CURVE (regression
);
6615 GogObject
const *equation
6617 gog_object_get_child_by_name (regression
, "Equation"):
6619 str
= odf_get_gog_style_name_from_obj
6620 (state
, GOG_OBJECT (regression
));
6621 gsf_xml_out_start_element
6622 (state
->xml
, CHART
"regression-curve");
6623 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", str
);
6626 if (is_reg_curve
&& state
->with_extension
) {
6627 /* Upper and lower bounds */
6628 bd
= gog_dataset_get_dim (GOG_DATASET (regression
), 0);
6630 odf_write_data_attribute
6631 (state
, bd
, pp
, GNMSTYLE
"lower-bound", NULL
);
6632 bd
= gog_dataset_get_dim (GOG_DATASET (regression
), 1);
6634 odf_write_data_attribute
6635 (state
, bd
, pp
, GNMSTYLE
"upper-bound", NULL
);
6637 if (equation
!= NULL
) {
6638 char const *eq_element
, *eq_automatic
, *eq_display
, *eq_r
;
6639 if (state
->odf_version
> 101) {
6640 eq_element
= CHART
"equation";
6641 eq_automatic
= CHART
"automatic-content";
6642 eq_display
= CHART
"display-equation";
6643 eq_r
= CHART
"display-r-square";
6645 eq_element
= GNMSTYLE
"equation";
6646 eq_automatic
= GNMSTYLE
"automatic-content";
6647 eq_display
= GNMSTYLE
"display-equation";
6648 eq_r
= GNMSTYLE
"display-r-square";
6650 gsf_xml_out_start_element
6651 (state
->xml
, eq_element
);
6652 odf_add_bool (state
->xml
, eq_automatic
, TRUE
);
6653 odf_write_plot_style_bool (state
->xml
, equation
,
6654 "show-eq", eq_display
);
6655 odf_write_plot_style_bool (state
->xml
, equation
,
6657 str
= odf_get_gog_style_name_from_obj
6658 (state
, GOG_OBJECT (equation
));
6659 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", str
);
6661 odf_write_gog_position (state
, equation
);
6662 odf_write_gog_position_pts (state
, equation
);
6663 gsf_xml_out_end_element (state
->xml
); /* </chart:equation> */
6666 gsf_xml_out_end_element (state
->xml
); /* </chart:regression-curve> */
6668 g_slist_free (regressions
);
6672 odf_write_attached_axis (GnmOOExport
*state
, char const * const axis_role
, int id
)
6674 GString
*str
= g_string_new (NULL
);
6675 g_string_append_printf (str
, "%s-%i", axis_role
, id
);
6676 gsf_xml_out_add_cstr_unchecked (state
->xml
, CHART
"attached-axis", str
->str
);
6677 g_string_free (str
, TRUE
);
6681 odf_write_attached_axes (GnmOOExport
*state
, GogObject
*series
)
6683 GogPlot
*plot
= gog_series_get_plot (GOG_SERIES (series
));
6684 GogAxis
*axis
= gog_plot_get_axis (plot
, GOG_AXIS_X
);
6687 id
= (NULL
!= axis
) ? gog_object_get_id (GOG_OBJECT (axis
)) : 0;
6689 odf_write_attached_axis (state
, "X-Axis", id
);
6691 axis
= gog_plot_get_axis (plot
, GOG_AXIS_Z
);
6692 id
= (NULL
!= axis
) ? gog_object_get_id (GOG_OBJECT (axis
)) : 0;
6694 odf_write_attached_axis (state
, "Z-Axis", id
);
6696 axis
= gog_plot_get_axis (plot
, GOG_AXIS_Y
);
6698 id
= gog_object_get_id (GOG_OBJECT (axis
));
6699 odf_write_attached_axis (state
, "Y-Axis", id
);
6707 odf_write_standard_series (GnmOOExport
*state
, GSList
const *series
, char const* class)
6711 parse_pos_init (&pp
, WORKBOOK (state
->wb
), NULL
, 0,0 );
6713 for (i
= 1; NULL
!= series
; series
= series
->next
, i
++) {
6714 GOData
const *dat
= gog_dataset_get_dim (GOG_DATASET (series
->data
), GOG_MS_DIM_VALUES
);
6715 if (NULL
!= dat
&& odf_write_data_element (state
, dat
, &pp
, CHART
"series",
6716 CHART
"values-cell-range-address",
6717 GNMSTYLE
"values-cell-range-expression")) {
6718 GogObjectRole
const *role
;
6720 GOData
const *cat
= gog_dataset_get_dim (GOG_DATASET (series
->data
),
6722 char *str
= odf_get_gog_style_name_from_obj (state
, series
->data
);
6724 odf_write_attached_axes (state
, series
->data
);
6726 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", str
);
6729 odf_write_label_cell_address
6730 (state
, gog_series_get_name (GOG_SERIES (series
->data
)));
6733 gsf_xml_out_add_cstr_unchecked (state
->xml
, CHART
"class", class);
6735 if (NULL
!= cat
&& odf_write_data_element (state
, cat
, &pp
, CHART
"domain",
6736 TABLE
"cell-range-address",
6737 GNMSTYLE
"cell-range-expression"))
6738 gsf_xml_out_end_element (state
->xml
); /* </chart:domain> */
6740 role
= gog_object_find_role_by_name
6741 (GOG_OBJECT (series
->data
), "Regression curve");
6743 odf_write_regression_curve (state
, role
, GOG_OBJECT (series
->data
), &pp
);
6745 role
= gog_object_find_role_by_name
6746 (GOG_OBJECT (series
->data
), "Trend line");
6748 odf_write_regression_curve (state
, role
, GOG_OBJECT (series
->data
), &pp
);
6750 /* Write data points if any */
6752 role
= gog_object_find_role_by_name
6753 (GOG_OBJECT (series
->data
), "Point");
6754 if (role
!= NULL
&& NULL
!= (points
= gog_object_get_children
6755 (GOG_OBJECT (series
->data
), role
))) {
6756 int index
= 0, next_index
= 0;
6758 points
= g_slist_sort (points
, (GCompareFunc
) cmp_data_points
);
6760 for (l
= points
; l
!= NULL
; l
= l
->next
) {
6761 char *style
= odf_get_gog_style_name_from_obj
6762 (state
, GOG_OBJECT (l
->data
));
6763 g_object_get (G_OBJECT (l
->data
), "index", &index
, NULL
);
6764 if (index
> next_index
) {
6765 gsf_xml_out_start_element (state
->xml
,
6766 CHART
"data-point");
6767 gsf_xml_out_add_int (state
->xml
, CHART
"repeated",
6768 index
- next_index
);
6769 gsf_xml_out_end_element (state
->xml
);
6770 /* CHART "data-point" */
6772 gsf_xml_out_start_element (state
->xml
,
6773 CHART
"data-point");
6774 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", style
);
6775 gsf_xml_out_end_element (state
->xml
);
6776 /* CHART "data-point" */
6778 next_index
= index
+ 1;
6780 g_slist_free (points
);
6783 if (state
->with_extension
) {
6784 odf_write_drop_line (state
, GOG_OBJECT (series
->data
),
6785 "Horizontal drop lines");
6786 odf_write_drop_line (state
, GOG_OBJECT (series
->data
),
6787 "Vertical drop lines");
6788 odf_write_drop_line (state
, GOG_OBJECT (series
->data
),
6790 odf_write_series_lines (state
, GOG_OBJECT (series
->data
));
6792 gsf_xml_out_end_element (state
->xml
); /* </chart:series> */
6798 odf_write_box_series (GnmOOExport
*state
, GSList
const *series
, char const* class)
6802 parse_pos_init (&pp
, WORKBOOK (state
->wb
), NULL
, 0,0 );
6804 for (i
= 1; NULL
!= series
; series
= series
->next
, i
++) {
6805 GOData
const *dat
= gog_dataset_get_dim (GOG_DATASET (series
->data
), 0);
6808 GnmExprTop
const *texpr
= gnm_go_data_get_expr (dat
);
6809 if (NULL
!= texpr
) {
6810 char *str
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
6812 gsf_xml_out_start_element (state
->xml
, CHART
"series");
6813 gsf_xml_out_add_cstr (state
->xml
, CHART
"values-cell-range-address",
6814 odf_strip_brackets (str
));
6816 str
= odf_get_gog_style_name_from_obj (state
, series
->data
);
6817 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", str
);
6819 odf_write_label_cell_address
6820 (state
, gog_series_get_name (GOG_SERIES (series
->data
)));
6822 gsf_xml_out_add_cstr_unchecked (state
->xml
, CHART
"class", class);
6823 gsf_xml_out_end_element (state
->xml
); /* </chart:series> */
6830 odf_write_gantt_series (GnmOOExport
*state
, GSList
const *series
, char const* class)
6834 parse_pos_init (&pp
, WORKBOOK (state
->wb
), NULL
, 0,0 );
6836 for (i
= 1; NULL
!= series
; series
= series
->next
, i
++) {
6837 GOData
const *dat
= gog_dataset_get_dim (GOG_DATASET (series
->data
), GOG_MS_DIM_VALUES
);
6839 GnmExprTop
const *texpr
= gnm_go_data_get_expr (dat
);
6840 if (NULL
!= texpr
) {
6841 char *str
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
6842 GOData
const *cat
= gog_dataset_get_dim (GOG_DATASET (series
->data
), GOG_MS_DIM_LABELS
);
6843 gsf_xml_out_start_element (state
->xml
, CHART
"series");
6844 gsf_xml_out_add_cstr (state
->xml
, CHART
"values-cell-range-address",
6845 odf_strip_brackets (str
));
6847 str
= odf_get_gog_style_name_from_obj (state
, series
->data
);
6848 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", str
);
6852 gsf_xml_out_add_cstr_unchecked (state
->xml
, CHART
"class", class);
6855 texpr
= gnm_go_data_get_expr (cat
);
6856 if (NULL
!= texpr
) {
6857 str
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
6858 gsf_xml_out_start_element (state
->xml
, CHART
"domain");
6859 gsf_xml_out_add_cstr (state
->xml
, TABLE
"cell-range-address",
6860 odf_strip_brackets (str
));
6861 gsf_xml_out_end_element (state
->xml
); /* </chart:domain> */
6865 gsf_xml_out_end_element (state
->xml
); /* </chart:series> */
6868 dat
= gog_dataset_get_dim (GOG_DATASET (series
->data
), GOG_MS_DIM_CATEGORIES
);
6870 GnmExprTop
const *texpr
= gnm_go_data_get_expr (dat
);
6871 if (NULL
!= texpr
) {
6872 char *str
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
6873 gsf_xml_out_start_element (state
->xml
, CHART
"series");
6874 gsf_xml_out_add_cstr (state
->xml
, CHART
"values-cell-range-address",
6875 odf_strip_brackets (str
));
6877 str
= odf_get_gog_style_name_from_obj (state
, series
->data
);
6878 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", str
);
6880 gsf_xml_out_end_element (state
->xml
); /* </chart:series> */
6887 odf_write_bubble_series (GnmOOExport
*state
, GSList
const *orig_series
, char const* class)
6891 GSList
const *series
;
6892 parse_pos_init (&pp
, WORKBOOK (state
->wb
), NULL
, 0,0 );
6894 for (series
= orig_series
, i
= 1; NULL
!= series
; series
= series
->next
, i
++) {
6895 GOData
const *dat
= gog_dataset_get_dim (GOG_DATASET (series
->data
), 2);
6898 GnmExprTop
const *texpr
= gnm_go_data_get_expr (dat
);
6899 if (NULL
!= texpr
) {
6900 char *str
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
6901 gsf_xml_out_start_element (state
->xml
, CHART
"series");
6902 gsf_xml_out_add_cstr (state
->xml
, CHART
"values-cell-range-address",
6903 odf_strip_brackets (str
));
6905 str
= odf_get_gog_style_name_from_obj (state
, series
->data
);
6906 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", str
);
6910 gsf_xml_out_add_cstr_unchecked (state
->xml
, CHART
"class", class);
6912 for (j
= 1; j
>= 0; j
--) {
6913 dat
= gog_dataset_get_dim (GOG_DATASET (series
->data
), j
);
6915 texpr
= gnm_go_data_get_expr (dat
);
6916 if (NULL
!= texpr
) {
6917 str
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
6918 gsf_xml_out_start_element (state
->xml
, CHART
"domain");
6919 gsf_xml_out_add_cstr (state
->xml
, TABLE
"cell-range-address",
6920 odf_strip_brackets (str
));
6921 gsf_xml_out_end_element (state
->xml
); /* </chart:domain> */
6927 gsf_xml_out_end_element (state
->xml
); /* </chart:series> */
6933 odf_write_min_max_series (GnmOOExport
*state
, GSList
const *orig_series
, char const* class)
6937 GSList
const *series
;
6938 parse_pos_init (&pp
, WORKBOOK (state
->wb
), NULL
, 0,0 );
6940 for (j
= 1; j
< 3; j
++) {
6941 gsf_xml_out_start_element (state
->xml
, CHART
"series");
6942 for (series
= orig_series
, i
= 1; NULL
!= series
; series
= series
->next
, i
++) {
6943 GOData
const *dat
= gog_dataset_get_dim (GOG_DATASET (series
->data
), j
);
6946 GnmExprTop
const *texpr
= gnm_go_data_get_expr (dat
);
6947 if (NULL
!= texpr
) {
6948 char *str
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
6949 gsf_xml_out_add_cstr (state
->xml
, CHART
"values-cell-range-address",
6950 odf_strip_brackets (str
));
6952 str
= odf_get_gog_style_name_from_obj (state
, series
->data
);
6953 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", str
);
6959 gsf_xml_out_add_cstr_unchecked (state
->xml
, CHART
"class", class);
6961 gsf_xml_out_end_element (state
->xml
); /* </chart:series> */
6967 odf_write_fill_type (GnmOOExport
*state
,
6968 GogObject
const *series
)
6970 gchar
*type_str
= NULL
;
6972 if (state
->with_extension
&& gnm_object_has_readable_prop (series
, "fill-type", G_TYPE_STRING
, &type_str
)) {
6973 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"fill-type", type_str
);
6979 odf_write_interpolation_attribute (GnmOOExport
*state
,
6980 G_GNUC_UNUSED GOStyle
const *style
,
6981 GogObject
const *series
)
6983 gchar
*interpolation
= NULL
;
6985 g_object_get (G_OBJECT (series
),
6986 "interpolation", &interpolation
,
6989 if (interpolation
!= NULL
) {
6990 if (0 == strcmp (interpolation
, "linear"))
6991 gsf_xml_out_add_cstr
6992 (state
->xml
, CHART
"interpolation", "none");
6993 else if (0 == strcmp (interpolation
, "spline"))
6994 gsf_xml_out_add_cstr
6995 (state
->xml
, CHART
"interpolation",
6997 else if (0 == strcmp (interpolation
, "odf-spline"))
6998 /* this one is really compatible with ODF */
6999 gsf_xml_out_add_cstr
7000 (state
->xml
, CHART
"interpolation",
7002 else if (state
->with_extension
) {
7003 char *tag
= g_strdup_printf ("gnm:%s", interpolation
);
7004 gsf_xml_out_add_cstr
7005 (state
->xml
, GNMSTYLE
"interpolation", tag
);
7008 gsf_xml_out_add_cstr
7009 (state
->xml
, CHART
"interpolation", "none");
7012 if (state
->with_extension
) {
7013 gboolean skip_invalid
= TRUE
;
7015 if (!gnm_object_has_readable_prop (series
,
7016 "interpolation-skip-invalid",
7020 odf_add_bool (state
->xml
,
7021 GNMSTYLE
"interpolation-skip-invalid",
7025 g_free (interpolation
);
7029 odf_scale_initial_angle (gnm_float angle
)
7034 angle
= gnm_fake_round (angle
);
7036 return (((int) angle
) % 360);
7040 odf_write_plot_style (GnmOOExport
*state
, GogObject
const *plot
)
7042 gchar
const *plot_type
= G_OBJECT_TYPE_NAME (plot
);
7043 gchar
*type_str
= NULL
;
7044 double default_separation
= 0.;
7047 odf_add_bool (state
->xml
, CHART
"auto-size", TRUE
);
7049 if (gnm_object_has_readable_prop (plot
, "type",
7050 G_TYPE_STRING
, &type_str
)) {
7051 if (type_str
!= NULL
) {
7052 odf_add_bool (state
->xml
, CHART
"stacked",
7053 (0== strcmp (type_str
, "stacked")));
7054 odf_add_bool (state
->xml
, CHART
"percentage",
7055 (0== strcmp (type_str
, "as_percentage")));
7060 if (gnm_object_has_readable_prop (plot
, "default-separation",
7061 G_TYPE_DOUBLE
, &default_separation
)) {
7062 if (0 == strcmp ("GogRingPlot", plot_type
)) {
7063 if (state
->with_extension
)
7064 odf_add_percent (state
->xml
,
7065 GNMSTYLE
"default-separation",
7066 default_separation
);
7068 gsf_xml_out_add_int (state
->xml
,
7070 (default_separation
* 100. + 0.5));
7073 /* Note: horizontal refers to the bars and vertical to the x-axis */
7074 odf_write_plot_style_bool (state
->xml
, plot
,
7075 "horizontal", CHART
"vertical");
7077 odf_write_plot_style_bool (state
->xml
, plot
,
7078 "vertical", CHART
"vertical");
7080 odf_write_plot_style_from_bool
7082 "default-style-has-markers", CHART
"symbol-type",
7083 "automatic", "none");
7085 odf_write_plot_style_int (state
->xml
, plot
,
7086 "gap-percentage", CHART
"gap-width");
7088 odf_write_plot_style_int (state
->xml
, plot
,
7089 "overlap-percentage", CHART
"overlap");
7091 odf_write_plot_style_double_percent (state
->xml
, plot
,
7095 if (gnm_object_has_readable_prop (plot
, "initial-angle", G_TYPE_DOUBLE
, &d
))
7096 gsf_xml_out_add_int (state
->xml
, CHART
"angle-offset", odf_scale_initial_angle (d
));
7098 if (gnm_object_has_readable_prop (plot
, "interpolation",
7100 odf_write_interpolation_attribute (state
, NULL
, plot
);
7102 if (0 == strcmp ( "GogXYZSurfacePlot", plot_type
) ||
7103 0 == strcmp ( "GogSurfacePlot", plot_type
) ||
7104 0 == strcmp ( "XLSurfacePlot", plot_type
))
7105 odf_add_bool (state
->xml
, CHART
"three-dimensional", TRUE
);
7107 odf_add_bool (state
->xml
, CHART
"three-dimensional", FALSE
);
7109 odf_write_plot_style_bool (state
->xml
, plot
, "default-style-has-lines", CHART
"lines");
7111 if (state
->with_extension
) {
7112 if (0 == strcmp ( "XLSurfacePlot", plot_type
))
7113 odf_add_bool (state
->xml
, GNMSTYLE
"multi-series",
7115 odf_write_plot_style_bool (state
->xml
, plot
,
7116 "outliers", GNMSTYLE
"outliers");
7118 odf_write_plot_style_double (state
->xml
, plot
,
7119 "radius-ratio", GNMSTYLE
7122 odf_write_plot_style_bool (state
->xml
, plot
,
7123 "vary-style-by-element",
7124 GNMSTYLE
"vary-style-by-element");
7126 odf_write_plot_style_bool (state
->xml
, plot
,
7128 GNMSTYLE
"show-negatives");
7135 odf_get_marker (GOMarkerShape m
)
7141 {{GO_MARKER_NONE
, "none"},
7142 {GO_MARKER_SQUARE
, "square"},
7143 {GO_MARKER_DIAMOND
,"diamond"},
7144 {GO_MARKER_TRIANGLE_DOWN
,"arrow-down"},
7145 {GO_MARKER_TRIANGLE_UP
,"arrow-up"},
7146 {GO_MARKER_TRIANGLE_RIGHT
,"arrow-right"},
7147 {GO_MARKER_TRIANGLE_LEFT
,"arrow-left"},
7148 {GO_MARKER_CIRCLE
,"circle"},
7150 {GO_MARKER_CROSS
,"plus"},
7151 {GO_MARKER_ASTERISK
,"asterisk"},
7152 {GO_MARKER_BAR
,"horizontal-bar"},
7153 {GO_MARKER_HALF_BAR
,"vertical-bar"}, /* Not ODF */
7154 {GO_MARKER_BUTTERFLY
,"bow-tie"},
7155 {GO_MARKER_HOURGLASS
,"hourglass"},
7156 {GO_MARKER_LEFT_HALF_BAR
,"star"},/* Not ODF */
7157 {GO_MARKER_MAX
, "star"}, /* not used by us */
7158 {GO_MARKER_MAX
+ 1, "vertical-bar"},/* not used by us */
7162 for (i
= 0; marks
[i
].str
!= NULL
; i
++)
7163 if (marks
[i
].m
== m
)
7164 return marks
[i
].str
;
7169 odf_add_expr (GnmOOExport
*state
, GogObject
const *obj
, gint dim
,
7170 char const *attribute
, char const *c_attribute
)
7174 parse_pos_init (&pp
, WORKBOOK (state
->wb
), NULL
, 0,0 );
7175 bd
= gog_dataset_get_dim (GOG_DATASET (obj
), dim
);
7177 odf_write_data_attribute
7178 (state
, bd
, &pp
, attribute
, c_attribute
);
7182 odf_write_axis_position (GnmOOExport
*state
, G_GNUC_UNUSED GOStyle
const *style
,
7183 GogObject
const *axis
)
7185 char *pos_str
= NULL
;
7186 if (gnm_object_has_readable_prop (axis
, "pos-str",
7187 G_TYPE_STRING
, &pos_str
)) {
7188 if (0 == strcmp (pos_str
, "low"))
7189 gsf_xml_out_add_cstr (state
->xml
, CHART
"axis-position", "start");
7190 else if (0 == strcmp (pos_str
, "high"))
7191 gsf_xml_out_add_cstr (state
->xml
, CHART
"axis-position", "end");
7192 else if (0 == strcmp (pos_str
, "cross")) {
7195 parse_pos_init (&pp
, WORKBOOK (state
->wb
), NULL
, 0, 0);
7196 bd
= gog_dataset_get_dim (GOG_DATASET (axis
), 4);
7198 odf_write_data_attribute (state
, bd
, &pp
,
7199 GNMSTYLE
"axis-position-expression",
7200 CHART
"axis-position");
7202 gsf_xml_out_add_cstr (state
->xml
, CHART
"axis-position", "0");
7209 odf_write_axisline_style (GnmOOExport
*state
, GOStyle
const *style
,
7210 GogObject
const *axis
)
7212 odf_write_axis_position (state
, style
, axis
);
7214 odf_write_plot_style_bool
7215 (state
->xml
, axis
, "major-tick-in", CHART
"tick-marks-major-inner");
7216 odf_write_plot_style_bool
7217 (state
->xml
, axis
, "major-tick-out", CHART
"tick-marks-major-outer");
7218 odf_write_plot_style_bool
7219 (state
->xml
, axis
, "minor-tick-in", CHART
"tick-marks-minor-inner");
7220 odf_write_plot_style_bool
7221 (state
->xml
, axis
, "minor-tick-out", CHART
"tick-marks-minor-outer");
7222 odf_write_plot_style_bool
7223 (state
->xml
, axis
, "major-tick-labeled", CHART
"display-label");
7227 odf_write_axis_style (GnmOOExport
*state
, GOStyle
const *style
,
7228 GogObject
const *axis
)
7231 GOData
const *interval
;
7232 gboolean user_defined
;
7233 gboolean logarithmic
= FALSE
;
7234 char *map_name_str
= NULL
;
7236 if (gnm_object_has_readable_prop (axis
, "map-name",
7237 G_TYPE_STRING
, &map_name_str
)) {
7238 logarithmic
= (0 != strcmp (map_name_str
, "Linear"));
7239 odf_add_bool (state
->xml
, CHART
"logarithmic", logarithmic
);
7240 g_free (map_name_str
);
7243 tmp
= gog_axis_get_entry
7244 (GOG_AXIS (axis
), GOG_AXIS_ELEM_MIN
, &user_defined
);
7246 go_xml_out_add_double (state
->xml
, CHART
"minimum", tmp
);
7247 if (state
->with_extension
)
7248 odf_add_expr (state
, GOG_OBJECT (axis
), 0,
7249 GNMSTYLE
"chart-minimum-expression", NULL
);
7251 tmp
= gog_axis_get_entry
7252 (GOG_AXIS (axis
), GOG_AXIS_ELEM_MAX
, &user_defined
);
7254 go_xml_out_add_double (state
->xml
, CHART
"maximum", tmp
);
7255 if (state
->with_extension
)
7256 odf_add_expr (state
, GOG_OBJECT (axis
), 1,
7257 GNMSTYLE
"chart-maximum-expression", NULL
);
7260 interval
= gog_dataset_get_dim (GOG_DATASET(axis
),2);
7261 if (interval
!= NULL
) {
7262 GnmExprTop
const *texpr
7263 = gnm_go_data_get_expr (interval
);
7264 if (texpr
!= NULL
&&
7265 GNM_EXPR_GET_OPER (texpr
->expr
) == GNM_EXPR_OP_CONSTANT
) {
7266 double val
= value_get_as_float (texpr
->expr
->constant
.value
);
7267 go_xml_out_add_double (state
->xml
, CHART
"interval-major", val
);
7269 interval
= gog_dataset_get_dim (GOG_DATASET(axis
),3);
7270 if (interval
!= NULL
) {
7271 texpr
= gnm_go_data_get_expr (interval
);
7272 if (texpr
!= NULL
&&
7273 GNM_EXPR_GET_OPER (texpr
->expr
) == GNM_EXPR_OP_CONSTANT
) {
7274 double val_minor
= value_get_as_float
7275 (texpr
->expr
->constant
.value
);
7276 if (val_minor
> 0) {
7278 val_minor
= gnm_floor(val_minor
+ 1.5);
7280 val_minor
= gnm_floor(val
/val_minor
+ 0.5);
7281 gsf_xml_out_add_float
7282 (state
->xml
, CHART
"interval-minor-divisor",
7289 if (state
->odf_version
> 101)
7290 odf_write_plot_style_bool
7292 "invert-axis", CHART
"reverse-direction");
7293 else if (state
->with_extension
)
7294 odf_write_plot_style_bool
7296 "invert-axis", GNMSTYLE
"reverse-direction");
7298 odf_write_axisline_style (state
, style
, axis
);
7302 odf_write_generic_axis_style (GnmOOExport
*state
, char const *style_label
)
7304 odf_start_style (state
->xml
, style_label
, "chart");
7305 gsf_xml_out_start_element (state
->xml
, STYLE
"chart-properties");
7307 gsf_xml_out_add_cstr (state
->xml
, CHART
"axis-position", "start");
7308 odf_add_bool (state
->xml
, CHART
"display-label", TRUE
);
7310 if (state
->odf_version
> 101)
7311 odf_add_bool (state
->xml
, CHART
"reverse-direction", TRUE
);
7312 gsf_xml_out_end_element (state
->xml
); /* </style:chart-properties> */
7313 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
7317 odf_write_one_axis_grid (GnmOOExport
*state
, GogObject
const *axis
,
7318 char const *role
, char const *class)
7320 GogObject
const *grid
;
7322 grid
= gog_object_get_child_by_name (axis
, role
);
7324 char *style
= odf_get_gog_style_name_from_obj (state
, GOG_OBJECT (grid
));
7326 gsf_xml_out_start_element (state
->xml
, CHART
"grid");
7327 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", style
);
7328 gsf_xml_out_add_cstr (state
->xml
, CHART
"class", class);
7329 gsf_xml_out_end_element (state
->xml
); /* </chart:grid> */
7336 odf_write_axis_grid (GnmOOExport
*state
, GogObject
const *axis
)
7338 g_return_if_fail (axis
!= NULL
);
7339 odf_write_one_axis_grid (state
, axis
, "MajorGrid", "major");
7340 odf_write_one_axis_grid (state
, axis
, "MinorGrid", "minor");
7344 odf_write_axislines (GnmOOExport
*state
, GogObject
const *axis
)
7346 g_return_if_fail (axis
!= NULL
);
7348 if (state
->with_extension
) {
7349 GogObjectRole
const *role
;
7350 role
= gog_object_find_role_by_name (axis
, "AxisLine");
7352 GSList
*l
, *lines
= gog_object_get_children (axis
, role
);
7354 while (l
!= NULL
&& l
->data
!= NULL
) {
7355 char *name
= odf_get_gog_style_name_from_obj (state
, GOG_OBJECT (l
->data
));
7356 gsf_xml_out_start_element (state
->xml
, GNMSTYLE
"axisline");
7358 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", name
);
7359 gsf_xml_out_end_element (state
->xml
); /* </gnm:axisline> */
7363 g_slist_free (lines
);
7370 odf_write_title (GnmOOExport
*state
, GogObject
const *title
,
7371 char const *id
, gboolean allow_content
)
7373 if (title
!= NULL
&& id
!= NULL
) {
7374 GOData
const *dat
= gog_dataset_get_dim (GOG_DATASET(title
),0);
7377 GnmExprTop
const *texpr
= gnm_go_data_get_expr (dat
);
7378 if (texpr
!= NULL
) {
7385 g_object_get (G_OBJECT (state
->xml
), "pretty-print", &pp
, NULL
);
7387 gsf_xml_out_start_element (state
->xml
, id
);
7389 odf_write_gog_position (state
, title
);
7390 odf_write_gog_position_pts (state
, title
);
7392 name
= odf_get_gog_style_name_from_obj (state
, title
);
7395 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name",
7400 parse_pos_init (&ppos
, WORKBOOK (state
->wb
), NULL
, 0,0 );
7401 formula
= gnm_expr_top_as_string (texpr
, &ppos
, state
->conv
);
7403 if (gnm_expr_top_is_rangeref (texpr
)) {
7404 char *f
= odf_strip_brackets (formula
);
7405 gsf_xml_out_add_cstr (state
->xml
,
7406 TABLE
"cell-range", f
);
7407 } else if (allow_content
&&
7408 (v
= gnm_expr_top_get_constant (texpr
)) &&
7409 VALUE_IS_STRING (v
)) {
7410 gboolean white_written
= TRUE
;
7413 g_object_set (G_OBJECT (state
->xml
), "pretty-print", FALSE
, NULL
);
7414 gsf_xml_out_start_element (state
->xml
, TEXT
"p");
7415 str
= value_peek_string (v
);
7416 if (GOG_IS_TEXT (title
) &&
7417 (text
= GOG_TEXT (title
))->allow_markup
) {
7418 PangoAttrList
*attr_list
= NULL
;
7419 char *text_clean
= NULL
;
7420 if (pango_parse_markup (str
, -1, 0,
7422 &text_clean
, NULL
, NULL
)) {
7423 odf_new_markup (state
, attr_list
, text_clean
);
7424 g_free (text_clean
);
7425 pango_attr_list_unref (attr_list
);
7427 odf_add_chars (state
, str
,strlen (str
),
7430 odf_add_chars (state
, str
,strlen (str
),
7432 gsf_xml_out_end_element (state
->xml
); /* </text:p> */
7433 g_object_set (G_OBJECT (state
->xml
), "pretty-print", pp
, NULL
);
7435 gboolean white_written
= TRUE
;
7436 if (state
->with_extension
)
7437 gsf_xml_out_add_cstr (state
->xml
,
7438 GNMSTYLE
"expression",
7440 if (allow_content
) {
7441 g_object_set (G_OBJECT (state
->xml
), "pretty-print", FALSE
, NULL
);
7442 gsf_xml_out_start_element
7443 (state
->xml
, TEXT
"p");
7444 odf_add_chars (state
, formula
,
7447 gsf_xml_out_end_element (state
->xml
);
7449 g_object_set (G_OBJECT (state
->xml
), "pretty-print", pp
, NULL
);
7452 gsf_xml_out_end_element (state
->xml
); /* </chart:title> */
7460 odf_write_label (GnmOOExport
*state
, GogObject
const *axis
)
7462 GSList
*labels
= gog_object_get_children
7463 (axis
, gog_object_find_role_by_name (axis
, "Label"));
7465 if (labels
!= NULL
) {
7466 GogObject
const *label
= NULL
;
7468 label
= labels
->data
;
7469 odf_write_title (state
, label
, CHART
"title", TRUE
);
7470 g_slist_free (labels
);
7477 odf_match_gradient (GOStyle
const *old
, GOStyle
const *new)
7481 if (old
->fill
.gradient
.brightness
!= new->fill
.gradient
.brightness
)
7484 if (old
->fill
.gradient
.brightness
>= 0.)
7485 result
= (old
->fill
.gradient
.brightness
== new->fill
.gradient
.brightness
);
7487 result
= (old
->fill
.pattern
.fore
== new->fill
.pattern
.fore
);
7489 return (result
&& (old
->fill
.gradient
.dir
== new->fill
.gradient
.dir
) &&
7490 (old
->fill
.pattern
.back
== new->fill
.pattern
.back
));
7494 odf_get_gradient_name (GnmOOExport
*state
, GOStyle
const* style
)
7496 gchar
const *grad
= g_hash_table_lookup (state
->graph_gradients
,
7500 return g_strdup (grad
);
7502 new_name
= g_strdup_printf ("Gradient-%i", g_hash_table_size (state
->graph_gradients
));
7503 g_hash_table_insert (state
->graph_gradients
,
7504 (gpointer
) style
, g_strdup (new_name
));
7509 odf_match_image (GOImage
*old
, GOImage
*new)
7511 return !go_image_differ (old
, new);
7516 odf_get_image_name (GnmOOExport
*state
, GOStyle
const* style
)
7518 gchar
const *image
= g_hash_table_lookup (state
->graph_fill_images
,
7519 (gpointer
) style
->fill
.image
.image
);
7522 return g_strdup (image
);
7524 new_name
= g_strdup_printf ("Fill-Image-%i",
7525 g_hash_table_size (state
->graph_fill_images
));
7526 g_hash_table_insert (state
->graph_fill_images
,
7527 (gpointer
) style
->fill
.image
.image
, g_strdup (new_name
));
7532 odf_match_pattern (GOPattern
const *old
, GOPattern
const *new)
7534 return (old
->pattern
== new->pattern
&&
7535 old
->back
== new->back
&&
7536 old
->fore
== new->fore
);
7540 odf_get_pattern_name (GnmOOExport
*state
, GOStyle
const* style
)
7542 gchar
const *hatch
= g_hash_table_lookup (state
->graph_hatches
,
7543 (gpointer
) &style
->fill
.pattern
);
7546 return g_strdup (hatch
);
7548 new_name
= g_strdup_printf ("Pattern-%i-%i", style
->fill
.pattern
.pattern
,
7549 g_hash_table_size (state
->graph_hatches
));
7550 g_hash_table_insert (state
->graph_hatches
,
7551 (gpointer
) &style
->fill
.pattern
, g_strdup (new_name
));
7556 odf_get_border_info (G_GNUC_UNUSED GnmOOExport
*state
, GOStyle
const *style
)
7558 if (style
->line
.width
<= 0)
7559 return g_strdup ("thin");
7560 if (style
->line
.width
== 1.5)
7561 return g_strdup ("medium");
7562 if (style
->line
.width
== 3)
7563 return g_strdup ("thick");
7564 return g_strdup_printf ("%.6fpt", style
->line
.width
);
7568 odf_write_gog_style_graphic (GnmOOExport
*state
, GOStyle
const *style
, gboolean with_border
)
7570 char const *image_types
[] =
7571 {"stretch", "repeat", "no-repeat"};
7576 if (style
->interesting_fields
& (GO_STYLE_FILL
)) {
7577 if (state
->with_extension
&& style
->fill
.auto_type
) {
7578 odf_add_bool (state
->xml
, GNMSTYLE
"auto-type", TRUE
);
7580 /* We need to write our colours even for auto_type == TRUE since nobody else understands this */
7581 switch (style
->fill
.type
) {
7582 case GO_STYLE_FILL_NONE
:
7583 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill", "none");
7585 case GO_STYLE_FILL_PATTERN
:
7586 if (style
->fill
.pattern
.pattern
== GO_PATTERN_SOLID
) {
7587 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill", "solid");
7588 if (!style
->fill
.auto_back
) {
7589 char *color
= odf_go_color_to_string (style
->fill
.pattern
.back
);
7590 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill-color", color
);
7591 odf_add_percent (state
->xml
, DRAW
"opacity",
7592 odf_go_color_opacity (style
->fill
.pattern
.back
));
7595 } else if (style
->fill
.pattern
.pattern
== GO_PATTERN_FOREGROUND_SOLID
) {
7596 if (state
->with_extension
)
7597 odf_add_bool (state
->xml
, GNMSTYLE
"foreground-solid", TRUE
);
7598 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill", "solid");
7599 if (!style
->fill
.auto_fore
) {
7600 char *color
= odf_go_color_to_string (style
->fill
.pattern
.fore
);
7601 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill-color", color
);
7602 odf_add_percent (state
->xml
, DRAW
"opacity",
7603 odf_go_color_opacity (style
->fill
.pattern
.fore
));
7607 gchar
*hatch
= odf_get_pattern_name (state
, style
);
7608 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill", "hatch");
7609 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill-hatch-name",
7611 if (!style
->fill
.auto_back
) {
7612 char *color
= odf_go_color_to_string (style
->fill
.pattern
.back
);
7613 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill-color", color
);
7614 odf_add_percent (state
->xml
, DRAW
"opacity",
7615 odf_go_color_opacity (style
->fill
.pattern
.back
));
7619 odf_add_bool (state
->xml
, DRAW
"fill-hatch-solid", TRUE
);
7620 if (state
->with_extension
)
7624 style
->fill
.pattern
.pattern
);
7627 case GO_STYLE_FILL_GRADIENT
: {
7628 gchar
*grad
= odf_get_gradient_name (state
, style
);
7629 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill", "gradient");
7630 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill-gradient-name", grad
);
7634 case GO_STYLE_FILL_IMAGE
: {
7635 gchar
*image
= odf_get_image_name (state
, style
);
7636 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill", "bitmap");
7637 gsf_xml_out_add_cstr (state
->xml
, DRAW
"fill-image-name", image
);
7639 if (style
->fill
.image
.type
< G_N_ELEMENTS (image_types
))
7640 gsf_xml_out_add_cstr (state
->xml
, STYLE
"repeat",
7641 image_types
[style
->fill
.image
.type
]);
7642 else g_warning ("Unexpected GOImageType value");
7648 if (style
->interesting_fields
& (GO_STYLE_LINE
| GO_STYLE_OUTLINE
| GO_STYLE_MARKER
)) {
7649 GOLineDashType dash_type
= style
->line
.dash_type
;
7650 gboolean has_line
= go_style_is_line_visible (style
);
7655 gsf_xml_out_add_cstr (state
->xml
,
7656 DRAW
"stroke", "none");
7657 else if (dash_type
== GO_LINE_SOLID
)
7658 gsf_xml_out_add_cstr (state
->xml
,
7659 DRAW
"stroke", "solid");
7661 char const *dash
= go_line_dash_as_str (dash_type
);
7662 gsf_xml_out_add_cstr (state
->xml
,
7663 DRAW
"stroke", "dash");
7664 gsf_xml_out_add_cstr
7666 DRAW
"stroke-dash", dash
);
7667 g_hash_table_insert (state
->graph_dashes
, g_strdup (dash
),
7668 GINT_TO_POINTER (dash_type
));
7670 if (style
->line
.auto_dash
&& state
->with_extension
)
7671 odf_add_bool (state
->xml
, GNMSTYLE
"auto-dash", TRUE
);
7673 if (style
->line
.auto_width
&& state
->with_extension
)
7674 odf_add_bool (state
->xml
, GNMSTYLE
"auto-width", TRUE
);
7675 else if (style
->line
.width
== 0.0) {
7676 odf_add_pt (state
->xml
, SVG
"stroke-width", 1.);
7677 if (state
->with_extension
)
7678 odf_add_pt (state
->xml
, GNMSTYLE
"stroke-width", 0.);
7679 } else if (style
->line
.width
> 0.0)
7680 odf_add_pt (state
->xml
, SVG
"stroke-width",
7684 * ods doesn't have separate colours for the marker, so use
7685 * the marker colour if we don't have a line.
7687 is_auto
= style
->line
.auto_color
;
7688 color
= style
->line
.color
;
7689 if (!has_line
&& (style
->interesting_fields
& GO_STYLE_MARKER
)) {
7690 is_auto
= style
->marker
.auto_fill_color
;
7691 color
= go_marker_get_fill_color (style
->marker
.mark
);
7695 char *s
= odf_go_color_to_string (color
);
7696 gsf_xml_out_add_cstr (state
->xml
, SVG
"stroke-color", s
);
7698 if (state
->with_extension
) {
7699 s
= odf_go_color_to_string (go_marker_get_outline_color (style
->marker
.mark
));
7700 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"marker-outline-colour", s
);
7702 s
= odf_go_color_to_string (go_marker_get_fill_color (style
->marker
.mark
));
7703 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"marker-fill-colour", s
);
7706 } else if (state
->with_extension
)
7707 odf_add_bool (state
->xml
, GNMSTYLE
"auto-color", style
->fill
.auto_fore
);
7708 if (state
->with_extension
&& (style
->interesting_fields
& GO_STYLE_MARKER
)) {
7709 odf_add_bool (state
->xml
, GNMSTYLE
"auto-marker-outline-colour",
7710 style
->marker
.auto_outline_color
);
7711 odf_add_bool (state
->xml
, GNMSTYLE
"auto-marker-fill-colour",
7712 style
->marker
.auto_fill_color
);
7715 gsf_xml_out_add_cstr (state
->xml
, DRAW
"stroke", "none");
7718 if (with_border
&& go_style_is_outline_visible (style
)) {
7719 char *border
= odf_get_border_info (state
, style
);
7720 if (strlen (border
) > 0)
7721 gsf_xml_out_add_cstr (state
->xml
, FOSTYLE
"border", border
);
7727 odf_write_gog_style_text (GnmOOExport
*state
, GOStyle
const *style
)
7729 if (style
!= NULL
) {
7730 PangoFontDescription
const *desc
= style
->font
.font
->desc
;
7731 PangoFontMask mask
= pango_font_description_get_set_fields (desc
);
7733 if (!style
->text_layout
.auto_angle
) {
7734 int val
= style
->text_layout
.angle
;
7735 odf_add_angle (state
->xml
, STYLE
"text-rotation-angle", val
);
7738 if (!style
->font
.auto_color
) {
7739 char *color
= odf_go_color_to_string (style
->font
.color
);
7740 gsf_xml_out_add_cstr (state
->xml
, FOSTYLE
"color", color
);
7744 if (mask
& PANGO_FONT_MASK_SIZE
)
7745 odf_add_pt (state
->xml
, FOSTYLE
"font-size",
7746 pango_font_description_get_size
7747 (style
->font
.font
->desc
)
7748 / (double)PANGO_SCALE
);
7750 if (mask
& PANGO_FONT_MASK_VARIANT
) {
7751 PangoVariant var
= pango_font_description_get_variant (desc
);
7753 case PANGO_VARIANT_NORMAL
:
7754 gsf_xml_out_add_cstr (state
->xml
,
7755 FOSTYLE
"font-variant", "normal");
7757 case PANGO_VARIANT_SMALL_CAPS
:
7758 gsf_xml_out_add_cstr (state
->xml
,
7759 FOSTYLE
"font-variant",
7766 /*Note that we should be using style:font-name instead of fo:font-family*/
7767 if (mask
& PANGO_FONT_MASK_FAMILY
)
7768 gsf_xml_out_add_cstr
7770 FOSTYLE
"font-family",
7771 pango_font_description_get_family (desc
));
7772 if (mask
& PANGO_FONT_MASK_STYLE
) {
7773 PangoStyle s
= pango_font_description_get_style (desc
);
7775 case PANGO_STYLE_NORMAL
:
7776 gsf_xml_out_add_cstr (state
->xml
,
7777 FOSTYLE
"font-style", "normal");
7779 case PANGO_STYLE_OBLIQUE
:
7780 gsf_xml_out_add_cstr (state
->xml
,
7781 FOSTYLE
"font-style", "oblique");
7783 case PANGO_STYLE_ITALIC
:
7784 gsf_xml_out_add_cstr (state
->xml
,
7785 FOSTYLE
"font-style", "italic");
7791 if (mask
& PANGO_FONT_MASK_WEIGHT
)
7792 odf_add_font_weight (state
,
7793 pango_font_description_get_weight (desc
));
7795 if ((mask
& PANGO_FONT_MASK_STRETCH
) && state
->with_extension
)
7796 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"font-stretch-pango",
7797 pango_font_description_get_stretch (desc
));
7798 if ((mask
& PANGO_FONT_MASK_GRAVITY
) && state
->with_extension
)
7799 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"font-gravity-pango",
7800 pango_font_description_get_gravity (desc
));
7802 if (state
->with_extension
)
7803 odf_add_bool (state
->xml
, GNMSTYLE
"auto-font",
7804 style
->font
.auto_font
);
7809 odf_write_gog_style_chart (GnmOOExport
*state
, GOStyle
const *style
, GogObject
const *obj
)
7811 gchar
const *type
= G_OBJECT_TYPE_NAME (G_OBJECT (obj
));
7812 void (*func
) (GnmOOExport
*state
, GOStyle
const *style
, GogObject
const *obj
);
7814 if (GOG_IS_PLOT (obj
))
7815 odf_write_plot_style (state
, obj
);
7817 if (GOG_IS_AXIS (obj
)) {
7818 GOFormat
*fmt
= gog_axis_get_format (GOG_AXIS (obj
));
7819 odf_add_bool (state
->xml
, CHART
"link-data-style-to-source", fmt
== NULL
);
7822 odf_write_fill_type (state
, obj
);
7824 func
= g_hash_table_lookup (state
->chart_props_hash
, type
);
7826 func (state
, style
, obj
);
7831 if (style
->interesting_fields
& (GO_STYLE_LINE
| GO_STYLE_OUTLINE
)) {
7832 odf_add_bool (state
->xml
,
7834 go_style_is_line_visible (style
));
7837 if (style
->interesting_fields
& GO_STYLE_MARKER
) {
7838 GOMarker
const *marker
= go_style_get_marker (style
);
7839 const char *symbol_type
= NULL
;
7841 if (style
->marker
.auto_shape
) {
7842 if (GOG_IS_SERIES (obj
)) {
7843 GogPlot
*plot
= gog_series_get_plot (GOG_SERIES (obj
));
7844 gboolean has_marker
= TRUE
;
7846 if (gnm_object_has_readable_prop
7847 (plot
, "default-style-has-markers",
7848 G_TYPE_BOOLEAN
, &has_marker
)) {
7850 symbol_type
= "automatic";
7852 symbol_type
= "automatic";
7854 symbol_type
= "automatic";
7856 GOMarkerShape m
= go_marker_get_shape (marker
);
7858 if (m
!= GO_MARKER_NONE
) {
7859 symbol_type
= "named-symbol";
7861 gsf_xml_out_add_cstr
7862 (state
->xml
, CHART
"symbol-name", odf_get_marker (m
));
7867 int size
= go_marker_get_size (marker
);
7868 odf_add_pt (state
->xml
, CHART
"symbol-width", size
);
7869 odf_add_pt (state
->xml
, CHART
"symbol-height", size
);
7871 symbol_type
= "none";
7873 gsf_xml_out_add_cstr (state
->xml
, CHART
"symbol-type", symbol_type
);
7878 odf_write_gog_style (GnmOOExport
*state
, GOStyle
const *style
,
7879 GogObject
const *obj
)
7881 char *name
= odf_get_gog_style_name (state
, style
, obj
);
7883 odf_start_style (state
->xml
, name
, "chart");
7885 if (GOG_IS_AXIS (obj
)) {
7886 GOFormat
*fmt
= gog_axis_get_format (GOG_AXIS (obj
));
7888 char const *name
= xl_find_format (state
, fmt
);
7889 gsf_xml_out_add_cstr (state
->xml
, STYLE
"data-style-name", name
);
7893 gsf_xml_out_start_element (state
->xml
, STYLE
"chart-properties");
7894 odf_write_gog_style_chart (state
, style
, obj
);
7895 gsf_xml_out_end_element (state
->xml
); /* </style:chart-properties> */
7897 gsf_xml_out_start_element (state
->xml
, STYLE
"graphic-properties");
7898 odf_write_gog_style_graphic (state
, style
, FALSE
);
7899 gsf_xml_out_end_element (state
->xml
); /* </style:graphic-properties> */
7901 gsf_xml_out_start_element (state
->xml
, STYLE
"paragraph-properties");
7902 gsf_xml_out_end_element (state
->xml
); /* </style:paragraph-properties> */
7904 gsf_xml_out_start_element (state
->xml
, STYLE
"text-properties");
7905 odf_write_gog_style_text (state
, style
);
7906 gsf_xml_out_end_element (state
->xml
); /* </style:text-properties> */
7908 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
7915 odf_write_gog_styles (GogObject
const *obj
, GnmOOExport
*state
)
7918 GOStyle
*style
= NULL
;
7920 if (gnm_object_has_readable_prop (obj
, "style", G_TYPE_NONE
, &style
)) {
7921 odf_write_gog_style (state
, style
, obj
);
7923 g_object_unref (style
);
7925 odf_write_gog_style (state
, NULL
, obj
);
7927 children
= gog_object_get_children (obj
, NULL
);
7928 g_slist_foreach (children
, (GFunc
) odf_write_gog_styles
, state
);
7929 g_slist_free (children
);
7933 odf_write_axis_categories (GnmOOExport
*state
, GSList
const *series
, GogMSDimType dim
)
7935 if (series
!= NULL
&& series
->data
!= NULL
) {
7936 GOData
const *cat
= gog_dataset_get_dim (GOG_DATASET (series
->data
), dim
);
7938 GnmExprTop
const *texpr
= gnm_go_data_get_expr (cat
);
7939 if (NULL
!= texpr
) {
7942 parse_pos_init (&pp
, WORKBOOK (state
->wb
), NULL
, 0,0 );
7943 cra
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
7945 gsf_xml_out_start_element (state
->xml
, CHART
"categories");
7946 gsf_xml_out_add_cstr (state
->xml
, TABLE
"cell-range-address",
7947 odf_strip_brackets (cra
));
7948 gsf_xml_out_end_element (state
->xml
); /* </chart:categories> */
7957 odf_write_axis_full (GnmOOExport
*state
,
7958 GogObject
const *chart
,
7959 char const *axis_role
,
7960 char const *dimension
,
7961 G_GNUC_UNUSED odf_chart_type_t gtype
,
7962 GSList
const *series
,
7963 gboolean include_cats
,
7966 GSList
*children
= NULL
, *l
;
7969 if (axis_role
== NULL
)
7972 str
= g_string_new (NULL
);
7973 children
= gog_object_get_children (chart
, gog_object_find_role_by_name (chart
, axis_role
));
7975 for (l
= children
; l
!= NULL
; l
= l
->next
) {
7976 GogObject
const *axis
= l
->data
;
7978 int id
= gog_object_get_id (GOG_OBJECT (axis
));
7981 gsf_xml_out_start_element (state
->xml
, CHART
"axis");
7982 gsf_xml_out_add_cstr (state
->xml
, CHART
"dimension", dimension
);
7983 if (state
->with_extension
)
7984 gsf_xml_out_add_int (state
->xml
, GNMSTYLE
"id", id
);
7985 g_string_truncate (str
, 0);
7986 g_string_append_printf (str
, "%s-%i", axis_role
, id
);
7987 gsf_xml_out_add_cstr_unchecked (state
->xml
, CHART
"name", str
->str
);
7988 name
= odf_get_gog_style_name_from_obj (state
, GOG_OBJECT (axis
));
7990 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", name
);
7992 if (state
->with_extension
&& 0 == strcmp (axis_role
,"Pseudo-3D-Axis")) {
7993 char *color_map_name
= NULL
;
7994 g_object_get (G_OBJECT (axis
), "color-map-name", &color_map_name
, NULL
);
7995 if (color_map_name
) {
7996 gsf_xml_out_add_cstr (state
->xml
, GNMSTYLE
"color-map-name", color_map_name
);
7997 g_free (color_map_name
);
8000 odf_write_label (state
, axis
);
8002 odf_write_axis_categories (state
, series
, dim
);
8003 odf_write_axis_grid (state
, axis
);
8004 odf_write_axislines (state
, axis
);
8005 gsf_xml_out_end_element (state
->xml
); /* </chart:axis> */
8008 g_slist_free (children
);
8009 g_string_free (str
, TRUE
);
8013 odf_write_axis (GnmOOExport
*state
,
8014 GogObject
const *chart
,
8015 char const *axis_role
,
8016 char const *dimension
,
8017 odf_chart_type_t gtype
,
8019 GSList
const *series
)
8021 odf_write_axis_full (state
, chart
, axis_role
, dimension
, gtype
, series
, TRUE
, dim
);
8025 odf_write_axis_no_cats (GnmOOExport
*state
,
8026 GogObject
const *chart
,
8027 char const *axis_role
,
8028 char const *dimension
,
8029 odf_chart_type_t gtype
,
8031 GSList
const *series
)
8033 odf_write_axis_full (state
, chart
, axis_role
, dimension
, gtype
, series
, FALSE
, dim
);
8037 odf_write_pie_axis (GnmOOExport
*state
,
8038 G_GNUC_UNUSED GogObject
const *chart
,
8039 G_GNUC_UNUSED
char const *axis_role
,
8040 char const *dimension
,
8041 G_GNUC_UNUSED odf_chart_type_t gtype
,
8043 GSList
const *series
)
8045 gsf_xml_out_start_element (state
->xml
, CHART
"axis");
8046 gsf_xml_out_add_cstr (state
->xml
, CHART
"dimension", dimension
);
8047 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", "pie-axis");
8048 odf_write_axis_categories (state
, series
, dim
);
8049 gsf_xml_out_end_element (state
->xml
); /* </chart:axis> */
8054 odf_write_plot (GnmOOExport
*state
, SheetObject
*so
, GogObject
const *graph
,
8055 GogObject
const *chart
, GogObject
const *plot
, GSList
*other_plots
)
8057 char const *plot_type
= G_OBJECT_TYPE_NAME (plot
);
8058 SheetObjectAnchor
const *anchor
= sheet_object_get_anchor (so
);
8059 double res_pts
[4] = {0.,0.,0.,0.};
8060 GSList
const *series
, *l
;
8061 GogObject
const *wall
= gog_object_get_child_by_name (chart
, "Backplane");
8062 GogObject
const *legend
= gog_object_get_child_by_name (chart
, "Legend");
8063 GogObject
const *color_scale
= gog_object_get_child_by_name (chart
, "Color-Scale");
8064 GogObjectRole
const *trole
= gog_object_find_role_by_name (graph
, "Title");
8065 GSList
*titles
= gog_object_get_children (graph
, trole
);
8066 GogObjectRole
const *trole2
= gog_object_find_role_by_name (chart
, "Title");
8067 GSList
*subtitles
= gog_object_get_children (chart
, trole2
);
8069 GOStyle
*style
= NULL
;
8073 char const *odf_plot_type
;
8074 odf_chart_type_t gtype
;
8076 char const * x_axis_name
;
8077 char const * y_axis_name
;
8078 char const * z_axis_name
;
8082 void (*odf_write_series
) (GnmOOExport
*state
,
8083 GSList
const *series
,
8085 void (*odf_write_x_axis
) (GnmOOExport
*state
,
8086 GogObject
const *chart
,
8087 char const *axis_role
,
8088 char const *dimension
,
8089 odf_chart_type_t gtype
,
8091 GSList
const *series
);
8092 void (*odf_write_y_axis
) (GnmOOExport
*state
,
8093 GogObject
const *chart
,
8094 char const *axis_role
,
8095 char const *dimension
,
8096 odf_chart_type_t gtype
,
8098 GSList
const *series
);
8099 void (*odf_write_z_axis
) (GnmOOExport
*state
,
8100 GogObject
const *chart
,
8101 char const *axis_role
,
8102 char const *dimension
,
8103 odf_chart_type_t gtype
,
8105 GSList
const *series
);
8106 } *this_plot
, *this_second_plot
, plots
[] = {
8107 { "GogColPlot", CHART
"bar", ODF_BARCOL
,
8108 20., "X-Axis", "Y-Axis", NULL
,
8109 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8110 odf_write_standard_series
,
8111 odf_write_axis
, odf_write_axis_no_cats
, odf_write_axis
},
8112 { "GogBarPlot", CHART
"bar", ODF_BARCOL
,
8113 20., "Y-Axis", "X-Axis", NULL
,
8114 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8115 odf_write_standard_series
,
8116 odf_write_axis
, odf_write_axis_no_cats
, odf_write_axis
},
8117 { "GogLinePlot", CHART
"line", ODF_LINE
,
8118 20., "X-Axis", "Y-Axis", NULL
,
8119 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8120 odf_write_standard_series
,
8121 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8122 { "GogPolarPlot", GNMSTYLE
"polar", ODF_POLAR
,
8123 20., "Circular-Axis", "Radial-Axis", NULL
,
8124 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8125 odf_write_standard_series
,
8126 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8127 { "GogAreaPlot", CHART
"area", ODF_AREA
,
8128 20., "X-Axis", "Y-Axis", NULL
,
8129 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8130 odf_write_standard_series
,
8131 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8132 { "GogDropBarPlot", CHART
"gantt", ODF_DROPBAR
,
8133 20., "X-Axis", "Y-Axis", NULL
,
8134 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8135 odf_write_gantt_series
,
8136 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8137 { "GogMinMaxPlot", CHART
"stock", ODF_MINMAX
,
8138 10., "X-Axis", "Y-Axis", NULL
,
8139 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8140 odf_write_min_max_series
,
8141 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8142 { "GogPiePlot", CHART
"circle", ODF_CIRCLE
,
8143 5., NULL
, "Y-Axis", NULL
,
8144 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8145 odf_write_standard_series
,
8146 NULL
, odf_write_pie_axis
, NULL
},
8147 { "GogRadarPlot", CHART
"radar", ODF_RADAR
,
8148 10., "Circular-Axis", "Radial-Axis", NULL
,
8149 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8150 odf_write_standard_series
,
8151 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8152 { "GogRadarAreaPlot", CHART
"filled-radar", ODF_RADARAREA
,
8153 10., "X-Axis", "Y-Axis", NULL
,
8154 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8155 odf_write_standard_series
,
8156 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8157 { "GogRingPlot", CHART
"ring", ODF_RING
,
8158 10., NULL
, "Y-Axis", NULL
,
8159 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8160 odf_write_standard_series
,
8161 NULL
, odf_write_pie_axis
, NULL
},
8162 { "GogXYPlot", CHART
"scatter", ODF_SCATTER
,
8163 20., "X-Axis", "Y-Axis", NULL
,
8164 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8165 odf_write_standard_series
,
8166 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8167 { "GogContourPlot", CHART
"surface", ODF_SURF
,
8168 20., "X-Axis", "Y-Axis", "Pseudo-3D-Axis",
8169 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8170 odf_write_bubble_series
,
8171 odf_write_axis
, odf_write_axis
, odf_write_axis_no_cats
},
8172 { "GogXYZContourPlot", GNMSTYLE
"xyz-surface", ODF_XYZ_SURF
,
8173 20., "X-Axis", "Y-Axis", NULL
,
8174 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8175 odf_write_bubble_series
,
8176 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8177 { "GogXYZSurfacePlot", GNMSTYLE
"xyz-surface", ODF_XYZ_GNM_SURF
,
8178 20., "X-Axis", "Y-Axis", "Z-Axis",
8179 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8180 odf_write_bubble_series
,
8181 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8182 { "GogSurfacePlot", CHART
"surface", ODF_GNM_SURF
,
8183 20., "X-Axis", "Y-Axis", "Z-Axis",
8184 GOG_MS_DIM_LABELS
, GOG_MS_DIM_VALUES
, GOG_MS_DIM_LABELS
,
8185 odf_write_bubble_series
,
8186 odf_write_axis
, odf_write_axis
, odf_write_axis_no_cats
},
8187 { "GogBubblePlot", CHART
"bubble", ODF_BUBBLE
,
8188 20., "X-Axis", "Y-Axis", NULL
,
8189 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8190 odf_write_bubble_series
,
8191 odf_write_axis_no_cats
, odf_write_axis_no_cats
, odf_write_axis_no_cats
},
8192 { "GogXYColorPlot", GNMSTYLE
"scatter-color", ODF_SCATTER_COLOUR
,
8193 20., "X-Axis", "Y-Axis", NULL
,
8194 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8195 odf_write_bubble_series
,
8196 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8197 { "XLSurfacePlot", CHART
"surface", ODF_GNM_SURF
,
8198 20., "X-Axis", "Y-Axis", "Z-Axis",
8199 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8200 odf_write_standard_series
,
8201 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8202 { "GogBoxPlot", GNMSTYLE
"box", ODF_GNM_BOX
,
8203 20., "X-Axis", "Y-Axis", NULL
,
8204 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8205 odf_write_box_series
,
8206 odf_write_axis
, odf_write_axis
, odf_write_axis
},
8208 20., "X-Axis", "Y-Axis", NULL
,
8209 GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
, GOG_MS_DIM_LABELS
,
8210 odf_write_standard_series
,
8211 odf_write_axis
, odf_write_axis
, odf_write_axis
}
8214 if (0 == strcmp ("GogBarColPlot", plot_type
)) {
8217 if (gnm_object_has_readable_prop (plot
, "horizontal",
8218 G_TYPE_BOOLEAN
, &b
) &&
8220 plot_type
= "GogBarPlot";
8222 plot_type
= "GogColPlot";
8225 for (this_plot
= &plots
[0]; this_plot
->type
!= NULL
; this_plot
++)
8226 if (0 == strcmp (plot_type
, this_plot
->type
))
8229 if (this_plot
->type
== NULL
) {
8230 g_printerr ("Encountered unknown chart type %s\n", plot_type
);
8231 this_plot
= &plots
[0];
8234 series
= gog_plot_get_series (GOG_PLOT (plot
));
8236 gsf_xml_out_start_element (state
->xml
, OFFICE
"automatic-styles");
8237 odf_write_character_styles (state
);
8239 odf_write_generic_axis_style (state
, "pie-axis");
8241 odf_start_style (state
->xml
, "plotstyle", "chart");
8242 gsf_xml_out_start_element (state
->xml
, STYLE
"chart-properties");
8243 odf_add_bool (state
->xml
, CHART
"auto-size", TRUE
);
8244 gsf_xml_out_end_element (state
->xml
); /* </style:chart-properties> */
8245 g_object_get (G_OBJECT (chart
), "style", &style
, NULL
);
8247 gsf_xml_out_start_element (state
->xml
, STYLE
"graphic-properties");
8248 odf_write_gog_style_graphic (state
, style
, TRUE
);
8249 gsf_xml_out_end_element (state
->xml
); /* </style:graphic-properties> */
8250 g_object_unref (style
);
8252 gsf_xml_out_end_element (state
->xml
); /* </style:style> */
8254 odf_write_gog_styles (chart
, state
);
8256 gsf_xml_out_end_element (state
->xml
); /* </office:automatic-styles> */
8258 gsf_xml_out_start_element (state
->xml
, OFFICE
"body");
8259 gsf_xml_out_start_element (state
->xml
, OFFICE
"chart");
8260 gsf_xml_out_start_element (state
->xml
, CHART
"chart");
8262 sheet_object_anchor_to_pts (anchor
, state
->sheet
, res_pts
);
8263 odf_add_pt (state
->xml
, SVG
"width", res_pts
[2] - res_pts
[0] - 2 * this_plot
->pad
);
8264 odf_add_pt (state
->xml
, SVG
"height", res_pts
[3] - res_pts
[1] - 2 * this_plot
->pad
);
8266 if (state
->odf_version
> 101) {
8267 gsf_xml_out_add_cstr (state
->xml
, XLINK
"type", "simple");
8268 gsf_xml_out_add_cstr (state
->xml
, XLINK
"href", "..");
8270 gsf_xml_out_add_cstr (state
->xml
, CHART
"class", this_plot
->odf_plot_type
);
8271 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", "plotstyle");
8275 if (titles
!= NULL
) {
8276 GogObject
const *title
= titles
->data
;
8277 odf_write_title (state
, title
, CHART
"title", TRUE
);
8278 g_slist_free (titles
);
8280 if (subtitles
!= NULL
) {
8281 GogObject
const *title
= subtitles
->data
;
8283 gboolean is_footer
= FALSE
;
8285 g_object_get (G_OBJECT (title
),
8286 "compass", &position
,
8288 is_footer
= NULL
!= g_strstr_len (position
, -1, "bottom");
8289 odf_write_title (state
, title
,
8290 is_footer
? CHART
"footer" : CHART
"subtitle",
8292 g_slist_free (subtitles
);
8297 /* Set up legend if appropriate*/
8299 if (legend
!= NULL
) {
8300 GogObjectPosition flags
;
8301 char *style_name
= odf_get_gog_style_name_from_obj
8303 GSList
*ltitles
= gog_object_get_children
8304 (legend
, gog_object_find_role_by_name
8306 gboolean is_position_manual
= FALSE
;
8308 gsf_xml_out_start_element (state
->xml
, CHART
"legend");
8309 gsf_xml_out_add_cstr (state
->xml
,
8312 g_free (style_name
);
8314 odf_write_gog_position (state
, legend
); /* gnumeric extensions */
8316 g_object_get (G_OBJECT (legend
),
8317 "is-position-manual", &is_position_manual
,
8319 if (is_position_manual
)
8320 odf_write_gog_position_pts (state
, legend
);
8322 flags
= gog_object_get_position_flags
8323 (legend
, GOG_POSITION_COMPASS
);
8325 GString
*compass
= g_string_new (NULL
);
8327 if (flags
& GOG_POSITION_N
)
8328 g_string_append (compass
, "top");
8329 if (flags
& GOG_POSITION_S
)
8330 g_string_append (compass
, "bottom");
8331 if ((flags
& (GOG_POSITION_S
| GOG_POSITION_N
)) &&
8332 (flags
& (GOG_POSITION_E
| GOG_POSITION_W
)))
8333 g_string_append (compass
, "-");
8334 if (flags
& GOG_POSITION_E
)
8335 g_string_append (compass
, "end");
8336 if (flags
& GOG_POSITION_W
)
8337 g_string_append (compass
, "start");
8339 gsf_xml_out_add_cstr (state
->xml
,
8340 CHART
"legend-position",
8343 g_string_free (compass
, TRUE
);
8347 if (ltitles
!= NULL
) {
8348 GogObject
const *title
= ltitles
->data
;
8350 if (state
->with_extension
)
8351 odf_write_title (state
, title
,
8352 GNMSTYLE
"title", state
->odf_version
> 101);
8353 else if (state
->odf_version
> 101) {
8355 gog_dataset_get_dim (GOG_DATASET(title
),0);
8358 GnmExprTop
const *texpr
8359 = gnm_go_data_get_expr (dat
);
8360 if (texpr
!= NULL
&&
8361 GNM_EXPR_GET_OPER (texpr
->expr
) == GNM_EXPR_OP_CONSTANT
8362 && VALUE_IS_STRING (texpr
->expr
->constant
.value
)) {
8363 gboolean white_written
= TRUE
;
8366 g_object_get (G_OBJECT (state
->xml
), "pretty-print", &pp
, NULL
);
8367 g_object_set (G_OBJECT (state
->xml
), "pretty-print", FALSE
, NULL
);
8368 gsf_xml_out_start_element (state
->xml
, TEXT
"p");
8369 str
= value_peek_string (texpr
->expr
->constant
.value
);
8370 odf_add_chars (state
, str
, strlen (str
),
8372 gsf_xml_out_end_element (state
->xml
); /* </text:p> */
8373 g_object_set (G_OBJECT (state
->xml
), "pretty-print", pp
, NULL
);
8378 g_slist_free (ltitles
);
8381 gsf_xml_out_end_element (state
->xml
); /* </chart:legend> */
8384 gsf_xml_out_start_element (state
->xml
, CHART
"plot-area");
8386 name
= odf_get_gog_style_name_from_obj (state
, plot
);
8388 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", name
);
8392 if (state
->odf_version
<= 101) {
8393 for ( l
= series
; NULL
!= l
; l
= l
->next
) {
8394 GOData
const *dat
= gog_dataset_get_dim
8395 (GOG_DATASET (l
->data
), GOG_MS_DIM_VALUES
);
8397 GnmExprTop
const *texpr
= gnm_go_data_get_expr (dat
);
8398 if (NULL
!= texpr
) {
8401 parse_pos_init (&pp
, WORKBOOK (state
->wb
), NULL
, 0,0 );
8402 str
= gnm_expr_top_as_string (texpr
, &pp
, state
->conv
);
8403 gsf_xml_out_add_cstr (state
->xml
, TABLE
"cell-range-address",
8404 odf_strip_brackets (str
));
8412 odf_write_gog_plot_area_position (state
, chart
);
8414 if (this_plot
->odf_write_z_axis
)
8415 this_plot
->odf_write_z_axis
8416 (state
, chart
, this_plot
->z_axis_name
, "z",
8417 this_plot
->gtype
, this_plot
->z_dim
, series
);
8418 if (this_plot
->odf_write_y_axis
)
8419 this_plot
->odf_write_y_axis
8420 (state
, chart
, this_plot
->y_axis_name
, "y",
8421 this_plot
->gtype
, this_plot
->y_dim
, series
);
8422 if (this_plot
->odf_write_x_axis
)
8423 this_plot
->odf_write_x_axis
8424 (state
, chart
, this_plot
->x_axis_name
, "x",
8425 this_plot
->gtype
, this_plot
->x_dim
, series
);
8427 if (this_plot
->odf_write_series
!= NULL
)
8428 this_plot
->odf_write_series (state
, series
, NULL
);
8430 while (other_plots
) {
8431 GogObject
const *second_plot
= GOG_OBJECT (other_plots
->data
);
8432 plot_type
= G_OBJECT_TYPE_NAME (second_plot
);
8434 if (0 == strcmp ("GogBarColPlot", plot_type
)) {
8437 if (gnm_object_has_readable_prop
8438 (second_plot
, "horizontal",
8439 G_TYPE_BOOLEAN
, &b
) && b
)
8440 plot_type
= "GogBarPlot";
8442 plot_type
= "GogColPlot";
8445 for (this_second_plot
= &plots
[0]; this_second_plot
->type
!= NULL
; this_second_plot
++)
8446 if (0 == strcmp (plot_type
, this_second_plot
->type
))
8449 if (this_second_plot
->type
== NULL
) {
8450 g_printerr ("Encountered unknown chart type %s\n", plot_type
);
8451 this_second_plot
= &plots
[0];
8454 series
= gog_plot_get_series (GOG_PLOT (second_plot
));
8456 this_second_plot
->odf_write_series (state
, series
, this_second_plot
->odf_plot_type
);
8457 other_plots
= other_plots
->next
;
8461 char *name
= odf_get_gog_style_name_from_obj (state
, wall
);
8463 gsf_xml_out_start_element (state
->xml
, CHART
"wall");
8464 odf_add_pt (state
->xml
, SVG
"width", res_pts
[2] - res_pts
[0] - 2 * this_plot
->pad
);
8466 gsf_xml_out_add_cstr (state
->xml
, CHART
"style-name", name
);
8467 gsf_xml_out_end_element (state
->xml
); /* </chart:wall> */
8471 gsf_xml_out_end_element (state
->xml
); /* </chart:plot_area> */
8473 if (color_scale
!= NULL
&& state
->with_extension
)
8474 gsf_xml_out_simple_element (state
->xml
, GNMSTYLE
"color-scale", NULL
);
8476 gsf_xml_out_end_element (state
->xml
); /* </chart:chart> */
8477 gsf_xml_out_end_element (state
->xml
); /* </office:chart> */
8478 gsf_xml_out_end_element (state
->xml
); /* </office:body> */
8483 odf_write_graph_content (GnmOOExport
*state
, GsfOutput
*child
, SheetObject
*so
, GogObject
const *chart
)
8486 GogGraph
const *graph
;
8487 gboolean plot_written
= FALSE
;
8489 state
->xml
= create_new_xml_child (state
, child
);
8490 gsf_xml_out_set_doc_type (state
->xml
, "\n");
8491 gsf_xml_out_start_element (state
->xml
, OFFICE
"document-content");
8493 for (i
= 0 ; i
< (int)G_N_ELEMENTS (ns
) ; i
++)
8494 gsf_xml_out_add_cstr_unchecked (state
->xml
, ns
[i
].key
, ns
[i
].url
);
8495 gsf_xml_out_add_cstr_unchecked (state
->xml
, OFFICE
"version",
8496 state
->odf_version_string
);
8498 graph
= sheet_object_graph_get_gog (so
);
8499 if (graph
!= NULL
) {
8501 GogRenderer
*renderer
;
8502 GogObjectRole
const *role
;
8504 sheet_object_position_pts_get (so
, pos
);
8505 renderer
= g_object_new (GOG_TYPE_RENDERER
,
8508 gog_renderer_update (renderer
, pos
[2] - pos
[0], pos
[3] - pos
[1]);
8509 g_object_get (G_OBJECT (renderer
), "view", &state
->root_view
, NULL
);
8511 role
= gog_object_find_role_by_name (chart
, "Plot");
8513 GSList
*plots
= gog_object_get_children
8514 (chart
, gog_object_find_role_by_name (chart
, "Plot"));
8515 if (plots
!= NULL
&& plots
->data
!= NULL
) {
8516 odf_write_plot (state
, so
, GOG_OBJECT (graph
),
8517 chart
, plots
->data
, plots
->next
);
8518 plot_written
= TRUE
;
8520 g_slist_free (plots
);
8522 g_object_unref (state
->root_view
);
8523 state
->root_view
= NULL
;
8524 g_object_unref (renderer
);
8526 if (!plot_written
) {
8527 gsf_xml_out_start_element (state
->xml
, OFFICE
"body");
8528 gsf_xml_out_start_element (state
->xml
, OFFICE
"chart");
8529 gsf_xml_out_start_element (state
->xml
, CHART
"chart");
8530 gsf_xml_out_add_cstr (state
->xml
, CHART
"class", GNMSTYLE
"none");
8531 gsf_xml_out_start_element (state
->xml
, CHART
"plot-area");
8532 gsf_xml_out_end_element (state
->xml
); /* </chart:plotarea> */
8533 gsf_xml_out_end_element (state
->xml
); /* </chart:chart> */
8534 gsf_xml_out_end_element (state
->xml
); /* </office:chart> */
8535 gsf_xml_out_end_element (state
->xml
); /* </office:body> */
8538 gsf_xml_out_end_element (state
->xml
); /* </office:document-content> */
8539 g_object_unref (state
->xml
);
8543 /**********************************************************************************/
8546 odf_write_images (SheetObjectImage
*soi
, char const *name
, GnmOOExport
*state
)
8553 g_object_get (G_OBJECT (soi
),
8554 "image-type", &image_type
,
8557 fullname
= g_strdup_printf ("Pictures/%s.%s", name
, image_type
);
8559 child
= gsf_outfile_new_child_full (state
->outfile
, fullname
, FALSE
,
8560 "compression-level", GSF_ZIP_DEFLATED
,
8562 if (NULL
!= child
) {
8564 guint8
const *data
= go_image_get_data (image
, &length
);
8565 gsf_output_write (child
, length
, data
);
8566 gsf_output_close (child
);
8567 g_object_unref (child
);
8571 g_free (image_type
);
8572 g_object_unref (image
);
8574 odf_update_progress (state
, state
->graph_progress
);
8578 odf_write_drop (GnmOOExport
*state
, G_GNUC_UNUSED GOStyle
const *style
,
8579 GogObject
const *obj
)
8581 GogObjectRole
const *h_role
= gog_object_find_role_by_name
8582 (obj
->parent
, "Horizontal drop lines");
8583 gboolean vertical
= !(h_role
== obj
->role
);
8585 odf_add_bool (state
->xml
, CHART
"vertical", vertical
);
8589 odf_write_reg_name (GnmOOExport
*state
, GogObject
const *obj
)
8591 if (state
->with_extension
)
8592 odf_add_expr (state
, obj
, -1, GNMSTYLE
"regression-name",
8593 LOEXT
"regression-name");
8597 odf_write_plot_style_affine (GsfXMLOut
*xml
, GogObject
const *plot
, float intercept
)
8600 if (gnm_object_has_readable_prop (plot
, "affine", G_TYPE_BOOLEAN
, &b
)) {
8601 odf_add_bool (xml
, GNMSTYLE
"regression-affine", b
);
8602 odf_add_bool (xml
, LOEXT
"regression-force-intercept", !b
);
8603 go_xml_out_add_double (xml
, LOEXT
"regression-intercept-value", intercept
);
8609 odf_write_lin_reg (GnmOOExport
*state
, G_GNUC_UNUSED GOStyle
const *style
,
8610 GogObject
const *obj
)
8612 gsf_xml_out_add_cstr (state
->xml
, CHART
"regression-type", "linear");
8613 if (state
->with_extension
) {
8614 odf_write_plot_style_uint (state
->xml
, obj
,
8615 "dims", GNMSTYLE
"regression-polynomial-dims");
8616 odf_write_plot_style_uint (state
->xml
, obj
,
8617 "dims", LOEXT
"regression-max-degree");
8618 odf_write_plot_style_affine (state
->xml
, obj
, 0.);
8620 odf_write_reg_name (state
, obj
);
8624 odf_write_polynom_reg (GnmOOExport
*state
, G_GNUC_UNUSED GOStyle
const *style
,
8625 GogObject
const *obj
)
8627 if (state
->with_extension
) {
8628 gsf_xml_out_add_cstr (state
->xml
, CHART
"regression-type",
8629 GNMSTYLE
"polynomial");
8630 odf_write_plot_style_uint (state
->xml
, obj
,
8631 "dims", GNMSTYLE
"regression-polynomial-dims");
8632 odf_write_plot_style_uint (state
->xml
, obj
,
8633 "dims", LOEXT
"regression-max-degree");
8634 odf_write_plot_style_affine (state
->xml
, obj
, 0.);
8636 odf_write_reg_name (state
, obj
);
8640 odf_write_exp_reg (GnmOOExport
*state
, G_GNUC_UNUSED GOStyle
const *style
,
8641 G_GNUC_UNUSED GogObject
const *obj
)
8643 gsf_xml_out_add_cstr (state
->xml
, CHART
"regression-type", "exponential");
8644 if (state
->with_extension
)
8645 odf_write_plot_style_affine (state
->xml
, obj
, 1.);
8646 odf_write_reg_name (state
, obj
);
8650 odf_write_power_reg (GnmOOExport
*state
, G_GNUC_UNUSED GOStyle
const *style
,
8651 G_GNUC_UNUSED GogObject
const *obj
)
8653 gsf_xml_out_add_cstr (state
->xml
, CHART
"regression-type", "power");
8654 odf_write_reg_name (state
, obj
);
8658 odf_write_log_reg (GnmOOExport
*state
, G_GNUC_UNUSED GOStyle
const *style
,
8659 G_GNUC_UNUSED GogObject
const *obj
)
8661 gsf_xml_out_add_cstr (state
->xml
, CHART
"regression-type", "logarithmic");
8662 odf_write_reg_name (state
, obj
);
8666 odf_write_log_fit_reg (GnmOOExport
*state
, G_GNUC_UNUSED GOStyle
const *style
,
8667 G_GNUC_UNUSED GogObject
const *obj
)
8669 if (state
->with_extension
)
8670 gsf_xml_out_add_cstr (state
->xml
, CHART
"regression-type",
8671 GNMSTYLE
"log-fit");
8672 odf_write_reg_name (state
, obj
);
8676 odf_write_movig_avg_reg (GnmOOExport
*state
, G_GNUC_UNUSED GOStyle
const *style
,
8677 G_GNUC_UNUSED GogObject
const *obj
)
8679 if (state
->with_extension
)
8680 gsf_xml_out_add_cstr (state
->xml
, CHART
"regression-type",
8681 GNMSTYLE
"moving-average");
8682 odf_write_reg_name (state
, obj
);
8686 odf_write_exp_smooth_reg (GnmOOExport
*state
, G_GNUC_UNUSED GOStyle
const *style
,
8687 G_GNUC_UNUSED GogObject
const *obj
)
8689 if (state
->with_extension
)
8690 gsf_xml_out_add_cstr (state
->xml
, CHART
"regression-type",
8691 GNMSTYLE
"exponential-smoothed");
8692 odf_write_reg_name (state
, obj
);
8696 odf_write_pie_point (GnmOOExport
*state
, G_GNUC_UNUSED GOStyle
const *style
,
8697 GogObject
const *obj
)
8699 double separation
= 0.;
8701 if (gnm_object_has_readable_prop (obj
, "separation",
8702 G_TYPE_DOUBLE
, &separation
)) {
8703 gsf_xml_out_add_int (state
->xml
,
8705 (separation
* 100. + 0.5));
8710 odf_fill_chart_props_hash (GnmOOExport
*state
)
8715 void (*odf_write_property
) (GnmOOExport
*state
,
8716 GOStyle
const *style
,
8717 GogObject
const *obj
);
8719 {"GogSeriesLines", odf_write_drop
},
8720 {"GogAxis", odf_write_axis_style
},
8721 {"GogAxisLine", odf_write_axisline_style
},
8722 {"GogLinRegCurve", odf_write_lin_reg
},
8723 {"GogPolynomRegCurve", odf_write_polynom_reg
},
8724 {"GogExpRegCurve", odf_write_exp_reg
},
8725 {"GogPowerRegCurve", odf_write_power_reg
},
8726 {"GogLogRegCurve", odf_write_log_reg
},
8727 {"GogLogFitCurve", odf_write_log_fit_reg
},
8728 {"GogMovingAvg", odf_write_movig_avg_reg
},
8729 {"GogExpSmooth", odf_write_exp_smooth_reg
},
8730 {"GogPieSeriesElement", odf_write_pie_point
},
8731 {"GogXYSeries", odf_write_interpolation_attribute
},
8732 {"GogLineSeries", odf_write_interpolation_attribute
},
8735 for (i
= 0 ; i
< (int)G_N_ELEMENTS (props
) ; i
++)
8736 g_hash_table_insert (state
->chart_props_hash
, (gpointer
) props
[i
].type
,
8737 props
[i
].odf_write_property
);
8741 _gsf_gdk_pixbuf_save (const gchar
*buf
,
8746 GsfOutput
*output
= GSF_OUTPUT (data
);
8747 gboolean ok
= gsf_output_write (output
, count
, buf
);
8750 *error
= g_error_copy (gsf_output_error (output
));
8756 odf_write_fill_images (GOImage
*image
, char const *name
, GnmOOExport
*state
)
8759 char *manifest_name
= g_strdup_printf ("%s/Pictures/%s.png",
8760 state
->object_name
, name
);
8762 child
= gsf_outfile_new_child_full (state
->outfile
, manifest_name
,
8764 "compression-level", GSF_ZIP_DEFLATED
,
8767 if (child
!= NULL
) {
8768 GdkPixbuf
*output_pixbuf
;
8770 state
->fill_image_files
8771 = g_slist_prepend (state
->fill_image_files
,
8773 output_pixbuf
= go_image_get_pixbuf (image
);
8775 gdk_pixbuf_save_to_callback (output_pixbuf
,
8776 _gsf_gdk_pixbuf_save
,
8779 gsf_output_close (child
);
8780 g_object_unref (child
);
8782 g_free (manifest_name
);
8789 odf_write_graphs (SheetObject
*so
, char const *name
, GnmOOExport
*state
)
8791 GogGraph
*graph
= sheet_object_graph_get_gog (so
);
8792 GogObjectRole
const *role
= gog_object_find_role_by_name (GOG_OBJECT (graph
), "Chart");
8793 GSList
*l
, *chart_list
= gog_object_get_children (GOG_OBJECT (graph
), role
);
8795 guint num
= g_slist_length (chart_list
);
8797 float progress
= state
->graph_progress
/ num
;
8801 while (NULL
!= chart_list
) {
8803 GogObject
const *chart
= chart_list
->data
;
8804 chartname
= g_strdup_printf ("%s-%i", name
, n
);
8805 g_hash_table_remove_all (state
->xl_styles
);
8807 state
->object_name
= chartname
;
8809 child
= gsf_outfile_new_child_full
8810 (state
->outfile
, chartname
, TRUE
,
8811 "compression-level", GSF_ZIP_DEFLATED
,
8813 if (NULL
!= child
) {
8814 char *fullname
= g_strdup_printf ("%s/content.xml", chartname
);
8815 GsfOutput
*sec_child
;
8817 state
->chart_props_hash
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
8819 odf_fill_chart_props_hash (state
);
8821 sec_child
= gsf_outfile_new_child_full (state
->outfile
, fullname
, FALSE
,
8822 "compression-level", GSF_ZIP_DEFLATED
,
8824 if (NULL
!= sec_child
) {
8825 odf_write_graph_content (state
, sec_child
, so
, chart
);
8826 gsf_output_close (sec_child
);
8827 g_object_unref (sec_child
);
8831 odf_update_progress (state
, 4 * progress
);
8833 fullname
= g_strdup_printf ("%s/meta.xml", chartname
);
8834 sec_child
= gsf_outfile_new_child_full (state
->outfile
, fullname
, FALSE
,
8835 "compression-level", GSF_ZIP_DEFLATED
,
8837 if (NULL
!= sec_child
) {
8838 odf_write_meta_graph (state
, sec_child
);
8839 gsf_output_close (sec_child
);
8840 g_object_unref (sec_child
);
8843 odf_update_progress (state
, progress
/ 2);
8845 fullname
= g_strdup_printf ("%s/styles.xml", chartname
);
8846 sec_child
= gsf_outfile_new_child_full (state
->outfile
, fullname
, FALSE
,
8847 "compression-level", GSF_ZIP_DEFLATED
,
8849 if (NULL
!= sec_child
) {
8850 odf_write_graph_styles (state
, sec_child
);
8851 gsf_output_close (sec_child
);
8852 g_object_unref (sec_child
);
8856 gnm_hash_table_foreach_ordered
8857 (state
->graph_fill_images
,
8858 (GHFunc
) odf_write_fill_images
,
8862 g_hash_table_remove_all (state
->graph_dashes
);
8863 g_hash_table_remove_all (state
->graph_hatches
);
8864 g_hash_table_remove_all (state
->graph_gradients
);
8865 g_hash_table_remove_all (state
->graph_fill_images
);
8867 g_hash_table_unref (state
->chart_props_hash
);
8868 state
->chart_props_hash
= NULL
;
8869 odf_update_progress (state
, progress
* (3./2.));
8871 gsf_output_close (child
);
8872 g_object_unref (child
);
8874 fullname
= g_strdup_printf ("Pictures/%s", chartname
);
8875 sec_child
= gsf_outfile_new_child_full (state
->outfile
, fullname
, FALSE
,
8876 "compression-level", GSF_ZIP_DEFLATED
,
8878 if (NULL
!= sec_child
) {
8879 if (!gog_graph_export_image (graph
, GO_IMAGE_FORMAT_SVG
,
8880 sec_child
, 100., 100.))
8881 g_print ("Failed to create svg image of graph.\n");
8882 gsf_output_close (sec_child
);
8883 g_object_unref (sec_child
);
8887 odf_update_progress (state
, progress
);
8889 fullname
= g_strdup_printf ("Pictures/%s.png", chartname
);
8890 sec_child
= gsf_outfile_new_child_full (state
->outfile
, fullname
, FALSE
,
8891 "compression-level", GSF_ZIP_DEFLATED
,
8893 if (NULL
!= sec_child
) {
8894 if (!gog_graph_export_image (graph
, GO_IMAGE_FORMAT_PNG
,
8895 sec_child
, 100., 100.))
8896 g_print ("Failed to create png image of graph.\n");
8897 gsf_output_close (sec_child
);
8898 g_object_unref (sec_child
);
8901 odf_update_progress (state
, progress
);
8904 chart_list
= chart_list
->next
;
8908 state
->object_name
= NULL
;
8913 /**********************************************************************************/
8916 openoffice_file_save_real (G_GNUC_UNUSED GOFileSaver
const *fs
, GOIOContext
*ioc
,
8917 WorkbookView
const *wbv
, GsfOutput
*output
,
8918 gboolean with_extension
)
8921 void (*func
) (GnmOOExport
*state
, GsfOutput
*child
);
8923 gboolean inhibit_compression
;
8924 } const streams
[] = {
8926 { odf_write_mimetype
, "mimetype", TRUE
},
8928 { odf_write_content
, "content.xml", FALSE
},
8929 { odf_write_styles
, "styles.xml", FALSE
}, /* must follow content */
8930 { odf_write_meta
, "meta.xml", FALSE
},
8931 { odf_write_settings
, "settings.xml", FALSE
},
8939 GsfOutput
*pictures
;
8940 GsfOutput
*manifest
;
8943 locale
= gnm_push_C_locale ();
8945 state
.outfile
= gsf_outfile_zip_new (output
, &err
);
8947 state
.with_extension
= with_extension
;
8948 state
.odf_version
= gsf_odf_get_version ();
8949 state
.odf_version_string
= g_strdup (gsf_odf_get_version_string ());
8952 state
.wb
= wb_view_get_workbook (wbv
);
8953 state
.conv
= odf_expr_conventions_new (&state
);
8954 state
.openformula_namemap
= NULL
;
8955 state
.openformula_handlermap
= NULL
;
8956 state
.graphs
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
8957 NULL
, (GDestroyNotify
) g_free
);
8958 state
.images
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
8959 NULL
, (GDestroyNotify
) g_free
);
8960 state
.controls
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
8961 NULL
, (GDestroyNotify
) g_free
);
8962 state
.named_cell_styles
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
8963 NULL
, (GDestroyNotify
) g_free
);
8964 state
.named_cell_style_regions
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
8965 (GDestroyNotify
) gnm_style_region_free
,
8966 (GDestroyNotify
) g_free
);
8967 state
.cell_styles
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
8968 NULL
, (GDestroyNotify
) g_free
);
8969 state
.so_styles
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
8970 NULL
, (GDestroyNotify
) g_free
);
8971 state
.xl_styles
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
8972 (GDestroyNotify
) g_free
, (GDestroyNotify
) g_free
);
8973 for (ui
= 0; ui
< G_N_ELEMENTS (state
.style_names
); ui
++)
8974 state
.style_names
[ui
] =
8975 g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
8976 NULL
, (GDestroyNotify
) g_free
);
8977 state
.graph_dashes
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
8978 (GDestroyNotify
) g_free
,
8980 state
.graph_hatches
= g_hash_table_new_full (g_direct_hash
,
8981 (GEqualFunc
)odf_match_pattern
,
8983 (GDestroyNotify
) g_free
);
8984 state
.graph_gradients
= g_hash_table_new_full (g_direct_hash
,
8985 (GEqualFunc
)odf_match_gradient
,
8987 (GDestroyNotify
) g_free
);
8988 state
.graph_fill_images
= g_hash_table_new_full (g_direct_hash
,
8989 (GEqualFunc
)odf_match_image
,
8991 (GDestroyNotify
) g_free
);
8992 state
.arrow_markers
= g_hash_table_new_full (g_direct_hash
,
8993 (GEqualFunc
)odf_match_arrow_markers
,
8994 (GDestroyNotify
) g_free
,
8995 (GDestroyNotify
) g_free
);
8996 state
.text_colours
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
8997 (GDestroyNotify
) g_free
,
8998 (GDestroyNotify
) g_free
);
8999 state
.font_sizes
= g_hash_table_new_full (g_str_hash
, g_str_equal
, (GDestroyNotify
) g_free
, NULL
);
9000 state
.col_styles
= NULL
;
9001 state
.row_styles
= NULL
;
9003 state
.date_long_fmt
= go_format_new_from_XL ("yyyy-mm-ddThh:mm:ss");
9004 state
.date_fmt
= go_format_new_from_XL ("yyyy-mm-dd");
9005 state
.time_fmt
= go_format_new_from_XL ("\"PT0\"[h]\"H\"mm\"M\"ss\"S\"");
9007 state
.fill_image_files
= NULL
;
9009 state
.last_progress
= 0;
9010 state
.sheet_progress
= ((float) PROGRESS_STEPS
) / 2 /
9011 (workbook_sheet_count (state
.wb
) + G_N_ELEMENTS (streams
));
9012 state
.graph_progress
= ((float) PROGRESS_STEPS
) / 2;
9013 go_io_progress_message (state
.ioc
, _("Writing Sheets..."));
9014 go_io_value_progress_set (state
.ioc
, PROGRESS_STEPS
, 0);
9018 /* ODF dos not have defaults per table, so we use our first table for defaults only.*/
9019 sheet
= workbook_sheet_by_index (state
.wb
, 0);
9021 state
.column_default
= &sheet
->cols
.default_style
;
9022 state
.row_default
= &sheet
->rows
.default_style
;
9023 if (NULL
!= (style
= sheet_style_default (sheet
))) {
9024 GnmRange r
= {{0,0},{0,0}};
9025 /* We need to make sure any referenced styles are added to the named hash */
9026 state
.default_style_region
= gnm_style_region_new (&r
, style
);
9027 odf_store_this_named_style (state
.default_style_region
->style
, "Gnumeric-default",
9028 &state
.default_style_region
->range
,
9030 gnm_style_unref (style
);
9032 GnmRange r
= {{0,0},{0,0}};
9033 state
.default_style_region
= gnm_style_region_new (&r
, NULL
);
9036 for (i
= 0 ; i
< G_N_ELEMENTS (streams
); i
++) {
9037 int comp_level
= streams
[i
].inhibit_compression
9040 GsfOutput
*child
= gsf_outfile_new_child_full
9041 (state
.outfile
, streams
[i
].name
, FALSE
,
9042 "compression-level", comp_level
,
9044 if (NULL
!= child
) {
9045 streams
[i
].func (&state
, child
);
9046 gsf_output_close (child
);
9047 g_object_unref (child
);
9049 odf_update_progress (&state
, state
.sheet_progress
);
9052 state
.graph_progress
= ((float) PROGRESS_STEPS
) / 2 /
9053 (8 * g_hash_table_size (state
.graphs
) + g_hash_table_size (state
.images
) + 1);
9054 go_io_progress_message (state
.ioc
, _("Writing Sheet Objects..."));
9056 pictures
= gsf_outfile_new_child_full (state
.outfile
, "Pictures", TRUE
,
9057 "compression-level", GSF_ZIP_DEFLATED
,
9059 gnm_hash_table_foreach_ordered
9061 (GHFunc
) odf_write_graphs
,
9064 gnm_hash_table_foreach_ordered
9066 (GHFunc
) odf_write_images
,
9069 if (NULL
!= pictures
) {
9070 gsf_output_close (pictures
);
9071 g_object_unref (pictures
);
9074 /* Need to write the manifest */
9075 manifest
= gsf_outfile_new_child_full
9076 (state
.outfile
, "META-INF/manifest.xml", FALSE
,
9077 "compression-level", GSF_ZIP_DEFLATED
,
9080 odf_write_manifest (&state
, manifest
);
9081 gsf_output_close (manifest
);
9082 g_object_unref (manifest
);
9084 /* Complain fiercely? */
9087 g_free (state
.conv
);
9088 if (state
.openformula_namemap
)
9089 g_hash_table_destroy (state
.openformula_namemap
);
9090 if (state
.openformula_handlermap
)
9091 g_hash_table_destroy (state
.openformula_handlermap
);
9093 go_io_value_progress_update (state
.ioc
, PROGRESS_STEPS
);
9094 go_io_progress_unset (state
.ioc
);
9095 gsf_output_close (GSF_OUTPUT (state
.outfile
));
9096 g_object_unref (state
.outfile
);
9098 g_free (state
.odf_version_string
);
9100 gnm_pop_C_locale (locale
);
9101 g_hash_table_unref (state
.graphs
);
9102 g_hash_table_unref (state
.images
);
9103 g_hash_table_unref (state
.controls
);
9104 g_hash_table_unref (state
.named_cell_styles
);
9105 g_hash_table_unref (state
.named_cell_style_regions
);
9106 g_hash_table_unref (state
.cell_styles
);
9107 g_hash_table_unref (state
.so_styles
);
9108 g_hash_table_unref (state
.xl_styles
);
9109 for (ui
= 0; ui
< G_N_ELEMENTS (state
.style_names
); ui
++)
9110 g_hash_table_unref (state
.style_names
[ui
]);
9111 g_hash_table_unref (state
.graph_dashes
);
9112 g_hash_table_unref (state
.graph_hatches
);
9113 g_hash_table_unref (state
.graph_gradients
);
9114 g_hash_table_unref (state
.graph_fill_images
);
9115 g_hash_table_unref (state
.arrow_markers
);
9116 g_hash_table_unref (state
.text_colours
);
9117 g_hash_table_unref (state
.font_sizes
);
9118 g_slist_free_full (state
.col_styles
, col_row_styles_free
);
9119 g_slist_free_full (state
.row_styles
, col_row_styles_free
);
9120 if (state
.default_style_region
)
9121 gnm_style_region_free (state
.default_style_region
);
9122 go_format_unref (state
.time_fmt
);
9123 go_format_unref (state
.date_fmt
);
9124 go_format_unref (state
.date_long_fmt
);
9126 ods_render_ops_clear (odf_render_ops
);
9127 ods_render_ops_clear (odf_render_ops_to_xl
);
9133 openoffice_file_save (GOFileSaver
const *fs
, GOIOContext
*ioc
,
9134 WorkbookView
const *wbv
, GsfOutput
*output
);
9136 G_MODULE_EXPORT
void
9137 openoffice_file_save (GOFileSaver
const *fs
, GOIOContext
*ioc
,
9138 WorkbookView
const *wbv
, GsfOutput
*output
)
9140 openoffice_file_save_real (fs
, ioc
, wbv
, output
, FALSE
);
9144 odf_file_save (GOFileSaver
const *fs
, GOIOContext
*ioc
,
9145 WorkbookView
const *wbv
, GsfOutput
*output
);
9147 G_MODULE_EXPORT
void
9148 odf_file_save (GOFileSaver
const *fs
, GOIOContext
*ioc
,
9149 WorkbookView
const *wbv
, GsfOutput
*output
)
9151 openoffice_file_save_real (fs
, ioc
, wbv
, output
, TRUE
);