[gnome-software] Refactor the installed application handling to a seporate file



commit f988add4f5ff4773ef29994c306835f58c0c9081
Author: Richard Hughes <richard hughsie com>
Date:   Thu Aug 22 09:23:40 2013 +0100

    Refactor the installed application handling to a seporate file

 src/Makefile.am          |    2 +
 src/gs-main.c            |  349 ++++----------------------------------
 src/gs-shell-installed.c |  424 ++++++++++++++++++++++++++++++++++++++++++++++
 src/gs-shell-installed.h |   61 +++++++
 4 files changed, 519 insertions(+), 317 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index caf8fb7..0e6bd87 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,6 +35,8 @@ gnome_software_SOURCES =                              \
        gs-app-widget.h                                 \
        gs-plugin.c                                     \
        gs-plugin.h                                     \
+       gs-shell-installed.c                            \
+       gs-shell-installed.h                            \
        gs-shell-updates.c                              \
        gs-shell-updates.h                              \
        gs-plugin-loader.c                              \
diff --git a/src/gs-main.c b/src/gs-main.c
index 8a76f6e..0e805af 100644
--- a/src/gs-main.c
+++ b/src/gs-main.c
@@ -29,6 +29,7 @@
 #include "gs-app-widget.h"
 #include "gs-resources.h"
 #include "gs-shell-updates.h"
+#include "gs-shell-installed.h"
 #include "gs-plugin-loader.h"
 
 typedef enum {
@@ -48,15 +49,13 @@ typedef struct {
        GtkBuilder              *builder;
        PkTask                  *task;
        guint                    waiting_tab_id;
-       GtkListBox              *list_box_installed;
        GtkCssProvider          *provider;
        gboolean                 ignore_primary_buttons;
        GsPluginLoader          *plugin_loader;
        guint                    tab_back_id;
         gint                     pending_apps;
        GsShellUpdates          *shell_updates;
-        GtkSizeGroup            *sizegroup_image;
-        GtkSizeGroup            *sizegroup_name;
+       GsShellInstalled        *shell_installed;
 } GsMainPrivate;
 
 static void gs_main_set_overview_mode_ui (GsMainPrivate *priv, GsMainMode mode, GsApp *app);
@@ -87,6 +86,7 @@ gs_main_show_waiting_tab_cb (gpointer user_data)
        return FALSE;
 }
 
+#if 0
 /**
  * gs_main_get_app_widget_for_id:
  **/
@@ -110,7 +110,9 @@ out:
        g_list_free (list);
        return tmp;
 }
+#endif
 
+#if 0
 /**
  * gs_main_progress_cb:
  **/
@@ -151,12 +153,12 @@ gs_main_progress_cb (PkProgress *progress,
                                      NULL);
                        g_warning ("need to find %s and update",
                                   pk_item_progress_get_package_id (item_progress));
-                       app_widget = gs_main_get_app_widget_for_id (priv->list_box_installed,
-                                                                   pk_item_progress_get_package_id 
(item_progress));
-                       if (app_widget != NULL) {
-                               gs_app_widget_set_kind (app_widget, GS_APP_WIDGET_KIND_BUSY);
-                               gs_app_widget_set_status (app_widget, pk_status_enum_to_string (status));
-                       }
+//                     app_widget = gs_main_get_app_widget_for_id (priv->list_box_installed,
+//                                                                 pk_item_progress_get_package_id 
(item_progress));
+//                     if (app_widget != NULL) {
+//                             gs_app_widget_set_kind (app_widget, GS_APP_WIDGET_KIND_BUSY);
+//                             gs_app_widget_set_status (app_widget, pk_status_enum_to_string (status));
+//                     }
                }
                return;
        }
@@ -229,6 +231,7 @@ gs_main_progress_cb (PkProgress *progress,
                }
        }
 }
+#endif
 
 /**
  * gs_main_progress_cb:
@@ -289,6 +292,7 @@ gs_main_plugin_loader_status_changed_cb (GsPluginLoader *plugin_loader,
        }
 }
 
+#if 0
 static void
 update_pending_apps (GsMainPrivate *priv, gint delta)
 {
@@ -308,6 +312,7 @@ update_pending_apps (GsMainPrivate *priv, gint delta)
         gtk_label_set_label (GTK_LABEL (widget), label);
         g_free (label);
 }
+#endif
 
 typedef struct {
        GsAppWidget     *app_widget;
@@ -316,6 +321,7 @@ typedef struct {
        const gchar     *package_id;
 } GsMainMethodData;
 
+#if 0
 /**
  * gs_main_remove_packages_cb:
  **/
