Commit 8e83ad51 authored by Richard Hughes's avatar Richard Hughes
Browse files

Use the AppStream data to populate the category tree

parent e62a17be
......@@ -359,6 +359,7 @@ typedef struct {
GSimpleAsyncResult *res;
GsPluginLoader *plugin_loader;
gchar *value;
GsCategory *category;
} GsPluginLoaderAsyncState;
/******************************************************************************/
......@@ -1155,7 +1156,7 @@ cd_plugin_loader_get_category_apps_thread_cb (GSimpleAsyncResult *res,
GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) g_object_get_data (G_OBJECT (cancellable), "state");
GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
GsPlugin *plugin;
GsPluginSearchFunc plugin_func = NULL;
GsPluginCategoryFunc plugin_func = NULL;
guint i;
/* run each plugin */
......@@ -1178,7 +1179,7 @@ cd_plugin_loader_get_category_apps_thread_cb (GSimpleAsyncResult *res,
g_debug ("run %s on %s", function_name,
g_module_name (plugin->module));
g_timer_start (plugin->timer);
ret = plugin_func (plugin, state->value, &state->list, cancellable, &error);
ret = plugin_func (plugin, state->category, &state->list, cancellable, &error);
if (!ret) {
cd_plugin_loader_get_all_state_finish (state, error);
g_error_free (error);
......@@ -1220,6 +1221,7 @@ cd_plugin_loader_get_category_apps_thread_cb (GSimpleAsyncResult *res,
/* success */
state->ret = TRUE;
g_object_unref (state->category);
cd_plugin_loader_get_all_state_finish (state, NULL);
out:
return;
......@@ -1248,7 +1250,7 @@ gs_plugin_loader_get_category_apps_async (GsPluginLoader *plugin_loader,
user_data,
gs_plugin_loader_get_category_apps_async);
state->plugin_loader = g_object_ref (plugin_loader);
state->value = g_strdup (gs_category_get_id (category));
state->category = g_object_ref (category);
if (cancellable != NULL)
state->cancellable = g_object_ref (cancellable);
......
......@@ -81,6 +81,11 @@ typedef gboolean (*GsPluginSearchFunc) (GsPlugin *plugin,
GList **list,
GCancellable *cancellable,
GError **error);
typedef gboolean (*GsPluginCategoryFunc) (GsPlugin *plugin,
GsCategory *category,
GList **list,
GCancellable *cancellable,
GError **error);
typedef gboolean (*GsPluginResultsFunc) (GsPlugin *plugin,
GList **list,
GCancellable *cancellable,
......@@ -122,7 +127,7 @@ gboolean gs_plugin_add_categories (GsPlugin *plugin,
GCancellable *cancellable,
GError **error);
gboolean gs_plugin_add_category_apps (GsPlugin *plugin,
const gchar *id,
GsCategory *category,
GList **list,
GCancellable *cancellable,
GError **error);
......
......@@ -28,7 +28,9 @@
#include "gs-shell-category.h"
struct GsShellCategoryPrivate {
GsPluginLoader *plugin_loader;
GtkBuilder *builder;
GCancellable *cancellable;
GsShell *shell;
GsCategory *category;
};
......@@ -46,7 +48,7 @@ gs_shell_category_refresh (GsShellCategory *shell)
gtk_widget_show (widget);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_header"));
gtk_widget_show (widget);
category = priv->category;
category = g_object_ref (priv->category);
if (gs_category_get_parent (category))
category = gs_category_get_parent (category);
gtk_label_set_label (GTK_LABEL (widget), gs_category_get_name (category));
......@@ -104,14 +106,54 @@ create_app_tile (GsShellCategory *shell, GsApp *app)
return button;
}
/**
* gs_shell_category_get_apps_cb:
**/
static void
gs_shell_category_get_apps_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GError *error = NULL;
gint i = 0;
GList *l;
GList *list;
GsApp *app;
GtkWidget *grid;
GtkWidget *tile;
GsShellCategory *shell = GS_SHELL_CATEGORY (user_data);
GsShellCategoryPrivate *priv = shell->priv;
GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
list = gs_plugin_loader_get_category_apps_finish (plugin_loader,
res,
&error);
if (list == NULL) {
g_warning ("failed to get apps for category apps: %s", error->message);
g_error_free (error);
goto out;
}
grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "category_detail_grid"));
for (l = list; l != NULL; l = l->next) {
app = GS_APP (l->data);
tile = create_app_tile (shell, app);
if (gs_category_get_parent (priv->category) != NULL)
gtk_grid_attach (GTK_GRID (grid), tile, 1 + (i % 2), i / 2, 1, 1);
else
gtk_grid_attach (GTK_GRID (grid), tile, i % 3, i / 3, 1, 1);
i++;
}
out:
g_list_free (list);
}
static void
gs_shell_category_populate_filtered (GsShellCategory *shell, GsCategory *category)
{
GsShellCategoryPrivate *priv = shell->priv;
gint i;
GtkWidget *tile;
GsApp *app;
GtkWidget *grid;
GsCategory *parent;
grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "category_detail_grid"));
gtk_grid_remove_column (GTK_GRID (grid), 2);
......@@ -119,24 +161,20 @@ gs_shell_category_populate_filtered (GsShellCategory *shell, GsCategory *categor
if (!category)
gtk_grid_remove_column (GTK_GRID (grid), 0);
/* FIXME load apps for this category and filter */
app = gs_app_new ("gnome-boxes");
gs_app_set_name (app, "Boxes");
gs_app_set_summary (app, "View and use virtual machines");
gs_app_set_url (app, "http://www.box.org");
gs_app_set_kind (app, GS_APP_KIND_NORMAL);
gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
gs_app_set_pixbuf (app, gdk_pixbuf_new_from_file ("/usr/share/icons/hicolor/48x48/apps/gnome-boxes.png", NULL));
for (i = 0; i < 30; i++) {
tile = create_app_tile (shell, app);
if (category)
gtk_grid_attach (GTK_GRID (grid), tile, 1 + (i % 2), i / 2, 1, 1);
else
gtk_grid_attach (GTK_GRID (grid), tile, i % 3, i / 3, 1, 1);
parent = gs_category_get_parent (category);
if (parent == NULL) {
g_debug ("search using %s",
gs_category_get_id (category));
} else {
g_debug ("search using %s/%s",
gs_category_get_id (parent),
gs_category_get_id (category));
}
g_object_unref (app);
gs_plugin_loader_get_category_apps_async (priv->plugin_loader,
category,
priv->cancellable,
gs_shell_category_get_apps_cb,
shell);
}
static void
......@@ -211,32 +249,37 @@ gs_shell_category_create_filter_list (GsShellCategory *shell, GsCategory *catego
void
gs_shell_category_set_category (GsShellCategory *shell, GsCategory *category)
{
GsShellCategoryPrivate *priv = shell->priv;
GsCategory *parent, *sub;
GsShellCategoryPrivate *priv = shell->priv;
GsCategory *sub;
GsCategory *selected = NULL;
GList *list;
GList *l;
if (gs_category_get_parent (category)) {
parent = gs_category_get_parent (category);
sub = category;
}
else {
parent = category;
sub = NULL;
list = gs_category_get_subcategories (category);
if (list) {
sub = GS_CATEGORY (list->data);
g_list_free (list);
/* this means we've come from the app-view -> back */
if (gs_category_get_parent (category) != NULL)
return;
/* select favourites by default */
list = gs_category_get_subcategories (category);
for (l = list; l != NULL; l = l->next) {
sub = GS_CATEGORY (l->data);
if (g_strcmp0 (gs_category_get_id (sub), "favourites") == 0) {
selected = sub;
break;
}
}
/* okay, no favourites, so just select the first entry */
if (selected == NULL && list != NULL)
selected = GS_CATEGORY (list->data);
/* save this */
g_clear_object (&priv->category);
if (sub)
priv->category = g_object_ref (sub);
else
priv->category = g_object_ref (parent);
priv->category = g_object_ref (selected);
gs_shell_category_create_filter_list (shell, parent, sub);
gs_shell_category_populate_filtered (shell, sub);
/* find apps in this group */
gs_shell_category_create_filter_list (shell, category, selected);
g_list_free (list);
}
GsCategory *
......@@ -259,6 +302,8 @@ gs_shell_category_finalize (GObject *object)
g_clear_object (&priv->builder);
g_clear_object (&priv->category);
g_clear_object (&priv->plugin_loader);
g_clear_object (&priv->cancellable);
G_OBJECT_CLASS (gs_shell_category_parent_class)->finalize (object);
}
......@@ -274,11 +319,17 @@ gs_shell_category_class_init (GsShellCategoryClass *klass)
}
void
gs_shell_category_setup (GsShellCategory *shell_category, GsShell *shell, GtkBuilder *builder)
gs_shell_category_setup (GsShellCategory *shell_category,
GsShell *shell,
GsPluginLoader *plugin_loader,
GtkBuilder *builder,
GCancellable *cancellable)
{
GsShellCategoryPrivate *priv = shell_category->priv;
priv->plugin_loader = g_object_ref (plugin_loader);
priv->builder = g_object_ref (builder);
priv->cancellable = g_object_ref (cancellable);
priv->shell = shell;
}
......
......@@ -60,6 +60,8 @@ GsCategory *gs_shell_category_get_category (GsShellCategory *shell_category
void gs_shell_category_refresh (GsShellCategory *shell_category);
void gs_shell_category_setup (GsShellCategory *shell_category,
GsShell *shell,
GtkBuilder *builder);
GsPluginLoader *plugin_loader,
GtkBuilder *builder,
GCancellable *cancellable);
#endif /* __GS_SHELL_CATEGORY_H */
......@@ -312,9 +312,9 @@ gs_shell_overview_get_categories_cb (GObject *source_object,
GtkWidget *grid;
GtkWidget *tile;
list = gs_plugin_loader_get_featured_finish (plugin_loader,
res,
&error);
list = gs_plugin_loader_get_categories_finish (plugin_loader,
res,
&error);
if (list == NULL) {
g_warning ("failed to get categories: %s", error->message);
g_error_free (error);
......
......@@ -431,7 +431,9 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
priv->cancellable);
gs_shell_category_setup (priv->shell_category,
shell,
priv->builder);
priv->plugin_loader,
priv->builder,
priv->cancellable);
/* set up search */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
......
......@@ -45,6 +45,7 @@ typedef struct {
gchar *name;
gchar *summary;
gchar *icon;
GPtrArray *appcategories;
} GsAppstreamItem;
struct GsPluginPrivate {
......@@ -69,6 +70,7 @@ gs_appstream_item_free (gpointer data)
g_free (item->name);
g_free (item->summary);
g_free (item->icon);
g_ptr_array_unref (item->appcategories);
g_free (item);
}
......@@ -241,6 +243,7 @@ gs_appstream_start_element_cb (GMarkupParseContext *context,
return;
}
plugin->priv->item_temp = g_new0 (GsAppstreamItem, 1);
plugin->priv->item_temp->appcategories = g_ptr_array_new_with_free_func (g_free);
break;
case GS_APPSTREAM_XML_SECTION_ID:
case GS_APPSTREAM_XML_SECTION_PKGNAME:
......@@ -328,9 +331,19 @@ gs_appstream_text_cb (GMarkupParseContext *context,
case GS_APPSTREAM_XML_SECTION_APPLICATIONS:
case GS_APPSTREAM_XML_SECTION_APPLICATION:
case GS_APPSTREAM_XML_SECTION_APPCATEGORIES:
case GS_APPSTREAM_XML_SECTION_APPCATEGORY:
/* ignore */
break;
case GS_APPSTREAM_XML_SECTION_APPCATEGORY:
if (plugin->priv->item_temp == NULL) {
g_set_error_literal (error,
GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_FAILED,
"item_temp category invalid");
return;
}
g_ptr_array_add (plugin->priv->item_temp->appcategories,
g_strndup (text, text_len));
break;
case GS_APPSTREAM_XML_SECTION_ID:
if (plugin->priv->item_temp == NULL ||
plugin->priv->item_temp->id != NULL) {
......@@ -505,7 +518,6 @@ gs_plugin_destroy (GsPlugin *plugin)
g_hash_table_unref (plugin->priv->hash_pkgname);
}
/**
* gs_plugin_startup:
*/
......@@ -692,3 +704,62 @@ gs_plugin_refine (GsPlugin *plugin,
out:
return ret;
}
static gboolean
in_array (GPtrArray *array, const gchar *search)
{
const gchar *tmp;
guint i;
for (i = 0; i < array->len; i++) {
tmp = g_ptr_array_index (array, i);
if (g_strcmp0 (tmp, search) == 0)
return TRUE;
}
return FALSE;
}
/**
* gs_plugin_add_category_apps:
*/
gboolean
gs_plugin_add_category_apps (GsPlugin *plugin,
GsCategory *category,
GList **list,
GCancellable *cancellable,
GError **error)
{
const gchar *search_id1;
const gchar *search_id2 = NULL;
gboolean ret = TRUE;
GsApp *app;
GsAppstreamItem *item;
GsCategory *parent;
guint i;
/* get the two search terms */
search_id1 = gs_category_get_id (category);
parent = gs_category_get_parent (category);
if (parent != NULL)
search_id2 = gs_category_get_id (parent);
/* just look at each app in turn */
for (i = 0; i < plugin->priv->array->len; i++) {
item = g_ptr_array_index (plugin->priv->array, i);
if (item->id == NULL)
continue;
if (!in_array (item->appcategories, search_id1))
continue;
if (search_id2 != NULL && !in_array (item->appcategories, search_id2))
continue;
/* got a search match, so add all the data we can */
app = gs_app_new (item->id);
ret = gs_plugin_refine_item (plugin, app, item, error);
if (!ret)
goto out;
gs_plugin_add_app (list, app);
}
out:
return ret;
}
......@@ -184,3 +184,25 @@ gs_plugin_refine (GsPlugin *plugin,
}
return TRUE;
}
/**
* gs_plugin_add_category_apps:
*/
gboolean
gs_plugin_add_category_apps (GsPlugin *plugin,
GsCategory *category,
GList **list,
GCancellable *cancellable,
GError **error)
{
GsApp *app;
app = gs_app_new ("gnome-boxes");
gs_app_set_name (app, "Boxes");
gs_app_set_summary (app, "View and use virtual machines");
gs_app_set_url (app, "http://www.box.org");
gs_app_set_kind (app, GS_APP_KIND_NORMAL);
gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
gs_app_set_pixbuf (app, gdk_pixbuf_new_from_file ("/usr/share/icons/hicolor/48x48/apps/gnome-boxes.png", NULL));
gs_plugin_add_app (list, app);
return TRUE;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment