[gnumeric] xls: style export improvements.



commit 30efc6e22a2b0dc93152b4e155943a5ce7f5f3bd
Author: Morten Welinder <terra gnome org>
Date:   Fri Mar 9 13:41:19 2012 -0500

    xls: style export improvements.

 ChangeLog                             |    8 +
 NEWS                                  |    1 +
 plugins/excel/ChangeLog               |   13 ++
 plugins/excel/ms-excel-write.c        |   37 ++--
 plugins/excel/xlsx-write.c            |    2 +-
 plugins/openoffice/ChangeLog          |    5 +
 plugins/openoffice/openoffice-write.c |    6 +-
 src/sheet-style.c                     |  290 ++++++++++++++++++---------------
 src/sheet-style.h                     |   10 +-
 src/sheet.c                           |    2 +-
 10 files changed, 215 insertions(+), 159 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 95c501c..2c64b04 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2012-03-09  Morten Welinder  <terra gnome org>
+
+	* src/sheet-style.c (sheet_style_is_default)
+	(sheet_style_get_nondefault_extent): New function.
+	(sheet_style_has_visible_content, sheet_style_most_common_in_col): Delete.
+	(sheet_style_get_extent): Drop col_styles argument.  All callers
+	changed.
+
 2012-03-08  Morten Welinder  <terra gnome org>
 
 	* src/expr-name.c (expr_name_set_pos): Make this work even without