@@ -360,12 +366,12 @@ gs_main_remove_packages_cb (PkClient *client,
        for (i = 0; i < array->len; i++) {
                package = g_ptr_array_index (array, i);
                g_debug ("removed %s", pk_package_get_id (package));
-               app_widget = gs_main_get_app_widget_for_id (data->priv->list_box_installed,
-                                                           pk_package_get_id (package));
-               if (app_widget != NULL) {
-                       gtk_container_remove (GTK_CONTAINER (data->priv->list_box_installed),
-                                             GTK_WIDGET (app_widget));
-               }
+//             app_widget = gs_main_get_app_widget_for_id (data->priv->list_box_installed,
+//                                                         pk_package_get_id (package));
+//             if (app_widget != NULL) {
+//                     gtk_container_remove (GTK_CONTAINER (data->priv->list_box_installed),
+//                                           GTK_WIDGET (app_widget));
+//             }
 //             app_widget = gs_main_get_app_widget_for_id (data->priv->list_box_updates,
 //                                                         pk_package_get_id (package));
 //             if (app_widget != NULL) {
@@ -382,7 +388,9 @@ out:
        if (results != NULL)
                g_object_unref (results);
 }
+#endif
 
+#if 0
 /**
  * gs_main_app_widget_button_clicked_cb:
  **/
@@ -478,170 +486,7 @@ gs_main_app_widget_button_clicked_cb (GsAppWidget *app_widget, GsMainPrivate *pr
                gtk_widget_destroy (dialog);
        }
 }
