From 6c3caf2a9c6bbc07289941355fabfc61bc805601 Mon Sep 17 00:00:00 2001 From: Kristian Rietveld Date: Fri, 26 Jul 2002 20:51:13 +0000 Subject: [PATCH] API additions: _move, _reorder and _swap for stores, path constructor. Fri Jul 26 22:53:37 2002 Kristian Rietveld API additions: _move, _reorder and _swap for stores, path constructor. * gtk/gtktreemodel.[ch] (gtk_tree_path_new_from_indices): new function. * gtk/gtkliststore.[ch]: added gtk_list_store_reorder_func (private), gtk_list_store_reorder, gtk_list_store_swap, gtk_list_store_move. * gtk/gtktreestore.[ch]: added gtk_tree_store_reorder_func (private), gtk_tree_store_reorder, gtk_tree_store_swap, gtk_tree_store_move. Fri Jul 26 22:32:57 2002 Kristian Rietveld Merge from stable: * gtk/gtktreestore.c (node_free): return FALSE, (gtk_tree_store_finalize): use g_node_traverse instead of g_node_children_foreach, so the whole tree will be freed (#88854, patch from Emmanuel Briot). Fri Jul 26 22:32:24 2002 Kristian Rietveld Merge from stable: * gtk/gtktreeview.c (gtk_tree_view_button_press): fix some memleaks, (#84426, patch from Matthias Clasen). Fri Jul 26 22:31:25 2002 Kristian Rietveld Merge from stable: * gtk/gtktreeview.c (gtk_tree_view_unref_tree_helper): _iter_children check shouldn't be in g_return_return_val_if_fail (pointed out by Josh Green, #88997), (gtk_tree_view_set_model): call _gtk_tree_view_column_unset_model for each column when we unset the model (part of #82484), (gtk_tree_view_get_cell_area): return if we ran out of tree or if we got an invalid path (#82376). * gtk/gtktreeprivate.h: add _gtk_tree_view_column_unset_model. * gtk/gtktreeviewcolumn.c: implement _gtk_tree_view_column_unset_model which disconnects the sort_column_changed_signal (part of #82484). * gtk/gtkliststore.c (gtk_list_store_insert): append row if the given postion is off the end of the tree (#85813). * gtk/gtkentry.c (gtk_cell_editable_key_press_event): let's use 2-space indent, commit changes if up/down keys has been pressed, this overrides the focus key foo so the user won't be surprised (#84665). --- ChangeLog | 54 +++++++ ChangeLog.pre-2-10 | 54 +++++++ ChangeLog.pre-2-2 | 54 +++++++ ChangeLog.pre-2-4 | 54 +++++++ ChangeLog.pre-2-6 | 54 +++++++ ChangeLog.pre-2-8 | 54 +++++++ gtk/gtkentry.c | 25 ++- gtk/gtkliststore.c | 260 ++++++++++++++++++++++++++++++- gtk/gtkliststore.h | 8 + gtk/gtktreemodel.c | 32 ++++ gtk/gtktreemodel.h | 2 + gtk/gtktreeprivate.h | 2 + gtk/gtktreestore.c | 336 +++++++++++++++++++++++++++++++++++++++- gtk/gtktreestore.h | 9 ++ gtk/gtktreeview.c | 24 ++- gtk/gtktreeviewcolumn.c | 14 +- 16 files changed, 1016 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 22b96e24ce..5451e85e0d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,57 @@ +Fri Jul 26 22:53:37 2002 Kristian Rietveld + + API additions: _move, _reorder and _swap for stores, path + constructor. + + * gtk/gtktreemodel.[ch] (gtk_tree_path_new_from_indices): new function. + + * gtk/gtkliststore.[ch]: added gtk_list_store_reorder_func (private), + gtk_list_store_reorder, gtk_list_store_swap, gtk_list_store_move. + + * gtk/gtktreestore.[ch]: added gtk_tree_store_reorder_func (private), + gtk_tree_store_reorder, gtk_tree_store_swap, gtk_tree_store_move. + +Fri Jul 26 22:32:57 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreestore.c (node_free): return FALSE, + (gtk_tree_store_finalize): use g_node_traverse instead of + g_node_children_foreach, so the whole tree will be freed (#88854, + patch from Emmanuel Briot). + +Fri Jul 26 22:32:24 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_button_press): fix some memleaks, + (#84426, patch from Matthias Clasen). + +Fri Jul 26 22:31:25 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_unref_tree_helper): _iter_children + check shouldn't be in g_return_return_val_if_fail (pointed out by + Josh Green, #88997), + (gtk_tree_view_set_model): call _gtk_tree_view_column_unset_model + for each column when we unset the model (part of #82484), + (gtk_tree_view_get_cell_area): return if we ran out of tree or + if we got an invalid path (#82376). + + * gtk/gtktreeprivate.h: add _gtk_tree_view_column_unset_model. + + * gtk/gtktreeviewcolumn.c: implement _gtk_tree_view_column_unset_model + which disconnects the sort_column_changed_signal (part of #82484). + + * gtk/gtkliststore.c (gtk_list_store_insert): append row if the + given postion is off the end of the tree (#85813). + + * gtk/gtkentry.c (gtk_cell_editable_key_press_event): let's use + 2-space indent, commit changes if up/down keys has been pressed, + this overrides the focus key foo so the user won't be surprised + (#84665). + Fri Jul 26 16:34:34 2002 Shivram U * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable), diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 22b96e24ce..5451e85e0d 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,57 @@ +Fri Jul 26 22:53:37 2002 Kristian Rietveld + + API additions: _move, _reorder and _swap for stores, path + constructor. + + * gtk/gtktreemodel.[ch] (gtk_tree_path_new_from_indices): new function. + + * gtk/gtkliststore.[ch]: added gtk_list_store_reorder_func (private), + gtk_list_store_reorder, gtk_list_store_swap, gtk_list_store_move. + + * gtk/gtktreestore.[ch]: added gtk_tree_store_reorder_func (private), + gtk_tree_store_reorder, gtk_tree_store_swap, gtk_tree_store_move. + +Fri Jul 26 22:32:57 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreestore.c (node_free): return FALSE, + (gtk_tree_store_finalize): use g_node_traverse instead of + g_node_children_foreach, so the whole tree will be freed (#88854, + patch from Emmanuel Briot). + +Fri Jul 26 22:32:24 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_button_press): fix some memleaks, + (#84426, patch from Matthias Clasen). + +Fri Jul 26 22:31:25 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_unref_tree_helper): _iter_children + check shouldn't be in g_return_return_val_if_fail (pointed out by + Josh Green, #88997), + (gtk_tree_view_set_model): call _gtk_tree_view_column_unset_model + for each column when we unset the model (part of #82484), + (gtk_tree_view_get_cell_area): return if we ran out of tree or + if we got an invalid path (#82376). + + * gtk/gtktreeprivate.h: add _gtk_tree_view_column_unset_model. + + * gtk/gtktreeviewcolumn.c: implement _gtk_tree_view_column_unset_model + which disconnects the sort_column_changed_signal (part of #82484). + + * gtk/gtkliststore.c (gtk_list_store_insert): append row if the + given postion is off the end of the tree (#85813). + + * gtk/gtkentry.c (gtk_cell_editable_key_press_event): let's use + 2-space indent, commit changes if up/down keys has been pressed, + this overrides the focus key foo so the user won't be surprised + (#84665). + Fri Jul 26 16:34:34 2002 Shivram U * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable), diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 22b96e24ce..5451e85e0d 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,57 @@ +Fri Jul 26 22:53:37 2002 Kristian Rietveld + + API additions: _move, _reorder and _swap for stores, path + constructor. + + * gtk/gtktreemodel.[ch] (gtk_tree_path_new_from_indices): new function. + + * gtk/gtkliststore.[ch]: added gtk_list_store_reorder_func (private), + gtk_list_store_reorder, gtk_list_store_swap, gtk_list_store_move. + + * gtk/gtktreestore.[ch]: added gtk_tree_store_reorder_func (private), + gtk_tree_store_reorder, gtk_tree_store_swap, gtk_tree_store_move. + +Fri Jul 26 22:32:57 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreestore.c (node_free): return FALSE, + (gtk_tree_store_finalize): use g_node_traverse instead of + g_node_children_foreach, so the whole tree will be freed (#88854, + patch from Emmanuel Briot). + +Fri Jul 26 22:32:24 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_button_press): fix some memleaks, + (#84426, patch from Matthias Clasen). + +Fri Jul 26 22:31:25 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_unref_tree_helper): _iter_children + check shouldn't be in g_return_return_val_if_fail (pointed out by + Josh Green, #88997), + (gtk_tree_view_set_model): call _gtk_tree_view_column_unset_model + for each column when we unset the model (part of #82484), + (gtk_tree_view_get_cell_area): return if we ran out of tree or + if we got an invalid path (#82376). + + * gtk/gtktreeprivate.h: add _gtk_tree_view_column_unset_model. + + * gtk/gtktreeviewcolumn.c: implement _gtk_tree_view_column_unset_model + which disconnects the sort_column_changed_signal (part of #82484). + + * gtk/gtkliststore.c (gtk_list_store_insert): append row if the + given postion is off the end of the tree (#85813). + + * gtk/gtkentry.c (gtk_cell_editable_key_press_event): let's use + 2-space indent, commit changes if up/down keys has been pressed, + this overrides the focus key foo so the user won't be surprised + (#84665). + Fri Jul 26 16:34:34 2002 Shivram U * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable), diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 22b96e24ce..5451e85e0d 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,57 @@ +Fri Jul 26 22:53:37 2002 Kristian Rietveld + + API additions: _move, _reorder and _swap for stores, path + constructor. + + * gtk/gtktreemodel.[ch] (gtk_tree_path_new_from_indices): new function. + + * gtk/gtkliststore.[ch]: added gtk_list_store_reorder_func (private), + gtk_list_store_reorder, gtk_list_store_swap, gtk_list_store_move. + + * gtk/gtktreestore.[ch]: added gtk_tree_store_reorder_func (private), + gtk_tree_store_reorder, gtk_tree_store_swap, gtk_tree_store_move. + +Fri Jul 26 22:32:57 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreestore.c (node_free): return FALSE, + (gtk_tree_store_finalize): use g_node_traverse instead of + g_node_children_foreach, so the whole tree will be freed (#88854, + patch from Emmanuel Briot). + +Fri Jul 26 22:32:24 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_button_press): fix some memleaks, + (#84426, patch from Matthias Clasen). + +Fri Jul 26 22:31:25 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_unref_tree_helper): _iter_children + check shouldn't be in g_return_return_val_if_fail (pointed out by + Josh Green, #88997), + (gtk_tree_view_set_model): call _gtk_tree_view_column_unset_model + for each column when we unset the model (part of #82484), + (gtk_tree_view_get_cell_area): return if we ran out of tree or + if we got an invalid path (#82376). + + * gtk/gtktreeprivate.h: add _gtk_tree_view_column_unset_model. + + * gtk/gtktreeviewcolumn.c: implement _gtk_tree_view_column_unset_model + which disconnects the sort_column_changed_signal (part of #82484). + + * gtk/gtkliststore.c (gtk_list_store_insert): append row if the + given postion is off the end of the tree (#85813). + + * gtk/gtkentry.c (gtk_cell_editable_key_press_event): let's use + 2-space indent, commit changes if up/down keys has been pressed, + this overrides the focus key foo so the user won't be surprised + (#84665). + Fri Jul 26 16:34:34 2002 Shivram U * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable), diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 22b96e24ce..5451e85e0d 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,57 @@ +Fri Jul 26 22:53:37 2002 Kristian Rietveld + + API additions: _move, _reorder and _swap for stores, path + constructor. + + * gtk/gtktreemodel.[ch] (gtk_tree_path_new_from_indices): new function. + + * gtk/gtkliststore.[ch]: added gtk_list_store_reorder_func (private), + gtk_list_store_reorder, gtk_list_store_swap, gtk_list_store_move. + + * gtk/gtktreestore.[ch]: added gtk_tree_store_reorder_func (private), + gtk_tree_store_reorder, gtk_tree_store_swap, gtk_tree_store_move. + +Fri Jul 26 22:32:57 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreestore.c (node_free): return FALSE, + (gtk_tree_store_finalize): use g_node_traverse instead of + g_node_children_foreach, so the whole tree will be freed (#88854, + patch from Emmanuel Briot). + +Fri Jul 26 22:32:24 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_button_press): fix some memleaks, + (#84426, patch from Matthias Clasen). + +Fri Jul 26 22:31:25 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_unref_tree_helper): _iter_children + check shouldn't be in g_return_return_val_if_fail (pointed out by + Josh Green, #88997), + (gtk_tree_view_set_model): call _gtk_tree_view_column_unset_model + for each column when we unset the model (part of #82484), + (gtk_tree_view_get_cell_area): return if we ran out of tree or + if we got an invalid path (#82376). + + * gtk/gtktreeprivate.h: add _gtk_tree_view_column_unset_model. + + * gtk/gtktreeviewcolumn.c: implement _gtk_tree_view_column_unset_model + which disconnects the sort_column_changed_signal (part of #82484). + + * gtk/gtkliststore.c (gtk_list_store_insert): append row if the + given postion is off the end of the tree (#85813). + + * gtk/gtkentry.c (gtk_cell_editable_key_press_event): let's use + 2-space indent, commit changes if up/down keys has been pressed, + this overrides the focus key foo so the user won't be surprised + (#84665). + Fri Jul 26 16:34:34 2002 Shivram U * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable), diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 22b96e24ce..5451e85e0d 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,57 @@ +Fri Jul 26 22:53:37 2002 Kristian Rietveld + + API additions: _move, _reorder and _swap for stores, path + constructor. + + * gtk/gtktreemodel.[ch] (gtk_tree_path_new_from_indices): new function. + + * gtk/gtkliststore.[ch]: added gtk_list_store_reorder_func (private), + gtk_list_store_reorder, gtk_list_store_swap, gtk_list_store_move. + + * gtk/gtktreestore.[ch]: added gtk_tree_store_reorder_func (private), + gtk_tree_store_reorder, gtk_tree_store_swap, gtk_tree_store_move. + +Fri Jul 26 22:32:57 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreestore.c (node_free): return FALSE, + (gtk_tree_store_finalize): use g_node_traverse instead of + g_node_children_foreach, so the whole tree will be freed (#88854, + patch from Emmanuel Briot). + +Fri Jul 26 22:32:24 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_button_press): fix some memleaks, + (#84426, patch from Matthias Clasen). + +Fri Jul 26 22:31:25 2002 Kristian Rietveld + + Merge from stable: + + * gtk/gtktreeview.c (gtk_tree_view_unref_tree_helper): _iter_children + check shouldn't be in g_return_return_val_if_fail (pointed out by + Josh Green, #88997), + (gtk_tree_view_set_model): call _gtk_tree_view_column_unset_model + for each column when we unset the model (part of #82484), + (gtk_tree_view_get_cell_area): return if we ran out of tree or + if we got an invalid path (#82376). + + * gtk/gtktreeprivate.h: add _gtk_tree_view_column_unset_model. + + * gtk/gtktreeviewcolumn.c: implement _gtk_tree_view_column_unset_model + which disconnects the sort_column_changed_signal (part of #82484). + + * gtk/gtkliststore.c (gtk_list_store_insert): append row if the + given postion is off the end of the tree (#85813). + + * gtk/gtkentry.c (gtk_cell_editable_key_press_event): let's use + 2-space indent, commit changes if up/down keys has been pressed, + this overrides the focus key foo so the user won't be surprised + (#84665). + Fri Jul 26 16:34:34 2002 Shivram U * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable), diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 70a2ddc5c6..c6fc15a9d4 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -1817,16 +1817,25 @@ gtk_cell_editable_key_press_event (GtkEntry *entry, GdkEventKey *key_event, gpointer data) { - if (key_event->keyval == GDK_Escape) - { - entry->editing_canceled = TRUE; - gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry)); - gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry)); + if (key_event->keyval == GDK_Escape) + { + entry->editing_canceled = TRUE; + gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry)); + gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry)); - return TRUE; - } + return TRUE; + } - return FALSE; + /* override focus */ + if (key_event->keyval == GDK_Up || key_event->keyval == GDK_Down) + { + gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry)); + gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry)); + + return TRUE; + } + + return FALSE; } static void diff --git a/gtk/gtkliststore.c b/gtk/gtkliststore.c index dac96f3df0..daf4b61988 100644 --- a/gtk/gtkliststore.c +++ b/gtk/gtkliststore.c @@ -1075,7 +1075,9 @@ gtk_list_store_insert (GtkListStore *list_store, if (list == NULL) { - g_warning ("%s: position %d is off the end of the list\n", G_STRLOC, position); + /* position if off the end of the list, append it */ + gtk_list_store_append (list_store, iter); + return; } @@ -1581,14 +1583,266 @@ gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest, return retval; } - -/* Sorting */ +/* Sorting and reordering */ typedef struct _SortTuple { gint offset; GSList *el; } SortTuple; +/* Reordering */ +static gint +gtk_list_store_reorder_func (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + SortTuple *a_reorder; + SortTuple *b_reorder; + + a_reorder = (SortTuple *)a; + b_reorder = (SortTuple *)b; + + if (a_reorder->offset < b_reorder->offset) + return -1; + if (a_reorder->offset > b_reorder->offset) + return 1; + + return 0; +} + +/** + * gtk_list_store_reorder: + * @store: A #GtkTreeStore. + * @new_order: An integer array indicating the new order for the list. + * + * Reorders @store to follow the order indicated by @new_order. Note that + * this function only works with unsorted stores. + **/ +void +gtk_list_store_reorder (GtkListStore *store, + gint *new_order) +{ + gint i; + GSList *current_list; + GtkTreePath *path; + SortTuple *sort_array; + + g_return_if_fail (GTK_IS_LIST_STORE (store)); + g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store)); + g_return_if_fail (new_order != NULL); + + sort_array = g_new (SortTuple, store->length); + + current_list = store->root; + + for (i = 0; i < store->length; i++) + { + sort_array[i].offset = new_order[i]; + sort_array[i].el = current_list; + + current_list = current_list->next; + } + + g_qsort_with_data (sort_array, + store->length, + sizeof (SortTuple), + gtk_list_store_reorder_func, + NULL); + + for (i = 0; i < store->length - 1; i++) + G_SLIST (sort_array[i].el)->next = G_SLIST (sort_array[i+1].el); + + store->root = G_SLIST (sort_array[0].el); + store->tail = G_SLIST (sort_array[store->length-1].el); + G_SLIST (store->tail)->next = NULL; + + /* emit signal */ + path = gtk_tree_path_new (); + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store), + path, NULL, new_order); + gtk_tree_path_free (path); + g_free (sort_array); +} + +/** + * gtk_list_store_swap: + * @store: A #GtkListStore. + * @a: A #GtkTreeIter. + * @b: Another #GtkTreeIter. + * + * Swaps @a and @b in @store. Note that this function only works with + * unsorted stores. + **/ +void +gtk_list_store_swap (GtkListStore *store, + GtkTreeIter *a, + GtkTreeIter *b) +{ + GSList *i, *prev_a = NULL, *prev_b = NULL; + gint j, a_count = 0, b_count = 0, *order; + GtkTreePath *path; + + g_return_if_fail (GTK_IS_LIST_STORE (store)); + g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store)); + g_return_if_fail (VALID_ITER (a, store)); + g_return_if_fail (VALID_ITER (b, store)); + + if (a->user_data == b->user_data) + return; + + if (a->user_data == store->root) + prev_a = NULL; + else + { + for (i = store->root; i; i = i->next, a_count++) + if (i->next == a->user_data) + { + prev_a = i; + break; + } + + a_count++; + } + + if (a->user_data == store->root) + prev_b = NULL; + else + { + for (i = store->root; i; i = i->next, b_count++) + if (i->next == b->user_data) + { + prev_b = i; + break; + } + + b_count++; + } + + if (!prev_a) + store->root = b->user_data; + else + prev_a->next = b->user_data; + + if (!prev_b) + store->root = a->user_data; + else + prev_b->next = a->user_data; + + /* think a_next inspead of a_prev here ... */ + prev_a = G_SLIST (a->user_data)->next; + prev_b = G_SLIST (b->user_data)->next; + + G_SLIST (a->user_data)->next = prev_b; + G_SLIST (b->user_data)->next = prev_a; + + /* emit signal */ + order = g_new (gint, store->length); + for (j = 0; j < store->length; j++) + if (j == a_count) + order[j] = b_count; + else if (j == b_count) + order[j] = a_count; + else + order[j] = j; + + path = gtk_tree_path_new (); + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store), + path, NULL, order); + gtk_tree_path_free (path); + g_free (order); +} + +/** + * gtk_list_store_move: + * @store: A #GtkTreeStore. + * @iter: A #GtkTreeIter. + * @position: A #GtkTreePath. + * + * Moves @iter in @store to the position before @position. Note that this + * function only works with unsorted stores. + **/ +void +gtk_list_store_move (GtkListStore *store, + GtkTreeIter *iter, + GtkTreePath *position) +{ + GSList *i, *prev = NULL, *new_prev = NULL; + gint old_pos = 0, j = 0, *order; + GtkTreePath *path; + + g_return_if_fail (GTK_IS_LIST_STORE (store)); + g_return_if_fail (!GTK_LIST_STORE_IS_SORTED (store)); + g_return_if_fail (VALID_ITER (iter, store)); + g_return_if_fail (position != NULL); + + if (gtk_tree_path_get_depth (position) != 1) + return; + + if (iter->user_data == store->root) + prev = NULL; + else + { + for (i = store->root; i; i = i->next, old_pos++) + if (i->next == iter->user_data) + { + prev = i; + break; + } + + old_pos++; + } + + if (old_pos == gtk_tree_path_get_indices (position)[0]) + return; + + if (gtk_tree_path_get_indices (position)[0] == 0) + new_prev = NULL; + else + { + for (i = store->root; i; i = i->next, j++) + if (j == gtk_tree_path_get_indices (position)[0] - 1) + { + new_prev = i; + break; + } + } + + if (!prev) + store->root = G_SLIST (iter->user_data)->next; + else + prev->next = G_SLIST (iter->user_data)->next; + + if (!new_prev) + { + G_SLIST (iter->user_data)->next = store->root; + store->root = G_SLIST (iter->user_data); + } + else + { + G_SLIST (iter->user_data)->next = new_prev->next; + new_prev->next = G_SLIST (iter->user_data); + } + + /* emit signal */ + order = g_new (gint, store->length); + for (j = 0; j < store->length; j++) + if (j < old_pos) + order[j] = j; + else if (j >= old_pos && j < gtk_tree_path_get_indices (position)[0]) + order[j] = j + 1; + else if (j == gtk_tree_path_get_indices (position)[0]) + order[j] = old_pos; + else + order[j] = j; + + path = gtk_tree_path_new (); + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store), + path, NULL, order); + gtk_tree_path_free (path); + g_free (order); +} + +/* Sorting */ static gint gtk_list_store_compare_func (gconstpointer a, gconstpointer b, diff --git a/gtk/gtkliststore.h b/gtk/gtkliststore.h index d13d33a630..6e35fa6cb2 100644 --- a/gtk/gtkliststore.h +++ b/gtk/gtkliststore.h @@ -108,6 +108,14 @@ void gtk_list_store_append (GtkListStore *list_store, void gtk_list_store_clear (GtkListStore *list_store); gboolean gtk_list_store_iter_is_valid (GtkListStore *list_store, GtkTreeIter *iter); +void gtk_list_store_reorder (GtkListStore *store, + gint *new_order); +void gtk_list_store_swap (GtkListStore *store, + GtkTreeIter *a, + GtkTreeIter *b); +void gtk_list_store_move (GtkListStore *store, + GtkTreeIter *iter, + GtkTreePath *position); #ifdef __cplusplus diff --git a/gtk/gtktreemodel.c b/gtk/gtktreemodel.c index a749cec3da..91cd2144ae 100644 --- a/gtk/gtktreemodel.c +++ b/gtk/gtktreemodel.c @@ -199,6 +199,38 @@ gtk_tree_path_new_from_string (const gchar *path) return retval; } +/** + * gtk_tree_path_new_from_indices: + * @first_index and @varargs: list of integers terminated by -1 + * + * Creates a new path with @first_index and @varargs as indices. + * + * Return value: A newly created GtkTreePath. + **/ +GtkTreePath * +gtk_tree_path_new_from_indices (gint first_index, + ...) +{ + int arg; + va_list args; + GtkTreePath *path; + + path = gtk_tree_path_new (); + + va_start (args, first_index); + arg = first_index; + + while (arg != -1) + { + gtk_tree_path_append_index (path, arg); + arg = va_arg (args, gint); + } + + va_end (args); + + return path; +} + /** * gtk_tree_path_to_string: * @path: A #GtkTreePath diff --git a/gtk/gtktreemodel.h b/gtk/gtktreemodel.h index a3f5e93cf9..4118f48260 100644 --- a/gtk/gtktreemodel.h +++ b/gtk/gtktreemodel.h @@ -116,6 +116,8 @@ struct _GtkTreeModelIface /* GtkTreePath operations */ GtkTreePath *gtk_tree_path_new (void); GtkTreePath *gtk_tree_path_new_from_string (const gchar *path); +GtkTreePath *gtk_tree_path_new_from_indices (gint first_index, + ...); gchar *gtk_tree_path_to_string (GtkTreePath *path); #define gtk_tree_path_new_root() gtk_tree_path_new_first() GtkTreePath *gtk_tree_path_new_first (void); diff --git a/gtk/gtktreeprivate.h b/gtk/gtktreeprivate.h index 5f01013197..d289d59d59 100644 --- a/gtk/gtktreeprivate.h +++ b/gtk/gtktreeprivate.h @@ -296,6 +296,8 @@ void _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column); void _gtk_tree_view_column_unrealize_button (GtkTreeViewColumn *column); void _gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column, GtkTreeView *tree_view); +void _gtk_tree_view_column_unset_model (GtkTreeViewColumn *column, + GtkTreeModel *old_model); void _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column); void _gtk_tree_view_column_set_width (GtkTreeViewColumn *column, gint width); diff --git a/gtk/gtktreestore.c b/gtk/gtktreestore.c index 14c8e5a2c0..4c3f8bbf88 100644 --- a/gtk/gtktreestore.c +++ b/gtk/gtktreestore.c @@ -433,10 +433,11 @@ gtk_tree_store_set_column_type (GtkTreeStore *tree_store, tree_store->column_headers[column] = type; } -static void +static gboolean node_free (GNode *node, gpointer data) { _gtk_tree_data_list_free (node->data, (GType*)data); + return FALSE; } static void @@ -444,7 +445,8 @@ gtk_tree_store_finalize (GObject *object) { GtkTreeStore *tree_store = GTK_TREE_STORE (object); - g_node_children_foreach (tree_store->root, G_TRAVERSE_ALL, node_free, tree_store->column_headers); + g_node_traverse (tree_store->root, G_POST_ORDER, G_TRAVERSE_ALL, -1, + node_free, tree_store->column_headers); _gtk_tree_data_list_header_free (tree_store->sort_list); g_free (tree_store->column_headers); @@ -1842,13 +1844,341 @@ gtk_tree_store_row_drop_possible (GtkTreeDragDest *drag_dest, return retval; } -/* Sorting */ +/* Sorting and reordering */ typedef struct _SortTuple { gint offset; GNode *node; } SortTuple; +/* Reordering */ +static gint +gtk_tree_store_reorder_func (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + SortTuple *a_reorder; + SortTuple *b_reorder; + + a_reorder = (SortTuple *)a; + b_reorder = (SortTuple *)b; + + if (a_reorder->offset < b_reorder->offset) + return -1; + if (a_reorder->offset > b_reorder->offset) + return 1; + + return 0; +} + +/** + * gtk_tree_store_reorder: + * @store: A #GtkTreeStore. + * @parent: A #GtkTreeIter. + * @new_order: An integer array indication the new order for the list. + * + * Reorders the children of @parent in @store to follow the order + * indicated by @new_order. Note that this function only works with + * unsorted stores. + **/ +void +gtk_tree_store_reorder (GtkTreeStore *store, + GtkTreeIter *parent, + gint *new_order) +{ + gint i, length = 0; + GNode *level, *node; + GtkTreePath *path; + SortTuple *sort_array; + + g_return_if_fail (GTK_IS_TREE_STORE (store)); + g_return_if_fail (!GTK_TREE_STORE_IS_SORTED (store)); + g_return_if_fail (parent == NULL || VALID_ITER (parent, store)); + g_return_if_fail (new_order != NULL); + + if (!parent) + level = G_NODE (store->root)->children; + else + level = G_NODE (parent->user_data)->children; + + /* count nodes */ + node = level; + while (node) + { + length++; + node = node->next; + } + + /* set up sortarray */ + sort_array = g_new (SortTuple, length); + + node = level; + for (i = 0; i < length; i++) + { + sort_array[i].offset = new_order[i]; + sort_array[i].node = node; + + node = node->next; + } + + g_qsort_with_data (sort_array, + length, + sizeof (SortTuple), + gtk_tree_store_reorder_func, + NULL); + + /* fix up level */ + for (i = 0; i < length - 1; i++) + { + sort_array[i].node->next = sort_array[i+1].node; + sort_array[i+1].node->prev = sort_array[i].node; + } + + sort_array[length-1].node->next = NULL; + sort_array[0].node->prev = NULL; + if (parent) + G_NODE (parent->user_data)->children = sort_array[0].node; + else + G_NODE (store->root)->children = sort_array[0].node; + + /* emit signal */ + if (parent) + path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), parent); + else + path = gtk_tree_path_new (); + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store), path, + parent, new_order); + gtk_tree_path_free (path); + g_free (sort_array); +} + +/** + * gtk_tree_store_swap: + * @store: A #GtkTreeStore. + * @a: A #GtkTreeIter. + * @b: Another #GtkTreeIter. + * + * Swaps @a and @b in the same level of @store. Note that this function + * only works with unsorted stores. + **/ +void +gtk_tree_store_swap (GtkTreeStore *store, + GtkTreeIter *a, + GtkTreeIter *b) +{ + GNode *tmp, *node_a, *node_b, *parent_node; + gint i, a_count, b_count, length, *order; + GtkTreePath *path_a, *path_b; + GtkTreeIter parent; + + g_return_if_fail (GTK_IS_TREE_STORE (store)); + g_return_if_fail (VALID_ITER (a, store)); + g_return_if_fail (VALID_ITER (b, store)); + + node_a = G_NODE (a->user_data); + node_b = G_NODE (b->user_data); + + /* basic sanity checking */ + if (node_a == node_b) + return; + + path_a = gtk_tree_model_get_path (GTK_TREE_MODEL (store), a); + path_b = gtk_tree_model_get_path (GTK_TREE_MODEL (store), b); + + g_return_if_fail (path_a && path_b); + + gtk_tree_path_up (path_a); + gtk_tree_path_up (path_b); + + if (gtk_tree_path_compare (path_a, path_b)) + { + gtk_tree_path_free (path_a); + gtk_tree_path_free (path_b); + + g_warning ("Given childs are not in the same level\n"); + return; + } + + gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &parent, path_a); + parent_node = G_NODE (parent.user_data); + + gtk_tree_path_free (path_b); + + /* counting nodes */ + tmp = parent_node; + i = a_count = b_count = 0; + while (tmp) + { + if (tmp == node_a) + a_count = i; + if (tmp == node_b) + b_count = i; + + tmp = tmp->next; + i++; + } + length = i; + + /* hacking the tree */ + if (!node_a->prev) + parent_node->children = node_b; + else + node_a->prev->next = node_b; + + if (!node_b->prev) + parent_node->children = node_a; + else + node_b->prev->next = node_a; + + if (node_a->next) + node_a->next->prev = node_b; + + if (node_b->next) + node_b->next->prev = node_a; + + tmp = node_a->next; + node_a->next = node_b->next; + node_b->next = tmp; + + tmp = node_a->prev; + node_a->prev = node_b->prev; + node_b->prev = tmp; + + /* emit signal */ + order = g_new (gint, length); + for (i = 0; i < length; i++) + if (i == a_count) + order[i] = b_count; + else if (i == b_count) + order[i] = a_count; + else + order[i] = i; + + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store), path_a, + &parent, order); + gtk_tree_path_free (path_a); + g_free (order); +} + +/** + * gtk_tree_store_move: + * @store: A #GtkTreeStore. + * @iter: A #GtkTreeIter. + * @position: A #GtkTreePath. + * + * Moves @iter in @store to the position before @position. @iter and + * @position should be in the same level. Note that this function only + * works with unsorted stores. + **/ +void +gtk_tree_store_move (GtkTreeStore *store, + GtkTreeIter *iter, + GtkTreePath *position) +{ + GNode *tmp, *new_prev, *new_next, *old_prev, *old_next; + gint old_pos, new_pos, length, i, *order; + GtkTreePath *path, *tmppath; + GtkTreeIter parent, new_iter; + + g_return_if_fail (GTK_IS_TREE_STORE (store)); + g_return_if_fail (!GTK_TREE_STORE_IS_SORTED (store)); + g_return_if_fail (VALID_ITER (iter, store)); + g_return_if_fail (position != NULL); + + /* sanity checks */ + path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter); + + if (!gtk_tree_path_compare (path, position)) + { + gtk_tree_path_free (path); + return; + } + + if (gtk_tree_path_get_depth (path) != gtk_tree_path_get_depth (position)) + { + gtk_tree_path_free (path); + + g_warning ("Given childs are not in the same level\n"); + return; + } + + tmppath = gtk_tree_path_copy (position); + gtk_tree_path_up (path); + gtk_tree_path_up (tmppath); + + if (gtk_tree_path_compare (path, tmppath)) + { + gtk_tree_path_free (path); + gtk_tree_path_free (tmppath); + + g_warning ("Given childs are not in the same level\n"); + return; + } + + gtk_tree_path_free (tmppath); + gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &parent, path); + + gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &new_iter, position); + + new_prev = G_NODE (new_iter.user_data)->prev; + new_next = G_NODE (new_iter.user_data); + + old_prev = G_NODE (iter->user_data)->prev; + old_next = G_NODE (iter->user_data)->next; + + /* counting nodes */ + tmp = G_NODE (parent.user_data); + length = old_pos = 0; + while (tmp) + { + if (tmp == iter->user_data) + old_pos = length; + + tmp = tmp->next; + length++; + } + + /* hacking the tree */ + if (!old_prev) + G_NODE (parent.user_data)->children = old_next; + else + old_prev->next = old_next; + + if (old_next) + old_next->prev = old_prev; + + if (!new_prev) + G_NODE (parent.user_data)->children = iter->user_data; + else + new_prev->next = iter->user_data; + + if (new_next) + new_next->prev = iter->user_data; + + G_NODE (iter->user_data)->prev = new_prev; + G_NODE (iter->user_data)->next = new_next; + + /* emit signal */ + new_pos = gtk_tree_path_get_indices (position)[gtk_tree_path_get_depth (position)-1]; + order = g_new (gint, length); + for (i = 0; i < length; i++) + if (i < old_pos) + order[i] = i; + else if (i >= old_pos && i < new_pos) + order[i] = i + 1; + else if (i == new_pos) + order[i] = old_pos; + else + order[i] = i; + + path = gtk_tree_path_new (); + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (store), + path, NULL, order); + gtk_tree_path_free (path); + g_free (order); +} + +/* Sorting */ static gint gtk_tree_store_compare_func (gconstpointer a, gconstpointer b, diff --git a/gtk/gtktreestore.h b/gtk/gtktreestore.h index 7190b7a76e..85f3c58b34 100644 --- a/gtk/gtktreestore.h +++ b/gtk/gtktreestore.h @@ -117,6 +117,15 @@ gint gtk_tree_store_iter_depth (GtkTreeStore *tree_store, void gtk_tree_store_clear (GtkTreeStore *tree_store); gboolean gtk_tree_store_iter_is_valid (GtkTreeStore *tree_store, GtkTreeIter *iter); +void gtk_tree_store_reorder (GtkTreeStore *tree_store, + GtkTreeIter *parent, + gint *new_order); +void gtk_tree_store_swap (GtkTreeStore *store, + GtkTreeIter *a, + GtkTreeIter *b); +void gtk_tree_store_move (GtkTreeStore *store, + GtkTreeIter *iter, + GtkTreePath *position); #ifdef __cplusplus diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c index afd7d0b0d4..16d9760e01 100644 --- a/gtk/gtktreeview.c +++ b/gtk/gtktreeview.c @@ -1828,7 +1828,11 @@ gtk_tree_view_button_press (GtkWidget *widget, } if (column == NULL) - return FALSE; + { + gtk_tree_path_free (path); + + return FALSE; + } /* decide if we edit */ if (event->type == GDK_BUTTON_PRESS && @@ -1885,6 +1889,7 @@ gtk_tree_view_button_press (GtkWidget *widget, &area, (GdkEvent *)event, flags); + g_free (path_string); gtk_tree_path_free (path); gtk_tree_path_free (anchor); return TRUE; @@ -3748,6 +3753,7 @@ validate_row (GtkTreeView *tree_view, gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &tmp_width, &tmp_height); + height = MAX (height, tmp_height); height = MAX (height, tree_view->priv->expander_size); @@ -6652,7 +6658,9 @@ gtk_tree_view_unref_tree_helper (GtkTreeModel *model, while (new_node && new_node->left != new_tree->nil) new_node = new_node->left; - g_return_val_if_fail (gtk_tree_model_iter_children (model, &child, iter), FALSE); + if (!gtk_tree_model_iter_children (model, &child, iter)) + return FALSE; + retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node); } @@ -7716,6 +7724,8 @@ gtk_tree_view_set_model (GtkTreeView *tree_view, if (tree_view->priv->model) { + GList *tmplist = tree_view->priv->columns; + gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree); g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model), @@ -7728,6 +7738,11 @@ gtk_tree_view_set_model (GtkTreeView *tree_view, (gpointer) gtk_tree_view_row_deleted, tree_view); g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model), (gpointer) gtk_tree_view_rows_reordered, tree_view); + + for (; tmplist; tmplist = tmplist->next) + _gtk_tree_view_column_unset_model (tmplist->data, + tree_view->priv->model); + if (tree_view->priv->tree) { _gtk_rbtree_free (tree_view->priv->tree); @@ -9717,9 +9732,10 @@ gtk_tree_view_get_cell_area (GtkTreeView *tree_view, if (path) { + gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node); + /* Get vertical coords */ - if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) && - tree == NULL) + if ((!ret && tree == NULL) || ret) return; rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator); diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c index c876a1eaa6..b57fed1903 100644 --- a/gtk/gtktreeviewcolumn.c +++ b/gtk/gtktreeviewcolumn.c @@ -86,7 +86,7 @@ static void gtk_tree_view_column_get_property (GObject GParamSpec *pspec); static void gtk_tree_view_column_finalize (GObject *object); -/* Button handling code */ +/* Button handling code */ static void gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column); static void gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column); @@ -927,7 +927,7 @@ gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_colu GtkSortType real_order; if (tree_column->sort_column_changed_signal == 0) - tree_column->sort_column_changed_signal = + tree_column->sort_column_changed_signal = g_signal_connect (G_OBJECT (model), "sort_column_changed", GTK_SIGNAL_FUNC (gtk_tree_view_model_sort_column_changed), tree_column); @@ -1008,6 +1008,16 @@ _gtk_tree_view_column_unrealize_button (GtkTreeViewColumn *column) column->window = NULL; } +void +_gtk_tree_view_column_unset_model (GtkTreeViewColumn *column, + GtkTreeModel *old_model) +{ + if (column->sort_column_changed_signal) + g_signal_handler_disconnect (G_OBJECT (old_model), + column->sort_column_changed_signal); + column->sort_column_changed_signal = 0; +} + void _gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column, GtkTreeView *tree_view)