[gnumeric] Improve chart export to ODF
- From: Andreas J. Guelzow <guelzow src gnome org>
- To: svn-commits-list gnome org
- Subject: [gnumeric] Improve chart export to ODF
- Date: Thu, 16 Jul 2009 03:09:38 +0000 (UTC)
commit 60dc5637404ae0e057a92436fc108c978c305dfc
Author: Andreas J. Guelzow <aguelzow pyrshep ca>
Date: Wed Jul 15 21:08:53 2009 -0600
Improve chart export to ODF
2009-07-15 Andreas J. Guelzow <aguelzow pyrshep ca>
* openoffice-read.c (od_style_prop_chart): handle
chart:reverse-direction, chart:symbol-type,
draw:stroke, chart:lines
(oo_chart_axis): in ODF proper the axis style should not affect
the overall graph.
(oo_plot_area): handle double series for Gantt charts
(oo_plot_area_end): ditto
(oo_plot_series): ditto
(oo_series_domain): handle dimensions for series:domain
(oo_chart_wall): hook-up to the correct element
* openoffice-write.c (odf_add_percent): new
(odf_write_frame): fix leak
(odf_write_series): handle more dimensions
(odf_write_gantt_series): new
(odf_write_bubble_series): new
(odf_write_ring_plot_style): new
(odf_write_line_chart_style): new
(odf_write_scatter_chart_style): new
(odf_write_scatter_series_style): new
(odf_write_axis_style): differentiate based on plot type
(odf_write_axis): ditto
(df_write_plot): handle more plot types
plugins/openoffice/ChangeLog | 25 ++
plugins/openoffice/openoffice-read.c | 248 ++++++++++++++-------
plugins/openoffice/openoffice-write.c | 389 ++++++++++++++++++++++++++++++---
3 files changed, 542 insertions(+), 120 deletions(-)
---
diff --git a/plugins/openoffice/ChangeLog b/plugins/openoffice/ChangeLog
index 2017c9d..8ada888 100644
--- a/plugins/openoffice/ChangeLog
+++ b/plugins/openoffice/ChangeLog
@@ -1,3 +1,28 @@
+2009-07-15 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+ * openoffice-read.c (od_style_prop_chart): handle
+ chart:reverse-direction, chart:symbol-type,
+ draw:stroke, chart:lines
+ (oo_chart_axis): in ODF proper the axis style should not affect
+ the overall graph.
+ (oo_plot_area): handle double series for Gantt charts
+ (oo_plot_area_end): ditto
+ (oo_plot_series): ditto
+ (oo_series_domain): handle dimensions for series:domain
+ (oo_chart_wall): hook-up to the correct element
+ * openoffice-write.c (odf_add_percent): new
+ (odf_write_frame): fix leak
+ (odf_write_series): handle more dimensions
+ (odf_write_gantt_series): new
+ (odf_write_bubble_series): new
+ (odf_write_ring_plot_style): new
+ (odf_write_line_chart_style): new
+ (odf_write_scatter_chart_style): new
+ (odf_write_scatter_series_style): new
+ (odf_write_axis_style): differentiate based on plot type
+ (odf_write_axis): ditto
+ (df_write_plot): handle more plot types
+
2009-07-13 Andreas J. Guelzow <aguelzow pyrshep ca>
* openoffice-read.c (od_draw_frame): use table:end-x and
diff --git a/plugins/openoffice/openoffice-read.c b/plugins/openoffice/openoffice-read.c
index ab26ef1..0a4b437 100644
--- a/plugins/openoffice/openoffice-read.c
+++ b/plugins/openoffice/openoffice-read.c
@@ -121,6 +121,8 @@ typedef enum {
OO_PLOT_SCATTER,
OO_PLOT_STOCK,
OO_PLOT_SURF,
+ OO_PLOT_BUBBLE,
+ OO_PLOT_GANTT,
OO_PLOT_UNKNOWN
} OOPlotType;
@@ -160,6 +162,7 @@ typedef struct {
int src_n_vectors;
GogSeries *series;
+ unsigned series_count; /* reset for each plotarea */
unsigned domain_count; /* reset for each series */
unsigned data_pt_count; /* reset for each series */
@@ -2864,7 +2867,7 @@ oo_prop_list_apply (GSList *props, GObject *obj)
for (ptr = props; ptr; ptr = ptr->next) {
prop = ptr->data;
if (NULL != g_object_class_find_property (klass, prop->name))
- g_object_set_property (obj, prop->name, &prop->value);
+ g_object_set_property (obj, prop->name, &prop->value);
}
}
@@ -2875,6 +2878,9 @@ od_style_prop_chart (GsfXMLIn *xin, xmlChar const **attrs)
OOChartStyle *style = state->chart.cur_graph_style;
gboolean btmp;
int tmp;
+ gboolean default_style_has_lines_set = FALSE;
+ gboolean draw_stroke_set = FALSE;
+ gboolean draw_stroke;
g_return_if_fail (style != NULL);
@@ -2889,6 +2895,9 @@ od_style_prop_chart (GsfXMLIn *xin, xmlChar const **attrs)
/* This is backwards from my intuition */
style->plot_props = g_slist_prepend (style->plot_props,
oo_prop_new_bool ("horizontal", btmp));
+ } else if (oo_attr_bool (xin, attrs, OO_NS_CHART, "reverse-direction", &btmp)) {
+ style->axis_props = g_slist_prepend (style->axis_props,
+ oo_prop_new_bool ("invert-axis", btmp));
} else if (oo_attr_bool (xin, attrs, OO_NS_CHART, "stacked", &btmp)) {
if (btmp)
style->plot_props = g_slist_prepend (style->plot_props,
@@ -2903,9 +2912,27 @@ od_style_prop_chart (GsfXMLIn *xin, xmlChar const **attrs)
} else if (oo_attr_int (xin, attrs, OO_NS_CHART, "gap-width", &tmp))
style->plot_props = g_slist_prepend (style->plot_props,
oo_prop_new_int ("gap-percentage", tmp));
- else if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), OO_NS_CHART, "series-source"))
+ else if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), OO_NS_CHART, "symbol-type"))
+ style->plot_props = g_slist_prepend
+ (style->plot_props,
+ oo_prop_new_bool ("default-style-has-markers",
+ !attr_eq (attrs[1], "none")));
+ else if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), OO_NS_DRAW, "stroke")) {
+ draw_stroke = !attr_eq (attrs[1], "none");
+ draw_stroke_set = TRUE;
+ } else if (oo_attr_bool (xin, attrs, OO_NS_CHART, "lines", &btmp)) {
+ style->plot_props = g_slist_prepend
+ (style->plot_props,
+ oo_prop_new_bool ("default-style-has-lines", btmp));
+ default_style_has_lines_set = TRUE;
+ } else if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), OO_NS_CHART, "series-source"))
style->src_in_rows = attr_eq (attrs[1], "rows");
}
+
+ if (draw_stroke_set && !default_style_has_lines_set)
+ style->plot_props = g_slist_prepend
+ (style->plot_props,
+ oo_prop_new_bool ("default-style-has-lines", draw_stroke));
}
static void
@@ -3309,11 +3336,83 @@ oo_chart_axis (GsfXMLIn *xin, xmlChar const **attrs)
/* AAARRRGGGHH : why would they do this. The axis style impact
* the plot ?? */
- if (NULL != state->chart.plot)
+ if (NULL != state->chart.plot && (state->ver == OOO_VER_1))
oo_prop_list_apply (style->plot_props, G_OBJECT (state->chart.plot));
}
}
+static int
+gog_series_map_dim (GogSeries const *series, GogMSDimType ms_type)
+{
+ GogSeriesDesc const *desc = &series->plot->desc.series;
+ unsigned i = desc->num_dim;
+
+ if (ms_type == GOG_MS_DIM_LABELS)
+ return -1;
+ while (i-- > 0)
+ if (desc->dim[i].ms_type == ms_type)
+ return i;
+ return -2;
+}
+/* If range == %NULL use an implicit range */
+static void
+oo_plot_assign_dim (GsfXMLIn *xin, xmlChar const *range, GogMSDimType dim_type)
+{
+ OOParseState *state = (OOParseState *)xin->user_state;
+
+ /* force relative to A1, not the containing cell */
+ GnmExprTop const *texpr;
+ GnmParsePos pp;
+ GnmValue *v;
+ int dim;
+
+ if (NULL == state->chart.series)
+ return;
+ dim = gog_series_map_dim (state->chart.series, dim_type);
+ if (dim < -1)
+ return;
+
+ if (NULL != range) {
+ GnmRangeRef ref;
+ char const *ptr = oo_rangeref_parse (&ref, CXML2C (range),
+ parse_pos_init_sheet (&pp, state->pos.sheet));
+ if (ptr == CXML2C (range))
+ return;
+ v = value_new_cellrange (&ref.a, &ref.b, 0, 0);
+#ifdef OO_DEBUG_OBJS
+ g_print ("%d = rangeref (%s)\n", dim, range);
+#endif
+ } else if (NULL != gog_dataset_get_dim (GOG_DATASET (state->chart.series), dim))
+ return; /* implicit does not overwrite existing */
+ else if (state->chart.src_n_vectors <= 0) {
+ oo_warning (xin,
+ "Not enough data in the supplied range for all the requests");
+ return;
+ } else {
+ v = value_new_cellrange_r (
+ state->chart.src_sheet,
+ &state->chart.src_range);
+
+#ifdef OO_DEBUG_OBJS
+ g_print ("%d = implicit (%s)\n", dim, range_as_string (&state->chart.src_range));
+#endif
+
+ state->chart.src_n_vectors--;
+ if (state->chart.src_in_rows)
+ state->chart.src_range.end.row = ++state->chart.src_range.start.row;
+ else
+ state->chart.src_range.end.col = ++state->chart.src_range.start.col;
+ }
+
+ texpr = gnm_expr_top_new_constant (v);
+ if (NULL != texpr)
+ gog_series_set_dim (state->chart.series, dim,
+ (dim_type != GOG_MS_DIM_LABELS)
+ ? gnm_go_data_vector_new_expr (state->pos.sheet, texpr)
+ : gnm_go_data_scalar_new_expr (state->pos.sheet, texpr),
+ NULL);
+}
+
static void
oo_plot_area (GsfXMLIn *xin, xmlChar const **attrs)
{
@@ -3345,6 +3444,8 @@ oo_plot_area (GsfXMLIn *xin, xmlChar const **attrs)
state->chart.src_n_vectors = -1;
state->chart.src_in_rows = TRUE;
+ state->chart.series = NULL;
+ state->chart.series_count = 0;
if (NULL != source_range_str) {
GnmParsePos pp;
GnmEvalPos ep;
@@ -3388,6 +3489,8 @@ oo_plot_area (GsfXMLIn *xin, xmlChar const **attrs)
case OO_PLOT_SCATTER: type = "GogXYPlot"; break;
case OO_PLOT_STOCK: type = "GogMinMaxPlot"; break;
case OO_PLOT_SURF: type = "GogContourPlot"; break;
+ case OO_PLOT_BUBBLE: type = "GogBubblePlot"; break;
+ case OO_PLOT_GANTT: type = "GogDropBarPlot"; break;
default: return;
}
@@ -3398,88 +3501,32 @@ oo_plot_area (GsfXMLIn *xin, xmlChar const **attrs)
style = l->data;
oo_prop_list_apply (style->plot_props, G_OBJECT (state->chart.plot));
}
+ if (state->chart.plot_type == OO_PLOT_GANTT) {
+ GogObject *yaxis = gog_object_get_child_by_name (GOG_OBJECT (state->chart.chart),
+ "Y-Axis");
+ if (yaxis != NULL) {
+ GValue *val = g_value_init (g_new0 (GValue, 1), G_TYPE_BOOLEAN);
+ g_value_set_boolean (val, TRUE);
+ g_object_set_property (G_OBJECT (yaxis), "invert-axis", val);
+ g_value_unset (val);
+ g_free (val);
+ }
+ }
}
static void
oo_plot_area_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
{
OOParseState *state = (OOParseState *)xin->user_state;
+ if (state->chart.series != NULL) {
+ oo_plot_assign_dim (xin, NULL, GOG_MS_DIM_VALUES);
+ state->chart.series = NULL;
+ }
state->chart.plot = NULL;
g_slist_free (state->chart.these_plot_styles);
state->chart.these_plot_styles = NULL;
}
-static int
-gog_series_map_dim (GogSeries const *series, GogMSDimType ms_type)
-{
- GogSeriesDesc const *desc = &series->plot->desc.series;
- unsigned i = desc->num_dim;
-
- if (ms_type == GOG_MS_DIM_LABELS)
- return -1;
- while (i-- > 0)
- if (desc->dim[i].ms_type == ms_type)
- return i;
- return -2;
-}
-/* If range == %NULL use an implicit range */
-static void
-oo_plot_assign_dim (GsfXMLIn *xin, xmlChar const *range, GogMSDimType dim_type)
-{
- OOParseState *state = (OOParseState *)xin->user_state;
-
- /* force relative to A1, not the containing cell */
- GnmExprTop const *texpr;
- GnmParsePos pp;
- GnmValue *v;
- int dim;
-
- if (NULL == state->chart.series)
- return;
- dim = gog_series_map_dim (state->chart.series, dim_type);
- if (dim < -1)
- return;
-
- if (NULL != range) {
- GnmRangeRef ref;
- char const *ptr = oo_rangeref_parse (&ref, CXML2C (range),
- parse_pos_init_sheet (&pp, state->pos.sheet));
- if (ptr == CXML2C (range))
- return;
- v = value_new_cellrange (&ref.a, &ref.b, 0, 0);
-#ifdef OO_DEBUG_OBJS
- g_print ("%d = rangeref (%s)\n", dim, range);
-#endif
- } else if (NULL != gog_dataset_get_dim (GOG_DATASET (state->chart.series), dim))
- return; /* implicit does not overwrite existing */
- else if (state->chart.src_n_vectors <= 0) {
- oo_warning (xin,
- "Not enough data in the supplied range for all the requests");
- return;
- } else {
- v = value_new_cellrange_r (
- state->chart.src_sheet,
- &state->chart.src_range);
-
-#ifdef OO_DEBUG_OBJS
- g_print ("%d = implicit (%s)\n", dim, range_as_string (&state->chart.src_range));
-#endif
-
- state->chart.src_n_vectors--;
- if (state->chart.src_in_rows)
- state->chart.src_range.end.row = ++state->chart.src_range.start.row;
- else
- state->chart.src_range.end.col = ++state->chart.src_range.start.col;
- }
-
- texpr = gnm_expr_top_new_constant (v);
- if (NULL != texpr)
- gog_series_set_dim (state->chart.series, dim,
- (dim_type != GOG_MS_DIM_LABELS)
- ? gnm_go_data_vector_new_expr (state->pos.sheet, texpr)
- : gnm_go_data_scalar_new_expr (state->pos.sheet, texpr),
- NULL);
-}
static void
oo_plot_series (GsfXMLIn *xin, xmlChar const **attrs)
@@ -3489,14 +3536,28 @@ oo_plot_series (GsfXMLIn *xin, xmlChar const **attrs)
#ifdef OO_DEBUG_OBJS
g_print ("<<<<< Start\n");
#endif
- state->chart.series = gog_plot_new_series (state->chart.plot);
+ state->chart.series_count++;
+ if (state->chart.series == NULL)
+ state->chart.series = gog_plot_new_series (state->chart.plot);
state->chart.domain_count = 0;
for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), OO_NS_CHART, "style"))
;
- else if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), OO_NS_CHART, "values-cell-range-address"))
- oo_plot_assign_dim (xin, attrs[1], GOG_MS_DIM_VALUES);
- else if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), OO_NS_CHART, "label-cell-address"))
+ else if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), OO_NS_CHART, "values-cell-range-address")) {
+ int dim;
+ switch (state->chart.plot_type) {
+ case OO_PLOT_GANTT:
+ dim = (state->chart.series_count % 2 == 1) ? GOG_MS_DIM_START : GOG_MS_DIM_END;
+ break;
+ case OO_PLOT_BUBBLE:
+ dim = GOG_MS_DIM_BUBBLES;
+ break;
+ default:
+ dim = GOG_MS_DIM_VALUES;
+ break;
+ }
+ oo_plot_assign_dim (xin, attrs[1], dim);
+ } else if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), OO_NS_CHART, "label-cell-address"))
oo_plot_assign_dim (xin, attrs[1], GOG_MS_DIM_LABELS);
}
@@ -3504,8 +3565,16 @@ static void
oo_plot_series_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
{
OOParseState *state = (OOParseState *)xin->user_state;
- oo_plot_assign_dim (xin, NULL, GOG_MS_DIM_VALUES);
- state->chart.series = NULL;
+
+ switch (state->chart.plot_type) {
+ case OO_PLOT_GANTT:
+ if ((state->chart.series_count % 2) != 0)
+ break;
+ default:
+ oo_plot_assign_dim (xin, NULL, GOG_MS_DIM_VALUES);
+ state->chart.series = NULL;
+ break;
+ }
#ifdef OO_DEBUG_OBJS
g_print (">>>>> end\n");
#endif
@@ -3521,9 +3590,11 @@ oo_series_domain (GsfXMLIn *xin, xmlChar const **attrs)
if (gsf_xml_in_namecmp (xin, CXML2C (attrs[0]), OO_NS_TABLE, "cell-range-address"))
src = attrs[1];
- oo_plot_assign_dim (xin, src, GOG_MS_DIM_CATEGORIES);
+ if (state->chart.plot_type == OO_PLOT_BUBBLE && (state->chart.domain_count == 0))
+ oo_plot_assign_dim (xin, src, GOG_MS_DIM_VALUES);
+ else
+ oo_plot_assign_dim (xin, src, GOG_MS_DIM_CATEGORIES);
-/* FIXME : Bubbles */
state->chart.domain_count++;
}
@@ -3548,6 +3619,8 @@ oo_chart (GsfXMLIn *xin, xmlChar const **attrs)
{ "chart:ring", OO_PLOT_RING },
{ "chart:scatter", OO_PLOT_SCATTER },
{ "chart:stock", OO_PLOT_STOCK },
+ { "chart:bubble", OO_PLOT_BUBBLE },
+ { "chart:gantt", OO_PLOT_GANTT },
{ NULL, 0 },
};
OOParseState *state = (OOParseState *)xin->user_state;
@@ -3634,7 +3707,12 @@ static void
oo_chart_wall (GsfXMLIn *xin, xmlChar const **attrs)
{
OOParseState *state = (OOParseState *)xin->user_state;
- gog_object_add_by_name (GOG_OBJECT (state->chart.chart), "Backplane", NULL);
+/* GOStyle *style = NULL; */
+/* GogObject *backplane; */
+
+ /* backplane = */gog_object_add_by_name (GOG_OBJECT (state->chart.chart), "Backplane", NULL);
+
+/* g_object_get (G_OBJECT (backplane), "style", &style, NULL); */
}
static void
@@ -4005,8 +4083,8 @@ static GsfXMLInNode const opendoc_content_dtd [] =
GSF_XML_IN_NODE (CHART_SERIES, SERIES_DOMAIN, OO_NS_CHART, "domain", GSF_XML_NO_CONTENT, &oo_series_domain, NULL),
GSF_XML_IN_NODE (CHART_SERIES, SERIES_DATA_PT, OO_NS_CHART, "data-point", GSF_XML_NO_CONTENT, &oo_series_pt, NULL),
GSF_XML_IN_NODE (CHART_SERIES, SERIES_DATA_ERR, OO_NS_CHART, "error-indicator", GSF_XML_NO_CONTENT, NULL, NULL),
- GSF_XML_IN_NODE (CHART_PLOT_AREA, CHART_WALL, OO_NS_CHART, "wall", GSF_XML_NO_CONTENT, NULL, NULL),
- GSF_XML_IN_NODE (CHART_PLOT_AREA, CHART_FLOOR, OO_NS_CHART, "floor", GSF_XML_NO_CONTENT, &oo_chart_wall, NULL),
+ GSF_XML_IN_NODE (CHART_PLOT_AREA, CHART_WALL, OO_NS_CHART, "wall", GSF_XML_NO_CONTENT, &oo_chart_wall, NULL),
+ GSF_XML_IN_NODE (CHART_PLOT_AREA, CHART_FLOOR, OO_NS_CHART, "floor", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (CHART_PLOT_AREA, CHART_AXIS, OO_NS_CHART, "axis", GSF_XML_NO_CONTENT, &oo_chart_axis, NULL),
GSF_XML_IN_NODE (CHART_AXIS, CHART_GRID, OO_NS_CHART, "grid", GSF_XML_NO_CONTENT, &oo_chart_grid, NULL),
GSF_XML_IN_NODE (CHART_AXIS, CHART_AXIS_CAT, OO_NS_CHART, "categories", GSF_XML_NO_CONTENT, NULL, NULL),
diff --git a/plugins/openoffice/openoffice-write.c b/plugins/openoffice/openoffice-write.c
index a39673b..cf8564a 100644
--- a/plugins/openoffice/openoffice-write.c
+++ b/plugins/openoffice/openoffice-write.c
@@ -382,6 +382,16 @@ odf_add_angle (GsfXMLOut *xml, char const *id, int val)
gsf_xml_out_add_int (xml, id, val);
}
+static void
+odf_add_percent (GsfXMLOut *xml, char const *id, double val)
+{
+ GString *str = g_string_new (NULL);
+
+ g_string_append_printf (str, "%.2f%%", val * 100.);
+ gsf_xml_out_add_cstr_unchecked (xml, id, str->str);
+ g_string_free (str, TRUE);
+}
+
static void
odf_add_pt (GsfXMLOut *xml, char const *id, float l)
@@ -2146,6 +2156,7 @@ odf_write_frame (GnmOOExport *state, SheetObject *so)
formula = gnm_expr_top_as_string (texpr, &pp, state->conv);
gnm_expr_top_unref (texpr);
gsf_xml_out_add_cstr (state->xml, TABLE "end-cell-address", odf_strip_brackets (formula));
+ g_free (formula);
if (IS_SHEET_OBJECT_GRAPH (so)) {
char const *name = g_hash_table_lookup (state->objects, so);
@@ -3146,21 +3157,54 @@ odf_write_manifest (GnmOOExport *state, GsfOutput *child)
}
/**********************************************************************************/
+typedef enum {
+ ODF_BARCOL,
+ ODF_LINE,
+ ODF_AREA,
+ ODF_DROPBAR,
+ ODF_MINMAX,
+ ODF_CIRCLE,
+ ODF_RADAR,
+ ODF_RADARAREA,
+ ODF_RING,
+ ODF_SCATTER,
+ ODF_SURF,
+ ODF_BUBBLE,
+ ODF_STOCK
+} odf_chart_type_t;
+
static void
odf_write_series (GnmOOExport *state, GSList const *series)
{
GnmParsePos pp;
+ int i;
parse_pos_init (&pp, WORKBOOK (state->wb), NULL, 0,0 );
- for ( ; NULL != series ; series = series->next) {
+ for (i = 1; NULL != series ; series = series->next, i++) {
GOData const *dat = gog_dataset_get_dim (GOG_DATASET (series->data), GOG_MS_DIM_VALUES);
if (NULL != dat) {
GnmExprTop const *texpr = gnm_go_data_get_expr (dat);
if (NULL != texpr) {
char *str = gnm_expr_top_as_string (texpr, &pp, state->conv);
+ GOData const *cat = gog_dataset_get_dim (GOG_DATASET (series->data), GOG_MS_DIM_LABELS);
gsf_xml_out_start_element (state->xml, CHART "series");
gsf_xml_out_add_cstr (state->xml, CHART "values-cell-range-address",
odf_strip_brackets (str));
+ g_free (str);
+ str = g_strdup_printf ("series%i", i);
+ gsf_xml_out_add_cstr (state->xml, CHART "style-name", str);
+ g_free (str);
+ if (NULL != cat) {
+ texpr = gnm_go_data_get_expr (cat);
+ if (NULL != texpr) {
+ str = gnm_expr_top_as_string (texpr, &pp, state->conv);
+ gsf_xml_out_start_element (state->xml, CHART "domain");
+ gsf_xml_out_add_cstr (state->xml, TABLE "cell-range-address",
+ odf_strip_brackets (str));
+ gsf_xml_out_end_element (state->xml); /* </chart:domain> */
+ g_free (str);
+ }
+ }
gsf_xml_out_end_element (state->xml); /* </chart:series> */
}
}
@@ -3168,11 +3212,107 @@ odf_write_series (GnmOOExport *state, GSList const *series)
}
static void
-odf_write_bar_col_plot_style (GnmOOExport *state, GogObject const *chart, GogObject const *plot)
+odf_write_gantt_series (GnmOOExport *state, GSList const *series)
+{
+ GnmParsePos pp;
+ int i;
+ parse_pos_init (&pp, WORKBOOK (state->wb), NULL, 0,0 );
+
+ for (i = 1; NULL != series ; series = series->next, i++) {
+ GOData const *dat = gog_dataset_get_dim (GOG_DATASET (series->data), GOG_MS_DIM_VALUES);
+ if (NULL != dat) {
+ GnmExprTop const *texpr = gnm_go_data_get_expr (dat);
+ if (NULL != texpr) {
+ char *str = gnm_expr_top_as_string (texpr, &pp, state->conv);
+ GOData const *cat = gog_dataset_get_dim (GOG_DATASET (series->data), GOG_MS_DIM_LABELS);
+ gsf_xml_out_start_element (state->xml, CHART "series");
+ gsf_xml_out_add_cstr (state->xml, CHART "values-cell-range-address",
+ odf_strip_brackets (str));
+ g_free (str);
+ str = g_strdup_printf ("series%i", i);
+ gsf_xml_out_add_cstr (state->xml, CHART "style-name", str);
+ g_free (str);
+ if (NULL != cat) {
+ texpr = gnm_go_data_get_expr (cat);
+ if (NULL != texpr) {
+ str = gnm_expr_top_as_string (texpr, &pp, state->conv);
+ gsf_xml_out_start_element (state->xml, CHART "domain");
+ gsf_xml_out_add_cstr (state->xml, TABLE "cell-range-address",
+ odf_strip_brackets (str));
+ gsf_xml_out_end_element (state->xml); /* </chart:domain> */
+ g_free (str);
+ }
+ }
+ gsf_xml_out_end_element (state->xml); /* </chart:series> */
+ }
+ }
+ dat = gog_dataset_get_dim (GOG_DATASET (series->data), GOG_MS_DIM_CATEGORIES);
+ if (NULL != dat) {
+ GnmExprTop const *texpr = gnm_go_data_get_expr (dat);
+ if (NULL != texpr) {
+ char *str = gnm_expr_top_as_string (texpr, &pp, state->conv);
+ gsf_xml_out_start_element (state->xml, CHART "series");
+ gsf_xml_out_add_cstr (state->xml, CHART "values-cell-range-address",
+ odf_strip_brackets (str));
+ g_free (str);
+ str = g_strdup_printf ("series%i", i);
+ gsf_xml_out_add_cstr (state->xml, CHART "style-name", str);
+ g_free (str);
+ gsf_xml_out_end_element (state->xml); /* </chart:series> */
+ }
+ }
+ }
+}
+
+static void
+odf_write_bubble_series (GnmOOExport *state, GSList const *orig_series)
+{
+ GnmParsePos pp;
+ int i;
+ GSList const *series;
+ parse_pos_init (&pp, WORKBOOK (state->wb), NULL, 0,0 );
+
+ gsf_xml_out_start_element (state->xml, CHART "series");
+ for (series = orig_series, i = 0; NULL != series; series = series->next, i++) {
+ GOData const *dat = gog_dataset_get_dim (GOG_DATASET (series->data), 2);
+
+ if (NULL != dat) {
+ GnmExprTop const *texpr = gnm_go_data_get_expr (dat);
+ if (NULL != texpr) {
+ char *str = gnm_expr_top_as_string (texpr, &pp, state->conv);
+ gsf_xml_out_add_cstr (state->xml, CHART "values-cell-range-address",
+ odf_strip_brackets (str));
+ g_free (str);
+ str = g_strdup_printf ("series%i", i);
+ gsf_xml_out_add_cstr (state->xml, CHART "style-name", str);
+ g_free (str);
+ break;
+ }
+ }
+ }
+ for (i = 1; i >= 0; i--)
+ for (series = orig_series; NULL != series ; series = series->next) {
+ GOData const *dat = gog_dataset_get_dim (GOG_DATASET (series->data), i);
+ if (NULL != dat) {
+ GnmExprTop const *texpr = gnm_go_data_get_expr (dat);
+ if (NULL != texpr) {
+ char *str = gnm_expr_top_as_string (texpr, &pp, state->conv);
+ gsf_xml_out_start_element (state->xml, CHART "domain");
+ gsf_xml_out_add_cstr (state->xml, TABLE "cell-range-address",
+ odf_strip_brackets (str));
+ gsf_xml_out_end_element (state->xml); /* </chart:domain> */
+ g_free (str);
+ break;
+ }
+ }
+ }
+ gsf_xml_out_end_element (state->xml); /* </chart:series> */
+}
+
+static void
+odf_write_bar_col_plot_style (GnmOOExport *state, G_GNUC_UNUSED GogObject const *chart, GogObject const *plot)
{
gboolean horizontal = FALSE;
- if (plot == NULL)
- return;
g_object_get (G_OBJECT (plot), "horizontal", &horizontal, NULL);
/* Note: horizontal refers to the bars and vertical to the x-axis */
@@ -3180,8 +3320,35 @@ odf_write_bar_col_plot_style (GnmOOExport *state, GogObject const *chart, GogObj
}
static void
+odf_write_ring_plot_style (GnmOOExport *state, G_GNUC_UNUSED GogObject const *chart, G_GNUC_UNUSED GogObject const *plot)
+{
+ odf_add_percent (state->xml, CHART "hole-size", 0.5);
+}
+
+static void
+odf_write_line_chart_style (GnmOOExport *state, G_GNUC_UNUSED GogObject const *chart, G_GNUC_UNUSED GogObject const *plot)
+{
+ gsf_xml_out_add_cstr (state->xml, CHART "symbol-type", "none");
+}
+
+static void
+odf_write_scatter_chart_style (GnmOOExport *state, G_GNUC_UNUSED GogObject const *chart, G_GNUC_UNUSED GogObject const *plot)
+{
+ gsf_xml_out_add_cstr (state->xml, DRAW "stroke", "none");
+ odf_add_bool (state->xml, CHART "lines", FALSE);
+}
+
+static void
+odf_write_scatter_series_style (GnmOOExport *state, G_GNUC_UNUSED GogObject const *series)
+{
+ gsf_xml_out_add_cstr (state->xml, DRAW "stroke", "none");
+ odf_add_bool (state->xml, CHART "lines", FALSE);
+ gsf_xml_out_add_cstr (state->xml, CHART "symbol-type", "automatic");
+}
+
+static void
odf_write_axis_style (GnmOOExport *state, GogObject const *chart, char const *axis_role,
- char const *style_label)
+ char const *style_label, odf_chart_type_t gtype)
{
GogObject const *axis = gog_object_get_child_by_name (chart, axis_role);
if (axis != NULL) {
@@ -3194,12 +3361,46 @@ odf_write_axis_style (GnmOOExport *state, GogObject const *chart, char const *ax
g_object_get (G_OBJECT (axis), "map-name", &type, NULL);
odf_add_bool (state->xml, CHART "logarithmic", 0 != strcmp (type, "Linear"));
gsf_xml_out_add_cstr (state->xml, CHART "axis-position", "start");
+ odf_add_bool (state->xml, CHART "display-label", TRUE);
if (gog_axis_get_bounds (GOG_AXIS (axis), &minima, &maxima)) {
gsf_xml_out_add_float (state->xml, CHART "minimum", minima, -1);
gsf_xml_out_add_float (state->xml, CHART "maximum", maxima, -1);
}
+ if (get_gsf_odf_version () > 101)
+ switch (gtype) {
+ case ODF_CIRCLE:
+ odf_add_bool (state->xml, CHART "reverse-direction", TRUE);
+ break;
+ case ODF_RING:
+ odf_add_bool (state->xml, CHART "reverse-direction",
+ *style_label == 'y' );
+ break;
+ case ODF_DROPBAR:
+ odf_add_bool (state->xml, CHART "reverse-direction",
+ *style_label == 'x' && *axis_role == 'Y');
+ break;
+ default:
+ break;
+ }
+ gsf_xml_out_end_element (state->xml); /* </style:chart-properties> */
+ gsf_xml_out_end_element (state->xml); /* </style:style> */
+ } else if (gtype == ODF_CIRCLE || gtype == ODF_RING) {
+ odf_start_style (state->xml, style_label, "chart");
+ gsf_xml_out_start_element (state->xml, STYLE "chart-properties");
+ if (get_gsf_odf_version () > 101)
+ switch (gtype) {
+ case ODF_CIRCLE:
+ odf_add_bool (state->xml, CHART "reverse-direction", TRUE);
+ break;
+ case ODF_RING:
+ odf_add_bool (state->xml, CHART "reverse-direction",
+ *style_label == 'y' );
+ break;
+ default:
+ break;
+ }
gsf_xml_out_end_element (state->xml); /* </style:chart-properties> */
gsf_xml_out_end_element (state->xml); /* </style:style> */
}
@@ -3207,10 +3408,10 @@ odf_write_axis_style (GnmOOExport *state, GogObject const *chart, char const *ax
static void
odf_write_axis (GnmOOExport *state, GogObject const *chart, char const *axis_role, char const *style_label,
- char const *dimension)
+ char const *dimension, odf_chart_type_t gtype)
{
GogObject const *axis = gog_object_get_child_by_name (chart, axis_role);
- if (axis != NULL) {
+ if (axis != NULL || (gtype == ODF_CIRCLE && *dimension == 'y') || (gtype == ODF_RING)) {
gsf_xml_out_start_element (state->xml, CHART "axis");
gsf_xml_out_add_cstr (state->xml, CHART "dimension", dimension);
gsf_xml_out_add_cstr (state->xml, CHART "style-name", style_label);
@@ -3219,89 +3420,179 @@ odf_write_axis (GnmOOExport *state, GogObject const *chart, char const *axis_rol
}
static void
-odf_write_plot (GnmOOExport *state, GogObject const *chart, GogObject const *plot)
+odf_write_plot (GnmOOExport *state, SheetObject *so, GogObject const *chart, GogObject const *plot)
{
-
- enum {
- ODF_BARCOL,
- ODF_LINE,
- ODF_AREA,
- ODF_DROPBAR,
- ODF_MINMAX,
- ODF_CIRCLE,
- ODF_RADAR,
- ODF_RADARAREA,
- ODF_RING,
- ODF_SCATTER,
- ODF_SURF,
- ODF_STOCK
- } gtype;
+ odf_chart_type_t gtype;
char const *plot_type = G_OBJECT_TYPE_NAME (plot);
char const *odf_plot_type;
+ SheetObjectAnchor const *anchor = sheet_object_get_anchor (so);
+ double res_pts[4] = {0.,0.,0.,0.};
+ double pad = 4.;
+ gboolean horizontal = FALSE;
+ GSList const *series, *l;
+ int i;
+ GogObject *wall = gog_object_get_child_by_name (plot, "Backplane");
if (0 == strcmp (plot_type, "GogBarColPlot")) {
gtype = ODF_BARCOL;
odf_plot_type = "chart:bar";
+ pad = 20.;
} else if (0 == strcmp (plot_type, "GogLinePlot")) {
gtype = ODF_LINE;
odf_plot_type = "chart:line";
+ pad = 20.;
} else if (0 == strcmp (plot_type, "GogAreaPlot")) {
gtype = ODF_AREA;
odf_plot_type = "chart:area";
+ pad = 20.;
} else if (0 == strcmp (plot_type, "GogDropBarPlot")) {
gtype = ODF_DROPBAR;
- odf_plot_type = "chart:bar";
+ odf_plot_type = "chart:gantt";
+ pad = 20.;
} else if (0 == strcmp (plot_type, "GogMinMaxPlot")) {
gtype = ODF_STOCK;
odf_plot_type = "chart:stock";
+ pad = 10.;
} else if (0 == strcmp (plot_type, "GogPiePlot")) {
gtype = ODF_CIRCLE;
odf_plot_type = "chart:circle";
+ pad = 5.;
} else if (0 == strcmp (plot_type, "GogRadarPlot")) {
gtype = ODF_RADAR;
odf_plot_type = "chart:radar";
+ pad = 10.;
} else if (0 == strcmp (plot_type, "GogRadarAreaPlot")) {
gtype = ODF_RADARAREA;
odf_plot_type = "chart:radararea";
+ pad = 10.;
} else if (0 == strcmp (plot_type, "GogRingPlot")) {
gtype = ODF_RING;
odf_plot_type = "chart:ring";
+ pad = 10.;
} else if (0 == strcmp (plot_type, "GogXYPlot")) {
gtype = ODF_SCATTER;
odf_plot_type = "chart:scatter";
+ pad = 20.;
} else if (0 == strcmp (plot_type, "GogContourPlot")) {
gtype = ODF_SURF;
odf_plot_type = "chart:surface";
+ pad = 20.;
+ } else if (0 == strcmp (plot_type, "GogXYZContourPlot")) {
+ gtype = ODF_SURF;
+ odf_plot_type = "chart:surface";
+ pad = 20.;
+ } else if (0 == strcmp (plot_type, "GogBubblePlot")) {
+ gtype = ODF_BUBBLE;
+ odf_plot_type = "chart:bubble";
+ pad = 20.;
} else {
g_print ("encountered unknown chart type %s\n", plot_type);
gtype = ODF_BARCOL;
- odf_plot_type = "GogBarColPlot";
+ odf_plot_type = "chart:bar";
}
+ series = gog_plot_get_series (GOG_PLOT (plot));
+
gsf_xml_out_start_element (state->xml, OFFICE "automatic-styles");
- odf_write_axis_style (state, chart, "Y-Axis", "yaxis");
- odf_write_axis_style (state, chart, "X-Axis", "xaxis");
+
+ switch (gtype) {
+ case ODF_RADAR:
+ odf_write_axis_style (state, chart, "Radial-Axis", "yaxis", gtype);
+ odf_write_axis_style (state, chart, "Circular-Axis", "xaxis", gtype);
+ break;
+ case ODF_BARCOL:
+ case ODF_DROPBAR:
+ g_object_get (G_OBJECT (plot), "horizontal", &horizontal, NULL);
+ odf_write_axis_style (state, chart, "Y-Axis", horizontal ? "xaxis" : "yaxis", gtype);
+ odf_write_axis_style (state, chart, "X-Axis", horizontal ? "yaxis" : "xaxis", gtype);
+ break;
+ default:
+ odf_write_axis_style (state, chart, "Y-Axis", "yaxis", gtype);
+ odf_write_axis_style (state, chart, "X-Axis", "xaxis", gtype);
+ break;
+ }
+
odf_start_style (state->xml, "plotstyle", "chart");
gsf_xml_out_start_element (state->xml, STYLE "chart-properties");
+ odf_add_bool (state->xml, CHART "auto-size", TRUE);
- if (gtype == ODF_BARCOL)
- odf_write_bar_col_plot_style (state, chart, plot);
+ switch (gtype) {
+ case ODF_SCATTER:
+ odf_write_scatter_chart_style (state, chart, plot);
+ break;
+ case ODF_LINE:
+ odf_write_line_chart_style (state, chart, plot);
+ break;
+ default:
+ break;
+ }
gsf_xml_out_end_element (state->xml); /* </style:chart-properties> */
gsf_xml_out_end_element (state->xml); /* </style:style> */
+
+ odf_start_style (state->xml, "plotarea", "chart");
+ gsf_xml_out_start_element (state->xml, STYLE "chart-properties");
+ odf_add_bool (state->xml, CHART "auto-size", TRUE);
+
+ switch (gtype) {
+ case ODF_BARCOL:
+ case ODF_DROPBAR:
+ odf_write_bar_col_plot_style (state, chart, plot);
+ break;
+ case ODF_RING:
+ odf_write_ring_plot_style (state, chart, plot);
+ break;
+ default:
+ break;
+ }
+
+ gsf_xml_out_end_element (state->xml); /* </style:chart-properties> */
+ gsf_xml_out_end_element (state->xml); /* </style:style> */
+
+ for (l = series, i = 1; l != NULL; l = l->next) {
+ char *name = g_strdup_printf ("series%i", i++);
+ odf_start_style (state->xml, name, "chart");
+ gsf_xml_out_start_element (state->xml, STYLE "chart-properties");
+ odf_add_bool (state->xml, CHART "auto-size", TRUE);
+ switch (gtype) {
+ case ODF_SCATTER:
+ odf_write_scatter_series_style (state, l->data);
+ break;
+ default:
+ break;
+ }
+ gsf_xml_out_end_element (state->xml); /* </style:chart-properties> */
+ gsf_xml_out_end_element (state->xml); /* </style:style> */
+ g_free (name);
+ }
+
+ if (wall != NULL) {
+ odf_start_style (state->xml, "wallstyle", "chart");
+ gsf_xml_out_start_element (state->xml, STYLE "graphic-properties");
+ gsf_xml_out_add_cstr (state->xml, DRAW "fill", "solid");
+/* gnm_xml_out_add_hex_color (state->xml, DRAW "fill-color", GnmColor const *c) */
+ gsf_xml_out_add_cstr (state->xml, DRAW "fill-color", "#D0D0D0");
+ gsf_xml_out_end_element (state->xml); /* </style:graphic-properties> */
+ gsf_xml_out_end_element (state->xml); /* </style:style> */
+ }
+
gsf_xml_out_end_element (state->xml); /* </office:automatic-styles> */
gsf_xml_out_start_element (state->xml, OFFICE "body");
gsf_xml_out_start_element (state->xml, OFFICE "chart");
gsf_xml_out_start_element (state->xml, CHART "chart");
+
+ sheet_object_anchor_to_pts (anchor, state->sheet, res_pts);
+ odf_add_pt (state->xml, SVG "width", res_pts[2] - res_pts[0] - 2 * pad);
+ odf_add_pt (state->xml, SVG "height", res_pts[3] - res_pts[1] - 2 * pad);
+
if (get_gsf_odf_version () > 101)
gsf_xml_out_add_cstr (state->xml, XLINK "href", "..");
gsf_xml_out_add_cstr (state->xml, CHART "class", odf_plot_type);
gsf_xml_out_add_cstr (state->xml, CHART "style-name", "plotstyle");
gsf_xml_out_start_element (state->xml, CHART "plot-area");
- gsf_xml_out_add_cstr (state->xml, CHART "style-name", "plotstyle");
+ gsf_xml_out_add_cstr (state->xml, CHART "style-name", "plotarea");
if (get_gsf_odf_version () <= 101) {
- GSList const *series = gog_plot_get_series (GOG_PLOT (plot));
for ( ; NULL != series ; series = series->next) {
GOData const *dat = gog_dataset_get_dim
(GOG_DATASET (series->data), GOG_MS_DIM_VALUES);
@@ -3314,14 +3605,42 @@ odf_write_plot (GnmOOExport *state, GogObject const *chart, GogObject const *plo
str = gnm_expr_top_as_string (texpr, &pp, state->conv);
gsf_xml_out_add_cstr (state->xml, TABLE "cell-range-address",
odf_strip_brackets (str));
+ g_free (str);
break;
}
}
}
}
- odf_write_axis (state, chart, "Y-Axis", "yaxis", "y");
- odf_write_axis (state, chart, "X-Axis", "xaxis", "x");
- odf_write_series (state, gog_plot_get_series (GOG_PLOT (plot)));
+
+ switch (gtype) {
+ case ODF_RADAR:
+ odf_write_axis (state, chart, "Radial-Axis", "yaxis", "y", gtype);
+ odf_write_axis (state, chart, "Circular-Axis", "xaxis", "x", gtype);
+ odf_write_series (state, series);
+ break;
+ case ODF_BUBBLE:
+ odf_write_axis (state, chart, "Y-Axis", "yaxis", "y", gtype);
+ odf_write_axis (state, chart, "X-Axis", "xaxis", "x", gtype);
+ odf_write_bubble_series (state, series);
+ break;
+ case ODF_DROPBAR:
+ odf_write_axis (state, chart, "Y-Axis", "yaxis", "y", gtype);
+ odf_write_axis (state, chart, "X-Axis", "xaxis", "x", gtype);
+ odf_write_gantt_series (state, series);
+ break;
+ default:
+ odf_write_axis (state, chart, "Y-Axis", "yaxis", "y", gtype);
+ odf_write_axis (state, chart, "X-Axis", "xaxis", "x", gtype);
+ odf_write_series (state, series);
+ break;
+ }
+
+ if (wall != NULL) {
+ gsf_xml_out_start_element (state->xml, CHART "wall");
+ odf_add_pt (state->xml, SVG "width", res_pts[2] - res_pts[0] - 2 * pad);
+ gsf_xml_out_add_cstr (state->xml, CHART "style-name", "wallstyle");
+ gsf_xml_out_end_element (state->xml); /* </chart:wall> */
+ }
gsf_xml_out_end_element (state->xml); /* </chart:plot_area> */
gsf_xml_out_end_element (state->xml); /* </chart:chart> */
gsf_xml_out_end_element (state->xml); /* </office:chart> */
@@ -3350,7 +3669,7 @@ odf_write_graph_content (GnmOOExport *state, GsfOutput *child, SheetObject *so)
if (chart != NULL) {
GogObject const *plot = gog_object_get_child_by_name (GOG_OBJECT (chart), "Plot");
if (plot != NULL)
- odf_write_plot (state, chart, plot);
+ odf_write_plot (state, so, chart, plot);
}
}
gsf_xml_out_end_element (state->xml); /* </office:document-content> */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]