-
-static void
-gs_main_app_widget_read_more_clicked_cb (GsAppWidget *app_widget, GsMainPrivate *priv)
-{
-        GtkWidget *details, *button, *grid;
-        GtkWidget *image, *label;
-        GsApp *app;
-        PangoAttrList *attr_list;
-        const gchar *tmp;
-
-        app = gs_app_widget_get_app (app_widget);
-
-        details = gtk_dialog_new_with_buttons (_("Details"),
-                                               GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET 
(app_widget))),
-                                               GTK_DIALOG_MODAL,
-                                               _("_Done"), GTK_RESPONSE_CLOSE,
-                                               NULL);
-        gtk_container_set_border_width (GTK_CONTAINER (details), 20);
-        button = gtk_dialog_get_widget_for_response (GTK_DIALOG (details), GTK_RESPONSE_CLOSE);
-        gtk_style_context_add_class (gtk_widget_get_style_context (button), "suggested-action");
-        g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), details);
-
-        grid = gtk_grid_new ();
-        gtk_widget_show (grid);
-        gtk_widget_set_halign (grid, GTK_ALIGN_FILL);
-        gtk_grid_set_column_spacing (GTK_GRID (grid), 20);
-        gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (details))), grid);
-
-        image = gtk_image_new ();
-        if (gs_app_get_pixbuf (app)) {
-                gtk_image_set_from_pixbuf (GTK_IMAGE (image), gs_app_get_pixbuf (app));         
gtk_widget_show (image);
-        }
-        gtk_grid_attach (GTK_GRID (grid), image, 0, 0, 1, 3);
-
-        label = gtk_label_new (gs_app_get_name (app));
-        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
-        gtk_widget_set_hexpand (label, TRUE);
-        gtk_widget_set_margin_bottom (label, 10);
-        attr_list = pango_attr_list_new ();
-        pango_attr_list_insert (attr_list, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
-        pango_attr_list_insert (attr_list, pango_attr_scale_new (1));
-        gtk_label_set_attributes (GTK_LABEL (label), attr_list);
-        pango_attr_list_unref (attr_list);
-        gtk_widget_show (label);
-        gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
-
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
-        gtk_widget_set_hexpand (label, TRUE);
-        gtk_widget_set_margin_bottom (label, 20);
-        if (gs_app_get_summary (app)) {
-                gtk_label_set_label (GTK_LABEL (label), gs_app_get_summary (app));
-                gtk_widget_show (label);
-        }
-        gtk_grid_attach (GTK_GRID (grid), label, 1, 1, 1, 1);
-        tmp = gs_app_get_description (app);
-        if (!tmp) {
-                tmp = _("The author of this software has not included a long description.");
-        }
-        label = gtk_label_new (tmp);
-        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
-        gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
-        gtk_widget_show (label);
-        gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 2, 1);
-
-        if (gs_app_get_url (app)) {
-                button = gtk_link_button_new_with_label (gs_app_get_url (app), _("Visit website"));
-                gtk_widget_set_halign (button, GTK_ALIGN_START);
-                gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
-                gtk_widget_show (button);
-                gtk_grid_attach (GTK_GRID (grid), button, 0, 4, 2, 1);
-        }
-
-        gtk_window_present (GTK_WINDOW (details));
-}
-
-/**
- * _gtk_container_remove_all_cb:
- **/
-static void
-_gtk_container_remove_all_cb (GtkWidget *widget, gpointer user_data)
-{
-       GtkContainer *container = GTK_CONTAINER (user_data);
-       gtk_container_remove (container, widget);
-}
-
-/**
- * _gtk_container_remove_all:
- **/
-static void
-_gtk_container_remove_all (GtkContainer *container)
-{
-       gtk_container_foreach (container,
-                              _gtk_container_remove_all_cb,
-                              container);
-}
-
-/**
- * gs_main_get_installed_cb:
- **/
-static void
-gs_main_get_installed_cb (GObject *source_object,
-                         GAsyncResult *res,
-                         gpointer user_data)
-{
-       GError *error = NULL;
-       GList *l;
-       GList *list;
-       GsApp *app;
-       GsMainPrivate *priv = (GsMainPrivate *) user_data;
-       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
-       GtkWidget *widget;
-
-       list = gs_plugin_loader_get_installed_finish (plugin_loader,
-                                                     res,
-                                                     &error);
-       if (list == NULL) {
-               g_warning ("failed to get installed apps: %s", error->message);
-               g_error_free (error);
-               goto out;
-       }
-       for (l = list; l != NULL; l = l->next) {
-               app = GS_APP (l->data);
-               g_debug ("adding installed %s", gs_app_get_id (app));
-               widget = gs_app_widget_new ();
-               g_signal_connect (widget, "button-clicked",
-                                 G_CALLBACK (gs_main_app_widget_button_clicked_cb),
-                                 priv);
-               g_signal_connect (widget, "read-more-clicked",
-                                 G_CALLBACK (gs_main_app_widget_read_more_clicked_cb),
-                                 priv);
-
-               gs_app_widget_set_kind (GS_APP_WIDGET (widget),
-                                       gs_app_get_kind (app) == GS_APP_KIND_SYSTEM ? 
GS_APP_WIDGET_KIND_BLANK : GS_APP_WIDGET_KIND_REMOVE);
-               gs_app_widget_set_app (GS_APP_WIDGET (widget), app);
-               gtk_container_add (GTK_CONTAINER (priv->list_box_installed), widget);
-                gs_app_widget_set_size_groups (GS_APP_WIDGET (widget),
-                                               priv->sizegroup_image,
-                                               priv->sizegroup_name);
-               gtk_widget_show (widget);
-       }
-
-       /* focus back to the text extry */
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
-       gtk_widget_grab_focus (widget);
-out:
-       return;
-}
-
-/**
- * gs_main_get_installed:
- **/
-static void
-gs_main_get_installed (GsMainPrivate *priv)
-{
-       /* remove old entries */
-       _gtk_container_remove_all (GTK_CONTAINER (priv->list_box_installed));
-
-       /* get popular apps */
-       gs_plugin_loader_get_installed_async (priv->plugin_loader,
-                                             priv->cancellable,
-                                             gs_main_get_installed_cb,
-                                             priv);
-}
+#endif
 
 static void
 app_tile_clicked (GtkButton *button, gpointer data)
