[gnumeric] Implement ctrl-click cell deselection. [#610696]



commit db6d71442b0bf92061acdd107285e477322c17ba
Author: Andreas J Guelzow <aguelzow pyrshep ca>
Date:   Wed Nov 30 10:02:40 2011 -0700

    Implement ctrl-click cell deselection. [#610696]
    
    2011-11-30  Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* src/cmd-edit.c: adjust calls to sv_selection_add_full and
    	sv_selection_add_pos throughout
    	(sv_select_cur_inputs): fix leak
    	* src/commands.c (cmd_colrow_hide_correct_selection): adjust
    	calls to sv_selection_add_full
    	* src/item-grid.c (item_grid_button_released): simplify selection,
    	adjust call to sv_selection_add_pos
    	* src/selection.c (sv_selection_add_pos): add argument
    	(sv_selection_add_full): add argument
    	(sv_selection_simplified_free): new
    	(sv_selection_simplify): new
    	(sv_selection_calc_simplification): new, use it throughout instead of
    	accessing sv->selection directly
    	(sheet_selection_set_internal): redraw headers if the selection mode
    	is not just ADD
    	(sv_selection_free): use g_slist_free_full
    	* src/selection.h (GnmSelectionMode): new
    	(sv_selection_add_pos): add argument
    	(sv_selection_add_full): add argument
    	(sv_selection_simplified_free): new
    	(sv_selection_simplify): new
    	* src/sheet-control-gui.c: adjust calls to sv_selection_add_full and
    	sv_selection_add_pos throughout
    	* src/sheet-view.c (sv_real_dispose): dispose of simplified selection
    	(sheet_view_init): initialize selection fields
    	* src/sheet-view.h: add fields
    	* src/sheet.c (gnm_sheet_resize_main): adjust call to sv_selection_add_pos
    	* src/test-pango.c (cb_exercise_pango): adjust call to sv_selection_add_full
    	* src/workbook-view.c (wb_view_selection_desc): use selection_first_range
    	rather than accessing the fields directly
    
    2011-11-30 Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* excel-xml-read.c (xl_xml_selection): adjust call to
    	sv_selection_add_full
    	* ms-excel-read.c (excel_read_SELECTION): adjust calls to
    	sv_selection_add_full and sv_selection_add_pos

 ChangeLog                      |   33 +++++++
 NEWS                           |    3 +-
 plugins/excel/ChangeLog        |    7 ++
 plugins/excel/excel-xml-read.c |   10 ++-
 plugins/excel/ms-excel-read.c  |    6 +-
 src/cmd-edit.c                 |   47 ++++++-----
 src/commands.c                 |    6 +-
 src/item-grid.c                |   10 ++-
 src/selection.c                |  185 +++++++++++++++++++++++++++++++++-------
 src/selection.h                |   13 +++-
 src/sheet-control-gui.c        |   20 +++--
 src/sheet-view.c               |    6 +-
 src/sheet-view.h               |    3 +
 src/sheet.c                    |    6 +-
 src/test-pango.c               |    3 +-
 src/workbook-view.c            |    2 +-
 16 files changed, 279 insertions(+), 81 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 819dac5..8964fc5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2011-11-30  Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* src/cmd-edit.c: adjust calls to sv_selection_add_full and
+	sv_selection_add_pos throughout
+	(sv_select_cur_inputs): fix leak
+	* src/commands.c (cmd_colrow_hide_correct_selection): adjust
+	calls to sv_selection_add_full
+	* src/item-grid.c (item_grid_button_released): simplify selection,
+	adjust call to sv_selection_add_pos
+	* src/selection.c (sv_selection_add_pos): add argument
+	(sv_selection_add_full): add argument
+	(sv_selection_simplified_free): new
+	(sv_selection_simplify): new
+	(sv_selection_calc_simplification): new, use it throughout instead of
+	accessing sv->selection directly
+	(sheet_selection_set_internal): redraw headers if the selection mode
+	is not just ADD
+	(sv_selection_free): use g_slist_free_full
+	* src/selection.h (GnmSelectionMode): new
+	(sv_selection_add_pos): add argument
+	(sv_selection_add_full): add argument
+	(sv_selection_simplified_free): new
+	(sv_selection_simplify): new
+	* src/sheet-control-gui.c: adjust calls to sv_selection_add_full and
+	sv_selection_add_pos throughout
+	* src/sheet-view.c (sv_real_dispose): dispose of simplified selection
+	(sheet_view_init): initialize selection fields
+	* src/sheet-view.h: add fields
+	* src/sheet.c (gnm_sheet_resize_main): adjust call to sv_selection_add_pos
+	* src/test-pango.c (cb_exercise_pango): adjust call to sv_selection_add_full
+	* src/workbook-view.c (wb_view_selection_desc): use selection_first_range
+	rather than accessing the fields directly
+
 2011-11-28  Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* src/wbc-gtk.c (wbc_gtk_create_status_area): force auto expression
diff --git a/NEWS b/NEWS
index c72641c..13567aa 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,8 @@
 Gnumeric 1.11.2
 
 Andreas:
-	* Colour the range expressions to match the range cursor.
+	* Colour the range expressions to match the range cursor. [#632156]
+	* Implement ctrl-click cell deselection. [#610696]
 
 
 --------------------------------------------------------------------------
diff --git a/plugins/excel/ChangeLog b/plugins/excel/ChangeLog
index f85cb2e..0608dce 100644
--- a/plugins/excel/ChangeLog
+++ b/plugins/excel/ChangeLog
@@ -1,3 +1,10 @@
+2011-11-30 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* excel-xml-read.c (xl_xml_selection): adjust call to
+	sv_selection_add_full
+	* ms-excel-read.c (excel_read_SELECTION): adjust calls to
+	sv_selection_add_full and sv_selection_add_pos
+
 2011-11-27  Morten Welinder <terra gnome org>
 
 	* Release 1.11.1
diff --git a/plugins/excel/excel-xml-read.c b/plugins/excel/excel-xml-read.c
index 71cf71b..36dde1d 100644
--- a/plugins/excel/excel-xml-read.c
+++ b/plugins/excel/excel-xml-read.c
@@ -908,10 +908,12 @@ xl_xml_selection (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
 		end = rangeref_parse (&rr, ptr, &pp, gnm_conventions_xls_r1c1);
 		if (end != ptr) {
 			range_init_rangeref (&r, &rr);
-			sv_selection_add_full (sv,
-				state->pos.col, state->pos.row,
-				r.start.col, r.start.row,
-				r.end.col, r.end.row);
+			sv_selection_add_full 
+				(sv,
+				 state->pos.col, state->pos.row,
+				 r.start.col, r.start.row,
+				 r.end.col, r.end.row, 
+				 GNM_SELECTION_MODE_ADD);
 
 			if (*end != ',')
 				break;
diff --git a/plugins/excel/ms-excel-read.c b/plugins/excel/ms-excel-read.c
index 07c9494..23a2a58 100644
--- a/plugins/excel/ms-excel-read.c
+++ b/plugins/excel/ms-excel-read.c
@@ -4504,12 +4504,14 @@ excel_read_SELECTION (BiffQuery *q, ExcelReadSheet *esheet)
 		sv_selection_add_full (sv,
 				       tmp.col, tmp.row,
 				       r.start.col, r.start.row,
-				       r.end.col, r.end.row);
+				       r.end.col, r.end.row, 
+				       GNM_SELECTION_MODE_ADD);
 	}
 
 	if (sv->selections == NULL) {
 		/* See bug 632050 */
-		sv_selection_add_pos (sv, 0, 0);
+		sv_selection_add_pos (sv, 0, 0, 
+				      GNM_SELECTION_MODE_ADD);
 		d (5, g_printerr ("No selection\n"););
 	}
 
diff --git a/src/cmd-edit.c b/src/cmd-edit.c
index 5d14a50..51d404f 100644
--- a/src/cmd-edit.c
+++ b/src/cmd-edit.c
@@ -1,4 +1,4 @@
-/* vim: set sw=8: */
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * cmd-edit.c: Various commands to be used by the edit menu.
  *
@@ -55,9 +55,11 @@ sv_select_cur_row (SheetView *sv)
 	if (sel != NULL) {
 		GnmRange r = *sel;
 		sv_selection_reset (sv);
-		sv_selection_add_full (sv,
-			sv->edit_pos.col, sv->edit_pos.row,
-			0, r.start.row, gnm_sheet_get_last_col (sv->sheet), r.end.row);
+		sv_selection_add_full 
+			(sv,
+			 sv->edit_pos.col, sv->edit_pos.row,
+			 0, r.start.row, gnm_sheet_get_last_col (sv->sheet), r.end.row, 
+			 GNM_SELECTION_MODE_ADD);
 		sheet_update (sv->sheet);
 	}
 }
@@ -75,9 +77,11 @@ sv_select_cur_col (SheetView *sv)
 	if (sel != NULL) {
 		GnmRange r = *sel;
 		sv_selection_reset (sv);
-		sv_selection_add_full (sv,
-			sv->edit_pos.col, sv->edit_pos.row,
-			r.start.col, 0, r.end.col, gnm_sheet_get_last_row (sv->sheet));
+		sv_selection_add_full 
+			(sv,
+			 sv->edit_pos.col, sv->edit_pos.row,
+			 r.start.col, 0, r.end.col, gnm_sheet_get_last_row (sv->sheet), 
+			 GNM_SELECTION_MODE_ADD);
 		sheet_update (sv->sheet);
 	}
 }
@@ -101,7 +105,8 @@ sv_select_cur_array (SheetView *sv)
 	/* leave the edit pos where it is, select the entire array. */
 	sv_selection_reset (sv);
 	sv_selection_add_full (sv, c, r,
-		a.start.col, a.start.row, a.end.col, a.end.row);
+			       a.start.col, a.start.row, a.end.col, a.end.row, 
+			       GNM_SELECTION_MODE_ADD);
 	sheet_update (sv->sheet);
 }
 
