summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--ChangeLog.pre-2-05
-rw-r--r--ChangeLog.pre-2-105
-rw-r--r--ChangeLog.pre-2-25
-rw-r--r--ChangeLog.pre-2-45
-rw-r--r--ChangeLog.pre-2-65
-rw-r--r--ChangeLog.pre-2-85
-rw-r--r--docs/reference/gtk/tmpl/gtktreeviewcolumn.sgml3
-rw-r--r--gtk/gtkliststore.c382
-rw-r--r--gtk/gtkmarshal.list1
-rw-r--r--gtk/gtkmarshalers.list1
-rw-r--r--gtk/gtktreedatalist.c26
-rw-r--r--gtk/gtktreedatalist.h9
-rw-r--r--gtk/gtktreemodel.c5
-rw-r--r--gtk/gtktreemodel.h2
-rw-r--r--gtk/gtktreesortable.h26
-rw-r--r--gtk/gtktreeview.c11
-rw-r--r--gtk/gtktreeviewcolumn.c88
-rw-r--r--gtk/gtktreeviewcolumn.h16
-rw-r--r--tests/Makefile.am17
-rw-r--r--tests/testtreesort.c127
21 files changed, 658 insertions, 91 deletions
diff --git a/ChangeLog b/ChangeLog
index 22114f22cf..9a2746c8f3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Tue Mar 27 20:55:29 2001 Jonathan Blandford <jrb@redhat.com>
+
+ * gtk/gtkliststore.c: More work on implementing sortable
+ interface.
+
Mon Mar 26 15:48:45 2001 Owen Taylor <otaylor@redhat.com>
* gtk/gtkwindow.c (gtk_window_list_toplevels): Don't
diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0
index 22114f22cf..9a2746c8f3 100644
--- a/ChangeLog.pre-2-0
+++ b/ChangeLog.pre-2-0
@@ -1,3 +1,8 @@
+Tue Mar 27 20:55:29 2001 Jonathan Blandford <jrb@redhat.com>
+
+ * gtk/gtkliststore.c: More work on implementing sortable
+ interface.
+
Mon Mar 26 15:48:45 2001 Owen Taylor <otaylor@redhat.com>
* gtk/gtkwindow.c (gtk_window_list_toplevels): Don't
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 22114f22cf..9a2746c8f3 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,8 @@
+Tue Mar 27 20:55:29 2001 Jonathan Blandford <jrb@redhat.com>
+
+ * gtk/gtkliststore.c: More work on implementing sortable
+ interface.
+
Mon Mar 26 15:48:45 2001 Owen Taylor <otaylor@redhat.com>
* gtk/gtkwindow.c (gtk_window_list_toplevels): Don't
diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2
index 22114f22cf..9a2746c8f3 100644
--- a/ChangeLog.pre-2-2
+++ b/ChangeLog.pre-2-2
@@ -1,3 +1,8 @@
+Tue Mar 27 20:55:29 2001 Jonathan Blandford <jrb@redhat.com>
+
+ * gtk/gtkliststore.c: More work on implementing sortable
+ interface.
+
Mon Mar 26 15:48:45 2001 Owen Taylor <otaylor@redhat.com>
* gtk/gtkwindow.c (gtk_window_list_toplevels): Don't
diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4
index 22114f22cf..9a2746c8f3 100644
--- a/ChangeLog.pre-2-4
+++ b/ChangeLog.pre-2-4
@@ -1,3 +1,8 @@
+Tue Mar 27 20:55:29 2001 Jonathan Blandford <jrb@redhat.com>
+
+ * gtk/gtkliststore.c: More work on implementing sortable
+ interface.
+
Mon Mar 26 15:48:45 2001 Owen Taylor <otaylor@redhat.com>
* gtk/gtkwindow.c (gtk_window_list_toplevels): Don't
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index 22114f22cf..9a2746c8f3 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -1,3 +1,8 @@
+Tue Mar 27 20:55:29 2001 Jonathan Blandford <jrb@redhat.com>
+
+ * gtk/gtkliststore.c: More work on implementing sortable
+ interface.
+
Mon Mar 26 15:48:45 2001 Owen Taylor <otaylor@redhat.com>
* gtk/gtkwindow.c (gtk_window_list_toplevels): Don't
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index 22114f22cf..9a2746c8f3 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,3 +1,8 @@
+Tue Mar 27 20:55:29 2001 Jonathan Blandford <jrb@redhat.com>
+
+ * gtk/gtkliststore.c: More work on implementing sortable
+ interface.
+
Mon Mar 26 15:48:45 2001 Owen Taylor <otaylor@redhat.com>
* gtk/gtkwindow.c (gtk_window_list_toplevels): Don't
diff --git a/docs/reference/gtk/tmpl/gtktreeviewcolumn.sgml b/docs/reference/gtk/tmpl/gtktreeviewcolumn.sgml
index 25628f2eaf..1164d6817b 100644
--- a/docs/reference/gtk/tmpl/gtktreeviewcolumn.sgml
+++ b/docs/reference/gtk/tmpl/gtktreeviewcolumn.sgml
@@ -34,7 +34,6 @@ GtkTreeViewColumn
@alignment:
@window:
@xalign:
-@id:
@width:
@min_width:
@max_width:
@@ -46,6 +45,8 @@ GtkTreeViewColumn
@cell:
@attributes:
@column_type:
+@sort_signal:
+@sort_column_id:
@sort_order:
@visible:
@button_active:
diff --git a/gtk/gtkliststore.c b/gtk/gtkliststore.c
index e3153e52e8..5d7b7878cc 100644
--- a/gtk/gtkliststore.c
+++ b/gtk/gtkliststore.c
@@ -26,6 +26,7 @@
#include <gobject/gvaluecollector.h>
#define G_SLIST(x) ((GSList *) x)
+#define GTK_LIST_STORE_IS_SORTED(list) (GTK_LIST_STORE (list)->sort_column_id != -1)
static void gtk_list_store_init (GtkListStore *list_store);
static void gtk_list_store_class_init (GtkListStoreClass *class);
@@ -79,6 +80,9 @@ static gboolean gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest,
GtkTreePath *dest_path);
/* sortable */
+static void gtk_list_store_sort (GtkListStore *list_store);
+static void gtk_list_store_sort_iter_changed (GtkListStore *list_store,
+ GtkTreeIter *iter);
static gboolean gtk_list_store_get_sort_column_id (GtkTreeSortable *sortable,
gint *sort_column_id,
GtkTreeSortOrder *order);
@@ -93,13 +97,14 @@ static void gtk_list_store_sort_column_id_set_func (GtkTreeSortable *
+
static void
validate_list_store (GtkListStore *list_store)
{
if (gtk_debug_flags & GTK_DEBUG_TREE)
{
g_assert (g_slist_length (list_store->root) == list_store->length);
-
+
g_assert (g_slist_last (list_store->root) == list_store->tail);
}
}
@@ -237,7 +242,7 @@ gtk_list_store_init (GtkListStore *list_store)
* i.e. all cells in a column have the same type such as #G_TYPE_STRING or
* #GDK_TYPE_PIXBUF. Use #GtkListStore to store data to be displayed in a
* #GtkTreeView.
- *
+ *
* Return value: a new #GtkListStore
**/
GtkListStore *
@@ -255,8 +260,8 @@ gtk_list_store_new (void)
* simultaneously setting up the columns and column types as with
* gtk_list_store_set_n_columns() and
* gtk_list_store_set_column_type().
- *
- *
+ *
+ *
* Return value: a new #GtkListStore
**/
GtkListStore *
@@ -298,7 +303,7 @@ gtk_list_store_new_with_types (gint n_columns,
* @n_columns: number of columns
*
* Sets the number of columns in the #GtkListStore.
- *
+ *
**/
void
gtk_list_store_set_n_columns (GtkListStore *list_store,
@@ -344,7 +349,7 @@ gtk_list_store_set_n_columns (GtkListStore *list_store,
* %G_TYPE_CHAR, %G_TYPE_BOOLEAN, %G_TYPE_POINTER, %G_TYPE_FLOAT,
* %G_TYPE_DOUBLE, %G_TYPE_STRING, %G_TYPE_OBJECT, and %G_TYPE_BOXED, along with
* subclasses of those types such as %GDK_TYPE_PIXBUF.
- *
+ *
**/
void
gtk_list_store_set_column_type (GtkListStore *list_store,
@@ -398,21 +403,21 @@ gtk_list_store_get_iter (GtkTreeModel *tree_model,
{
GSList *list;
gint i;
-
+
g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
- g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
+ g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
i = gtk_tree_path_get_indices (path)[0];
if (i >= GTK_LIST_STORE (tree_model)->length)
return FALSE;
-
+
list = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
i);
/* If this fails, list_store->length has gotten mangled. */
g_assert (list);
-
+
iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
iter->user_data = list;
return TRUE;
@@ -497,7 +502,7 @@ gtk_list_store_iter_children (GtkTreeModel *tree_model,
/* but if parent == NULL we return the list itself as children of the
* "root"
*/
-
+
if (GTK_LIST_STORE (tree_model)->root)
{
iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
@@ -532,7 +537,7 @@ gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
gint n)
{
GSList *child;
-
+
g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
if (parent)
@@ -573,7 +578,7 @@ gtk_list_store_iter_parent (GtkTreeModel *tree_model,
* Sets the data in the cell specified by @iter and @column.
* The type of @value must be convertible to the type of the
* column.
- *
+ *
**/
void
gtk_list_store_set_value (GtkListStore *list_store,
@@ -667,6 +672,9 @@ gtk_list_store_set_value (GtkListStore *list_store,
gtk_tree_path_free (path);
if (converted)
g_value_unset (&real_value);
+
+ if (GTK_LIST_STORE_IS_SORTED (list_store))
+ gtk_list_store_sort_iter_changed (list_store, iter);
}
/**
@@ -677,7 +685,7 @@ gtk_list_store_set_value (GtkListStore *list_store,
*
* See gtk_list_store_set(); this version takes a va_list for
* use by language bindings.
- *
+ *
**/
void
gtk_list_store_set_valist (GtkListStore *list_store,
@@ -730,7 +738,7 @@ gtk_list_store_set_valist (GtkListStore *list_store,
* @list_store: a #GtkListStore
* @iter: row iterator
* @Varargs: pairs of column number and value, terminated with -1
- *
+ *
* Sets the value of one or more cells in the row referenced by @iter.
* The variable argument list should contain integer column numbers,
* each column number followed by the value to be set.
@@ -782,7 +790,7 @@ remove_link_saving_prev (GSList *list,
}
*prevp = prev;
-
+
return list;
}
@@ -800,17 +808,17 @@ gtk_list_store_remove_silently (GtkListStore *list_store,
{
GSList *prev = NULL;
-
+
list_store->root = remove_link_saving_prev (G_SLIST (list_store->root),
G_SLIST (iter->user_data),
&prev);
list_store->length -= 1;
-
+
if (iter->user_data == list_store->tail)
list_store->tail = prev;
}
-
+
list_store->stamp ++;
}
@@ -821,7 +829,7 @@ gtk_list_store_remove_silently (GtkListStore *list_store,
*
* Removes the given row from the list store, emitting the
* "deleted" signal on #GtkTreeModel.
- *
+ *
**/
void
gtk_list_store_remove (GtkListStore *list_store,
@@ -831,15 +839,15 @@ gtk_list_store_remove (GtkListStore *list_store,
g_return_if_fail (list_store != NULL);
g_return_if_fail (GTK_IS_LIST_STORE (list_store));
- g_return_if_fail (iter->user_data != NULL);
+ g_return_if_fail (iter->user_data != NULL);
path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
validate_list_store (list_store);
-
+
gtk_list_store_remove_silently (list_store, iter, path);
- validate_list_store (list_store);
+ validate_list_store (list_store);
gtk_tree_model_deleted (GTK_TREE_MODEL (list_store), path);
@@ -853,7 +861,7 @@ insert_after (GtkListStore *list_store,
{
g_return_if_fail (sibling != NULL);
g_return_if_fail (new_list != NULL);
-
+
/* insert new node after list */
new_list->next = sibling->next;
sibling->next = new_list;
@@ -874,7 +882,7 @@ insert_after (GtkListStore *list_store,
* Creates a new row at @position, initializing @iter to point to the
* new row, and emitting the "inserted" signal from the #GtkTreeModel
* interface.
- *
+ *
**/
void
gtk_list_store_insert (GtkListStore *list_store,
@@ -884,13 +892,14 @@ gtk_list_store_insert (GtkListStore *list_store,
GSList *list;
GtkTreePath *path;
GSList *new_list;
-
+
g_return_if_fail (list_store != NULL);
g_return_if_fail (GTK_IS_LIST_STORE (list_store));
g_return_if_fail (iter != NULL);
g_return_if_fail (position >= 0);
- if (position == 0)
+ if (position == 0 ||
+ GTK_LIST_STORE_IS_SORTED (list_store))
{
gtk_list_store_prepend (list_store, iter);
return;
@@ -907,12 +916,12 @@ gtk_list_store_insert (GtkListStore *list_store,
}
insert_after (list_store, list, new_list);
-
+
iter->stamp = list_store->stamp;
iter->user_data = new_list;
validate_list_store (list_store);
-
+
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, position);
gtk_tree_model_inserted (GTK_TREE_MODEL (list_store), path, iter);
@@ -928,7 +937,7 @@ gtk_list_store_insert (GtkListStore *list_store,
* Inserts a new row before @sibling, initializing @iter to point to
* the new row, and emitting the "inserted" signal from the
* #GtkTreeModel interface.
- *
+ *
**/
void
gtk_list_store_insert_before (GtkListStore *list_store,
@@ -943,12 +952,18 @@ gtk_list_store_insert_before (GtkListStore *list_store,
g_return_if_fail (GTK_IS_LIST_STORE (list_store));
g_return_if_fail (iter != NULL);
+ if (GTK_LIST_STORE_IS_SORTED (list_store))
+ {
+ gtk_list_store_prepend (list_store, iter);
+ return;
+ }
+
if (sibling == NULL)
{
gtk_list_store_append (list_store, iter);
return;
}
-
+
new_list = g_slist_alloc ();
prev = NULL;
@@ -973,7 +988,7 @@ gtk_list_store_insert_before (GtkListStore *list_store,
if (list_store->root == NULL)
list_store->tail = new_list;
-
+
if (prev)
{
new_list->next = prev->next;
@@ -991,7 +1006,7 @@ gtk_list_store_insert_before (GtkListStore *list_store,
list_store->length += 1;
validate_list_store (list_store);
-
+
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, i);
gtk_tree_model_inserted (GTK_TREE_MODEL (list_store), path, iter);
@@ -1007,7 +1022,7 @@ gtk_list_store_insert_before (GtkListStore *list_store,
* Inserts a new row after @sibling, initializing @iter to point to
* the new row, and emitting the "inserted" signal from the
* #GtkTreeModel interface.
- *
+ *
**/
void
gtk_list_store_insert_after (GtkListStore *list_store,
@@ -1024,7 +1039,8 @@ gtk_list_store_insert_after (GtkListStore *list_store,
if (sibling)
g_return_if_fail (sibling->stamp == list_store->stamp);
- if (sibling == NULL)
+ if (sibling == NULL ||
+ GTK_LIST_STORE_IS_SORTED (list_store))
{
gtk_list_store_prepend (list_store, iter);
return;
@@ -1038,12 +1054,12 @@ gtk_list_store_insert_after (GtkListStore *list_store,
new_list = g_slist_alloc ();
insert_after (list_store, list, new_list);
-
+
iter->stamp = list_store->stamp;
iter->user_data = new_list;
validate_list_store (list_store);
-
+
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, i);
gtk_tree_model_inserted (GTK_TREE_MODEL (list_store), path, iter);
@@ -1058,7 +1074,7 @@ gtk_list_store_insert_after (GtkListStore *list_store,
* Prepends a row to @store, initializing @iter to point to the
* new row, and emitting the "inserted" signal on the #GtkTreeModel
* interface for the @store.
- *
+ *
**/
void
gtk_list_store_prepend (GtkListStore *list_store,
@@ -1075,14 +1091,14 @@ gtk_list_store_prepend (GtkListStore *list_store,
if (list_store->root == NULL)
list_store->tail = iter->user_data;
-
+
G_SLIST (iter->user_data)->next = G_SLIST (list_store->root);
list_store->root = iter->user_data;
list_store->length += 1;
validate_list_store (list_store);
-
+
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, 0);
gtk_tree_model_inserted (GTK_TREE_MODEL (list_store), path, iter);
@@ -1097,7 +1113,7 @@ gtk_list_store_prepend (GtkListStore *list_store,
* Appends a row to @store, initializing @iter to point to the
* new row, and emitting the "inserted" signal on the #GtkTreeModel
* interface for the @store.
- *
+ *
**/
void
gtk_list_store_append (GtkListStore *list_store,
@@ -1109,6 +1125,12 @@ gtk_list_store_append (GtkListStore *list_store,
g_return_if_fail (GTK_IS_LIST_STORE (list_store));
g_return_if_fail (iter != NULL);
+ if (GTK_LIST_STORE_IS_SORTED (list_store))
+ {
+ gtk_list_store_prepend (list_store, iter);
+ return;
+ }
+
iter->stamp = list_store->stamp;
iter->user_data = g_slist_alloc ();
@@ -1122,7 +1144,7 @@ gtk_list_store_append (GtkListStore *list_store,
list_store->length += 1;
validate_list_store (list_store);
-
+
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, list_store->length - 1);
gtk_tree_model_inserted (GTK_TREE_MODEL (list_store), path, iter);
@@ -1135,7 +1157,7 @@ gtk_list_store_drag_data_delete (GtkTreeDragSource *drag_source,
{
GtkTreeIter iter;
g_return_val_if_fail (GTK_IS_LIST_STORE (drag_source), FALSE);
-
+
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source),
&iter,
path))
@@ -1187,12 +1209,12 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
GtkTreeModel *src_model = NULL;
GtkTreePath *src_path = NULL;
gboolean retval = FALSE;
-
+
g_return_val_if_fail (GTK_IS_LIST_STORE (drag_dest), FALSE);
tree_model = GTK_TREE_MODEL (drag_dest);
list_store = GTK_LIST_STORE (drag_dest);
-
+
if (gtk_selection_data_get_tree_row (selection_data,
&src_model,
&src_path) &&
@@ -1202,7 +1224,7 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
GtkTreeIter src_iter;
GtkTreeIter dest_iter;
GtkTreePath *prev;
-
+
if (!gtk_tree_model_get_iter (src_model,
&src_iter,
src_path))
@@ -1220,7 +1242,7 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
*/
gtk_list_store_prepend (GTK_LIST_STORE (tree_model),
&dest_iter);
-
+
retval = TRUE;
}
else
@@ -1238,7 +1260,7 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
}
gtk_tree_path_free (prev);
-
+
/* If we succeeded in creating dest_iter, copy data from src
*/
if (retval)
@@ -1255,7 +1277,7 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
{
copy_iter = _gtk_tree_data_list_node_copy (dl,
list_store->column_headers[col]);
-
+
if (copy_head == NULL)
copy_head = copy_iter;
@@ -1267,7 +1289,7 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
dl = dl->next;
++col;
}
-
+
G_SLIST (dest_iter.user_data)->data = copy_head;
path = gtk_list_store_get_path (GTK_TREE_MODEL (tree_model), &dest_iter);
@@ -1283,11 +1305,11 @@ gtk_list_store_drag_data_received (GtkTreeDragDest *drag_dest,
}
out:
-
+
if (src_path)
gtk_tree_path_free (src_path);
-
- return retval;
+
+ return retval;
}
static gboolean
@@ -1297,12 +1319,12 @@ gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest,
GtkTreePath *dest_path)
{
gint *indices;
-
+
g_return_val_if_fail (GTK_IS_LIST_STORE (drag_dest), FALSE);
if (src_model != GTK_TREE_MODEL (drag_dest))
return FALSE;
-
+
if (gtk_tree_path_get_depth (dest_path) != 1)
return FALSE;
@@ -1316,7 +1338,250 @@ gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest,
return FALSE;
}
+
/* Sorting */
+typedef struct _SortTuple
+{
+ gint offset;
+ GSList *el;
+} SortTuple;
+
+static gint
+_gtk_list_store_compare_func (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data)
+{
+ GtkListStore *list_store = user_data;
+ GtkTreeDataSortHeader *header = NULL;
+ GSList *el_a; /* Los Angeles? */
+ GSList *el_b;
+ GtkTreeIter iter_a;
+ GtkTreeIter iter_b;
+ gint retval;
+
+ header = _gtk_tree_data_list_get_header (list_store->sort_list,
+ list_store->sort_column_id);
+
+ g_return_val_if_fail (header != NULL, 0);
+ g_return_val_if_fail (header->func != NULL, 0);
+
+ el_a = ((SortTuple *) a)->el;
+ el_b = ((SortTuple *) b)->el;
+
+ iter_a.stamp = list_store->stamp;
+ iter_a.user_data = el_a;
+ iter_b.stamp = list_store->stamp;
+ iter_b.user_data = el_b;
+
+ retval = (* header->func) (GTK_TREE_MODEL (list_store),
+ &iter_a, &iter_b,
+ header->data);
+
+ if (list_store->order == GTK_TREE_SORT_DESCENDING)
+ {
+ if (retval > 0)
+ retval = -1;
+ else if (retval < 0)
+ retval = 1;
+ }
+ return retval;
+}
+
+static void
+gtk_list_store_sort (GtkListStore *list_store)
+{
+ GtkTreeDataSortHeader *header = NULL;
+ GArray *sort_array;
+ gint i;
+ GList *header_list;
+ gint *new_order;
+ GSList *list;
+ GtkTreePath *path;
+
+ if (list_store->length <= 1)
+ return;
+
+ g_assert (GTK_LIST_STORE_IS_SORTED (list_store));
+
+ for (header_list = list_store->sort_list; header_list; header_list = header_list->next)
+ {
+ header = (GtkTreeDataSortHeader*) header_list->data;
+ if (header->sort_column_id == list_store->sort_column_id)
+ break;
+ }
+
+ /* We want to make sure that we have a function */
+ g_return_if_fail (header != NULL);
+ g_return_if_fail (header->func != NULL);
+
+ list = G_SLIST (list_store->root);
+
+ sort_array = g_array_sized_new (FALSE, FALSE,
+ sizeof (SortTuple),
+ list_store->length);
+
+ for (i = 0; i < list_store->length; i++)
+ {
+ SortTuple tuple;
+
+ /* If this fails, we are in an inconsistent state. Bad */
+ g_return_if_fail (list != NULL);
+
+ tuple.offset = i;
+ tuple.el = list;
+ g_array_append_val (sort_array, tuple);
+
+ list = list->next;
+ }
+
+ g_array_sort_with_data (sort_array, _gtk_list_store_compare_func, list_store);
+
+ for (i = 0; i < list_store->length - 1; i++)
+ g_array_index (sort_array, SortTuple, i).el->next =
+ g_array_index (sort_array, SortTuple, i + 1).el;
+ g_array_index (sort_array, SortTuple, list_store->length - 1).el->next = NULL;
+ list_store->root = g_array_index (sort_array, SortTuple, 0).el;
+
+ /* Let the world know about our new order */
+ new_order = g_new (gint, list_store->length);
+ for (i = 0; i < list_store->length; i++)
+ new_order[i] = g_array_index (sort_array, SortTuple, i).offset;
+ path = gtk_tree_path_new ();
+ gtk_tree_model_reordered (GTK_TREE_MODEL (list_store),
+ path, new_order);
+ gtk_tree_path_free (path);
+ g_free (new_order);
+ g_array_free (sort_array, TRUE);
+}
+
+static void
+gtk_list_store_sort_iter_changed (GtkListStore *list_store,
+ GtkTreeIter *iter)
+
+{
+ GtkTreeDataSortHeader *header;
+ GSList *prev = NULL;
+ GSList *next = NULL;
+ GSList *list = G_SLIST (list_store->root);
+
+ GtkTreeIter tmp_iter;
+ gint cmp_a = 0;
+ gint cmp_b = 0;
+
+ if (list_store->length < 2)
+ return;
+
+ tmp_iter.stamp = list_store->stamp;
+ header = _gtk_tree_data_list_get_header (list_store->sort_list,
+ list_store->sort_column_id);
+ g_return_if_fail (header != NULL);
+ g_return_if_fail (header->func != NULL);
+
+ /* First we find the iter, its prev, and its next */
+ while (list)
+ {
+ if (list == G_SLIST (iter->user_data))
+ break;
+ prev = list;
+ list = list->next;
+ }
+ g_assert (list != NULL);
+
+ next = list->next;
+
+ /* Check the common case, where we don't need to sort it moved. */
+ if (prev != NULL)
+ {
+ tmp_iter.user_data = prev;
+ cmp_a = (* header->func) (GTK_TREE_MODEL (list_store),
+ &tmp_iter, iter,
+ header->data);
+ }
+
+ if (next != NULL)
+ {
+ tmp_iter.user_data = next;
+ cmp_b = (* header->func) (GTK_TREE_MODEL (list_store),
+ iter, &tmp_iter,
+ header->data);
+ }
+
+
+ if (list_store->order == GTK_TREE_SORT_DESCENDING)
+ {
+ if (cmp_a < 0)
+ cmp_a = 1;
+ else if (cmp_a > 0)
+ cmp_a = -1;
+
+ if (cmp_b < 0)
+ cmp_b = 1;
+ else if (cmp_b > 0)
+ cmp_b = -1;
+
+ }
+
+ if (prev == NULL && cmp_b <= 0)
+ return;
+ else if (next == NULL && cmp_a <= 0)
+ return;
+ else if (prev != NULL && next != NULL &&
+ cmp_a <= 0 && cmp_b <= 0)
+ return;
+
+ /* We actually need to sort it */
+ /* First, remove the old link. */
+
+ if (prev == NULL)
+ list_store->root = next;
+ else
+ prev->next = next;
+ if (next == NULL)
+ list_store->tail = prev;
+ list->next = NULL;
+
+ /* FIXME: as an optimization, we can potentially start at next */
+ prev = NULL;
+ list = G_SLIST (list_store->root);
+
+ tmp_iter.user_data = list;
+ if (list_store->order == GTK_TREE_SORT_DESCENDING)
+ cmp_a = (* header->func) (GTK_TREE_MODEL (list_store),
+ &tmp_iter, iter, header->data);
+ else
+ cmp_a = (* header->func) (GTK_TREE_MODEL (list_store),
+ iter, &tmp_iter, header->data);
+
+ while ((list->next) && (cmp_a > 0))
+ {
+ prev = list;
+ list = list->next;
+ tmp_iter.user_data = list;
+ if (list_store->order == GTK_TREE_SORT_DESCENDING)
+ cmp_a = (* header->func) (GTK_TREE_MODEL (list_store),
+ &tmp_iter, iter, header->data);
+ else
+ cmp_a = (* header->func) (GTK_TREE_MODEL (list_store),
+ iter, &tmp_iter, header->data);
+ }
+
+ if ((!list->next) && (cmp_a > 0))
+ {
+ list->next = G_SLIST (iter->user_data);
+ list_store->tail = list->next;
+ }
+ else if (prev)
+ {
+ prev->next = G_SLIST (iter->user_data);
+ G_SLIST (iter->user_data)->next = list;
+ }
+ else
+ {
+ G_SLIST (iter->user_data)->next = G_SLIST (list_store->root);
+ list_store->root = G_SLIST (iter->user_data);
+ }
+}
+
static gboolean
gtk_list_store_get_sort_column_id (GtkTreeSortable *sortable,
gint *sort_column_id,
@@ -1356,8 +1621,15 @@ gtk_list_store_set_sort_column_id (GtkTreeSortable *sortable,
}
g_return_if_fail (list != NULL);
+ if ((list_store->sort_column_id == sort_column_id) &&
+ (list_store->order == order))
+ return;
+
list_store->sort_column_id = sort_column_id;
list_store->order = order;
+
+ if (list_store->sort_column_id >= 0)
+ gtk_list_store_sort (list_store);
}
static void
diff --git a/gtk/gtkmarshal.list b/gtk/gtkmarshal.list
index 26e90358ff..43aabf179d 100644
--- a/gtk/gtkmarshal.list
+++ b/gtk/gtkmarshal.list
@@ -38,6 +38,7 @@ NONE:STRING,INT,POINTER
VOID:BOOLEAN
VOID:BOXED
VOID:BOXED,BOXED
+VOID:BOXED,BOXED,POINTER
VOID:BOXED,POINTER
VOID:BOXED,OBJECT
VOID:BOXED,STRING,INT
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index 26e90358ff..43aabf179d 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -38,6 +38,7 @@ NONE:STRING,INT,POINTER
VOID:BOOLEAN
VOID:BOXED
VOID:BOXED,BOXED
+VOID:BOXED,BOXED,POINTER
VOID:BOXED,POINTER
VOID:BOXED,OBJECT
VOID:BOXED,STRING,INT
diff --git a/gtk/gtktreedatalist.c b/gtk/gtktreedatalist.c
index 0bf6152665..81596e6ede 100644
--- a/gtk/gtktreedatalist.c
+++ b/gtk/gtktreedatalist.c
@@ -264,7 +264,8 @@ gtk_tree_data_list_compare_func (GtkTreeModel *model,
GValue a_value = {0, };
GValue b_value = {0, };
gint retval;
-
+ gchar *stra, *strb;
+
gtk_tree_model_get_value (model, a, column, &a_value);
gtk_tree_model_get_value (model, b, column, &b_value);
@@ -299,7 +300,13 @@ gtk_tree_data_list_compare_func (GtkTreeModel *model,
retval = (g_value_get_double (&a_value) < g_value_get_double (&b_value));
break;
case G_TYPE_STRING:
- retval = strcmp (g_value_get_string (&a_value), g_value_get_string (&b_value));
+ stra = g_value_get_string (&a_value);
+ strb = g_value_get_string (&b_value);
+ if (stra == NULL)
+ stra = "";
+ if (strb == NULL)
+ strb = "";
+ retval = strcmp (stra, strb);
break;
case G_TYPE_POINTER:
case G_TYPE_BOXED:
@@ -356,3 +363,18 @@ _gtk_tree_data_list_header_free (GList *list)
}
g_list_free (list);
}
+
+GtkTreeDataSortHeader *
+_gtk_tree_data_list_get_header (GList *header_list,
+ gint sort_column_id)
+{
+ GtkTreeDataSortHeader *header = NULL;
+
+ for (; header_list; header_list = header_list->next)
+ {
+ header = (GtkTreeDataSortHeader*) header_list->data;
+ if (header->sort_column_id == sort_column_id)
+ return header;
+ }
+ return NULL;
+}
diff --git a/gtk/gtktreedatalist.h b/gtk/gtktreedatalist.h
index 9294395347..7d725d8d3e 100644
--- a/gtk/gtktreedatalist.h
+++ b/gtk/gtktreedatalist.h
@@ -63,8 +63,11 @@ GtkTreeDataList *_gtk_tree_data_list_node_copy (GtkTreeDataList *list,
GType type);
/* Header code */
-GList *_gtk_tree_data_list_header_new (gint n_columns,
- GType *types);
-void _gtk_tree_data_list_header_free (GList *header_list);
+GList * _gtk_tree_data_list_header_new (gint n_columns,
+ GType *types);
+void _gtk_tree_data_list_header_free (GList *header_list);
+GtkTreeDataSortHeader *_gtk_tree_data_list_get_header (GList *header_list,
+ gint sort_column_id);
+
#endif /* __GTK_TREE_DATA_LIST_H__ */
diff --git a/gtk/gtktreemodel.c b/gtk/gtktreemodel.c
index 68c2d0f2e2..0e21974d0f 100644
--- a/gtk/gtktreemodel.c
+++ b/gtk/gtktreemodel.c
@@ -112,9 +112,10 @@ gtk_tree_model_base_init (gpointer g_class)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeModelIface, reordered),
NULL, NULL,
- gtk_marshal_VOID__BOXED_POINTER,
- G_TYPE_NONE, 2,
+ gtk_marshal_VOID__BOXED_BOXED_POINTER,
+ G_TYPE_NONE, 3,
GTK_TYPE_TREE_PATH,
+ GTK_TYPE_TREE_ITER,
G_TYPE_POINTER);
initialized = TRUE;
}
diff --git a/gtk/gtktreemodel.h b/gtk/gtktreemodel.h
index 4aaac7d834..80ed13aa61 100644
--- a/gtk/gtktreemodel.h
+++ b/gtk/gtktreemodel.h
@@ -69,6 +69,7 @@ struct _GtkTreeModelIface
GtkTreePath *path);
void (* reordered) (GtkTreeModel *tree_model,
GtkTreePath *path,
+ GtkTreeIter *iter,
gint *new_order);
/* Virtual Table */
@@ -219,6 +220,7 @@ void gtk_tree_model_deleted (GtkTreeModel *tree_model,
GtkTreePath *path);
void gtk_tree_model_reordered (GtkTreeModel *tree_model,
GtkTreePath *path,
+ GtkTreeIter *iter,
gint *new_order);
diff --git a/gtk/gtktreesortable.h b/gtk/gtktreesortable.h
index 85369b9bd7..b417f9aba2 100644
--- a/gtk/gtktreesortable.h
+++ b/gtk/gtktreesortable.h
@@ -28,7 +28,6 @@ extern "C" {
typedef enum
{
- GTK_TREE_SORT_NONE,
GTK_TREE_SORT_ASCENDING,
GTK_TREE_SORT_DESCENDING
} GtkTreeSortOrder;
@@ -71,19 +70,20 @@ struct _GtkTreeSortableIface
};
-GType gtk_tree_sortable_get_type (void) G_GNUC_CONST;
+GType gtk_tree_sortable_get_type (void) G_GNUC_CONST;
+
+gboolean gtk_tree_sortable_get_sort_column_id (GtkTreeSortable *sortable,
+ gint *sort_column_id,
+ GtkTreeSortOrder *order);
+void gtk_tree_sortable_set_sort_column_id (GtkTreeSortable *sortable,
+ gint sort_column_id,
+ GtkTreeSortOrder order);
+void gtk_tree_sortable_sort_column_id_set_func (GtkTreeSortable *sortable,
+ gint sort_column_id,
+ GtkTreeIterCompareFunc func,
+ gpointer data,
+ GtkDestroyNotify destroy);
-gboolean gtk_tree_sortable_get_sort_id (GtkTreeSortable *sortable,
- gint *sort_column_id,
- GtkTreeSortOrder *order);
-void gtk_tree_sortable_set_sort_id (GtkTreeSortable *sortable,
- gint sort_column_id,
- GtkTreeSortOrder order);
-void gtk_tree_sortable_sort_id_set_func (GtkTreeSortable *sortable,
- gint sort_column_id,
- GtkTreeIterCompareFunc func,
- gpointer data,
- GtkDestroyNotify destroy);
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index fc9412b5df..60dea96e90 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -3011,6 +3011,17 @@ gtk_tree_view_reordered (GtkTreeModel *model,
GtkTreePath *parent,
gint *new_order)
{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (model);
+ GtkTreeIter iter;
+ GArray *array;
+ gint len;
+
+ gtk_tree_model_get_iter (model, parent, &iter);
+ len = gtk_tree_model_iter_n_children (model, &iter);
+
+ if (len < 2)
+ return;
+
}
diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c
index 528035c167..e97a32e3de 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -252,6 +252,8 @@ gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
tree_column->dirty = TRUE;
tree_column->sort_order = GTK_TREE_SORT_ASCENDING;
tree_column->show_sort_indicator = FALSE;
+ tree_column->sort_signal = 0;
+ tree_column->sort_column_id = -1;
}
static void
@@ -1478,6 +1480,79 @@ gtk_tree_view_column_get_alignment (GtkTreeViewColumn *tree_column)
return tree_column->xalign;
}
+
+static void
+sort_clicked_func (GtkTreeViewColumn *tree_column,
+ gpointer data)
+{
+ GList *list;
+
+ g_return_if_fail (tree_column->tree_view != NULL);
+
+ if (tree_column->show_sort_indicator)
+ {
+ if (tree_column->sort_order == GTK_TREE_SORT_ASCENDING)
+ gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_DESCENDING);
+ else
+ gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_ASCENDING);
+ }
+ else
+ {
+ gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_ASCENDING);
+ gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
+ }
+
+ list = (GTK_TREE_VIEW (tree_column->tree_view)->priv->columns);
+ g_assert (list);
+ while (list)
+ {
+ GtkTreeViewColumn *tmp_column;
+
+ tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
+ if (tmp_column->visible && tmp_column != tree_column)
+ gtk_tree_view_column_set_sort_indicator (tmp_column, FALSE);
+
+ list = list->next;
+ }
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
+ tree_column->sort_column_id,
+ tree_column->sort_order);
+}
+
+/**
+ * gtk_tree_view_column_set_sort_column_id:
+ * @tree_column: a #GtkTreeViewColumn
+ * @sort_column_id: The sort_column_id of the model to sort on.
+ *
+ * Sets the sort_column_id that the column sorts on.
+ **/
+void
+gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column,
+ gint sort_column_id)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
+ g_return_if_fail (sort_column_id >= 0);
+
+ if (tree_column->sort_column_id == sort_column_id)
+ return;
+
+ if (sort_column_id == -1)
+ {
+ if (tree_column->sort_signal)
+ g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_signal);
+ return;
+ }
+
+ if (! tree_column->sort_signal)
+ tree_column->sort_signal = g_signal_connectc (G_OBJECT (tree_column),
+ "clicked",
+ G_CALLBACK (sort_clicked_func),
+ NULL, FALSE);
+ tree_column->sort_column_id = sort_column_id;
+ gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
+ gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_ASCENDING);
+}
+
/**
* gtk_tree_view_column_set_sort_indicator:
* @tree_column: a #GtkTreeViewColumn
@@ -1531,12 +1606,13 @@ gtk_tree_view_column_get_sort_indicator (GtkTreeViewColumn *tree_column)
* @order: sort order that the sort indicator should indicate
*
* Changes the appearance of the sort indicator. (This <emphasis>does
- * not</emphasis> actually sort the model - for the models shipped
- * with GTK+, use at gtk_tree_sortable_set_sort_column() to do
- * that. For custom models, the mechanism will vary.) The sort
- * indicator changes direction to indicate normal sort or reverse
- * sort. Note that you must have the sort indicator enabled to see
- * anything when calling this function; see
+ * not</emphasis> actually sort the model. Use
+ * gtk_tree_view_column_set_sort_column_id() if you want automatic sorting
+ * support. This function is primarily for custom sorting behavior, and should
+ * be used in conjunction with #gtk_tree_sortable_set_sort_column() to do
+ * that. For custom models, the mechanism will vary.) The sort indicator changes
+ * direction to indicate normal sort or reverse sort. Note that you must have
+ * the sort indicator enabled to see anything when calling this function; see
* gtk_tree_view_column_set_sort_indicator().
*
**/
diff --git a/gtk/gtktreeviewcolumn.h b/gtk/gtktreeviewcolumn.h
index 36677c2da5..1eaaf2d03b 100644
--- a/gtk/gtktreeviewcolumn.h
+++ b/gtk/gtktreeviewcolumn.h
@@ -64,8 +64,6 @@ struct _GtkTreeViewColumn
GdkWindow *window;
gfloat xalign;
- gint id;
-
gint width;
gint min_width;
gint max_width;
@@ -78,7 +76,13 @@ struct _GtkTreeViewColumn
GtkCellRenderer *cell;
GSList *attributes;
GtkTreeViewColumnSizing column_type;
+
+ /* Sorting */
+ guint sort_signal;
+ gint sort_column_id;
GtkTreeSortOrder sort_order;
+
+
guint visible : 1;
guint button_active : 1;
guint dirty : 1;
@@ -147,6 +151,14 @@ GtkWidget *gtk_tree_view_column_get_widget (GtkTreeViewColumn
void gtk_tree_view_column_set_alignment (GtkTreeViewColumn *tree_column,
gfloat xalign);
gfloat gtk_tree_view_column_get_alignment (GtkTreeViewColumn *tree_column);
+
+
+/* You probably only want to use gtk_tree_view_column_set_sort_column_id. The
+ * other sorting functions exist primarily to let others do their own custom sorting.
+ */
+
+void gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column,
+ gint sort_column_id);
void gtk_tree_view_column_set_sort_indicator (GtkTreeViewColumn *tree_column,
gboolean setting);
gboolean gtk_tree_view_column_get_sort_indicator (GtkTreeViewColumn *tree_column);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 673df78590..d60330472b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -31,21 +31,24 @@ LDADDS = @STRIP_BEGIN@ \
@STRIP_END@
noinst_PROGRAMS = \
- testsocket \
- testsocket_child \
+## testsocket \
+## testsocket_child \
testtreeview \
testtreefocus \
- testtreecolumns
+ testtreecolumns \
+ testtreesort
-testsocket_DEPENDENCIES = $(DEPS)
-testsocket_child_DEPENDENCIES = $(DEPS)
+#testsocket_DEPENDENCIES = $(DEPS)
+#testsocket_child_DEPENDENCIES = $(DEPS)
testtreeview_DEPENDENCIES = $(DEPS)
testtreefocus_DEPENDENCIES = $(DEPS)
testtreecolumns_DEPENDENCIES = $(DEPS)
+testtreesort_DEPENDENCIES = $(DEPS)
-testsocket_LDADD = $(LDADDS)
-testsocket_child_LDADD = $(LDADDS)
+#testsocket_LDADD = $(LDADDS)
+#testsocket_child_LDADD = $(LDADDS)
testtreeview_LDADD = $(LDADDS)
testtreefocus_LDADD = $(LDADDS)
testtreecolumns_LDADD = $(LDADDS)
+testtreesort_LDADD = $(LDADDS)
diff --git a/tests/testtreesort.c b/tests/testtreesort.c
new file mode 100644
index 0000000000..2a4e74b660
--- /dev/null
+++ b/tests/testtreesort.c
@@ -0,0 +1,127 @@
+#include <gtk/gtk.h>
+
+
+typedef struct _ListSort ListSort;
+struct _ListSort
+{
+ const gchar *word_1;
+ const gchar *word_2;
+ const gchar *word_3;
+ const gchar *word_4;
+};
+
+static ListSort data[] =
+{
+ { "Apples", "Transmorgrify", "Exculpatory", "Gesundheit"},
+ { "Oranges", "Wicker", "Adamantine", "Convivial" },
+ { "Bovine Spongiform Encephilopathy", "Sleazebucket", "Mountaineer", "Pander" },
+ { "Foot and Mouth", "Lampshade", "Skim Milk\nFull Milk", "Viewless" },
+ { "Blood,\nsweat,\ntears", "The Man", "Horses", "Muckety-Muck" },
+ { "Rare Steak", "Siam", "Watchdog", "Xantippe" },
+ { "SIGINT", "Rabbit Breath", "Alligator", "Bloodstained" },
+ { "Google", "Chrysanthemums", "Hobnob", "Leapfrog"},
+ { "Technology fibre optic", "Turtle", "Academe", "Lonely" },
+ { "Freon", "Harpes", "Quidditch", "Reagan" },
+ { "Transposition", "Fruit Basket", "Monkey Wort", "Glogg" },
+ { "Fern", "Glasnost and Perestroika", "Latitude", "Bomberman!!!" },
+ {NULL, }
+};
+
+
+enum
+{
+ WORD_COLUMN = 0,
+ WORD_COLUMN_2,
+ WORD_COLUMN_3,
+ WORD_COLUMN_4,
+ NUM_COLUMNS
+};
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *scrolled_window;
+ GtkWidget *tree_view;
+ GtkTreeModel *model;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ gint i;
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect (GTK_OBJECT (window), "destroy", gtk_main_quit, NULL);
+ vbox = gtk_vbox_new (FALSE, 8);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
+ gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("My List of cool words"), FALSE, FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_ETCHED_IN);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
+
+ model = gtk_list_store_new_with_types (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
+ 0, GTK_TREE_SORT_ASCENDING);
+ for (i = 0; data[i].word_1 != NULL; i++)
+ {
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ WORD_COLUMN, data[i].word_1,
+ WORD_COLUMN_2, data[i].word_2,
+ WORD_COLUMN_3, data[i].word_3,
+ WORD_COLUMN_4, data[i].word_4,
+ -1);
+ }
+
+ tree_view = gtk_tree_view_new_with_model (model);
+ g_object_unref (G_OBJECT (model));
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("First Word", renderer,
+ "text", WORD_COLUMN,
+ NULL);
+ gtk_tree_view_column_set_sort_column_id (column, WORD_COLUMN);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+ g_object_unref (column);
+ g_object_unref (renderer);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("Second Word", renderer,
+ "text", WORD_COLUMN_2,
+ NULL);
+ gtk_tree_view_column_set_sort_column_id (column, WORD_COLUMN_2);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+ g_object_unref (column);
+ g_object_unref (renderer);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("Third Word", renderer,
+ "text", WORD_COLUMN_3,
+ NULL);
+ gtk_tree_view_column_set_sort_column_id (column, WORD_COLUMN_3);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+ g_object_unref (column);
+ g_object_unref (renderer);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("Fourth Word", renderer,
+ "text", WORD_COLUMN_4,
+ NULL);
+ gtk_tree_view_column_set_sort_column_id (column, WORD_COLUMN_4);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+ g_object_unref (column);
+ g_object_unref (renderer);
+
+ gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
+ gtk_widget_show_all (window);
+ gtk_main ();
+
+ return 0;
+}