/* Lists/Settings * #Keywords: GtkListItemFactory, GListModel * * This demo shows a settings viewer for GSettings. * * It demonstrates how to implement support for trees with GtkListView. * It also shows how to set up sorting and filtering for columns in a * GtkColumnView. * * It also demonstrates different styles of list. The tree on the left * uses the ­.navigation-sidebar style class, the list on the right uses * the ­.data-table style class. */ #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 GtkFilter *current_filter; static gboolean transform_settings_to_keys (GBinding *binding, const GValue *from_value, GValue *to_value, gpointer data) { GtkTreeListRow *treelistrow; GSettings *settings; GSettingsSchema *schema; GListStore *store; GtkSortListModel *sort_model; GtkFilterListModel *filter_model; GtkFilter *filter; char **keys; guint i; treelistrow = g_value_get_object (from_value); if (treelistrow == NULL) return TRUE; settings = gtk_tree_list_row_get_item (treelistrow); 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); sort_model = gtk_sort_list_model_new (G_LIST_MODEL (store), g_object_ref (gtk_column_view_get_sorter (GTK_COLUMN_VIEW (data)))); filter = GTK_FILTER (gtk_string_filter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name"))); g_set_object (¤t_filter, filter); filter_model = gtk_filter_list_model_new (G_LIST_MODEL (sort_model), filter); g_value_take_object (to_value, gtk_no_selection_new (G_LIST_MODEL (filter_model))); return TRUE; } 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 search_changed (GtkSearchEntry *entry, gpointer data) { const char *text = gtk_editable_get_text (GTK_EDITABLE (entry)); if (current_filter) gtk_string_filter_set_search (GTK_STRING_FILTER (current_filter), text); } static void stop_search (GtkSearchEntry *entry, gpointer data) { gtk_editable_set_text (GTK_EDITABLE (entry), ""); if (current_filter) gtk_string_filter_set_search (GTK_STRING_FILTER (current_filter), ""); } static GtkWidget *window = NULL; GtkWidget * do_listview_settings (GtkWidget *do_widget) { if (window == NULL) { GtkWidget *listview, *columnview; GListModel *model; GtkTreeListModel *treemodel; GtkSingleSelection *selection; GtkBuilderScope *scope; GtkBuilder *builder; GtkColumnViewColumn *name_column; GtkColumnViewColumn *type_column; GtkColumnViewColumn *default_column; GtkColumnViewColumn *summary_column; GtkColumnViewColumn *description_column; GtkSorter *sorter; GActionGroup *actions; GAction *action; 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, search_changed); gtk_builder_cscope_add_callback (scope, stop_search); 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_settings/listview_settings.ui", NULL); 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_WIDGET (gtk_builder_get_object (builder, "listview")); columnview = GTK_WIDGET (gtk_builder_get_object (builder, "columnview")); type_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "type_column")); default_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "default_column")); summary_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "summary_column")); description_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "description_column")); actions = G_ACTION_GROUP (g_simple_action_group_new ()); action = G_ACTION (g_property_action_new ("show-type", type_column, "visible")); g_action_map_add_action (G_ACTION_MAP (actions), action); g_object_unref (action); action = G_ACTION (g_property_action_new ("show-default", default_column, "visible")); g_action_map_add_action (G_ACTION_MAP (actions), action); g_object_unref (action); action = G_ACTION (g_property_action_new ("show-summary", summary_column, "visible")); g_action_map_add_action (G_ACTION_MAP (actions), action); g_object_unref (action); action = G_ACTION (g_property_action_new ("show-description", description_column, "visible")); g_action_map_add_action (G_ACTION_MAP (actions), action); g_object_unref (action); gtk_widget_insert_action_group (columnview, "columnview", actions); g_object_unref (actions); model = create_settings_model (NULL, NULL); treemodel = gtk_tree_list_model_new (model, FALSE, TRUE, create_settings_model, NULL, NULL); selection = gtk_single_selection_new (G_LIST_MODEL (treemodel)); g_object_bind_property_full (selection, "selected-item", columnview, "model", G_BINDING_SYNC_CREATE, transform_settings_to_keys, NULL, columnview, NULL); gtk_list_view_set_model (GTK_LIST_VIEW (listview), GTK_SELECTION_MODEL (selection)); g_object_unref (selection); name_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "name_column")); sorter = GTK_SORTER (gtk_string_sorter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name"))); gtk_column_view_column_set_sorter (name_column, sorter); g_object_unref (sorter); sorter = GTK_SORTER (gtk_string_sorter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "type"))); gtk_column_view_column_set_sorter (type_column, sorter); g_object_unref (sorter); 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; }