@@ -161,7 +166,8 @@ sv_select_cur_depends (SheetView *sv)
 	/* Short circuit */
 	if (g_list_length (deps) == 1) {
 		GnmCell *cell = deps->data;
-		sv_selection_add_pos (sv, cell->pos.col, cell->pos.row);
+		sv_selection_add_pos (sv, cell->pos.col, cell->pos.row, 
+				      GNM_SELECTION_MODE_ADD);
 	} else {
 		GnmRange *cur = NULL;
 		ptr = NULL;
@@ -253,18 +259,17 @@ sv_select_cur_inputs (SheetView *sv)
 		GnmRangeRef const *r = value_get_rangeref (v);
 
 #warning "FIXME: What do we do in these 3D cases?"
-		if (r->a.sheet != r->b.sheet)
-			continue;
-		if (r->a.sheet != NULL && r->a.sheet != sv->sheet)
-			continue;
-
-		sv_selection_add_full (sv,
-			gnm_cellref_get_col (&r->a, &ep),
-			gnm_cellref_get_row (&r->a, &ep),
-			gnm_cellref_get_col (&r->a, &ep),
-			gnm_cellref_get_row (&r->a, &ep),
-			gnm_cellref_get_col (&r->b, &ep),
-			gnm_cellref_get_row (&r->b, &ep));
+		if ((r->a.sheet == r->b.sheet) && 
+		    (r->a.sheet == NULL || r->a.sheet == sv->sheet)) {
+		      gint row, col;
+		      row = gnm_cellref_get_row (&r->a, &ep);
+		      col = gnm_cellref_get_col (&r->a, &ep);
+		      sv_selection_add_full 
+			      (sv, col, row, col, row,
+			       gnm_cellref_get_col (&r->b, &ep),
+			       gnm_cellref_get_row (&r->b, &ep), 
+			       GNM_SELECTION_MODE_ADD);
+		    }
 		value_release (v);
 	}
 	g_slist_free (ranges);
