[gtk/wip/otte/listview: 958/1040] demo: Add a GSettings tree demo



commit 571fc11a4cf2d793990d2063829b62f527d6bc60
Author: Benjamin Otte <otte redhat com>
Date:   Sun Oct 13 07:40:58 2019 +0200

    demo: Add a GSettings tree demo
    
    It is meant to look somewhat like dconf-editor when it is done.
    
    So far, it's just a list.

 demos/gtk-demo/demo.gresource.xml   |   4 +
 demos/gtk-demo/listview_settings.c  | 256 ++++++++++++++++++++++++++++++++++++
 demos/gtk-demo/listview_settings.ui | 108 +++++++++++++++
 demos/gtk-demo/meson.build          |   1 +
 4 files changed, 369 insertions(+)
---
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 1e93dd26e8..3e4460ca4c 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -111,6 +111,9 @@
     <file>gnome-fs-directory.png</file>
     <file>gnome-fs-regular.png</file>
   </gresource>
+  <gresource prefix="/listview_settings">
+    <file>listview_settings.ui</file>
+  </gresource>
   <gresource prefix="/listview_weather">
     <file compressed="true">listview_weather.txt</file>
   </gresource>
@@ -190,6 +193,7 @@
     <file>infobar.c</file>
     <file>links.c</file>
     <file>listbox.c</file>
+    <file>listview_settings.c</file>
     <file>listview_weather.c</file>
     <file>list_store.c</file>
     <file>markup.c</file>
