diff options
Diffstat (limited to 'treeviewutils.c')
-rw-r--r-- | treeviewutils.c | 430 |
1 files changed, 280 insertions, 150 deletions
diff --git a/treeviewutils.c b/treeviewutils.c index 2472eb6..20d7777 100644 --- a/treeviewutils.c +++ b/treeviewutils.c @@ -1,11 +1,9 @@ -/* -*- mode: C; c-file-style: "linux" -*- */ - /* MemProf -- memory profiler and leak detector * Copyright 2002, Soeren Sandmann (sandmann@daimi.au.dk) * Copyright 2003, 2004, Red Hat, Inc. * * Sysprof -- Sampling, systemwide CPU profiler - * Copyright 2004, 2005, Soeren Sandmann + * Copyright 2004, 2005, 2006, 2007, 2008 Soeren Sandmann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,74 +23,134 @@ #include "treeviewutils.h" -void -column_set_sort_id (GtkTreeViewColumn *column, - int column_id) +static void on_column_clicked (GtkTreeViewColumn *column, + gpointer data); +typedef struct { - g_object_set_data (G_OBJECT (column), - "mi-saved-sort-column", GINT_TO_POINTER (column_id)); - gtk_tree_view_column_set_sort_column_id (column, column_id); -} + int model_column; + GtkSortType default_order; +} SortInfo; -void -tree_view_unset_sort_ids (GtkTreeView *tree_view) +static void +set_sort_info (GtkTreeView *view, + GtkTreeViewColumn *column, + int model_column, + GtkSortType default_order) { - GList *columns = gtk_tree_view_get_columns (tree_view); - GList *l; - - for (l = columns; l; l = l->next) { - gtk_tree_view_column_set_sort_column_id (l->data, -1); - } - - g_list_free (columns); + SortInfo *info; + + info = g_new0 (SortInfo, 1); + info->model_column = model_column; + info->default_order = default_order; + + gtk_tree_view_column_set_clickable (column, TRUE); + + g_object_set_data (G_OBJECT (column), "column_info", info); + g_signal_connect (column, "clicked", G_CALLBACK (on_column_clicked), view); } -void -tree_view_set_sort_ids (GtkTreeView *tree_view) +static SortInfo * +get_sort_info (GtkTreeViewColumn *column) { - GList *columns = gtk_tree_view_get_columns (tree_view); - GList *l; - - for (l = columns; l; l = l->next) { - int column_id = GPOINTER_TO_INT (g_object_get_data (l->data, "mi-saved-sort-column")); - gtk_tree_view_column_set_sort_column_id (l->data, column_id); - } - - g_list_free (columns); + return g_object_get_data (G_OBJECT (column), "column_info"); } -int -list_iter_get_index (GtkTreeModel *model, - GtkTreeIter *iter) +static GtkTreeViewColumn * +find_column_by_model_column (GtkTreeView *view, + int model_column) { - GtkTreePath *path = gtk_tree_model_get_path (model,iter); - int result; + GList *columns = gtk_tree_view_get_columns (view); + GList *list; + GtkTreeViewColumn *result = NULL; + + for (list = columns; list != NULL; list = list->next) + { + GtkTreeViewColumn *column = list->data; + SortInfo *info = get_sort_info (column); - g_assert (path); - g_assert (gtk_tree_path_get_depth (path) == 1); - result = gtk_tree_path_get_indices (path)[0]; - gtk_tree_path_free (path); + if (info->model_column == model_column) + result = column; + } + + g_list_free (columns); + + return result; +} - return result; +void +tree_view_set_sort_column (GtkTreeView *view, + int model_column, + int sort_type) +{ + GList *columns, *list; + GtkTreeSortable *sortable; + GtkTreeViewColumn *column = find_column_by_model_column (view, model_column); + SortInfo *info = get_sort_info (column); + + /* For each column in the view, unset the sort indicator */ + columns = gtk_tree_view_get_columns (view); + for (list = columns; list != NULL; list = list->next) + { + GtkTreeViewColumn *col = GTK_TREE_VIEW_COLUMN (list->data); + + gtk_tree_view_column_set_sort_indicator (col, FALSE); + } + + /* Set the sort indicator for this column */ + gtk_tree_view_column_set_sort_indicator (column, TRUE); + gtk_tree_view_column_set_sort_order (column, sort_type); + + /* And sort the column */ + sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model (view)); + + gtk_tree_sortable_set_sort_column_id (sortable, + info->model_column, + sort_type); +} +static void +on_column_clicked (GtkTreeViewColumn *column, + gpointer data) +{ + GtkTreeView *view = data; + GtkSortType sort_type; + SortInfo *info = get_sort_info (column); + + /* Find out what our current sort indicator is. If it is NONE, then + * select the default for the column, otherwise, select the opposite + */ + if (!gtk_tree_view_column_get_sort_indicator (column)) + { + sort_type = info->default_order; + } + else + { + if (gtk_tree_view_column_get_sort_order (column) == GTK_SORT_ASCENDING) + sort_type = GTK_SORT_DESCENDING; + else + sort_type = GTK_SORT_ASCENDING; + } + + tree_view_set_sort_column (view, info->model_column, sort_type); } GtkTreeViewColumn * add_plain_text_column (GtkTreeView *view, const gchar *title, gint model_column) { - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - - renderer = gtk_cell_renderer_text_new (); - g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); - column = gtk_tree_view_column_new_with_attributes (title, renderer, - "text", model_column, - NULL); - gtk_tree_view_column_set_resizable (column, TRUE); - gtk_tree_view_append_column (view, column); - column_set_sort_id (column, model_column); - - return column; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + column = gtk_tree_view_column_new_with_attributes (title, renderer, + "text", model_column, + NULL); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (view, column); + + set_sort_info (view, column, model_column, GTK_SORT_ASCENDING); + + return column; } static void @@ -100,19 +158,19 @@ pointer_to_text (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { - gpointer p; - gchar *text; - int column = GPOINTER_TO_INT (data); - - gtk_tree_model_get (tree_model, iter, column, &p, -1); - text = g_strdup_printf ("%p", p); - g_object_set (cell, "text", text, NULL); - g_free (text); + gpointer p; + gchar *text; + int column = GPOINTER_TO_INT (data); + + gtk_tree_model_get (tree_model, iter, column, &p, -1); + text = g_strdup_printf ("%p", p); + g_object_set (cell, "text", text, NULL); + g_free (text); } typedef struct { - int column; - char *format; + int column; + char *format; } ColumnInfo; static void @@ -120,113 +178,185 @@ double_to_text (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { - gdouble d; - gchar *text; - ColumnInfo *info = data; - - gtk_tree_model_get (tree_model, iter, info->column, &d, -1); - - text = g_strdup_printf (info->format, d); - - g_object_set (cell, "text", text, NULL); - g_free (text); + gdouble d; + gchar *text; + ColumnInfo *info = data; + + gtk_tree_model_get (tree_model, iter, info->column, &d, -1); + + text = g_strdup_printf (info->format, d); + + g_object_set (cell, "markup", text, NULL); + g_free (text); } static void free_column_info (void *data) { - ColumnInfo *info = data; - g_free (info->format); - g_free (info); + ColumnInfo *info = data; + g_free (info->format); + g_free (info); } GtkTreeViewColumn * -add_double_format_column (GtkTreeView *view, const gchar *title, gint model_column, const char *format) +add_double_format_column (GtkTreeView *view, + const gchar *title, + gint model_column, + const char *format) { - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - ColumnInfo *column_info = g_new (ColumnInfo, 1); - - renderer = gtk_cell_renderer_text_new (); - g_object_set (renderer, "xalign", 1.0, NULL); - - column = gtk_tree_view_column_new (); - gtk_tree_view_column_set_title (column, title); - gtk_tree_view_column_pack_start (column, renderer, TRUE); - gtk_tree_view_column_set_resizable (column, FALSE); - - column_info->column = model_column; - column_info->format = g_strdup (format); - - gtk_tree_view_column_set_cell_data_func (column, renderer, - double_to_text, column_info, free_column_info); - - gtk_tree_view_append_column (view, column); - column_set_sort_id (column, model_column); - - return column; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + ColumnInfo *column_info = g_new (ColumnInfo, 1); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, "xalign", 1.0, NULL); + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, title); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_set_resizable (column, FALSE); + + column_info->column = model_column; + column_info->format = g_strdup (format); + + gtk_tree_view_column_set_cell_data_func ( + column, renderer, double_to_text, column_info, free_column_info); + + gtk_tree_view_append_column (view, column); + + set_sort_info (view, column, model_column, GTK_SORT_DESCENDING); + + return column; } GtkTreeViewColumn * add_pointer_column (GtkTreeView *view, const gchar *title, gint model_column) { - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - - renderer = gtk_cell_renderer_text_new (); - - column = gtk_tree_view_column_new (); - if (title) - gtk_tree_view_column_set_title (column, title); - gtk_tree_view_column_pack_start (column, renderer, TRUE); - gtk_tree_view_column_set_resizable (column, TRUE); - gtk_tree_view_column_set_cell_data_func (column, renderer, - pointer_to_text, GINT_TO_POINTER (model_column), NULL); - - gtk_tree_view_append_column (view, column); - column_set_sort_id (column, model_column); - - return column; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + renderer = gtk_cell_renderer_text_new (); + + column = gtk_tree_view_column_new (); + if (title) + gtk_tree_view_column_set_title (column, title); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_cell_data_func ( + column, renderer, pointer_to_text, GINT_TO_POINTER (model_column), NULL); + + gtk_tree_view_append_column (view, column); + + return column; } -typedef struct +void +tree_view_set_model_with_default_sort (GtkTreeView *view, + GtkTreeModel *model, + int model_column, + GtkSortType default_sort) { - gboolean is_sorted; - int sort_column; - GtkSortType sort_type; -} SortState; - + int column; + GtkSortType type; + GtkTreeSortable *old_model; + GtkAdjustment *adjustment; + + old_model = GTK_TREE_SORTABLE (gtk_tree_view_get_model (view)); + + if (!(old_model && gtk_tree_sortable_get_sort_column_id ( + GTK_TREE_SORTABLE (old_model), &column, &type))) + { + column = model_column; + type = default_sort; + } + + /* Setting the sort column here prevents the "rows_reordered" + * signal from being emitted when the model is attached to + * a treeview. This is desirable because at that point there + * is a handler attached, which means the signal will actually + * be emitted. + */ + gtk_tree_sortable_set_sort_column_id ( + GTK_TREE_SORTABLE (model), column, type); + + gtk_tree_view_set_model (view, model); + + tree_view_set_sort_column (view, column, type); + + /* Workaround for GTK+ crack, see bug 405625 */ + adjustment = gtk_tree_view_get_vadjustment (view); + if (adjustment) + gtk_adjustment_set_value (adjustment, 0); +} -gpointer -save_sort_state (GtkTreeView *view) +static void +process_iter (GtkTreeView *view, + GtkTreeIter *iter, + VisibleCallback callback, + gpointer data) { - SortState *state = NULL; - GtkTreeModel *model = gtk_tree_view_get_model (view); - - if (model && GTK_IS_TREE_SORTABLE (model)) { - state = g_new (SortState, 1); - state->is_sorted = gtk_tree_sortable_get_sort_column_id ( - GTK_TREE_SORTABLE (model), - &(state->sort_column), - &(state->sort_type)); + GtkTreeModel *model = gtk_tree_view_get_model (view); + GtkTreePath *path; + GtkTreeIter child; + + path = gtk_tree_model_get_path (model, iter); + + callback (view, path, iter, data); + + if (gtk_tree_view_row_expanded (view, path)) + { + if (gtk_tree_model_iter_children (model, &child, iter)) + { + do + { + process_iter (view, &child, callback, data); + } + while (gtk_tree_model_iter_next (model, &child)); } - return state; + } + + gtk_tree_path_free (path); } void -restore_sort_state (GtkTreeView *view, gpointer st) -{ - SortState *state = st; - GtkTreeModel *model = gtk_tree_view_get_model (view); - - if (state) { - if (state->is_sorted && model && GTK_IS_TREE_SORTABLE (model)) { - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), - state->sort_column, - state->sort_type); - } - g_free (state); - } - - gtk_tree_sortable_sort_column_changed (GTK_TREE_SORTABLE (model)); +tree_view_foreach_visible (GtkTreeView *view, + VisibleCallback callback, + gpointer data) +{ + GtkTreeModel *model = gtk_tree_view_get_model (view); + GtkTreeIter iter; + + if (model && gtk_tree_model_get_iter_first (model, &iter)) + process_iter (view, &iter, callback, data); } + +/* Not really a *treeview* utility, but there isn't really a + * better place to put it + */ +void +set_error (GError **err, gint domain, gint code, + const char *format, va_list args) +{ + char *msg; + + if (!err) + return; + + msg = g_strdup_vprintf (format, args); + + if (*err == NULL) + { + *err = g_error_new_literal (G_MARKUP_ERROR, code, msg); + } + else + { + /* Warning text from GLib */ + g_warning ("GError set over the top of a previous GError or uninitialized memory.\n" + "This indicates a bug in someone's code. You must ensure an error is NULL before it's set.\n" + "The overwriting error message was: %s", + msg); + } + + g_free (msg); +} + |