diff --git a/src/commands.c b/src/commands.c
index 1834618..abcd85e 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -2235,10 +2235,12 @@ cmd_colrow_hide_correct_selection (CmdColRowHide *me, WorkbookControl *wbc)
 		sv_selection_reset (sv);
 		if (me->is_cols)
 			sv_selection_add_full (sv, y, x, y, 0,
-					       y, gnm_sheet_get_last_row (sheet));
+					       y, gnm_sheet_get_last_row (sheet), 
+					       GNM_SELECTION_MODE_ADD);
 		else
 			sv_selection_add_full (sv, y, x, 0, x,
-					       gnm_sheet_get_last_col (sheet), x);
+					       gnm_sheet_get_last_col (sheet), x, 
+					       GNM_SELECTION_MODE_ADD);
 	}
 #endif
 }
diff --git a/src/item-grid.c b/src/item-grid.c
index fee3c9c..fbb6b50 100644
--- a/src/item-grid.c
+++ b/src/item-grid.c
@@ -807,7 +807,7 @@ plain_draw : /* a quick hack to deal with 142267 */
 }
 
 static double
-item_grid_distance (GocItem *item, double x, double y,
+item_grid_distance (GocItem *item, G_GNUC_UNUSED double x, G_GNUC_UNUSED double y,
 		 GocItem **actual_item)
 {
 	*actual_item = item;
@@ -930,7 +930,10 @@ item_grid_button_pressed (GocItem *item, int button, double x_, double y_)
 
 		if (event->button != 1 || !(event->state & GDK_SHIFT_MASK) ||
 		    sv->selections == NULL) {
-			sv_selection_add_pos (sv, pos.col, pos.row);
+			sv_selection_add_pos (sv, pos.col, pos.row, 
+					      (already_selected && (event->state & GDK_CONTROL_MASK)) ? 
+					      GNM_SELECTION_MODE_REMOVE :
+					      GNM_SELECTION_MODE_ADD);
 			sv_make_cell_visible (sv, pos.col, pos.row, FALSE);
 		} else if (event->button != 2)
 			sv_selection_extend_to (sv, pos.col, pos.row);
@@ -1099,6 +1102,7 @@ item_grid_button_released (GocItem *item, int button, G_GNUC_UNUSED double x_, G
 /*				sheet->edit_pos.col, sheet->edit_pos.row, FALSE); */
 		/* Fall through */
 	case ITEM_GRID_SELECTING_CELL_RANGE :
+		sv_selection_simplify (scg_view (scg));
 		wb_view_selection_desc (
 			wb_control_view (scg_wbc (scg)), TRUE, NULL);
 		break;
@@ -1170,7 +1174,7 @@ item_grid_init (ItemGrid *ig)
 
 static void
 item_grid_set_property (GObject *obj, guint param_id,
-			GValue const *value, GParamSpec *pspec)
+			GValue const *value, G_GNUC_UNUSED GParamSpec *pspec)
 {
 	ItemGrid *ig = ITEM_GRID (obj);
 	GnmRange const *r;
diff --git a/src/selection.c b/src/selection.c
index 6fc6a19..112bcff 100644
--- a/src/selection.c
+++ b/src/selection.c
@@ -32,6 +32,63 @@
 #include "cell.h"
 
 /**
+ * sv_selection_calc_simplification:
+ * @sv :
+ * @mode:
+ *
+ * Create the simplified seelction list if necessary
+ *
+ * Returns the simplified version
+ **/
+
+static GSList *
+sv_selection_calc_simplification (SheetView const *sv)
+{
+	GSList *simp = NULL, *ptr;
+	GnmRange *r_rm;
+	SheetView *sv_mod = (SheetView *)sv;
+
+	if (sv->selection_mode != GNM_SELECTION_MODE_REMOVE)
+		return sv->selections;
+	if (sv->selections_simplified != NULL)
+		return sv->selections_simplified;
+
+	g_return_val_if_fail (sv->selections != NULL && 
+			      sv->selections->data != NULL,
+			      sv->selections);
+
+	ptr = sv->selections->next;
+	r_rm = sv->selections->data;
+
+	for (ptr = sv->selections->next; ptr != NULL; ptr = ptr->next) {
+		GnmRange *r = ptr->data;
+		if (range_overlap (r_rm, r)) {
+			GSList *pieces;
+			if (range_contained (r, r_rm))
+				continue;
+			pieces = range_split_ranges (r_rm, r);
+			g_free (pieces->data);
+			pieces = g_slist_delete_link (pieces, pieces);
+			simp = g_slist_concat (pieces, simp);
+		} else {
+			GnmRange *r_new = g_new (GnmRange, 1);
+			*r_new = *r;
+			simp = g_slist_prepend (simp, r_new);
+		}
+	}
+	
+	if (simp == NULL) {
+		GnmRange *r_new = g_new (GnmRange, 1);
+		range_init_cellpos (r_new, &sv->edit_pos);
+		simp = g_slist_prepend (simp, r_new);
+	}
+
+	sv_mod->selections_simplified = g_slist_reverse (simp);
+	
+	return sv->selections_simplified;
+}
+
+/**
  * sv_is_singleton_selected:
  * @sv :
  *
@@ -42,6 +99,7 @@
 GnmCellPos const *
 sv_is_singleton_selected (SheetView const *sv)
 {
+#warning FIXME Should we be using the selection rather than the cursor? 
 	if (sv->cursor.move_corner.col == sv->cursor.base_corner.col &&
 	    sv->cursor.move_corner.row == sv->cursor.base_corner.row)
 		return &sv->cursor.move_corner;
@@ -62,7 +120,8 @@ sv_is_pos_selected (SheetView const *sv, int col, int row)
 	GSList *ptr;
 	GnmRange const *sr;
 
-	for (ptr = sv->selections; ptr != NULL ; ptr = ptr->next) {
+	for (ptr = sv_selection_calc_simplification (sv);
+	     ptr != NULL ; ptr = ptr->next) {
 		sr = ptr->data;
 		if (range_contains (sr, col, row))
 			return TRUE;
@@ -83,7 +142,8 @@ sv_is_range_selected (SheetView const *sv, GnmRange const *r)
 	GSList *ptr;
 	GnmRange const *sr;
 
-	for (ptr = sv->selections; ptr != NULL ; ptr = ptr->next){
+	for (ptr = sv_selection_calc_simplification (sv);
+	     ptr != NULL ; ptr = ptr->next){
 		sr = ptr->data;
 		if (range_overlap (sr, r))
 			return TRUE;
@@ -105,7 +165,8 @@ sv_is_full_range_selected (SheetView const *sv, GnmRange const *r)
 	GSList *ptr;
 	GnmRange const *sr;
 
-	for (ptr = sv->selections; ptr != NULL ; ptr = ptr->next) {
+	for (ptr = sv_selection_calc_simplification (sv);
+	     ptr != NULL ; ptr = ptr->next) {
 		sr = ptr->data;
 		if (range_contained (r, sr))
 			return TRUE;
@@ -131,7 +192,11 @@ gboolean
 sv_is_colrow_selected (SheetView const *sv, int colrow, gboolean is_col)
 {
 	GSList *l;
-	for (l = sv->selections; l != NULL; l = l->next) {
+
+	g_return_val_if_fail (IS_SHEET_VIEW (sv), FALSE);
+
+	for (l = sv_selection_calc_simplification (sv);
+	     l != NULL; l = l->next) {
 		GnmRange const *ss = l->data;
 
 		if (is_col) {
@@ -166,7 +231,8 @@ sv_is_full_colrow_selected (SheetView const *sv, gboolean is_cols, int index)
 
 	g_return_val_if_fail (IS_SHEET_VIEW (sv), FALSE);
 
-	for (l = sv->selections; l != NULL; l = l->next){
+	for (l = sv_selection_calc_simplification (sv);
+	     l != NULL; l = l->next){
 		GnmRange const *r = l->data;
 		if (is_cols) {
 			if (r->start.row > 0 || r->end.row < gnm_sheet_get_last_row (sv->sheet))
@@ -203,7 +269,8 @@ sv_selection_col_type (SheetView const *sv, int col)
 	if (sv->selections == NULL)
 		return COL_ROW_NO_SELECTION;
 
-	for (ptr = sv->selections; ptr != NULL; ptr = ptr->next) {
+	for (ptr = sv_selection_calc_simplification (sv);
+	     ptr != NULL; ptr = ptr->next) {
 		sr = ptr->data;
 
 		if (sr->start.col > col || sr->end.col < col)
@@ -238,7 +305,8 @@ sv_selection_row_type (SheetView const *sv, int row)
 	if (sv->selections == NULL)
 		return COL_ROW_NO_SELECTION;
 
-	for (ptr = sv->selections; ptr != NULL; ptr = ptr->next) {
+	for (ptr = sv_selection_calc_simplification (sv);
+	     ptr != NULL; ptr = ptr->next) {
 		sr = ptr->data;
 
 		if (sr->start.row > row || sr->end.row < row)
@@ -429,6 +497,8 @@ sheet_selection_set_internal (SheetView *sv,
 	if (!just_add_it && range_equal (ss, &new_sel))
 		return;
 
+	sv_selection_simplified_free (sv);
+
 	old_sel = *ss;
 	*ss = new_sel;
 
@@ -460,8 +530,9 @@ sheet_selection_set_internal (SheetView *sv,
 	}
 
 	/* Has the entire row been selected/unselected */
-	if ((new_sel.start.row == 0 && new_sel.end.row == gnm_sheet_get_last_row (sv->sheet)) ^
-	    (old_sel.start.row == 0 && old_sel.end.row == gnm_sheet_get_last_row (sv->sheet))) {
+	if (((new_sel.start.row == 0 && new_sel.end.row == gnm_sheet_get_last_row (sv->sheet)) ^
+	     (old_sel.start.row == 0 && old_sel.end.row == gnm_sheet_get_last_row (sv->sheet)))
+	    || sv->selection_mode != GNM_SELECTION_MODE_ADD) {
 		GnmRange tmp = range_union (&new_sel, &old_sel);
 		sv_redraw_headers (sv, TRUE, FALSE, &tmp);
 	} else {
@@ -493,8 +564,9 @@ sheet_selection_set_internal (SheetView *sv,
 	}
 
 	/* Has the entire col been selected/unselected */
-	if ((new_sel.start.col == 0 && new_sel.end.col == gnm_sheet_get_last_col (sv->sheet)) ^
-	    (old_sel.start.col == 0 && old_sel.end.col == gnm_sheet_get_last_col (sv->sheet))) {
+	if (((new_sel.start.col == 0 && new_sel.end.col == gnm_sheet_get_last_col (sv->sheet)) ^
+	     (old_sel.start.col == 0 && old_sel.end.col == gnm_sheet_get_last_col (sv->sheet)))
+	    || sv->selection_mode != GNM_SELECTION_MODE_ADD) {
 		GnmRange tmp = range_union (&new_sel, &old_sel);
 		sv_redraw_headers (sv, FALSE, TRUE, &tmp);
 	} else {
@@ -574,6 +646,29 @@ sv_selection_set (SheetView *sv, GnmCellPos const *edit,
 		move_col, move_row, FALSE);
 }
 
+void
+sv_selection_simplify (SheetView *sv)
+{
+	switch (sv->selection_mode) {
+	case GNM_SELECTION_MODE_ADD:
+		/* already simplified */
+		return;
+	case GNM_SELECTION_MODE_REMOVE:
+		sv_selection_calc_simplification (sv);
+		if (sv->selections_simplified != NULL) {
+			sv_selection_free (sv);
+			sv->selections = sv->selections_simplified;
+			sv->selections_simplified = NULL;
+		}
+		break;
+	default:
+	case GNM_SELECTION_MODE_TOGGLE:
+		g_warning ("Selection mode %d not implemented!\n", sv->selection_mode);
+		break;
+	}
+	sv->selection_mode = GNM_SELECTION_MODE_ADD;
+}
+
 /**
  * sv_selection_add_full :
  * @sv             : #SheetView whose selection is append to.
@@ -587,16 +682,19 @@ void
 sv_selection_add_full (SheetView *sv,
 		       int edit_col, int edit_row,
 		       int base_col, int base_row,
-		       int move_col, int move_row)
+		       int move_col, int move_row, 
+		       GnmSelectionMode mode)
 {
 	GnmRange *ss;
 	GnmCellPos edit;
 
 	g_return_if_fail (IS_SHEET_VIEW (sv));
+	sv_selection_simplify (sv);
 
 	/* Create and prepend new selection */
 	ss = g_new0 (GnmRange, 1);
 	sv->selections = g_slist_prepend (sv->selections, ss);
+	sv->selection_mode = mode;
 	edit.col = edit_col;
 	edit.row = edit_row;
 	sheet_selection_set_internal (sv, &edit,
@@ -608,12 +706,13 @@ void
 sv_selection_add_range (SheetView *sv, GnmRange const *r)
 {
 	sv_selection_add_full (sv, r->start.col, r->start.row,
-		r->start.col, r->start.row, r->end.col, r->end.row);
+			       r->start.col, r->start.row, r->end.col, r->end.row, 
+			       GNM_SELECTION_MODE_ADD);
 }
 void
-sv_selection_add_pos (SheetView *sv, int col, int row)
+sv_selection_add_pos (SheetView *sv, int col, int row, GnmSelectionMode mode)
 {
-	sv_selection_add_full (sv, col, row, col, row, col, row);
+	sv_selection_add_full (sv, col, row, col, row, col, row, mode);
 }
 
 /**
@@ -628,12 +727,23 @@ sv_selection_add_pos (SheetView *sv, int col, int row)
 void
 sv_selection_free (SheetView *sv)
 {
-	GSList *list;
-
-	for (list = sv->selections; list; list = list->next)
-		g_free (list->data);
-	g_slist_free (sv->selections);
+	g_slist_free_full (sv->selections, g_free);
 	sv->selections = NULL;
+	sv->selection_mode = GNM_SELECTION_MODE_ADD;
+}
+
+/**
+ * sv_selection_simplified_free
+ * @sv: #SheetView
+ *
+ * Releases the simplified selection associated with @sv
+ *
+ **/
+void
+sv_selection_simplified_free (SheetView *sv)
+{
+	g_slist_free_full (sv->selections_simplified, g_free);
+	sv->selections_simplified = NULL;
 }
 
 /**
@@ -656,6 +766,7 @@ sv_selection_reset (SheetView *sv)
 	/* Empty the sheets selection */
 	list = sv->selections;
 	sv->selections = NULL;
+	sv->selection_mode = GNM_SELECTION_MODE_ADD;
 
 	/* Redraw the grid, & headers for each region */
 	for (tmp = list; tmp; tmp = tmp->next){
@@ -689,12 +800,14 @@ selection_get_ranges (SheetView const *sv, gboolean allow_intersection)
 	g_printerr ("============================\n");
 #endif
 
+	l = sv_selection_calc_simplification (sv);
+
 	/*
 	 * Run through all the selection regions to see if any of
 	 * the proposed regions overlap.  Start the search with the
 	 * single user proposed segment and accumulate distict regions.
 	 */
-	for (l = sv->selections; l != NULL; l = l->next) {
+	for (; l != NULL; l = l->next) {
 		GnmRange const *r = l->data;
 
 		/* The set of regions that do not interset with b or
@@ -969,7 +1082,9 @@ selection_get_ranges (SheetView const *sv, gboolean allow_intersection)
  * Applies the specified function for all ranges in the selection.  Optionally
  * select whether to use the high level potentially over lapped ranges, rather
  * than the smaller system created non-intersection regions.
+ *
  */
+
 void
 sv_selection_apply (SheetView *sv, SelectionApplyFunc const func,
 		    gboolean allow_intersection,
@@ -981,13 +1096,14 @@ sv_selection_apply (SheetView *sv, SelectionApplyFunc const func,
 	g_return_if_fail (IS_SHEET_VIEW (sv));
 
 	if (allow_intersection) {
-		for (l = sv->selections; l != NULL; l = l->next) {
+		for (l = sv_selection_calc_simplification (sv);
+		     l != NULL; l = l->next) {
 			GnmRange const *ss = l->data;
 
 			(*func) (sv, ss, closure);
 		}
 	} else {
-		proposed = selection_get_ranges (sv, allow_intersection);
+		proposed = selection_get_ranges (sv, FALSE);
 		while (proposed != NULL) {
 			/* pop the 1st element off the list */
 			GnmRange *r = proposed->data;
@@ -1039,7 +1155,7 @@ sv_selection_apply_in_order (SheetView *sv, SelectionApplyFunc const func,
 
 	g_return_if_fail (IS_SHEET_VIEW (sv));
 
-	reverse = g_slist_copy (sv->selections);
+	reverse = g_slist_copy (sv_selection_calc_simplification (sv));
 	reverse = g_slist_reverse (reverse);
 	for (l = reverse; l != NULL; l = l->next) {
 		GnmRange const *ss = l->data;
@@ -1087,7 +1203,7 @@ sv_selection_foreach (SheetView *sv,
 
 	g_return_val_if_fail (IS_SHEET_VIEW (sv), FALSE);
 
-	for (l = sv->selections; l != NULL; l = l->next) {
+	for (l = sv_selection_calc_simplification (sv); l != NULL; l = l->next) {
 		GnmRange *ss = l->data;
 		if (!range_cb (sv, ss, user_data))
 			return FALSE;
@@ -1221,12 +1337,15 @@ sv_selection_walk_step (SheetView *sv, gboolean forward, gboolean horizontal)
 	GnmCellPos destination;
 	GnmRange const *ss;
 	gboolean is_singleton = FALSE;
+	GSList *selections;
 
 	g_return_if_fail (IS_SHEET_VIEW (sv));
 	g_return_if_fail (sv->selections != NULL);
 
-	ss = sv->selections->data;
-	selections_count = g_slist_length (sv->selections);
+	selections = sv_selection_calc_simplification (sv);
+
+	ss = selections->data;
+	selections_count = g_slist_length (selections);
 
 	/* If there is no selection besides the cursor iterate through the
 	 * entire sheet.  Move the cursor and selection as we go.  Ignore
@@ -1358,7 +1477,7 @@ characterize_vec (Sheet *sheet, GnmRange *vector,
 void
 sv_selection_to_plot (SheetView *sv, GogPlot *go_plot)
 {
-	GSList *ptr, *sels;
+	GSList *ptr, *sels, *selections;
 	GnmRange const *r;
 	int num_cols, num_rows;
 
@@ -1376,11 +1495,13 @@ sv_selection_to_plot (SheetView *sv, GogPlot *go_plot)
 
 	gboolean default_to_cols;
 
+	selections = sv_selection_calc_simplification (sv);
+
 	/* Use the total number of cols vs rows in all of the selected regions.
 	 * We can not use just one in case one of the others happens to be the transpose
 	 * eg select A1 + A:B would default_to_cols = FALSE, then produce a vector for each row */
 	num_cols = num_rows = 0;
-	for (ptr = sv->selections; ptr != NULL ; ptr = ptr->next) {
+	for (ptr = selections; ptr != NULL ; ptr = ptr->next) {
 		r = ptr->data;
 		num_cols += range_width (r);
 		num_rows += range_height (r);
@@ -1403,7 +1524,7 @@ sv_selection_to_plot (SheetView *sv, GogPlot *go_plot)
 		to retrieve the axis data and the matrix z values. We probably should raise
 		an error condition if it is not the case */
 		/* selections are in reverse order so walk them backwards */
-		GSList const *ptr = g_slist_last (sv->selections);
+		GSList const *ptr = g_slist_last (selections);
 		GnmRange vector = *((GnmRange const *) ptr->data);
 		int start_row = vector.start.row;
 		int start_col = vector.start.col;
@@ -1447,7 +1568,7 @@ sv_selection_to_plot (SheetView *sv, GogPlot *go_plot)
 
 	/* selections are in reverse order so walk them backwards */
 	cur_dim = 0;
-	sels = ptr = g_slist_reverse (g_slist_copy (sv->selections));
+	sels = ptr = g_slist_reverse (g_slist_copy (selections));
 	for (; ptr != NULL; ptr = ptr->next) {
 		GnmRange vector = *((GnmRange const *)ptr->data);
 
@@ -1546,5 +1667,5 @@ skip :
 
 	g_slist_free (sels);
 
-#warning TODO is last series is incomplete try to shift data out of optional dimensions
+#warning TODO If last series is incomplete try to shift data out of optional dimensions.
 }
diff --git a/src/selection.h b/src/selection.h
index ae3a463..765ae27 100644
--- a/src/selection.h
+++ b/src/selection.h
@@ -13,6 +13,12 @@ typedef enum {
 	COL_ROW_FULL_SELECTION
 } ColRowSelectionType;
 
+typedef enum {
+	GNM_SELECTION_MODE_ADD = 0,
+	GNM_SELECTION_MODE_REMOVE,
+	GNM_SELECTION_MODE_TOGGLE
+} GnmSelectionMode;
+
 /* Selection information */
 GnmCellPos const *sv_is_singleton_selected (SheetView const *sv);
 gboolean sv_is_pos_selected         (SheetView const *sv, int col, int row);
@@ -36,17 +42,20 @@ void	 sv_selection_to_plot	   (SheetView *sv, GogPlot *plot);
 
 /* Selection management */
 void	 sv_selection_reset	   (SheetView *sv);
-void	 sv_selection_add_pos	   (SheetView *sv, int col, int row);
+void	 sv_selection_add_pos	   (SheetView *sv, int col, int row, GnmSelectionMode mode);
 void	 sv_selection_add_range	   (SheetView *sv, GnmRange const *range);
 void	 sv_selection_add_full	   (SheetView *sv,
 				    int edit_col, int edit_row,
 				    int base_col, int base_row,
-				    int move_col, int move_row);
+				    int move_col, int move_row, 
+				    GnmSelectionMode mode);
 void	sv_selection_set	   (SheetView *sv, GnmCellPos const *edit,
 				    int base_col, int base_row,
 				    int move_col, int move_row);
 void	sv_selection_extend_to	   (SheetView *sv, int col, int row);
 void	sv_selection_free	   (SheetView *sv);
+void	sv_selection_simplified_free  (SheetView *sv);
+void    sv_selection_simplify         (SheetView *sv);
 
 void	sv_selection_walk_step	   (SheetView *sv,
 				    gboolean forward,
diff --git a/src/sheet-control-gui.c b/src/sheet-control-gui.c
index 863a2d7..b8feb93 100644
--- a/src/sheet-control-gui.c
+++ b/src/sheet-control-gui.c
@@ -485,7 +485,9 @@ scg_select_all (SheetControlGUI *scg)
 		wbcg_edit_finish (scg->wbcg, WBC_EDIT_REJECT, NULL);
 		sv_selection_reset (sv);
 		sv_selection_add_full (sv, sv->edit_pos.col, sv->edit_pos.row,
-			0, 0, gnm_sheet_get_last_col (sheet), gnm_sheet_get_last_row (sheet));
+				       0, 0, gnm_sheet_get_last_col (sheet), 
+				       gnm_sheet_get_last_row (sheet), 
+				       GNM_SELECTION_MODE_ADD);
 	}
 	sheet_update (sheet);
 }
@@ -528,16 +530,18 @@ scg_colrow_select (SheetControlGUI *scg, gboolean is_cols,
 			GnmPane *pane =
 				scg_pane (scg, scg->pane[3] ? 3 : 0);
 			sv_selection_add_full (sv,
-				index, pane->first.row,
-				index, 0,
-				index, gnm_sheet_get_last_row (sv->sheet));
+					       index, pane->first.row,
+					       index, 0,
+					       index, gnm_sheet_get_last_row (sv->sheet), 
+					       GNM_SELECTION_MODE_ADD);
 		} else {
 			GnmPane *pane =
 				scg_pane (scg, scg->pane[1] ? 1 : 0);
 			sv_selection_add_full (sv,
-				pane->first.col, index,
-				0, index,
-				gnm_sheet_get_last_col (sv->sheet), index);
+					       pane->first.col, index,
+					       0, index,
+					       gnm_sheet_get_last_col (sv->sheet), index, 
+					       GNM_SELECTION_MODE_ADD);
 		}
 	}
 
@@ -3448,7 +3452,7 @@ scg_cursor_move (SheetControlGUI *scg, int n,
 	sv_cursor_set (sv, &tmp,
 		       tmp.col, tmp.row, tmp.col, tmp.row, NULL);
 	sv_make_cell_visible (sv, tmp.col, tmp.row, FALSE);
-	sv_selection_add_pos (sv, tmp.col, tmp.row);
+	sv_selection_add_pos (sv, tmp.col, tmp.row, GNM_SELECTION_MODE_ADD);
 }
 
 /**
diff --git a/src/sheet-view.c b/src/sheet-view.c
index d30a999..4e11f98 100644
--- a/src/sheet-view.c
+++ b/src/sheet-view.c
@@ -223,6 +223,7 @@ sv_real_dispose (GObject *object)
 
 	sv_unant (sv);
 	sv_selection_free (sv);
+	sv_selection_simplified_free (sv);
 	auto_expr_timer_clear (sv);
 
 	parent_class->dispose (object);
@@ -260,7 +261,10 @@ sheet_view_init (GObject *object)
 	sv->unfrozen_top_left.col = sv->unfrozen_top_left.row = -1;
 	sv->initial_top_left.col = sv->initial_top_left.row = 0;
 
-	sv_selection_add_pos (sv, 0, 0);
+	sv->selections = NULL;
+	sv->selection_mode = GNM_SELECTION_MODE_ADD;
+	sv->selections_simplified = NULL;
+	sv_selection_add_pos (sv, 0, 0, GNM_SELECTION_MODE_ADD);
 }
 
 GSF_CLASS (SheetView, sheet_view,
diff --git a/src/sheet-view.h b/src/sheet-view.h
index ea5d954..c9b836d 100644
--- a/src/sheet-view.h
+++ b/src/sheet-view.h
@@ -26,6 +26,9 @@ struct _SheetView {
 	 * a normalized version of SheetView::{cursor.base_corner:move_corner}
 	 */
 	GSList		*selections;
+	GSList		*selections_simplified;
+	int              selection_mode; /* GnmSelectionMode */
+
 	GnmCellPos	 edit_pos;	/* Cell that would be edited */
 	GnmCellPos	 edit_pos_real;	/* Even in the middle of a merged cell */
 	int		 first_tab_col;	/* where to jump to after an Enter */
diff --git a/src/sheet.c b/src/sheet.c
index 1c8a3a8..598c7cc 100644
--- a/src/sheet.c
+++ b/src/sheet.c
@@ -1200,9 +1200,9 @@ gnm_sheet_resize_main (Sheet *sheet, int cols, int rows,
 				g_free (r);
 			}
 			g_slist_free (sel);
-			if (!any) {
-				sv_selection_add_pos (sv, 0, 0);
-			}
+			if (!any)
+				sv_selection_add_pos (sv, 0, 0, 
+						      GNM_SELECTION_MODE_ADD);
 			sv_make_cell_visible (sv, vis.col, vis.row, FALSE);
 		});
 
diff --git a/src/test-pango.c b/src/test-pango.c
index d9efc4a..432e7fb 100644
--- a/src/test-pango.c
+++ b/src/test-pango.c
@@ -42,7 +42,8 @@ cb_exercise_pango (gpointer data)
 
 	if (state == 0) {
 		sv_selection_reset (sv);
-		sv_selection_add_full(sv, 0, 0, 0, 0, 40, STEP_SIZE*TEST_STEPS);
+		sv_selection_add_full (sv, 0, 0, 0, 0, 40, STEP_SIZE*TEST_STEPS, 
+				       GNM_SELECTION_MODE_ADD);
 		cmd_area_set_text (wbc, sv, "=rand()", NULL);
 	} else if (state < TEST_STEPS) {
 		SHEET_VIEW_FOREACH_CONTROL(wb_control_cur_sheet_view (wbc),
diff --git a/src/workbook-view.c b/src/workbook-view.c
index d1b90d6..984adb9 100644
--- a/src/workbook-view.c
+++ b/src/workbook-view.c
@@ -369,7 +369,7 @@ wb_view_selection_desc (WorkbookView *wbv, gboolean use_pos,
 		g_return_if_fail (IS_SHEET_VIEW (sv));
 		g_return_if_fail (sv->selections);
 
-		r = sv->selections->data;
+		r = selection_first_range (sv, NULL, NULL);
 
 		if (use_pos || range_is_singleton (r) ||
 		    (NULL != (m = gnm_sheet_merge_is_corner (sv->sheet, &r->start)) &&



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