summaryrefslogtreecommitdiff
path: root/treeviewutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'treeviewutils.c')
-rw-r--r--treeviewutils.c430
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);
+}
+