From ddefbfa8b588e65cd4b2f614b0310c6909f12a3d Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 8 May 2023 20:47:39 +0200 Subject: [PATCH] gtk-demo: Add alternative settings demo This one displays a long list of all settings with sections and allows filtering the list to quickly search for keys. --- demos/gtk-demo/demo.gresource.xml | 4 + demos/gtk-demo/listview_settings2.c | 230 +++++++++++++++++++++++++++ demos/gtk-demo/listview_settings2.ui | 130 +++++++++++++++ demos/gtk-demo/meson.build | 1 + 4 files changed, 365 insertions(+) create mode 100644 demos/gtk-demo/listview_settings2.c create mode 100644 demos/gtk-demo/listview_settings2.ui diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml index 615d782bfe..ba87e860ce 100644 --- a/demos/gtk-demo/demo.gresource.xml +++ b/demos/gtk-demo/demo.gresource.xml @@ -195,6 +195,9 @@ listview_settings.ui + + listview_settings2.ui + ucdnames.data @@ -312,6 +315,7 @@ listview_minesweeper.c listview_selections.c listview_settings.c + listview_settings2.c listview_ucd.c listview_weather.c listview_words.c diff --git a/demos/gtk-demo/listview_settings2.c b/demos/gtk-demo/listview_settings2.c new file mode 100644 index 0000000000..4f3e87fb68 --- /dev/null +++ b/demos/gtk-demo/listview_settings2.c @@ -0,0 +1,230 @@ +/* Lists/Settings v2 + * #Keywords: GtkListHeaderFactory, GtkSectionModel + * + * This demo shows a settings viewer for GSettings. + * + * It demonstrates how to implement support for sections with GtkListView. + * + * It also shows how to quickly flatten a large tree of items into a list + * that can be filtered to find the itmes one is looking for. + */ + +#include + +#include "settings-key.h" + +static void +item_value_changed (GtkEditableLabel *label, + GParamSpec *pspec, + GtkColumnViewCell *cell) +{ + SettingsKey *self; + GSettingsSchemaKey *key; + const char *text; + const GVariantType *type; + GVariant *variant; + GError *error = NULL; + const char *name; + char *value; + + text = gtk_editable_get_text (GTK_EDITABLE (label)); + + self = gtk_column_view_cell_get_item (cell); + key = settings_key_get_key (self); + + type = g_settings_schema_key_get_value_type (key); + name = g_settings_schema_key_get_name (key); + + variant = g_variant_parse (type, text, NULL, NULL, &error); + if (!variant) + { + g_warning ("%s", error->message); + g_clear_error (&error); + goto revert; + } + + if (!g_settings_schema_key_range_check (key, variant)) + { + g_warning ("Not a valid value for %s", name); + goto revert; + } + + g_settings_set_value (settings_key_get_settings (self), name, variant); + g_variant_unref (variant); + return; + +revert: + gtk_widget_error_bell (GTK_WIDGET (label)); + + g_object_get (self, "value", &value, NULL); + gtk_editable_set_text (GTK_EDITABLE (label), value); + g_free (value); +} + +static int +strvcmp (gconstpointer p1, + gconstpointer p2) +{ + const char * const *s1 = p1; + const char * const *s2 = p2; + + return strcmp (*s1, *s2); +} + +static gpointer +map_settings_to_keys (gpointer item, + gpointer unused) +{ + GSettings *settings = item; + GSettingsSchema *schema; + GListStore *store; + char **keys; + guint i; + + g_object_get (settings, "settings-schema", &schema, NULL); + + store = g_list_store_new (SETTINGS_TYPE_KEY); + + keys = g_settings_schema_list_keys (schema); + + for (i = 0; keys[i] != NULL; i++) + { + GSettingsSchemaKey *almost_there = g_settings_schema_get_key (schema, keys[i]); + SettingsKey *finally = settings_key_new (settings, almost_there); + g_list_store_append (store, finally); + g_object_unref (finally); + g_settings_schema_key_unref (almost_there); + } + + g_strfreev (keys); + g_settings_schema_unref (schema); + g_object_unref (settings); + + return store; +} + +static GListModel * +create_settings_model (gpointer item, + gpointer unused) +{ + GSettings *settings = item; + char **schemas; + GListStore *result; + guint i; + + if (settings == NULL) + { + g_settings_schema_source_list_schemas (g_settings_schema_source_get_default (), + TRUE, + &schemas, + NULL); + } + else + { + schemas = g_settings_list_children (settings); + } + + if (schemas == NULL || schemas[0] == NULL) + { + g_free (schemas); + return NULL; + } + + qsort (schemas, g_strv_length (schemas), sizeof (char *), strvcmp); + + result = g_list_store_new (G_TYPE_SETTINGS); + for (i = 0; schemas[i] != NULL; i++) + { + GSettings *child; + + if (settings == NULL) + child = g_settings_new (schemas[i]); + else + child = g_settings_get_child (settings, schemas[i]); + + g_list_store_append (result, child); + g_object_unref (child); + } + + g_strfreev (schemas); + + return G_LIST_MODEL (result); +} + +static void +search_enabled (GtkSearchEntry *entry) +{ + gtk_editable_set_text (GTK_EDITABLE (entry), ""); +} + +static void +stop_search (GtkSearchEntry *entry, + gpointer data) +{ + gtk_editable_set_text (GTK_EDITABLE (entry), ""); +} + +static GtkWidget *window = NULL; + +GtkWidget * +do_listview_settings2 (GtkWidget *do_widget) +{ + if (window == NULL) + { + GtkListView *listview; + GListModel *model; + GtkTreeListModel *treemodel; + GtkNoSelection *selection; + GtkBuilderScope *scope; + GtkBuilder *builder; + GError *error = NULL; + GtkFilter *filter; + + g_type_ensure (SETTINGS_TYPE_KEY); + + scope = gtk_builder_cscope_new (); + gtk_builder_cscope_add_callback (scope, search_enabled); + gtk_builder_cscope_add_callback (scope, stop_search); + gtk_builder_cscope_add_callback (scope, settings_key_get_search_string); + gtk_builder_cscope_add_callback (scope, item_value_changed); + + builder = gtk_builder_new (); + gtk_builder_set_scope (builder, scope); + g_object_unref (scope); + + gtk_builder_add_from_resource (builder, "/listview_settings2/listview_settings2.ui", &error); + g_assert_no_error (error); + + window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); + gtk_window_set_display (GTK_WINDOW (window), + gtk_widget_get_display (do_widget)); + g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window); + + listview = GTK_LIST_VIEW (gtk_builder_get_object (builder, "listview")); + filter = GTK_FILTER (gtk_builder_get_object (builder, "filter")); + + model = create_settings_model (NULL, NULL); + treemodel = gtk_tree_list_model_new (model, + TRUE, + TRUE, + create_settings_model, + NULL, + NULL); + model = G_LIST_MODEL (gtk_map_list_model_new (G_LIST_MODEL (treemodel), map_settings_to_keys, NULL, NULL)); + model = G_LIST_MODEL (gtk_flatten_list_model_new (model)); + model = G_LIST_MODEL (gtk_filter_list_model_new (model, g_object_ref (filter))); + selection = gtk_no_selection_new (model); + + gtk_list_view_set_model (GTK_LIST_VIEW (listview), GTK_SELECTION_MODEL (selection)); + g_object_unref (selection); + + g_object_unref (builder); + } + + if (!gtk_widget_get_visible (window)) + gtk_widget_set_visible (window, TRUE); + else + gtk_window_destroy (GTK_WINDOW (window)); + + return window; +} diff --git a/demos/gtk-demo/listview_settings2.ui b/demos/gtk-demo/listview_settings2.ui new file mode 100644 index 0000000000..0600f63582 --- /dev/null +++ b/demos/gtk-demo/listview_settings2.ui @@ -0,0 +1,130 @@ + + + + + + + + + + Settings + 640 + 480 + + + + + system-search-symbolic + + + + + + + vertical + + + + + + + + + + + + + + + + 1 + + + + + + + + ]]> + + + + + + + + + ]]> + + + + + + + + + + diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build index f1ce4ffc6b..976c3ec997 100644 --- a/demos/gtk-demo/meson.build +++ b/demos/gtk-demo/meson.build @@ -57,6 +57,7 @@ demos = files([ 'listview_minesweeper.c', 'listview_selections.c', 'listview_settings.c', + 'listview_settings2.c', 'listview_ucd.c', 'listview_weather.c', 'listview_words.c', -- 2.30.2