From fb31765cbe33890f325a87015507364156741321 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:59:44 +0200 Subject: Adding upstream version 42.0. Signed-off-by: Daniel Baumann --- src/legacy/treeview.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 src/legacy/treeview.c (limited to 'src/legacy/treeview.c') diff --git a/src/legacy/treeview.c b/src/legacy/treeview.c new file mode 100644 index 0000000..b50393d --- /dev/null +++ b/src/legacy/treeview.c @@ -0,0 +1,289 @@ +/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +#include + +#include "treeview.h" + +typedef struct +{ + GSettings *settings; + gboolean store_column_order; + GHashTable *excluded_columns; +} GsmTreeViewPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GsmTreeView, gsm_tree_view, GTK_TYPE_TREE_VIEW) + +static void +gsm_tree_view_finalize (GObject *object) +{ + GsmTreeViewPrivate *priv = gsm_tree_view_get_instance_private (GSM_TREE_VIEW (object)); + + g_hash_table_destroy (priv->excluded_columns); + priv->excluded_columns = NULL; + + G_OBJECT_CLASS (gsm_tree_view_parent_class)->finalize (object); +} + +static void +gsm_tree_view_class_init (GsmTreeViewClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = gsm_tree_view_finalize; +} + +static void +gsm_tree_view_init (GsmTreeView *self) +{ + GsmTreeViewPrivate *priv = gsm_tree_view_get_instance_private (self); + + priv->excluded_columns = g_hash_table_new (g_direct_hash, g_direct_equal); +} + +void +gsm_tree_view_save_state (GsmTreeView *tree_view) +{ + GsmTreeViewPrivate *priv; + + g_return_if_fail (GSM_IS_TREE_VIEW (tree_view)); + + priv = gsm_tree_view_get_instance_private (tree_view); + GtkTreeModel *model; + gint sort_col; + GtkSortType sort_type; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); + g_settings_delay (priv->settings); + if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), + &sort_col, + &sort_type)) { + g_settings_set_int (priv->settings, "sort-col", sort_col); + g_settings_set_int (priv->settings, "sort-order", sort_type); + } + + if (priv->store_column_order) { + GList *columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (tree_view)); + GList *iter; + GVariantBuilder builder; + + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + + for (iter = columns; iter != NULL; iter = iter->next) { + gint id = gtk_tree_view_column_get_sort_column_id (GTK_TREE_VIEW_COLUMN (iter->data)); + g_variant_builder_add (&builder, "i", id); + } + + g_settings_set_value (priv->settings, "columns-order", + g_variant_builder_end (&builder)); + + g_list_free (columns); + } + + g_settings_apply (priv->settings); +} + +GtkTreeViewColumn * +gsm_tree_view_get_column_from_id (GsmTreeView *tree_view, gint sort_id) +{ + GList *columns; + GList *iter; + GtkTreeViewColumn *col = NULL; + + g_return_val_if_fail (GSM_IS_TREE_VIEW (tree_view), NULL); + + columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (tree_view)); + + for (iter = columns; iter != NULL; iter = iter->next) { + col = GTK_TREE_VIEW_COLUMN (iter->data); + if (gtk_tree_view_column_get_sort_column_id (col) == sort_id) + break; + } + + g_list_free (columns); + + return col; +} + +static gboolean +cb_column_header_clicked (GtkTreeViewColumn *column, GdkEventButton *event, gpointer data) +{ + GtkMenu *menu = GTK_MENU (data); + + if (event->button == GDK_BUTTON_SECONDARY) { + gtk_menu_popup_at_pointer (menu, (GdkEvent*)event); + return TRUE; + } + + return FALSE; +} + +void +gsm_tree_view_load_state (GsmTreeView *tree_view) +{ + GsmTreeViewPrivate *priv; + GtkTreeModel *model; + gint sort_col; + GtkSortType sort_type; + + g_return_if_fail (GSM_IS_TREE_VIEW (tree_view)); + + priv = gsm_tree_view_get_instance_private (tree_view); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); + + sort_col = g_settings_get_int (priv->settings, "sort-col"); + sort_type = g_settings_get_int (priv->settings, "sort-order"); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), + sort_col, + sort_type); + + if (priv->store_column_order) { + GtkMenu *header_menu = GTK_MENU (gtk_menu_new ()); + GList *columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (tree_view)); + GList *iter; + GVariantIter *var_iter; + GtkTreeViewColumn *col, *last; + gint sort_id; + + for (iter = columns; iter != NULL; iter = iter->next) { + const char *title; + char *key; + GtkButton *button; + GtkCheckMenuItem *column_item; + + col = GTK_TREE_VIEW_COLUMN (iter->data); + sort_id = gtk_tree_view_column_get_sort_column_id (col); + + if (priv->excluded_columns && + g_hash_table_contains (priv->excluded_columns, GINT_TO_POINTER (sort_id))) { + gtk_tree_view_column_set_visible (col, FALSE); + continue; + } + + title = gtk_tree_view_column_get_title (col); + + button = GTK_BUTTON (gtk_tree_view_column_get_button (col)); + g_signal_connect (button, "button-press-event", + G_CALLBACK (cb_column_header_clicked), + header_menu); + + column_item = GTK_CHECK_MENU_ITEM (gtk_check_menu_item_new_with_label (title)); + g_object_bind_property (col, "visible", + column_item, "active", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + gtk_menu_shell_append (GTK_MENU_SHELL (header_menu), GTK_WIDGET (column_item)); + + key = g_strdup_printf ("col-%d-width", sort_id); + gtk_tree_view_column_set_fixed_width (col, g_settings_get_int (priv->settings, key)); + gtk_tree_view_column_set_min_width (col, 30); + g_free (key); + + key = g_strdup_printf ("col-%d-visible", sort_id); + gtk_tree_view_column_set_visible (col, g_settings_get_boolean (priv->settings, key)); + g_free (key); + } + + g_list_free (columns); + + gtk_widget_show_all (GTK_WIDGET (header_menu)); + + g_settings_get (priv->settings, "columns-order", "ai", &var_iter); + last = NULL; + while (g_variant_iter_loop (var_iter, "i", &sort_id)) { + col = gsm_tree_view_get_column_from_id (tree_view, sort_id); + + if (col != NULL && col != last) { + gtk_tree_view_move_column_after (GTK_TREE_VIEW (tree_view), + col, last); + last = col; + } + } + g_variant_iter_free (var_iter); + } +} + +void +gsm_tree_view_add_excluded_column (GsmTreeView *tree_view, gint column_id) +{ + GsmTreeViewPrivate *priv; + + g_return_if_fail (GSM_IS_TREE_VIEW (tree_view)); + + priv = gsm_tree_view_get_instance_private (tree_view); + g_hash_table_add (priv->excluded_columns, GINT_TO_POINTER (column_id)); +} + +static guint timeout_id = 0; +static GtkTreeViewColumn *current_column; + +static gboolean +save_column_state (gpointer data) +{ + GSettings *settings = G_SETTINGS (data); + gint column_id = gtk_tree_view_column_get_sort_column_id (current_column); + gint width = gtk_tree_view_column_get_width (current_column); + gboolean visible = gtk_tree_view_column_get_visible (current_column); + + gchar *key; + g_settings_delay (settings); + + key = g_strdup_printf ("col-%d-width", column_id); + g_settings_set_int (settings, key, width); + g_free (key); + + key = g_strdup_printf ("col-%d-visible", column_id); + g_settings_set_boolean (settings, key, visible); + g_free (key); + timeout_id = 0; + g_settings_apply (settings); + + return FALSE; +} + +static void +cb_update_column_state (GObject *object, GParamSpec *pspec, gpointer data) +{ + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (object); + + current_column = column; + + if (timeout_id > 0) + g_source_remove (timeout_id); + + timeout_id = g_timeout_add_seconds (1, save_column_state, data); +} + +void +gsm_tree_view_append_and_bind_column (GsmTreeView *tree_view, GtkTreeViewColumn *column) +{ + GsmTreeViewPrivate *priv; + + g_return_if_fail (GSM_IS_TREE_VIEW (tree_view)); + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column)); + + priv = gsm_tree_view_get_instance_private (tree_view); + + gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), + column); + + g_signal_connect (column, "notify::fixed-width", + G_CALLBACK (cb_update_column_state), + priv->settings); + + g_signal_connect (column, "notify::visible", + G_CALLBACK (cb_update_column_state), + priv->settings); +} + + +GsmTreeView * +gsm_tree_view_new (GSettings *settings, gboolean store_column_order) +{ + GsmTreeView *self = g_object_new (GSM_TYPE_TREE_VIEW, NULL); + GsmTreeViewPrivate *priv = gsm_tree_view_get_instance_private (self); + + priv->settings = settings; + priv->store_column_order = store_column_order; + + return self; +} -- cgit v1.2.3