summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorey Berla <corey@berla.me>2023-01-02 08:41:29 -0800
committerCorey Berla <corey@berla.me>2023-05-04 21:32:59 +0000
commit4ce37b0d6b7674efc829509e71cf6687611a3cb3 (patch)
tree6707b48327ef02096da46f2d1368b8f9f74b5c84
parent8d9083a043bf6af8cb054d728a96d457247f5632 (diff)
downloadnautilus-4ce37b0d6b7674efc829509e71cf6687611a3cb3.tar.gz
column-chooser: Port from TreeView to ListBox
-rw-r--r--src/nautilus-column-chooser.c440
-rw-r--r--src/resources/ui/nautilus-column-chooser.ui68
2 files changed, 173 insertions, 335 deletions
diff --git a/src/nautilus-column-chooser.c b/src/nautilus-column-chooser.c
index 6e1935bc0..ea72c8643 100644
--- a/src/nautilus-column-chooser.c
+++ b/src/nautilus-column-chooser.c
@@ -17,11 +17,13 @@
* see <http://www.gnu.org/licenses/>.
*
* Authors: Dave Camp <dave@ximian.com>
+ * Corey Berla <corey@berla.me>
*/
#include <config.h>
#include "nautilus-column-chooser.h"
+#include <adwaita.h>
#include <string.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
@@ -34,9 +36,8 @@ struct _NautilusColumnChooser
{
AdwWindow parent;
- GtkWidget *view;
- GtkListStore *store;
-
+ GListModel *model;
+ GtkWidget *list_box;
GtkWidget *use_default_button;
GtkWidget *window_title;
@@ -45,15 +46,6 @@ struct _NautilusColumnChooser
enum
{
- COLUMN_VISIBLE,
- COLUMN_LABEL,
- COLUMN_NAME,
- COLUMN_SENSITIVE,
- NUM_COLUMNS
-};
-
-enum
-{
PROP_FILE = 1,
NUM_PROPERTIES
};
@@ -68,6 +60,39 @@ static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE (NautilusColumnChooser, nautilus_column_chooser, ADW_TYPE_WINDOW);
+static GStrv
+get_column_names (NautilusColumnChooser *chooser,
+ gboolean only_visible)
+{
+ g_autoptr (GStrvBuilder) builder = g_strv_builder_new ();
+
+ for (guint i = 0; i < g_list_model_get_n_items (chooser->model); i++)
+ {
+ g_autoptr (NautilusColumn) column = g_list_model_get_item (chooser->model, i);
+ char *name;
+ gboolean visible;
+
+ g_object_get (column, "name", &name, "visible", &visible, NULL);
+
+ if (!only_visible || visible)
+ {
+ g_strv_builder_add (builder, name);
+ }
+ else
+ {
+ g_free (name);
+ }
+ }
+
+ return g_strv_builder_end (builder);
+}
+
+static void
+list_changed (NautilusColumnChooser *chooser)
+{
+ g_signal_emit (chooser, signals[CHANGED], 0);
+}
+
static void
nautilus_column_chooser_set_property (GObject *object,
guint param_id,
@@ -95,73 +120,6 @@ nautilus_column_chooser_set_property (GObject *object,
}
static void
-list_changed (NautilusColumnChooser *chooser)
-{
- g_signal_emit (chooser, signals[CHANGED], 0);
-}
-
-static void
-toggle_path (NautilusColumnChooser *chooser,
- GtkTreePath *path)
-{
- GtkTreeIter iter;
- gboolean visible;
- g_autofree gchar *name = NULL;
-
- gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->store),
- &iter, path);
- gtk_tree_model_get (GTK_TREE_MODEL (chooser->store), &iter,
- COLUMN_VISIBLE, &visible,
- COLUMN_NAME, &name, -1);
-
- if (g_strcmp0 (name, "name") == 0)
- {
- /* Don't allow name column to be disabled. */
- return;
- }
-
- gtk_list_store_set (chooser->store,
- &iter, COLUMN_VISIBLE, !visible, -1);
- list_changed (chooser);
-}
-
-
-static void
-visible_toggled_callback (GtkCellRendererToggle *cell,
- char *path_string,
- gpointer user_data)
-{
- GtkTreePath *path;
-
- path = gtk_tree_path_new_from_string (path_string);
- toggle_path (NAUTILUS_COLUMN_CHOOSER (user_data), path);
- gtk_tree_path_free (path);
-}
-
-static void
-view_row_activated_callback (GtkTreeView *tree_view,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- gpointer user_data)
-{
- toggle_path (NAUTILUS_COLUMN_CHOOSER (user_data), path);
-}
-
-static void
-selection_changed_callback (GtkTreeSelection *selection,
- gpointer user_data)
-{
-}
-
-static void
-row_deleted_callback (GtkTreeModel *model,
- GtkTreePath *path,
- gpointer user_data)
-{
- list_changed (NAUTILUS_COLUMN_CHOOSER (user_data));
-}
-
-static void
use_default_clicked_callback (GtkWidget *button,
gpointer user_data)
{
@@ -170,235 +128,104 @@ use_default_clicked_callback (GtkWidget *button,
}
static void
-populate_tree (NautilusColumnChooser *chooser)
+notify_row_switch_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
{
- GList *columns;
- GList *l;
-
- columns = nautilus_get_columns_for_file (chooser->file);
-
- for (l = columns; l != NULL; l = l->next)
- {
- GtkTreeIter iter;
- NautilusColumn *column;
- char *name;
- char *label;
- gboolean visible = FALSE;
- gboolean sensitive = TRUE;
-
- column = NAUTILUS_COLUMN (l->data);
+ NautilusColumnChooser *chooser = user_data;
- g_object_get (G_OBJECT (column),
- "name", &name, "label", &label,
- NULL);
-
- if (strcmp (name, "name") == 0)
- {
- visible = TRUE;
- sensitive = FALSE;
- }
- if (strcmp (name, "starred") == 0)
- {
- g_free (name);
- g_free (label);
- continue;
- }
-
- gtk_list_store_append (chooser->store, &iter);
- gtk_list_store_set (chooser->store, &iter,
- COLUMN_VISIBLE, visible,
- COLUMN_LABEL, label,
- COLUMN_NAME, name,
- COLUMN_SENSITIVE, sensitive,
- -1);
-
- g_free (name);
- g_free (label);
- }
-
- nautilus_column_list_free (columns);
+ list_changed (chooser);
}
-static void
-nautilus_column_chooser_constructed (GObject *object)
+static GtkWidget *
+add_list_box_row (GObject *item,
+ gpointer user_data)
{
- NautilusColumnChooser *chooser;
- g_autofree gchar *name = NULL;
+ NautilusColumn *column = NAUTILUS_COLUMN (item);
+ NautilusColumnChooser *chooser = user_data;
+ g_autofree char *label = NULL;
+ g_autofree char *name = NULL;
+ GtkWidget *row;
+ GtkWidget *row_switch;
- G_OBJECT_CLASS (nautilus_column_chooser_parent_class)->constructed (object);
+ g_object_get (column, "label", &label, "name", &name, NULL);
- chooser = NAUTILUS_COLUMN_CHOOSER (object);
- name = nautilus_file_get_display_name (chooser->file);
-
- adw_window_title_set_subtitle (ADW_WINDOW_TITLE (chooser->window_title), name);
-
- populate_tree (chooser);
-
- g_signal_connect (chooser->store, "row-deleted",
- G_CALLBACK (row_deleted_callback), chooser);
-}
+ row = adw_action_row_new ();
+ adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), label);
-static void
-set_visible_columns (NautilusColumnChooser *chooser,
- char **visible_columns)
-{
- GHashTable *visible_columns_hash;
- GtkTreeIter iter;
- int i;
-
- visible_columns_hash = g_hash_table_new (g_str_hash, g_str_equal);
- /* always show the name column */
- g_hash_table_insert (visible_columns_hash, "name", "name");
- for (i = 0; visible_columns[i] != NULL; ++i)
+ if (g_strcmp0 (name, "name") == 0)
{
- g_hash_table_insert (visible_columns_hash,
- visible_columns[i],
- visible_columns[i]);
+ return row;
}
- if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->store),
- &iter))
- {
- do
- {
- char *name;
- gboolean visible;
-
- gtk_tree_model_get (GTK_TREE_MODEL (chooser->store),
- &iter,
- COLUMN_NAME, &name,
- -1);
+ row_switch = gtk_switch_new ();
+ g_object_bind_property (column, "visible", row_switch, "active",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_signal_connect (row_switch, "notify::active",
+ G_CALLBACK (notify_row_switch_cb),
+ chooser);
- visible = (g_hash_table_lookup (visible_columns_hash, name) != NULL);
-
- gtk_list_store_set (chooser->store,
- &iter,
- COLUMN_VISIBLE, visible,
- -1);
- g_free (name);
- }
- while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->store), &iter));
- }
+ gtk_widget_set_halign (row_switch, GTK_ALIGN_END);
+ gtk_widget_set_valign (row_switch, GTK_ALIGN_CENTER);
+ adw_action_row_add_suffix (ADW_ACTION_ROW (row), row_switch);
- g_hash_table_destroy (visible_columns_hash);
+ return row;
}
-static char **
-get_column_names (NautilusColumnChooser *chooser,
- gboolean only_visible)
+static guint
+strv_index (char **column_order,
+ char *name)
{
- GPtrArray *ret;
- GtkTreeIter iter;
-
- ret = g_ptr_array_new ();
- if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->store),
- &iter))
+ for (gint i = 0; column_order[i] != NULL; i++)
{
- do
+ if (g_strcmp0 (column_order[i], name) == 0)
{
- char *name;
- gboolean visible;
- gtk_tree_model_get (GTK_TREE_MODEL (chooser->store),
- &iter,
- COLUMN_VISIBLE, &visible,
- COLUMN_NAME, &name,
- -1);
- if (!only_visible || visible)
- {
- /* give ownership to the array */
- g_ptr_array_add (ret, name);
- }
- else
- {
- g_free (name);
- }
+ return i;
}
- while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->store), &iter));
}
- g_ptr_array_add (ret, NULL);
- return (char **) g_ptr_array_free (ret, FALSE);
+ return G_MAXUINT;
}
-static gboolean
-get_column_iter (NautilusColumnChooser *chooser,
- NautilusColumn *column,
- GtkTreeIter *iter)
+static gint
+column_sort_func (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data)
{
- char *column_name;
+ g_autofree char *a_name = NULL;
+ g_autofree char *b_name = NULL;
+ guint a_pos, b_pos;
+ char **column_order = user_data;
- g_object_get (NAUTILUS_COLUMN (column), "name", &column_name, NULL);
+ g_object_get ((gpointer) a, "name", &a_name, NULL);
+ g_object_get ((gpointer) b, "name", &b_name, NULL);
+ a_pos = strv_index (column_order, a_name);
+ b_pos = strv_index (column_order, b_name);
- if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser->store),
- iter))
- {
- do
- {
- char *name;
-
- gtk_tree_model_get (GTK_TREE_MODEL (chooser->store),
- iter,
- COLUMN_NAME, &name,
- -1);
- if (!strcmp (name, column_name))
- {
- g_free (column_name);
- g_free (name);
- return TRUE;
- }
-
- g_free (name);
- }
- while (gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser->store), iter));
- }
- g_free (column_name);
- return FALSE;
+ return a_pos == b_pos ? 0 : a_pos < b_pos ? -1 : 1;
}
static void
set_column_order (NautilusColumnChooser *chooser,
char **column_order)
{
- GList *columns;
- GList *l;
- GtkTreePath *path;
-
- columns = nautilus_get_columns_for_file (chooser->file);
- columns = nautilus_sort_columns (columns, column_order);
-
- g_signal_handlers_block_by_func (chooser->store,
- G_CALLBACK (row_deleted_callback),
- chooser);
+ g_list_store_sort (G_LIST_STORE (chooser->model), column_sort_func, column_order);
+}
- path = gtk_tree_path_new_first ();
- for (l = columns; l != NULL; l = l->next)
+static void
+set_visible_columns (NautilusColumnChooser *chooser,
+ char **visible_columns)
+{
+ for (guint i = 0; i < g_list_model_get_n_items (chooser->model); i++)
{
- GtkTreeIter iter;
+ g_autoptr (NautilusColumn) column = g_list_model_get_item (chooser->model, i);
+ g_autofree char *name = NULL;
+ gboolean visible;
- if (get_column_iter (chooser, NAUTILUS_COLUMN (l->data), &iter))
- {
- GtkTreeIter before;
- if (path)
- {
- gtk_tree_model_get_iter (GTK_TREE_MODEL (chooser->store),
- &before, path);
- gtk_list_store_move_after (chooser->store,
- &iter, &before);
- gtk_tree_path_next (path);
- }
- else
- {
- gtk_list_store_move_after (chooser->store,
- &iter, NULL);
- }
- }
+ g_object_get (column, "name", &name, NULL);
+ visible = g_strv_contains ((const char **) visible_columns, name);
+ g_object_set (column, "visible", visible, NULL);
}
- gtk_tree_path_free (path);
- g_signal_handlers_unblock_by_func (chooser->store,
- G_CALLBACK (row_deleted_callback),
- chooser);
-
- nautilus_column_list_free (columns);
}
void
@@ -430,6 +257,56 @@ nautilus_column_chooser_get_settings (NautilusColumnChooser *chooser,
}
static void
+populate_list (NautilusColumnChooser *chooser)
+{
+ GList *columns = nautilus_get_columns_for_file (chooser->file);
+
+ g_list_store_remove_all (G_LIST_STORE (chooser->model));
+
+ for (GList *l = columns; l != NULL; l = l->next)
+ {
+ g_autofree char *name = NULL;
+
+ g_object_get (l->data, "name", &name, NULL);
+
+ if (strcmp (name, "starred") == 0)
+ {
+ continue;
+ }
+
+ g_list_store_append (G_LIST_STORE (chooser->model), l->data);
+ }
+
+ nautilus_column_list_free (columns);
+}
+
+static void
+nautilus_column_chooser_constructed (GObject *object)
+{
+ NautilusColumnChooser *chooser;
+ g_autofree gchar *name = NULL;
+
+ G_OBJECT_CLASS (nautilus_column_chooser_parent_class)->constructed (object);
+
+ chooser = NAUTILUS_COLUMN_CHOOSER (object);
+ name = nautilus_file_get_display_name (chooser->file);
+
+ adw_window_title_set_subtitle (ADW_WINDOW_TITLE (chooser->window_title), name);
+
+ populate_list (chooser);
+}
+
+static void
+nautilus_column_chooser_finalize (GObject *object)
+{
+ NautilusColumnChooser *chooser = NAUTILUS_COLUMN_CHOOSER (object);
+
+ g_clear_object (&chooser->model);
+
+ G_OBJECT_CLASS (nautilus_column_chooser_parent_class)->finalize (object);
+}
+
+static void
nautilus_column_chooser_class_init (NautilusColumnChooserClass *chooser_class)
{
GtkWidgetClass *widget_class;
@@ -440,15 +317,12 @@ nautilus_column_chooser_class_init (NautilusColumnChooserClass *chooser_class)
oclass->set_property = nautilus_column_chooser_set_property;
oclass->constructed = nautilus_column_chooser_constructed;
+ oclass->finalize = nautilus_column_chooser_finalize;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/nautilus/ui/nautilus-column-chooser.ui");
- gtk_widget_class_bind_template_child (widget_class, NautilusColumnChooser, view);
- gtk_widget_class_bind_template_child (widget_class, NautilusColumnChooser, store);
+ gtk_widget_class_bind_template_child (widget_class, NautilusColumnChooser, list_box);
gtk_widget_class_bind_template_child (widget_class, NautilusColumnChooser, use_default_button);
gtk_widget_class_bind_template_child (widget_class, NautilusColumnChooser, window_title);
- gtk_widget_class_bind_template_callback (widget_class, view_row_activated_callback);
- gtk_widget_class_bind_template_callback (widget_class, selection_changed_callback);
- gtk_widget_class_bind_template_callback (widget_class, visible_toggled_callback);
gtk_widget_class_bind_template_callback (widget_class, use_default_clicked_callback);
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_Escape, 0, "window.close", NULL);
@@ -471,9 +345,7 @@ nautilus_column_chooser_class_init (NautilusColumnChooserClass *chooser_class)
g_object_class_install_property (oclass,
PROP_FILE,
- g_param_spec_object ("file",
- "File",
- "The file this column chooser is for",
+ g_param_spec_object ("file", NULL, NULL,
NAUTILUS_TYPE_FILE,
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_WRITABLE));
@@ -483,6 +355,14 @@ static void
nautilus_column_chooser_init (NautilusColumnChooser *chooser)
{
gtk_widget_init_template (GTK_WIDGET (chooser));
+
+ chooser->model = G_LIST_MODEL (g_list_store_new (G_TYPE_OBJECT));
+
+ gtk_list_box_bind_model (GTK_LIST_BOX (chooser->list_box),
+ G_LIST_MODEL (chooser->model),
+ (GtkListBoxCreateWidgetFunc) add_list_box_row,
+ chooser,
+ NULL);
}
GtkWidget *
diff --git a/src/resources/ui/nautilus-column-chooser.ui b/src/resources/ui/nautilus-column-chooser.ui
index c9744c6a0..1323d2428 100644
--- a/src/resources/ui/nautilus-column-chooser.ui
+++ b/src/resources/ui/nautilus-column-chooser.ui
@@ -1,18 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
- <object class="GtkListStore" id="store">
- <columns>
- <!-- column-name COLUMN_VISIBLE -->
- <column type="gboolean"/>
- <!-- column-name COLUMN_LABEL -->
- <column type="gchararray"/>
- <!-- column-name COLUMN_NAME -->
- <column type="gchararray"/>
- <!-- column-name COLUMN_SENSITIVE -->
- <column type="gboolean"/>
- </columns>
- </object>
<template class="NautilusColumnChooser" parent="AdwWindow">
<property name="modal">True</property>
<property name="default-width">360</property>
@@ -31,59 +19,29 @@
</object>
</child>
<child>
- <object class="GtkBox" id="box">
- <property name="margin-top">18</property>
- <property name="margin-bottom">18</property>
- <property name="margin-start">18</property>
- <property name="margin-end">18</property>
+ <object class="GtkBox">
<property name="orientation">vertical</property>
- <property name="spacing">18</property>
<child>
<object class="GtkScrolledWindow">
<property name="child">
- <object class="GtkTreeView" id="view">
+ <object class="GtkListBox" id="list_box">
+ <property name="margin-bottom">12</property>
+ <property name="margin-end">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">12</property>
<property name="vexpand">True</property>
- <property name="model">store</property>
- <property name="headers-visible">False</property>
- <property name="reorderable">True</property>
- <signal name="row-activated" handler="view_row_activated_callback" swapped="no"/>
- <child internal-child="selection">
- <object class="GtkTreeSelection">
- <signal name="changed" handler="selection_changed_callback" swapped="no"/>
- </object>
- </child>
- <child>
- <object class="GtkTreeViewColumn" id="visible-column">
- <child>
- <object class="GtkCellRendererToggle">
- <signal name="toggled" handler="visible_toggled_callback" swapped="no"/>
- </object>
- <attributes>
- <attribute name="sensitive">3</attribute>
- <attribute name="active">0</attribute>
- </attributes>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkTreeViewColumn" id="label-column">
- <child>
- <object class="GtkCellRendererText"/>
- <attributes>
- <attribute name="sensitive">3</attribute>
- <attribute name="text">1</attribute>
- </attributes>
- </child>
- </object>
- </child>
+ <property name="selection-mode">none</property>
+ <style>
+ <class name="boxed-list"/>
+ </style>
</object>
</property>
- <style>
- <class name="frame"/>
- </style>
</object>
</child>
<child>
+ <object class="GtkSeparator"/>
+ </child>
+ <child>
<object class="GtkBox">
<property name="spacing">12</property>
<child>