[gnumeric] .gnumeric: For clipboards, send also result values.



commit b661dc33ce85adc2f1babd797ffd58bad73cc10d
Author: Morten Welinder <terra gnome org>
Date:   Fri Apr 20 14:19:40 2018 -0400

    .gnumeric: For clipboards, send also result values.

 ChangeLog           |    8 ++
 src/xml-sax-read.c  |  227 ++++++++++++++++++++++++++++-----------------------
 src/xml-sax-write.c |   19 ++++-
 3 files changed, 148 insertions(+), 106 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index acb2407..c98a92e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2018-04-20  Morten Welinder  <terra gnome org>
+
+       * src/xml-sax-write.c (xml_write_cell_and_position): In the
+       clipboard case, write result values too.
+
+       * src/xml-sax-read.c (xml_sax_cell_content): Rework this rat's
+       nest of conditionals.  Accept values for expressions.
+
 2018-04-18  Morten Welinder  <terra gnome org>
 
        * src/mstyle.c (gnm_style_get_cond_style): Flip reversed
diff --git a/src/xml-sax-read.c b/src/xml-sax-read.c
index 22f3224..ea515d3 100644
--- a/src/xml-sax-read.c
+++ b/src/xml-sax-read.c
@@ -299,6 +299,13 @@ xml_sax_attr_range (xmlChar const * const *attrs, GnmRange *res)
 
 /*****************************************************************************/
 
+typedef enum {
+       READ_FULL_FILE,
+       READ_CLIPBOARD,
+       READ_STYLE
+} ReadFileWhat;
+
+
 typedef struct {
        GsfXMLIn base;
 
@@ -349,6 +356,7 @@ typedef struct {
        int expr_id, array_rows, array_cols;
        int value_type;
        GOFormat *value_fmt;
+       char *value_result;
 
        GnmScenario *scenario;
        GnmValue *scenario_range;
@@ -1946,6 +1954,7 @@ xml_sax_cell (GsfXMLIn *xin, xmlChar const **attrs)
        int value_type = -1;
        GOFormat *value_fmt = NULL;
        int expr_id = -1;
+       const char *value_result = NULL;
 
        g_return_if_fail (state->cell.row == -1);
        g_return_if_fail (state->cell.col == -1);
@@ -1953,6 +1962,7 @@ xml_sax_cell (GsfXMLIn *xin, xmlChar const **attrs)
        g_return_if_fail (state->array_cols == -1);
        g_return_if_fail (state->expr_id == -1);
        g_return_if_fail (state->value_type == -1);
+       g_return_if_fail (state->value_result == NULL);
 
        for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
                if (gnm_xml_attr_int (attrs, "Col", &col)) ;
@@ -1961,12 +1971,19 @@ xml_sax_cell (GsfXMLIn *xin, xmlChar const **attrs)
                else if (gnm_xml_attr_int (attrs, "Rows", &rows)) ;
                else if (gnm_xml_attr_int (attrs, "ExprID", &expr_id)) ;
                else if (gnm_xml_attr_int (attrs, "ValueType", &value_type)) ;
-               else if (attr_eq (attrs[0], "ValueFormat"))
+               else if (attr_eq (attrs[0], "Value"))
+                       value_result = CXML2C (attrs[1]);
+               else if (attr_eq (attrs[0], "ValueFormat")) {
+                       if (value_fmt) go_format_unref (value_fmt);
                        value_fmt = make_format (CXML2C (attrs[1]));
-               else
+               } else
                        unknown_attr (xin, attrs);
        }
 
+       // Ignore value_result absent a type
+       if (value_type == -1)
+               value_result = NULL;
+
        XML_CHECK2 (col >= 0 && col < gnm_sheet_get_max_cols (sheet),
                    go_format_unref (value_fmt));
        XML_CHECK2 (row >= 0 && row < gnm_sheet_get_max_rows (sheet),
@@ -1986,6 +2003,7 @@ xml_sax_cell (GsfXMLIn *xin, xmlChar const **attrs)
        state->expr_id = expr_id;
        state->value_type = value_type;
        state->value_fmt = value_fmt;
+       state->value_result = g_strdup (value_result);
 }
 
 /*
@@ -2087,6 +2105,11 @@ xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
        GnmCell *cell = NULL; /* Regular case */
        GnmCellCopy *cc = NULL; /* Clipboard case */
        GnmCellRegion *cr = state->clipboard;
+       GnmExprTop const *texpr = NULL;
+       GnmValue *v = NULL;
+       char const *content = xin->content->str;
+       gboolean has_contents = (xin->content->len > 0);
+       const char *expr_start = gnm_expr_char_start_p (content);
 
        int const col = state->cell.col;
        int const row = state->cell.row;
@@ -2096,6 +2119,7 @@ xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
        int const value_type = state->value_type;
        gboolean const seen_contents = state->seen_cell_contents;
        GOFormat *value_fmt = state->value_fmt;
+       char *value_result = state->value_result;
 
        /* Clean out the state before any error checking */
        state->cell.row = state->cell.col = -1;
@@ -2103,6 +2127,7 @@ xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
        state->expr_id = -1;
        state->value_type = -1;
        state->value_fmt = NULL;
+       state->value_result = NULL;
        state->seen_cell_contents = strcmp (xin->node->id, "CELL_CONTENT") == 0;
 
        if (seen_contents)
@@ -2129,87 +2154,31 @@ xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
                parse_pos_init_cell (&pos, cell);
        }
 
