gnumeric r16559 - in trunk: . plugins/excel



Author: mortenw
Date: Wed May  7 14:56:09 2008
New Revision: 16559
URL: http://svn.gnome.org/viewvc/gnumeric?rev=16559&view=rev

Log:
2008-05-07  Morten Welinder  <terra gnome org>

	* ms-excel-write.c (ExcelStyleVariant): New type.
	(xf_init): Create cell_style_variant hash.  Change domain type of
	xf.two_way_table to ExcelStyleVariant.  All users changed.
	(xf_free): Destroy cell_style_variant.
	(cb_cell_pre_pass): If a string cell needs quoting, mark it as
	variant 1.
	(excel_sheet_write_block): Use proper variant.
	(build_xf_data): Set ->format properly.
	(excel_write_XF): Propagate ->format into XF.  Fixes #530704.



Modified:
   trunk/NEWS
   trunk/plugins/excel/ChangeLog
   trunk/plugins/excel/ms-excel-write.c
   trunk/plugins/excel/ms-excel-write.h

Modified: trunk/NEWS
==============================================================================
--- trunk/NEWS	(original)
+++ trunk/NEWS	Wed May  7 14:56:09 2008
@@ -1,3 +1,9 @@
+Gnumeric 1.9.1
+
+Morten:
+	Fix Excel export problem for strings that need quoting.  [#530704]
+
+--------------------------------------------------------------------------
 Gnumeric 1.9.0
 
 David Reiser:

Modified: trunk/plugins/excel/ms-excel-write.c
==============================================================================
--- trunk/plugins/excel/ms-excel-write.c	(original)
+++ trunk/plugins/excel/ms-excel-write.c	Wed May  7 14:56:09 2008
@@ -3,11 +3,12 @@
  * ms-excel-write.c: MS Excel support for Gnumeric
  *
  * Authors:
- *    Michael Meeks (mmeeks gnu org)
- *    Jon K Hellan  (hellan acm org)
- *    Jody Goldberg (jody gnome org)
+ *    Michael Meeks  (mmeeks gnu org)
+ *    Jon K Hellan   (hellan acm org)
+ *    Jody Goldberg  (jody gnome org)
+ *    Morten Welinder (terra gnome org)
  *
- * (C) 1998-2007 Michael Meeks, Jon K Hellan, Jody Goldberg
+ * (C) 1998-2008 Michael Meeks, Jon K Hellan, Jody Goldberg, Morten Welinder
  **/
 
 /*
@@ -115,6 +116,28 @@
 			 BlipType *bt);
 };
 
+/*
+ * We sometimes need multiple XF records for a single Gnumeric style.  That
+ * happens, for example when we synthesize the cell-is-quoted flag.
+ */
+typedef struct {
+	GnmStyle const *style;
+	int variant;
+} ExcelStyleVariant;
+
+static guint
+excel_style_variant_hash (ExcelStyleVariant const *esv)
+{
+	return gnm_style_hash_XL (esv->style) ^ esv->variant;
+}
+
+static gboolean
+excel_style_variant_equal (ExcelStyleVariant const *a,
+			   ExcelStyleVariant const *b)
+{
+	return a->variant == b->variant && gnm_style_equal (a->style, b->style);
+}
+
 static guint
 gnm_color_to_bgr (GnmColor const *c)
 {
@@ -1730,14 +1753,16 @@
 {
 	put_color_bgr (ewb, go_color_to_bgr (c));
 }
+
 /**
  * Add colors in mstyle to palette
  **/
 static void
-put_colors (GnmStyle const *st, gconstpointer dummy, XLExportBase *ewb)
+put_colors (ExcelStyleVariant const *esv, gpointer dummy, XLExportBase *ewb)
 {
 	unsigned i, j;
 	GnmBorder const *b;
+	GnmStyle const *st = esv->style;
 
 	put_color_gnm (ewb, gnm_style_get_font_color (st));
 	put_color_gnm (ewb, gnm_style_get_back_color (st));
@@ -1800,7 +1825,8 @@
 
 	/* For each color in each style, get color index from hash. If
            none, it is not there yet, and we enter it. */
-	g_hash_table_foreach (twt->unique_keys, (GHFunc) put_colors, xle);
+	g_hash_table_foreach (xle->xf.two_way_table->unique_keys,
+			      (GHFunc) put_colors, xle);
 
 	twt = xle->pal.two_way_table;
 	for (i = twt->idx_to_key->len - 1; i >= EXCEL_DEF_PAL_LEN; i--) {
@@ -2093,9 +2119,9 @@
 }
 
 static void
-put_style_font (GnmStyle const *style, gconstpointer dummy, XLExportBase *xle)
+put_style_font (ExcelStyleVariant const *esv, gconstpointer dummy, XLExportBase *xle)
 {
-	put_efont (excel_font_new (style), xle);
+	put_efont (excel_font_new (esv->style), xle);
 }
 
 static void
@@ -2248,11 +2274,12 @@
 {
 	return two_way_table_key_to_idx (xle->formats.two_way_table, format);
 }
+
 static void
-put_format (GnmStyle const *mstyle, gconstpointer dummy, XLExportBase *xle)
+put_format (ExcelStyleVariant const *esv, gpointer dummy, XLExportBase *xle)
 {
 	two_way_table_put (xle->formats.two_way_table,
-		go_format_ref (gnm_style_get_format (mstyle)), TRUE,
+		go_format_ref (gnm_style_get_format (esv->style)), TRUE,
 		(AfterPutFunc) after_put_format,
 		"Found unique format %d - 0x%x\n");
 }
@@ -2313,9 +2340,13 @@
 static void
 xf_init (XLExportBase *xle)
 {
+	ExcelStyleVariant *esv;
+
 	/* Excel starts at XF_RESERVED for user defined xf */
-	xle->xf.two_way_table = two_way_table_new (gnm_style_hash_XL,
-		(GCompareFunc) gnm_style_equal_XL, XF_RESERVED, NULL);
+	xle->xf.two_way_table = two_way_table_new
+		((GHashFunc)excel_style_variant_hash,
+		 (GCompareFunc)excel_style_variant_equal,
+		 XF_RESERVED, g_free);
 
 	/* We store the default style for the workbook on xls import, use it if
 	 * it's available.  While we have a default style per sheet, we don't
@@ -2333,10 +2364,14 @@
 	xle->xf.value_fmt_styles = g_hash_table_new_full (
 		g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)gnm_style_unlink);
 	/* Register default style, its font and format */
-	two_way_table_put (xle->xf.two_way_table, xle->xf.default_style,
-		TRUE, NULL, NULL);
-	put_style_font (xle->xf.default_style, NULL, xle);
-	put_format (xle->xf.default_style, NULL, xle);
+	esv = g_new (ExcelStyleVariant, 1);
+	esv->style = xle->xf.default_style;
+	esv->variant = 0;
+	two_way_table_put (xle->xf.two_way_table, esv, TRUE, NULL, NULL);
+	put_style_font (esv, NULL, xle);
+	put_format (esv, NULL, xle);
+
+	xle->xf.cell_style_variant = g_hash_table_new (g_direct_hash, g_direct_equal);
 }
 
 static void
@@ -2348,10 +2383,12 @@
 		gnm_style_unref (ewb->xf.default_style);
 		ewb->xf.default_style = NULL;
 		g_hash_table_destroy (ewb->xf.value_fmt_styles);
+
+		g_hash_table_destroy (ewb->xf.cell_style_variant);
 	}
 }
 
-static GnmStyle *
+static const ExcelStyleVariant *
 xf_get_mstyle (XLExportBase *xle, gint idx)
 {
 	return two_way_table_idx_to_key (xle->xf.two_way_table, idx);
@@ -2406,17 +2443,17 @@
 static void
 cb_cell_pre_pass (gpointer ignored, GnmCell const *cell, ExcelWriteState *ewb)
 {
-	int index;
-	GnmStyle const	*style;
-	GOFormat	*fmt;
-	GnmString	*str;
+	GnmStyle const *style;
+	GOFormat *fmt;
+	gboolean use_sst;
 
 	if (gnm_cell_has_expr (cell) || cell->value == NULL)
 		return;
 
-	if ((fmt = VALUE_FMT (cell->value)) != NULL) {
-		style = gnm_cell_get_style (cell);
+	use_sst = VALUE_IS_STRING (cell->value) && ewb->sst.strings != NULL;
+	style = gnm_cell_get_style (cell);
 
+	if ((fmt = VALUE_FMT (cell->value)) != NULL) {
 		/* Collect unique fonts in rich text */
 		if (VALUE_IS_STRING (cell->value) &&
 		    go_format_is_markup (fmt)) {
@@ -2424,9 +2461,9 @@
 				go_format_get_markup (fmt),
 				style);
 
-			g_hash_table_insert (ewb->cell_markup,
-				(gpointer)cell, txo);
-			return; /* we use RSTRING, no need to add to SST */
+			g_hash_table_insert (ewb->cell_markup, (gpointer)cell, txo);
+			/* we use RSTRING, no need to add to SST */
+			use_sst = FALSE;
 		}
 
 		/* XL has no notion of value format.  We need to create
@@ -2436,29 +2473,57 @@
 		else if (go_format_is_general (gnm_style_get_format (style))) {
 			GnmStyle *tmp = gnm_style_dup (style);
 			gnm_style_set_format (tmp, fmt);
+			style = sheet_style_find (cell->base.sheet, tmp);
 			g_hash_table_insert (ewb->base.xf.value_fmt_styles,
-				(gpointer)cell,
-				sheet_style_find (cell->base.sheet, tmp));
+					     (gpointer)cell,
+					     (gpointer)style);
 		}
 	}
 
 	/* Collect strings for the SST if we need them */
-	if (ewb->sst.strings != NULL && VALUE_IS_STRING (cell->value)) {
-		str = cell->value->v_str.val;
+	if (use_sst) {
+		GnmString *str = cell->value->v_str.val;
 		if (!g_hash_table_lookup_extended (ewb->sst.strings, str, NULL, NULL)) {
-			index = ewb->sst.indicies->len;
+			int index = ewb->sst.indicies->len;
 			g_ptr_array_add (ewb->sst.indicies, str);
 			g_hash_table_insert (ewb->sst.strings, str,
 				GINT_TO_POINTER (index));
 		}
 	}
+
+	if (VALUE_IS_STRING (cell->value)) {
+		/*
+		 * We need to know if Excel's parser would consider the string
+		 * a non-string if edited.  We use our parser as a proxy for
+		 * that.
+		 */
+		char *text = gnm_cell_get_entered_text (cell);
+		gboolean quoted = (text[0] == '\'');
+		g_free (text);
+
+		if (quoted) {
+			int xf;
+			ExcelStyleVariant *esv = g_new (ExcelStyleVariant, 1);
+			esv->variant = 1;
+			esv->style = style;
+			xf = two_way_table_put (ewb->base.xf.two_way_table,
+						esv, FALSE, NULL, NULL);
+			g_hash_table_insert (ewb->base.xf.cell_style_variant,
+					     (gpointer)cell,
+					     GINT_TO_POINTER (1));
+		}
+	}
 }
 
 static void
 cb_accum_styles (GnmStyle const *st, gconstpointer dummy, XLExportBase *xle)
 {
-	two_way_table_put (xle->xf.two_way_table, (gpointer)st, TRUE, NULL, NULL);
+	ExcelStyleVariant *esv = g_new (ExcelStyleVariant, 1);
+	esv->style = st;
+	esv->variant = 0;
+	two_way_table_put (xle->xf.two_way_table, esv, TRUE, NULL, NULL);
 }
+
 static void
 gather_styles (ExcelWriteState *ewb)
 {
@@ -2472,9 +2537,13 @@
 			(GHFunc) cb_cell_pre_pass, &ewb->base);
 		sheet_style_foreach (esheet->gnum_sheet,
 			(GHFunc) cb_accum_styles, &ewb->base);
-		for (col = 0; col < esheet->max_col; col++)
-			esheet->col_xf [col] = two_way_table_key_to_idx (
-				ewb->base.xf.two_way_table, esheet->col_style [col]);
+		for (col = 0; col < esheet->max_col; col++) {
+			ExcelStyleVariant esv;
+			esv.style = esheet->col_style[col];
+			esv.variant = 0;
+			esheet->col_xf[col] = two_way_table_key_to_idx
+				(ewb->base.xf.two_way_table, &esv);
+		}
 	}
 }
 
@@ -2651,16 +2720,17 @@
 #endif
 
 static void
-build_xf_data (XLExportBase *xle, BiffXFData *xfd, GnmStyle *st)
+build_xf_data (XLExportBase *xle, BiffXFData *xfd, const ExcelStyleVariant *esv)
 {
 	ExcelWriteFont *f;
 	GnmBorder const *b;
 	int i;
+	GnmStyle const *st = esv->style;
 
 	memset (xfd, 0, sizeof *xfd);
 
 	xfd->parentstyle  = XF_MAGIC;
-	xfd->mstyle       = st;
+	xfd->mstyle       = (gpointer)st;
 
 	f = excel_font_new (st);
 	xfd->font_idx = two_way_table_key_to_idx (xle->fonts.two_way_table, f);
@@ -2671,6 +2741,7 @@
 
 	xfd->locked	= gnm_style_get_contents_locked (st);
 	xfd->hidden	= gnm_style_get_contents_hidden (st);
+	xfd->format     = (esv->variant & 1) ? MS_BIFF_F_LOTUS : MS_BIFF_F_MS;
 	xfd->halign	= gnm_style_get_align_h (st);
 	xfd->valign	= gnm_style_get_align_v (st);
 	xfd->wrap_text	= gnm_style_get_wrap_text (st);
@@ -2734,7 +2805,7 @@
 			tmp16 |= (1 << 1);
 
 		tmp16 |= (0 << 2);	/* GnmCell style */
-		/* tmp16 |= (0 << 3);	lotus123 transition */
+		tmp16 |= (xfd->format << 3);
 		/* tmp16 |= (0 << 4);	style 0 == parent */
 		GSF_LE_SET_GUINT16(data+4, tmp16);
 
@@ -4602,16 +4673,13 @@
 excel_sheet_write_block (ExcelWriteSheet *esheet, guint32 begin, int nrows,
 			 GArray *dbcells)
 {
-	GnmStyle const *style;
 	ExcelWriteState *ewb = esheet->ewb;
 	int col, row, max_row, max_col = esheet->max_col;
 	unsigned  ri_start [2]; /* Row info start */
 	unsigned *rc_start;	/* Row cells start */
 	guint16   xf_list [SHEET_MAX_COLS];
 	GnmRange  r;
-	GnmCell const	*cell;
 	Sheet		*sheet = esheet->gnum_sheet;
-	int	    xf;
 	TwoWayTable *twt = esheet->ewb->base.xf.two_way_table;
 	gboolean has_content = FALSE;
 
@@ -4639,16 +4707,23 @@
 			continue;
 		has_content = TRUE;
 		for (col = 0; col < max_col; col++) {
-			cell = sheet_cell_get (sheet, col, row);
+			int xf;
+			GnmCell const *cell = sheet_cell_get (sheet, col, row);
+			ExcelStyleVariant esv;
+
+			esv.variant = GPOINTER_TO_INT
+				(g_hash_table_lookup (ewb->base.xf.cell_style_variant, cell));
 
 			/* check for a magic value_fmt override*/
-			style = g_hash_table_lookup (ewb->base.xf.value_fmt_styles, cell);
-			if (style == NULL)
-				style = sheet_style_get (sheet, col, row);
-			xf = two_way_table_key_to_idx (twt, style);
+			esv.style = g_hash_table_lookup
+				(ewb->base.xf.value_fmt_styles, cell);
+			if (esv.style == NULL)
+				esv.style = sheet_style_get (sheet, col, row);
+			xf = two_way_table_key_to_idx (twt, &esv);
+
 			if (xf < 0) {
 				g_warning ("Can't find style %p for cell %s!%s",
-					   style, sheet->name_unquoted, cell_name (cell));
+					   esv.style, sheet->name_unquoted, cell_name (cell));
 				xf = 0;
 			}
 			if (cell == NULL) {
@@ -4984,9 +5059,9 @@
 
 	/* Gather Info from styles */
 	twt = xle->xf.two_way_table;
-	g_hash_table_foreach (twt->unique_keys, (GHFunc) put_style_font, xle);
+	g_hash_table_foreach (twt->unique_keys, (GHFunc)put_style_font, xle);
 	twt = xle->xf.two_way_table;
-	g_hash_table_foreach (twt->unique_keys, (GHFunc) put_format, xle);
+	g_hash_table_foreach (twt->unique_keys, (GHFunc)put_format, xle);
 	gather_palette (xle);
 }
 

Modified: trunk/plugins/excel/ms-excel-write.h
==============================================================================
--- trunk/plugins/excel/ms-excel-write.h	(original)
+++ trunk/plugins/excel/ms-excel-write.h	Wed May  7 14:56:09 2008
@@ -61,6 +61,7 @@
 		TwoWayTable *two_way_table;
 		GnmStyle    *default_style;
 		GHashTable  *value_fmt_styles;
+		GHashTable  *cell_style_variant;
 	} xf;
 	struct {
 		TwoWayTable *two_way_table;



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