[gnumeric] Styles: optimize styles after loading a file.
- From: Morten Welinder <mortenw src gnome org>
- To: svn-commits-list gnome org
- Subject: [gnumeric] Styles: optimize styles after loading a file.
- Date: Thu, 7 May 2009 14:59:11 -0400 (EDT)
commit c1a2185e15afcf174e72cfdc8bfdeee7267acb5d
Author: Morten Welinder <terra gnome org>
Date: Thu May 7 14:58:39 2009 -0400
Styles: optimize styles after loading a file.
---
ChangeLog | 9 ++
NEWS | 3 +
src/sheet-style.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++-
src/sheet-style.h | 2 +
src/workbook-view.c | 1 +
src/workbook.c | 8 ++
src/workbook.h | 1 +
7 files changed, 333 insertions(+), 1 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 482eda1..b854a8a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2009-05-07 Morten Welinder <terra gnome org>
+
+ * src/sheet-style.c (sheet_style_optimize): New function.
+
+ * src/workbook.c (workbook_optimize_style): New function.
+
+ * src/workbook-view.c (wb_view_new_from_input): Call
+ workbook_optimize_style.
+
2009-05-06 Morten Welinder <terra gnome org>
* configure.in: Post-release bump.
diff --git a/NEWS b/NEWS
index 56437f4..cb106fe 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
Gnumeric 1.9.8
+Morten:
+ * Optimize styles on load.
+
--------------------------------------------------------------------------
Gnumeric 1.9.7
diff --git a/src/sheet-style.c b/src/sheet-style.c
index 496a6a2..786956d 100644
--- a/src/sheet-style.c
+++ b/src/sheet-style.c
@@ -29,6 +29,7 @@
#include "style-border.h"
#include "style-color.h"
#include "style-conditions.h"
+#include "parse-util.h"
#include "cell.h"
#include "gutils.h"
#include <goffice/utils/go-glib-extras.h>
@@ -202,6 +203,9 @@ static int const tile_size [] = {
TILE_SIZE_ROW, /* TILE_ROW */
TILE_SIZE_COL * TILE_SIZE_ROW /* TILE_MATRIX */
};
+static const char * const tile_type_str [] = {
+ "simple", "col", "row", "matrix", "ptr-matrix"
+};
static int const tile_widths [] = {
1,
TILE_SIZE_COL,
@@ -372,7 +376,7 @@ cell_tile_ptr_matrix_new (CellTile *t)
int i = TILE_SIZE_COL * TILE_SIZE_ROW;
while (--i >= 0)
res->ptr [i] = cell_tile_style_new (
- t->style_simple.style [i], TILE_SIMPLE);
+ t->style_matrix.style [i], TILE_SIMPLE);
break;
}
default : ;
@@ -2577,3 +2581,307 @@ sheet_style_foreach (Sheet const *sheet, GHFunc func, gpointer user_data)
g_hash_table_foreach (sheet->style_data->style_hash, func, user_data);
}
+
+/* ------------------------------------------------------------------------- */
+
+typedef struct {
+ GnmSheetSize const *ss;
+ gboolean debug;
+} CellTileOptimize;
+
+static void
+cell_tile_optimize (CellTile **tile, int level, CellTileOptimize *data,
+ int ccol, int crow)
+{
+ CellTileType type;
+ int const w = tile_widths[level];
+ int const h = tile_heights[level];
+ CellTile *res;
+ int i;
+ GnmRange rng;
+
+ type = (*tile)->type;
+ if (type == TILE_SIMPLE)
+ return;
+
+ range_init (&rng,
+ ccol, crow,
+ MIN (ccol + tile_widths[level + 1] - 1,
+ data->ss->max_cols - 1),
+ MIN (crow + tile_heights[level + 1] - 1,
+ data->ss->max_rows - 1));
+
+ switch (type) {
+ case TILE_COL:
+ case TILE_ROW: {
+ int s = tile_size[type];
+ int i;
+ gboolean same = TRUE;
+
+ for (i = 1; i < s; i++) {
+ if (!gnm_style_equal ((*tile)->style_any.style[0],
+ (*tile)->style_any.style[i])) {
+ same = FALSE;
+ break;
+ }
+ }
+
+ if (!same)
+ return;
+
+ type = TILE_SIMPLE;
+ break;
+ }
+
+ case TILE_MATRIX: {
+ gboolean csame = TRUE;
+ gboolean rsame = TRUE;
+ int c, r, i;
+
+ for (i = r = 0 ; r < TILE_SIZE_ROW ; ++r, i += TILE_SIZE_COL) {
+ for (c = 0 ; c < TILE_SIZE_COL ; ++c) {
+ if (rsame && c &&
+ !gnm_style_equal ((*tile)->style_matrix.style[i + c],
+ (*tile)->style_matrix.style[i ])) {
+ rsame = FALSE;
+ if (!csame)
+ return;
+ }
+ if (csame && r &&
+ !gnm_style_equal ((*tile)->style_matrix.style[i + c],
+ (*tile)->style_matrix.style[ c])) {
+ csame = FALSE;
+ if (!rsame)
+ return;
+ }
+ }
+ }
+
+ if (csame && rsame)
+ type = TILE_SIMPLE;
+ else if (csame) {
+ type = TILE_COL;
+ } else {
+ type = TILE_ROW;
+ }
+ break;
+ }
+
+ case TILE_PTR_MATRIX: {
+ int c, r, i;
+ gboolean csame = TRUE;
+ gboolean rsame = TRUE;
+ gboolean all_simple = TRUE;
+
+ for (i = r = 0 ; r < TILE_SIZE_ROW ; ++r, i += TILE_SIZE_COL) {
+ int const cr = crow + h*r;
+ for (c = 0 ; c < TILE_SIZE_COL ; ++c) {
+ int const cc = ccol + w*c;
+ CellTile const *tcr, *tc0, *t0r;
+ cell_tile_optimize ((*tile)->ptr_matrix.ptr + i + c,
+ level - 1, data, cc, cr);
+ tcr = (*tile)->ptr_matrix.ptr[i + c];
+ t0r = (*tile)->ptr_matrix.ptr[i];
+ tc0 = (*tile)->ptr_matrix.ptr[c];
+
+ if (tcr->type != TILE_SIMPLE) {
+ all_simple = FALSE;
+ csame = FALSE;
+ rsame = FALSE;
+ }
+
+ if (rsame && c)
+ rsame = gnm_style_equal (tcr->style_simple.style[0],
+ t0r->style_simple.style[0]);
+
+ if (csame && r)
+ csame = gnm_style_equal (tcr->style_simple.style[0],
+ tc0->style_simple.style[0]);
+ }
+ }
+ if (csame && rsame) {
+ res = cell_tile_style_new ((*tile)->ptr_matrix.ptr[0]->style_simple.style[0], type);
+ } else if (csame) {
+ res = cell_tile_style_new (NULL, TILE_COL);
+ for (i = 0; i < TILE_SIZE_COL; i++) {
+ GnmStyle *mstyle = (*tile)->ptr_matrix.ptr[i]
+ ->style_simple.style[0];
+ res->style_col.style[i] = mstyle;
+ gnm_style_link (mstyle);
+ }
+ } else if (rsame) {
+ res = cell_tile_style_new (NULL, TILE_ROW);
+ for (i = 0; i < TILE_SIZE_ROW; i++) {
+ GnmStyle *mstyle = (*tile)->ptr_matrix.ptr[i * TILE_SIZE_COL]
+ ->style_simple.style[0];
+ res->style_row.style[i] = mstyle;
+ gnm_style_link (mstyle);
+ }
+ break;
+ } else if (all_simple) {
+ if (data->debug)
+ g_printerr ("Could turn %s into a matrix\n",
+ range_as_string (&rng));
+ return;
+ } else
+ return;
+
+ if (data->debug)
+ g_printerr ("Turning %s (%dx%d) from a %s into a %s\n",
+ range_as_string (&rng),
+ range_width (&rng), range_height (&rng),
+ tile_type_str[(*tile)->type],
+ tile_type_str[res->type]);
+ cell_tile_dtor (*tile);
+ *tile = res;
+ return;
+ }
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (data->debug)
+ g_printerr ("Turning %s (%dx%d) from a %s into a %s\n",
+ range_as_string (&rng),
+ range_width (&rng), range_height (&rng),
+ tile_type_str[(*tile)->type],
+ tile_type_str[type]);
+ res = cell_tile_style_new (NULL, type);
+ switch (type) {
+ case TILE_SIMPLE:
+ res->style_simple.style[0] = (*tile)->style_any.style[0];
+ break;
+ case TILE_ROW:
+ for (i = 0; i < TILE_SIZE_ROW; i++)
+ res->style_row.style[i] =
+ (*tile)->style_matrix.style[i * TILE_SIZE_COL];
+ break;
+ case TILE_COL:
+ for (i = 0; i < TILE_SIZE_COL; i++)
+ res->style_col.style[i] =
+ (*tile)->style_matrix.style[i];
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ for (i = 0; i < tile_size[type]; i++)
+ gnm_style_link (res->style_any.style[i]);
+
+ cell_tile_dtor (*tile);
+ *tile = res;
+}
+
+static GSList *
+sample_styles (Sheet *sheet)
+{
+ GnmSheetSize const *ss = gnm_sheet_get_size (sheet);
+ GSList *res = NULL;
+ int c = 0, r = 0;
+ const int SKIP = 1;
+
+ while (1) {
+ GnmStyle const *mstyle = sheet_style_get (sheet, c, r);
+ if (res == NULL || mstyle != res->data) {
+ gnm_style_ref (mstyle);
+ res = g_slist_prepend (res, GINT_TO_POINTER (c));
+ res = g_slist_prepend (res, GINT_TO_POINTER (r));
+ res = g_slist_prepend (res, (gpointer)mstyle);
+ }
+
+ c += SKIP;
+ if (c >= ss->max_cols) {
+ c -= ss->max_cols;
+ r++;
+ if (r >= ss->max_rows)
+ break;
+ }
+ }
+
+ return g_slist_reverse (res);
+}
+
+static void
+verify_styles (GSList *pre, GSList *post)
+{
+ GSList *lpre, *lpost;
+ gboolean silent = FALSE;
+
+ for (lpre = pre, lpost = post;
+ lpre || lpost;
+ lpre = (lpre ? lpre->next->next->next : NULL),
+ lpost = (lpost ? lpost->next->next->next : NULL)) {
+ int cpre = lpre ? GPOINTER_TO_INT (lpre->data) : -1;
+ int rpre = lpre ? GPOINTER_TO_INT (lpre->next->data) : -1;
+ GnmStyle const *spre = lpre ? lpre->next->next->data : NULL;
+ int cpost = lpost ? GPOINTER_TO_INT (lpost->data) : -1;
+ int rpost = lpost ? GPOINTER_TO_INT (lpost->next->data) : -1;
+ GnmStyle const *spost = lpost ? lpost->next->next->data : NULL;
+
+ if (!silent) {
+ if (!spre || !spost) {
+ g_warning ("Style optimizer failure at end!");
+ silent = TRUE;
+ } else if (cpre != cpost || rpre != rpost) {
+ g_warning ("Style optimizer position conflict at %s!",
+ cell_coord_name (cpre, rpre));
+ silent = TRUE;
+ } else if (!gnm_style_equal (spre, spost)) {
+ g_warning ("Style optimizer failure at %s!",
+ cell_coord_name (cpre, rpre));
+ }
+ }
+
+ if (spre) gnm_style_unref (spre);
+ if (spost) gnm_style_unref (spost);
+ }
+
+ g_slist_free (pre);
+ g_slist_free (post);
+}
+
+void
+sheet_style_optimize (Sheet *sheet)
+{
+ CellTileOptimize data;
+ GSList *pre;
+ static guint debug_flags;
+ static gboolean debug_inited = FALSE;
+ gboolean verify;
+ enum { GNM_DEBUG_STYLE_OPTIMIZE = 1,
+ GNM_DEBUG_STYLE_OPTIMIZE_VERIFY = 2
+ };
+
+ g_return_if_fail (IS_SHEET (sheet));
+
+ if (!debug_inited) {
+ /* not static */
+ const GDebugKey keys[] = {
+ { (char*)"style-optimize", GNM_DEBUG_STYLE_OPTIMIZE },
+ { (char*)"style-optimize-verify", GNM_DEBUG_STYLE_OPTIMIZE_VERIFY },
+ };
+
+ const char *val = g_getenv ("GNM_DEBUG");
+ debug_flags = val
+ ? g_parse_debug_string (val, keys, G_N_ELEMENTS (keys))
+ : 0;
+
+ debug_inited = TRUE;
+ }
+ verify = (debug_flags & GNM_DEBUG_STYLE_OPTIMIZE_VERIFY) != 0;
+
+ data.ss = gnm_sheet_get_size (sheet);
+ data.debug = (debug_flags & GNM_DEBUG_STYLE_OPTIMIZE) != 0;
+
+ pre = verify ? sample_styles (sheet) : NULL;
+
+ cell_tile_optimize (&sheet->style_data->styles,
+ sheet->tile_top_level, &data,
+ 0, 0);
+
+ if (verify) {
+ GSList *post = sample_styles (sheet);
+ verify_styles (pre, post);
+ }
+}
diff --git a/src/sheet-style.h b/src/sheet-style.h
index 5917233..1e7ad36 100644
--- a/src/sheet-style.h
+++ b/src/sheet-style.h
@@ -83,6 +83,8 @@ GnmStyleList *sheet_style_collect_validations (Sheet const *s, GnmRange const *r
/* For internal use only */
void sheet_style_unlink (Sheet *sheet, GnmStyle *st);
+void sheet_style_optimize (Sheet *sheet);
+
G_END_DECLS
#endif /* _GNM_SHEET_STYLE_H_ */
diff --git a/src/workbook-view.c b/src/workbook-view.c
index 0947b90..02771fe 100644
--- a/src/workbook-view.c
+++ b/src/workbook-view.c
@@ -1067,6 +1067,7 @@ wb_view_new_from_input (GsfInput *input,
new_wbv = NULL;
} else {
workbook_share_expressions (new_wb, TRUE);
+ workbook_optimize_style (new_wb);
workbook_recalc (new_wb);
go_doc_set_dirty (GO_DOC (new_wb), FALSE);
}
diff --git a/src/workbook.c b/src/workbook.c
index 787a087..4b5a15b 100644
--- a/src/workbook.c
+++ b/src/workbook.c
@@ -529,6 +529,14 @@ workbook_share_expressions (Workbook *wb, gboolean freeit)
return es;
}
+void
+workbook_optimize_style (Workbook *wb)
+{
+ WORKBOOK_FOREACH_SHEET (wb, sheet, {
+ sheet_style_optimize (sheet);
+ });
+}
+
GSList *
workbook_local_functions (Workbook const *wb)
{
diff --git a/src/workbook.h b/src/workbook.h
index ceb236f..fab92c2 100644
--- a/src/workbook.h
+++ b/src/workbook.h
@@ -41,6 +41,7 @@ unsigned workbook_find_command (Workbook *wb,
gboolean is_undo, gpointer cmd);
GnmExprSharer *workbook_share_expressions (Workbook *wb, gboolean freeit);
+void workbook_optimize_style (Workbook *wb);
/* IO Routines */
gboolean workbook_set_saveinfo (Workbook *wb, FileFormatLevel lev,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]