+       // ----------------------------------------
+
        is_post_52_array = (array_cols > 0) && (array_rows > 0);
+       if (is_post_52_array && has_contents) {
+               // Array formula
+               g_return_if_fail (content[0] == '=');
+               xml_cell_set_array_expr (state, cell, cc, content + 1,
+                                        array_cols, array_rows);
+               goto done;
+       }
 
-       if (xin->content->len > 0) {
-               char const * content = xin->content->str;
+       // ----------------------------------------
 
-               if (is_post_52_array) {
-                       g_return_if_fail (content[0] == '=');
-
-                       xml_cell_set_array_expr (state, cell, cc, content+1,
-                                                array_cols, array_rows);
-               } else if (state->version >= GNM_XML_V3 ||
-                          xml_not_used_old_array_spec (state, cell, cc, content)) {
-                       if (value_type > 0) {
-                               GnmValue *v = value_new_from_string (value_type, content, value_fmt, FALSE);
-                               if (v == NULL) {
-                                       char *msg = g_strdup_printf
-                                               ("Parsing \"%s\" as type 0x%x",
-                                                content, value_type);
-                                       xml_sax_barf (G_STRFUNC, msg);
-                                       g_free (msg);
-                                       v = value_new_string (content);
-                               }
-                               if (cell)
-                                       gnm_cell_set_value (cell, v);
-                               else
-                                       cc->val = v;
-                       } else {
-                               const char *expr_start = gnm_expr_char_start_p (content);
-                               if (expr_start && *expr_start) {
-                                       GnmParseError perr;
-                                       GnmExprTop const *texpr;
-
-                                       parse_error_init (&perr);
-                                       texpr = gnm_expr_parse_str (expr_start,
-                                                                   &pos,
-                                                                   GNM_EXPR_PARSE_DEFAULT,
-                                                                   state->convs,
-                                                                   &perr);
-                                       if (!texpr) {
-                                               g_warning ("Unparsable expression for %s: %s (%s)\n",
-                                                          cell ? cell_name (cell) : "-",
-                                                          content,
-                                                          perr.err->message);
-                                               texpr = gnm_expr_top_new_constant (value_new_string 
(expr_start));
-                                       }
-                                       if (cell) {
-                                               gnm_cell_set_expr (cell, texpr);
-                                               gnm_expr_top_unref (texpr);
-                                       } else if (texpr)
-                                               cc->texpr = texpr;
-                                       parse_error_free (&perr);
-                               } else if (cell)
-                                       gnm_cell_set_text (cell, content);
-                               else
-                                       cc->val = value_new_string (content);
-                       }
-               }
+       if (has_contents && state->version < GNM_XML_V3 &&
+           !xml_not_used_old_array_spec (state, cell, cc, content)) {
+               // Very old array syntax -- irrelevant
+               goto done;
+       }
 
-               if (expr_id > 0) {
-                       gpointer id = GINT_TO_POINTER (expr_id);
-                       GnmExprTop const *texpr =
-                               g_hash_table_lookup (state->expr_map, id);
-                       if (texpr == NULL) {
-                               if (cc)
-                                       texpr = cc->texpr;
-                               else if (gnm_cell_has_expr (cell)) {
-                                       texpr = cell->base.texpr;
-                               } else
-                                       g_warning ("XML-IO : Shared expression with no expression ??");
-                               if (texpr) {
-                                       gnm_expr_top_ref (texpr);
-                                       g_hash_table_insert (state->expr_map,
-                                                            id,
-                                                            (gpointer)texpr);
-                               }
-                       } else if (!is_post_52_array)
-                               g_warning ("XML-IO : Duplicate shared expression");
-               }
-       } else if (expr_id > 0) {
-               GnmExprTop const *texpr = g_hash_table_lookup (state->expr_map,
-                       GINT_TO_POINTER (expr_id));
+       // ----------------------------------------
+
+       if (!has_contents && expr_id > 0) {
+               // Re-use of expression id
+               texpr = g_hash_table_lookup (state->expr_map,
+                                            GINT_TO_POINTER (expr_id));
 
                if (!texpr) {
                        char *msg = g_strdup_printf
@@ -2224,33 +2193,91 @@ xml_sax_cell_content (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
                                             GINT_TO_POINTER (expr_id),
                                             (gpointer)texpr);
                }
+               gnm_expr_top_ref (texpr);
+               goto assign_and_done;
+       }
+
+       // ----------------------------------------
+
+       if (value_type > 0) {
+               // Cell value
+               gboolean from_content = (value_result == NULL);
+               const char *txt = from_content ? content : value_result;
+               v = value_new_from_string (value_type, txt, value_fmt, FALSE);
+               if (v == NULL) {
+                       char *msg = g_strdup_printf
+                               ("Parsing \"%s\" as type 0x%x",
+                                txt, value_type);
+                       xml_sax_barf (G_STRFUNC, msg);
+                       g_free (msg);
+                       v = value_new_string (txt);
+               }
 
-               if (cell)
-                       gnm_cell_set_expr (cell, texpr);
+               // If we consumed the contents as a value, then it's not
+               // an expression.
+               if (from_content)
+                       expr_start = NULL;
                else {
-                       cc->texpr = texpr;
-                       gnm_expr_top_ref (texpr);
+                       if (value_fmt)
+                               value_set_fmt (v, value_fmt);
                }
-       } else if (is_new_cell) {
-               GnmValue *v;
+       }
 
-               /*
-                * Only set to empty if this is a new cell.
-                * If it was created by a previous array
-                * we do not want to erase it.
-                */
-               v = value_new_from_string (value_type, "", NULL, FALSE);
-               if (!v) {
-                       xml_sax_barf (G_STRFUNC, "v != NULL");
-                       v = value_new_empty ();
+       // ----------------------------------------
+
+       if (expr_start && *expr_start) {
+               GnmParseError perr;
+
+               parse_error_init (&perr);
+               texpr = gnm_expr_parse_str (expr_start,
+                                           &pos,
+                                           GNM_EXPR_PARSE_DEFAULT,
+                                           state->convs,
+                                           &perr);
+               // Don't warn in the clipboard case.
+               // It's probably an unknown sheet ref
+               if (!texpr && !cr)
+                       g_warning ("Unparsable expression for %s: %s (%s)\n",
+                                  cell ? cell_name (cell) : "-",
+                                  content,
+                                  perr.err->message);
+               if (!texpr)
+                       texpr = gnm_expr_top_new_constant (value_new_string (expr_start));
+               parse_error_free (&perr);
+
+               if (expr_id > 0) {
+                       gpointer id = GINT_TO_POINTER (expr_id);
+                       GnmExprTop const *texpr0 =
+                               g_hash_table_lookup (state->expr_map, id);
+                       if (!texpr0) {
+                               gnm_expr_top_ref (texpr);
+                               g_hash_table_insert (state->expr_map,
+                                                    id,
+                                                    (gpointer)texpr);
+                       } else if (!is_post_52_array)
+                               g_warning ("XML-IO : Duplicate shared expression");
                }
+       }
 
-               gnm_cell_set_value (cell, v);
-       } else if (cr) {
-               cc->val = value_new_empty ();
+assign_and_done:
+       if (!v)
+               v = value_new_empty ();
+       if (cell) {
+               // Regular case
+               if (texpr) {
+                       gnm_cell_set_expr_and_value (cell, texpr, v, TRUE);
+                       gnm_expr_top_unref (texpr);
+               } else
+                       gnm_cell_set_value (cell, v);
+       } else {
+               // Clipboard case
+               cc->texpr = texpr;
+               cc->val = v;
        }
 
+done:
        go_format_unref (value_fmt);
+       g_free (value_result);
 }
 
 static void
@@ -3354,6 +3381,7 @@ read_file_init_state (XMLSaxParseState *state,
        state->expr_id = -1;
        state->value_type = -1;
        state->value_fmt = NULL;
+       state->value_result = NULL;
        state->scenario = NULL;
        state->scenario_range = NULL;
        state->filter = NULL;
@@ -3411,11 +3439,6 @@ read_file_free_state (XMLSaxParseState *state, gboolean self)
                g_free (state);
 }
 
-typedef enum {
-       READ_FULL_FILE,
-       READ_CLIPBOARD
-} ReadFileWhat;
-
 static gboolean
 read_file_common (ReadFileWhat what, XMLSaxParseState *state,
                  GOIOContext *io_context,
diff --git a/src/xml-sax-write.c b/src/xml-sax-write.c
index 3e23c76..92fbae2 100644
--- a/src/xml-sax-write.c
+++ b/src/xml-sax-write.c
@@ -72,6 +72,9 @@ typedef struct {
        GHashTable         *expr_map;
        GString            *cell_str;   /* Scratch pad.  */
 
+       // Do we write result values?  For now this is clipboard only
+       gboolean            write_value_result;
+
        GsfXMLOut *output;
 } GnmOutputXML;
 
@@ -870,11 +873,12 @@ xml_write_cell_and_position (GnmOutputXML *state,
        }
 
        if (write_contents) {
+               gboolean write_value = !texpr || state->write_value_result;
                GString *str = state->cell_str;
 
                g_string_truncate (str, 0);
 
-               if (!texpr) {
+               if (write_value) {
                        if (val != NULL) {
                                gsf_xml_out_add_int (state->output, "ValueType", val->v_any.type);
                                if (VALUE_FMT (val) != NULL) {
@@ -882,10 +886,16 @@ xml_write_cell_and_position (GnmOutputXML *state,
                                        gsf_xml_out_add_cstr (state->output, "ValueFormat", fmt);
                                }
                                value_get_as_gstring (val, str, state->convs);
+                               if (texpr) {
+                                       gsf_xml_out_add_cstr (state->output, "Value", str->str);
+                                       g_string_truncate (str, 0);
+                               }
                        } else {
                                g_warning ("%s has no value ?", cellpos_as_string (&pp->eval));
                        }
-               } else {
+               }
+
+               if (texpr) {
                        GnmConventionsOut out;
                        out.accum = str;
                        out.pp    = pp;
@@ -1489,6 +1499,7 @@ gnm_xml_file_save_full (G_GNUC_UNUSED GOFileSaver const *fs,
        state.convs     = gnm_xml_io_conventions ();
        state.expr_map  = g_hash_table_new (g_direct_hash, g_direct_equal);
        state.cell_str  = g_string_new (NULL);
+       state.write_value_result = FALSE;
        go_doc_init_write (GO_DOC (state.wb), state.output);
 
        locale = gnm_push_C_locale ();
@@ -1588,8 +1599,7 @@ cb_xml_write_cell_region_cells (GnmCellCopy *cc,
  * gnm_cellregion_to_xml:
  * @cr: the content to store.
  *
- * Caller is responsible for free-ing the result.
- * Returns: (transfer full): NULL on error
+ * Returns: (transfer full): %NULL on error
  **/
 GsfOutputMemory *
 gnm_cellregion_to_xml (GnmCellRegion const *cr)
@@ -1611,6 +1621,7 @@ gnm_cellregion_to_xml (GnmCellRegion const *cr)
        state.state.convs = gnm_xml_io_conventions ();
        state.state.expr_map = g_hash_table_new (g_direct_hash, g_direct_equal);
        state.state.cell_str = g_string_new (NULL);
+       state.state.write_value_result = TRUE;
 
        locale = gnm_push_C_locale ();
        if (cr->origin_sheet) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]