[gnome-software/wip/folders: 2/10] Add a GsFolders object



commit f45b5f57a45dec808f3d13e52eafd7b3093dffad
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Nov 13 08:42:29 2013 -0500

    Add a GsFolders object
    
    Unlike categories, we use a single, singleton object here that
    wraps the app-folders setting and offers an api to make changes
    to this setting.

 src/Makefile.am  |    2 +
 src/gs-folders.c |  314 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/gs-folders.h |   78 ++++++++++++++
 3 files changed, 394 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index d0ae431..39eb9fb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -150,6 +150,8 @@ gnome_software_service_SOURCES =                    \
        gs-shell-search-provider.h                      \
        gs-application.c                                \
        gs-application.h                                \
+       gs-folders.c                                    \
+       gs-folders.h                                    \               
        gs-main.c
 
 gnome_software_LDADD =                                 \
diff --git a/src/gs-folders.c b/src/gs-folders.c
new file mode 100644
index 0000000..edc5148
--- /dev/null
+++ b/src/gs-folders.c
@@ -0,0 +1,314 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2013 Matthias Clasen <mclasen redhat com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "gs-folders.h"
+
+static void    gs_folders_finalize     (GObject        *object);
+
+#define GS_FOLDERS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_FOLDERS, GsFoldersPrivate))
+
+/* We are loading folders from a settings with type
+ * a{sas}, which maps folder ids to list of app ids.
+ *
+ * For convenience, we unfold this variant into GsFolder
+ * structs and two hash tables, one with folder ids
+ * as keys, and one with app ids.
+ */
+
+typedef struct 
+{
+       gchar *id;
+       gchar *name;
+       GPtrArray *apps;
+} GsFolder;
+
+struct GsFoldersPrivate
+{
+       GSettings *settings;
+       GHashTable *folders;
+       GHashTable *apps;
+};
+
+G_DEFINE_TYPE (GsFolders, gs_folders, G_TYPE_OBJECT)
+
+static GsFolder *
+gs_folder_new (const gchar *id, const gchar *name)
+{
+       GsFolder *folder;
+
+       folder = g_new0 (GsFolder, 1);
+       folder->id = g_strdup (id);
+       folder->name = g_strdup (name ? name : id);
+       folder->apps = g_ptr_array_new_with_free_func (g_free);
+
+       return folder;
+}
+
+static void
+gs_folder_free (GsFolder *folder)
+{
+       g_free (folder->id);
+       g_free (folder->name);
+       g_ptr_array_free (folder->apps, TRUE);
+       g_free (folder);
+}
+
+static void
+gs_folders_class_init (GsFoldersClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       object_class->finalize = gs_folders_finalize;
+       g_type_class_add_private (klass, sizeof (GsFoldersPrivate));
+}
+
+static const gchar *
+lookup_folder_name (const gchar *id)
+{
+       /* FIXME - we should consult directory files here.
+        * The one hardcoded entry here is just to test
+        * id-name separation.
+        */
+       if (g_strcmp0 (id, "other") == 0)
+               return "Sundry";
+
+       return id;
+}
+
+static void
+load (GsFolders *folders)
+{
+       GVariant *v;
+       GVariantIter iter;
+       const gchar *id;
+       GVariantIter *apps;
+       GsFolder *folder;
+       gchar *app;
+       guint i;
+
+       folders->priv->folders = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, 
(GDestroyNotify)gs_folder_free);
+       folders->priv->apps = g_hash_table_new (g_str_hash, g_str_equal);
+
+       v = g_settings_get_value (folders->priv->settings, "app-folders");
+       g_variant_iter_init (&iter, v);
+       while (g_variant_iter_next (&iter, "{&sas}", &id, &apps)) {
+
+               folder = gs_folder_new (id, lookup_folder_name (id));
+               while (g_variant_iter_next (apps, "s", &app)) {
+                       g_ptr_array_add (folder->apps, app);
+               }
+               
+               g_hash_table_insert (folders->priv->folders, (gpointer)folder->id, folder);
+               for (i = 0; i < folder->apps->len; i++) {
+                       g_hash_table_insert (folders->priv->apps, g_ptr_array_index (folder->apps, i), 
folder);
+               }
+
+               g_variant_iter_free (apps);
+       }
+       g_variant_unref (v);
+}
+
+static void
+save (GsFolders *folders)
+{
+       GHashTableIter iter;
+       GVariantBuilder builder;
+       GsFolder *folder;
+       
+       g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sas}"));
+       g_hash_table_iter_init (&iter, folders->priv->folders);
+       while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&folder)) {
+               g_ptr_array_add (folder->apps, NULL);
+               g_variant_builder_add (&builder, "{s^as}",
+                                      folder->id, folder->apps->pdata);
+               g_ptr_array_remove (folder->apps, NULL);
+       }
+
+       g_settings_set_value (folders->priv->settings, "app-folders", g_variant_builder_end (&builder));
+       
+}
+
+static void
+clear (GsFolders *folders)
+{
+       g_hash_table_unref (folders->priv->apps);
+       g_hash_table_unref (folders->priv->folders);
+
+       folders->priv->apps = NULL;
+       folders->priv->folders = NULL;
+}
+
+static void
+gs_folders_init (GsFolders *folders)
+{
+       folders->priv = GS_FOLDERS_GET_PRIVATE (folders);
+
+       folders->priv->settings = g_settings_new ("org.gnome.software");
+       load (folders);
+}
+
+static void
+gs_folders_finalize (GObject *object)
+{
+       GsFolders *folders = GS_FOLDERS (object);
+
+       clear (folders);
+       g_object_unref (folders->priv->settings);
+
+       G_OBJECT_CLASS (gs_folders_parent_class)->finalize (object);
+}
+
+static GsFolders *
+gs_folders_new (void)
+{
+       return GS_FOLDERS (g_object_new (GS_TYPE_FOLDERS, NULL));
+}
+
+static GsFolders *singleton;
+
+GsFolders *
+gs_folders_get (void)
+{
+       if (!singleton)
+               singleton = gs_folders_new ();
+
+       return g_object_ref (singleton);        
+}
+
+gchar **
+gs_folders_get_folders (GsFolders *folders)
+{
+       return (gchar**) g_hash_table_get_keys_as_array (folders->priv->folders, NULL);
+}
+
+const gchar **
+gs_folders_get_apps (GsFolders *folders, const gchar *id)
+{
+       GsFolder *folder;
+
+       folder = g_hash_table_lookup (folders->priv->folders, id);
+
+       return folder ? (const gchar**)folder->apps->pdata : NULL;
+}
+
+void
+gs_folders_add_folder (GsFolders *folders, const gchar *id)
+{
+       GsFolder *folder;
+
+       folder = g_hash_table_lookup (folders->priv->folders, id);
+       if (!folder) {
+               folder = gs_folder_new (id, id);
+               g_hash_table_insert (folders->priv->folders, folder->id, folder);
+       }
+}
+
+void
+gs_folders_remove_folder (GsFolders *folders, const gchar *id)
+{
+       GsFolder *folder;
+       guint i;
+
+       if (id == NULL)
+               return;
+
+       folder = g_hash_table_lookup (folders->priv->folders, id);
+       if (folder) {
+               for (i = 0; i < folder->apps->len; i++) {
+                       g_hash_table_remove (folders->priv->apps, g_ptr_array_index (folder->apps, i));
+               }
+               g_hash_table_remove (folders->priv->folders, folder->id);
+       }
+}
+
+const gchar *
+gs_folders_get_folder_name (GsFolders *folders, const gchar *id)
+{
+       GsFolder *folder;
+
+       folder = g_hash_table_lookup (folders->priv->folders, id);
+
+       return folder ? folder->name : NULL;
+}
+
+void
+gs_folders_set_folder_name (GsFolders *folders, const gchar *id, const gchar *name)
+{
+       GsFolder *folder;
+
+       folder = g_hash_table_lookup (folders->priv->folders, id);
+       if (folder) {
+               g_free (folder->name);
+               folder->name = g_strdup (name);
+       }
+}
+
+const gchar *
+gs_folders_get_app_folder (GsFolders *folders, const gchar *app)
+{
+       GsFolder *folder;
+
+       folder = g_hash_table_lookup (folders->priv->apps, app);
+
+       return folder ? folder->id : NULL;
+}
+
+void
+gs_folders_set_app_folder (GsFolders *folders, const gchar *app, const gchar *id)
+{
+       GsFolder *folder;
+       GsFolder *old_folder = NULL;
+       gchar *app_id = NULL;
+
+       g_hash_table_lookup_extended (folders->priv->apps, app, (gpointer *)&app_id, (gpointer *)&old_folder);
+
+       if (old_folder) {
+               g_hash_table_remove (folders->priv->apps, app_id);
+               g_ptr_array_remove (old_folder->apps, app_id);
+       }
+
+       if (id) {
+               app_id = g_strdup (app);
+               folder = g_hash_table_lookup (folders->priv->folders, id);
+               g_ptr_array_add (folder->apps, app_id);
+               g_hash_table_insert (folders->priv->apps, app_id, folder);
+       }
+}
+
+void
+gs_folders_save (GsFolders *folders)
+{
+       save (folders);
+}
+
+void
+gs_folders_revert (GsFolders *folders)
+{
+       clear (folders);
+       load (folders);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-folders.h b/src/gs-folders.h
new file mode 100644
index 0000000..41f447f
--- /dev/null
+++ b/src/gs-folders.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2013 Matthias Clasen <mclasen redhat com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GS_FOLDERS_H
+#define __GS_FOLDERS_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_FOLDERS                (gs_folders_get_type ())
+#define GS_FOLDERS(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_FOLDERS, GsFolders))
+#define GS_FOLDERS_CLASS(k)            (G_TYPE_CHECK_CLASS_CAST((k), GS_TYPE_FOLDERS, GsFoldersClass))
+#define GS_IS_FOLDERS(o)               (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_FOLDERS))
+#define GS_IS_FOLDERS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GS_TYPE_FOLDERS))
+#define GS_FOLDERS_GET_CLASS(o)        (G_TYPE_INSTANCE_GET_CLASS ((o), GS_TYPE_FOLDERS, GsFoldersClass))
+
+typedef struct GsFoldersPrivate GsFoldersPrivate;
+
+typedef struct
+{
+        GObject                 parent;
+        GsFoldersPrivate       *priv;
+} GsFolders;
+
+typedef struct
+{
+       GObjectClass             parent_class;
+} GsFoldersClass;
+
+GType            gs_folders_get_type           (void);
+
+GsFolders       *gs_folders_get                (void);
+
+gchar          **gs_folders_get_folders        (GsFolders      *folders);
+const gchar    **gs_folders_get_apps           (GsFolders      *folders,
+                                                const gchar    *id);
+void             gs_folders_add_folder         (GsFolders      *folders,
+                                                const gchar    *id);
+void             gs_folders_remove_folder      (GsFolders      *folders,
+                                                const gchar    *id);
+const gchar     *gs_folders_get_folder_name    (GsFolders      *folders,
+                                                const gchar    *id);
+void             gs_folders_set_folder_name    (GsFolders      *folders,
+                                                const gchar    *id,
+                                                const gchar    *name);
+const gchar     *gs_folders_get_app_folder     (GsFolders      *folders,
+                                                const gchar    *app);
+void             gs_folders_set_app_folder     (GsFolders      *folders,
+                                                const gchar    *app,
+                                                const gchar    *id);
+void             gs_folders_save               (GsFolders      *folders);
+void             gs_folders_revert             (GsFolders      *folders);
+
+G_END_DECLS
+
+#endif /* __GS_FOLDERS_H */
+
+/* vim: set noexpandtab: */


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