@@ -1136,7 +981,7 @@ gs_main_set_overview_mode (GsMainPrivate *priv, GsMainMode mode, GsApp *app, con
                gs_main_get_categories (priv);
                break;
        case GS_MAIN_MODE_INSTALLED:
-               gs_main_get_installed (priv);
+               gs_shell_installed_refresh (priv->shell_installed, priv->cancellable);
                break;
        case GS_MAIN_MODE_UPDATES:
                gs_shell_updates_refresh (priv->shell_updates, priv->cancellable);
@@ -1313,115 +1158,6 @@ gs_main_setup_featured (GsMainPrivate *priv)
 }
 
 /**
- * gs_main_utf8_filter_helper:
- **/
-static gboolean
-gs_main_utf8_filter_helper (const gchar *haystack, const gchar *needle_utf8)
-{
-       gboolean ret;
-       gchar *haystack_utf8;
-       haystack_utf8 = g_utf8_casefold (haystack, -1);
-       ret = strstr (haystack_utf8, needle_utf8) != NULL;
-       g_free (haystack_utf8);
-       return ret;
-}
-
-/**
- * gs_main_list_header_func
- **/
-static void
-gs_main_list_header_func (GtkListBoxRow *row,
-                         GtkListBoxRow *before,
-                         gpointer user_data)
-{
-       GtkWidget *header;
-
-       /* first entry */
-       header = gtk_list_box_row_get_header (row);
-       if (before == NULL) {
-               gtk_list_box_row_set_header (row, NULL);
-               return;
-       }
-
-       /* already set */
-       if (header != NULL)
-               return;
-
-       /* set new */
-       header = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
-       gtk_list_box_row_set_header (row, header);
-}
-
-/**
- * gs_main_installed_filter_func:
- **/
-static gboolean
-gs_main_installed_filter_func (GtkListBoxRow *row, void *user_data)
-{
-       const gchar *tmp;
-       GtkWidget *widget;
-       GsMainPrivate *priv = (GsMainPrivate *) user_data;
-       GsAppWidget *app_widget = GS_APP_WIDGET (gtk_bin_get_child (GTK_BIN (row)));
-       gchar *needle_utf8 = NULL;
-       gboolean ret = TRUE;
-       GsApp *app;
-
-       app = gs_app_widget_get_app (app_widget);
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
-       tmp = gtk_entry_get_text (GTK_ENTRY (widget));
-       if (tmp[0] == '\0')
-               goto out;
-
-       needle_utf8 = g_utf8_casefold (tmp, -1);
-       ret = gs_main_utf8_filter_helper (gs_app_get_name (app),
-                                         needle_utf8);
-       if (ret)
-               goto out;
-       ret = gs_main_utf8_filter_helper (gs_app_get_summary (app),
-                                         needle_utf8);
-       if (ret)
-               goto out;
-       ret = gs_main_utf8_filter_helper (gs_app_get_version (app),
-                                         needle_utf8);
-       if (ret)
-               goto out;
-       ret = gs_main_utf8_filter_helper (gs_app_get_id (app),
-                                         needle_utf8);
-       if (ret)
-               goto out;
-out:
-       g_free (needle_utf8);
-       return ret;
-}
-
-
-/**
- * gs_main_filter_text_changed_cb:
- **/
-static gboolean
-gs_main_filter_text_changed_cb (GtkEntry *entry, GsMainPrivate *priv)
-{
-       gtk_list_box_invalidate_filter (priv->list_box_installed);
-       return FALSE;
-}
-
-/**
- * gs_main_installed_sort_func:
- **/
-static gint
-gs_main_installed_sort_func (GtkListBoxRow *a,
-                            GtkListBoxRow *b,
-                            gpointer user_data)
-{
-       GsAppWidget *aw1 = GS_APP_WIDGET (gtk_bin_get_child (GTK_BIN (a)));
-       GsAppWidget *aw2 = GS_APP_WIDGET (gtk_bin_get_child (GTK_BIN (b)));
-       GsApp *a1 = gs_app_widget_get_app (aw1);
-       GsApp *a2 = gs_app_widget_get_app (aw2);
-       return g_strcmp0 (gs_app_get_name (a1),
-                         gs_app_get_name (a2));
-}
-
-/**
  * gs_main_startup_cb:
  **/
 static void
@@ -1491,28 +1227,6 @@ gs_main_startup_cb (GApplication *application, GsMainPrivate *priv)
 
        /* setup featured tiles */
        gs_main_setup_featured (priv);
-       /* setup installed */
-       priv->list_box_installed = GTK_LIST_BOX (gtk_list_box_new ());
-       gtk_list_box_set_header_func (priv->list_box_installed,
-                                     gs_main_list_header_func,
-                                     priv,
-                                     NULL);
-       gtk_list_box_set_filter_func (priv->list_box_installed,
-                                     gs_main_installed_filter_func,
-                                     priv,
-                                     NULL);
-       gtk_list_box_set_sort_func (priv->list_box_installed,
-                                   gs_main_installed_sort_func,
-                                   priv,
-                                   NULL);
-       gtk_list_box_set_selection_mode (priv->list_box_installed,
-                                        GTK_SELECTION_NONE);
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "scrolledwindow_install"));
-       gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (priv->list_box_installed));
-       gtk_widget_show (GTK_WIDGET (priv->list_box_installed));
-
-        priv->sizegroup_image = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
-        priv->sizegroup_name = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
        /* setup buttons */
        widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
@@ -1549,16 +1263,15 @@ gs_main_startup_cb (GApplication *application, GsMainPrivate *priv)
                          G_CALLBACK (gs_main_button_updates_back_cb), priv);
         
 
