summaryrefslogtreecommitdiff
path: root/gtk/gtktreestore.c
diff options
context:
space:
mode:
authorKristian Rietveld <kris@gtk.org>2002-07-26 20:51:13 +0000
committerKristian Rietveld <kristian@src.gnome.org>2002-07-26 20:51:13 +0000
commit6c3caf2a9c6bbc07289941355fabfc61bc805601 (patch)
treed2c544a88bd4f70a6480a7010cf1a37f0a852f3f /gtk/gtktreestore.c
parentc8e242f14bbba315b4389df8bfffdb7a91b8c2b5 (diff)
downloadgtk+-6c3caf2a9c6bbc07289941355fabfc61bc805601.tar.gz
API additions: _move, _reorder and _swap for stores, path constructor.
Fri Jul 26 22:53:37 2002 Kristian Rietveld <kris@gtk.org> 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 <kris@gtk.org> 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 <kris@gtk.org> 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 <kris@gtk.org> 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).
Diffstat (limited to 'gtk/gtktreestore.c')
-rw-r--r--gtk/gtktreestore.c336
1 files changed, 333 insertions, 3 deletions
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,