From 32c3d29bbc14cc1d4c054eb9d6538b0199e90c61 Mon Sep 17 00:00:00 2001 From: Christopher James Lahey Date: Wed, 26 Jul 2000 20:33:39 +0000 Subject: Added "table_selection_model" argument. Removed foreach function and 2000-07-26 Christopher James Lahey * e-table-group-container.c, e-table-group-container.h, e-table-group-leaf.c, e-table-group-leaf.h: Added "table_selection_model" argument. Removed foreach function and selection notification. * e-table-group.c, e-table-group.h: Removed foreach function and selection notification. * e-table-header.c: Fixed header width calculation to include the last column. * e-table-item.c, e-table-item.h: Fixed this to use the new selection model. * e-table-scrolled.c, e-table-scrolled.h: Removed selection notification. * e-table-selection-model.c, e-table-selection-model.h: Finished notification signals and fixed a bunch of bit manipulations. Implemented do_something method. * e-table.c, e-table.h: Create an ETableSelectionModel and use it properly. svn path=/trunk/; revision=4363 --- widgets/e-table/ChangeLog | 25 ++ widgets/e-table/e-table-group-container.c | 55 ++-- widgets/e-table/e-table-group-container.h | 2 + widgets/e-table/e-table-group-leaf.c | 38 +-- widgets/e-table/e-table-group-leaf.h | 2 + widgets/e-table/e-table-group.c | 36 --- widgets/e-table/e-table-group.h | 8 - widgets/e-table/e-table-header.c | 2 +- widgets/e-table/e-table-item.c | 447 +++++++++++++++--------------- widgets/e-table/e-table-item.h | 11 +- widgets/e-table/e-table-scrolled.c | 20 -- widgets/e-table/e-table-scrolled.h | 1 - widgets/e-table/e-table-selection-model.c | 238 +++++++++++++--- widgets/e-table/e-table-selection-model.h | 31 ++- widgets/e-table/e-table.c | 50 +--- widgets/e-table/e-table.h | 1 - widgets/table/e-table-group-container.c | 55 ++-- widgets/table/e-table-group-container.h | 2 + widgets/table/e-table-group-leaf.c | 38 +-- widgets/table/e-table-group-leaf.h | 2 + widgets/table/e-table-group.c | 36 --- widgets/table/e-table-group.h | 8 - widgets/table/e-table-header.c | 2 +- widgets/table/e-table-item.c | 447 +++++++++++++++--------------- widgets/table/e-table-item.h | 11 +- widgets/table/e-table-scrolled.c | 20 -- widgets/table/e-table-scrolled.h | 1 - widgets/table/e-table-selection-model.c | 238 +++++++++++++--- widgets/table/e-table-selection-model.h | 31 ++- widgets/table/e-table.c | 50 +--- widgets/table/e-table.h | 1 - 31 files changed, 1041 insertions(+), 868 deletions(-) diff --git a/widgets/e-table/ChangeLog b/widgets/e-table/ChangeLog index 39e7449fd9..6f8633c08c 100644 --- a/widgets/e-table/ChangeLog +++ b/widgets/e-table/ChangeLog @@ -1,3 +1,28 @@ +2000-07-26 Christopher James Lahey + + * e-table-group-container.c, e-table-group-container.h, + e-table-group-leaf.c, e-table-group-leaf.h: Added "table_selection_model" + argument. Removed foreach function and selection notification. + + * e-table-group.c, e-table-group.h: Removed foreach function and + selection notification. + + * e-table-header.c: Fixed header width calculation to include the + last column. + + * e-table-item.c, e-table-item.h: Fixed this to use the new + selection model. + + * e-table-scrolled.c, e-table-scrolled.h: Removed selection + notification. + + * e-table-selection-model.c, e-table-selection-model.h: Finished + notification signals and fixed a bunch of bit manipulations. + Implemented do_something method. + + * e-table.c, e-table.h: Create an ETableSelectionModel and use it + properly. + 2000-07-25 Christopher James Lahey * e-table-selection-model.c: Made foreach call the callback in top diff --git a/widgets/e-table/e-table-group-container.c b/widgets/e-table/e-table-group-container.c index f4e10917fb..f3788f154f 100644 --- a/widgets/e-table/e-table-group-container.c +++ b/widgets/e-table/e-table-group-container.c @@ -37,6 +37,7 @@ enum { ARG_TABLE_DRAW_GRID, ARG_TABLE_DRAW_FOCUS, ARG_CURSOR_MODE, + ARG_TABLE_SELECTION_MODEL, ARG_LENGTH_THRESHOLD, }; @@ -97,6 +98,9 @@ etgc_destroy (GtkObject *object) if (etgc->sort_info) gtk_object_unref (GTK_OBJECT(etgc->sort_info)); + if (etgc->table_selection_model) + gtk_object_unref (GTK_OBJECT(etgc->table_selection_model)); + if (etgc->rect) gtk_object_destroy (GTK_OBJECT(etgc->rect)); @@ -315,13 +319,6 @@ compute_text (ETableGroupContainer *etgc, ETableGroupContainerChildNode *child_n g_free (text); } -static void -child_row_selection (ETableGroup *etg, int row, gboolean selected, - ETableGroupContainer *etgc) -{ - e_table_group_row_selection (E_TABLE_GROUP (etgc), row, selected); -} - static void child_cursor_change (ETableGroup *etg, int row, ETableGroupContainer *etgc) @@ -395,10 +392,9 @@ etgc_add (ETableGroup *etg, gint row) "drawgrid", etgc->draw_grid, "drawfocus", etgc->draw_focus, "cursor_mode", etgc->cursor_mode, + "table_selection_model", etgc->table_selection_model, "length_threshold", etgc->length_threshold, NULL); - gtk_signal_connect (GTK_OBJECT (child), "row_selection", - GTK_SIGNAL_FUNC (child_row_selection), etgc); gtk_signal_connect (GTK_OBJECT (child), "cursor_change", GTK_SIGNAL_FUNC (child_cursor_change), etgc); gtk_signal_connect (GTK_OBJECT (child), "double_click", @@ -546,29 +542,6 @@ etgc_get_focus_column (ETableGroup *etg) return 0; } -static void -etgc_selected_row_foreach (ETableGroup *etg, - ETableForeachFunc func, - gpointer closure) -{ - ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg); - if (etgc->children) { - GList *list; - for (list = etgc->children; list; list = list->next) { - ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data; - ETableGroup *child = child_node->child; - e_table_group_selected_row_foreach (child, func, closure); - } - } -} - - - - - - - - static void etgc_thaw (ETableGroup *etg) { @@ -612,6 +585,20 @@ etgc_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) } break; + case ARG_TABLE_SELECTION_MODEL: + if (etgc->table_selection_model) + gtk_object_unref(GTK_OBJECT(etgc->table_selection_model)); + etgc->table_selection_model = E_TABLE_SELECTION_MODEL(GTK_VALUE_OBJECT (*arg)); + if (etgc->table_selection_model) + gtk_object_ref(GTK_OBJECT(etgc->table_selection_model)); + for (list = etgc->children; list; list = g_list_next (list)) { + ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data; + gtk_object_set (GTK_OBJECT(child_node->child), + "table_selection_model", etgc->table_selection_model, + NULL); + } + break; + case ARG_TABLE_DRAW_GRID: etgc->draw_grid = GTK_VALUE_BOOL (*arg); for (list = etgc->children; list; list = g_list_next (list)) { @@ -697,7 +684,6 @@ etgc_class_init (GtkObjectClass *object_class) e_group_class->get_cursor_row = etgc_get_cursor_row; e_group_class->get_focus_column = etgc_get_focus_column; e_group_class->get_printable = etgc_get_printable; - e_group_class->selected_row_foreach = etgc_selected_row_foreach; gtk_object_add_arg_type ("ETableGroupContainer::drawgrid", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); @@ -705,6 +691,8 @@ etgc_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_TABLE_DRAW_FOCUS); gtk_object_add_arg_type ("ETableGroupContainer::cursor_mode", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_CURSOR_MODE); + gtk_object_add_arg_type ("ETableGroupContainer::table_selection_model", GTK_TYPE_OBJECT, + GTK_ARG_WRITABLE, ARG_TABLE_SELECTION_MODEL); gtk_object_add_arg_type ("ETableGroupContainer::length_threshold", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_LENGTH_THRESHOLD); @@ -811,6 +799,7 @@ etgc_init (GtkObject *object) container->draw_focus = 1; container->cursor_mode = E_TABLE_CURSOR_SIMPLE; container->length_threshold = -1; + container->table_selection_model = NULL; } E_MAKE_TYPE (e_table_group_container, "ETableGroupContainer", ETableGroupContainer, etgc_class_init, etgc_init, PARENT_TYPE); diff --git a/widgets/e-table/e-table-group-container.h b/widgets/e-table/e-table-group-container.h index 1157768ea4..bdb717b92d 100644 --- a/widgets/e-table/e-table-group-container.h +++ b/widgets/e-table/e-table-group-container.h @@ -41,6 +41,8 @@ typedef struct { int n; int length_threshold; + ETableSelectionModel *table_selection_model; + guint draw_grid : 1; guint draw_focus : 1; ETableCursorMode cursor_mode; diff --git a/widgets/e-table/e-table-group-leaf.c b/widgets/e-table/e-table-group-leaf.c index 08c4c4a475..f6b540cdae 100644 --- a/widgets/e-table/e-table-group-leaf.c +++ b/widgets/e-table/e-table-group-leaf.c @@ -31,6 +31,7 @@ enum { ARG_TABLE_DRAW_FOCUS, ARG_CURSOR_MODE, ARG_LENGTH_THRESHOLD, + ARG_TABLE_SELECTION_MODEL, }; static void etgl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); @@ -44,6 +45,8 @@ etgl_destroy (GtkObject *object) gtk_object_unref (GTK_OBJECT(etgl->subset)); if (etgl->item) gtk_object_destroy (GTK_OBJECT(etgl->item)); + if (etgl->table_selection_model) + gtk_object_unref (GTK_OBJECT(etgl->table_selection_model)); if (GTK_OBJECT_CLASS (etgl_parent_class)->destroy) GTK_OBJECT_CLASS (etgl_parent_class)->destroy (object); } @@ -80,13 +83,6 @@ e_table_group_leaf_new (GnomeCanvasGroup *parent, return E_TABLE_GROUP (etgl); } -static void -etgl_row_selection (GtkObject *object, gint row, gboolean selected, ETableGroupLeaf *etgl) -{ - if (row < E_TABLE_SUBSET(etgl->subset)->n_map) - e_table_group_row_selection (E_TABLE_GROUP(etgl), E_TABLE_SUBSET(etgl->subset)->map_table[row], selected); -} - static void etgl_cursor_change (GtkObject *object, gint row, ETableGroupLeaf *etgl) { @@ -149,10 +145,9 @@ etgl_realize (GnomeCanvasItem *item) "cursor_mode", etgl->cursor_mode, "minimum_width", etgl->minimum_width, "length_threshold", etgl->length_threshold, + "table_selection_model", etgl->table_selection_model, NULL)); - gtk_signal_connect (GTK_OBJECT(etgl->item), "row_selection", - GTK_SIGNAL_FUNC(etgl_row_selection), etgl); gtk_signal_connect (GTK_OBJECT(etgl->item), "cursor_change", GTK_SIGNAL_FUNC(etgl_cursor_change), etgl); gtk_signal_connect (GTK_OBJECT(etgl->item), "double_click", @@ -244,15 +239,6 @@ etgl_get_printable (ETableGroup *etg) return e_table_item_get_printable (etgl->item); } -static void -etgl_selected_row_foreach(ETableGroup *etg, - ETableForeachFunc func, - gpointer closure) -{ - ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg); - e_table_item_selected_row_foreach (etgl->item, func, closure); -} - static void etgl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) { @@ -284,6 +270,17 @@ etgl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) NULL); } break; + case ARG_TABLE_SELECTION_MODEL: + if (etgl->table_selection_model) + gtk_object_unref(GTK_OBJECT(etgl->table_selection_model)); + etgl->table_selection_model = E_TABLE_SELECTION_MODEL(GTK_VALUE_OBJECT (*arg)); + if (etgl->table_selection_model) + gtk_object_ref(GTK_OBJECT(etgl->table_selection_model)); + if (etgl->item) { + gnome_canvas_item_set (GNOME_CANVAS_ITEM(etgl->item), + "table_selection_model", etgl->table_selection_model, + NULL); + } case ARG_TABLE_DRAW_GRID: etgl->draw_grid = GTK_VALUE_BOOL (*arg); @@ -365,7 +362,6 @@ etgl_class_init (GtkObjectClass *object_class) e_group_class->get_cursor_row = etgl_get_cursor_row; e_group_class->get_focus_column = etgl_get_focus_column; e_group_class->get_printable = etgl_get_printable; - e_group_class->selected_row_foreach = etgl_selected_row_foreach; gtk_object_add_arg_type ("ETableGroupLeaf::drawgrid", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); @@ -375,6 +371,8 @@ etgl_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_CURSOR_MODE); gtk_object_add_arg_type ("ETableGroupLeaf::length_threshold", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_LENGTH_THRESHOLD); + gtk_object_add_arg_type ("ETableGroupLeaf::table_selection_model", GTK_TYPE_OBJECT, + GTK_ARG_WRITABLE, ARG_TABLE_SELECTION_MODEL); gtk_object_add_arg_type ("ETableGroupLeaf::height", GTK_TYPE_DOUBLE, GTK_ARG_READABLE, ARG_HEIGHT); @@ -403,6 +401,8 @@ etgl_init (GtkObject *object) etgl->cursor_mode = E_TABLE_CURSOR_SIMPLE; etgl->length_threshold = -1; + etgl->table_selection_model = NULL; + e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM(object), etgl_reflow); } diff --git a/widgets/e-table/e-table-group-leaf.h b/widgets/e-table/e-table-group-leaf.h index 365f268307..1cc041206b 100644 --- a/widgets/e-table/e-table-group-leaf.h +++ b/widgets/e-table/e-table-group-leaf.h @@ -32,6 +32,8 @@ typedef struct { guint draw_grid : 1; guint draw_focus : 1; ETableCursorMode cursor_mode; + + ETableSelectionModel *table_selection_model; } ETableGroupLeaf; typedef struct { diff --git a/widgets/e-table/e-table-group.c b/widgets/e-table/e-table-group.c index 18f8084b2c..d3c6e2e08d 100644 --- a/widgets/e-table/e-table-group.c +++ b/widgets/e-table/e-table-group.c @@ -25,7 +25,6 @@ static GnomeCanvasGroupClass *etg_parent_class; enum { - ROW_SELECTION, CURSOR_CHANGE, DOUBLE_CLICK, RIGHT_CLICK, @@ -239,31 +238,6 @@ e_table_group_get_printable (ETableGroup *etg) return NULL; } -void -e_table_group_selected_row_foreach (ETableGroup *etg, - ETableForeachFunc func, - gpointer closure) -{ - g_return_if_fail (etg != NULL); - g_return_if_fail (E_IS_TABLE_GROUP (etg)); - - if (ETG_CLASS (etg)->selected_row_foreach) - ETG_CLASS (etg)->selected_row_foreach (etg, func, closure); -} - - - -void -e_table_group_row_selection (ETableGroup *e_table_group, gint row, gboolean selected) -{ - g_return_if_fail (e_table_group != NULL); - g_return_if_fail (E_IS_TABLE_GROUP (e_table_group)); - - gtk_signal_emit (GTK_OBJECT (e_table_group), - etg_signals [ROW_SELECTION], - row, selected); -} - void e_table_group_cursor_change (ETableGroup *e_table_group, gint row) { @@ -364,7 +338,6 @@ etg_class_init (GtkObjectClass *object_class) item_class->event = etg_event; - klass->row_selection = NULL; klass->cursor_change = NULL; klass->double_click = NULL; klass->right_click = NULL; @@ -382,18 +355,9 @@ etg_class_init (GtkObjectClass *object_class) klass->get_focus = etg_get_focus; klass->get_ecol = NULL; klass->get_printable = NULL; - klass->selected_row_foreach = NULL; etg_parent_class = gtk_type_class (PARENT_TYPE); - etg_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableGroupClass, row_selection), - gtk_marshal_NONE__INT_INT, - GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - etg_signals [CURSOR_CHANGE] = gtk_signal_new ("cursor_change", GTK_RUN_LAST, diff --git a/widgets/e-table/e-table-group.h b/widgets/e-table/e-table-group.h index ef6be1d35f..f4fd25a779 100644 --- a/widgets/e-table/e-table-group.h +++ b/widgets/e-table/e-table-group.h @@ -45,7 +45,6 @@ typedef struct { GnomeCanvasGroupClass parent_class; /* Signals */ - void (*row_selection) (ETableGroup *etg, int row, gboolean selected); void (*cursor_change) (ETableGroup *etg, int row); void (*double_click) (ETableGroup *etg, int row); gint (*right_click) (ETableGroup *etg, int row, int col, GdkEvent *event); @@ -65,7 +64,6 @@ typedef struct { gint (*get_focus_column) (ETableGroup *etg); ETableCol *(*get_ecol) (ETableGroup *etg); EPrintable *(*get_printable) (ETableGroup *etg); - void (*selected_row_foreach) (ETableGroup *etg, ETableForeachFunc func, gpointer closure); } ETableGroupClass; @@ -91,9 +89,6 @@ gint e_table_group_get_focus_column (ETableGroup *etg); ETableHeader *e_table_group_get_header (ETableGroup *etg); ETableCol *e_table_group_get_ecol (ETableGroup *etg); EPrintable *e_table_group_get_printable (ETableGroup *etg); -void e_table_group_selected_row_foreach (ETableGroup *etg, - ETableForeachFunc func, - gpointer closure); ETableGroup *e_table_group_new (GnomeCanvasGroup *parent, ETableHeader *full_header, @@ -108,9 +103,6 @@ void e_table_group_construct (GnomeCanvasGroup *parent, ETableModel *model); /* For emitting the signals */ -void e_table_group_row_selection (ETableGroup *etg, - gint row, - gboolean selected); void e_table_group_cursor_change (ETableGroup *etg, gint row); void e_table_group_double_click (ETableGroup *etg, diff --git a/widgets/e-table/e-table-header.c b/widgets/e-table/e-table-header.c index 06aeb50b3f..f95797e5c4 100644 --- a/widgets/e-table/e-table-header.c +++ b/widgets/e-table/e-table-header.c @@ -616,7 +616,7 @@ e_table_header_col_diff (ETableHeader *eth, int start_col, int end_col) if (start_col < 0) start_col = 0; if (end_col > eth->col_count) - end_col = eth->col_count - 1; + end_col = eth->col_count; total = 0; for (col = start_col; col < end_col; col++){ diff --git a/widgets/e-table/e-table-item.c b/widgets/e-table/e-table-item.c index 947b28107e..9e66a487be 100644 --- a/widgets/e-table/e-table-item.c +++ b/widgets/e-table/e-table-item.c @@ -30,7 +30,6 @@ static GnomeCanvasItemClass *eti_parent_class; enum { - ROW_SELECTION, CURSOR_CHANGE, DOUBLE_CLICK, RIGHT_CLICK, @@ -44,11 +43,11 @@ enum { ARG_0, ARG_TABLE_HEADER, ARG_TABLE_MODEL, + ARG_TABLE_SELECTION_MODEL, ARG_TABLE_DRAW_GRID, ARG_TABLE_DRAW_FOCUS, ARG_CURSOR_MODE, ARG_LENGTH_THRESHOLD, - ARG_HAS_CURSOR, ARG_CURSOR_ROW, ARG_MINIMUM_WIDTH, @@ -59,18 +58,17 @@ enum { static int eti_get_height (ETableItem *eti); static int eti_get_minimum_width (ETableItem *eti); static int eti_row_height (ETableItem *eti, int row); -static void e_table_item_unselect_row (ETableItem *eti, int row); -static void e_table_item_select_row (ETableItem *eti, int row); -static void eti_selection (GnomeCanvasItem *item, int flags, gpointer user_data); -static int eti_selection_compare (GnomeCanvasItem *item, gpointer data1, gpointer data2, int flags); -static void e_table_item_focus (ETableItem *eti, int col, int row, gboolean add_selection); -static void -eti_request_region_show (ETableItem *eti, - int start_col, int start_row, - int end_col, int end_row); +static void e_table_item_focus (ETableItem *eti, int col, int row, gboolean shift_p, gboolean ctrl_p); +static void eti_cursor_change (ETableSelectionModel *selection, int row, int col, ETableItem *eti); +static void eti_selection_change (ETableSelectionModel *selection, ETableItem *eti); +#if 0 +static void eti_request_region_show (ETableItem *eti, + int start_col, int start_row, + int end_col, int end_row); +#endif #define ETI_ROW_HEIGHT(eti,row) ((eti)->height_cache && (eti)->height_cache[(row)] != -1 ? (eti)->height_cache[(row)] : eti_row_height((eti),(row))) -static gint +inline static gint model_to_view_row(ETableItem *eti, int row) { int i; @@ -90,7 +88,7 @@ model_to_view_row(ETableItem *eti, int row) return row; } -static gint +inline static gint view_to_model_row(ETableItem *eti, int row) { if (eti->uses_source_model) { @@ -309,6 +307,28 @@ eti_remove_table_model (ETableItem *eti) eti->uses_source_model = 0; } +/* + * eti_remove_table_model: + * + * Invoked to release the table model associated with this ETableItem + */ +static void +eti_remove_table_selection_model (ETableItem *eti) +{ + if (!eti->selection) + return; + + gtk_signal_disconnect (GTK_OBJECT (eti->selection), + eti->selection_change_id); + gtk_signal_disconnect (GTK_OBJECT (eti->selection), + eti->cursor_change_id); + gtk_object_unref (GTK_OBJECT (eti->selection)); + + eti->selection_change_id = 0; + eti->cursor_change_id = 0; + eti->selection = NULL; +} + /* * eti_remove_header_model: * @@ -579,16 +599,19 @@ eti_request_region_redraw (ETableItem *eti, int end_col, int end_row, int border) { int x1, y1, width, height; - - x1 = e_table_header_col_diff (eti->header, 0, start_col); - y1 = eti_row_diff (eti, 0, start_row); - width = e_table_header_col_diff (eti->header, start_col, end_col + 1); - height = eti_row_diff (eti, start_row, end_row + 1); - - eti_item_region_redraw (eti, eti->x1 + x1 - border, - eti->y1 + y1 - border, - eti->x1 + x1 + width + 1 + border, - eti->y1 + y1 + height + 1 + border); + + if (eti->rows > 0) { + + x1 = e_table_header_col_diff (eti->header, 0, start_col); + y1 = eti_row_diff (eti, 0, start_row); + width = e_table_header_col_diff (eti->header, start_col, end_col + 1); + height = eti_row_diff (eti, start_row, end_row + 1); + + eti_item_region_redraw (eti, eti->x1 + x1 - border, + eti->y1 + y1 - border, + eti->x1 + x1 + width + 1 + border, + eti->y1 + y1 + height + 1 + border); + } } /* @@ -619,7 +642,7 @@ eti_table_model_row_changed (ETableModel *table_model, int row, ETableItem *eti) eti_table_model_changed (table_model, eti); return; } - + eti_request_region_redraw (eti, 0, row, eti->cols, row, 0); } @@ -630,7 +653,7 @@ eti_table_model_cell_changed (ETableModel *table_model, int col, int row, ETable eti_table_model_changed (table_model, eti); return; } - + eti_request_region_redraw (eti, 0, row, eti->cols -1, row, 0); } @@ -652,14 +675,20 @@ e_table_item_redraw_range (ETableItem *eti, int end_col, int end_row) { int border; + int cursor_col, cursor_row; g_return_if_fail (eti != NULL); g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - if ((start_col == eti->cursor_col) || - (end_col == eti->cursor_col) || - (view_to_model_row(eti, start_row) == eti->cursor_row) || - (view_to_model_row(eti, end_row) == eti->cursor_row)) + + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); + + if ((start_col == cursor_col) || + (end_col == cursor_col) || + (view_to_model_row(eti, start_row) == cursor_row) || + (view_to_model_row(eti, end_row) == cursor_row)) border = 2; else border = 0; @@ -710,6 +739,25 @@ eti_add_table_model (ETableItem *eti, ETableModel *table_model) eti_table_model_changed (table_model, eti); } +static void +eti_add_table_selection_model (ETableItem *eti, ETableSelectionModel *selection) +{ + g_assert (eti->selection == NULL); + + eti->selection = selection; + gtk_object_ref (GTK_OBJECT (eti->selection)); + + eti->selection_change_id = gtk_signal_connect ( + GTK_OBJECT (selection), "selection_changed", + GTK_SIGNAL_FUNC (eti_selection_change), eti); + + eti->cursor_change_id = gtk_signal_connect ( + GTK_OBJECT (selection), "cursor_changed", + GTK_SIGNAL_FUNC (eti_cursor_change), eti); + + eti_selection_change(selection, eti); +} + static void eti_header_dim_changed (ETableHeader *eth, int col, ETableItem *eti) { @@ -727,7 +775,7 @@ eti_header_structure_changed (ETableHeader *eth, ETableItem *eti) * There should be at least one column */ g_assert (eti->cols != 0); - + if (eti->cell_views){ eti_unrealize_cell_views (eti); eti_detach_cell_views (eti); @@ -772,10 +820,10 @@ eti_destroy (GtkObject *object) eti_remove_header_model (eti); eti_remove_table_model (eti); + eti_remove_table_selection_model (eti); -#if 0 - g_slist_free (eti->selection); -#endif + if (eti->selection) + gtk_object_unref(GTK_OBJECT(eti->selection)); if (eti->height_cache_idle_id) g_source_remove(eti->height_cache_idle_id); @@ -791,6 +839,7 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) { GnomeCanvasItem *item; ETableItem *eti; + int cursor_col; item = GNOME_CANVAS_ITEM (o); eti = E_TABLE_ITEM (o); @@ -806,6 +855,12 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) eti_add_table_model (eti, E_TABLE_MODEL(GTK_VALUE_OBJECT (*arg))); break; + case ARG_TABLE_SELECTION_MODEL: + eti_remove_table_selection_model (eti); + if (GTK_VALUE_OBJECT (*arg)) + eti_add_table_selection_model (eti, E_TABLE_SELECTION_MODEL(GTK_VALUE_OBJECT (*arg))); + break; + case ARG_LENGTH_THRESHOLD: eti->length_threshold = GTK_VALUE_INT (*arg); break; @@ -831,7 +886,11 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti)); break; case ARG_CURSOR_ROW: - e_table_item_focus (eti, eti->cursor_col != -1 ? eti->cursor_col : 0, view_to_model_row(eti, GTK_VALUE_INT (*arg)), FALSE); + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + NULL); + + e_table_item_focus (eti, cursor_col != -1 ? cursor_col : 0, view_to_model_row(eti, GTK_VALUE_INT (*arg)), FALSE, FALSE); break; } eti->needs_redraw = 1; @@ -843,6 +902,7 @@ eti_get_arg (GtkObject *o, GtkArg *arg, guint arg_id) { GnomeCanvasItem *item; ETableItem *eti; + int row; item = GNOME_CANVAS_ITEM (o); eti = E_TABLE_ITEM (o); @@ -857,11 +917,11 @@ eti_get_arg (GtkObject *o, GtkArg *arg, guint arg_id) case ARG_MINIMUM_WIDTH: GTK_VALUE_DOUBLE (*arg) = eti->minimum_width; break; - case ARG_HAS_CURSOR: - GTK_VALUE_BOOL (*arg) = (eti->cursor_row != -1); - break; case ARG_CURSOR_ROW: - GTK_VALUE_INT (*arg) = model_to_view_row(eti, eti->cursor_row); + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &row, + NULL); + GTK_VALUE_INT (*arg) = model_to_view_row(eti, row); break; default: arg->type = GTK_TYPE_INVALID; @@ -890,18 +950,16 @@ eti_init (GnomeCanvasItem *item) eti->source_model = NULL; eti->row_guess = -1; - eti->cursor_row = -1; - eti->cursor_col = 0; eti->cursor_mode = E_TABLE_CURSOR_SIMPLE; + eti->selection_change_id = 0; + eti->cursor_change_id = 0; eti->selection = NULL; eti->needs_redraw = 0; eti->needs_compute_height = 0; e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM (eti), eti_reflow); - e_canvas_item_set_selection_callback (GNOME_CANVAS_ITEM (eti), eti_selection); - e_canvas_item_set_selection_compare_callback (GNOME_CANVAS_ITEM (eti), eti_selection_compare); } #define gray50_width 2 @@ -1078,13 +1136,19 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, for (row = first_row; row < last_row; row++){ int xd, height; gboolean selected; + gint cursor_col, cursor_row; height = ETI_ROW_HEIGHT (eti, row); xd = x_offset; /* printf ("paint: %d %d\n", yd, yd + height); */ - selected = g_slist_find (eti->selection, GINT_TO_POINTER (view_to_model_row(eti, row))) != NULL; + selected = e_table_selection_model_is_row_selected(eti->selection, row); + + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); for (col = first_col; col < last_col; col++){ ETableCol *ecol = e_table_header_get_column (eti->header, col); @@ -1092,7 +1156,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, gboolean col_selected = selected; switch (eti->cursor_mode) { case E_TABLE_CURSOR_SIMPLE: - if (eti->cursor_col == col && eti->cursor_row == view_to_model_row(eti, row)) + if (cursor_col == col && cursor_row == view_to_model_row(eti, row)) col_selected = !col_selected; break; case E_TABLE_CURSOR_LINE: @@ -1103,7 +1167,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, e_cell_draw (ecell_view, drawable, ecol->col_idx, col, row, col_selected, xd, yd, xd + ecol->width, yd + height); - if (col == eti->cursor_col && view_to_model_row(eti, row) == eti->cursor_row){ + if (col == cursor_col && view_to_model_row(eti, row) == cursor_row){ f_x1 = xd; f_x2 = xd + ecol->width; f_y1 = yd; @@ -1213,31 +1277,55 @@ static void eti_cursor_move (ETableItem *eti, gint row, gint column) { e_table_item_leave_edit (eti); - e_table_item_focus (eti, column, view_to_model_row(eti, row), FALSE); + e_table_item_focus (eti, column, view_to_model_row(eti, row), FALSE, FALSE); } static void eti_cursor_move_left (ETableItem *eti) { - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row), eti->cursor_col - 1); + int cursor_col, cursor_row; + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); + + eti_cursor_move (eti, model_to_view_row(eti, cursor_row), cursor_col - 1); } static void eti_cursor_move_right (ETableItem *eti) { - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row), eti->cursor_col + 1); + int cursor_col, cursor_row; + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); + + eti_cursor_move (eti, model_to_view_row(eti, cursor_row), cursor_col + 1); } static void eti_cursor_move_up (ETableItem *eti) { - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row) - 1, eti->cursor_col); + int cursor_col, cursor_row; + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); + + eti_cursor_move (eti, model_to_view_row(eti, cursor_row) - 1, cursor_col); } static void eti_cursor_move_down (ETableItem *eti) { - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row) + 1, eti->cursor_col); + int cursor_col, cursor_row; + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); + + eti_cursor_move (eti, model_to_view_row(eti, cursor_row) + 1, cursor_col); } /* FIXME: cursor */ @@ -1254,36 +1342,26 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) double x1, y1; int col, row; gint shifted = e->button.state & GDK_SHIFT_MASK; + gint ctrled = e->button.state & GDK_CONTROL_MASK; + gint cursor_row, cursor_col; switch (e->button.button) { case 1: /* Fall through. */ case 2: gnome_canvas_item_w2i (item, &e->button.x, &e->button.y); - if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) return TRUE; - - if (eti->cursor_row != view_to_model_row(eti, row) || eti->cursor_col != col){ - /* - * Focus the cell, and select the row - */ - if (e_table_item_is_row_selected(eti, view_to_model_row(eti, row))) { - int nums[2]; - e_table_item_leave_edit (eti); - nums[0] = view_to_model_row(eti, row); - nums[1] = 0; - e_canvas_item_remove_selection(GNOME_CANVAS_ITEM(eti), nums); - } else { - e_table_item_leave_edit (eti); - e_table_item_focus (eti, col, view_to_model_row(eti, row), shifted); - } - } - if (eti->cursor_row == view_to_model_row(eti, row) && eti->cursor_col == col){ + e_table_selection_model_do_something(eti->selection, row, col, shifted, ctrled); + + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &cursor_row, + "cursor_col", &cursor_col, + NULL); + + if (cursor_row == view_to_model_row(eti, row) && cursor_col == col){ - e_table_item_focus (eti, col, view_to_model_row(eti, row), shifted); - ecol = e_table_header_get_column (eti->header, col); ecell_view = eti->cell_views [col]; @@ -1316,6 +1394,7 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) case GDK_BUTTON_RELEASE: { double x1, y1; int col, row; + gint cursor_row, cursor_col; switch (e->button.button) { case 1: /* Fall through. */ @@ -1326,7 +1405,12 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) return TRUE; - if (eti->cursor_row == view_to_model_row(eti, row) && eti->cursor_col == col){ + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &cursor_row, + "cursor_col", &cursor_col, + NULL); + + if (cursor_row == view_to_model_row(eti, row) && cursor_col == col){ ecol = e_table_header_get_column (eti->header, col); ecell_view = eti->cell_views [col]; @@ -1370,13 +1454,19 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) case GDK_MOTION_NOTIFY: { int col, row; double x1, y1; + gint cursor_col, cursor_row; gnome_canvas_item_w2i (item, &e->motion.x, &e->motion.y); if (!find_cell (eti, e->motion.x, e->motion.y, &col, &row, &x1, &y1)) return TRUE; - if (eti->cursor_row == view_to_model_row(eti, row) && eti->cursor_col == col){ + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &cursor_row, + "cursor_col", &cursor_col, + NULL); + + if (cursor_row == view_to_model_row(eti, row) && cursor_col == col){ ecol = e_table_header_get_column (eti->header, col); ecell_view = eti->cell_views [col]; @@ -1391,40 +1481,42 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) break; } - case GDK_KEY_PRESS: - if (eti->cursor_col == -1) + case GDK_KEY_PRESS: { + gint cursor_row, cursor_col; + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &cursor_row, + "cursor_col", &cursor_col, + NULL); + + if (cursor_col == -1) return FALSE; switch (e->key.keyval){ case GDK_Left: -#if 0 - if (!eti->mode_spreadsheet && eti_editing (eti)) + if (eti_editing (eti)) break; -#endif - if (eti->cursor_col > 0) + if (cursor_col > 0) eti_cursor_move_left (eti); break; case GDK_Right: -#if 0 - if (!eti->mode_spreadsheet && eti_editing (eti)) + if (eti_editing (eti)) break; -#endif - if (eti->cursor_col < eti->cols - 1) + if (cursor_col < eti->cols - 1) eti_cursor_move_right (eti); break; case GDK_Up: - if (eti->cursor_row != view_to_model_row(eti, 0)) + if (cursor_row != view_to_model_row(eti, 0)) eti_cursor_move_up (eti); else return_val = FALSE; break; case GDK_Down: - if (eti->cursor_row != view_to_model_row(eti, eti->rows - 1)) + if (cursor_row != view_to_model_row(eti, eti->rows - 1)) eti_cursor_move_down (eti); else return_val = FALSE; @@ -1435,17 +1527,17 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) case GDK_ISO_Left_Tab: if ((e->key.state & GDK_SHIFT_MASK) != 0){ /* shift tab */ - if (eti->cursor_col > 0) + if (cursor_col > 0) eti_cursor_move_left (eti); - else if (eti->cursor_row != view_to_model_row(eti, 0)) - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row) - 1, eti->cols - 1); + else if (cursor_row != view_to_model_row(eti, 0)) + eti_cursor_move (eti, model_to_view_row(eti, cursor_row) - 1, eti->cols - 1); else return_val = FALSE; } else { - if (eti->cursor_col < eti->cols - 1) + if (cursor_col < eti->cols - 1) eti_cursor_move_right (eti); - else if (eti->cursor_row != view_to_model_row(eti, eti->rows - 1)) - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row) + 1, 0); + else if (cursor_row != view_to_model_row(eti, eti->rows - 1)) + eti_cursor_move (eti, model_to_view_row(eti, cursor_row) + 1, 0); else return_val = FALSE; } @@ -1454,17 +1546,25 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) default: if (!eti_editing (eti)){ gtk_signal_emit (GTK_OBJECT (eti), eti_signals [KEY_PRESS], - model_to_view_row(eti, eti->cursor_row), eti->cursor_col, e, &return_val); + model_to_view_row(eti, cursor_row), cursor_col, e, &return_val); } else { - ecol = e_table_header_get_column (eti->header, eti->cursor_col); - ecell_view = eti->cell_views [eti->cursor_col]; - e_cell_event (ecell_view, e, ecol->col_idx, eti->cursor_col, model_to_view_row(eti, eti->cursor_row)); + ecol = e_table_header_get_column (eti->header, cursor_col); + ecell_view = eti->cell_views [cursor_col]; + e_cell_event (ecell_view, e, ecol->col_idx, cursor_col, model_to_view_row(eti, cursor_row)); } } break; + } - case GDK_KEY_RELEASE: - if (eti->cursor_col == -1) + case GDK_KEY_RELEASE: { + gint cursor_row, cursor_col; + + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &cursor_row, + "cursor_col", &cursor_col, + NULL); + + if (cursor_col == -1) return FALSE; if (eti_editing (eti)){ @@ -1473,6 +1573,7 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) e_cell_event (ecell_view, e, ecol->col_idx, eti->editing_col, eti->editing_row); } break; + } default: return_val = FALSE; @@ -1480,21 +1581,6 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) return return_val; } -/* - * ETableItem::row_selection method - */ -static void -eti_row_selection (ETableItem *eti, int row, gboolean selected) -{ - int view_row = model_to_view_row(eti, row); - eti_request_region_redraw (eti, 0, view_row, eti->cols - 1, view_row, 0); - - if (selected) - eti->selection = g_slist_prepend (eti->selection, GINT_TO_POINTER (row)); - else - eti->selection = g_slist_remove (eti->selection, GINT_TO_POINTER (row)); -} - static void eti_class_init (GtkObjectClass *object_class) { @@ -1514,7 +1600,6 @@ eti_class_init (GtkObjectClass *object_class) item_class->point = eti_point; item_class->event = eti_event; - eti_class->row_selection = eti_row_selection; eti_class->cursor_change = NULL; eti_class->double_click = NULL; eti_class->right_click = NULL; @@ -1524,6 +1609,8 @@ eti_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_TABLE_HEADER); gtk_object_add_arg_type ("ETableItem::ETableModel", GTK_TYPE_OBJECT, GTK_ARG_WRITABLE, ARG_TABLE_MODEL); + gtk_object_add_arg_type ("ETableItem::table_selection_model", GTK_TYPE_OBJECT, + GTK_ARG_WRITABLE, ARG_TABLE_SELECTION_MODEL); gtk_object_add_arg_type ("ETableItem::drawgrid", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); gtk_object_add_arg_type ("ETableItem::drawfocus", GTK_TYPE_BOOL, @@ -1539,19 +1626,9 @@ eti_class_init (GtkObjectClass *object_class) GTK_ARG_READWRITE, ARG_WIDTH); gtk_object_add_arg_type ("ETableItem::height", GTK_TYPE_DOUBLE, GTK_ARG_READABLE, ARG_HEIGHT); - gtk_object_add_arg_type ("ETableItem::has_cursor", GTK_TYPE_BOOL, - GTK_ARG_READWRITE, ARG_HAS_CURSOR); gtk_object_add_arg_type ("ETableItem::cursor_row", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_CURSOR_ROW); - eti_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableItemClass, row_selection), - gtk_marshal_NONE__INT_INT, - GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - eti_signals [CURSOR_CHANGE] = gtk_signal_new ("cursor_change", GTK_RUN_LAST, @@ -1614,11 +1691,11 @@ e_table_item_get_type (void) void e_table_item_set_cursor (ETableItem *eti, int col, int row) { - e_table_item_focus(eti, col, view_to_model_row(eti, row), FALSE); + e_table_item_focus(eti, col, view_to_model_row(eti, row), FALSE, FALSE); } static void -e_table_item_focus (ETableItem *eti, int col, int row, gboolean add_selection) +e_table_item_focus (ETableItem *eti, int col, int row, gboolean shift_p, gboolean ctrl_p) { g_return_if_fail (eti != NULL); g_return_if_fail (E_IS_TABLE_ITEM (eti)); @@ -1632,34 +1709,26 @@ e_table_item_focus (ETableItem *eti, int col, int row, gboolean add_selection) } if (row != -1) { - int *nums; - nums = g_new(int, 2); - nums[0] = row; - nums[1] = col; - if (add_selection) - e_canvas_item_add_selection(GNOME_CANVAS_ITEM(eti), nums); - else - e_canvas_item_set_cursor(GNOME_CANVAS_ITEM(eti), nums); + e_table_selection_model_do_something(eti->selection, + row, col, + shift_p, + ctrl_p); } } gint e_table_item_get_focused_column (ETableItem *eti) { + int cursor_col; + g_return_val_if_fail (eti != NULL, -1); g_return_val_if_fail (E_IS_TABLE_ITEM (eti), -1); + + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + NULL); - return eti->cursor_col; -} - - -const GSList * -e_table_item_get_selection (ETableItem *eti) -{ - g_return_val_if_fail (eti != NULL, NULL); - g_return_val_if_fail (E_IS_TABLE_ITEM (eti), NULL); - - return eti->selection; + return cursor_col; } gboolean @@ -1668,91 +1737,28 @@ e_table_item_is_row_selected (ETableItem *eti, int row) g_return_val_if_fail (eti != NULL, FALSE); g_return_val_if_fail (E_IS_TABLE_ITEM (eti), FALSE); - if (g_slist_find (eti->selection, GINT_TO_POINTER (row))) - return TRUE; - else - return FALSE; -} - -void e_table_item_selected_row_foreach (ETableItem *eti, - ETableForeachFunc func, - gpointer closure) -{ - GSList *list = eti->selection; - for (; list; list = g_slist_next(list)) { - (func) (GPOINTER_TO_INT(list->data), closure); - } -} - -static void -e_table_item_unselect_row (ETableItem *eti, int row) -{ - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - gtk_signal_emit (GTK_OBJECT (eti), eti_signals [ROW_SELECTION], - row, 0); + return e_table_selection_model_is_row_selected(eti->selection, row); } static void -e_table_item_select_row (ETableItem *eti, int row) +eti_cursor_change (ETableSelectionModel *selection, int row, int col, ETableItem *eti) { - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - gtk_signal_emit (GTK_OBJECT (eti), eti_signals [ROW_SELECTION], - GINT_TO_POINTER (row), 1); -} - -static void -eti_selection (GnomeCanvasItem *item, int flags, gpointer data) -{ - int *nums = data; - int row = nums[0]; - int col = nums[1]; - ETableItem *eti = E_TABLE_ITEM(item); - int selected = e_table_item_is_row_selected(eti, row); - int cursored = (row == eti->cursor_row); + int view_row = model_to_view_row(eti, row); - if (selected && (flags & E_CANVAS_ITEM_SELECTION_SELECT) == 0) { - e_table_item_unselect_row (eti, row); - } - if ((!selected) && (flags & E_CANVAS_ITEM_SELECTION_SELECT) != 0) { - e_table_item_select_row (eti, row); - } - if ((!cursored) && (flags & E_CANVAS_ITEM_SELECTION_CURSOR) != 0) { - int view_row = model_to_view_row(eti, row); - - eti->cursor_col = col; - eti->cursor_row = row; - gtk_signal_emit (GTK_OBJECT (eti), eti_signals [CURSOR_CHANGE], - view_row); - eti_request_region_show (eti, col, view_row, col, view_row); - } - if ((cursored) && (flags & E_CANVAS_ITEM_SELECTION_CURSOR) == 0) { - e_table_item_leave_edit(eti); - eti->cursor_row = -1; - eti->cursor_col = -1; - } - if (flags & E_CANVAS_ITEM_SELECTION_DELETE_DATA) { - g_free(data); - } + gtk_signal_emit (GTK_OBJECT (eti), eti_signals [CURSOR_CHANGE], + view_row); + eti_request_region_show (eti, col, view_row, col, view_row); + if (e_table_model_is_cell_editable(selection->model, col, row)) + e_table_item_enter_edit (eti, col, view_row); } -static gint -eti_selection_compare (GnomeCanvasItem *item, gpointer data1, gpointer data2, int flags) +static void +eti_selection_change (ETableSelectionModel *selection, ETableItem *eti) { - int *val1 = (int *) data1; - int *val2 = (int *) data2; - if (*val1 < *val2) - return -1; - else if (*val1 == *val2) - return 0; - else - return 1; + eti->needs_redraw = TRUE; + gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(eti)); } - void e_table_item_enter_edit (ETableItem *eti, int col, int row) { @@ -1760,6 +1766,9 @@ e_table_item_enter_edit (ETableItem *eti, int col, int row) g_return_if_fail (eti != NULL); g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if (eti_editing (eti)) + e_table_item_leave_edit(eti); eti->editing_col = col; eti->editing_row = row; diff --git a/widgets/e-table/e-table-item.h b/widgets/e-table/e-table-item.h index 619db68803..7102ef3ef7 100644 --- a/widgets/e-table/e-table-item.h +++ b/widgets/e-table/e-table-item.h @@ -5,6 +5,7 @@ #include #include "e-table-model.h" #include "e-table-header.h" +#include "e-table-selection-model.h" #include "e-table-defines.h" #include @@ -27,6 +28,7 @@ typedef struct { ETableHeader *header; ETableModel *source_model; + ETableSelectionModel *selection; int x1, y1; int minimum_width, width, height; @@ -43,6 +45,9 @@ typedef struct { int table_model_cell_change_id; int table_model_row_inserted_id; int table_model_row_deleted_id; + + int selection_change_id; + int cursor_change_id; GdkGC *fill_gc; GdkGC *grid_gc; @@ -77,12 +82,8 @@ typedef struct { int length_threshold; gint row_guess; - gint cursor_row; - gint cursor_col; ETableCursorMode cursor_mode; - GSList *selection; - /* * During editing */ @@ -94,7 +95,6 @@ typedef struct { typedef struct { GnomeCanvasItemClass parent_class; - void (*row_selection) (ETableItem *eti, int row, gboolean selected); void (*cursor_change) (ETableItem *eti, int row); void (*double_click) (ETableItem *eti, int row); gint (*right_click) (ETableItem *eti, int row, int col, GdkEvent *event); @@ -114,7 +114,6 @@ gint e_table_item_get_focused_column (ETableItem *eti); /* * Handling the selection */ -const GSList *e_table_item_get_selection (ETableItem *e_table_Item); gboolean e_table_item_is_row_selected (ETableItem *e_table_Item, int row); diff --git a/widgets/e-table/e-table-scrolled.c b/widgets/e-table/e-table-scrolled.c index b8260b6407..1a7b5251ad 100644 --- a/widgets/e-table/e-table-scrolled.c +++ b/widgets/e-table/e-table-scrolled.c @@ -28,7 +28,6 @@ static GtkObjectClass *parent_class; enum { - ROW_SELECTION, CURSOR_CHANGE, DOUBLE_CLICK, RIGHT_CLICK, @@ -47,14 +46,6 @@ enum { static gint ets_signals [LAST_SIGNAL] = { 0, }; -static void -row_selection_proxy (ETable *et, int row, gboolean selected, ETableScrolled *ets) -{ - gtk_signal_emit (GTK_OBJECT (ets), - ets_signals [ROW_SELECTION], - row, selected); -} - static void cursor_change_proxy (ETable *et, int row, ETableScrolled *ets) { @@ -117,8 +108,6 @@ e_table_scrolled_real_construct (ETableScrolled *ets) gtk_container_add(GTK_CONTAINER(ets), GTK_WIDGET(ets->table)); - gtk_signal_connect(GTK_OBJECT(ets->table), "row_selection", - GTK_SIGNAL_FUNC(row_selection_proxy), ets); gtk_signal_connect(GTK_OBJECT(ets->table), "cursor_change", GTK_SIGNAL_FUNC(cursor_change_proxy), ets); gtk_signal_connect(GTK_OBJECT(ets->table), "double_click", @@ -297,20 +286,11 @@ e_table_scrolled_class_init (GtkObjectClass *object_class) object_class->set_arg = ets_set_arg; object_class->get_arg = ets_get_arg; - klass->row_selection = NULL; klass->cursor_change = NULL; klass->double_click = NULL; klass->right_click = NULL; klass->key_press = NULL; - ets_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableScrolledClass, row_selection), - gtk_marshal_NONE__INT_INT, - GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - ets_signals [CURSOR_CHANGE] = gtk_signal_new ("cursor_change", GTK_RUN_LAST, diff --git a/widgets/e-table/e-table-scrolled.h b/widgets/e-table/e-table-scrolled.h index daaf4429a0..d5a0c06a58 100644 --- a/widgets/e-table/e-table-scrolled.h +++ b/widgets/e-table/e-table-scrolled.h @@ -25,7 +25,6 @@ typedef struct { typedef struct { EScrollFrameClass parent_class; - void (*row_selection) (ETableScrolled *est, int row, gboolean selected); void (*cursor_change) (ETableScrolled *est, int row); void (*double_click) (ETableScrolled *est, int row); gint (*right_click) (ETableScrolled *est, int row, int col, GdkEvent *event); diff --git a/widgets/e-table/e-table-selection-model.c b/widgets/e-table/e-table-selection-model.c index 9c631ca603..35e0cb13aa 100644 --- a/widgets/e-table/e-table-selection-model.c +++ b/widgets/e-table/e-table-selection-model.c @@ -15,36 +15,49 @@ #define ETSM_CLASS(e) ((ETableSelectionModelClass *)((GtkObject *)e)->klass) #define PARENT_TYPE gtk_object_get_type () - + +#define ONES ((guint32) 0xffffffff) + +#define BOX(n) ((n) / 32) +#define OFFSET(n) (31 - ((n) % 32)) +#define BITMASK(n) (((guint32) 0x1) << OFFSET(n)) +#define BITMASK_LEFT(n) (((guint32) ONES) << (32 - ((n) % 32))) +#define BITMASK_RIGHT(n) (((guint32) ONES) >> ((n) % 32)) static GtkObjectClass *e_table_selection_model_parent_class; enum { - SELECTION_MODEL_CHANGED, - GROUP_SELECTION_CHANGED, + CURSOR_CHANGED, + SELECTION_CHANGED, LAST_SIGNAL }; static guint e_table_selection_model_signals [LAST_SIGNAL] = { 0, }; +enum { + ARG_0, + ARG_MODEL, + ARG_CURSOR_ROW, + ARG_CURSOR_COL, +}; + static void model_changed(ETableModel *etm, ETableSelectionModel *etsm) { g_free(etsm->selection); etsm->selection = NULL; etsm->row_count = -1; + gtk_signal_emit(GTK_OBJECT(etsm), + e_table_selection_model_signals [SELECTION_CHANGED]); } +#if 1 static void model_row_inserted(ETableModel *etm, int row, ETableSelectionModel *etsm) { int box; int i; - int offset; if(etsm->row_count >= 0) { - guint32 bitmask1 = 0xffff; - guint32 bitmask2; - /* Add another word if needed. */ if ((etsm->row_count & 0x1f) == 0) { etsm->selection = g_realloc(etsm->selection, (etsm->row_count >> 5) + 1); @@ -58,12 +71,8 @@ model_row_inserted(ETableModel *etm, int row, ETableSelectionModel *etsm) etsm->selection[i] = (etsm->selection[i] >> 1) | (etsm->selection[i - 1] << 31); } - /* Build bitmasks for the left and right half of the box */ - offset = row & 0x1f; - bitmask1 = bitmask1 << (32 - offset); - bitmask2 = ~bitmask1; /* Shift right half of box one bit to the right. */ - etsm->selection[box] = (etsm->selection[box] & bitmask1) | ((etsm->selection[box] & bitmask2) >> 1); + etsm->selection[box] = (etsm->selection[box] & BITMASK_LEFT(row)) | ((etsm->selection[box] & BITMASK_RIGHT(row)) >> 1); etsm->row_count ++; } } @@ -74,19 +83,15 @@ model_row_deleted(ETableModel *etm, int row, ETableSelectionModel *etsm) int box; int i; int last; - int offset; if(etsm->row_count >= 0) { - guint32 bitmask1 = 0xffff; - guint32 bitmask2; + guint32 bitmask; box = row >> 5; last = etsm->row_count >> 5; /* Build bitmasks for the left and right half of the box */ - offset = row & 0x1f; - bitmask1 = bitmask1 << (32 - offset); - bitmask2 = (~bitmask1) >> 1; + bitmask = BITMASK_RIGHT(row) >> 1; /* Shift right half of box one bit to the left. */ - etsm->selection[box] = (etsm->selection[box] & bitmask1) | ((etsm->selection[box] & bitmask2) << 1); + etsm->selection[box] = (etsm->selection[box] & BITMASK_LEFT(row))| ((etsm->selection[box] & bitmask) << 1); /* Shift all words to the right of our box left one bit. */ if (box < last) { @@ -105,6 +110,21 @@ model_row_deleted(ETableModel *etm, int row, ETableSelectionModel *etsm) } } +#else + +static void +model_row_inserted(ETableModel *etm, int row, ETableSelectionModel *etsm) +{ + model_changed(etm, etsm); +} + +static void +model_row_deleted(ETableModel *etm, int row, ETableSelectionModel *etsm) +{ + model_changed(etm, etsm); +} +#endif + inline static void add_model(ETableSelectionModel *etsm, ETableModel *model) { @@ -141,15 +161,59 @@ etsm_destroy (GtkObject *object) ETableSelectionModel *etsm; etsm = E_TABLE_SELECTION_MODEL (object); - + + drop_model(etsm); + g_free(etsm->selection); } +static void +etsm_get_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + ETableSelectionModel *etsm = E_TABLE_SELECTION_MODEL (o); + + switch (arg_id){ + case ARG_MODEL: + GTK_VALUE_OBJECT (*arg) = GTK_OBJECT(etsm->model); + break; + + case ARG_CURSOR_ROW: + GTK_VALUE_INT(*arg) = etsm->cursor_row; + break; + + case ARG_CURSOR_COL: + GTK_VALUE_INT(*arg) = etsm->cursor_col; + break; + } +} + +static void +etsm_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + ETableSelectionModel *etsm = E_TABLE_SELECTION_MODEL (o); + + switch (arg_id){ + case ARG_MODEL: + drop_model(etsm); + add_model(etsm, GTK_VALUE_OBJECT (*arg) ? E_TABLE_MODEL(GTK_VALUE_OBJECT (*arg)) : NULL); + break; + + case ARG_CURSOR_ROW: + e_table_selection_model_do_something(etsm, GTK_VALUE_INT(*arg), etsm->cursor_col, FALSE, FALSE); + break; + + case ARG_CURSOR_COL: + e_table_selection_model_do_something(etsm, etsm->cursor_row, GTK_VALUE_INT(*arg), FALSE, FALSE); + break; + } +} + static void e_table_selection_model_init (ETableSelectionModel *selection) { selection->selection = NULL; selection->row_count = -1; + selection->model = NULL; } static void @@ -160,29 +224,38 @@ e_table_selection_model_class_init (ETableSelectionModelClass *klass) e_table_selection_model_parent_class = gtk_type_class (gtk_object_get_type ()); object_class = GTK_OBJECT_CLASS(klass); - + object_class->destroy = etsm_destroy; -#if 0 - e_table_selection_model_signals [SELECTION_MODEL_CHANGED] = - gtk_signal_new ("selection_model_changed", + object_class->get_arg = etsm_get_arg; + object_class->set_arg = etsm_set_arg; + + e_table_selection_model_signals [CURSOR_CHANGED] = + gtk_signal_new ("cursor_changed", GTK_RUN_LAST, object_class->type, - GTK_SIGNAL_OFFSET (ETableSelectionModelClass, selection_model_changed), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); + GTK_SIGNAL_OFFSET (ETableSelectionModelClass, cursor_changed), + gtk_marshal_NONE__INT_INT, + GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - e_table_selection_model_signals [GROUP_SELECTION_CHANGED] = - gtk_signal_new ("group_selection_changed", + e_table_selection_model_signals [SELECTION_CHANGED] = + gtk_signal_new ("selection_changed", GTK_RUN_LAST, object_class->type, - GTK_SIGNAL_OFFSET (ETableSelectionModelClass, group_selection_changed), + GTK_SIGNAL_OFFSET (ETableSelectionModelClass, selection_changed), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); - klass->selection_model_changed = NULL; - klass->group_selection_changed = NULL; -#endif + klass->cursor_changed = NULL; + klass->selection_changed = NULL; + gtk_object_class_add_signals (object_class, e_table_selection_model_signals, LAST_SIGNAL); + + gtk_object_add_arg_type ("ETableSelectionModel::model", GTK_TYPE_OBJECT, + GTK_ARG_READWRITE, ARG_MODEL); + gtk_object_add_arg_type ("ETableSelectionModel::cursor_row", GTK_TYPE_INT, + GTK_ARG_READWRITE, ARG_CURSOR_ROW); + gtk_object_add_arg_type ("ETableSelectionModel::cursor_col", GTK_TYPE_INT, + GTK_ARG_READWRITE, ARG_CURSOR_COL); } E_MAKE_TYPE(e_table_selection_model, "ETableSelectionModel", ETableSelectionModel, @@ -196,12 +269,12 @@ e_table_selection_model_new (void) gboolean e_table_selection_model_is_row_selected (ETableSelectionModel *selection, - guint n) + gint n) { if (selection->row_count < n) return 0; else - return ((selection->selection[n / 32]) >> (31 - (n % 32))) & 0x1; + return (selection->selection[BOX(n)] >> OFFSET(n)) & 0x1; } void @@ -211,12 +284,12 @@ e_table_selection_model_foreach (ETableSelectionModel *selection, { int i; int last = (selection->row_count + 31) / 32; - for (i = 0; i < last; i--) { + for (i = 0; i < last; i++) { if (selection->selection[i]) { int j; guint32 value = selection->selection[i]; - for (j = 0; j < 32; j--) { - if (value & 0x8000) { + for (j = 0; j < 32; j++) { + if (value & 0x80000000) { callback(i * 32 + j, closure); } value <<= 1; @@ -224,3 +297,92 @@ e_table_selection_model_foreach (ETableSelectionModel *selection, } } } + +#define OPERATE(object, mask, grow) ((grow) ? ((object) |= ~(mask)) : ((object) &= (mask))) + +void e_table_selection_model_do_something (ETableSelectionModel *selection, + guint row, + guint col, + gboolean shift_p, + gboolean ctrl_p) +{ + if (selection->row_count < 0) { + if (selection->model) { + selection->row_count = e_table_model_row_count(selection->model); + g_free(selection->selection); + selection->selection = g_new0(gint, (selection->row_count + 31) / 32); + } + } + if (selection->row_count >= 0 && row < selection->row_count) { + if (shift_p) { + int grow_selection; + int i; + int last; + int first_row; + int last_row; + if ((selection->selection_start_row < row && row <= selection->cursor_row) || + (selection->selection_start_row >= row && row >= selection->cursor_row)) { + /* In this case, the selection is shrinking. */ + grow_selection = FALSE; + } else if ((selection->selection_start_row <= selection->cursor_row && selection->cursor_row <= row) || + (selection->selection_start_row > selection->cursor_row && selection->cursor_row >= row)) { + /* In this case, the selection is growing. */ + grow_selection = TRUE; + } else { + /* In this case the selection is changing direction. Ick. Screw it. */ + return; + } + first_row = MIN(selection->cursor_row, row); + last_row = MAX(selection->cursor_row, row) + 1; + if (first_row != last_row) { + i = BOX(first_row); + last = BOX(last_row); + + if (i == last) { + OPERATE(selection->selection[i], BITMASK_LEFT(first_row) | BITMASK_RIGHT(last_row), grow_selection); + } else { + OPERATE(selection->selection[i], BITMASK_LEFT(first_row), grow_selection); + for (i ++; i < last; i++) + if (grow_selection) + selection->selection[i] = ONES; + else + selection->selection[i] = 0; + OPERATE(selection->selection[i], BITMASK_RIGHT(last_row), grow_selection); + } + gtk_signal_emit(GTK_OBJECT(selection), + e_table_selection_model_signals [SELECTION_CHANGED]); + } + } else { + if (ctrl_p) { + if (selection->selection[BOX(row)] & BITMASK(row)) + selection->selection[BOX(row)] &= ~BITMASK(row); + else + selection->selection[BOX(row)] |= BITMASK(row); + gtk_signal_emit(GTK_OBJECT(selection), + e_table_selection_model_signals [SELECTION_CHANGED]); + } else { + int i; + for (i = 0; i < ((selection->row_count + 31) / 32); i++) { + if (!((i == BOX(row) && selection->selection[i] == BITMASK(row)) || + (i != BOX(row) && selection->selection[i] == 0))) { + g_free(selection->selection); + selection->selection = g_new0(gint, (selection->row_count + 31) / 32); + selection->selection[BOX(row)] = BITMASK(row); + + gtk_signal_emit(GTK_OBJECT(selection), + e_table_selection_model_signals [SELECTION_CHANGED]); + break; + } + } + } + selection->selection_start_row = row; + } + if (selection->cursor_row != row || + selection->cursor_col != col) { + gtk_signal_emit(GTK_OBJECT(selection), + e_table_selection_model_signals[CURSOR_CHANGED], row, col); + selection->cursor_row = row; + selection->cursor_col = col; + } + } +} diff --git a/widgets/e-table/e-table-selection-model.h b/widgets/e-table/e-table-selection-model.h index 2aaba021f8..251b1ceb00 100644 --- a/widgets/e-table/e-table-selection-model.h +++ b/widgets/e-table/e-table-selection-model.h @@ -19,13 +19,14 @@ typedef struct { gint row_count; guint32 *selection; - + gint cursor_row; gint cursor_col; + gint selection_start_row; guint model_changed_id; guint model_row_inserted_id, model_row_deleted_id; - + guint frozen : 1; guint selection_model_changed : 1; guint group_info_changed : 1; @@ -37,20 +38,26 @@ typedef struct { /* * Signals */ -#if 0 - void (*selection_model_changed) (ETableSelectionModel *selection); - void (*group_model_changed) (ETableSelectionModel *selection); -#endif + + void (*cursor_changed) (ETableSelectionModel *selection, int row, int col); + void (*selection_changed) (ETableSelectionModel *selection); + } ETableSelectionModelClass; GtkType e_table_selection_model_get_type (void); -gboolean e_table_selection_model_is_row_selected (ETableSelectionModel *selection, - guint n); -void e_table_selection_model_foreach (ETableSelectionModel *selection, - ETableForeachFunc callback, - gpointer closure); +gboolean e_table_selection_model_is_row_selected (ETableSelectionModel *selection, + gint n); +void e_table_selection_model_foreach (ETableSelectionModel *selection, + ETableForeachFunc callback, + gpointer closure); + +void e_table_selection_model_do_something (ETableSelectionModel *selection, + guint row, + guint col, + gboolean shift_p, + gboolean ctrl_p); -ETableSelectionModel *e_table_selection_model_new (void); +ETableSelectionModel *e_table_selection_model_new (void); #endif /* _E_TABLE_SELECTION_MODEL_H_ */ diff --git a/widgets/e-table/e-table.c b/widgets/e-table/e-table.c index c20c7cd21e..ae258a5c44 100644 --- a/widgets/e-table/e-table.c +++ b/widgets/e-table/e-table.c @@ -40,7 +40,6 @@ static GtkObjectClass *e_table_parent_class; enum { - ROW_SELECTION, CURSOR_CHANGE, DOUBLE_CLICK, RIGHT_CLICK, @@ -183,6 +182,8 @@ e_table_init (GtkObject *object) e_table->drag_col = -1; e_table->drop_row = -1; e_table->drop_col = -1; + + e_table->selection = e_table_selection_model_new(); } static void @@ -269,18 +270,6 @@ table_canvas_reflow (GnomeCanvas *canvas, ETable *e_table) e_table->reflow_idle_id = g_idle_add_full (400, (GSourceFunc) table_canvas_reflow_idle, e_table, NULL); } -static void -group_row_selection (ETableGroup *etg, int row, gboolean selected, ETable *et) -{ - gtk_signal_emit (GTK_OBJECT (et), - et_signals [ROW_SELECTION], - row, selected); - if (et->row_selection_active && selected) { - e_table_click_to_add_commit (E_TABLE_CLICK_TO_ADD(et->click_to_add)); - et->row_selection_active = FALSE; - } -} - static void group_cursor_change (ETableGroup *etg, int row, ETable *et) { @@ -336,9 +325,8 @@ changed_idle (gpointer data) "drawfocus", et->draw_focus, "cursor_mode", et->cursor_mode, "length_threshold", et->length_threshold, + "table_selection_model", et->selection, NULL); - gtk_signal_connect (GTK_OBJECT (et->group), "row_selection", - GTK_SIGNAL_FUNC (group_row_selection), et); gtk_signal_connect (GTK_OBJECT (et->group), "cursor_change", GTK_SIGNAL_FUNC (group_cursor_change), et); gtk_signal_connect (GTK_OBJECT (et->group), "double_click", @@ -399,14 +387,6 @@ et_table_row_deleted (ETableModel *table_model, int row, ETable *et) } } -static void -click_to_add_row_selection (ETableClickToAdd *etcta, int row, gboolean selected, ETable *et) -{ - if ((!et->row_selection_active) && selected) { - et->row_selection_active = TRUE; - } -} - static void e_table_setup_table (ETable *e_table, ETableHeader *full_header, ETableHeader *header, ETableModel *model) @@ -460,9 +440,6 @@ e_table_setup_table (ETable *e_table, ETableHeader *full_header, ETableHeader *h "message", e_table->click_to_add_message, NULL); - gtk_signal_connect(GTK_OBJECT(e_table->click_to_add), "row_selection", - GTK_SIGNAL_FUNC(click_to_add_row_selection), e_table); - e_canvas_vbox_add_item(E_CANVAS_VBOX(e_table->canvas_vbox), e_table->click_to_add); } @@ -477,10 +454,9 @@ e_table_setup_table (ETable *e_table, ETableHeader *full_header, ETableHeader *h "drawfocus", e_table->draw_focus, "cursor_mode", e_table->cursor_mode, "length_threshold", e_table->length_threshold, + "table_selection_model", e_table->selection, NULL); - gtk_signal_connect (GTK_OBJECT (e_table->group), "row_selection", - GTK_SIGNAL_FUNC(group_row_selection), e_table); gtk_signal_connect (GTK_OBJECT (e_table->group), "cursor_change", GTK_SIGNAL_FUNC(group_cursor_change), e_table); gtk_signal_connect (GTK_OBJECT (e_table->group), "double_click", @@ -607,6 +583,9 @@ et_real_construct (ETable *e_table, ETableHeader *full_header, ETableModel *etm, e_table->model = etm; gtk_object_ref (GTK_OBJECT (etm)); + gtk_object_set (GTK_OBJECT (e_table->selection), + "model", etm, + NULL); gtk_widget_push_visual (gdk_rgb_get_visual ()); gtk_widget_push_colormap (gdk_rgb_get_cmap ()); @@ -812,9 +791,9 @@ e_table_selected_row_foreach (ETable *e_table, ETableForeachFunc callback, gpointer closure) { - e_table_group_selected_row_foreach(e_table->group, - callback, - closure); + e_table_selection_model_foreach(e_table->selection, + callback, + closure); } @@ -1240,7 +1219,6 @@ e_table_class_init (GtkObjectClass *object_class) object_class->set_arg = et_set_arg; object_class->get_arg = et_get_arg; - klass->row_selection = NULL; klass->cursor_change = NULL; klass->double_click = NULL; klass->right_click = NULL; @@ -1256,14 +1234,6 @@ e_table_class_init (GtkObjectClass *object_class) klass->table_drag_drop = NULL; klass->table_drag_data_received = NULL; - et_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableClass, row_selection), - gtk_marshal_NONE__INT_INT, - GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - et_signals [CURSOR_CHANGE] = gtk_signal_new ("cursor_change", GTK_RUN_LAST, diff --git a/widgets/e-table/e-table.h b/widgets/e-table/e-table.h index 06905a3711..a2e608b41e 100644 --- a/widgets/e-table/e-table.h +++ b/widgets/e-table/e-table.h @@ -80,7 +80,6 @@ typedef struct { typedef struct { GtkTableClass parent_class; - void (*row_selection) (ETable *et, int row, gboolean selected); void (*cursor_change) (ETable *et, int row); void (*double_click) (ETable *et, int row); gint (*right_click) (ETable *et, int row, int col, GdkEvent *event); diff --git a/widgets/table/e-table-group-container.c b/widgets/table/e-table-group-container.c index f4e10917fb..f3788f154f 100644 --- a/widgets/table/e-table-group-container.c +++ b/widgets/table/e-table-group-container.c @@ -37,6 +37,7 @@ enum { ARG_TABLE_DRAW_GRID, ARG_TABLE_DRAW_FOCUS, ARG_CURSOR_MODE, + ARG_TABLE_SELECTION_MODEL, ARG_LENGTH_THRESHOLD, }; @@ -97,6 +98,9 @@ etgc_destroy (GtkObject *object) if (etgc->sort_info) gtk_object_unref (GTK_OBJECT(etgc->sort_info)); + if (etgc->table_selection_model) + gtk_object_unref (GTK_OBJECT(etgc->table_selection_model)); + if (etgc->rect) gtk_object_destroy (GTK_OBJECT(etgc->rect)); @@ -315,13 +319,6 @@ compute_text (ETableGroupContainer *etgc, ETableGroupContainerChildNode *child_n g_free (text); } -static void -child_row_selection (ETableGroup *etg, int row, gboolean selected, - ETableGroupContainer *etgc) -{ - e_table_group_row_selection (E_TABLE_GROUP (etgc), row, selected); -} - static void child_cursor_change (ETableGroup *etg, int row, ETableGroupContainer *etgc) @@ -395,10 +392,9 @@ etgc_add (ETableGroup *etg, gint row) "drawgrid", etgc->draw_grid, "drawfocus", etgc->draw_focus, "cursor_mode", etgc->cursor_mode, + "table_selection_model", etgc->table_selection_model, "length_threshold", etgc->length_threshold, NULL); - gtk_signal_connect (GTK_OBJECT (child), "row_selection", - GTK_SIGNAL_FUNC (child_row_selection), etgc); gtk_signal_connect (GTK_OBJECT (child), "cursor_change", GTK_SIGNAL_FUNC (child_cursor_change), etgc); gtk_signal_connect (GTK_OBJECT (child), "double_click", @@ -546,29 +542,6 @@ etgc_get_focus_column (ETableGroup *etg) return 0; } -static void -etgc_selected_row_foreach (ETableGroup *etg, - ETableForeachFunc func, - gpointer closure) -{ - ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg); - if (etgc->children) { - GList *list; - for (list = etgc->children; list; list = list->next) { - ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data; - ETableGroup *child = child_node->child; - e_table_group_selected_row_foreach (child, func, closure); - } - } -} - - - - - - - - static void etgc_thaw (ETableGroup *etg) { @@ -612,6 +585,20 @@ etgc_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) } break; + case ARG_TABLE_SELECTION_MODEL: + if (etgc->table_selection_model) + gtk_object_unref(GTK_OBJECT(etgc->table_selection_model)); + etgc->table_selection_model = E_TABLE_SELECTION_MODEL(GTK_VALUE_OBJECT (*arg)); + if (etgc->table_selection_model) + gtk_object_ref(GTK_OBJECT(etgc->table_selection_model)); + for (list = etgc->children; list; list = g_list_next (list)) { + ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data; + gtk_object_set (GTK_OBJECT(child_node->child), + "table_selection_model", etgc->table_selection_model, + NULL); + } + break; + case ARG_TABLE_DRAW_GRID: etgc->draw_grid = GTK_VALUE_BOOL (*arg); for (list = etgc->children; list; list = g_list_next (list)) { @@ -697,7 +684,6 @@ etgc_class_init (GtkObjectClass *object_class) e_group_class->get_cursor_row = etgc_get_cursor_row; e_group_class->get_focus_column = etgc_get_focus_column; e_group_class->get_printable = etgc_get_printable; - e_group_class->selected_row_foreach = etgc_selected_row_foreach; gtk_object_add_arg_type ("ETableGroupContainer::drawgrid", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); @@ -705,6 +691,8 @@ etgc_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_TABLE_DRAW_FOCUS); gtk_object_add_arg_type ("ETableGroupContainer::cursor_mode", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_CURSOR_MODE); + gtk_object_add_arg_type ("ETableGroupContainer::table_selection_model", GTK_TYPE_OBJECT, + GTK_ARG_WRITABLE, ARG_TABLE_SELECTION_MODEL); gtk_object_add_arg_type ("ETableGroupContainer::length_threshold", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_LENGTH_THRESHOLD); @@ -811,6 +799,7 @@ etgc_init (GtkObject *object) container->draw_focus = 1; container->cursor_mode = E_TABLE_CURSOR_SIMPLE; container->length_threshold = -1; + container->table_selection_model = NULL; } E_MAKE_TYPE (e_table_group_container, "ETableGroupContainer", ETableGroupContainer, etgc_class_init, etgc_init, PARENT_TYPE); diff --git a/widgets/table/e-table-group-container.h b/widgets/table/e-table-group-container.h index 1157768ea4..bdb717b92d 100644 --- a/widgets/table/e-table-group-container.h +++ b/widgets/table/e-table-group-container.h @@ -41,6 +41,8 @@ typedef struct { int n; int length_threshold; + ETableSelectionModel *table_selection_model; + guint draw_grid : 1; guint draw_focus : 1; ETableCursorMode cursor_mode; diff --git a/widgets/table/e-table-group-leaf.c b/widgets/table/e-table-group-leaf.c index 08c4c4a475..f6b540cdae 100644 --- a/widgets/table/e-table-group-leaf.c +++ b/widgets/table/e-table-group-leaf.c @@ -31,6 +31,7 @@ enum { ARG_TABLE_DRAW_FOCUS, ARG_CURSOR_MODE, ARG_LENGTH_THRESHOLD, + ARG_TABLE_SELECTION_MODEL, }; static void etgl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); @@ -44,6 +45,8 @@ etgl_destroy (GtkObject *object) gtk_object_unref (GTK_OBJECT(etgl->subset)); if (etgl->item) gtk_object_destroy (GTK_OBJECT(etgl->item)); + if (etgl->table_selection_model) + gtk_object_unref (GTK_OBJECT(etgl->table_selection_model)); if (GTK_OBJECT_CLASS (etgl_parent_class)->destroy) GTK_OBJECT_CLASS (etgl_parent_class)->destroy (object); } @@ -80,13 +83,6 @@ e_table_group_leaf_new (GnomeCanvasGroup *parent, return E_TABLE_GROUP (etgl); } -static void -etgl_row_selection (GtkObject *object, gint row, gboolean selected, ETableGroupLeaf *etgl) -{ - if (row < E_TABLE_SUBSET(etgl->subset)->n_map) - e_table_group_row_selection (E_TABLE_GROUP(etgl), E_TABLE_SUBSET(etgl->subset)->map_table[row], selected); -} - static void etgl_cursor_change (GtkObject *object, gint row, ETableGroupLeaf *etgl) { @@ -149,10 +145,9 @@ etgl_realize (GnomeCanvasItem *item) "cursor_mode", etgl->cursor_mode, "minimum_width", etgl->minimum_width, "length_threshold", etgl->length_threshold, + "table_selection_model", etgl->table_selection_model, NULL)); - gtk_signal_connect (GTK_OBJECT(etgl->item), "row_selection", - GTK_SIGNAL_FUNC(etgl_row_selection), etgl); gtk_signal_connect (GTK_OBJECT(etgl->item), "cursor_change", GTK_SIGNAL_FUNC(etgl_cursor_change), etgl); gtk_signal_connect (GTK_OBJECT(etgl->item), "double_click", @@ -244,15 +239,6 @@ etgl_get_printable (ETableGroup *etg) return e_table_item_get_printable (etgl->item); } -static void -etgl_selected_row_foreach(ETableGroup *etg, - ETableForeachFunc func, - gpointer closure) -{ - ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg); - e_table_item_selected_row_foreach (etgl->item, func, closure); -} - static void etgl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) { @@ -284,6 +270,17 @@ etgl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) NULL); } break; + case ARG_TABLE_SELECTION_MODEL: + if (etgl->table_selection_model) + gtk_object_unref(GTK_OBJECT(etgl->table_selection_model)); + etgl->table_selection_model = E_TABLE_SELECTION_MODEL(GTK_VALUE_OBJECT (*arg)); + if (etgl->table_selection_model) + gtk_object_ref(GTK_OBJECT(etgl->table_selection_model)); + if (etgl->item) { + gnome_canvas_item_set (GNOME_CANVAS_ITEM(etgl->item), + "table_selection_model", etgl->table_selection_model, + NULL); + } case ARG_TABLE_DRAW_GRID: etgl->draw_grid = GTK_VALUE_BOOL (*arg); @@ -365,7 +362,6 @@ etgl_class_init (GtkObjectClass *object_class) e_group_class->get_cursor_row = etgl_get_cursor_row; e_group_class->get_focus_column = etgl_get_focus_column; e_group_class->get_printable = etgl_get_printable; - e_group_class->selected_row_foreach = etgl_selected_row_foreach; gtk_object_add_arg_type ("ETableGroupLeaf::drawgrid", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); @@ -375,6 +371,8 @@ etgl_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_CURSOR_MODE); gtk_object_add_arg_type ("ETableGroupLeaf::length_threshold", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_LENGTH_THRESHOLD); + gtk_object_add_arg_type ("ETableGroupLeaf::table_selection_model", GTK_TYPE_OBJECT, + GTK_ARG_WRITABLE, ARG_TABLE_SELECTION_MODEL); gtk_object_add_arg_type ("ETableGroupLeaf::height", GTK_TYPE_DOUBLE, GTK_ARG_READABLE, ARG_HEIGHT); @@ -403,6 +401,8 @@ etgl_init (GtkObject *object) etgl->cursor_mode = E_TABLE_CURSOR_SIMPLE; etgl->length_threshold = -1; + etgl->table_selection_model = NULL; + e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM(object), etgl_reflow); } diff --git a/widgets/table/e-table-group-leaf.h b/widgets/table/e-table-group-leaf.h index 365f268307..1cc041206b 100644 --- a/widgets/table/e-table-group-leaf.h +++ b/widgets/table/e-table-group-leaf.h @@ -32,6 +32,8 @@ typedef struct { guint draw_grid : 1; guint draw_focus : 1; ETableCursorMode cursor_mode; + + ETableSelectionModel *table_selection_model; } ETableGroupLeaf; typedef struct { diff --git a/widgets/table/e-table-group.c b/widgets/table/e-table-group.c index 18f8084b2c..d3c6e2e08d 100644 --- a/widgets/table/e-table-group.c +++ b/widgets/table/e-table-group.c @@ -25,7 +25,6 @@ static GnomeCanvasGroupClass *etg_parent_class; enum { - ROW_SELECTION, CURSOR_CHANGE, DOUBLE_CLICK, RIGHT_CLICK, @@ -239,31 +238,6 @@ e_table_group_get_printable (ETableGroup *etg) return NULL; } -void -e_table_group_selected_row_foreach (ETableGroup *etg, - ETableForeachFunc func, - gpointer closure) -{ - g_return_if_fail (etg != NULL); - g_return_if_fail (E_IS_TABLE_GROUP (etg)); - - if (ETG_CLASS (etg)->selected_row_foreach) - ETG_CLASS (etg)->selected_row_foreach (etg, func, closure); -} - - - -void -e_table_group_row_selection (ETableGroup *e_table_group, gint row, gboolean selected) -{ - g_return_if_fail (e_table_group != NULL); - g_return_if_fail (E_IS_TABLE_GROUP (e_table_group)); - - gtk_signal_emit (GTK_OBJECT (e_table_group), - etg_signals [ROW_SELECTION], - row, selected); -} - void e_table_group_cursor_change (ETableGroup *e_table_group, gint row) { @@ -364,7 +338,6 @@ etg_class_init (GtkObjectClass *object_class) item_class->event = etg_event; - klass->row_selection = NULL; klass->cursor_change = NULL; klass->double_click = NULL; klass->right_click = NULL; @@ -382,18 +355,9 @@ etg_class_init (GtkObjectClass *object_class) klass->get_focus = etg_get_focus; klass->get_ecol = NULL; klass->get_printable = NULL; - klass->selected_row_foreach = NULL; etg_parent_class = gtk_type_class (PARENT_TYPE); - etg_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableGroupClass, row_selection), - gtk_marshal_NONE__INT_INT, - GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - etg_signals [CURSOR_CHANGE] = gtk_signal_new ("cursor_change", GTK_RUN_LAST, diff --git a/widgets/table/e-table-group.h b/widgets/table/e-table-group.h index ef6be1d35f..f4fd25a779 100644 --- a/widgets/table/e-table-group.h +++ b/widgets/table/e-table-group.h @@ -45,7 +45,6 @@ typedef struct { GnomeCanvasGroupClass parent_class; /* Signals */ - void (*row_selection) (ETableGroup *etg, int row, gboolean selected); void (*cursor_change) (ETableGroup *etg, int row); void (*double_click) (ETableGroup *etg, int row); gint (*right_click) (ETableGroup *etg, int row, int col, GdkEvent *event); @@ -65,7 +64,6 @@ typedef struct { gint (*get_focus_column) (ETableGroup *etg); ETableCol *(*get_ecol) (ETableGroup *etg); EPrintable *(*get_printable) (ETableGroup *etg); - void (*selected_row_foreach) (ETableGroup *etg, ETableForeachFunc func, gpointer closure); } ETableGroupClass; @@ -91,9 +89,6 @@ gint e_table_group_get_focus_column (ETableGroup *etg); ETableHeader *e_table_group_get_header (ETableGroup *etg); ETableCol *e_table_group_get_ecol (ETableGroup *etg); EPrintable *e_table_group_get_printable (ETableGroup *etg); -void e_table_group_selected_row_foreach (ETableGroup *etg, - ETableForeachFunc func, - gpointer closure); ETableGroup *e_table_group_new (GnomeCanvasGroup *parent, ETableHeader *full_header, @@ -108,9 +103,6 @@ void e_table_group_construct (GnomeCanvasGroup *parent, ETableModel *model); /* For emitting the signals */ -void e_table_group_row_selection (ETableGroup *etg, - gint row, - gboolean selected); void e_table_group_cursor_change (ETableGroup *etg, gint row); void e_table_group_double_click (ETableGroup *etg, diff --git a/widgets/table/e-table-header.c b/widgets/table/e-table-header.c index 06aeb50b3f..f95797e5c4 100644 --- a/widgets/table/e-table-header.c +++ b/widgets/table/e-table-header.c @@ -616,7 +616,7 @@ e_table_header_col_diff (ETableHeader *eth, int start_col, int end_col) if (start_col < 0) start_col = 0; if (end_col > eth->col_count) - end_col = eth->col_count - 1; + end_col = eth->col_count; total = 0; for (col = start_col; col < end_col; col++){ diff --git a/widgets/table/e-table-item.c b/widgets/table/e-table-item.c index 947b28107e..9e66a487be 100644 --- a/widgets/table/e-table-item.c +++ b/widgets/table/e-table-item.c @@ -30,7 +30,6 @@ static GnomeCanvasItemClass *eti_parent_class; enum { - ROW_SELECTION, CURSOR_CHANGE, DOUBLE_CLICK, RIGHT_CLICK, @@ -44,11 +43,11 @@ enum { ARG_0, ARG_TABLE_HEADER, ARG_TABLE_MODEL, + ARG_TABLE_SELECTION_MODEL, ARG_TABLE_DRAW_GRID, ARG_TABLE_DRAW_FOCUS, ARG_CURSOR_MODE, ARG_LENGTH_THRESHOLD, - ARG_HAS_CURSOR, ARG_CURSOR_ROW, ARG_MINIMUM_WIDTH, @@ -59,18 +58,17 @@ enum { static int eti_get_height (ETableItem *eti); static int eti_get_minimum_width (ETableItem *eti); static int eti_row_height (ETableItem *eti, int row); -static void e_table_item_unselect_row (ETableItem *eti, int row); -static void e_table_item_select_row (ETableItem *eti, int row); -static void eti_selection (GnomeCanvasItem *item, int flags, gpointer user_data); -static int eti_selection_compare (GnomeCanvasItem *item, gpointer data1, gpointer data2, int flags); -static void e_table_item_focus (ETableItem *eti, int col, int row, gboolean add_selection); -static void -eti_request_region_show (ETableItem *eti, - int start_col, int start_row, - int end_col, int end_row); +static void e_table_item_focus (ETableItem *eti, int col, int row, gboolean shift_p, gboolean ctrl_p); +static void eti_cursor_change (ETableSelectionModel *selection, int row, int col, ETableItem *eti); +static void eti_selection_change (ETableSelectionModel *selection, ETableItem *eti); +#if 0 +static void eti_request_region_show (ETableItem *eti, + int start_col, int start_row, + int end_col, int end_row); +#endif #define ETI_ROW_HEIGHT(eti,row) ((eti)->height_cache && (eti)->height_cache[(row)] != -1 ? (eti)->height_cache[(row)] : eti_row_height((eti),(row))) -static gint +inline static gint model_to_view_row(ETableItem *eti, int row) { int i; @@ -90,7 +88,7 @@ model_to_view_row(ETableItem *eti, int row) return row; } -static gint +inline static gint view_to_model_row(ETableItem *eti, int row) { if (eti->uses_source_model) { @@ -309,6 +307,28 @@ eti_remove_table_model (ETableItem *eti) eti->uses_source_model = 0; } +/* + * eti_remove_table_model: + * + * Invoked to release the table model associated with this ETableItem + */ +static void +eti_remove_table_selection_model (ETableItem *eti) +{ + if (!eti->selection) + return; + + gtk_signal_disconnect (GTK_OBJECT (eti->selection), + eti->selection_change_id); + gtk_signal_disconnect (GTK_OBJECT (eti->selection), + eti->cursor_change_id); + gtk_object_unref (GTK_OBJECT (eti->selection)); + + eti->selection_change_id = 0; + eti->cursor_change_id = 0; + eti->selection = NULL; +} + /* * eti_remove_header_model: * @@ -579,16 +599,19 @@ eti_request_region_redraw (ETableItem *eti, int end_col, int end_row, int border) { int x1, y1, width, height; - - x1 = e_table_header_col_diff (eti->header, 0, start_col); - y1 = eti_row_diff (eti, 0, start_row); - width = e_table_header_col_diff (eti->header, start_col, end_col + 1); - height = eti_row_diff (eti, start_row, end_row + 1); - - eti_item_region_redraw (eti, eti->x1 + x1 - border, - eti->y1 + y1 - border, - eti->x1 + x1 + width + 1 + border, - eti->y1 + y1 + height + 1 + border); + + if (eti->rows > 0) { + + x1 = e_table_header_col_diff (eti->header, 0, start_col); + y1 = eti_row_diff (eti, 0, start_row); + width = e_table_header_col_diff (eti->header, start_col, end_col + 1); + height = eti_row_diff (eti, start_row, end_row + 1); + + eti_item_region_redraw (eti, eti->x1 + x1 - border, + eti->y1 + y1 - border, + eti->x1 + x1 + width + 1 + border, + eti->y1 + y1 + height + 1 + border); + } } /* @@ -619,7 +642,7 @@ eti_table_model_row_changed (ETableModel *table_model, int row, ETableItem *eti) eti_table_model_changed (table_model, eti); return; } - + eti_request_region_redraw (eti, 0, row, eti->cols, row, 0); } @@ -630,7 +653,7 @@ eti_table_model_cell_changed (ETableModel *table_model, int col, int row, ETable eti_table_model_changed (table_model, eti); return; } - + eti_request_region_redraw (eti, 0, row, eti->cols -1, row, 0); } @@ -652,14 +675,20 @@ e_table_item_redraw_range (ETableItem *eti, int end_col, int end_row) { int border; + int cursor_col, cursor_row; g_return_if_fail (eti != NULL); g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - if ((start_col == eti->cursor_col) || - (end_col == eti->cursor_col) || - (view_to_model_row(eti, start_row) == eti->cursor_row) || - (view_to_model_row(eti, end_row) == eti->cursor_row)) + + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); + + if ((start_col == cursor_col) || + (end_col == cursor_col) || + (view_to_model_row(eti, start_row) == cursor_row) || + (view_to_model_row(eti, end_row) == cursor_row)) border = 2; else border = 0; @@ -710,6 +739,25 @@ eti_add_table_model (ETableItem *eti, ETableModel *table_model) eti_table_model_changed (table_model, eti); } +static void +eti_add_table_selection_model (ETableItem *eti, ETableSelectionModel *selection) +{ + g_assert (eti->selection == NULL); + + eti->selection = selection; + gtk_object_ref (GTK_OBJECT (eti->selection)); + + eti->selection_change_id = gtk_signal_connect ( + GTK_OBJECT (selection), "selection_changed", + GTK_SIGNAL_FUNC (eti_selection_change), eti); + + eti->cursor_change_id = gtk_signal_connect ( + GTK_OBJECT (selection), "cursor_changed", + GTK_SIGNAL_FUNC (eti_cursor_change), eti); + + eti_selection_change(selection, eti); +} + static void eti_header_dim_changed (ETableHeader *eth, int col, ETableItem *eti) { @@ -727,7 +775,7 @@ eti_header_structure_changed (ETableHeader *eth, ETableItem *eti) * There should be at least one column */ g_assert (eti->cols != 0); - + if (eti->cell_views){ eti_unrealize_cell_views (eti); eti_detach_cell_views (eti); @@ -772,10 +820,10 @@ eti_destroy (GtkObject *object) eti_remove_header_model (eti); eti_remove_table_model (eti); + eti_remove_table_selection_model (eti); -#if 0 - g_slist_free (eti->selection); -#endif + if (eti->selection) + gtk_object_unref(GTK_OBJECT(eti->selection)); if (eti->height_cache_idle_id) g_source_remove(eti->height_cache_idle_id); @@ -791,6 +839,7 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) { GnomeCanvasItem *item; ETableItem *eti; + int cursor_col; item = GNOME_CANVAS_ITEM (o); eti = E_TABLE_ITEM (o); @@ -806,6 +855,12 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) eti_add_table_model (eti, E_TABLE_MODEL(GTK_VALUE_OBJECT (*arg))); break; + case ARG_TABLE_SELECTION_MODEL: + eti_remove_table_selection_model (eti); + if (GTK_VALUE_OBJECT (*arg)) + eti_add_table_selection_model (eti, E_TABLE_SELECTION_MODEL(GTK_VALUE_OBJECT (*arg))); + break; + case ARG_LENGTH_THRESHOLD: eti->length_threshold = GTK_VALUE_INT (*arg); break; @@ -831,7 +886,11 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti)); break; case ARG_CURSOR_ROW: - e_table_item_focus (eti, eti->cursor_col != -1 ? eti->cursor_col : 0, view_to_model_row(eti, GTK_VALUE_INT (*arg)), FALSE); + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + NULL); + + e_table_item_focus (eti, cursor_col != -1 ? cursor_col : 0, view_to_model_row(eti, GTK_VALUE_INT (*arg)), FALSE, FALSE); break; } eti->needs_redraw = 1; @@ -843,6 +902,7 @@ eti_get_arg (GtkObject *o, GtkArg *arg, guint arg_id) { GnomeCanvasItem *item; ETableItem *eti; + int row; item = GNOME_CANVAS_ITEM (o); eti = E_TABLE_ITEM (o); @@ -857,11 +917,11 @@ eti_get_arg (GtkObject *o, GtkArg *arg, guint arg_id) case ARG_MINIMUM_WIDTH: GTK_VALUE_DOUBLE (*arg) = eti->minimum_width; break; - case ARG_HAS_CURSOR: - GTK_VALUE_BOOL (*arg) = (eti->cursor_row != -1); - break; case ARG_CURSOR_ROW: - GTK_VALUE_INT (*arg) = model_to_view_row(eti, eti->cursor_row); + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &row, + NULL); + GTK_VALUE_INT (*arg) = model_to_view_row(eti, row); break; default: arg->type = GTK_TYPE_INVALID; @@ -890,18 +950,16 @@ eti_init (GnomeCanvasItem *item) eti->source_model = NULL; eti->row_guess = -1; - eti->cursor_row = -1; - eti->cursor_col = 0; eti->cursor_mode = E_TABLE_CURSOR_SIMPLE; + eti->selection_change_id = 0; + eti->cursor_change_id = 0; eti->selection = NULL; eti->needs_redraw = 0; eti->needs_compute_height = 0; e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM (eti), eti_reflow); - e_canvas_item_set_selection_callback (GNOME_CANVAS_ITEM (eti), eti_selection); - e_canvas_item_set_selection_compare_callback (GNOME_CANVAS_ITEM (eti), eti_selection_compare); } #define gray50_width 2 @@ -1078,13 +1136,19 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, for (row = first_row; row < last_row; row++){ int xd, height; gboolean selected; + gint cursor_col, cursor_row; height = ETI_ROW_HEIGHT (eti, row); xd = x_offset; /* printf ("paint: %d %d\n", yd, yd + height); */ - selected = g_slist_find (eti->selection, GINT_TO_POINTER (view_to_model_row(eti, row))) != NULL; + selected = e_table_selection_model_is_row_selected(eti->selection, row); + + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); for (col = first_col; col < last_col; col++){ ETableCol *ecol = e_table_header_get_column (eti->header, col); @@ -1092,7 +1156,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, gboolean col_selected = selected; switch (eti->cursor_mode) { case E_TABLE_CURSOR_SIMPLE: - if (eti->cursor_col == col && eti->cursor_row == view_to_model_row(eti, row)) + if (cursor_col == col && cursor_row == view_to_model_row(eti, row)) col_selected = !col_selected; break; case E_TABLE_CURSOR_LINE: @@ -1103,7 +1167,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, e_cell_draw (ecell_view, drawable, ecol->col_idx, col, row, col_selected, xd, yd, xd + ecol->width, yd + height); - if (col == eti->cursor_col && view_to_model_row(eti, row) == eti->cursor_row){ + if (col == cursor_col && view_to_model_row(eti, row) == cursor_row){ f_x1 = xd; f_x2 = xd + ecol->width; f_y1 = yd; @@ -1213,31 +1277,55 @@ static void eti_cursor_move (ETableItem *eti, gint row, gint column) { e_table_item_leave_edit (eti); - e_table_item_focus (eti, column, view_to_model_row(eti, row), FALSE); + e_table_item_focus (eti, column, view_to_model_row(eti, row), FALSE, FALSE); } static void eti_cursor_move_left (ETableItem *eti) { - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row), eti->cursor_col - 1); + int cursor_col, cursor_row; + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); + + eti_cursor_move (eti, model_to_view_row(eti, cursor_row), cursor_col - 1); } static void eti_cursor_move_right (ETableItem *eti) { - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row), eti->cursor_col + 1); + int cursor_col, cursor_row; + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); + + eti_cursor_move (eti, model_to_view_row(eti, cursor_row), cursor_col + 1); } static void eti_cursor_move_up (ETableItem *eti) { - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row) - 1, eti->cursor_col); + int cursor_col, cursor_row; + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); + + eti_cursor_move (eti, model_to_view_row(eti, cursor_row) - 1, cursor_col); } static void eti_cursor_move_down (ETableItem *eti) { - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row) + 1, eti->cursor_col); + int cursor_col, cursor_row; + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + "cursor_row", &cursor_row, + NULL); + + eti_cursor_move (eti, model_to_view_row(eti, cursor_row) + 1, cursor_col); } /* FIXME: cursor */ @@ -1254,36 +1342,26 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) double x1, y1; int col, row; gint shifted = e->button.state & GDK_SHIFT_MASK; + gint ctrled = e->button.state & GDK_CONTROL_MASK; + gint cursor_row, cursor_col; switch (e->button.button) { case 1: /* Fall through. */ case 2: gnome_canvas_item_w2i (item, &e->button.x, &e->button.y); - if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) return TRUE; - - if (eti->cursor_row != view_to_model_row(eti, row) || eti->cursor_col != col){ - /* - * Focus the cell, and select the row - */ - if (e_table_item_is_row_selected(eti, view_to_model_row(eti, row))) { - int nums[2]; - e_table_item_leave_edit (eti); - nums[0] = view_to_model_row(eti, row); - nums[1] = 0; - e_canvas_item_remove_selection(GNOME_CANVAS_ITEM(eti), nums); - } else { - e_table_item_leave_edit (eti); - e_table_item_focus (eti, col, view_to_model_row(eti, row), shifted); - } - } - if (eti->cursor_row == view_to_model_row(eti, row) && eti->cursor_col == col){ + e_table_selection_model_do_something(eti->selection, row, col, shifted, ctrled); + + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &cursor_row, + "cursor_col", &cursor_col, + NULL); + + if (cursor_row == view_to_model_row(eti, row) && cursor_col == col){ - e_table_item_focus (eti, col, view_to_model_row(eti, row), shifted); - ecol = e_table_header_get_column (eti->header, col); ecell_view = eti->cell_views [col]; @@ -1316,6 +1394,7 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) case GDK_BUTTON_RELEASE: { double x1, y1; int col, row; + gint cursor_row, cursor_col; switch (e->button.button) { case 1: /* Fall through. */ @@ -1326,7 +1405,12 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) return TRUE; - if (eti->cursor_row == view_to_model_row(eti, row) && eti->cursor_col == col){ + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &cursor_row, + "cursor_col", &cursor_col, + NULL); + + if (cursor_row == view_to_model_row(eti, row) && cursor_col == col){ ecol = e_table_header_get_column (eti->header, col); ecell_view = eti->cell_views [col]; @@ -1370,13 +1454,19 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) case GDK_MOTION_NOTIFY: { int col, row; double x1, y1; + gint cursor_col, cursor_row; gnome_canvas_item_w2i (item, &e->motion.x, &e->motion.y); if (!find_cell (eti, e->motion.x, e->motion.y, &col, &row, &x1, &y1)) return TRUE; - if (eti->cursor_row == view_to_model_row(eti, row) && eti->cursor_col == col){ + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &cursor_row, + "cursor_col", &cursor_col, + NULL); + + if (cursor_row == view_to_model_row(eti, row) && cursor_col == col){ ecol = e_table_header_get_column (eti->header, col); ecell_view = eti->cell_views [col]; @@ -1391,40 +1481,42 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) break; } - case GDK_KEY_PRESS: - if (eti->cursor_col == -1) + case GDK_KEY_PRESS: { + gint cursor_row, cursor_col; + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &cursor_row, + "cursor_col", &cursor_col, + NULL); + + if (cursor_col == -1) return FALSE; switch (e->key.keyval){ case GDK_Left: -#if 0 - if (!eti->mode_spreadsheet && eti_editing (eti)) + if (eti_editing (eti)) break; -#endif - if (eti->cursor_col > 0) + if (cursor_col > 0) eti_cursor_move_left (eti); break; case GDK_Right: -#if 0 - if (!eti->mode_spreadsheet && eti_editing (eti)) + if (eti_editing (eti)) break; -#endif - if (eti->cursor_col < eti->cols - 1) + if (cursor_col < eti->cols - 1) eti_cursor_move_right (eti); break; case GDK_Up: - if (eti->cursor_row != view_to_model_row(eti, 0)) + if (cursor_row != view_to_model_row(eti, 0)) eti_cursor_move_up (eti); else return_val = FALSE; break; case GDK_Down: - if (eti->cursor_row != view_to_model_row(eti, eti->rows - 1)) + if (cursor_row != view_to_model_row(eti, eti->rows - 1)) eti_cursor_move_down (eti); else return_val = FALSE; @@ -1435,17 +1527,17 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) case GDK_ISO_Left_Tab: if ((e->key.state & GDK_SHIFT_MASK) != 0){ /* shift tab */ - if (eti->cursor_col > 0) + if (cursor_col > 0) eti_cursor_move_left (eti); - else if (eti->cursor_row != view_to_model_row(eti, 0)) - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row) - 1, eti->cols - 1); + else if (cursor_row != view_to_model_row(eti, 0)) + eti_cursor_move (eti, model_to_view_row(eti, cursor_row) - 1, eti->cols - 1); else return_val = FALSE; } else { - if (eti->cursor_col < eti->cols - 1) + if (cursor_col < eti->cols - 1) eti_cursor_move_right (eti); - else if (eti->cursor_row != view_to_model_row(eti, eti->rows - 1)) - eti_cursor_move (eti, model_to_view_row(eti, eti->cursor_row) + 1, 0); + else if (cursor_row != view_to_model_row(eti, eti->rows - 1)) + eti_cursor_move (eti, model_to_view_row(eti, cursor_row) + 1, 0); else return_val = FALSE; } @@ -1454,17 +1546,25 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) default: if (!eti_editing (eti)){ gtk_signal_emit (GTK_OBJECT (eti), eti_signals [KEY_PRESS], - model_to_view_row(eti, eti->cursor_row), eti->cursor_col, e, &return_val); + model_to_view_row(eti, cursor_row), cursor_col, e, &return_val); } else { - ecol = e_table_header_get_column (eti->header, eti->cursor_col); - ecell_view = eti->cell_views [eti->cursor_col]; - e_cell_event (ecell_view, e, ecol->col_idx, eti->cursor_col, model_to_view_row(eti, eti->cursor_row)); + ecol = e_table_header_get_column (eti->header, cursor_col); + ecell_view = eti->cell_views [cursor_col]; + e_cell_event (ecell_view, e, ecol->col_idx, cursor_col, model_to_view_row(eti, cursor_row)); } } break; + } - case GDK_KEY_RELEASE: - if (eti->cursor_col == -1) + case GDK_KEY_RELEASE: { + gint cursor_row, cursor_col; + + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_row", &cursor_row, + "cursor_col", &cursor_col, + NULL); + + if (cursor_col == -1) return FALSE; if (eti_editing (eti)){ @@ -1473,6 +1573,7 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) e_cell_event (ecell_view, e, ecol->col_idx, eti->editing_col, eti->editing_row); } break; + } default: return_val = FALSE; @@ -1480,21 +1581,6 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) return return_val; } -/* - * ETableItem::row_selection method - */ -static void -eti_row_selection (ETableItem *eti, int row, gboolean selected) -{ - int view_row = model_to_view_row(eti, row); - eti_request_region_redraw (eti, 0, view_row, eti->cols - 1, view_row, 0); - - if (selected) - eti->selection = g_slist_prepend (eti->selection, GINT_TO_POINTER (row)); - else - eti->selection = g_slist_remove (eti->selection, GINT_TO_POINTER (row)); -} - static void eti_class_init (GtkObjectClass *object_class) { @@ -1514,7 +1600,6 @@ eti_class_init (GtkObjectClass *object_class) item_class->point = eti_point; item_class->event = eti_event; - eti_class->row_selection = eti_row_selection; eti_class->cursor_change = NULL; eti_class->double_click = NULL; eti_class->right_click = NULL; @@ -1524,6 +1609,8 @@ eti_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_TABLE_HEADER); gtk_object_add_arg_type ("ETableItem::ETableModel", GTK_TYPE_OBJECT, GTK_ARG_WRITABLE, ARG_TABLE_MODEL); + gtk_object_add_arg_type ("ETableItem::table_selection_model", GTK_TYPE_OBJECT, + GTK_ARG_WRITABLE, ARG_TABLE_SELECTION_MODEL); gtk_object_add_arg_type ("ETableItem::drawgrid", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); gtk_object_add_arg_type ("ETableItem::drawfocus", GTK_TYPE_BOOL, @@ -1539,19 +1626,9 @@ eti_class_init (GtkObjectClass *object_class) GTK_ARG_READWRITE, ARG_WIDTH); gtk_object_add_arg_type ("ETableItem::height", GTK_TYPE_DOUBLE, GTK_ARG_READABLE, ARG_HEIGHT); - gtk_object_add_arg_type ("ETableItem::has_cursor", GTK_TYPE_BOOL, - GTK_ARG_READWRITE, ARG_HAS_CURSOR); gtk_object_add_arg_type ("ETableItem::cursor_row", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_CURSOR_ROW); - eti_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableItemClass, row_selection), - gtk_marshal_NONE__INT_INT, - GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - eti_signals [CURSOR_CHANGE] = gtk_signal_new ("cursor_change", GTK_RUN_LAST, @@ -1614,11 +1691,11 @@ e_table_item_get_type (void) void e_table_item_set_cursor (ETableItem *eti, int col, int row) { - e_table_item_focus(eti, col, view_to_model_row(eti, row), FALSE); + e_table_item_focus(eti, col, view_to_model_row(eti, row), FALSE, FALSE); } static void -e_table_item_focus (ETableItem *eti, int col, int row, gboolean add_selection) +e_table_item_focus (ETableItem *eti, int col, int row, gboolean shift_p, gboolean ctrl_p) { g_return_if_fail (eti != NULL); g_return_if_fail (E_IS_TABLE_ITEM (eti)); @@ -1632,34 +1709,26 @@ e_table_item_focus (ETableItem *eti, int col, int row, gboolean add_selection) } if (row != -1) { - int *nums; - nums = g_new(int, 2); - nums[0] = row; - nums[1] = col; - if (add_selection) - e_canvas_item_add_selection(GNOME_CANVAS_ITEM(eti), nums); - else - e_canvas_item_set_cursor(GNOME_CANVAS_ITEM(eti), nums); + e_table_selection_model_do_something(eti->selection, + row, col, + shift_p, + ctrl_p); } } gint e_table_item_get_focused_column (ETableItem *eti) { + int cursor_col; + g_return_val_if_fail (eti != NULL, -1); g_return_val_if_fail (E_IS_TABLE_ITEM (eti), -1); + + gtk_object_get(GTK_OBJECT(eti->selection), + "cursor_col", &cursor_col, + NULL); - return eti->cursor_col; -} - - -const GSList * -e_table_item_get_selection (ETableItem *eti) -{ - g_return_val_if_fail (eti != NULL, NULL); - g_return_val_if_fail (E_IS_TABLE_ITEM (eti), NULL); - - return eti->selection; + return cursor_col; } gboolean @@ -1668,91 +1737,28 @@ e_table_item_is_row_selected (ETableItem *eti, int row) g_return_val_if_fail (eti != NULL, FALSE); g_return_val_if_fail (E_IS_TABLE_ITEM (eti), FALSE); - if (g_slist_find (eti->selection, GINT_TO_POINTER (row))) - return TRUE; - else - return FALSE; -} - -void e_table_item_selected_row_foreach (ETableItem *eti, - ETableForeachFunc func, - gpointer closure) -{ - GSList *list = eti->selection; - for (; list; list = g_slist_next(list)) { - (func) (GPOINTER_TO_INT(list->data), closure); - } -} - -static void -e_table_item_unselect_row (ETableItem *eti, int row) -{ - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - gtk_signal_emit (GTK_OBJECT (eti), eti_signals [ROW_SELECTION], - row, 0); + return e_table_selection_model_is_row_selected(eti->selection, row); } static void -e_table_item_select_row (ETableItem *eti, int row) +eti_cursor_change (ETableSelectionModel *selection, int row, int col, ETableItem *eti) { - g_return_if_fail (eti != NULL); - g_return_if_fail (E_IS_TABLE_ITEM (eti)); - - gtk_signal_emit (GTK_OBJECT (eti), eti_signals [ROW_SELECTION], - GINT_TO_POINTER (row), 1); -} - -static void -eti_selection (GnomeCanvasItem *item, int flags, gpointer data) -{ - int *nums = data; - int row = nums[0]; - int col = nums[1]; - ETableItem *eti = E_TABLE_ITEM(item); - int selected = e_table_item_is_row_selected(eti, row); - int cursored = (row == eti->cursor_row); + int view_row = model_to_view_row(eti, row); - if (selected && (flags & E_CANVAS_ITEM_SELECTION_SELECT) == 0) { - e_table_item_unselect_row (eti, row); - } - if ((!selected) && (flags & E_CANVAS_ITEM_SELECTION_SELECT) != 0) { - e_table_item_select_row (eti, row); - } - if ((!cursored) && (flags & E_CANVAS_ITEM_SELECTION_CURSOR) != 0) { - int view_row = model_to_view_row(eti, row); - - eti->cursor_col = col; - eti->cursor_row = row; - gtk_signal_emit (GTK_OBJECT (eti), eti_signals [CURSOR_CHANGE], - view_row); - eti_request_region_show (eti, col, view_row, col, view_row); - } - if ((cursored) && (flags & E_CANVAS_ITEM_SELECTION_CURSOR) == 0) { - e_table_item_leave_edit(eti); - eti->cursor_row = -1; - eti->cursor_col = -1; - } - if (flags & E_CANVAS_ITEM_SELECTION_DELETE_DATA) { - g_free(data); - } + gtk_signal_emit (GTK_OBJECT (eti), eti_signals [CURSOR_CHANGE], + view_row); + eti_request_region_show (eti, col, view_row, col, view_row); + if (e_table_model_is_cell_editable(selection->model, col, row)) + e_table_item_enter_edit (eti, col, view_row); } -static gint -eti_selection_compare (GnomeCanvasItem *item, gpointer data1, gpointer data2, int flags) +static void +eti_selection_change (ETableSelectionModel *selection, ETableItem *eti) { - int *val1 = (int *) data1; - int *val2 = (int *) data2; - if (*val1 < *val2) - return -1; - else if (*val1 == *val2) - return 0; - else - return 1; + eti->needs_redraw = TRUE; + gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(eti)); } - void e_table_item_enter_edit (ETableItem *eti, int col, int row) { @@ -1760,6 +1766,9 @@ e_table_item_enter_edit (ETableItem *eti, int col, int row) g_return_if_fail (eti != NULL); g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if (eti_editing (eti)) + e_table_item_leave_edit(eti); eti->editing_col = col; eti->editing_row = row; diff --git a/widgets/table/e-table-item.h b/widgets/table/e-table-item.h index 619db68803..7102ef3ef7 100644 --- a/widgets/table/e-table-item.h +++ b/widgets/table/e-table-item.h @@ -5,6 +5,7 @@ #include #include "e-table-model.h" #include "e-table-header.h" +#include "e-table-selection-model.h" #include "e-table-defines.h" #include @@ -27,6 +28,7 @@ typedef struct { ETableHeader *header; ETableModel *source_model; + ETableSelectionModel *selection; int x1, y1; int minimum_width, width, height; @@ -43,6 +45,9 @@ typedef struct { int table_model_cell_change_id; int table_model_row_inserted_id; int table_model_row_deleted_id; + + int selection_change_id; + int cursor_change_id; GdkGC *fill_gc; GdkGC *grid_gc; @@ -77,12 +82,8 @@ typedef struct { int length_threshold; gint row_guess; - gint cursor_row; - gint cursor_col; ETableCursorMode cursor_mode; - GSList *selection; - /* * During editing */ @@ -94,7 +95,6 @@ typedef struct { typedef struct { GnomeCanvasItemClass parent_class; - void (*row_selection) (ETableItem *eti, int row, gboolean selected); void (*cursor_change) (ETableItem *eti, int row); void (*double_click) (ETableItem *eti, int row); gint (*right_click) (ETableItem *eti, int row, int col, GdkEvent *event); @@ -114,7 +114,6 @@ gint e_table_item_get_focused_column (ETableItem *eti); /* * Handling the selection */ -const GSList *e_table_item_get_selection (ETableItem *e_table_Item); gboolean e_table_item_is_row_selected (ETableItem *e_table_Item, int row); diff --git a/widgets/table/e-table-scrolled.c b/widgets/table/e-table-scrolled.c index b8260b6407..1a7b5251ad 100644 --- a/widgets/table/e-table-scrolled.c +++ b/widgets/table/e-table-scrolled.c @@ -28,7 +28,6 @@ static GtkObjectClass *parent_class; enum { - ROW_SELECTION, CURSOR_CHANGE, DOUBLE_CLICK, RIGHT_CLICK, @@ -47,14 +46,6 @@ enum { static gint ets_signals [LAST_SIGNAL] = { 0, }; -static void -row_selection_proxy (ETable *et, int row, gboolean selected, ETableScrolled *ets) -{ - gtk_signal_emit (GTK_OBJECT (ets), - ets_signals [ROW_SELECTION], - row, selected); -} - static void cursor_change_proxy (ETable *et, int row, ETableScrolled *ets) { @@ -117,8 +108,6 @@ e_table_scrolled_real_construct (ETableScrolled *ets) gtk_container_add(GTK_CONTAINER(ets), GTK_WIDGET(ets->table)); - gtk_signal_connect(GTK_OBJECT(ets->table), "row_selection", - GTK_SIGNAL_FUNC(row_selection_proxy), ets); gtk_signal_connect(GTK_OBJECT(ets->table), "cursor_change", GTK_SIGNAL_FUNC(cursor_change_proxy), ets); gtk_signal_connect(GTK_OBJECT(ets->table), "double_click", @@ -297,20 +286,11 @@ e_table_scrolled_class_init (GtkObjectClass *object_class) object_class->set_arg = ets_set_arg; object_class->get_arg = ets_get_arg; - klass->row_selection = NULL; klass->cursor_change = NULL; klass->double_click = NULL; klass->right_click = NULL; klass->key_press = NULL; - ets_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableScrolledClass, row_selection), - gtk_marshal_NONE__INT_INT, - GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - ets_signals [CURSOR_CHANGE] = gtk_signal_new ("cursor_change", GTK_RUN_LAST, diff --git a/widgets/table/e-table-scrolled.h b/widgets/table/e-table-scrolled.h index daaf4429a0..d5a0c06a58 100644 --- a/widgets/table/e-table-scrolled.h +++ b/widgets/table/e-table-scrolled.h @@ -25,7 +25,6 @@ typedef struct { typedef struct { EScrollFrameClass parent_class; - void (*row_selection) (ETableScrolled *est, int row, gboolean selected); void (*cursor_change) (ETableScrolled *est, int row); void (*double_click) (ETableScrolled *est, int row); gint (*right_click) (ETableScrolled *est, int row, int col, GdkEvent *event); diff --git a/widgets/table/e-table-selection-model.c b/widgets/table/e-table-selection-model.c index 9c631ca603..35e0cb13aa 100644 --- a/widgets/table/e-table-selection-model.c +++ b/widgets/table/e-table-selection-model.c @@ -15,36 +15,49 @@ #define ETSM_CLASS(e) ((ETableSelectionModelClass *)((GtkObject *)e)->klass) #define PARENT_TYPE gtk_object_get_type () - + +#define ONES ((guint32) 0xffffffff) + +#define BOX(n) ((n) / 32) +#define OFFSET(n) (31 - ((n) % 32)) +#define BITMASK(n) (((guint32) 0x1) << OFFSET(n)) +#define BITMASK_LEFT(n) (((guint32) ONES) << (32 - ((n) % 32))) +#define BITMASK_RIGHT(n) (((guint32) ONES) >> ((n) % 32)) static GtkObjectClass *e_table_selection_model_parent_class; enum { - SELECTION_MODEL_CHANGED, - GROUP_SELECTION_CHANGED, + CURSOR_CHANGED, + SELECTION_CHANGED, LAST_SIGNAL }; static guint e_table_selection_model_signals [LAST_SIGNAL] = { 0, }; +enum { + ARG_0, + ARG_MODEL, + ARG_CURSOR_ROW, + ARG_CURSOR_COL, +}; + static void model_changed(ETableModel *etm, ETableSelectionModel *etsm) { g_free(etsm->selection); etsm->selection = NULL; etsm->row_count = -1; + gtk_signal_emit(GTK_OBJECT(etsm), + e_table_selection_model_signals [SELECTION_CHANGED]); } +#if 1 static void model_row_inserted(ETableModel *etm, int row, ETableSelectionModel *etsm) { int box; int i; - int offset; if(etsm->row_count >= 0) { - guint32 bitmask1 = 0xffff; - guint32 bitmask2; - /* Add another word if needed. */ if ((etsm->row_count & 0x1f) == 0) { etsm->selection = g_realloc(etsm->selection, (etsm->row_count >> 5) + 1); @@ -58,12 +71,8 @@ model_row_inserted(ETableModel *etm, int row, ETableSelectionModel *etsm) etsm->selection[i] = (etsm->selection[i] >> 1) | (etsm->selection[i - 1] << 31); } - /* Build bitmasks for the left and right half of the box */ - offset = row & 0x1f; - bitmask1 = bitmask1 << (32 - offset); - bitmask2 = ~bitmask1; /* Shift right half of box one bit to the right. */ - etsm->selection[box] = (etsm->selection[box] & bitmask1) | ((etsm->selection[box] & bitmask2) >> 1); + etsm->selection[box] = (etsm->selection[box] & BITMASK_LEFT(row)) | ((etsm->selection[box] & BITMASK_RIGHT(row)) >> 1); etsm->row_count ++; } } @@ -74,19 +83,15 @@ model_row_deleted(ETableModel *etm, int row, ETableSelectionModel *etsm) int box; int i; int last; - int offset; if(etsm->row_count >= 0) { - guint32 bitmask1 = 0xffff; - guint32 bitmask2; + guint32 bitmask; box = row >> 5; last = etsm->row_count >> 5; /* Build bitmasks for the left and right half of the box */ - offset = row & 0x1f; - bitmask1 = bitmask1 << (32 - offset); - bitmask2 = (~bitmask1) >> 1; + bitmask = BITMASK_RIGHT(row) >> 1; /* Shift right half of box one bit to the left. */ - etsm->selection[box] = (etsm->selection[box] & bitmask1) | ((etsm->selection[box] & bitmask2) << 1); + etsm->selection[box] = (etsm->selection[box] & BITMASK_LEFT(row))| ((etsm->selection[box] & bitmask) << 1); /* Shift all words to the right of our box left one bit. */ if (box < last) { @@ -105,6 +110,21 @@ model_row_deleted(ETableModel *etm, int row, ETableSelectionModel *etsm) } } +#else + +static void +model_row_inserted(ETableModel *etm, int row, ETableSelectionModel *etsm) +{ + model_changed(etm, etsm); +} + +static void +model_row_deleted(ETableModel *etm, int row, ETableSelectionModel *etsm) +{ + model_changed(etm, etsm); +} +#endif + inline static void add_model(ETableSelectionModel *etsm, ETableModel *model) { @@ -141,15 +161,59 @@ etsm_destroy (GtkObject *object) ETableSelectionModel *etsm; etsm = E_TABLE_SELECTION_MODEL (object); - + + drop_model(etsm); + g_free(etsm->selection); } +static void +etsm_get_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + ETableSelectionModel *etsm = E_TABLE_SELECTION_MODEL (o); + + switch (arg_id){ + case ARG_MODEL: + GTK_VALUE_OBJECT (*arg) = GTK_OBJECT(etsm->model); + break; + + case ARG_CURSOR_ROW: + GTK_VALUE_INT(*arg) = etsm->cursor_row; + break; + + case ARG_CURSOR_COL: + GTK_VALUE_INT(*arg) = etsm->cursor_col; + break; + } +} + +static void +etsm_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + ETableSelectionModel *etsm = E_TABLE_SELECTION_MODEL (o); + + switch (arg_id){ + case ARG_MODEL: + drop_model(etsm); + add_model(etsm, GTK_VALUE_OBJECT (*arg) ? E_TABLE_MODEL(GTK_VALUE_OBJECT (*arg)) : NULL); + break; + + case ARG_CURSOR_ROW: + e_table_selection_model_do_something(etsm, GTK_VALUE_INT(*arg), etsm->cursor_col, FALSE, FALSE); + break; + + case ARG_CURSOR_COL: + e_table_selection_model_do_something(etsm, etsm->cursor_row, GTK_VALUE_INT(*arg), FALSE, FALSE); + break; + } +} + static void e_table_selection_model_init (ETableSelectionModel *selection) { selection->selection = NULL; selection->row_count = -1; + selection->model = NULL; } static void @@ -160,29 +224,38 @@ e_table_selection_model_class_init (ETableSelectionModelClass *klass) e_table_selection_model_parent_class = gtk_type_class (gtk_object_get_type ()); object_class = GTK_OBJECT_CLASS(klass); - + object_class->destroy = etsm_destroy; -#if 0 - e_table_selection_model_signals [SELECTION_MODEL_CHANGED] = - gtk_signal_new ("selection_model_changed", + object_class->get_arg = etsm_get_arg; + object_class->set_arg = etsm_set_arg; + + e_table_selection_model_signals [CURSOR_CHANGED] = + gtk_signal_new ("cursor_changed", GTK_RUN_LAST, object_class->type, - GTK_SIGNAL_OFFSET (ETableSelectionModelClass, selection_model_changed), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); + GTK_SIGNAL_OFFSET (ETableSelectionModelClass, cursor_changed), + gtk_marshal_NONE__INT_INT, + GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - e_table_selection_model_signals [GROUP_SELECTION_CHANGED] = - gtk_signal_new ("group_selection_changed", + e_table_selection_model_signals [SELECTION_CHANGED] = + gtk_signal_new ("selection_changed", GTK_RUN_LAST, object_class->type, - GTK_SIGNAL_OFFSET (ETableSelectionModelClass, group_selection_changed), + GTK_SIGNAL_OFFSET (ETableSelectionModelClass, selection_changed), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); - klass->selection_model_changed = NULL; - klass->group_selection_changed = NULL; -#endif + klass->cursor_changed = NULL; + klass->selection_changed = NULL; + gtk_object_class_add_signals (object_class, e_table_selection_model_signals, LAST_SIGNAL); + + gtk_object_add_arg_type ("ETableSelectionModel::model", GTK_TYPE_OBJECT, + GTK_ARG_READWRITE, ARG_MODEL); + gtk_object_add_arg_type ("ETableSelectionModel::cursor_row", GTK_TYPE_INT, + GTK_ARG_READWRITE, ARG_CURSOR_ROW); + gtk_object_add_arg_type ("ETableSelectionModel::cursor_col", GTK_TYPE_INT, + GTK_ARG_READWRITE, ARG_CURSOR_COL); } E_MAKE_TYPE(e_table_selection_model, "ETableSelectionModel", ETableSelectionModel, @@ -196,12 +269,12 @@ e_table_selection_model_new (void) gboolean e_table_selection_model_is_row_selected (ETableSelectionModel *selection, - guint n) + gint n) { if (selection->row_count < n) return 0; else - return ((selection->selection[n / 32]) >> (31 - (n % 32))) & 0x1; + return (selection->selection[BOX(n)] >> OFFSET(n)) & 0x1; } void @@ -211,12 +284,12 @@ e_table_selection_model_foreach (ETableSelectionModel *selection, { int i; int last = (selection->row_count + 31) / 32; - for (i = 0; i < last; i--) { + for (i = 0; i < last; i++) { if (selection->selection[i]) { int j; guint32 value = selection->selection[i]; - for (j = 0; j < 32; j--) { - if (value & 0x8000) { + for (j = 0; j < 32; j++) { + if (value & 0x80000000) { callback(i * 32 + j, closure); } value <<= 1; @@ -224,3 +297,92 @@ e_table_selection_model_foreach (ETableSelectionModel *selection, } } } + +#define OPERATE(object, mask, grow) ((grow) ? ((object) |= ~(mask)) : ((object) &= (mask))) + +void e_table_selection_model_do_something (ETableSelectionModel *selection, + guint row, + guint col, + gboolean shift_p, + gboolean ctrl_p) +{ + if (selection->row_count < 0) { + if (selection->model) { + selection->row_count = e_table_model_row_count(selection->model); + g_free(selection->selection); + selection->selection = g_new0(gint, (selection->row_count + 31) / 32); + } + } + if (selection->row_count >= 0 && row < selection->row_count) { + if (shift_p) { + int grow_selection; + int i; + int last; + int first_row; + int last_row; + if ((selection->selection_start_row < row && row <= selection->cursor_row) || + (selection->selection_start_row >= row && row >= selection->cursor_row)) { + /* In this case, the selection is shrinking. */ + grow_selection = FALSE; + } else if ((selection->selection_start_row <= selection->cursor_row && selection->cursor_row <= row) || + (selection->selection_start_row > selection->cursor_row && selection->cursor_row >= row)) { + /* In this case, the selection is growing. */ + grow_selection = TRUE; + } else { + /* In this case the selection is changing direction. Ick. Screw it. */ + return; + } + first_row = MIN(selection->cursor_row, row); + last_row = MAX(selection->cursor_row, row) + 1; + if (first_row != last_row) { + i = BOX(first_row); + last = BOX(last_row); + + if (i == last) { + OPERATE(selection->selection[i], BITMASK_LEFT(first_row) | BITMASK_RIGHT(last_row), grow_selection); + } else { + OPERATE(selection->selection[i], BITMASK_LEFT(first_row), grow_selection); + for (i ++; i < last; i++) + if (grow_selection) + selection->selection[i] = ONES; + else + selection->selection[i] = 0; + OPERATE(selection->selection[i], BITMASK_RIGHT(last_row), grow_selection); + } + gtk_signal_emit(GTK_OBJECT(selection), + e_table_selection_model_signals [SELECTION_CHANGED]); + } + } else { + if (ctrl_p) { + if (selection->selection[BOX(row)] & BITMASK(row)) + selection->selection[BOX(row)] &= ~BITMASK(row); + else + selection->selection[BOX(row)] |= BITMASK(row); + gtk_signal_emit(GTK_OBJECT(selection), + e_table_selection_model_signals [SELECTION_CHANGED]); + } else { + int i; + for (i = 0; i < ((selection->row_count + 31) / 32); i++) { + if (!((i == BOX(row) && selection->selection[i] == BITMASK(row)) || + (i != BOX(row) && selection->selection[i] == 0))) { + g_free(selection->selection); + selection->selection = g_new0(gint, (selection->row_count + 31) / 32); + selection->selection[BOX(row)] = BITMASK(row); + + gtk_signal_emit(GTK_OBJECT(selection), + e_table_selection_model_signals [SELECTION_CHANGED]); + break; + } + } + } + selection->selection_start_row = row; + } + if (selection->cursor_row != row || + selection->cursor_col != col) { + gtk_signal_emit(GTK_OBJECT(selection), + e_table_selection_model_signals[CURSOR_CHANGED], row, col); + selection->cursor_row = row; + selection->cursor_col = col; + } + } +} diff --git a/widgets/table/e-table-selection-model.h b/widgets/table/e-table-selection-model.h index 2aaba021f8..251b1ceb00 100644 --- a/widgets/table/e-table-selection-model.h +++ b/widgets/table/e-table-selection-model.h @@ -19,13 +19,14 @@ typedef struct { gint row_count; guint32 *selection; - + gint cursor_row; gint cursor_col; + gint selection_start_row; guint model_changed_id; guint model_row_inserted_id, model_row_deleted_id; - + guint frozen : 1; guint selection_model_changed : 1; guint group_info_changed : 1; @@ -37,20 +38,26 @@ typedef struct { /* * Signals */ -#if 0 - void (*selection_model_changed) (ETableSelectionModel *selection); - void (*group_model_changed) (ETableSelectionModel *selection); -#endif + + void (*cursor_changed) (ETableSelectionModel *selection, int row, int col); + void (*selection_changed) (ETableSelectionModel *selection); + } ETableSelectionModelClass; GtkType e_table_selection_model_get_type (void); -gboolean e_table_selection_model_is_row_selected (ETableSelectionModel *selection, - guint n); -void e_table_selection_model_foreach (ETableSelectionModel *selection, - ETableForeachFunc callback, - gpointer closure); +gboolean e_table_selection_model_is_row_selected (ETableSelectionModel *selection, + gint n); +void e_table_selection_model_foreach (ETableSelectionModel *selection, + ETableForeachFunc callback, + gpointer closure); + +void e_table_selection_model_do_something (ETableSelectionModel *selection, + guint row, + guint col, + gboolean shift_p, + gboolean ctrl_p); -ETableSelectionModel *e_table_selection_model_new (void); +ETableSelectionModel *e_table_selection_model_new (void); #endif /* _E_TABLE_SELECTION_MODEL_H_ */ diff --git a/widgets/table/e-table.c b/widgets/table/e-table.c index c20c7cd21e..ae258a5c44 100644 --- a/widgets/table/e-table.c +++ b/widgets/table/e-table.c @@ -40,7 +40,6 @@ static GtkObjectClass *e_table_parent_class; enum { - ROW_SELECTION, CURSOR_CHANGE, DOUBLE_CLICK, RIGHT_CLICK, @@ -183,6 +182,8 @@ e_table_init (GtkObject *object) e_table->drag_col = -1; e_table->drop_row = -1; e_table->drop_col = -1; + + e_table->selection = e_table_selection_model_new(); } static void @@ -269,18 +270,6 @@ table_canvas_reflow (GnomeCanvas *canvas, ETable *e_table) e_table->reflow_idle_id = g_idle_add_full (400, (GSourceFunc) table_canvas_reflow_idle, e_table, NULL); } -static void -group_row_selection (ETableGroup *etg, int row, gboolean selected, ETable *et) -{ - gtk_signal_emit (GTK_OBJECT (et), - et_signals [ROW_SELECTION], - row, selected); - if (et->row_selection_active && selected) { - e_table_click_to_add_commit (E_TABLE_CLICK_TO_ADD(et->click_to_add)); - et->row_selection_active = FALSE; - } -} - static void group_cursor_change (ETableGroup *etg, int row, ETable *et) { @@ -336,9 +325,8 @@ changed_idle (gpointer data) "drawfocus", et->draw_focus, "cursor_mode", et->cursor_mode, "length_threshold", et->length_threshold, + "table_selection_model", et->selection, NULL); - gtk_signal_connect (GTK_OBJECT (et->group), "row_selection", - GTK_SIGNAL_FUNC (group_row_selection), et); gtk_signal_connect (GTK_OBJECT (et->group), "cursor_change", GTK_SIGNAL_FUNC (group_cursor_change), et); gtk_signal_connect (GTK_OBJECT (et->group), "double_click", @@ -399,14 +387,6 @@ et_table_row_deleted (ETableModel *table_model, int row, ETable *et) } } -static void -click_to_add_row_selection (ETableClickToAdd *etcta, int row, gboolean selected, ETable *et) -{ - if ((!et->row_selection_active) && selected) { - et->row_selection_active = TRUE; - } -} - static void e_table_setup_table (ETable *e_table, ETableHeader *full_header, ETableHeader *header, ETableModel *model) @@ -460,9 +440,6 @@ e_table_setup_table (ETable *e_table, ETableHeader *full_header, ETableHeader *h "message", e_table->click_to_add_message, NULL); - gtk_signal_connect(GTK_OBJECT(e_table->click_to_add), "row_selection", - GTK_SIGNAL_FUNC(click_to_add_row_selection), e_table); - e_canvas_vbox_add_item(E_CANVAS_VBOX(e_table->canvas_vbox), e_table->click_to_add); } @@ -477,10 +454,9 @@ e_table_setup_table (ETable *e_table, ETableHeader *full_header, ETableHeader *h "drawfocus", e_table->draw_focus, "cursor_mode", e_table->cursor_mode, "length_threshold", e_table->length_threshold, + "table_selection_model", e_table->selection, NULL); - gtk_signal_connect (GTK_OBJECT (e_table->group), "row_selection", - GTK_SIGNAL_FUNC(group_row_selection), e_table); gtk_signal_connect (GTK_OBJECT (e_table->group), "cursor_change", GTK_SIGNAL_FUNC(group_cursor_change), e_table); gtk_signal_connect (GTK_OBJECT (e_table->group), "double_click", @@ -607,6 +583,9 @@ et_real_construct (ETable *e_table, ETableHeader *full_header, ETableModel *etm, e_table->model = etm; gtk_object_ref (GTK_OBJECT (etm)); + gtk_object_set (GTK_OBJECT (e_table->selection), + "model", etm, + NULL); gtk_widget_push_visual (gdk_rgb_get_visual ()); gtk_widget_push_colormap (gdk_rgb_get_cmap ()); @@ -812,9 +791,9 @@ e_table_selected_row_foreach (ETable *e_table, ETableForeachFunc callback, gpointer closure) { - e_table_group_selected_row_foreach(e_table->group, - callback, - closure); + e_table_selection_model_foreach(e_table->selection, + callback, + closure); } @@ -1240,7 +1219,6 @@ e_table_class_init (GtkObjectClass *object_class) object_class->set_arg = et_set_arg; object_class->get_arg = et_get_arg; - klass->row_selection = NULL; klass->cursor_change = NULL; klass->double_click = NULL; klass->right_click = NULL; @@ -1256,14 +1234,6 @@ e_table_class_init (GtkObjectClass *object_class) klass->table_drag_drop = NULL; klass->table_drag_data_received = NULL; - et_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ETableClass, row_selection), - gtk_marshal_NONE__INT_INT, - GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - et_signals [CURSOR_CHANGE] = gtk_signal_new ("cursor_change", GTK_RUN_LAST, diff --git a/widgets/table/e-table.h b/widgets/table/e-table.h index 06905a3711..a2e608b41e 100644 --- a/widgets/table/e-table.h +++ b/widgets/table/e-table.h @@ -80,7 +80,6 @@ typedef struct { typedef struct { GtkTableClass parent_class; - void (*row_selection) (ETable *et, int row, gboolean selected); void (*cursor_change) (ETable *et, int row); void (*double_click) (ETable *et, int row); gint (*right_click) (ETable *et, int row, int col, GdkEvent *event); -- cgit v1.2.3