diff --git a/demos/gtk-demo/listview_settings.c b/demos/gtk-demo/listview_settings.c
new file mode 100644
index 0000000000..75af45a0c0
--- /dev/null
+++ b/demos/gtk-demo/listview_settings.c
@@ -0,0 +1,256 @@
+/* Lists/Settings
+ *
+ * This demo shows a settings viewer for GSettings.
+ *
+ * It demonstrates how to implement support for trees with listview.
+ */
+
+#include <gtk/gtk.h>
+
+/* Create an object that wraps GSettingsSchemaKey because that's a boxed type */
+typedef struct _SettingsKey SettingsKey;
+struct _SettingsKey
+{
+  GObject parent_instance;
+
+  GSettings *settings;
+  GSettingsSchemaKey *key;
+};
+
+enum {
+  PROP_0,
+  PROP_NAME,
+  PROP_SUMMARY,
+  PROP_DESCRIPTION,
+  PROP_VALUE,
+
+  N_PROPS
+};
+
+#define SETTINGS_TYPE_KEY (settings_key_get_type ())
+G_DECLARE_FINAL_TYPE (SettingsKey, settings_key, SETTINGS, KEY, GObject);
+
+G_DEFINE_TYPE (SettingsKey, settings_key, G_TYPE_OBJECT);
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
+static void
+settings_key_get_property (GObject    *object,
+                           guint       property_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+  SettingsKey *self = SETTINGS_KEY (object);
+
+  switch (property_id)
+    {
+    case PROP_DESCRIPTION:
+      g_value_set_string (value, g_settings_schema_key_get_description (self->key));
+      break;
+
+    case PROP_NAME:
+      g_value_set_string (value, g_settings_schema_key_get_name (self->key));
+      break;
+
+    case PROP_SUMMARY:
+      g_value_set_string (value, g_settings_schema_key_get_summary (self->key));
+      break;
+
+    case PROP_VALUE:
+      {
+        GVariant *variant = g_settings_get_value (self->settings, g_settings_schema_key_get_name 
(self->key));
+        g_value_take_string (value, g_variant_print (variant, FALSE));
+        g_variant_unref (variant);
+      }
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+settings_key_class_init (SettingsKeyClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->get_property = settings_key_get_property;
+
+  properties[PROP_DESCRIPTION] =
+    g_param_spec_string ("description", NULL, NULL, NULL, G_PARAM_READABLE);
+  properties[PROP_NAME] =
+    g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READABLE);
+  properties[PROP_SUMMARY] =
+    g_param_spec_string ("summary", NULL, NULL, NULL, G_PARAM_READABLE);
+  properties[PROP_VALUE] =
+    g_param_spec_string ("value", NULL, NULL, NULL, G_PARAM_READABLE);
+
+  g_object_class_install_properties (gobject_class, N_PROPS, properties);
+}
+
+static void
+settings_key_init (SettingsKey *self)
+{
+}
+
+static SettingsKey *
+settings_key_new (GSettings          *settings,
+                  GSettingsSchemaKey *key)
+{
+  SettingsKey *result = g_object_new (SETTINGS_TYPE_KEY, NULL);
+
+  result->settings = g_object_ref (settings);
+  result->key = g_settings_schema_key_ref (key);
+
+  return result;
+}
+
+static int
+strvcmp (gconstpointer p1,
+         gconstpointer p2)
+{
+  const char * const *s1 = p1;
+  const char * const *s2 = p2;
+
+  return strcmp (*s1, *s2);
+}
+
+static gboolean
+transform_settings_to_keys (GBinding     *binding,
+                            const GValue *from_value,
+                            GValue       *to_value,
+                            gpointer      unused)
+{
+  GtkTreeListRow *treelistrow;
+  GSettings *settings;
+  GSettingsSchema *schema;
+  GListStore *store;
+  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);
+  qsort (keys, g_strv_length (keys), sizeof (char *), strvcmp);
+
+  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);
+
+  g_value_take_object (to_value, store);
+
+  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);
+    }
+
+  return G_LIST_MODEL (result);
+}
+
+static GtkWidget *window = NULL;
+
+GtkWidget *
+do_listview_settings (GtkWidget *do_widget)
+{
+  if (window == NULL)
+    {
+      GtkWidget *listview, *columnview;
+      GListModel *model;
+      GtkTreeListModel *treemodel;
+      GtkSingleSelection *selection;
+      GtkBuilder *builder;
+
+      g_type_ensure (SETTINGS_TYPE_KEY);
+
+      builder = gtk_builder_new_from_resource ("/listview_settings/listview_settings.ui");
+      window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
+      gtk_window_set_display (GTK_WINDOW (window),
+                              gtk_widget_get_display (do_widget));
+      g_signal_connect (window, "destroy",
+                        G_CALLBACK (gtk_widget_destroyed), &window);
+
+      listview = GTK_WIDGET (gtk_builder_get_object (builder, "listview"));
+      columnview = GTK_WIDGET (gtk_builder_get_object (builder, "columnview"));
+      model = create_settings_model (NULL, NULL);
+      treemodel = gtk_tree_list_model_new (FALSE,
+                                           model,
+                                           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,
+                                   NULL, NULL);
+      gtk_list_view_set_model (GTK_LIST_VIEW (listview), G_LIST_MODEL (selection));
+      g_object_unref (selection);
+      g_object_unref (treemodel);
+      g_object_unref (model);
+    }
+
+  if (!gtk_widget_get_visible (window))
+    gtk_widget_show (window);
+  else
+    gtk_widget_destroy (window);
+
+  return window;
+}
diff --git a/demos/gtk-demo/listview_settings.ui b/demos/gtk-demo/listview_settings.ui
new file mode 100644
index 0000000000..529adb4756
--- /dev/null
+++ b/demos/gtk-demo/listview_settings.ui
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="GtkWindow" id="window">
+    <property name="title" translatable="yes">Settings</property>
+    <property name="default-width">600</property>
+    <property name="default-height">400</property>
+    <child>
+      <object class="GtkPaned">
+        <child>
+          <object class="GtkScrolledWindow">
+            <child>
+              <object class="GtkListView" id="listview">
+                <property name="factory">
+                  <object class="GtkBuilderListItemFactory">
+                    <property name="bytes"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GtkListItem">
+    <property name="child">
+      <object class="GtkTreeExpander" id="expander">
+        <binding name="list-row">
+          <lookup name="item">GtkListItem</lookup>
+        </binding>
+        <property name="child">
+          <object class="GtkLabel">
+            <property name="xalign">0</property>
+            <binding name="label">
+              <lookup name="schema" type="GSettings">
+                <lookup name="item">expander</lookup>
+              </lookup>
+            </binding>
+          </object>
+        </property>
+      </object>
+    </property>
+  </template>
+</interface>
+                    ]]></property>
+                  </object>
+                </property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow">
+            <child>
+              <object class="GtkColumnView" id="columnview">
+                <child>
+                  <object class="GtkColumnViewColumn">
+                    <property name="title">Name</property>
+                    <property name="factory">
+                      <object class="GtkBuilderListItemFactory">
+                        <property name="bytes"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GtkListItem">
+    <property name="child">
+      <object class="GtkLabel">
+        <property name="xalign">0</property>
+        <binding name="label">
+          <lookup name="name" type="SettingsKey">
+            <lookup name="item">GtkListItem</lookup>
+          </lookup>
+        </binding>
+      </object>
+    </property>
+  </template>
+</interface>
+                        ]]></property>
+                      </object>
+                    </property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkColumnViewColumn">
+                    <property name="title">Value</property>
+                    <property name="factory">
+                      <object class="GtkBuilderListItemFactory">
+                        <property name="bytes"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GtkListItem">
+    <property name="child">
+      <object class="GtkLabel">
+        <property name="xalign">0</property>
+        <binding name="label">
+          <lookup name="value" type="SettingsKey">
+            <lookup name="item">GtkListItem</lookup>
+          </lookup>
+        </binding>
+      </object>
+    </property>
+  </template>
+</interface>
+                        ]]></property>
+                      </object>
+                    </property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 60f3a03fca..de4bde9b3e 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -41,6 +41,7 @@ demos = files([
   'listbox.c',
   'flowbox.c',
   'list_store.c',
+  'listview_settings.c',
   'listview_weather.c',
   'markup.c',
   'modelbutton.c',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]