[gnome-software/wip/hughsie/categories] Use the new-style category classification
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/hughsie/categories] Use the new-style category classification
- Date: Wed, 1 Jun 2016 16:44:48 +0000 (UTC)
commit 8b15b860190d17d05c82071316ecd45f4fdd30b4
Author: Richard Hughes <richard hughsie com>
Date: Wed Jun 1 17:18:37 2016 +0100
Use the new-style category classification
src/gs-category.c | 62 ++++
src/gs-category.h | 6 +
src/gs-cmd.c | 19 +-
src/gs-plugin-loader.c | 25 +--
src/gs-shell-overview.c | 12 +-
src/plugins/Makefile.am | 22 +-
src/plugins/gs-plugin-appstream.c | 140 ++++----
src/plugins/gs-plugin-hardcoded-categories.c | 469 ++++++++++++++++++++++++++
src/plugins/gs-plugin-menu-spec-categories.c | 69 ----
src/plugins/gs-plugin-menu-spec-refine.c | 114 -------
src/plugins/menu-spec-common.c | 217 ------------
src/plugins/menu-spec-common.h | 42 ---
12 files changed, 636 insertions(+), 561 deletions(-)
---
diff --git a/src/gs-category.c b/src/gs-category.c
index 984c92c..18c5a8a 100644
--- a/src/gs-category.c
+++ b/src/gs-category.c
@@ -43,6 +43,7 @@ struct _GsCategory
gchar *icon;
gboolean important;
GPtrArray *key_colors;
+ GPtrArray *tags;
GsCategory *parent;
guint size;
GPtrArray *children;
@@ -267,6 +268,65 @@ gs_category_add_key_color (GsCategory *category, const GdkRGBA *key_color)
}
/**
+ * gs_category_get_tags:
+ * @category: a #GsCategory
+ *
+ * Gets the list of AppStream tags for the category.
+ *
+ * Returns: (element-type utf8) (transfer none): An array
+ **/
+GPtrArray *
+gs_category_get_tags (GsCategory *category)
+{
+ g_return_val_if_fail (GS_IS_CATEGORY (category), NULL);
+ return category->tags;
+}
+
+/**
+ * gs_category_has_tag:
+ * @category: a #GsCategory
+ * @tag: a tag found in AppStream, e.g. "AudioVisual::Player"
+ *
+ * Finds out if the category has the specific AppStream tag pair.
+ *
+ * Returns: %TRUE if found, %FALSE otherwise
+ **/
+gboolean
+gs_category_has_tag (GsCategory *category, const gchar *tag)
+{
+ guint i;
+
+ g_return_val_if_fail (GS_IS_CATEGORY (category), FALSE);
+ g_return_val_if_fail (tag != NULL, FALSE);
+
+ for (i = 0; i < category->tags->len; i++) {
+ const gchar *tag_tmp = g_ptr_array_index (category->tags, i);
+ if (g_strcmp0 (tag_tmp, tag) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * gs_category_add_tag:
+ * @category: a #GsCategory
+ * @tag: a tag found in AppStream, e.g. "AudioVisual::Player"
+ *
+ * Adds a tag pair to the category.
+ **/
+void
+gs_category_add_tag (GsCategory *category, const gchar *tag)
+{
+ g_return_if_fail (GS_IS_CATEGORY (category));
+ g_return_if_fail (tag != NULL);
+
+ /* add if not already found */
+ if (gs_category_has_tag (category, tag))
+ return;
+ g_ptr_array_add (category->tags, g_strdup (tag));
+}
+
+/**
* gs_category_find_child:
* @category: a #GsCategory
* @id: a category ID, e.g. "other"
@@ -396,6 +456,7 @@ gs_category_finalize (GObject *object)
(gpointer *) &category->parent);
g_ptr_array_unref (category->children);
g_ptr_array_unref (category->key_colors);
+ g_ptr_array_unref (category->tags);
g_free (category->id);
g_free (category->name);
g_free (category->icon);
@@ -415,6 +476,7 @@ gs_category_init (GsCategory *category)
{
category->children = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
category->key_colors = g_ptr_array_new_with_free_func ((GDestroyNotify) gdk_rgba_free);
+ category->tags = g_ptr_array_new_with_free_func (g_free);
}
/**
diff --git a/src/gs-category.h b/src/gs-category.h
index bd41e69..7cc97e4 100644
--- a/src/gs-category.h
+++ b/src/gs-category.h
@@ -49,6 +49,12 @@ GPtrArray *gs_category_get_key_colors (GsCategory *category);
void gs_category_add_key_color (GsCategory *category,
const GdkRGBA *key_color);
+GPtrArray *gs_category_get_tags (GsCategory *category);
+gboolean gs_category_has_tag (GsCategory *category,
+ const gchar *tag);
+void gs_category_add_tag (GsCategory *category,
+ const gchar *tag);
+
GsCategory *gs_category_find_child (GsCategory *category,
const gchar *id);
GPtrArray *gs_category_get_children (GsCategory *category);
diff --git a/src/gs-cmd.c b/src/gs-cmd.c
index 776ea7f..60244a8 100644
--- a/src/gs-cmd.c
+++ b/src/gs-cmd.c
@@ -89,9 +89,10 @@ gs_cmd_show_results_categories (GPtrArray *list)
parent = gs_category_get_parent (cat);
if (parent != NULL){
g_autofree gchar *id = NULL;
- id = g_strdup_printf ("%s/%s",
+ id = g_strdup_printf ("%s/%s [%i]",
gs_category_get_id (parent),
- gs_category_get_id (cat));
+ gs_category_get_id (cat),
+ gs_category_get_size (cat));
tmp = gs_cmd_pad_spaces (id, 32);
g_print ("%s : %s\n",
tmp, gs_category_get_name (cat));
@@ -147,6 +148,8 @@ gs_cmd_refine_flag_from_string (const gchar *flag, GError **error)
return GS_PLUGIN_REFINE_FLAGS_REQUIRE_REVIEW_RATINGS;
if (g_strcmp0 (flag, "key-colors") == 0)
return GS_PLUGIN_REFINE_FLAGS_REQUIRE_KEY_COLORS;
+ if (g_strcmp0 (flag, "icon") == 0)
+ return GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON;
g_set_error (error,
GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_NOT_SUPPORTED,
@@ -430,13 +433,15 @@ main (int argc, char **argv)
}
} else if (argc == 3 && g_strcmp0 (argv[1], "get-category-apps") == 0) {
g_autoptr(GsCategory) category = NULL;
+ g_autoptr(GsCategory) parent = NULL;
g_auto(GStrv) split = NULL;
split = g_strsplit (argv[2], "/", 2);
- category = gs_category_new (split[0]);
- if (g_strv_length (split) == 2) {
- g_autoptr(GsCategory) child = NULL;
- child = gs_category_new (split[1]);
- gs_category_add_child (category, child);
+ if (g_strv_length (split) == 1) {
+ category = gs_category_new (split[0]);
+ } else {
+ parent = gs_category_new (split[0]);
+ category = gs_category_new (split[1]);
+ gs_category_add_child (parent, category);
}
for (i = 0; i < repeat; i++) {
if (list != NULL)
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index b932893..0156656 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -2141,9 +2141,9 @@ gs_plugin_loader_category_sort_cb (gconstpointer a, gconstpointer b)
GsCategory *catb = GS_CATEGORY (*(GsCategory **) b);
/* addons always go last */
- if (g_strcmp0 (gs_category_get_id (cata), "Addons") == 0)
+ if (g_strcmp0 (gs_category_get_id (cata), "addons") == 0)
return 1;
- if (g_strcmp0 (gs_category_get_id (catb), "Addons") == 0)
+ if (g_strcmp0 (gs_category_get_id (catb), "addons") == 0)
return -1;
return g_strcmp0 (gs_category_get_name (cata),
@@ -2208,27 +2208,6 @@ gs_plugin_loader_get_categories_thread_cb (GTask *task,
gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
}
- /* ensure they all have an 'All' category */
- for (i = 0; i < state->catlist->len; i++) {
- GsCategory *parent = GS_CATEGORY (g_ptr_array_index (state->catlist, i));
- if (g_strcmp0 (gs_category_get_id (parent), "Addons") == 0)
- continue;
- if (gs_category_find_child (parent, "all") == NULL) {
- g_autoptr(GsCategory) child = NULL;
- child = gs_category_new ("all");
- gs_category_add_child (parent, child);
- /* this is probably valid... */
- gs_category_set_size (child, gs_category_get_size (parent));
- }
- if (gs_category_find_child (parent, "featured") == NULL) {
- g_autoptr(GsCategory) child = NULL;
- child = gs_category_new ("featured");
- gs_category_add_child (parent, child);
- /* this is probably valid... */
- gs_category_set_size (child, 5);
- }
- }
-
/* sort by name */
g_ptr_array_sort (state->catlist, gs_plugin_loader_category_sort_cb);
for (i = 0; i < state->catlist->len; i++) {
diff --git a/src/gs-shell-overview.c b/src/gs-shell-overview.c
index d55a847..c2de572 100644
--- a/src/gs-shell-overview.c
+++ b/src/gs-shell-overview.c
@@ -385,24 +385,24 @@ gs_shell_overview_load (GsShellOverview *self)
date = g_date_time_new_now_utc ();
switch (g_date_time_get_day_of_year (date) % 4) {
case 0:
- category_of_day = "Audio";
+ category_of_day = "audio-video";
/* TRANSLATORS: this is a heading for audio applications which have been featured
('recommended') by the distribution */
- gtk_label_set_label (GTK_LABEL (priv->popular_rotating_heading), _("Recommended Audio
Applications"));
+ gtk_label_set_label (GTK_LABEL (priv->popular_rotating_heading), _("Recommended Audio & Video
Applications"));
break;
case 1:
- category_of_day = "Game";
+ category_of_day = "games";
/* TRANSLATORS: this is a heading for games which have been featured ('recommended') by the
distribution */
gtk_label_set_label (GTK_LABEL (priv->popular_rotating_heading), _("Recommended Games"));
break;
case 2:
- category_of_day = "Graphics";
+ category_of_day = "graphics";
/* TRANSLATORS: this is a heading for graphics applications which have been featured
('recommended') by the distribution */
gtk_label_set_label (GTK_LABEL (priv->popular_rotating_heading), _("Recommended Graphics
Applications"));
break;
case 3:
- category_of_day = "Office";
+ category_of_day = "productivity";
/* TRANSLATORS: this is a heading for office applications which have been featured
('recommended') by the distribution */
- gtk_label_set_label (GTK_LABEL (priv->popular_rotating_heading), _("Recommended Office
Applications"));
+ gtk_label_set_label (GTK_LABEL (priv->popular_rotating_heading), _("Recommended Productivity
Applications"));
break;
default:
g_assert_not_reached ();
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 2a1630e..813a071 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -33,10 +33,9 @@ plugin_LTLIBRARIES = \
libgs_plugin_dummy.la \
libgs_plugin_dpkg.la \
libgs_plugin_hardcoded-blacklist.la \
+ libgs_plugin_hardcoded-categories.la \
libgs_plugin_hardcoded-popular.la \
libgs_plugin_hardcoded-featured.la \
- libgs_plugin_menu-spec-categories.la \
- libgs_plugin_menu-spec-refine.la \
libgs_plugin_fedora-distro-upgrades.la \
libgs_plugin_provenance.la \
libgs_plugin_provenance-license.la \
@@ -210,21 +209,10 @@ libgs_plugin_steam_la_LDFLAGS = -module -avoid-version
libgs_plugin_steam_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
endif
-libgs_plugin_menu_spec_categories_la_SOURCES = \
- gs-plugin-menu-spec-categories.c \
- menu-spec-common.c \
- menu-spec-common.h
-libgs_plugin_menu_spec_categories_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_menu_spec_categories_la_LDFLAGS = -module -avoid-version
-libgs_plugin_menu_spec_categories_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
-
-libgs_plugin_menu_spec_refine_la_SOURCES = \
- gs-plugin-menu-spec-refine.c \
- menu-spec-common.c \
- menu-spec-common.h
-libgs_plugin_menu_spec_refine_la_LIBADD = $(GS_PLUGIN_LIBS)
-libgs_plugin_menu_spec_refine_la_LDFLAGS = -module -avoid-version
-libgs_plugin_menu_spec_refine_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+libgs_plugin_hardcoded_categories_la_SOURCES = gs-plugin-hardcoded-categories.c
+libgs_plugin_hardcoded_categories_la_LIBADD = $(GS_PLUGIN_LIBS)
+libgs_plugin_hardcoded_categories_la_LDFLAGS = -module -avoid-version
+libgs_plugin_hardcoded_categories_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
libgs_plugin_hardcoded_blacklist_la_SOURCES = gs-plugin-hardcoded-blacklist.c
libgs_plugin_hardcoded_blacklist_la_LIBADD = $(GS_PLUGIN_LIBS)
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
index 244f223..575c761 100644
--- a/src/plugins/gs-plugin-appstream.c
+++ b/src/plugins/gs-plugin-appstream.c
@@ -63,8 +63,7 @@ gs_plugin_initialize (GsPlugin *plugin)
AS_STORE_WATCH_FLAG_ADDED |
AS_STORE_WATCH_FLAG_REMOVED);
- /* need category list and package name */
- gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "menu-spec-categories");
+ /* need package name */
gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "dpkg");
}
@@ -390,46 +389,52 @@ gs_plugin_add_category_apps (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- const gchar *search_id1;
- const gchar *search_id2 = NULL;
- AsApp *item;
- GsCategory *parent;
GPtrArray *array;
+ GPtrArray *tags;
guint i;
+ guint j;
g_autoptr(AsProfileTask) ptask = NULL;
- /* get the two search terms */
+ /* just look at each app in turn */
ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
"appstream::add-category-apps");
- search_id1 = gs_category_get_id (category);
- parent = gs_category_get_parent (category);
- if (parent != NULL)
- search_id2 = gs_category_get_id (parent);
-
- /* the "General" item has no ID */
- if (search_id1 == NULL) {
- search_id1 = search_id2;
- search_id2 = NULL;
- }
-
- /* just look at each app in turn */
array = as_store_get_apps (priv->store);
- for (i = 0; i < array->len; i++) {
- g_autoptr(GsApp) app = NULL;
- item = g_ptr_array_index (array, i);
- if (as_app_get_id (item) == NULL)
- continue;
- if (g_strcmp0 (search_id1, "all") != 0 &&
- !as_app_has_category (item, search_id1))
- continue;
- if (search_id2 != NULL && !as_app_has_category (item, search_id2))
+ tags = gs_category_get_tags (category);
+ if (tags->len == 0) {
+ g_warning ("no tags for %s", gs_category_get_id (category));
+ return TRUE;
+ }
+ for (j = 0; j < tags->len; j++) {
+ const gchar *tag = g_ptr_array_index (tags, j);
+ g_auto(GStrv) split = g_strsplit (tag, "::", -1);
+ if (g_strv_length (split) != 2)
continue;
- /* got a search match, so add all the data we can */
- app = gs_plugin_appstream_create_app (plugin, as_app_get_id (item));
- if (!gs_appstream_refine_app (plugin, app, item, error))
- return FALSE;
- gs_app_list_add (list, app);
+ /* match the app */
+ for (i = 0; i < array->len; i++) {
+ AsApp *item;
+ g_autoptr(GsApp) app = NULL;
+
+ /* no ID is invalid */
+ item = g_ptr_array_index (array, i);
+ if (as_app_get_id (item) == NULL)
+ continue;
+
+ /* match the parent */
+ if (!as_app_has_category (item, split[0]))
+ continue;
+
+ /* match the child */
+ if (!as_app_has_category (item, split[1]))
+ continue;
+
+ /* add all the data we can */
+ app = gs_plugin_appstream_create_app (plugin,
+ as_app_get_id (item));
+ if (!gs_appstream_refine_app (plugin, app, item, error))
+ return FALSE;
+ gs_app_list_add (list, app);
+ }
}
return TRUE;
}
@@ -528,44 +533,43 @@ gs_plugin_add_installed (GsPlugin *plugin,
return TRUE;
}
+static gboolean
+_as_app_matches_category_tag (AsApp *app, const gchar *tag)
+{
+ g_auto(GStrv) split = g_strsplit (tag, "::", -1);
+ if (!as_app_has_category (app, split[0]))
+ return FALSE;
+ if (split[1] != NULL && !as_app_has_category (app, split[1]))
+ return FALSE;
+ return TRUE;
+}
+
static void
-gs_plugin_add_categories_for_app (GPtrArray *list, AsApp *app)
+gs_plugin_add_categories_for_app (GsCategory *parent, AsApp *app)
{
- guint i, j;
+ GPtrArray *children;
+ GPtrArray *tags;
GsCategory *category;
- GsCategory *parent;
- gboolean found_subcat;
-
- /* does it match the main category */
- for (i = 0; i < list->len; i++) {
- GPtrArray *children;
- parent = GS_CATEGORY (g_ptr_array_index (list, i));
- if (!as_app_has_category (app, gs_category_get_id (parent)))
- continue;
- gs_category_increment_size (parent);
-
- /* does it match any sub-categories */
- found_subcat = FALSE;
- children = gs_category_get_children (parent);
- for (j = 0; j < children->len; j++) {
- category = GS_CATEGORY (g_ptr_array_index (children, j));
- if (!as_app_has_category (app, gs_category_get_id (category)))
- continue;
- gs_category_increment_size (category);
- found_subcat = TRUE;
- }
+ guint i, j;
- /* matching the main category but no subcategories means we have
- * to create a new 'Other' subcategory manually */
- if (!found_subcat) {
- category = gs_category_find_child (parent, "other");
- if (category == NULL) {
- category = gs_category_new ("other");
- gs_category_add_child (parent, category);
- g_object_unref (category);
+ /* find all the sub-categories */
+ children = gs_category_get_children (parent);
+ for (j = 0; j < children->len; j++) {
+ gboolean matched = FALSE;
+ category = GS_CATEGORY (g_ptr_array_index (children, j));
+
+ /* do any tags match this application */
+ tags = gs_category_get_tags (category);
+ for (i = 0; i < tags->len; i++) {
+ const gchar *tag = g_ptr_array_index (tags, i);
+ if (_as_app_matches_category_tag (app, tag)) {
+ matched = TRUE;
+ break;
}
- as_app_add_category (app, gs_category_get_id (category));
+ }
+ if (matched) {
gs_category_increment_size (category);
+ gs_category_increment_size (parent);
}
}
}
@@ -580,6 +584,7 @@ gs_plugin_add_categories (GsPlugin *plugin,
AsApp *app;
GPtrArray *array;
guint i;
+ guint j;
g_autoptr(AsProfileTask) ptask = NULL;
/* find out how many packages are in each category */
@@ -592,7 +597,10 @@ gs_plugin_add_categories (GsPlugin *plugin,
continue;
if (as_app_get_priority (app) < 0)
continue;
- gs_plugin_add_categories_for_app (list, app);
+ for (j = 0; j < list->len; j++) {
+ GsCategory *parent = GS_CATEGORY (g_ptr_array_index (list, j));
+ gs_plugin_add_categories_for_app (parent, app);
+ }
}
return TRUE;
}
diff --git a/src/plugins/gs-plugin-hardcoded-categories.c b/src/plugins/gs-plugin-hardcoded-categories.c
new file mode 100644
index 0000000..be66ee6
--- /dev/null
+++ b/src/plugins/gs-plugin-hardcoded-categories.c
@@ -0,0 +1,469 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2011-2016 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 <gnome-software.h>
+#include <glib/gi18n.h>
+
+/*
+ * SECTION:
+ * Adds categories from a hardcoded list based on the the desktop menu
+ * specification.
+ */
+
+void
+gs_plugin_initialize (GsPlugin *plugin)
+{
+ /* need categories */
+ gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_BEFORE, "appstream");
+
+ /* the old name for these plugins */
+ gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_CONFLICTS, "menu-spec-categories");
+ gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_CONFLICTS, "menu-spec-refine");
+}
+
+typedef struct {
+ const gchar *id;
+ const gchar *name;
+ const gchar *fdo_cats[16];
+} GsCategoryMap;
+
+typedef struct {
+ const gchar *id;
+ GsCategoryMap *mapping;
+ const gchar *name;
+ const gchar *icon;
+ const gchar *key_colors;
+ gboolean important;
+} GsCategoryData;
+
+/* AudioVideo */
+static const GsCategoryMap map_audiovisual[] = {
+// { "all", NC_("Menu of AudioVideo", "All"),
+// { NULL } },
+ { "featured", NC_("Menu of AudioVideo", "Featured"),
+ { "AudioVideo::featured",
+ NULL} },
+ { "creation-editing", NC_("Menu of AudioVideo", "Audio Creation & Editing"),
+ { "AudioVideo::AudioVideoEditing",
+ "AudioVideo::Midi",
+ "AudioVideo::DiscBurning",
+ "AudioVideo::Sequencer",
+ NULL} },
+ { "music-players", NC_("Menu of AudioVideo", "Music Players"),
+ { "AudioVideo::Music",
+ "AudioVideo::Player",
+ NULL} },
+ { NULL }
+};
+
+/* Development */
+static const GsCategoryMap map_developertools[] = {
+ { "featured", NC_("Menu of Development", "Featured"),
+ { "Development::featured",
+ NULL} },
+ { "debuggers", NC_("Menu of Development", "Debuggers"),
+ { "Development:Debugger",
+ NULL} },
+ { "ide", NC_("Menu of Development", "IDEs"),
+ { "Development::IDE",
+ "Development::GUIDesigner",
+ NULL} },
+ { NULL }
+};
+
+/* Education */
+static const GsCategoryMap map_education[] = {
+ { "featured", NC_("Menu of Education", "Featured"),
+ { "Education::featured",
+ NULL} },
+ { "astronomy", NC_("Menu of Education", "Astronomy"),
+ { "Education::Astronomy",
+ NULL} },
+ { "chemistry", NC_("Menu of Education", "Chemistry"),
+ { "Education::Chemistry",
+ NULL} },
+ { "languages", NC_("Menu of Education", "Languages"),
+ { "Education::Languages",
+ "Education::Literature",
+ NULL} },
+ { "math", NC_("Menu of Education", "Math"),
+ { "Education::Math",
+ "Education::NumericalAnalysis",
+ NULL} },
+ { NULL }
+};
+
+/* Games */
+static const GsCategoryMap map_games[] = {
+ { "featured", NC_("Menu of Games", "Featured"),
+ { "Game::featured",
+ NULL} },
+ { "action", NC_("Menu of Games", "Action"),
+ { "Game::ActionGame",
+ NULL} },
+ { "adventure", NC_("Menu of Games", "Adventure"),
+ { "Game::AdventureGame",
+ NULL} },
+ { "arcade", NC_("Menu of Games", "Arcade"),
+ { "Game::ArcadeGame",
+ NULL} },
+ { "blocks", NC_("Menu of Games", "Blocks"),
+ { "Game::BlocksGame",
+ NULL} },
+ { "board", NC_("Menu of Games", "Board"),
+ { "Game::BoardGame",
+ NULL} },
+ { "card", NC_("Menu of Games", "Card"),
+ { "Game::CardGame",
+ NULL} },
+ { "emulator", NC_("Menu of Games", "Emulators"),
+ { "Game::Emulator",
+ NULL} },
+ { "kids", NC_("Menu of Games", "Kids"),
+ { "Game::KidsGame",
+ NULL} },
+ { "logic", NC_("Menu of Games", "Logic"),
+ { "Game::LogicGame",
+ NULL} },
+ { "role-playing", NC_("Menu of Games", "Role Playing"),
+ { "Game::RolePlaying",
+ NULL} },
+ { "sports", NC_("Menu of Games", "Sports"),
+ { "Game::SportsGame",
+ "Game::Simulation",
+ NULL} },
+ { "strategy", NC_("Menu of Games", "Strategy"),
+ { "Game::StrategyGame",
+ NULL} },
+ { NULL }
+};
+
+/* Graphics */
+static const GsCategoryMap map_graphics[] = {
+ { "featured", NC_("Menu of Graphics", "Featured"),
+ { "Graphics::featured",
+ NULL} },
+ { "3d", NC_("Menu of Graphics", "3D Graphics"),
+ { "Graphics::3DGraphics",
+ NULL} },
+ { "photography", NC_("Menu of Graphics", "Photography"),
+ { "Graphics::Photography",
+ NULL} },
+ { "scanning", NC_("Menu of Graphics", "Scanning"),
+ { "Graphics::Scanning",
+ NULL} },
+ { "vector", NC_("Menu of Graphics", "Vector Graphics"),
+ { "Graphics::VectorGraphics",
+ NULL} },
+ { "viewers", NC_("Menu of Graphics", "Viewers"),
+ { "Graphics::Viewer",
+ NULL} },
+ { NULL }
+};
+
+/* Office */
+static const GsCategoryMap map_productivity[] = {
+ { "featured", NC_("Menu of Office", "Featured"),
+ { "Office::featured",
+ NULL} },
+ { "calendar", NC_("Menu of Office", "Calendar"),
+ { "Office::Calendar",
+ "Office::ProjectManagement",
+ NULL} },
+ { "database", NC_("Menu of Office", "Database"),
+ { "Office::Database",
+ NULL} },
+ { "finance", NC_("Menu of Office", "Finance"),
+ { "Office::Finance",
+ "Office::Spreadsheet",
+ NULL} },
+ { "word Processor", NC_("Menu of Office", "Word Processor"),
+ { "Office::WordProcessor",
+ "Office::Dictionary",
+ NULL} },
+ { NULL }
+};
+
+/* Addons */
+static const GsCategoryMap map_addons[] = {
+ { "fonts", NC_("Menu of Addons", "Fonts"),
+ { "Addons::Fonts",
+ NULL} },
+ { "codecs", NC_("Menu of Addons", "Codecs"),
+ { "Addons::Codecs",
+ NULL} },
+ { "input-sources", NC_("Menu of Addons", "Input Sources"),
+ { "Addons::InputSources",
+ NULL} },
+ { "language-packs", NC_("Menu of Addons", "Language Packs"),
+ { "Addons::LanguagePacks",
+ NULL} },
+ { "shell-sxtensions", NC_("Menu of Addons", "Shell Extensions"),
+ { "Addons::ShellExtensions",
+ NULL} },
+ { "Localization", NC_("Menu of Addons", "Localization"),
+ { "Addons::Localization",
+ NULL} },
+ { NULL }
+};
+
+/* Science */
+static const GsCategoryMap map_science[] = {
+ { "featured", NC_("Menu of Science", "Featured"),
+ { "Science::featured",
+ NULL} },
+ { "artificial-intelligence", NC_("Menu of Science", "Artificial Intelligence"),
+ { "Science::ArtificialIntelligence",
+ NULL} },
+ { "astronomy", NC_("Menu of Science", "Astronomy"),
+ { "Science::Astronomy",
+ NULL} },
+ { "chemistry", NC_("Menu of Science", "Chemistry"),
+ { "Science::Chemistry",
+ NULL} },
+ { "math", NC_("Menu of Science", "Math"),
+ { "Science::Math",
+ "Science::Physics",
+ "Science::NumericalAnalysis",
+ NULL} },
+ { "robotics", NC_("Menu of Science", "Robotics"),
+ { "Science::Robotics",
+ NULL} },
+ { NULL }
+};
+
+/* Communication */
+static const GsCategoryMap map_communication[] = {
+ { "featured", NC_("Menu of Communication", "Featured"),
+ { "Network::featured",
+ NULL} },
+ { "chat", NC_("Menu of Communication", "Chat"),
+ { "Network::Chat",
+ "Network::IRCClient",
+ "Network::Telephony",
+ "Network::VideoConference",
+ "Network::Email",
+ NULL} },
+ { "news", NC_("Menu of Communication", "News"),
+ { "Network::Feed",
+ "Network::News",
+ NULL} },
+ { "web-browsers", NC_("Menu of Communication", "Web Browsers"),
+ { "Network::WebBrowser",
+ NULL} },
+ { NULL }
+};
+
+/* Utilities */
+static const GsCategoryMap map_utilities[] = {
+ { "featured", NC_("Menu of Utilities", "Featured"),
+ { "Utilities::featured",
+ NULL} },
+ { "text-editors", NC_("Menu of Utilities", "Text Editors"),
+ { "Utility::TextEditor",
+ NULL} },
+ { NULL }
+};
+
+/* main categories */
+static const GsCategoryData msdata[] = {
+ /* TRANSLATORS: this is the menu spec main category for Audio & Video */
+ { "audio-video", map_audiovisual, N_("Audio & Video"),
+ "folder-music-symbolic", "#215d9c", TRUE },
+ /* TRANSLATORS: this is the menu spec main category for Development */
+ { "developer-tools", map_developertools, N_("Developer Tools"),
+ "applications-engineering-symbolic", "#297bcc" },
+ /* TRANSLATORS: this is the menu spec main category for Education */
+ { "education", map_education, N_("Education"),
+ "system-help-symbolic", "#29cc5d" },
+ /* TRANSLATORS: this is the menu spec main category for Game */
+ { "games", map_games, N_("Games"),
+ "applications-games-symbolic", "#c4a000", TRUE },
+ /* TRANSLATORS: this is the menu spec main category for Graphics */
+ { "graphics", map_graphics, N_("Graphics & Photography"),
+ "applications-graphics-symbolic", "#75507b", TRUE },
+ /* TRANSLATORS: this is the menu spec main category for Office */
+ { "productivity", map_productivity, N_("Productivity"),
+ "text-editor-symbolic", "#cc0000", TRUE },
+ /* TRANSLATORS: this is the menu spec main category for Add-ons */
+ { "addons", map_addons, N_("Add-ons"),
+ "application-x-addon-symbolic", "#4e9a06", TRUE },
+ /* TRANSLATORS: this is the menu spec main category for Science */
+ { "science", map_science, N_("Science"),
+ "applications-science-symbolic", "#9c29ca" },
+ /* TRANSLATORS: this is the menu spec main category for Communication */
+ { "communication", map_communication, N_("Communication & News"),
+ "user-available-symbolic", "#729fcf", TRUE },
+ /* TRANSLATORS: this is the menu spec main category for Utilities */
+ { "utilities", map_utilities, N_("Utilities"),
+ "applications-utilities-symbolic", "#2944cc" },
+ { NULL }
+};
+
+gboolean
+gs_plugin_add_categories (GsPlugin *plugin,
+ GPtrArray *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gchar msgctxt[100];
+ guint i, j, k;
+
+ for (i = 0; msdata[i].id != NULL; i++) {
+ GdkRGBA key_color;
+ GsCategory *category = NULL;
+
+ /* add parent category */
+ category = gs_category_new (msdata[i].id);
+ gs_category_set_icon (category, msdata[i].icon);
+ gs_category_set_name (category, gettext (msdata[i].name));
+ gs_category_set_important (category, msdata[i].important);
+ if (gdk_rgba_parse (&key_color, msdata[i].key_colors))
+ gs_category_add_key_color (category, &key_color);
+ g_ptr_array_add (list, category);
+ g_snprintf (msgctxt, 100, "Menu subcategory of %s", msdata[i].name);
+
+ /* add subcategories */
+ for (j = 0; msdata[i].mapping[j].id != NULL; j++) {
+ const GsCategoryMap *map = &msdata[i].mapping[j];
+ g_autoptr(GsCategory) sub = gs_category_new (map->id);
+ for (k = 0; map->fdo_cats[k] != NULL; k++)
+ gs_category_add_tag (sub, map->fdo_cats[k]);
+ gs_category_set_name (sub, g_dpgettext2 (GETTEXT_PACKAGE,
+ msgctxt,
+ map->name));
+ gs_category_add_child (category, sub);
+ }
+ }
+ return TRUE;
+}
+
+/* most of this time this won't be required, unless the user creates a
+ * GsCategory manually and uses it to get results, for instance in the
+ * overview page or with gnome-software-cmd get-category-apps games/featured */
+gboolean
+gs_plugin_add_category_apps (GsPlugin *plugin,
+ GsCategory *category,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GPtrArray *tags;
+ GsCategory *parent;
+ guint i, j, k;
+
+ /* already set */
+ tags = gs_category_get_tags (category);
+ if (tags->len > 0)
+ return TRUE;
+
+ /* not valid */
+ parent = gs_category_get_parent (category);
+ if (parent == NULL)
+ return TRUE;
+
+ /* find tags for a parent::child category */
+ for (i = 0; msdata[i].id != NULL; i++) {
+ if (g_strcmp0 (gs_category_get_id (parent), msdata[i].id) != 0)
+ continue;
+ for (j = 0; msdata[i].mapping[j].id != NULL; j++) {
+ const GsCategoryMap *map = &msdata[i].mapping[j];
+ if (g_strcmp0 (gs_category_get_id (category), map->id) != 0)
+ continue;
+ for (k = 0; map->fdo_cats[k] != NULL; k++)
+ gs_category_add_tag (category, map->fdo_cats[k]);
+ }
+ }
+ return TRUE;
+}
+
+static void
+gs_plugin_refine_app_category (GsPlugin *plugin,
+ GsApp *app,
+ const GsCategoryData *cat)
+{
+ const gchar *menu_path[] = { NULL, NULL, NULL };
+ gboolean ret = FALSE;
+ gchar *tmp;
+ guint i;
+
+ /* find a sub-level category the app has */
+ for (i = 0; msdata[i].id != NULL; i++) {
+ tmp = g_strstr_len (msdata[i].id, -1, "::");
+ if (tmp == NULL)
+ continue;
+
+//FIXME: this isn't going to work!
+
+ if (!g_str_has_prefix (msdata[i].id, cat->id))
+ continue;
+ ret = gs_app_has_category (app, tmp + 2);
+ if (ret) {
+ g_autofree gchar *msgctxt = NULL;
+ msgctxt = g_strdup_printf ("Menu subcategory of %s", cat->name);
+ menu_path[1] = g_dpgettext2 (GETTEXT_PACKAGE, msgctxt, msdata[i].name);
+ break;
+ }
+ }
+
+ /* the top-level category always exists */
+ menu_path[0] = gettext (cat->name);
+ gs_app_set_menu_path (app, (gchar **) menu_path);
+}
+
+gboolean
+gs_plugin_refine_app (GsPlugin *plugin,
+ GsApp *app,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gchar *tmp;
+ guint i;
+ const gchar *EMPTY[] = { "", NULL };
+
+ /* nothing to do here */
+ if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_MENU_PATH) == 0)
+ return TRUE;
+ if (gs_app_get_menu_path (app) != NULL)
+ return TRUE;
+
+ /* find a top level category the app has */
+ for (i = 0; msdata[i].id != NULL; i++) {
+ tmp = g_strstr_len (msdata[i].id, -1, "::");
+ if (tmp != NULL)
+ continue;
+ ret = gs_app_has_category (app, msdata[i].id);
+ if (ret) {
+ gs_plugin_refine_app_category (plugin, app, &msdata[i]);
+ break;
+ }
+ }
+
+ /* don't keep searching for this */
+ if (!ret)
+ gs_app_set_menu_path (app, (gchar **) EMPTY);
+
+ return TRUE;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]