From 14bfde56c8c54c7ad947dcf96be38f8b4e71e53e Mon Sep 17 00:00:00 2001 From: Christopher James Lahey Date: Fri, 25 Feb 2000 04:08:59 +0000 Subject: Added duplicate_value and add_value. Use the new compare functions. Made 2000-02-24 Christopher James Lahey * test-table.c: Added duplicate_value and add_value. Use the new compare functions. Made it so we only create one model to better test model view stuff. Changed the test to not have as many extra, useless, columns. * test-cols.c, test-check.c: Added duplicate_value and add_value. Use the new compare functions. * e-table.c, e-table.h: Use all the new features of e-table-groups (sorting and grouping). Handle on the fly reorganization of groups in an idle loop. Compare functions now are to return -1 if the first item is greater, 0 if they are equal, or 1 if the second item is greater. * e-table-subset.c, e-table-subset.h: Made e-table-subset disconnect properly from its signals when it dies. * e-table-subset-variable.c, e-table-subset-variable.h: Virtualized the add and remove commands so that e_table_sorted_variable could override the add command to do sorting. * e-table-sorted.c: Fixed this to inherit properly from ETableSubset. * e-table-simple.h, e-table-simple.c: Added handling of duplicate_value and free_value; * e-table-model.c, e-table-model.h: Added duplicate_value and free_value for memory allocation of table elements outside the table. * e-table-item.c: Fixed a crashing bug. * e-table-group.c: Added sorting. Fixed destruction to delete the right things. * e-table-group-leaf.c, e-table-group-leaf.h: Pass column and sort order information into the e_table_sorted_variable. Properly destroy things when deleted. * e-table-group-container.c, e-table-group-container.h: Properly handle the list of subgroups. Handle proper sorting and grouping of subgroups. * e-table-sorted-variable.c, e-table-sorted-variable.h: Files to do a sorted model that stays sorted as you add and remove rows. * Makefile.am: Added e-table-sorted-variable.c and e-table-sorted-variable.h. svn path=/trunk/; revision=1930 --- widgets/e-table/ChangeLog | 52 +++++++++++ widgets/e-table/Makefile.am | 2 + widgets/e-table/e-table-group-container.c | 56 +++++++++-- widgets/e-table/e-table-group-container.h | 5 +- widgets/e-table/e-table-group-leaf.c | 18 +++- widgets/e-table/e-table-group-leaf.h | 6 +- widgets/e-table/e-table-group.c | 39 ++++++-- widgets/e-table/e-table-item.c | 4 + widgets/e-table/e-table-model.c | 66 +++++++++---- widgets/e-table/e-table-model.h | 9 +- widgets/e-table/e-table-simple.c | 22 +++++ widgets/e-table/e-table-simple.h | 6 ++ widgets/e-table/e-table-sorted-variable.c | 148 ++++++++++++++++++++++++++++++ widgets/e-table/e-table-sorted-variable.h | 34 +++++++ widgets/e-table/e-table-sorted.c | 2 +- widgets/e-table/e-table-subset-variable.c | 80 +++++++++++----- widgets/e-table/e-table-subset-variable.h | 5 + widgets/e-table/e-table-subset.c | 41 +++++++-- widgets/e-table/e-table-subset.h | 4 + widgets/e-table/e-table.c | 98 ++++++++++++++++++++ widgets/e-table/e-table.h | 10 ++ widgets/e-table/test-check.c | 26 +++++- widgets/e-table/test-cols.c | 27 +++++- widgets/e-table/test-table.c | 39 +++++--- widgets/table/e-table-group-container.c | 56 +++++++++-- widgets/table/e-table-group-container.h | 5 +- widgets/table/e-table-group-leaf.c | 18 +++- widgets/table/e-table-group-leaf.h | 6 +- widgets/table/e-table-group.c | 39 ++++++-- widgets/table/e-table-item.c | 4 + widgets/table/e-table-model.c | 66 +++++++++---- widgets/table/e-table-model.h | 9 +- widgets/table/e-table-simple.c | 22 +++++ widgets/table/e-table-simple.h | 6 ++ widgets/table/e-table-sorted-variable.c | 148 ++++++++++++++++++++++++++++++ widgets/table/e-table-sorted-variable.h | 34 +++++++ widgets/table/e-table-sorted.c | 2 +- widgets/table/e-table-subset-variable.c | 80 +++++++++++----- widgets/table/e-table-subset-variable.h | 5 + widgets/table/e-table-subset.c | 41 +++++++-- widgets/table/e-table-subset.h | 4 + widgets/table/e-table.c | 98 ++++++++++++++++++++ widgets/table/e-table.h | 10 ++ widgets/table/test-check.c | 26 +++++- widgets/table/test-cols.c | 27 +++++- widgets/table/test-table.c | 39 +++++--- 46 files changed, 1354 insertions(+), 190 deletions(-) create mode 100644 widgets/e-table/e-table-sorted-variable.c create mode 100644 widgets/e-table/e-table-sorted-variable.h create mode 100644 widgets/table/e-table-sorted-variable.c create mode 100644 widgets/table/e-table-sorted-variable.h diff --git a/widgets/e-table/ChangeLog b/widgets/e-table/ChangeLog index e4caa9707c..4c4a9d65cd 100644 --- a/widgets/e-table/ChangeLog +++ b/widgets/e-table/ChangeLog @@ -1,3 +1,55 @@ +2000-02-24 Christopher James Lahey + + * test-table.c: Added duplicate_value and add_value. Use the new + compare functions. Made it so we only create one model to better + test model view stuff. Changed the test to not have as many + extra, useless, columns. + + * test-cols.c, test-check.c: Added duplicate_value and add_value. Use the new + compare functions. + + * e-table.c, e-table.h: Use all the new features of e-table-groups + (sorting and grouping). Handle on the fly reorganization of + groups in an idle loop. Compare functions now are to return -1 if + the first item is greater, 0 if they are equal, or 1 if the second + item is greater. + + * e-table-subset.c, e-table-subset.h: Made e-table-subset + disconnect properly from its signals when it dies. + + * e-table-subset-variable.c, e-table-subset-variable.h: + Virtualized the add and remove commands so that + e_table_sorted_variable could override the add command to do sorting. + + * e-table-sorted.c: Fixed this to inherit properly from + ETableSubset. + + * e-table-simple.h, e-table-simple.c: Added handling of + duplicate_value and free_value; + + * e-table-model.c, e-table-model.h: Added duplicate_value and + free_value for memory allocation of table elements outside the + table. + + * e-table-item.c: Fixed a crashing bug. + + * e-table-group.c: Added sorting. Fixed destruction to delete the + right things. + + * e-table-group-leaf.c, e-table-group-leaf.h: Pass column and sort + order information into the e_table_sorted_variable. Properly + destroy things when deleted. + + * e-table-group-container.c, e-table-group-container.h: Properly + handle the list of subgroups. Handle proper sorting and grouping + of subgroups. + + * e-table-sorted-variable.c, e-table-sorted-variable.h: Files to + do a sorted model that stays sorted as you add and remove rows. + + * Makefile.am: Added e-table-sorted-variable.c and + e-table-sorted-variable.h. + 2000-02-24 Christopher James Lahey * e-table-item.c: Made keyboard focus navigation work across diff --git a/widgets/e-table/Makefile.am b/widgets/e-table/Makefile.am index 0780ae7c57..c6fe615258 100644 --- a/widgets/e-table/Makefile.am +++ b/widgets/e-table/Makefile.am @@ -39,6 +39,8 @@ libetable_a_SOURCES = \ e-table-simple.h \ e-table-sorted.c \ e-table-sorted.h \ + e-table-sorted-variable.c \ + e-table-sorted-variable.h \ e-table-subset.c \ e-table-subset.h \ e-table-subset-variable.c \ diff --git a/widgets/e-table/e-table-group-container.c b/widgets/e-table/e-table-group-container.c index 634d7934ef..4b30f6af29 100644 --- a/widgets/e-table/e-table-group-container.c +++ b/widgets/e-table/e-table-group-container.c @@ -59,15 +59,42 @@ typedef struct { gint count; } ETableGroupContainerChildNode; +static void +e_table_group_container_child_node_free(ETableGroupContainer *etgc, ETableGroupContainerChildNode *child_node) +{ + ETableGroup *etg = E_TABLE_GROUP(etgc); + ETableGroup *child = child_node->child; + gtk_object_destroy(GTK_OBJECT(child)); + e_table_model_free_value(etg->model, etgc->ecol->col_idx, child_node->key); + gtk_object_destroy(GTK_OBJECT(child_node->text)); + gtk_object_destroy(GTK_OBJECT(child_node->rect)); +} + +static void +e_table_group_container_list_free(ETableGroupContainer *etgc) +{ + ETableGroupContainerChildNode *child_node; + GList *list; + for ( list = etgc->children; list; list = g_list_next(list) ) { + child_node = (ETableGroupContainerChildNode *) list->data; + e_table_group_container_child_node_free(etgc, child_node); + } + g_list_free(etgc->children); +} + static void etgc_destroy (GtkObject *object) { ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (object); gdk_font_unref(etgc->font); + gtk_object_unref(GTK_OBJECT(etgc->ecol)); + gtk_object_destroy(GTK_OBJECT(etgc->rect)); + e_table_group_container_list_free(etgc); GTK_OBJECT_CLASS (etgc_parent_class)->destroy (object); } + #if 0 void e_table_group_add (ETableGroup *etg, GnomeCanvasItem *item) @@ -168,11 +195,13 @@ void e_table_group_container_construct (GnomeCanvasGroup *parent, ETableGroupContainer *etgc, ETableHeader *full_header, ETableHeader *header, - ETableModel *model, ETableCol *ecol, xmlNode *child_rules) + ETableModel *model, ETableCol *ecol, int ascending, xmlNode *child_rules) { e_table_group_construct (parent, E_TABLE_GROUP (etgc), full_header, header, model); etgc->ecol = ecol; + gtk_object_ref(GTK_OBJECT(etgc->ecol)); etgc->child_rules = child_rules; + etgc->ascending = ascending; etgc->font = gdk_font_load ("lucidasans-10"); #if 0 @@ -217,7 +246,7 @@ e_table_group_container_construct (GnomeCanvasGroup *parent, ETableGroupContaine ETableGroup * e_table_group_container_new (GnomeCanvasGroup *parent, ETableHeader *full_header, ETableHeader *header, - ETableModel *model, ETableCol *ecol, xmlNode *child_rules) + ETableModel *model, ETableCol *ecol, int ascending, xmlNode *child_rules) { ETableGroupContainer *etgc; @@ -227,7 +256,7 @@ e_table_group_container_new (GnomeCanvasGroup *parent, ETableHeader *full_ etgc = gtk_type_new (e_table_group_container_get_type ()); e_table_group_container_construct (parent, etgc, full_header, header, - model, ecol, child_rules); + model, ecol, ascending, child_rules); return E_TABLE_GROUP (etgc); } @@ -498,15 +527,21 @@ static void etgc_add (ETableGroup *etg, gint row) GList *list = etgc->children; ETableGroup *child; ETableGroupContainerChildNode *child_node; - for ( ; list; list = g_list_next(list) ) { + int i = 0; + for ( ; list; list = g_list_next(list), i++ ) { + int comp_val; child_node = (ETableGroupContainerChildNode *)(list->data); - if ( (*comp)(child_node->key, val) ) { + comp_val = (*comp)(child_node->key, val); + if ( comp_val == 0 ) { child = child_node->child; child_node->count ++; e_table_group_add(child, row); compute_text(etgc, child_node); return; } + if ( (comp_val > 0 && etgc->ascending) || + (comp_val < 0 && (!etgc->ascending)) ) + break; } child_node = g_new(ETableGroupContainerChildNode, 1); child_node->rect = gnome_canvas_item_new(GNOME_CANVAS_GROUP(etgc), @@ -524,13 +559,17 @@ static void etgc_add (ETableGroup *etg, gint row) NULL); child = e_table_group_new(GNOME_CANVAS_GROUP(etgc), etg->full_header, etg->header, etg->model, etgc->child_rules); child_node->child = child; - child_node->key = val; + child_node->key = e_table_model_duplicate_value(etg->model, etgc->ecol->col_idx, val); gtk_signal_connect(GTK_OBJECT(child), "resize", etgc_child_resize, etgc); child_node->count = 1; e_table_group_add(child, row); - etgc->children = g_list_append(etgc->children, child_node); + if ( list ) { + etgc->children = g_list_insert(etgc->children, child_node, i); + } + else + etgc->children = g_list_append(etgc->children, child_node); compute_text(etgc, child_node); etgc_queue_reposition(E_TABLE_GROUP_CONTAINER(etg)); } @@ -545,8 +584,7 @@ static gboolean etgc_remove (ETableGroup *etg, gint row) if ( e_table_group_remove(child, row) ) { child_node->count --; if ( child_node->count == 0 ) { - gtk_object_unref(GTK_OBJECT(child_node->text)); - gtk_object_unref(GTK_OBJECT(child)); + e_table_group_container_child_node_free(etgc, child_node); etgc->children = g_list_remove(etgc->children, child_node); g_free(child_node); } else { diff --git a/widgets/e-table/e-table-group-container.h b/widgets/e-table/e-table-group-container.h index 4942f9e695..2234e77ac1 100644 --- a/widgets/e-table/e-table-group-container.h +++ b/widgets/e-table/e-table-group-container.h @@ -20,6 +20,7 @@ typedef struct { * The ETableCol used to group this set */ ETableCol *ecol; + gint ascending; /* * List of ETableGroups we stack @@ -55,11 +56,11 @@ typedef struct { } ETableGroupContainerClass; ETableGroup *e_table_group_container_new (GnomeCanvasGroup *parent, ETableHeader *full_header, ETableHeader *header, - ETableModel *model, ETableCol *ecol, xmlNode *child_rules); + ETableModel *model, ETableCol *ecol, int ascending, xmlNode *child_rules); void e_table_group_container_construct (GnomeCanvasGroup *parent, ETableGroupContainer *etgc, ETableHeader *full_header, ETableHeader *header, - ETableModel *model, ETableCol *ecol, xmlNode *child_rules); + ETableModel *model, ETableCol *ecol, int ascending, xmlNode *child_rules); GtkType e_table_group_container_get_type (void); diff --git a/widgets/e-table/e-table-group-leaf.c b/widgets/e-table/e-table-group-leaf.c index ba73ad9886..2e939453d7 100644 --- a/widgets/e-table/e-table-group-leaf.c +++ b/widgets/e-table/e-table-group-leaf.c @@ -36,23 +36,31 @@ static void etgl_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); static void etgl_destroy (GtkObject *object) { - GTK_OBJECT_CLASS (etgl_parent_class)->destroy (object); + ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF(object); + gtk_object_unref(GTK_OBJECT(etgl->subset)); + gtk_object_destroy(GTK_OBJECT(etgl->item)); + if ( GTK_OBJECT_CLASS (etgl_parent_class)->destroy ) + GTK_OBJECT_CLASS (etgl_parent_class)->destroy (object); } static void e_table_group_leaf_construct (GnomeCanvasGroup *parent, ETableGroupLeaf *etgl, ETableHeader *full_header, ETableHeader *header, - ETableModel *model) + ETableModel *model, + int col, + int ascending) { + etgl->subset = E_TABLE_SUBSET_VARIABLE(e_table_sorted_variable_new(model, col, ascending, e_table_header_get_column(full_header, col)->compare)); e_table_group_construct (parent, E_TABLE_GROUP (etgl), full_header, header, model); - etgl->subset = E_TABLE_SUBSET_VARIABLE(e_table_subset_variable_new(model)); } ETableGroup * e_table_group_leaf_new (GnomeCanvasGroup *parent, ETableHeader *full_header, ETableHeader *header, - ETableModel *model) + ETableModel *model, + int col, + int ascending) { ETableGroupLeaf *etgl; @@ -61,7 +69,7 @@ e_table_group_leaf_new (GnomeCanvasGroup *parent, ETableHeader *full_heade etgl = gtk_type_new (e_table_group_leaf_get_type ()); e_table_group_leaf_construct (parent, etgl, full_header, - header, model); + header, model, col, ascending); return E_TABLE_GROUP (etgl); } diff --git a/widgets/e-table/e-table-group-leaf.h b/widgets/e-table/e-table-group-leaf.h index 372bf4cc70..6ffd9066d1 100644 --- a/widgets/e-table/e-table-group-leaf.h +++ b/widgets/e-table/e-table-group-leaf.h @@ -4,7 +4,7 @@ #include #include "e-table-group.h" -#include "e-table-subset-variable.h" +#include "e-table-sorted-variable.h" #include "e-table-item.h" #define E_TABLE_GROUP_LEAF_TYPE (e_table_group_leaf_get_type ()) @@ -33,7 +33,9 @@ typedef struct { ETableGroup *e_table_group_leaf_new (GnomeCanvasGroup *parent, ETableHeader *full_header, ETableHeader *header, - ETableModel *model); + ETableModel *model, + int col, + int ascending); GtkType e_table_group_leaf_get_type (void); #endif /* _E_TABLE_GROUP_LEAF_H_ */ diff --git a/widgets/e-table/e-table-group.c b/widgets/e-table/e-table-group.c index 1f4e2037cd..6ae8a25db7 100644 --- a/widgets/e-table/e-table-group.c +++ b/widgets/e-table/e-table-group.c @@ -17,6 +17,7 @@ #include #include #include "e-util/e-util.h" +#include "e-util/e-xml-utils.h" #define TITLE_HEIGHT 16 #define GROUP_INDENT 10 @@ -45,7 +46,7 @@ enum { static void etg_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); static void etg_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); static gboolean etg_get_focus (ETableGroup *etg); - +static void etg_destroy (GtkObject *object); #if 0 GnomeCanvasItem * e_table_group_new (GnomeCanvasGroup *parent, ETableCol *ecol, @@ -64,6 +65,17 @@ e_table_group_new (GnomeCanvasGroup *parent, ETableCol *ecol, } #endif +static void +etg_destroy (GtkObject *object) +{ + ETableGroup *etg = E_TABLE_GROUP(object); + gtk_object_unref(GTK_OBJECT(etg->header)); + gtk_object_unref(GTK_OBJECT(etg->full_header)); + gtk_object_unref(GTK_OBJECT(etg->model)); + if ( GTK_OBJECT_CLASS (etg_parent_class)->destroy ) + GTK_OBJECT_CLASS (etg_parent_class)->destroy (object); +} + ETableGroup * e_table_group_new (GnomeCanvasGroup *parent, ETableHeader *full_header, @@ -71,17 +83,22 @@ e_table_group_new (GnomeCanvasGroup *parent, ETableModel *model, xmlNode *rules) { + int column; + int ascending; + g_return_val_if_fail (model != NULL, NULL); - + + column = e_xml_get_integer_prop_by_name(rules, "column"); + ascending = e_xml_get_integer_prop_by_name(rules, "ascending"); + if(rules && !xmlStrcmp(rules->name, "group")) { - gint col_idx = atoi(xmlGetProp(rules, "column")); ETableCol *col; - if ( col_idx > e_table_header_count(full_header) ) - return e_table_group_leaf_new(parent, full_header, header, model); - col = e_table_header_get_columns(full_header)[col_idx]; - return e_table_group_container_new(parent, full_header, header, model, col, rules->childs); + if ( column > e_table_header_count(full_header) ) + return e_table_group_leaf_new(parent, full_header, header, model, column, ascending); + col = e_table_header_get_columns(full_header)[column]; + return e_table_group_container_new(parent, full_header, header, model, col, ascending, rules->childs); } else { - return e_table_group_leaf_new(parent, full_header, header, model); + return e_table_group_leaf_new(parent, full_header, header, model, column, ascending); } return NULL; } @@ -93,10 +110,13 @@ e_table_group_construct (GnomeCanvasGroup *parent, ETableHeader *header, ETableModel *model) { - gnome_canvas_item_constructv (GNOME_CANVAS_ITEM (etg), parent, 0, NULL); etg->full_header = full_header; + gtk_object_ref(GTK_OBJECT(etg->full_header)); etg->header = header; + gtk_object_ref(GTK_OBJECT(etg->header)); etg->model = model; + gtk_object_ref(GTK_OBJECT(etg->model)); + gnome_canvas_item_constructv (GNOME_CANVAS_ITEM (etg), parent, 0, NULL); } void @@ -311,6 +331,7 @@ etg_class_init (GtkObjectClass *object_class) object_class->set_arg = etg_set_arg; object_class->get_arg = etg_get_arg; + object_class->destroy = etg_destroy; item_class->event = etg_event; diff --git a/widgets/e-table/e-table-item.c b/widgets/e-table/e-table-item.c index 286b1a8352..a7d5573fad 100644 --- a/widgets/e-table/e-table-item.c +++ b/widgets/e-table/e-table-item.c @@ -307,6 +307,10 @@ static void eti_table_model_changed (ETableModel *table_model, ETableItem *eti) { eti->rows = e_table_model_row_count (eti->table_model); + + if (eti->focused_row > eti->rows - 1) { + eti->focused_row = eti->rows - 1; + } if (eti->cell_views) eti_compute_height (eti); diff --git a/widgets/e-table/e-table-model.c b/widgets/e-table/e-table-model.c index e84e6da4d3..ef14b98018 100644 --- a/widgets/e-table/e-table-model.c +++ b/widgets/e-table/e-table-model.c @@ -13,6 +13,9 @@ #define ETM_CLASS(e) ((ETableModelClass *)((GtkObject *)e)->klass) +#define PARENT_TYPE gtk_object_get_type(); + + static GtkObjectClass *e_table_model_parent_class; enum { @@ -80,6 +83,28 @@ e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row) return ETM_CLASS (e_table_model)->is_cell_editable (e_table_model, col, row); } +void * +e_table_model_duplicate_value (ETableModel *e_table_model, int col, const void *value) +{ + g_return_val_if_fail (e_table_model != NULL, NULL); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL); + + if (ETM_CLASS (e_table_model)->duplicate_value) + return ETM_CLASS (e_table_model)->duplicate_value (e_table_model, col, value); + else + return NULL; +} + +void +e_table_model_free_value (ETableModel *e_table_model, int col, void *value) +{ + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); + + if (ETM_CLASS (e_table_model)->free_value) + ETM_CLASS (e_table_model)->free_value (e_table_model, col, value); +} + static void e_table_model_destroy (GtkObject *object) { @@ -121,27 +146,30 @@ e_table_model_class_init (GtkObjectClass *object_class) gtk_object_class_add_signals (object_class, e_table_model_signals, LAST_SIGNAL); } -GtkType + +guint e_table_model_get_type (void) { - static GtkType type = 0; - - if (!type){ - GtkTypeInfo info = { - "ETableModel", - sizeof (ETableModel), - sizeof (ETableModelClass), - (GtkClassInitFunc) e_table_model_class_init, - (GtkObjectInitFunc) NULL, - NULL, /* reserved 1 */ - NULL, /* reserved 2 */ - (GtkClassInitFunc) NULL - }; - - type = gtk_type_unique (gtk_object_get_type (), &info); - } - - return type; + static guint type = 0; + + if (!type) + { + GtkTypeInfo info = + { + "ETableModle", + sizeof (ETableModel), + sizeof (ETableModelClass), + (GtkClassInitFunc) e_table_model_class_init, + NULL, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + type = gtk_type_unique (gtk_object_get_type(), &info); + } + + return type; } void diff --git a/widgets/e-table/e-table-model.h b/widgets/e-table/e-table-model.h index 9f2dbbf87c..ceca8e348f 100644 --- a/widgets/e-table/e-table-model.h +++ b/widgets/e-table/e-table-model.h @@ -27,6 +27,10 @@ typedef struct { void *(*value_at) (ETableModel *etm, int col, int row); void (*set_value_at) (ETableModel *etm, int col, int row, const void *value); gboolean (*is_cell_editable) (ETableModel *etm, int col, int row); + + void *(*duplicate_value) (ETableModel *etm, int col, const void *value); + void (*free_value) (ETableModel *etm, int col, void *value); + void (*thaw) (ETableModel *etm); /* * Signals @@ -48,9 +52,12 @@ int e_table_model_column_count (ETableModel *e_table_model); const char *e_table_model_column_name (ETableModel *e_table_model, int col); int e_table_model_row_count (ETableModel *e_table_model); void *e_table_model_value_at (ETableModel *e_table_model, int col, int row); -void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *data); +void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *value); gboolean e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row); +void *e_table_model_duplicate_value (ETableModel *e_table_model, int col, const void *value); +void e_table_model_free_value (ETableModel *e_table_model, int col, void *value); + void e_table_model_freeze (ETableModel *e_table_model); void e_table_model_thaw (ETableModel *e_table_model); diff --git a/widgets/e-table/e-table-simple.c b/widgets/e-table/e-table-simple.c index 1f64d08f39..e90abfcc4f 100644 --- a/widgets/e-table/e-table-simple.c +++ b/widgets/e-table/e-table-simple.c @@ -55,6 +55,22 @@ simple_is_cell_editable (ETableModel *etm, int col, int row) return simple->is_cell_editable (etm, col, row, simple->data); } +static void * +simple_duplicate_value (ETableModel *etm, int col, const void *value) +{ + ETableSimple *simple = (ETableSimple *)etm; + + return simple->duplicate_value (etm, col, value, simple->data); +} + +static void +simple_free_value (ETableModel *etm, int col, void *value) +{ + ETableSimple *simple = (ETableSimple *)etm; + + simple->free_value (etm, col, value, simple->data); +} + static void simple_thaw (ETableModel *etm) { @@ -73,6 +89,8 @@ e_table_simple_class_init (GtkObjectClass *object_class) model_class->value_at = simple_value_at; model_class->set_value_at = simple_set_value_at; model_class->is_cell_editable = simple_is_cell_editable; + model_class->duplicate_value = simple_duplicate_value; + model_class->free_value = simple_free_value; model_class->thaw = simple_thaw; } @@ -105,6 +123,8 @@ e_table_simple_new (ETableSimpleColumnCountFn col_count, ETableSimpleValueAtFn value_at, ETableSimpleSetValueAtFn set_value_at, ETableSimpleIsCellEditableFn is_cell_editable, + ETableSimpleDuplicateValueFn duplicate_value, + ETableSimpleFreeValueFn free_value, ETableSimpleThawFn thaw, void *data) { @@ -118,6 +138,8 @@ e_table_simple_new (ETableSimpleColumnCountFn col_count, et->set_value_at = set_value_at; et->is_cell_editable = is_cell_editable; et->thaw = thaw; + et->duplicate_value = duplicate_value; + et->free_value = free_value; et->data = data; return (ETableModel *) et; diff --git a/widgets/e-table/e-table-simple.h b/widgets/e-table/e-table-simple.h index a3164eefc0..51134f45aa 100644 --- a/widgets/e-table/e-table-simple.h +++ b/widgets/e-table/e-table-simple.h @@ -9,6 +9,8 @@ typedef int (*ETableSimpleRowCountFn) (ETableModel *etm, void *dat typedef void *(*ETableSimpleValueAtFn) (ETableModel *etm, int col, int row, void *data); typedef void (*ETableSimpleSetValueAtFn) (ETableModel *etm, int col, int row, const void *val, void *data); typedef gboolean (*ETableSimpleIsCellEditableFn) (ETableModel *etm, int col, int row, void *data); +typedef void *(*ETableSimpleDuplicateValueFn) (ETableModel *etm, int col, const void *val, void *data); +typedef void (*ETableSimpleFreeValueFn) (ETableModel *etm, int col, void *val, void *data); typedef void (*ETableSimpleThawFn) (ETableModel *etm, void *data); typedef struct { @@ -19,6 +21,8 @@ typedef struct { ETableSimpleValueAtFn value_at; ETableSimpleSetValueAtFn set_value_at; ETableSimpleIsCellEditableFn is_cell_editable; + ETableSimpleDuplicateValueFn duplicate_value; + ETableSimpleFreeValueFn free_value; ETableSimpleThawFn thaw; void *data; } ETableSimple; @@ -34,6 +38,8 @@ ETableModel *e_table_simple_new (ETableSimpleColumnCountFn col_count, ETableSimpleValueAtFn value_at, ETableSimpleSetValueAtFn set_value_at, ETableSimpleIsCellEditableFn is_cell_editable, + ETableSimpleDuplicateValueFn duplicate_value, + ETableSimpleFreeValueFn free_value, ETableSimpleThawFn thaw, void *data); diff --git a/widgets/e-table/e-table-sorted-variable.c b/widgets/e-table/e-table-sorted-variable.c new file mode 100644 index 0000000000..478038fdb7 --- /dev/null +++ b/widgets/e-table/e-table-sorted-variable.c @@ -0,0 +1,148 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * E-table-sorted.c: Implements a table that sorts another table + * + * Author: + * Miguel de Icaza (miguel@gnu.org) + * + * (C) 1999 Helix Code, Inc. + */ +#include +#include +#include +#include +#include "e-util/e-util.h" +#include "e-table-sorted-variable.h" + +#define PARENT_TYPE E_TABLE_SUBSET_VARIABLE_TYPE + +#define INCREMENT_AMOUNT 10 + +static ETableSubsetVariableClass *etsv_parent_class; + +static void etsv_proxy_model_changed (ETableModel *etm, ETableSortedVariable *etsv); +static void etsv_proxy_model_row_changed (ETableModel *etm, int row, ETableSortedVariable *etsv); +static void etsv_proxy_model_cell_changed (ETableModel *etm, int col, int row, ETableSortedVariable *etsv); +static void etsv_add (ETableSubsetVariable *etssv, gint row); + +static void +etsv_destroy (GtkObject *object) +{ + ETableSortedVariable *etsv = E_TABLE_SORTED_VARIABLE (object); + ETableSubset *etss = E_TABLE_SUBSET (object); + + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etsv->table_model_changed_id); + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etsv->table_model_row_changed_id); + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etsv->table_model_cell_changed_id); + + etsv->table_model_changed_id = 0; + etsv->table_model_row_changed_id = 0; + etsv->table_model_cell_changed_id = 0; + + GTK_OBJECT_CLASS (etsv_parent_class)->destroy (object); +} + +static void +etsv_class_init (GtkObjectClass *object_class) +{ + ETableSubsetVariableClass *etssv_class = E_TABLE_SUBSET_VARIABLE_CLASS(object_class); + + etsv_parent_class = gtk_type_class (PARENT_TYPE); + + object_class->destroy = etsv_destroy; + + etssv_class->add = etsv_add; +} + +E_MAKE_TYPE(e_table_sorted_variable, "ETableSortedVariable", ETableSortedVariable, etsv_class_init, NULL, PARENT_TYPE); + +static void +etsv_add (ETableSubsetVariable *etssv, + gint row) +{ + ETableModel *etm = E_TABLE_MODEL(etssv); + ETableSubset *etss = E_TABLE_SUBSET(etssv); + ETableSortedVariable *etsv = E_TABLE_SORTED_VARIABLE(etssv); + int i; + int col = etsv->sort_col; + GCompareFunc comp = etsv->compare; + gint ascending = etsv->ascending; + + void *val = e_table_model_value_at(etss->source, col, row); + + /* FIXME: binary search anyone? */ + for ( i = 0; i < etss->n_map; i++ ) { + int comp_val = (*comp)(val, e_table_model_value_at(etss->source, col, etss->map_table[i])); + if ( (ascending && comp_val < 0) || ((!ascending) && comp_val > 0) ) + break; + } + if ( etss->n_map + 1 > etssv->n_vals_allocated ) { + etss->map_table = g_realloc(etss->map_table, (etssv->n_vals_allocated + INCREMENT_AMOUNT) * sizeof(int)); + etssv->n_vals_allocated += INCREMENT_AMOUNT; + } + if ( i < etss->n_map ) + memmove(etss->map_table + i + 1, etss->map_table + i, (etss->n_map - i) * sizeof(int)); + etss->map_table[i] = row; + etss->n_map++; + if ( !etm->frozen ) + e_table_model_changed(etm); +} + +ETableModel * +e_table_sorted_variable_new (ETableModel *source, int col, int ascending, GCompareFunc compare) +{ + ETableSortedVariable *etsv = gtk_type_new (E_TABLE_SORTED_VARIABLE_TYPE); + ETableSubsetVariable *etssv = E_TABLE_SUBSET_VARIABLE (etsv); + + if (e_table_subset_variable_construct (etssv, source) == NULL){ + gtk_object_destroy (GTK_OBJECT (etsv)); + return NULL; + } + + etsv->sort_col = col; + etsv->ascending = ascending; + etsv->compare = compare; + + etsv->table_model_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_changed", + GTK_SIGNAL_FUNC (etsv_proxy_model_changed), etsv); + etsv->table_model_row_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_row_changed", + GTK_SIGNAL_FUNC (etsv_proxy_model_row_changed), etsv); + etsv->table_model_cell_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_cell_changed", + GTK_SIGNAL_FUNC (etsv_proxy_model_cell_changed), etsv); + + return E_TABLE_MODEL(etsv); +} + +static void +etsv_proxy_model_changed (ETableModel *etm, ETableSortedVariable *etsv) +{ + if ( !E_TABLE_MODEL(etsv)->frozen ) { + /* FIXME: do_resort(); */ + } +} + +static void +etsv_proxy_model_row_changed (ETableModel *etm, int row, ETableSortedVariable *etsv) +{ + ETableSubsetVariable *etssv = E_TABLE_SUBSET_VARIABLE(etsv); + if ( !E_TABLE_MODEL(etsv)->frozen ) { + if(e_table_subset_variable_remove(etssv, row)) + e_table_subset_variable_add(etssv, row); + } +} + +static void +etsv_proxy_model_cell_changed (ETableModel *etm, int col, int row, ETableSortedVariable *etsv) +{ + ETableSubsetVariable *etssv = E_TABLE_SUBSET_VARIABLE(etsv); + if ( !E_TABLE_MODEL(etsv)->frozen ) { + if ( col == etsv->sort_col ) { + if(e_table_subset_variable_remove(etssv, row)) + e_table_subset_variable_add(etssv, row); + } + } +} + diff --git a/widgets/e-table/e-table-sorted-variable.h b/widgets/e-table/e-table-sorted-variable.h new file mode 100644 index 0000000000..cf188acd4a --- /dev/null +++ b/widgets/e-table/e-table-sorted-variable.h @@ -0,0 +1,34 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +#ifndef _E_TABLE_SORTED_VARIABLE_H_ +#define _E_TABLE_SORTED_VARIABLE_H_ + +#include +#include "e-table-model.h" +#include "e-table-subset-variable.h" + +#define E_TABLE_SORTED_VARIABLE_TYPE (e_table_sorted_variable_get_type ()) +#define E_TABLE_SORTED_VARIABLE(o) (GTK_CHECK_CAST ((o), E_TABLE_SORTED_VARIABLE_TYPE, ETableSortedVariable)) +#define E_TABLE_SORTED_VARIABLE_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TABLE_SORTED_VARIABLE_TYPE, ETableSortedVariableClass)) +#define E_IS_TABLE_SORTED_VARIABLE(o) (GTK_CHECK_TYPE ((o), E_TABLE_SORTED_VARIABLE_TYPE)) +#define E_IS_TABLE_SORTED_VARIABLE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_SORTED_VARIABLE_TYPE)) + +typedef struct { + ETableSubsetVariable base; + + short sort_col; + int ascending; + GCompareFunc compare; + + int table_model_changed_id; + int table_model_row_changed_id; + int table_model_cell_changed_id; +} ETableSortedVariable; + +typedef struct { + ETableSubsetVariableClass parent_class; +} ETableSortedVariableClass; + +GtkType e_table_sorted_variable_get_type (void); +ETableModel *e_table_sorted_variable_new (ETableModel *etm, int col, int ascending, GCompareFunc compare); + +#endif /* _E_TABLE_SORTED_VARIABLE_H_ */ diff --git a/widgets/e-table/e-table-sorted.c b/widgets/e-table/e-table-sorted.c index 16644a45b1..c754f4cff7 100644 --- a/widgets/e-table/e-table-sorted.c +++ b/widgets/e-table/e-table-sorted.c @@ -13,7 +13,7 @@ #define PARENT_TYPE E_TABLE_SUBSET_TYPE -static ETableModelClass *ets_parent_class; +static ETableSubsetClass *ets_parent_class; static void ets_class_init (GtkObjectClass *klass) diff --git a/widgets/e-table/e-table-subset-variable.c b/widgets/e-table/e-table-subset-variable.c index 76da03c44f..5a3e0f2ddf 100644 --- a/widgets/e-table/e-table-subset-variable.c +++ b/widgets/e-table/e-table-subset-variable.c @@ -14,16 +14,58 @@ #include "e-util/e-util.h" #include "e-table-subset-variable.h" +#define ETSSV_CLASS(e) ((ETableSubsetVariableClass *)((GtkObject *)e)->klass) + #define PARENT_TYPE E_TABLE_SUBSET_TYPE #define INCREMENT_AMOUNT 10 -static ETableModelClass *etssv_parent_class; +static ETableSubsetClass *etssv_parent_class; + +static void +etssv_add (ETableSubsetVariable *etssv, + gint row) +{ + ETableModel *etm = E_TABLE_MODEL(etssv); + ETableSubset *etss = E_TABLE_SUBSET(etssv); + + if ( etss->n_map + 1 > etssv->n_vals_allocated ) { + etss->map_table = g_realloc(etss->map_table, (etssv->n_vals_allocated + INCREMENT_AMOUNT) * sizeof(int)); + etssv->n_vals_allocated += INCREMENT_AMOUNT; + } + etss->map_table[etss->n_map++] = row; + if ( !etm->frozen ) + e_table_model_changed(etm); +} + +static gboolean +etssv_remove (ETableSubsetVariable *etssv, + gint row) +{ + ETableModel *etm = E_TABLE_MODEL(etssv); + ETableSubset *etss = E_TABLE_SUBSET(etssv); + int i; + + for ( i = 0; i < etss->n_map; i++ ) { + if (etss->map_table[i] == row) { + memmove(etss->map_table + i, etss->map_table + i + 1, (etss->n_map - i - 1) * sizeof(int)); + etss->n_map --; + if ( !etm->frozen ) + e_table_model_changed(etm); + return TRUE; + } + } + return FALSE; +} static void -etssv_class_init (GtkObjectClass *klass) +etssv_class_init (GtkObjectClass *object_class) { + ETableSubsetVariableClass *klass = E_TABLE_SUBSET_VARIABLE_CLASS(object_class); etssv_parent_class = gtk_type_class (PARENT_TYPE); + + klass->add = etssv_add; + klass->remove = etssv_remove; } E_MAKE_TYPE(e_table_subset_variable, "ETableSubsetVariable", ETableSubsetVariable, etssv_class_init, NULL, PARENT_TYPE); @@ -56,34 +98,24 @@ void e_table_subset_variable_add (ETableSubsetVariable *etssv, gint row) { - ETableModel *etm = E_TABLE_MODEL(etssv); - ETableSubset *etss = E_TABLE_SUBSET(etssv); - - if ( etss->n_map + 1 > etssv->n_vals_allocated ) - etss->map_table = g_realloc(etss->map_table, (etssv->n_vals_allocated + INCREMENT_AMOUNT) * sizeof(int)); - etss->map_table[etss->n_map++] = row; - if ( !etm->frozen ) - e_table_model_changed(etm); + g_return_if_fail (etssv != NULL); + g_return_if_fail (E_IS_TABLE_SUBSET_VARIABLE(etssv)); + + if (ETSSV_CLASS(etssv)->add) + ETSSV_CLASS (etssv)->add (etssv, row); } gboolean e_table_subset_variable_remove (ETableSubsetVariable *etssv, gint row) { - ETableModel *etm = E_TABLE_MODEL(etssv); - ETableSubset *etss = E_TABLE_SUBSET(etssv); - int i; - - for ( i = 0; i < etss->n_map; i++ ) { - if (etss->map_table[i] == row) { - memmove(etss->map_table + i, etss->map_table + i + 1, (etss->n_map - i - 1) * sizeof(int)); - etss->n_map --; - if ( !etm->frozen ) - e_table_model_changed(etm); - return TRUE; - } - } - return FALSE; + g_return_val_if_fail (etssv != NULL, FALSE); + g_return_val_if_fail (E_IS_TABLE_SUBSET_VARIABLE(etssv), FALSE); + + if (ETSSV_CLASS(etssv)->remove) + return ETSSV_CLASS (etssv)->remove (etssv, row); + else + return FALSE; } void diff --git a/widgets/e-table/e-table-subset-variable.h b/widgets/e-table/e-table-subset-variable.h index 9755fb2477..8ac0af0382 100644 --- a/widgets/e-table/e-table-subset-variable.h +++ b/widgets/e-table/e-table-subset-variable.h @@ -19,6 +19,11 @@ typedef struct { typedef struct { ETableSubsetClass parent_class; + + void (*add) (ETableSubsetVariable *ets, + gint row); + gboolean (*remove) (ETableSubsetVariable *ets, + gint row); } ETableSubsetVariableClass; GtkType e_table_subset_variable_get_type (void); diff --git a/widgets/e-table/e-table-subset.c b/widgets/e-table/e-table-subset.c index a09d221980..b4473b87ef 100644 --- a/widgets/e-table/e-table-subset.c +++ b/widgets/e-table/e-table-subset.c @@ -25,6 +25,17 @@ etss_destroy (GtkObject *object) if (etss->source) gtk_object_unref (GTK_OBJECT (etss->source)); + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etss->table_model_changed_id); + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etss->table_model_row_changed_id); + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etss->table_model_cell_changed_id); + + etss->table_model_changed_id = 0; + etss->table_model_row_changed_id = 0; + etss->table_model_cell_changed_id = 0; + if (etss->map_table) free (etss->map_table); @@ -71,6 +82,22 @@ etss_is_cell_editable (ETableModel *etm, int col, int row) return e_table_model_is_cell_editable (etss->source, col, etss->map_table [row]); } +static void * +etss_duplicate_value (ETableModel *etm, int col, const void *value) +{ + ETableSubset *etss = (ETableSubset *)etm; + + return e_table_model_duplicate_value (etss->source, col, value); +} + +static void +etss_free_value (ETableModel *etm, int col, void *value) +{ + ETableSubset *etss = (ETableSubset *)etm; + + e_table_model_free_value (etss->source, col, value); +} + static void etss_thaw (ETableModel *etm) { @@ -91,6 +118,8 @@ etss_class_init (GtkObjectClass *klass) table_class->value_at = etss_value_at; table_class->set_value_at = etss_set_value_at; table_class->is_cell_editable = etss_is_cell_editable; + table_class->duplicate_value = etss_duplicate_value; + table_class->free_value = etss_free_value; table_class->thaw = etss_thaw; } @@ -155,12 +184,12 @@ e_table_subset_construct (ETableSubset *etss, ETableModel *source, int nvals) for (i = 0; i < nvals; i++) etss->map_table [i] = i; - gtk_signal_connect (GTK_OBJECT (source), "model_changed", - GTK_SIGNAL_FUNC (etss_proxy_model_changed), etss); - gtk_signal_connect (GTK_OBJECT (source), "model_row_changed", - GTK_SIGNAL_FUNC (etss_proxy_model_row_changed), etss); - gtk_signal_connect (GTK_OBJECT (source), "model_cell_changed", - GTK_SIGNAL_FUNC (etss_proxy_model_cell_changed), etss); + etss->table_model_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_changed", + GTK_SIGNAL_FUNC (etss_proxy_model_changed), etss); + etss->table_model_row_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_row_changed", + GTK_SIGNAL_FUNC (etss_proxy_model_row_changed), etss); + etss->table_model_cell_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_cell_changed", + GTK_SIGNAL_FUNC (etss_proxy_model_cell_changed), etss); return E_TABLE_MODEL (etss); } diff --git a/widgets/e-table/e-table-subset.h b/widgets/e-table/e-table-subset.h index d8af1696f5..074120a410 100644 --- a/widgets/e-table/e-table-subset.h +++ b/widgets/e-table/e-table-subset.h @@ -17,6 +17,10 @@ typedef struct { ETableModel *source; int n_map; int *map_table; + + int table_model_changed_id; + int table_model_row_changed_id; + int table_model_cell_changed_id; } ETableSubset; typedef struct { diff --git a/widgets/e-table/e-table.c b/widgets/e-table/e-table.c index 551ef52227..e508e24e02 100644 --- a/widgets/e-table/e-table.c +++ b/widgets/e-table/e-table.c @@ -34,6 +34,8 @@ static GtkObjectClass *e_table_parent_class; +static void e_table_fill_table (ETable *e_table, ETableModel *model); + static void et_destroy (GtkObject *object) { @@ -42,6 +44,20 @@ et_destroy (GtkObject *object) gtk_object_unref (GTK_OBJECT (et->model)); gtk_object_unref (GTK_OBJECT (et->full_header)); gtk_object_unref (GTK_OBJECT (et->header)); + gtk_widget_destroy (GTK_WIDGET (et->header_canvas)); + gtk_widget_destroy (GTK_WIDGET (et->table_canvas)); + + gtk_signal_disconnect (GTK_OBJECT (et->model), + et->table_model_change_id); + gtk_signal_disconnect (GTK_OBJECT (et->model), + et->table_row_change_id); + gtk_signal_disconnect (GTK_OBJECT (et->model), + et->table_cell_change_id); + + if (et->rebuild_idle_id) { + g_source_remove(et->rebuild_idle_id); + et->rebuild_idle_id = 0; + } (*e_table_parent_class->destroy)(object); } @@ -54,6 +70,11 @@ e_table_init (GtkObject *object) e_table->draw_grid = 1; e_table->draw_focus = 1; e_table->spreadsheet = 1; + + e_table->need_rebuild = 0; + e_table->need_row_changes = 0; + e_table->row_changes_list = NULL; + e_table->rebuild_idle_id = 0; } static ETableHeader * @@ -527,6 +548,72 @@ table_canvas_size_allocate (GtkWidget *widget, GtkAllocation *alloc, ETable *e_t NULL); } +static void +change_row (gpointer key, gpointer value, gpointer data) +{ + ETable *et = E_TABLE(data); + gint row = GPOINTER_TO_INT(key); + if ( e_table_group_remove(et->group, row) ) { + e_table_group_add(et->group, row); + } +} + +static gboolean +changed_idle (gpointer data) +{ + ETable *et = E_TABLE(data); + if ( et->need_rebuild ) { + gtk_object_destroy( GTK_OBJECT(et->group ) ); + et->group = e_table_group_new(GNOME_CANVAS_GROUP(et->table_canvas->root), + et->full_header, + et->header, + et->model, + e_xml_get_child_by_name(xmlDocGetRootElement(et->specification), "grouping")->childs); + e_table_fill_table(et, et->model); + } else if (et->need_row_changes) { + g_hash_table_foreach(et->row_changes_list, change_row, et); + } + et->need_rebuild = 0; + et->need_row_changes = 0; + if (et->row_changes_list) + g_hash_table_destroy(et->row_changes_list); + et->row_changes_list = NULL; + et->rebuild_idle_id = 0; + return FALSE; +} + +static void +et_table_model_changed (ETableModel *model, ETable *et) +{ + et->need_rebuild = TRUE; + if ( !et->rebuild_idle_id ) { + et->rebuild_idle_id = g_idle_add(changed_idle, et); + } +} + +static void +et_table_row_changed (ETableModel *table_model, int row, ETable *et) +{ + if ( !et->need_rebuild ) { + if (!et->need_row_changes) { + et->need_row_changes = 1; + et->row_changes_list = g_hash_table_new (g_direct_hash, g_direct_equal); + } + if (!g_hash_table_lookup(et->row_changes_list, GINT_TO_POINTER(row))) { + g_hash_table_insert(et->row_changes_list, GINT_TO_POINTER(row), GINT_TO_POINTER(row + 1)); + } + } + if ( !et->rebuild_idle_id ) { + et->rebuild_idle_id = g_idle_add(changed_idle, et); + } +} + +static void +et_table_cell_changed (ETableModel *table_model, int view_col, int row, ETable *et) +{ + et_table_row_changed(table_model, row, et); +} + static void e_table_setup_table (ETable *e_table, ETableHeader *full_header, ETableHeader *header, ETableModel *model, xmlNode *xml_grouping) { @@ -546,6 +633,17 @@ e_table_setup_table (ETable *e_table, ETableHeader *full_header, ETableHeader *h model, xml_grouping->childs); + e_table->table_model_change_id = gtk_signal_connect ( + GTK_OBJECT (model), "model_changed", + GTK_SIGNAL_FUNC (et_table_model_changed), e_table); + + e_table->table_row_change_id = gtk_signal_connect ( + GTK_OBJECT (model), "model_row_changed", + GTK_SIGNAL_FUNC (et_table_row_changed), e_table); + + e_table->table_cell_change_id = gtk_signal_connect ( + GTK_OBJECT (model), "model_cell_changed", + GTK_SIGNAL_FUNC (et_table_cell_changed), e_table); } static void diff --git a/widgets/e-table/e-table.h b/widgets/e-table/e-table.h index a372d8042c..841013c09a 100644 --- a/widgets/e-table/e-table.h +++ b/widgets/e-table/e-table.h @@ -26,6 +26,10 @@ typedef struct { ETableGroup *group; + int table_model_change_id; + int table_row_change_id; + int table_cell_change_id; + GnomeCanvas *header_canvas, *table_canvas; GnomeCanvasItem *header_item, *root; @@ -35,6 +39,12 @@ typedef struct { guint draw_grid:1; guint draw_focus:1; guint spreadsheet:1; + + guint need_rebuild:1; + guint need_row_changes:1; + + GHashTable *row_changes_list; + gint rebuild_idle_id; } ETable; typedef struct { diff --git a/widgets/e-table/test-check.c b/widgets/e-table/test-check.c index a6a59788ad..7894898255 100644 --- a/widgets/e-table/test-check.c +++ b/widgets/e-table/test-check.c @@ -14,6 +14,7 @@ #include "e-table-item.h" #include "e-util/e-cursors.h" #include "e-util/e-canvas-utils.h" +#include "e-util/e-util.h" #include "e-cell-text.h" #include "e-cell-checkbox.h" @@ -79,6 +80,24 @@ is_cell_editable (ETableModel *etc, int col, int row, void *data) return TRUE; } +static void * +duplicate_value (ETableModel *etc, int col, const void *value, void *data) +{ + if (col == 0){ + return (void *) value; + } else { + return g_strdup(value); + } +} + +static void +free_value (ETableModel *etc, int col, void *value, void *data) +{ + if (col != 0){ + g_free(value); + } +} + static void thaw (ETableModel *etc, void *data) { @@ -107,7 +126,8 @@ check_test (void) e_table_model = e_table_simple_new ( col_count, row_count, value_at, - set_value_at, is_cell_editable, thaw, NULL); + set_value_at, is_cell_editable, + duplicate_value, free_value, thaw, NULL); /* * Header @@ -118,11 +138,11 @@ check_test (void) cell_image_check = e_cell_checkbox_new (); pixbuf = gdk_pixbuf_new_from_file("clip.png"); - col_0 = e_table_col_new_with_pixbuf (0, pixbuf, 18, 18, cell_image_check, g_int_equal, TRUE); + col_0 = e_table_col_new_with_pixbuf (0, pixbuf, 18, 18, cell_image_check, g_int_compare, TRUE); gdk_pixbuf_unref(pixbuf); e_table_header_add_column (e_table_header, col_0, 0); - col_1 = e_table_col_new (1, "Item Name", 180, 20, cell_left_just, g_str_equal, TRUE); + col_1 = e_table_col_new (1, "Item Name", 180, 20, cell_left_just, g_str_compare, TRUE); e_table_header_add_column (e_table_header, col_1, 1); e_table_col_set_arrow ( col_1, E_TABLE_COL_ARROW_DOWN ); diff --git a/widgets/e-table/test-cols.c b/widgets/e-table/test-cols.c index adc9ed6c20..d65b9945b7 100644 --- a/widgets/e-table/test-cols.c +++ b/widgets/e-table/test-cols.c @@ -10,6 +10,7 @@ #include #include "e-util/e-canvas-utils.h" #include "e-util/e-cursors.h" +#include "e-util/e-util.h" #include "e-table-simple.h" #include "e-table-header.h" #include "e-table-header-item.h" @@ -79,6 +80,24 @@ is_cell_editable (ETableModel *etc, int col, int row, void *data) return TRUE; } +static void * +duplicate_value (ETableModel *etc, int col, const void *value, void *data) +{ + if (col == 0){ + return (void *)value; + } else { + return g_strdup(value); + } +} + +static void +free_value (ETableModel *etc, int col, void *value, void *data) +{ + if (col != 0){ + g_free(value); + } +} + static void set_canvas_size (GnomeCanvas *canvas, GtkAllocation *alloc) { @@ -106,7 +125,9 @@ multi_cols_test (void) e_table_model = e_table_simple_new ( col_count, row_count, value_at, - set_value_at, is_cell_editable, thaw, NULL); + set_value_at, is_cell_editable, + duplicate_value, free_value, + thaw, NULL); /* * Header @@ -131,10 +152,10 @@ multi_cols_test (void) g_free (images); } - col_1 = e_table_col_new (1, "Item Name", 180, 20, cell_left_just, g_str_equal, TRUE); + col_1 = e_table_col_new (1, "Item Name", 180, 20, cell_left_just, g_str_compare, TRUE); e_table_header_add_column (e_table_header, col_1, 0); - col_0 = e_table_col_new (0, "A", 48, 48, cell_image_toggle, g_int_equal, TRUE); + col_0 = e_table_col_new (0, "A", 48, 48, cell_image_toggle, g_int_compare, TRUE); e_table_header_add_column (e_table_header, col_0, 1); /* diff --git a/widgets/e-table/test-table.c b/widgets/e-table/test-table.c index 1bd50e1479..0fdf32fcbe 100644 --- a/widgets/e-table/test-table.c +++ b/widgets/e-table/test-table.c @@ -176,6 +176,18 @@ is_cell_editable (ETableModel *etc, int col, int row, void *data) return TRUE; } +static void * +duplicate_value (ETableModel *etc, int col, const void *value, void *data) +{ + return g_strdup(value); +} + +static void +free_value (ETableModel *etc, int col, void *value, void *data) +{ + g_free(value); +} + static void thaw (ETableModel *etc, void *data) { @@ -205,7 +217,8 @@ table_browser_test (void) */ e_table_model = e_table_simple_new ( col_count, row_count, value_at, - set_value_at, is_cell_editable, thaw, NULL); + set_value_at, is_cell_editable, + duplicate_value, free_value, thaw, NULL); /* * Header @@ -217,7 +230,7 @@ table_browser_test (void) ETableCol *ecol = e_table_col_new ( i, column_labels [i], 80, 20, cell_left_just, - g_str_equal, TRUE); + g_str_compare, TRUE); e_table_header_add_column (e_table_header, ecol, i); } @@ -263,7 +276,6 @@ static void do_e_table_demo (const char *spec) { GtkWidget *e_table, *window, *frame; - ETableModel *e_table_model; ECell *cell_left_just; ETableHeader *full_header; int i; @@ -271,9 +283,14 @@ do_e_table_demo (const char *spec) /* * Data model */ - e_table_model = e_table_simple_new ( - col_count, row_count, value_at, - set_value_at, is_cell_editable, thaw, NULL); + static ETableModel *e_table_model = NULL; + + if ( e_table_model == NULL ) + e_table_model = + e_table_simple_new (col_count, row_count, value_at, + set_value_at, is_cell_editable, + duplicate_value, free_value, + thaw, NULL); full_header = e_table_header_new (); cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT, TRUE); @@ -282,7 +299,7 @@ do_e_table_demo (const char *spec) ETableCol *ecol = e_table_col_new ( i, column_labels [i], 80, 20, cell_left_just, - g_str_equal, TRUE); + g_str_compare, TRUE); e_table_header_add_column (full_header, ecol, i); } @@ -306,9 +323,9 @@ e_table_test (void) load_data (); if (1){/*getenv ("DO")){*/ - do_e_table_demo (" 0 1 2 3 4 "); - do_e_table_demo (" 0 0 0 0 0 1 2 3 4 "); + do_e_table_demo (" 0 1 2 3 4 "); + do_e_table_demo (" 0 0 1 2 3 4 "); } - do_e_table_demo (" 0 1 2 3 4 "); - do_e_table_demo (" 0 1 2 3 4 "); + do_e_table_demo (" 0 1 2 3 4 "); + do_e_table_demo (" 0 1 2 3 4 "); } diff --git a/widgets/table/e-table-group-container.c b/widgets/table/e-table-group-container.c index 634d7934ef..4b30f6af29 100644 --- a/widgets/table/e-table-group-container.c +++ b/widgets/table/e-table-group-container.c @@ -59,15 +59,42 @@ typedef struct { gint count; } ETableGroupContainerChildNode; +static void +e_table_group_container_child_node_free(ETableGroupContainer *etgc, ETableGroupContainerChildNode *child_node) +{ + ETableGroup *etg = E_TABLE_GROUP(etgc); + ETableGroup *child = child_node->child; + gtk_object_destroy(GTK_OBJECT(child)); + e_table_model_free_value(etg->model, etgc->ecol->col_idx, child_node->key); + gtk_object_destroy(GTK_OBJECT(child_node->text)); + gtk_object_destroy(GTK_OBJECT(child_node->rect)); +} + +static void +e_table_group_container_list_free(ETableGroupContainer *etgc) +{ + ETableGroupContainerChildNode *child_node; + GList *list; + for ( list = etgc->children; list; list = g_list_next(list) ) { + child_node = (ETableGroupContainerChildNode *) list->data; + e_table_group_container_child_node_free(etgc, child_node); + } + g_list_free(etgc->children); +} + static void etgc_destroy (GtkObject *object) { ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (object); gdk_font_unref(etgc->font); + gtk_object_unref(GTK_OBJECT(etgc->ecol)); + gtk_object_destroy(GTK_OBJECT(etgc->rect)); + e_table_group_container_list_free(etgc); GTK_OBJECT_CLASS (etgc_parent_class)->destroy (object); } + #if 0 void e_table_group_add (ETableGroup *etg, GnomeCanvasItem *item) @@ -168,11 +195,13 @@ void e_table_group_container_construct (GnomeCanvasGroup *parent, ETableGroupContainer *etgc, ETableHeader *full_header, ETableHeader *header, - ETableModel *model, ETableCol *ecol, xmlNode *child_rules) + ETableModel *model, ETableCol *ecol, int ascending, xmlNode *child_rules) { e_table_group_construct (parent, E_TABLE_GROUP (etgc), full_header, header, model); etgc->ecol = ecol; + gtk_object_ref(GTK_OBJECT(etgc->ecol)); etgc->child_rules = child_rules; + etgc->ascending = ascending; etgc->font = gdk_font_load ("lucidasans-10"); #if 0 @@ -217,7 +246,7 @@ e_table_group_container_construct (GnomeCanvasGroup *parent, ETableGroupContaine ETableGroup * e_table_group_container_new (GnomeCanvasGroup *parent, ETableHeader *full_header, ETableHeader *header, - ETableModel *model, ETableCol *ecol, xmlNode *child_rules) + ETableModel *model, ETableCol *ecol, int ascending, xmlNode *child_rules) { ETableGroupContainer *etgc; @@ -227,7 +256,7 @@ e_table_group_container_new (GnomeCanvasGroup *parent, ETableHeader *full_ etgc = gtk_type_new (e_table_group_container_get_type ()); e_table_group_container_construct (parent, etgc, full_header, header, - model, ecol, child_rules); + model, ecol, ascending, child_rules); return E_TABLE_GROUP (etgc); } @@ -498,15 +527,21 @@ static void etgc_add (ETableGroup *etg, gint row) GList *list = etgc->children; ETableGroup *child; ETableGroupContainerChildNode *child_node; - for ( ; list; list = g_list_next(list) ) { + int i = 0; + for ( ; list; list = g_list_next(list), i++ ) { + int comp_val; child_node = (ETableGroupContainerChildNode *)(list->data); - if ( (*comp)(child_node->key, val) ) { + comp_val = (*comp)(child_node->key, val); + if ( comp_val == 0 ) { child = child_node->child; child_node->count ++; e_table_group_add(child, row); compute_text(etgc, child_node); return; } + if ( (comp_val > 0 && etgc->ascending) || + (comp_val < 0 && (!etgc->ascending)) ) + break; } child_node = g_new(ETableGroupContainerChildNode, 1); child_node->rect = gnome_canvas_item_new(GNOME_CANVAS_GROUP(etgc), @@ -524,13 +559,17 @@ static void etgc_add (ETableGroup *etg, gint row) NULL); child = e_table_group_new(GNOME_CANVAS_GROUP(etgc), etg->full_header, etg->header, etg->model, etgc->child_rules); child_node->child = child; - child_node->key = val; + child_node->key = e_table_model_duplicate_value(etg->model, etgc->ecol->col_idx, val); gtk_signal_connect(GTK_OBJECT(child), "resize", etgc_child_resize, etgc); child_node->count = 1; e_table_group_add(child, row); - etgc->children = g_list_append(etgc->children, child_node); + if ( list ) { + etgc->children = g_list_insert(etgc->children, child_node, i); + } + else + etgc->children = g_list_append(etgc->children, child_node); compute_text(etgc, child_node); etgc_queue_reposition(E_TABLE_GROUP_CONTAINER(etg)); } @@ -545,8 +584,7 @@ static gboolean etgc_remove (ETableGroup *etg, gint row) if ( e_table_group_remove(child, row) ) { child_node->count --; if ( child_node->count == 0 ) { - gtk_object_unref(GTK_OBJECT(child_node->text)); - gtk_object_unref(GTK_OBJECT(child)); + e_table_group_container_child_node_free(etgc, child_node); etgc->children = g_list_remove(etgc->children, child_node); g_free(child_node); } else { diff --git a/widgets/table/e-table-group-container.h b/widgets/table/e-table-group-container.h index 4942f9e695..2234e77ac1 100644 --- a/widgets/table/e-table-group-container.h +++ b/widgets/table/e-table-group-container.h @@ -20,6 +20,7 @@ typedef struct { * The ETableCol used to group this set */ ETableCol *ecol; + gint ascending; /* * List of ETableGroups we stack @@ -55,11 +56,11 @@ typedef struct { } ETableGroupContainerClass; ETableGroup *e_table_group_container_new (GnomeCanvasGroup *parent, ETableHeader *full_header, ETableHeader *header, - ETableModel *model, ETableCol *ecol, xmlNode *child_rules); + ETableModel *model, ETableCol *ecol, int ascending, xmlNode *child_rules); void e_table_group_container_construct (GnomeCanvasGroup *parent, ETableGroupContainer *etgc, ETableHeader *full_header, ETableHeader *header, - ETableModel *model, ETableCol *ecol, xmlNode *child_rules); + ETableModel *model, ETableCol *ecol, int ascending, xmlNode *child_rules); GtkType e_table_group_container_get_type (void); diff --git a/widgets/table/e-table-group-leaf.c b/widgets/table/e-table-group-leaf.c index ba73ad9886..2e939453d7 100644 --- a/widgets/table/e-table-group-leaf.c +++ b/widgets/table/e-table-group-leaf.c @@ -36,23 +36,31 @@ static void etgl_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); static void etgl_destroy (GtkObject *object) { - GTK_OBJECT_CLASS (etgl_parent_class)->destroy (object); + ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF(object); + gtk_object_unref(GTK_OBJECT(etgl->subset)); + gtk_object_destroy(GTK_OBJECT(etgl->item)); + if ( GTK_OBJECT_CLASS (etgl_parent_class)->destroy ) + GTK_OBJECT_CLASS (etgl_parent_class)->destroy (object); } static void e_table_group_leaf_construct (GnomeCanvasGroup *parent, ETableGroupLeaf *etgl, ETableHeader *full_header, ETableHeader *header, - ETableModel *model) + ETableModel *model, + int col, + int ascending) { + etgl->subset = E_TABLE_SUBSET_VARIABLE(e_table_sorted_variable_new(model, col, ascending, e_table_header_get_column(full_header, col)->compare)); e_table_group_construct (parent, E_TABLE_GROUP (etgl), full_header, header, model); - etgl->subset = E_TABLE_SUBSET_VARIABLE(e_table_subset_variable_new(model)); } ETableGroup * e_table_group_leaf_new (GnomeCanvasGroup *parent, ETableHeader *full_header, ETableHeader *header, - ETableModel *model) + ETableModel *model, + int col, + int ascending) { ETableGroupLeaf *etgl; @@ -61,7 +69,7 @@ e_table_group_leaf_new (GnomeCanvasGroup *parent, ETableHeader *full_heade etgl = gtk_type_new (e_table_group_leaf_get_type ()); e_table_group_leaf_construct (parent, etgl, full_header, - header, model); + header, model, col, ascending); return E_TABLE_GROUP (etgl); } diff --git a/widgets/table/e-table-group-leaf.h b/widgets/table/e-table-group-leaf.h index 372bf4cc70..6ffd9066d1 100644 --- a/widgets/table/e-table-group-leaf.h +++ b/widgets/table/e-table-group-leaf.h @@ -4,7 +4,7 @@ #include #include "e-table-group.h" -#include "e-table-subset-variable.h" +#include "e-table-sorted-variable.h" #include "e-table-item.h" #define E_TABLE_GROUP_LEAF_TYPE (e_table_group_leaf_get_type ()) @@ -33,7 +33,9 @@ typedef struct { ETableGroup *e_table_group_leaf_new (GnomeCanvasGroup *parent, ETableHeader *full_header, ETableHeader *header, - ETableModel *model); + ETableModel *model, + int col, + int ascending); GtkType e_table_group_leaf_get_type (void); #endif /* _E_TABLE_GROUP_LEAF_H_ */ diff --git a/widgets/table/e-table-group.c b/widgets/table/e-table-group.c index 1f4e2037cd..6ae8a25db7 100644 --- a/widgets/table/e-table-group.c +++ b/widgets/table/e-table-group.c @@ -17,6 +17,7 @@ #include #include #include "e-util/e-util.h" +#include "e-util/e-xml-utils.h" #define TITLE_HEIGHT 16 #define GROUP_INDENT 10 @@ -45,7 +46,7 @@ enum { static void etg_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); static void etg_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); static gboolean etg_get_focus (ETableGroup *etg); - +static void etg_destroy (GtkObject *object); #if 0 GnomeCanvasItem * e_table_group_new (GnomeCanvasGroup *parent, ETableCol *ecol, @@ -64,6 +65,17 @@ e_table_group_new (GnomeCanvasGroup *parent, ETableCol *ecol, } #endif +static void +etg_destroy (GtkObject *object) +{ + ETableGroup *etg = E_TABLE_GROUP(object); + gtk_object_unref(GTK_OBJECT(etg->header)); + gtk_object_unref(GTK_OBJECT(etg->full_header)); + gtk_object_unref(GTK_OBJECT(etg->model)); + if ( GTK_OBJECT_CLASS (etg_parent_class)->destroy ) + GTK_OBJECT_CLASS (etg_parent_class)->destroy (object); +} + ETableGroup * e_table_group_new (GnomeCanvasGroup *parent, ETableHeader *full_header, @@ -71,17 +83,22 @@ e_table_group_new (GnomeCanvasGroup *parent, ETableModel *model, xmlNode *rules) { + int column; + int ascending; + g_return_val_if_fail (model != NULL, NULL); - + + column = e_xml_get_integer_prop_by_name(rules, "column"); + ascending = e_xml_get_integer_prop_by_name(rules, "ascending"); + if(rules && !xmlStrcmp(rules->name, "group")) { - gint col_idx = atoi(xmlGetProp(rules, "column")); ETableCol *col; - if ( col_idx > e_table_header_count(full_header) ) - return e_table_group_leaf_new(parent, full_header, header, model); - col = e_table_header_get_columns(full_header)[col_idx]; - return e_table_group_container_new(parent, full_header, header, model, col, rules->childs); + if ( column > e_table_header_count(full_header) ) + return e_table_group_leaf_new(parent, full_header, header, model, column, ascending); + col = e_table_header_get_columns(full_header)[column]; + return e_table_group_container_new(parent, full_header, header, model, col, ascending, rules->childs); } else { - return e_table_group_leaf_new(parent, full_header, header, model); + return e_table_group_leaf_new(parent, full_header, header, model, column, ascending); } return NULL; } @@ -93,10 +110,13 @@ e_table_group_construct (GnomeCanvasGroup *parent, ETableHeader *header, ETableModel *model) { - gnome_canvas_item_constructv (GNOME_CANVAS_ITEM (etg), parent, 0, NULL); etg->full_header = full_header; + gtk_object_ref(GTK_OBJECT(etg->full_header)); etg->header = header; + gtk_object_ref(GTK_OBJECT(etg->header)); etg->model = model; + gtk_object_ref(GTK_OBJECT(etg->model)); + gnome_canvas_item_constructv (GNOME_CANVAS_ITEM (etg), parent, 0, NULL); } void @@ -311,6 +331,7 @@ etg_class_init (GtkObjectClass *object_class) object_class->set_arg = etg_set_arg; object_class->get_arg = etg_get_arg; + object_class->destroy = etg_destroy; item_class->event = etg_event; diff --git a/widgets/table/e-table-item.c b/widgets/table/e-table-item.c index 286b1a8352..a7d5573fad 100644 --- a/widgets/table/e-table-item.c +++ b/widgets/table/e-table-item.c @@ -307,6 +307,10 @@ static void eti_table_model_changed (ETableModel *table_model, ETableItem *eti) { eti->rows = e_table_model_row_count (eti->table_model); + + if (eti->focused_row > eti->rows - 1) { + eti->focused_row = eti->rows - 1; + } if (eti->cell_views) eti_compute_height (eti); diff --git a/widgets/table/e-table-model.c b/widgets/table/e-table-model.c index e84e6da4d3..ef14b98018 100644 --- a/widgets/table/e-table-model.c +++ b/widgets/table/e-table-model.c @@ -13,6 +13,9 @@ #define ETM_CLASS(e) ((ETableModelClass *)((GtkObject *)e)->klass) +#define PARENT_TYPE gtk_object_get_type(); + + static GtkObjectClass *e_table_model_parent_class; enum { @@ -80,6 +83,28 @@ e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row) return ETM_CLASS (e_table_model)->is_cell_editable (e_table_model, col, row); } +void * +e_table_model_duplicate_value (ETableModel *e_table_model, int col, const void *value) +{ + g_return_val_if_fail (e_table_model != NULL, NULL); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL); + + if (ETM_CLASS (e_table_model)->duplicate_value) + return ETM_CLASS (e_table_model)->duplicate_value (e_table_model, col, value); + else + return NULL; +} + +void +e_table_model_free_value (ETableModel *e_table_model, int col, void *value) +{ + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); + + if (ETM_CLASS (e_table_model)->free_value) + ETM_CLASS (e_table_model)->free_value (e_table_model, col, value); +} + static void e_table_model_destroy (GtkObject *object) { @@ -121,27 +146,30 @@ e_table_model_class_init (GtkObjectClass *object_class) gtk_object_class_add_signals (object_class, e_table_model_signals, LAST_SIGNAL); } -GtkType + +guint e_table_model_get_type (void) { - static GtkType type = 0; - - if (!type){ - GtkTypeInfo info = { - "ETableModel", - sizeof (ETableModel), - sizeof (ETableModelClass), - (GtkClassInitFunc) e_table_model_class_init, - (GtkObjectInitFunc) NULL, - NULL, /* reserved 1 */ - NULL, /* reserved 2 */ - (GtkClassInitFunc) NULL - }; - - type = gtk_type_unique (gtk_object_get_type (), &info); - } - - return type; + static guint type = 0; + + if (!type) + { + GtkTypeInfo info = + { + "ETableModle", + sizeof (ETableModel), + sizeof (ETableModelClass), + (GtkClassInitFunc) e_table_model_class_init, + NULL, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + type = gtk_type_unique (gtk_object_get_type(), &info); + } + + return type; } void diff --git a/widgets/table/e-table-model.h b/widgets/table/e-table-model.h index 9f2dbbf87c..ceca8e348f 100644 --- a/widgets/table/e-table-model.h +++ b/widgets/table/e-table-model.h @@ -27,6 +27,10 @@ typedef struct { void *(*value_at) (ETableModel *etm, int col, int row); void (*set_value_at) (ETableModel *etm, int col, int row, const void *value); gboolean (*is_cell_editable) (ETableModel *etm, int col, int row); + + void *(*duplicate_value) (ETableModel *etm, int col, const void *value); + void (*free_value) (ETableModel *etm, int col, void *value); + void (*thaw) (ETableModel *etm); /* * Signals @@ -48,9 +52,12 @@ int e_table_model_column_count (ETableModel *e_table_model); const char *e_table_model_column_name (ETableModel *e_table_model, int col); int e_table_model_row_count (ETableModel *e_table_model); void *e_table_model_value_at (ETableModel *e_table_model, int col, int row); -void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *data); +void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *value); gboolean e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row); +void *e_table_model_duplicate_value (ETableModel *e_table_model, int col, const void *value); +void e_table_model_free_value (ETableModel *e_table_model, int col, void *value); + void e_table_model_freeze (ETableModel *e_table_model); void e_table_model_thaw (ETableModel *e_table_model); diff --git a/widgets/table/e-table-simple.c b/widgets/table/e-table-simple.c index 1f64d08f39..e90abfcc4f 100644 --- a/widgets/table/e-table-simple.c +++ b/widgets/table/e-table-simple.c @@ -55,6 +55,22 @@ simple_is_cell_editable (ETableModel *etm, int col, int row) return simple->is_cell_editable (etm, col, row, simple->data); } +static void * +simple_duplicate_value (ETableModel *etm, int col, const void *value) +{ + ETableSimple *simple = (ETableSimple *)etm; + + return simple->duplicate_value (etm, col, value, simple->data); +} + +static void +simple_free_value (ETableModel *etm, int col, void *value) +{ + ETableSimple *simple = (ETableSimple *)etm; + + simple->free_value (etm, col, value, simple->data); +} + static void simple_thaw (ETableModel *etm) { @@ -73,6 +89,8 @@ e_table_simple_class_init (GtkObjectClass *object_class) model_class->value_at = simple_value_at; model_class->set_value_at = simple_set_value_at; model_class->is_cell_editable = simple_is_cell_editable; + model_class->duplicate_value = simple_duplicate_value; + model_class->free_value = simple_free_value; model_class->thaw = simple_thaw; } @@ -105,6 +123,8 @@ e_table_simple_new (ETableSimpleColumnCountFn col_count, ETableSimpleValueAtFn value_at, ETableSimpleSetValueAtFn set_value_at, ETableSimpleIsCellEditableFn is_cell_editable, + ETableSimpleDuplicateValueFn duplicate_value, + ETableSimpleFreeValueFn free_value, ETableSimpleThawFn thaw, void *data) { @@ -118,6 +138,8 @@ e_table_simple_new (ETableSimpleColumnCountFn col_count, et->set_value_at = set_value_at; et->is_cell_editable = is_cell_editable; et->thaw = thaw; + et->duplicate_value = duplicate_value; + et->free_value = free_value; et->data = data; return (ETableModel *) et; diff --git a/widgets/table/e-table-simple.h b/widgets/table/e-table-simple.h index a3164eefc0..51134f45aa 100644 --- a/widgets/table/e-table-simple.h +++ b/widgets/table/e-table-simple.h @@ -9,6 +9,8 @@ typedef int (*ETableSimpleRowCountFn) (ETableModel *etm, void *dat typedef void *(*ETableSimpleValueAtFn) (ETableModel *etm, int col, int row, void *data); typedef void (*ETableSimpleSetValueAtFn) (ETableModel *etm, int col, int row, const void *val, void *data); typedef gboolean (*ETableSimpleIsCellEditableFn) (ETableModel *etm, int col, int row, void *data); +typedef void *(*ETableSimpleDuplicateValueFn) (ETableModel *etm, int col, const void *val, void *data); +typedef void (*ETableSimpleFreeValueFn) (ETableModel *etm, int col, void *val, void *data); typedef void (*ETableSimpleThawFn) (ETableModel *etm, void *data); typedef struct { @@ -19,6 +21,8 @@ typedef struct { ETableSimpleValueAtFn value_at; ETableSimpleSetValueAtFn set_value_at; ETableSimpleIsCellEditableFn is_cell_editable; + ETableSimpleDuplicateValueFn duplicate_value; + ETableSimpleFreeValueFn free_value; ETableSimpleThawFn thaw; void *data; } ETableSimple; @@ -34,6 +38,8 @@ ETableModel *e_table_simple_new (ETableSimpleColumnCountFn col_count, ETableSimpleValueAtFn value_at, ETableSimpleSetValueAtFn set_value_at, ETableSimpleIsCellEditableFn is_cell_editable, + ETableSimpleDuplicateValueFn duplicate_value, + ETableSimpleFreeValueFn free_value, ETableSimpleThawFn thaw, void *data); diff --git a/widgets/table/e-table-sorted-variable.c b/widgets/table/e-table-sorted-variable.c new file mode 100644 index 0000000000..478038fdb7 --- /dev/null +++ b/widgets/table/e-table-sorted-variable.c @@ -0,0 +1,148 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * E-table-sorted.c: Implements a table that sorts another table + * + * Author: + * Miguel de Icaza (miguel@gnu.org) + * + * (C) 1999 Helix Code, Inc. + */ +#include +#include +#include +#include +#include "e-util/e-util.h" +#include "e-table-sorted-variable.h" + +#define PARENT_TYPE E_TABLE_SUBSET_VARIABLE_TYPE + +#define INCREMENT_AMOUNT 10 + +static ETableSubsetVariableClass *etsv_parent_class; + +static void etsv_proxy_model_changed (ETableModel *etm, ETableSortedVariable *etsv); +static void etsv_proxy_model_row_changed (ETableModel *etm, int row, ETableSortedVariable *etsv); +static void etsv_proxy_model_cell_changed (ETableModel *etm, int col, int row, ETableSortedVariable *etsv); +static void etsv_add (ETableSubsetVariable *etssv, gint row); + +static void +etsv_destroy (GtkObject *object) +{ + ETableSortedVariable *etsv = E_TABLE_SORTED_VARIABLE (object); + ETableSubset *etss = E_TABLE_SUBSET (object); + + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etsv->table_model_changed_id); + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etsv->table_model_row_changed_id); + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etsv->table_model_cell_changed_id); + + etsv->table_model_changed_id = 0; + etsv->table_model_row_changed_id = 0; + etsv->table_model_cell_changed_id = 0; + + GTK_OBJECT_CLASS (etsv_parent_class)->destroy (object); +} + +static void +etsv_class_init (GtkObjectClass *object_class) +{ + ETableSubsetVariableClass *etssv_class = E_TABLE_SUBSET_VARIABLE_CLASS(object_class); + + etsv_parent_class = gtk_type_class (PARENT_TYPE); + + object_class->destroy = etsv_destroy; + + etssv_class->add = etsv_add; +} + +E_MAKE_TYPE(e_table_sorted_variable, "ETableSortedVariable", ETableSortedVariable, etsv_class_init, NULL, PARENT_TYPE); + +static void +etsv_add (ETableSubsetVariable *etssv, + gint row) +{ + ETableModel *etm = E_TABLE_MODEL(etssv); + ETableSubset *etss = E_TABLE_SUBSET(etssv); + ETableSortedVariable *etsv = E_TABLE_SORTED_VARIABLE(etssv); + int i; + int col = etsv->sort_col; + GCompareFunc comp = etsv->compare; + gint ascending = etsv->ascending; + + void *val = e_table_model_value_at(etss->source, col, row); + + /* FIXME: binary search anyone? */ + for ( i = 0; i < etss->n_map; i++ ) { + int comp_val = (*comp)(val, e_table_model_value_at(etss->source, col, etss->map_table[i])); + if ( (ascending && comp_val < 0) || ((!ascending) && comp_val > 0) ) + break; + } + if ( etss->n_map + 1 > etssv->n_vals_allocated ) { + etss->map_table = g_realloc(etss->map_table, (etssv->n_vals_allocated + INCREMENT_AMOUNT) * sizeof(int)); + etssv->n_vals_allocated += INCREMENT_AMOUNT; + } + if ( i < etss->n_map ) + memmove(etss->map_table + i + 1, etss->map_table + i, (etss->n_map - i) * sizeof(int)); + etss->map_table[i] = row; + etss->n_map++; + if ( !etm->frozen ) + e_table_model_changed(etm); +} + +ETableModel * +e_table_sorted_variable_new (ETableModel *source, int col, int ascending, GCompareFunc compare) +{ + ETableSortedVariable *etsv = gtk_type_new (E_TABLE_SORTED_VARIABLE_TYPE); + ETableSubsetVariable *etssv = E_TABLE_SUBSET_VARIABLE (etsv); + + if (e_table_subset_variable_construct (etssv, source) == NULL){ + gtk_object_destroy (GTK_OBJECT (etsv)); + return NULL; + } + + etsv->sort_col = col; + etsv->ascending = ascending; + etsv->compare = compare; + + etsv->table_model_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_changed", + GTK_SIGNAL_FUNC (etsv_proxy_model_changed), etsv); + etsv->table_model_row_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_row_changed", + GTK_SIGNAL_FUNC (etsv_proxy_model_row_changed), etsv); + etsv->table_model_cell_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_cell_changed", + GTK_SIGNAL_FUNC (etsv_proxy_model_cell_changed), etsv); + + return E_TABLE_MODEL(etsv); +} + +static void +etsv_proxy_model_changed (ETableModel *etm, ETableSortedVariable *etsv) +{ + if ( !E_TABLE_MODEL(etsv)->frozen ) { + /* FIXME: do_resort(); */ + } +} + +static void +etsv_proxy_model_row_changed (ETableModel *etm, int row, ETableSortedVariable *etsv) +{ + ETableSubsetVariable *etssv = E_TABLE_SUBSET_VARIABLE(etsv); + if ( !E_TABLE_MODEL(etsv)->frozen ) { + if(e_table_subset_variable_remove(etssv, row)) + e_table_subset_variable_add(etssv, row); + } +} + +static void +etsv_proxy_model_cell_changed (ETableModel *etm, int col, int row, ETableSortedVariable *etsv) +{ + ETableSubsetVariable *etssv = E_TABLE_SUBSET_VARIABLE(etsv); + if ( !E_TABLE_MODEL(etsv)->frozen ) { + if ( col == etsv->sort_col ) { + if(e_table_subset_variable_remove(etssv, row)) + e_table_subset_variable_add(etssv, row); + } + } +} + diff --git a/widgets/table/e-table-sorted-variable.h b/widgets/table/e-table-sorted-variable.h new file mode 100644 index 0000000000..cf188acd4a --- /dev/null +++ b/widgets/table/e-table-sorted-variable.h @@ -0,0 +1,34 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +#ifndef _E_TABLE_SORTED_VARIABLE_H_ +#define _E_TABLE_SORTED_VARIABLE_H_ + +#include +#include "e-table-model.h" +#include "e-table-subset-variable.h" + +#define E_TABLE_SORTED_VARIABLE_TYPE (e_table_sorted_variable_get_type ()) +#define E_TABLE_SORTED_VARIABLE(o) (GTK_CHECK_CAST ((o), E_TABLE_SORTED_VARIABLE_TYPE, ETableSortedVariable)) +#define E_TABLE_SORTED_VARIABLE_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_TABLE_SORTED_VARIABLE_TYPE, ETableSortedVariableClass)) +#define E_IS_TABLE_SORTED_VARIABLE(o) (GTK_CHECK_TYPE ((o), E_TABLE_SORTED_VARIABLE_TYPE)) +#define E_IS_TABLE_SORTED_VARIABLE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_TABLE_SORTED_VARIABLE_TYPE)) + +typedef struct { + ETableSubsetVariable base; + + short sort_col; + int ascending; + GCompareFunc compare; + + int table_model_changed_id; + int table_model_row_changed_id; + int table_model_cell_changed_id; +} ETableSortedVariable; + +typedef struct { + ETableSubsetVariableClass parent_class; +} ETableSortedVariableClass; + +GtkType e_table_sorted_variable_get_type (void); +ETableModel *e_table_sorted_variable_new (ETableModel *etm, int col, int ascending, GCompareFunc compare); + +#endif /* _E_TABLE_SORTED_VARIABLE_H_ */ diff --git a/widgets/table/e-table-sorted.c b/widgets/table/e-table-sorted.c index 16644a45b1..c754f4cff7 100644 --- a/widgets/table/e-table-sorted.c +++ b/widgets/table/e-table-sorted.c @@ -13,7 +13,7 @@ #define PARENT_TYPE E_TABLE_SUBSET_TYPE -static ETableModelClass *ets_parent_class; +static ETableSubsetClass *ets_parent_class; static void ets_class_init (GtkObjectClass *klass) diff --git a/widgets/table/e-table-subset-variable.c b/widgets/table/e-table-subset-variable.c index 76da03c44f..5a3e0f2ddf 100644 --- a/widgets/table/e-table-subset-variable.c +++ b/widgets/table/e-table-subset-variable.c @@ -14,16 +14,58 @@ #include "e-util/e-util.h" #include "e-table-subset-variable.h" +#define ETSSV_CLASS(e) ((ETableSubsetVariableClass *)((GtkObject *)e)->klass) + #define PARENT_TYPE E_TABLE_SUBSET_TYPE #define INCREMENT_AMOUNT 10 -static ETableModelClass *etssv_parent_class; +static ETableSubsetClass *etssv_parent_class; + +static void +etssv_add (ETableSubsetVariable *etssv, + gint row) +{ + ETableModel *etm = E_TABLE_MODEL(etssv); + ETableSubset *etss = E_TABLE_SUBSET(etssv); + + if ( etss->n_map + 1 > etssv->n_vals_allocated ) { + etss->map_table = g_realloc(etss->map_table, (etssv->n_vals_allocated + INCREMENT_AMOUNT) * sizeof(int)); + etssv->n_vals_allocated += INCREMENT_AMOUNT; + } + etss->map_table[etss->n_map++] = row; + if ( !etm->frozen ) + e_table_model_changed(etm); +} + +static gboolean +etssv_remove (ETableSubsetVariable *etssv, + gint row) +{ + ETableModel *etm = E_TABLE_MODEL(etssv); + ETableSubset *etss = E_TABLE_SUBSET(etssv); + int i; + + for ( i = 0; i < etss->n_map; i++ ) { + if (etss->map_table[i] == row) { + memmove(etss->map_table + i, etss->map_table + i + 1, (etss->n_map - i - 1) * sizeof(int)); + etss->n_map --; + if ( !etm->frozen ) + e_table_model_changed(etm); + return TRUE; + } + } + return FALSE; +} static void -etssv_class_init (GtkObjectClass *klass) +etssv_class_init (GtkObjectClass *object_class) { + ETableSubsetVariableClass *klass = E_TABLE_SUBSET_VARIABLE_CLASS(object_class); etssv_parent_class = gtk_type_class (PARENT_TYPE); + + klass->add = etssv_add; + klass->remove = etssv_remove; } E_MAKE_TYPE(e_table_subset_variable, "ETableSubsetVariable", ETableSubsetVariable, etssv_class_init, NULL, PARENT_TYPE); @@ -56,34 +98,24 @@ void e_table_subset_variable_add (ETableSubsetVariable *etssv, gint row) { - ETableModel *etm = E_TABLE_MODEL(etssv); - ETableSubset *etss = E_TABLE_SUBSET(etssv); - - if ( etss->n_map + 1 > etssv->n_vals_allocated ) - etss->map_table = g_realloc(etss->map_table, (etssv->n_vals_allocated + INCREMENT_AMOUNT) * sizeof(int)); - etss->map_table[etss->n_map++] = row; - if ( !etm->frozen ) - e_table_model_changed(etm); + g_return_if_fail (etssv != NULL); + g_return_if_fail (E_IS_TABLE_SUBSET_VARIABLE(etssv)); + + if (ETSSV_CLASS(etssv)->add) + ETSSV_CLASS (etssv)->add (etssv, row); } gboolean e_table_subset_variable_remove (ETableSubsetVariable *etssv, gint row) { - ETableModel *etm = E_TABLE_MODEL(etssv); - ETableSubset *etss = E_TABLE_SUBSET(etssv); - int i; - - for ( i = 0; i < etss->n_map; i++ ) { - if (etss->map_table[i] == row) { - memmove(etss->map_table + i, etss->map_table + i + 1, (etss->n_map - i - 1) * sizeof(int)); - etss->n_map --; - if ( !etm->frozen ) - e_table_model_changed(etm); - return TRUE; - } - } - return FALSE; + g_return_val_if_fail (etssv != NULL, FALSE); + g_return_val_if_fail (E_IS_TABLE_SUBSET_VARIABLE(etssv), FALSE); + + if (ETSSV_CLASS(etssv)->remove) + return ETSSV_CLASS (etssv)->remove (etssv, row); + else + return FALSE; } void diff --git a/widgets/table/e-table-subset-variable.h b/widgets/table/e-table-subset-variable.h index 9755fb2477..8ac0af0382 100644 --- a/widgets/table/e-table-subset-variable.h +++ b/widgets/table/e-table-subset-variable.h @@ -19,6 +19,11 @@ typedef struct { typedef struct { ETableSubsetClass parent_class; + + void (*add) (ETableSubsetVariable *ets, + gint row); + gboolean (*remove) (ETableSubsetVariable *ets, + gint row); } ETableSubsetVariableClass; GtkType e_table_subset_variable_get_type (void); diff --git a/widgets/table/e-table-subset.c b/widgets/table/e-table-subset.c index a09d221980..b4473b87ef 100644 --- a/widgets/table/e-table-subset.c +++ b/widgets/table/e-table-subset.c @@ -25,6 +25,17 @@ etss_destroy (GtkObject *object) if (etss->source) gtk_object_unref (GTK_OBJECT (etss->source)); + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etss->table_model_changed_id); + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etss->table_model_row_changed_id); + gtk_signal_disconnect (GTK_OBJECT (etss->source), + etss->table_model_cell_changed_id); + + etss->table_model_changed_id = 0; + etss->table_model_row_changed_id = 0; + etss->table_model_cell_changed_id = 0; + if (etss->map_table) free (etss->map_table); @@ -71,6 +82,22 @@ etss_is_cell_editable (ETableModel *etm, int col, int row) return e_table_model_is_cell_editable (etss->source, col, etss->map_table [row]); } +static void * +etss_duplicate_value (ETableModel *etm, int col, const void *value) +{ + ETableSubset *etss = (ETableSubset *)etm; + + return e_table_model_duplicate_value (etss->source, col, value); +} + +static void +etss_free_value (ETableModel *etm, int col, void *value) +{ + ETableSubset *etss = (ETableSubset *)etm; + + e_table_model_free_value (etss->source, col, value); +} + static void etss_thaw (ETableModel *etm) { @@ -91,6 +118,8 @@ etss_class_init (GtkObjectClass *klass) table_class->value_at = etss_value_at; table_class->set_value_at = etss_set_value_at; table_class->is_cell_editable = etss_is_cell_editable; + table_class->duplicate_value = etss_duplicate_value; + table_class->free_value = etss_free_value; table_class->thaw = etss_thaw; } @@ -155,12 +184,12 @@ e_table_subset_construct (ETableSubset *etss, ETableModel *source, int nvals) for (i = 0; i < nvals; i++) etss->map_table [i] = i; - gtk_signal_connect (GTK_OBJECT (source), "model_changed", - GTK_SIGNAL_FUNC (etss_proxy_model_changed), etss); - gtk_signal_connect (GTK_OBJECT (source), "model_row_changed", - GTK_SIGNAL_FUNC (etss_proxy_model_row_changed), etss); - gtk_signal_connect (GTK_OBJECT (source), "model_cell_changed", - GTK_SIGNAL_FUNC (etss_proxy_model_cell_changed), etss); + etss->table_model_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_changed", + GTK_SIGNAL_FUNC (etss_proxy_model_changed), etss); + etss->table_model_row_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_row_changed", + GTK_SIGNAL_FUNC (etss_proxy_model_row_changed), etss); + etss->table_model_cell_changed_id = gtk_signal_connect (GTK_OBJECT (source), "model_cell_changed", + GTK_SIGNAL_FUNC (etss_proxy_model_cell_changed), etss); return E_TABLE_MODEL (etss); } diff --git a/widgets/table/e-table-subset.h b/widgets/table/e-table-subset.h index d8af1696f5..074120a410 100644 --- a/widgets/table/e-table-subset.h +++ b/widgets/table/e-table-subset.h @@ -17,6 +17,10 @@ typedef struct { ETableModel *source; int n_map; int *map_table; + + int table_model_changed_id; + int table_model_row_changed_id; + int table_model_cell_changed_id; } ETableSubset; typedef struct { diff --git a/widgets/table/e-table.c b/widgets/table/e-table.c index 551ef52227..e508e24e02 100644 --- a/widgets/table/e-table.c +++ b/widgets/table/e-table.c @@ -34,6 +34,8 @@ static GtkObjectClass *e_table_parent_class; +static void e_table_fill_table (ETable *e_table, ETableModel *model); + static void et_destroy (GtkObject *object) { @@ -42,6 +44,20 @@ et_destroy (GtkObject *object) gtk_object_unref (GTK_OBJECT (et->model)); gtk_object_unref (GTK_OBJECT (et->full_header)); gtk_object_unref (GTK_OBJECT (et->header)); + gtk_widget_destroy (GTK_WIDGET (et->header_canvas)); + gtk_widget_destroy (GTK_WIDGET (et->table_canvas)); + + gtk_signal_disconnect (GTK_OBJECT (et->model), + et->table_model_change_id); + gtk_signal_disconnect (GTK_OBJECT (et->model), + et->table_row_change_id); + gtk_signal_disconnect (GTK_OBJECT (et->model), + et->table_cell_change_id); + + if (et->rebuild_idle_id) { + g_source_remove(et->rebuild_idle_id); + et->rebuild_idle_id = 0; + } (*e_table_parent_class->destroy)(object); } @@ -54,6 +70,11 @@ e_table_init (GtkObject *object) e_table->draw_grid = 1; e_table->draw_focus = 1; e_table->spreadsheet = 1; + + e_table->need_rebuild = 0; + e_table->need_row_changes = 0; + e_table->row_changes_list = NULL; + e_table->rebuild_idle_id = 0; } static ETableHeader * @@ -527,6 +548,72 @@ table_canvas_size_allocate (GtkWidget *widget, GtkAllocation *alloc, ETable *e_t NULL); } +static void +change_row (gpointer key, gpointer value, gpointer data) +{ + ETable *et = E_TABLE(data); + gint row = GPOINTER_TO_INT(key); + if ( e_table_group_remove(et->group, row) ) { + e_table_group_add(et->group, row); + } +} + +static gboolean +changed_idle (gpointer data) +{ + ETable *et = E_TABLE(data); + if ( et->need_rebuild ) { + gtk_object_destroy( GTK_OBJECT(et->group ) ); + et->group = e_table_group_new(GNOME_CANVAS_GROUP(et->table_canvas->root), + et->full_header, + et->header, + et->model, + e_xml_get_child_by_name(xmlDocGetRootElement(et->specification), "grouping")->childs); + e_table_fill_table(et, et->model); + } else if (et->need_row_changes) { + g_hash_table_foreach(et->row_changes_list, change_row, et); + } + et->need_rebuild = 0; + et->need_row_changes = 0; + if (et->row_changes_list) + g_hash_table_destroy(et->row_changes_list); + et->row_changes_list = NULL; + et->rebuild_idle_id = 0; + return FALSE; +} + +static void +et_table_model_changed (ETableModel *model, ETable *et) +{ + et->need_rebuild = TRUE; + if ( !et->rebuild_idle_id ) { + et->rebuild_idle_id = g_idle_add(changed_idle, et); + } +} + +static void +et_table_row_changed (ETableModel *table_model, int row, ETable *et) +{ + if ( !et->need_rebuild ) { + if (!et->need_row_changes) { + et->need_row_changes = 1; + et->row_changes_list = g_hash_table_new (g_direct_hash, g_direct_equal); + } + if (!g_hash_table_lookup(et->row_changes_list, GINT_TO_POINTER(row))) { + g_hash_table_insert(et->row_changes_list, GINT_TO_POINTER(row), GINT_TO_POINTER(row + 1)); + } + } + if ( !et->rebuild_idle_id ) { + et->rebuild_idle_id = g_idle_add(changed_idle, et); + } +} + +static void +et_table_cell_changed (ETableModel *table_model, int view_col, int row, ETable *et) +{ + et_table_row_changed(table_model, row, et); +} + static void e_table_setup_table (ETable *e_table, ETableHeader *full_header, ETableHeader *header, ETableModel *model, xmlNode *xml_grouping) { @@ -546,6 +633,17 @@ e_table_setup_table (ETable *e_table, ETableHeader *full_header, ETableHeader *h model, xml_grouping->childs); + e_table->table_model_change_id = gtk_signal_connect ( + GTK_OBJECT (model), "model_changed", + GTK_SIGNAL_FUNC (et_table_model_changed), e_table); + + e_table->table_row_change_id = gtk_signal_connect ( + GTK_OBJECT (model), "model_row_changed", + GTK_SIGNAL_FUNC (et_table_row_changed), e_table); + + e_table->table_cell_change_id = gtk_signal_connect ( + GTK_OBJECT (model), "model_cell_changed", + GTK_SIGNAL_FUNC (et_table_cell_changed), e_table); } static void diff --git a/widgets/table/e-table.h b/widgets/table/e-table.h index a372d8042c..841013c09a 100644 --- a/widgets/table/e-table.h +++ b/widgets/table/e-table.h @@ -26,6 +26,10 @@ typedef struct { ETableGroup *group; + int table_model_change_id; + int table_row_change_id; + int table_cell_change_id; + GnomeCanvas *header_canvas, *table_canvas; GnomeCanvasItem *header_item, *root; @@ -35,6 +39,12 @@ typedef struct { guint draw_grid:1; guint draw_focus:1; guint spreadsheet:1; + + guint need_rebuild:1; + guint need_row_changes:1; + + GHashTable *row_changes_list; + gint rebuild_idle_id; } ETable; typedef struct { diff --git a/widgets/table/test-check.c b/widgets/table/test-check.c index a6a59788ad..7894898255 100644 --- a/widgets/table/test-check.c +++ b/widgets/table/test-check.c @@ -14,6 +14,7 @@ #include "e-table-item.h" #include "e-util/e-cursors.h" #include "e-util/e-canvas-utils.h" +#include "e-util/e-util.h" #include "e-cell-text.h" #include "e-cell-checkbox.h" @@ -79,6 +80,24 @@ is_cell_editable (ETableModel *etc, int col, int row, void *data) return TRUE; } +static void * +duplicate_value (ETableModel *etc, int col, const void *value, void *data) +{ + if (col == 0){ + return (void *) value; + } else { + return g_strdup(value); + } +} + +static void +free_value (ETableModel *etc, int col, void *value, void *data) +{ + if (col != 0){ + g_free(value); + } +} + static void thaw (ETableModel *etc, void *data) { @@ -107,7 +126,8 @@ check_test (void) e_table_model = e_table_simple_new ( col_count, row_count, value_at, - set_value_at, is_cell_editable, thaw, NULL); + set_value_at, is_cell_editable, + duplicate_value, free_value, thaw, NULL); /* * Header @@ -118,11 +138,11 @@ check_test (void) cell_image_check = e_cell_checkbox_new (); pixbuf = gdk_pixbuf_new_from_file("clip.png"); - col_0 = e_table_col_new_with_pixbuf (0, pixbuf, 18, 18, cell_image_check, g_int_equal, TRUE); + col_0 = e_table_col_new_with_pixbuf (0, pixbuf, 18, 18, cell_image_check, g_int_compare, TRUE); gdk_pixbuf_unref(pixbuf); e_table_header_add_column (e_table_header, col_0, 0); - col_1 = e_table_col_new (1, "Item Name", 180, 20, cell_left_just, g_str_equal, TRUE); + col_1 = e_table_col_new (1, "Item Name", 180, 20, cell_left_just, g_str_compare, TRUE); e_table_header_add_column (e_table_header, col_1, 1); e_table_col_set_arrow ( col_1, E_TABLE_COL_ARROW_DOWN ); diff --git a/widgets/table/test-cols.c b/widgets/table/test-cols.c index adc9ed6c20..d65b9945b7 100644 --- a/widgets/table/test-cols.c +++ b/widgets/table/test-cols.c @@ -10,6 +10,7 @@ #include #include "e-util/e-canvas-utils.h" #include "e-util/e-cursors.h" +#include "e-util/e-util.h" #include "e-table-simple.h" #include "e-table-header.h" #include "e-table-header-item.h" @@ -79,6 +80,24 @@ is_cell_editable (ETableModel *etc, int col, int row, void *data) return TRUE; } +static void * +duplicate_value (ETableModel *etc, int col, const void *value, void *data) +{ + if (col == 0){ + return (void *)value; + } else { + return g_strdup(value); + } +} + +static void +free_value (ETableModel *etc, int col, void *value, void *data) +{ + if (col != 0){ + g_free(value); + } +} + static void set_canvas_size (GnomeCanvas *canvas, GtkAllocation *alloc) { @@ -106,7 +125,9 @@ multi_cols_test (void) e_table_model = e_table_simple_new ( col_count, row_count, value_at, - set_value_at, is_cell_editable, thaw, NULL); + set_value_at, is_cell_editable, + duplicate_value, free_value, + thaw, NULL); /* * Header @@ -131,10 +152,10 @@ multi_cols_test (void) g_free (images); } - col_1 = e_table_col_new (1, "Item Name", 180, 20, cell_left_just, g_str_equal, TRUE); + col_1 = e_table_col_new (1, "Item Name", 180, 20, cell_left_just, g_str_compare, TRUE); e_table_header_add_column (e_table_header, col_1, 0); - col_0 = e_table_col_new (0, "A", 48, 48, cell_image_toggle, g_int_equal, TRUE); + col_0 = e_table_col_new (0, "A", 48, 48, cell_image_toggle, g_int_compare, TRUE); e_table_header_add_column (e_table_header, col_0, 1); /* diff --git a/widgets/table/test-table.c b/widgets/table/test-table.c index 1bd50e1479..0fdf32fcbe 100644 --- a/widgets/table/test-table.c +++ b/widgets/table/test-table.c @@ -176,6 +176,18 @@ is_cell_editable (ETableModel *etc, int col, int row, void *data) return TRUE; } +static void * +duplicate_value (ETableModel *etc, int col, const void *value, void *data) +{ + return g_strdup(value); +} + +static void +free_value (ETableModel *etc, int col, void *value, void *data) +{ + g_free(value); +} + static void thaw (ETableModel *etc, void *data) { @@ -205,7 +217,8 @@ table_browser_test (void) */ e_table_model = e_table_simple_new ( col_count, row_count, value_at, - set_value_at, is_cell_editable, thaw, NULL); + set_value_at, is_cell_editable, + duplicate_value, free_value, thaw, NULL); /* * Header @@ -217,7 +230,7 @@ table_browser_test (void) ETableCol *ecol = e_table_col_new ( i, column_labels [i], 80, 20, cell_left_just, - g_str_equal, TRUE); + g_str_compare, TRUE); e_table_header_add_column (e_table_header, ecol, i); } @@ -263,7 +276,6 @@ static void do_e_table_demo (const char *spec) { GtkWidget *e_table, *window, *frame; - ETableModel *e_table_model; ECell *cell_left_just; ETableHeader *full_header; int i; @@ -271,9 +283,14 @@ do_e_table_demo (const char *spec) /* * Data model */ - e_table_model = e_table_simple_new ( - col_count, row_count, value_at, - set_value_at, is_cell_editable, thaw, NULL); + static ETableModel *e_table_model = NULL; + + if ( e_table_model == NULL ) + e_table_model = + e_table_simple_new (col_count, row_count, value_at, + set_value_at, is_cell_editable, + duplicate_value, free_value, + thaw, NULL); full_header = e_table_header_new (); cell_left_just = e_cell_text_new (e_table_model, NULL, GTK_JUSTIFY_LEFT, TRUE); @@ -282,7 +299,7 @@ do_e_table_demo (const char *spec) ETableCol *ecol = e_table_col_new ( i, column_labels [i], 80, 20, cell_left_just, - g_str_equal, TRUE); + g_str_compare, TRUE); e_table_header_add_column (full_header, ecol, i); } @@ -306,9 +323,9 @@ e_table_test (void) load_data (); if (1){/*getenv ("DO")){*/ - do_e_table_demo (" 0 1 2 3 4 "); - do_e_table_demo (" 0 0 0 0 0 1 2 3 4 "); + do_e_table_demo (" 0 1 2 3 4 "); + do_e_table_demo (" 0 0 1 2 3 4 "); } - do_e_table_demo (" 0 1 2 3 4 "); - do_e_table_demo (" 0 1 2 3 4 "); + do_e_table_demo (" 0 1 2 3 4 "); + do_e_table_demo (" 0 1 2 3 4 "); } -- cgit v1.2.3