diff --git a/NEWS b/NEWS
index 3bb1498..09191d2 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,7 @@ Morten:
 	* Improve xls image export.   [Part of #671513]
 	* Fix sheet object order on xls export.
 	* Fix xls export for formulas in conditions.  [Part of #671513]
+	* Export non-visible style stuff to xls.  [Part of #671513]
 
 --------------------------------------------------------------------------
 Gnumeric 1.11.2
diff --git a/plugins/excel/ChangeLog b/plugins/excel/ChangeLog
index acdc7c9..33d6bd7 100644
--- a/plugins/excel/ChangeLog
+++ b/plugins/excel/ChangeLog
@@ -1,3 +1,16 @@
+2012-03-09  Morten Welinder  <terra gnome org>
+
+	* xlsx-write.c (xlsx_write_sheet): Use new
+	sheet_style_most_common.
+
+	* ms-excel-write.c (excel_sheet_extent): Use new
+	sheet_style_get_nondefault_extent.
+	(gather_styles): Gather styles for all columns.
+	(excel_write_colinfos): Ensure a column style for all columns.
+	(excel_sheet_write_block): Drop only styles that differ from the
+	column default.  Visibility is irrelevant.
+	(excel_sheet_new): Use new sheet_style_most_common.
+
 2012-03-08  Morten Welinder  <terra gnome org>
 
 	* ms-formula-write.c (excel_write_formula): Base length
diff --git a/plugins/excel/ms-excel-write.c b/plugins/excel/ms-excel-write.c
index 55f655c..75796be 100644
--- a/plugins/excel/ms-excel-write.c
+++ b/plugins/excel/ms-excel-write.c
@@ -211,10 +211,16 @@ excel_sheet_extent (Sheet const *sheet, GnmRange *extent, GnmStyle **col_styles,
 		    int maxcols, int maxrows, GOIOContext *io_context)
 {
 	int i;
+	GnmRange r;
 
 	/* Ignore spans and merges past the bound */
 	*extent = sheet_get_extent (sheet, FALSE);
 
+	range_init (&r, 0, 0,
+		    MAX (maxcols, gnm_sheet_get_max_cols(sheet)) - 1,
+		    MAX (maxrows, gnm_sheet_get_max_rows(sheet)) - 1);
+	sheet_style_get_nondefault_extent (sheet, extent, &r, col_styles);
+
 	if (extent->end.col >= maxcols) {
 		go_io_warning (io_context,
 			ngettext("Some content will be lost when saving.  "
@@ -240,8 +246,6 @@ excel_sheet_extent (Sheet const *sheet, GnmRange *extent, GnmStyle **col_styles,
 		extent->end.row = maxrows - 1;
 	}
 
-	sheet_style_get_extent (sheet, extent, col_styles);
-
 	/* include collapsed or hidden rows */
 	for (i = maxrows ; i-- > extent->end.row ; )
 		if (!colrow_is_empty (sheet_row_get (sheet, i))) {
@@ -2406,7 +2410,6 @@ xf_init (XLExportBase *xle)
 	if (xle->xf.default_style == NULL)
 		xle->xf.default_style = gnm_style_new_default ();
 	else {
-		gnm_style_dump (xle->xf.default_style);
 		gnm_style_ref (xle->xf.default_style);
 	}
 
@@ -2587,16 +2590,16 @@ static void
 gather_styles (ExcelWriteState *ewb)
 {
 	unsigned i;
-	int	 col;
-	ExcelWriteSheet *esheet;
 
 	for (i = 0; i < ewb->esheets->len; i++) {
-		esheet = g_ptr_array_index (ewb->esheets, i);
-		sheet_cell_foreach (esheet->gnum_sheet,
+		ExcelWriteSheet *esheet = g_ptr_array_index (ewb->esheets, i);
+		Sheet *sheet = esheet->gnum_sheet;
+		int col, cols = MIN (XLS_MaxCol, gnm_sheet_get_max_cols(sheet));
+		sheet_cell_foreach (sheet,
 			(GHFunc) cb_cell_pre_pass, &ewb->base);
-		sheet_style_foreach (esheet->gnum_sheet,
+		sheet_style_foreach (sheet,
 			(GHFunc) cb_accum_styles, &ewb->base);
-		for (col = 0; col < esheet->max_col; col++) {
+		for (col = 0; col < cols; col++) {
 			ExcelStyleVariant esv;
 			esv.style = esheet->col_style[col];
 			esv.variant = 0;
@@ -3726,12 +3729,11 @@ excel_write_colinfos (BiffPut *bp, ExcelWriteSheet *esheet)
 	ColRowInfo const *ci, *info;
 	int first_col = 0, i;
 	guint16	new_xf, xf = 0;
+	int cols = MIN (XLS_MaxCol, gnm_sheet_get_max_cols (esheet->gnum_sheet));
 
-	if (esheet->max_col <= 0)
-		return;
 	info = sheet_col_get (esheet->gnum_sheet, 0);
 	xf   = esheet->col_xf [0];
-	for (i = 1; i < esheet->max_col; i++) {
+	for (i = 1; i < cols; i++) {
 		ci = sheet_col_get (esheet->gnum_sheet, i);
 		new_xf = esheet->col_xf [i];
 		if (xf != new_xf || !colrow_equal (info, ci)) {
@@ -5122,7 +5124,7 @@ excel_sheet_write_DBCELL (ExcelWriteSheet *esheet,
  *
  * See: 'Finding records in BIFF files'
  */
-static guint32
+guint32
 excel_sheet_write_block (ExcelWriteSheet *esheet, guint32 begin, int nrows,
 			 GArray *dbcells)
 {
@@ -5163,8 +5165,8 @@ excel_sheet_write_block (ExcelWriteSheet *esheet, guint32 begin, int nrows,
 		/* Save start pos of 1st cell in row */
 		r.start.row = r.end.row = row;
 		rc_start [row - begin] = ewb->bp->streamPos;
-		if (! (NULL != sheet_row_get (sheet, row) ||
-		       sheet_style_has_visible_content (sheet, &r)))
+		if (sheet_row_get (sheet, row) == NULL &&
+		    sheet_style_is_default (sheet, &r, esheet->col_style))
 			continue;
 		has_content = TRUE;
 		for (col = 0; col < max_col; col++) {
@@ -5500,9 +5502,8 @@ excel_sheet_new (ExcelWriteState *ewb, Sheet *sheet,
 	g_return_val_if_fail (ewb, NULL);
 
 	esheet->col_xf = g_new (guint16, gnm_sheet_get_max_cols (sheet));
-	esheet->col_style = g_new (GnmStyle*, gnm_sheet_get_max_cols (sheet));
-	excel_sheet_extent (sheet, &extent, esheet->col_style,
-			    maxcols, maxrows, ewb->io_context);
+	esheet->col_style = sheet_style_most_common (sheet, TRUE);
+	excel_sheet_extent (sheet, &extent, esheet->col_style, maxcols, maxrows, ewb->io_context);
 
 	esheet->gnum_sheet = sheet;
 	esheet->streamPos  = 0x0deadbee;
diff --git a/plugins/excel/xlsx-write.c b/plugins/excel/xlsx-write.c
index 1338a16..4f7553b 100644
--- a/plugins/excel/xlsx-write.c
+++ b/plugins/excel/xlsx-write.c
@@ -1927,7 +1927,7 @@ xlsx_write_sheet (XLSXWriteState *state, GsfOutfile *dir, GsfOutfile *wb_part, u
 	GnmStyle **col_styles;
 
 	state->sheet = workbook_sheet_by_index (state->base.wb, i);
-	col_styles = g_new (GnmStyle*, XLSX_MAX_COLS);
+	col_styles = sheet_style_most_common (state->sheet, TRUE);
 	excel_sheet_extent (state->sheet, &extent, col_styles,
 			    XLSX_MAX_COLS, XLSX_MAX_ROWS, state->io_context);
 	cell_extent = sheet_get_cells_extent (state->sheet);
diff --git a/plugins/openoffice/ChangeLog b/plugins/openoffice/ChangeLog
index 944cca0..551e22f 100644
--- a/plugins/openoffice/ChangeLog
+++ b/plugins/openoffice/ChangeLog
@@ -1,3 +1,8 @@
+2012-03-09  Morten Welinder  <terra gnome org>
+
+	* openoffice-write.c (odf_write_sheet): Use new
+	sheet_style_most_common.
+
 2012-03-07  Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* openoffice-write.c (odf_write_axis_style): only write user defined
diff --git a/plugins/openoffice/openoffice-write.c b/plugins/openoffice/openoffice-write.c
index 584b8e1..8a38b3a 100644
--- a/plugins/openoffice/openoffice-write.c
+++ b/plugins/openoffice/openoffice-write.c
@@ -3451,7 +3451,7 @@ odf_write_sheet (GnmOOExport *state)
 	int max_cols = gnm_sheet_get_max_cols (sheet);
 	int max_rows = gnm_sheet_get_max_rows (sheet);
 	GnmStyle **col_styles = g_new0 (GnmStyle *, max_cols);
-	GnmRange extent, style_extent, cell_extent, r;
+	GnmRange extent, cell_extent, r;
 	GSList *sheet_merges = NULL;
 	GnmPageBreaks *pb = sheet->print_info->page_breaks.v;
 	gboolean repeat_top_use, repeat_left_use;
@@ -3461,9 +3461,7 @@ odf_write_sheet (GnmOOExport *state)
 	cell_extent = sheet_get_cells_extent (sheet);
 	extent = range_union (&extent, &cell_extent);
 
-	style_extent = extent;
-	/* We only want to get the common column style */
-	sheet_style_get_extent (sheet, &style_extent, col_styles);
+	col_styles = sheet_style_most_common (sheet, TRUE);
 
 	repeat_top_use = print_load_repeat_range
 		(sheet->print_info->repeat_top, &r, sheet);
diff --git a/src/sheet-style.c b/src/sheet-style.c
index 5986d67..25e5f41 100644
--- a/src/sheet-style.c
+++ b/src/sheet-style.c
@@ -1925,103 +1925,193 @@ sheet_style_insert_colrow (GnmExprRelocateInfo const *rinfo)
 }
 
 static void
-cb_visible_content (GnmStyle *style,
-		    int corner_col, int corner_row, int width, int height,
-		    GnmRange const *apply_to, gpointer res)
+cb_style_extent (GnmStyle *style,
+		 int corner_col, int corner_row, int width, int height,
+		 GnmRange const *apply_to, gpointer user)
 {
-	*((gboolean *)res) |= gnm_style_visible_in_blank (style);
+	GnmRange *res = user;
+	if (gnm_style_visible_in_blank (style)) {
+		int tmp = corner_col+width-1;
+		if (res->end.col < tmp)
+			res->end.col = tmp;
+		if (res->start.col > corner_col)
+			res->start.col = corner_col;
+
+		tmp = corner_row+height-1;
+		if (res->end.row < tmp)
+			res->end.row = tmp;
+		if (res->start.row > corner_row)
+			res->start.row = corner_row;
+	}
 }
 
 /**
- * sheet_style_has_visible_content :
+ * sheet_style_get_extent:
  *
- * @sheet :
- * @r     :
+ * @sheet: sheet to measure
+ * @res: starting range and resulting range
  *
- * Are any of the styles in the target region visible in a blank cell.  The
- * implementation is simplistic.  We should really ignore borders at the
- * edges IF they have been seen before.
+ * A simple implementation that finds the smallest range containing all visible styles
+ * and containing @res.
  */
-gboolean
-sheet_style_has_visible_content (Sheet const *sheet, GnmRange *src)
+void
+sheet_style_get_extent (Sheet const *sheet, GnmRange *res)
 {
-	gboolean res = FALSE;
+	GnmRange r;
+
+	range_init_full_sheet (&r, sheet);
 	foreach_tile (sheet->style_data->styles,
-		      sheet->tile_top_level, 0, 0, src,
-		      cb_visible_content, &res);
-	return res;
+		      sheet->tile_top_level, 0, 0, &r,
+		      cb_style_extent, res);
 }
 
-typedef struct {
+struct cb_nondefault_extent {
 	GnmRange *res;
-	GnmStyle **most_common_in_cols;
-} StyleExtentData;
+	GnmStyle **col_defaults;
+};
 
 static void
-cb_style_extent (GnmStyle *style,
-		 int corner_col, int corner_row, int width, int height,
-		 GnmRange const *apply_to, gpointer user)
+cb_nondefault_extent (GnmStyle *style,
+		      int corner_col, int corner_row, int width, int height,
+		      GnmRange const *apply_to, gpointer user_)
 {
-	StyleExtentData *data = user;
-	if (gnm_style_visible_in_blank (style)) {
+	struct cb_nondefault_extent *user = user_;
+	GnmRange *res = user->res;
+	int i;
 
-		/* always check if the column is extended */
-		int tmp = corner_col+width-1;
-		int i = corner_col;
-		if (data->res->end.col < tmp)
-			data->res->end.col = tmp;
-		if (data->res->start.col > corner_col)
-			data->res->start.col = corner_col;
-
-		/* only check the row if the style is not the most common in
-		 * all of the columns in the tile */
-		if (data->most_common_in_cols != NULL) {
-			for (; i <= tmp ; i++)
-				if (style != data->most_common_in_cols[i])
-					break;
-			if (i > tmp)
-				return;
+	for (i = 0; i < width; i++) {
+		int col = corner_col + i;
+		if (col >= apply_to->start.col &&
+		    col <= apply_to->end.col &&
+		    style != user->col_defaults[col]) {
+			int max_row = MIN (corner_row + height - 1,
+					   apply_to->end.row);
+			int min_row = MAX (corner_row, apply_to->start.row);
+
+			res->start.col = MIN (col, res->start.col);
+			res->start.row = MIN (min_row, res->start.row);
+
+			res->end.col = MAX (col, res->end.col);
+			res->end.row = MAX (max_row, res->end.row);
 		}
-		tmp = corner_row+height-1;
-		if (data->res->end.row < tmp)
-			data->res->end.row = tmp;
-		if (data->res->start.row > corner_row)
-			data->res->start.row = corner_row;
 	}
 }
 
-/**
- * sheet_style_get_extent :
- *
- * @sheet :
- * @r     :
- * most_common_in_cols : optionally NULL.
- *
- * A simple implementation that finds the smallest range containing all visible styles
- * and containing res. x If @most_common_in_cols is specified it finds the most common
- * style for each column (0..gnm_sheet_get_last_col (sheet)) and ignores that style in
- * boundary calculations.
- */
 void
-sheet_style_get_extent (Sheet const *sheet, GnmRange *res,
-			GnmStyle **most_common_in_cols)
+sheet_style_get_nondefault_extent (Sheet const *sheet, GnmRange *extent,
+				   const GnmRange *src, GnmStyle **col_defaults)
 {
-	StyleExtentData data;
-	GnmRange r;
+	struct cb_nondefault_extent user;
+	user.res = extent;
+	user.col_defaults = col_defaults;
+	foreach_tile (sheet->style_data->styles,
+		      sheet->tile_top_level, 0, 0, src,
+		      cb_nondefault_extent, &user);
+}
 
-	if (most_common_in_cols != NULL) {
-		int i;
-		for (i = 0; i < gnm_sheet_get_max_cols (sheet); i++)
-			most_common_in_cols[i] = sheet_style_most_common_in_col (sheet, i);
+struct cb_is_default {
+	gboolean res;
+	GnmStyle **col_defaults;
+};
+
+static void
+cb_is_default (GnmStyle *style,
+	       int corner_col, int corner_row, int width, int height,
+	       GnmRange const *apply_to, gpointer user_)
+{
+	struct cb_is_default *user = user_;
+	int i;
+
+	for (i = 0; user->res && i < width; i++) {
+		if (style != user->col_defaults[corner_col + i])
+			user->res = FALSE;
 	}
+}
+
+gboolean
+sheet_style_is_default (Sheet const *sheet, const GnmRange *r, GnmStyle **col_defaults)
+{
+	struct cb_is_default user;
+
+	user.res = TRUE;
+	user.col_defaults = col_defaults;
+
+	foreach_tile (sheet->style_data->styles,
+		      sheet->tile_top_level, 0, 0, r,
+		      cb_is_default, &user);
+
+	return user.res;
+}
+
+
+struct cb_most_common {
+	GHashTable *h;
+	int l;
+	gboolean is_col;
+};
+
+static void
+cb_most_common (GnmStyle *style,
+		int corner_col, int corner_row, int width, int height,
+		GnmRange const *apply_to, gpointer user)
+{
+	struct cb_most_common *cmc = user;
+	int *counts = g_hash_table_lookup (cmc->h, style);
+	int i;
+	if (!counts) {
+		counts = g_new0 (int, cmc->l);
+		g_hash_table_insert (cmc->h, style, counts);
+	}
+
+	if (cmc->is_col)
+		for (i = 0; i < width; i++)
+			counts[corner_col + i] += height;
+	else
+		for (i = 0; i < height; i++)
+			counts[corner_row + i] += width;
+}
+
+GnmStyle **
+sheet_style_most_common (Sheet const *sheet, gboolean is_col)
+{
+	GnmRange r;
+	struct cb_most_common cmc;
+	int *max;
+	GnmStyle **res;
+	GHashTableIter iter;
+	gpointer key, value;
+
+	g_return_val_if_fail (IS_SHEET (sheet), NULL);
 
-	/* This could easily be optimized */
-	data.res = res;
-	data.most_common_in_cols = most_common_in_cols;
 	range_init_full_sheet (&r, sheet);
+	cmc.h = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+	cmc.l = colrow_max (is_col, sheet);
+	cmc.is_col = is_col;
 	foreach_tile (sheet->style_data->styles,
 		      sheet->tile_top_level, 0, 0, &r,
-		      cb_style_extent, &data);
+		      cb_most_common, &cmc);
+
+	max = g_new0 (int, cmc.l);
+	res = g_new0 (GnmStyle *, cmc.l);
+	g_hash_table_iter_init (&iter, cmc.h);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		int *counts = value;
+		GnmStyle *style = key;
+		int j;
+		for (j = 0; j < cmc.l; j++) {
+			/* FIXME: we really ought to break ties in a
+			   consistent way that does not depend on hash
+			   order.  */
+			if (counts[j] > max[j]) {
+				max[j] = counts[j];
+				res[j] = style;
+			}
+		}
+	}
+	g_hash_table_destroy (cmc.h);
+	g_free (max);
+
+	return res;
 }
 
 /****************************************************************************/
@@ -2448,68 +2538,6 @@ style_list_get_style (GnmStyleList const *list, int col, int row)
 }
 
 static void
-cb_accumulate_count (GnmStyle *style,
-		     int corner_col, int corner_row, int width, int height,
-		     GnmRange const *apply_to, gpointer accumulator)
-{
-	gpointer count;
-
-	count = g_hash_table_lookup (accumulator, style);
-	if (count == NULL) {
-		int *res = g_new (int, 1);
-		*res = height;
-		g_hash_table_insert (accumulator, style, res);
-	} else
-		*((int *)count) += height;
-}
-
-typedef struct
-{
-	GnmStyle *style;
-	int     count;
-} MostCommon;
-
-static void
-cb_find_max (gpointer key, gpointer value, gpointer user_data)
-{
-	MostCommon *mc = user_data;
-	int count = *((int *)value);
-	if (mc->style == NULL || mc->count < count) {
-		mc->style = key;
-		mc->count = count;
-	}
-
-	g_free (value);
-}
-
-/**
- * sheet_style_most_common_in_col :
- * @sheet :
- * @col :
- *
- * Find the most common style in a column.
- * The resulting style does not have its reference count bumped.
- */
-GnmStyle *
-sheet_style_most_common_in_col (Sheet const *sheet, int col)
-{
-	MostCommon  res;
-	GHashTable *accumulator;
-	GnmRange       r;
-
-	range_init_cols (&r, sheet, col, col);
-	accumulator = g_hash_table_new (gnm_style_hash, (GCompareFunc) gnm_style_equal);
-	foreach_tile (sheet->style_data->styles,
-		      sheet->tile_top_level, 0, 0, &r,
-		      cb_accumulate_count, accumulator);
-
-	res.style = NULL;
-	g_hash_table_foreach (accumulator, cb_find_max, &res);
-	g_hash_table_destroy (accumulator);
-	return res.style;
-}
-
-static void
 cb_find_link (GnmStyle *style,
 	      int corner_col, int corner_row, int width, int height,
 	      GnmRange const *apply_to, gpointer user)
diff --git a/src/sheet-style.h b/src/sheet-style.h
index 696b46c..2238765 100644
--- a/src/sheet-style.h
+++ b/src/sheet-style.h
@@ -44,19 +44,21 @@ void	 sheet_style_insert_colrow	(GnmExprRelocateInfo const *rinfo);
 void	 sheet_style_relocate		(GnmExprRelocateInfo const *rinfo);
 unsigned int sheet_style_find_conflicts (Sheet const *sheet, GnmRange const *r,
 					 GnmStyle **style, GnmBorder **borders);
-void	 sheet_style_get_extent		(Sheet const *sheet, GnmRange *r,
-					 GnmStyle **most_common_in_cols);
-gboolean sheet_style_has_visible_content(Sheet const *sheet, GnmRange *src);
+void	 sheet_style_get_extent		(Sheet const *sheet, GnmRange *r);
+void	 sheet_style_get_nondefault_extent (Sheet const *sheet, GnmRange *extent,
+					    const GnmRange *src, GnmStyle **col_defaults);
+gboolean sheet_style_is_default         (Sheet const *sheet, const GnmRange *r, GnmStyle **col_defaults);
 void     style_row_init			(GnmBorder const * * *prev_vert,
 					 GnmStyleRow *sr, GnmStyleRow *next_sr,
 					 int start_col, int end_col,
 					 gpointer mem, gboolean hide_grid);
-GnmStyle *sheet_style_most_common_in_col   (Sheet const *sheet, int col);
 GnmHLink *sheet_style_region_contains_link (Sheet const *sheet, GnmRange const *r);
 void	  sheet_style_foreach (Sheet const *sheet,
 			       GHFunc	    func,
 			       gpointer    user_data);
 
+GnmStyle **sheet_style_most_common (Sheet const *sheet, gboolean is_col);
+
 void sheet_style_init     (Sheet *sheet);
 void sheet_style_resize   (Sheet *sheet, int cols, int rows);
 void sheet_style_shutdown (Sheet *sheet);
diff --git a/src/sheet.c b/src/sheet.c
index 70bec82..9d19388 100644
--- a/src/sheet.c
+++ b/src/sheet.c
@@ -2240,7 +2240,7 @@ sheet_get_printarea	(Sheet const *sheet,
 
 	print_area = sheet_get_extent (sheet, TRUE);
 	if (include_styles)
-		sheet_style_get_extent (sheet, &print_area, NULL);
+		sheet_style_get_extent (sheet, &print_area);
 
 	return print_area;
 }



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