-       /* setup updates UI */
+       /* setup UI */
        priv->shell_updates = gs_shell_updates_new ();
        gs_shell_updates_setup (priv->shell_updates,
                                priv->plugin_loader,
                                priv->builder);
-
-       /* refilter on search box changing */
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
-       g_signal_connect (GTK_EDITABLE (widget), "changed",
-                         G_CALLBACK (gs_main_filter_text_changed_cb), priv);
+       priv->shell_installed = gs_shell_installed_new ();
+       gs_shell_installed_setup (priv->shell_installed,
+                                 priv->plugin_loader,
+                                 priv->builder);
 
        /* show the status on a different page */
        g_signal_connect (priv->plugin_loader, "status-changed",
@@ -1676,6 +1389,8 @@ out:
                g_object_unref (priv->application);
                if (priv->shell_updates != NULL)
                        g_object_unref (priv->shell_updates);
+               if (priv->shell_installed != NULL)
+                       g_object_unref (priv->shell_installed);
                if (priv->provider != NULL)
                        g_object_unref (priv->provider);
                if (priv->builder != NULL)
diff --git a/src/gs-shell-installed.c b/src/gs-shell-installed.c
new file mode 100644
index 0000000..b681a78
--- /dev/null
+++ b/src/gs-shell-installed.c
@@ -0,0 +1,424 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie 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 <string.h>
+#include <glib/gi18n.h>
+
+#include "gs-shell-installed.h"
+#include "gs-app.h"
+#include "gs-app-widget.h"
+
+static void    gs_shell_installed_finalize     (GObject        *object);
+
+#define GS_SHELL_INSTALLED_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_SHELL_INSTALLED, 
GsShellInstalledPrivate))
+
+struct GsShellInstalledPrivate
+{
+       GsPluginLoader          *plugin_loader;
+       GtkBuilder              *builder;
+       GtkListBox              *list_box_installed;
+       GtkSizeGroup            *sizegroup_image;
+       GtkSizeGroup            *sizegroup_name;
+};
+
+enum {
+       COLUMN_UPDATE_APP,
+       COLUMN_UPDATE_NAME,
+       COLUMN_UPDATE_VERSION,
+       COLUMN_UPDATE_LAST
+};
+
+G_DEFINE_TYPE (GsShellInstalled, gs_shell_installed, G_TYPE_OBJECT)
+
+/**
+ * _gtk_container_remove_all_cb:
+ **/
+static void
+_gtk_container_remove_all_cb (GtkWidget *widget, gpointer user_data)
+{
+       GtkContainer *container = GTK_CONTAINER (user_data);
+       gtk_container_remove (container, widget);
+}
+
+/**
+ * _gtk_container_remove_all:
+ **/
+static void
+_gtk_container_remove_all (GtkContainer *container)
+{
+       gtk_container_foreach (container,
+                              _gtk_container_remove_all_cb,
+                              container);
+}
+
+static void
+gs_shell_installed_app_widget_read_more_clicked_cb (GsAppWidget *app_widget,
+                                                   GsShellInstalled *shell_installed)
+{
+       const gchar *tmp;
+       GsApp *app;
+       GtkWidget *details, *button, *grid;
+       GtkWidget *image, *label;
+       PangoAttrList *attr_list;
+
+       app = gs_app_widget_get_app (app_widget);
+
+       details = gtk_dialog_new_with_buttons (_("Details"),
+                                              GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (app_widget))),
+                                              GTK_DIALOG_MODAL,
+                                              _("_Done"), GTK_RESPONSE_CLOSE,
+                                              NULL);
+       gtk_container_set_border_width (GTK_CONTAINER (details), 20);
+       button = gtk_dialog_get_widget_for_response (GTK_DIALOG (details), GTK_RESPONSE_CLOSE);
+       gtk_style_context_add_class (gtk_widget_get_style_context (button), "suggested-action");
+       g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), details);
+
+       grid = gtk_grid_new ();
+       gtk_widget_show (grid);
+       gtk_widget_set_halign (grid, GTK_ALIGN_FILL);
+       gtk_grid_set_column_spacing (GTK_GRID (grid), 20);
+       gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (details))), grid);
+
+       image = gtk_image_new ();
+       if (gs_app_get_pixbuf (app)) {
+               gtk_image_set_from_pixbuf (GTK_IMAGE (image), gs_app_get_pixbuf (app));  gtk_widget_show 
(image);
+       }
+       gtk_grid_attach (GTK_GRID (grid), image, 0, 0, 1, 3);
+
+       label = gtk_label_new (gs_app_get_name (app));
+       gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+       gtk_widget_set_hexpand (label, TRUE);
+       gtk_widget_set_margin_bottom (label, 10);
+       attr_list = pango_attr_list_new ();
+       pango_attr_list_insert (attr_list, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+       pango_attr_list_insert (attr_list, pango_attr_scale_new (1));
+       gtk_label_set_attributes (GTK_LABEL (label), attr_list);
+       pango_attr_list_unref (attr_list);
+       gtk_widget_show (label);
+       gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
+
+       label = gtk_label_new (NULL);
+       gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+       gtk_widget_set_hexpand (label, TRUE);
+       gtk_widget_set_margin_bottom (label, 20);
+       if (gs_app_get_summary (app)) {
+               gtk_label_set_label (GTK_LABEL (label), gs_app_get_summary (app));
+               gtk_widget_show (label);
+       }
+       gtk_grid_attach (GTK_GRID (grid), label, 1, 1, 1, 1);
+       tmp = gs_app_get_description (app);
+       if (!tmp) {
+               tmp = _("The author of this software has not included a long description.");
+       }
+       label = gtk_label_new (tmp);
+       gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+       gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+       gtk_widget_show (label);
+       gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 2, 1);
+
+       if (gs_app_get_url (app)) {
+               button = gtk_link_button_new_with_label (gs_app_get_url (app), _("Visit website"));
+               gtk_widget_set_halign (button, GTK_ALIGN_START);
+               gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+               gtk_widget_show (button);
+               gtk_grid_attach (GTK_GRID (grid), button, 0, 4, 2, 1);
+       }
+
+       gtk_window_present (GTK_WINDOW (details));
+}
+
+/**
+ * gs_shell_installed_get_installed_cb:
+ **/
+static void
+gs_shell_installed_get_installed_cb (GObject *source_object,
+                                    GAsyncResult *res,
+                                    gpointer user_data)
+{
+       GError *error = NULL;
+       GList *l;
+       GList *list;
+       GsApp *app;
+       GsShellInstalled *shell_installed = GS_SHELL_INSTALLED (user_data);
+       GsShellInstalledPrivate *priv = shell_installed->priv;
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
+       GtkWidget *widget;
+
+       list = gs_plugin_loader_get_installed_finish (plugin_loader,
+                                                     res,
+                                                     &error);
+       if (list == NULL) {
+               g_warning ("failed to get installed apps: %s", error->message);
+               g_error_free (error);
+               goto out;
+       }
+       for (l = list; l != NULL; l = l->next) {
+               app = GS_APP (l->data);
+               g_debug ("adding installed %s", gs_app_get_id (app));
+               widget = gs_app_widget_new ();
+//FIXME: We need to connect this to allow removal in the list
+//             g_signal_connect (widget, "button-clicked",
+//                               G_CALLBACK (gs_shell_installed_app_widget_button_clicked_cb),
+//                               shell_installed);
+               g_signal_connect (widget, "read-more-clicked",
+                                 G_CALLBACK (gs_shell_installed_app_widget_read_more_clicked_cb),
+                                 shell_installed);
+
+               gs_app_widget_set_kind (GS_APP_WIDGET (widget),
+                                       gs_app_get_kind (app) == GS_APP_KIND_SYSTEM ? 
GS_APP_WIDGET_KIND_BLANK : GS_APP_WIDGET_KIND_REMOVE);
+               gs_app_widget_set_app (GS_APP_WIDGET (widget), app);
+               gtk_container_add (GTK_CONTAINER (priv->list_box_installed), widget);
+               gs_app_widget_set_size_groups (GS_APP_WIDGET (widget),
+                                              priv->sizegroup_image,
+                                              priv->sizegroup_name);
+               gtk_widget_show (widget);
+       }
+
+       /* focus back to the text extry */
+       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
+       gtk_widget_grab_focus (widget);
+out:
+       return;
+}
+
+/**
+ * gs_shell_installed_refresh:
+ **/
+void
+gs_shell_installed_refresh (GsShellInstalled *shell_installed,
+                           GCancellable *cancellable)
+{
+       GsShellInstalledPrivate *priv = shell_installed->priv;
+
+       /* remove old entries */
+       _gtk_container_remove_all (GTK_CONTAINER (priv->list_box_installed));
+
+       /* get popular apps */
+       gs_plugin_loader_get_installed_async (priv->plugin_loader,
+                                             cancellable,
+                                             gs_shell_installed_get_installed_cb,
+                                             shell_installed);
+}
+
+/**
+ * gs_shell_installed_filter_text_changed_cb:
+ **/
+static gboolean
+gs_shell_installed_filter_text_changed_cb (GtkEntry *entry,
+                                          GsShellInstalled *shell_installed)
+{
+       GsShellInstalledPrivate *priv = shell_installed->priv;
+       gtk_list_box_invalidate_filter (priv->list_box_installed);
+       return FALSE;
+}
+
+/**
+ * gs_shell_installed_sort_func:
+ **/
+static gint
+gs_shell_installed_sort_func (GtkListBoxRow *a,
+                             GtkListBoxRow *b,
+                             gpointer user_data)
+{
+       GsAppWidget *aw1 = GS_APP_WIDGET (gtk_bin_get_child (GTK_BIN (a)));
+       GsAppWidget *aw2 = GS_APP_WIDGET (gtk_bin_get_child (GTK_BIN (b)));
+       GsApp *a1 = gs_app_widget_get_app (aw1);
+       GsApp *a2 = gs_app_widget_get_app (aw2);
+       return g_strcmp0 (gs_app_get_name (a1),
+                         gs_app_get_name (a2));
+}
+
+/**
+ * gs_shell_installed_utf8_filter_helper:
+ **/
+static gboolean
+gs_shell_installed_utf8_filter_helper (const gchar *haystack,
+                                      const gchar *needle_utf8)
+{
+       gboolean ret;
+       gchar *haystack_utf8;
+       haystack_utf8 = g_utf8_casefold (haystack, -1);
+       ret = strstr (haystack_utf8, needle_utf8) != NULL;
+       g_free (haystack_utf8);
+       return ret;
+}
+
+/**
+ * gs_shell_installed_filter_func:
+ **/
+static gboolean
+gs_shell_installed_filter_func (GtkListBoxRow *row, void *user_data)
+{
+       const gchar *tmp;
+       gboolean ret = TRUE;
+       gchar *needle_utf8 = NULL;
+       GsApp *app;
+       GsAppWidget *app_widget = GS_APP_WIDGET (gtk_bin_get_child (GTK_BIN (row)));
+       GsShellInstalled *shell_installed = GS_SHELL_INSTALLED (user_data);
+       GsShellInstalledPrivate *priv = shell_installed->priv;
+       GtkWidget *widget;
+
+       app = gs_app_widget_get_app (app_widget);
+       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
+       tmp = gtk_entry_get_text (GTK_ENTRY (widget));
+       if (tmp[0] == '\0')
+               goto out;
+
+       needle_utf8 = g_utf8_casefold (tmp, -1);
+       ret = gs_shell_installed_utf8_filter_helper (gs_app_get_name (app),
+                                         needle_utf8);
+       if (ret)
+               goto out;
+       ret = gs_shell_installed_utf8_filter_helper (gs_app_get_summary (app),
+                                         needle_utf8);
+       if (ret)
+               goto out;
+       ret = gs_shell_installed_utf8_filter_helper (gs_app_get_version (app),
+                                         needle_utf8);
+       if (ret)
+               goto out;
+       ret = gs_shell_installed_utf8_filter_helper (gs_app_get_id (app),
+                                         needle_utf8);
+       if (ret)
+               goto out;
+out:
+       g_free (needle_utf8);
+       return ret;
+}
+
+/**
+ * gs_shell_installed_list_header_func
+ **/
+static void
+gs_shell_installed_list_header_func (GtkListBoxRow *row,
+                                    GtkListBoxRow *before,
+                                    gpointer user_data)
+{
+       GtkWidget *header;
+
+       /* first entry */
+       header = gtk_list_box_row_get_header (row);
+       if (before == NULL) {
+               gtk_list_box_row_set_header (row, NULL);
+               return;
+       }
+
+       /* already set */
+       if (header != NULL)
+               return;
+
+       /* set new */
+       header = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+       gtk_list_box_row_set_header (row, header);
+}
+
+/**
+ * gs_shell_installed_setup:
+ */
+void
+gs_shell_installed_setup (GsShellInstalled *shell_installed,
+                         GsPluginLoader *plugin_loader,
+                         GtkBuilder *builder)
+{
+       GsShellInstalledPrivate *priv = shell_installed->priv;
+       GtkWidget *widget;
+
+       g_return_if_fail (GS_IS_SHELL_INSTALLED (shell_installed));
+
+       priv->plugin_loader = g_object_ref (plugin_loader);
+       priv->builder = g_object_ref (builder);
+
+       /* refilter on search box changing */
+       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
+       g_signal_connect (GTK_EDITABLE (widget), "changed",
+                         G_CALLBACK (gs_shell_installed_filter_text_changed_cb), shell_installed);
+
+       /* setup installed */
+       priv->list_box_installed = GTK_LIST_BOX (gtk_list_box_new ());
+       gtk_list_box_set_header_func (priv->list_box_installed,
+                                     gs_shell_installed_list_header_func,
+                                     shell_installed,
+                                     NULL);
+       gtk_list_box_set_filter_func (priv->list_box_installed,
+                                     gs_shell_installed_filter_func,
+                                     shell_installed,
+                                     NULL);
+       gtk_list_box_set_sort_func (priv->list_box_installed,
+                                   gs_shell_installed_sort_func,
+                                   shell_installed,
+                                   NULL);
+       gtk_list_box_set_selection_mode (priv->list_box_installed,
+                                        GTK_SELECTION_NONE);
+       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "scrolledwindow_install"));
+       gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (priv->list_box_installed));
+       gtk_widget_show (GTK_WIDGET (priv->list_box_installed));
+}
+
+/**
+ * gs_shell_installed_class_init:
+ **/
+static void
+gs_shell_installed_class_init (GsShellInstalledClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       object_class->finalize = gs_shell_installed_finalize;
+
+       g_type_class_add_private (klass, sizeof (GsShellInstalledPrivate));
+}
+
+/**
+ * gs_shell_installed_init:
+ **/
+static void
+gs_shell_installed_init (GsShellInstalled *shell_installed)
+{
+       shell_installed->priv = GS_SHELL_INSTALLED_GET_PRIVATE (shell_installed);
+       shell_installed->priv->sizegroup_image = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+       shell_installed->priv->sizegroup_name = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+}
+
+/**
+ * gs_shell_installed_finalize:
+ **/
+static void
+gs_shell_installed_finalize (GObject *object)
+{
+       GsShellInstalled *shell_installed = GS_SHELL_INSTALLED (object);
+       GsShellInstalledPrivate *priv = shell_installed->priv;
+
+       g_object_unref (priv->builder);
+       g_object_unref (priv->plugin_loader);
+
+       G_OBJECT_CLASS (gs_shell_installed_parent_class)->finalize (object);
+}
+
+/**
+ * gs_shell_installed_new:
+ **/
+GsShellInstalled *
+gs_shell_installed_new (void)
+{
+       GsShellInstalled *shell_installed;
+       shell_installed = g_object_new (GS_TYPE_SHELL_INSTALLED, NULL);
+       return GS_SHELL_INSTALLED (shell_installed);
+}
diff --git a/src/gs-shell-installed.h b/src/gs-shell-installed.h
new file mode 100644
index 0000000..a1bbb44
--- /dev/null
+++ b/src/gs-shell-installed.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie 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_SHELL_INSTALLED_H
+#define __GS_SHELL_INSTALLED_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gs-plugin-loader.h"
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_SHELL_INSTALLED                (gs_shell_installed_get_type ())
+#define GS_SHELL_INSTALLED(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_SHELL_INSTALLED, 
GsShellInstalled))
+#define GS_SHELL_INSTALLED_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), GS_TYPE_SHELL_INSTALLED, 
GsShellInstalledClass))
+#define GS_IS_SHELL_INSTALLED(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_SHELL_INSTALLED))
+#define GS_IS_SHELL_INSTALLED_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GS_TYPE_SHELL_INSTALLED))
+#define GS_SHELL_INSTALLED_GET_CLASS(o)        (G_TYPE_INSTANCE_GET_CLASS ((o), GS_TYPE_SHELL_INSTALLED, 
GsShellInstalledClass))
+
+typedef struct GsShellInstalledPrivate GsShellInstalledPrivate;
+
+typedef struct
+{
+        GObject                         parent;
+        GsShellInstalledPrivate        *priv;
+} GsShellInstalled;
+
+typedef struct
+{
+       GObjectClass                     parent_class;
+} GsShellInstalledClass;
+
+GType           gs_shell_installed_get_type    (void);
+
+GsShellInstalled *gs_shell_installed_new       (void);
+void            gs_shell_installed_refresh     (GsShellInstalled       *shell_installed,
+                                                GCancellable           *cancellable);
+void            gs_shell_installed_setup       (GsShellInstalled       *shell_installed,
+                                                GsPluginLoader         *plugin_loader,
+                                                GtkBuilder             *builder);
+
+#endif /* __GS_SHELL_INSTALLED_H */


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