[gnome-software] Add support for 'missing' applications and codecs that we know exist but we can't install



commit 531df9562356986ee1b97537b59a8236c1a59ee7
Author: Richard Hughes <richard hughsie com>
Date:   Wed Oct 16 20:25:00 2013 +0100

    Add support for 'missing' applications and codecs that we know exist but we can't install
    
    This is useful for directing users to web pages to enabled 3rd party software sources.

 src/gs-app-widget.c                       |   20 +++++++++
 src/gs-app.c                              |   15 ++++++-
 src/gs-app.h                              |    3 +
 src/gs-plugin-loader.c                    |   62 +++++++++++++++++++++++++++++
 src/gs-shell-details.c                    |    3 +
 src/gs-shell-search.c                     |   30 ++++++++++++++
 src/plugins/gs-plugin-appstream.c         |    2 +
 src/plugins/gs-plugin-packagekit-refine.c |    7 ++-
 8 files changed, 137 insertions(+), 5 deletions(-)
---
diff --git a/src/gs-app-widget.c b/src/gs-app-widget.c
index 96e6086..e58ac11 100644
--- a/src/gs-app-widget.c
+++ b/src/gs-app-widget.c
@@ -70,6 +70,8 @@ gs_app_widget_refresh (GsAppWidget *app_widget)
        if (priv->show_update &&
            gs_app_get_state (priv->app) == GS_APP_STATE_UPDATABLE)
                tmp = gs_app_get_update_details (priv->app);
+       if (gs_app_get_kind (priv->app) == GS_APP_KIND_MISSING)
+               tmp = gs_app_get_summary_missing (priv->app);
        if (tmp == NULL)
                tmp = gs_app_get_description (priv->app);
        if (tmp == NULL)
@@ -77,6 +79,17 @@ gs_app_widget_refresh (GsAppWidget *app_widget)
        if (tmp == NULL)
                tmp = gs_app_get_name (priv->app);
 
+       /* only show the name box if the application is found */
+       switch (gs_app_get_kind (priv->app)) {
+       case GS_APP_KIND_MISSING:
+               gtk_widget_set_visible (priv->name_box, FALSE);
+               gtk_widget_set_margin_right (priv->description_label, 250);
+               break;
+       default:
+               gtk_widget_set_visible (priv->name_box, TRUE);
+               gtk_widget_set_margin_right (priv->description_label, 0);
+       }
+
        /* join the lines*/
        str = g_string_new (tmp);
        gs_string_replace (str, "\n", " ");
@@ -104,6 +117,13 @@ gs_app_widget_refresh (GsAppWidget *app_widget)
        gtk_style_context_remove_class (context, "destructive-action");
 
        switch (gs_app_get_state (app_widget->priv->app)) {
+       case GS_APP_STATE_UNAVAILABLE:
+               gtk_widget_set_visible (priv->spinner, FALSE);
+               gtk_widget_set_visible (priv->button, TRUE);
+               /* TRANSLATORS: this is a button next to the search results that
+                * allows the application to be easily installed */
+               gtk_button_set_label (GTK_BUTTON (priv->button), _("Visit website"));
+               break;
        case GS_APP_STATE_AVAILABLE:
                gtk_widget_set_visible (priv->spinner, FALSE);
                gtk_widget_set_visible (priv->button, TRUE);
diff --git a/src/gs-app.c b/src/gs-app.c
index db1af70..b7ff563 100644
--- a/src/gs-app.c
+++ b/src/gs-app.c
@@ -137,6 +137,8 @@ gs_app_kind_to_string (GsAppKind kind)
                return "package";
        if (kind == GS_APP_KIND_OS_UPDATE)
                return "os-update";
+       if (kind == GS_APP_KIND_MISSING)
+               return "missing";
        return NULL;
 }
 
@@ -158,6 +160,8 @@ gs_app_state_to_string (GsAppState state)
                return "removing";
        if (state == GS_APP_STATE_UPDATABLE)
                return "updatable";
+       if (state == GS_APP_STATE_UNAVAILABLE)
+               return "unavailable";
        return NULL;
 }
 
@@ -298,6 +302,7 @@ gs_app_get_state (GsApp *app)
  * UPDATABLE --> REMOVING   --> AVAILABLE
  * INSTALLED --> REMOVING   --> AVAILABLE
  * AVAILABLE --> INSTALLING --> INSTALLED
+ * UNKNOWN   --> UNAVAILABLE
  */
 void
 gs_app_set_state (GsApp *app, GsAppState state)
@@ -315,7 +320,8 @@ gs_app_set_state (GsApp *app, GsAppState state)
                /* unknown has to go into one of the stable states */
                if (state == GS_APP_STATE_INSTALLED ||
                    state == GS_APP_STATE_AVAILABLE ||
-                   state == GS_APP_STATE_UPDATABLE)
+                   state == GS_APP_STATE_UPDATABLE ||
+                   state == GS_APP_STATE_UNAVAILABLE)
                        state_change_ok = TRUE;
                break;
        case GS_APP_STATE_INSTALLED:
@@ -409,16 +415,19 @@ gs_app_set_kind (GsApp *app, GsAppKind kind)
        case GS_APP_KIND_PACKAGE:
                /* package can become either normal or a system application */
                if (kind == GS_APP_KIND_NORMAL ||
-                   kind == GS_APP_KIND_SYSTEM)
+                   kind == GS_APP_KIND_SYSTEM ||
+                   kind == GS_APP_KIND_UNKNOWN)
                        state_change_ok = TRUE;
                break;
        case GS_APP_KIND_NORMAL:
                /* normal can only be promoted to system */
-               if (kind == GS_APP_KIND_SYSTEM)
+               if (kind == GS_APP_KIND_SYSTEM ||
+                   kind == GS_APP_KIND_UNKNOWN)
                        state_change_ok = TRUE;
                break;
        case GS_APP_KIND_SYSTEM:
        case GS_APP_KIND_OS_UPDATE:
+       case GS_APP_KIND_MISSING:
                /* this can never change state */
                break;
        default:
diff --git a/src/gs-app.h b/src/gs-app.h
index 81fcfa1..4864255 100644
--- a/src/gs-app.h
+++ b/src/gs-app.h
@@ -62,6 +62,7 @@ typedef enum {
        GS_APP_KIND_SYSTEM,     /* can be updated, but not installed or removed */
        GS_APP_KIND_PACKAGE,    /* can be updated, but not installed or removed */
        GS_APP_KIND_OS_UPDATE,  /* can be updated, but not installed or removed */
+       GS_APP_KIND_MISSING,    /* you can't do anything to this */
        GS_APP_KIND_LAST
 } GsAppKind;
 
@@ -72,6 +73,7 @@ typedef enum {
        GS_APP_STATE_INSTALLING,
        GS_APP_STATE_REMOVING,
        GS_APP_STATE_UPDATABLE,
+       GS_APP_STATE_UNAVAILABLE,       /* we found a reference to this */
        GS_APP_STATE_LAST
 } GsAppState;
 
@@ -89,6 +91,7 @@ typedef enum {
 #define        GS_APP_SIZE_MISSING                     1
 
 #define        GS_APP_URL_KIND_HOMEPAGE                "homepage"
+#define        GS_APP_URL_KIND_MISSING                 "missing"
 
 GQuark          gs_app_error_quark             (void);
 GType           gs_app_get_type                (void);
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index f71c3e8..bbf988e 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -389,6 +389,14 @@ gs_plugin_loader_app_is_valid (GsApp *app, gpointer user_data)
                return FALSE;
        }
 
+       /* don't show unconverted unavailables */
+       if (gs_app_get_kind (app) == GS_APP_KIND_UNKNOWN &&
+               gs_app_get_state (app) == GS_APP_STATE_UNAVAILABLE) {
+               g_debug ("app invalid as unconverted unavailable %s",
+                        gs_plugin_loader_get_app_str (app));
+               return FALSE;
+       }
+
        /* don't show unknown kind */
        if (gs_app_get_kind (app) == GS_APP_KIND_UNKNOWN) {
                g_debug ("app invalid as kind unknown %s",
@@ -1165,6 +1173,57 @@ gs_plugin_loader_get_featured_finish (GsPluginLoader *plugin_loader,
 /******************************************************************************/
 
 /**
+ * gs_plugin_loader_convert_unavailable_app:
+ **/
+static void
+gs_plugin_loader_convert_unavailable_app (GsApp *app, const gchar *search)
+{
+       GString *tmp;
+
+       tmp = g_string_new ("");
+       /* TRANSLATORS: this is when we know about an application or
+        * addon, but it can't be listed for some reason */
+       g_string_append_printf (tmp, _("No addon codecs are available "
+                               "for the %s format."), search);
+       g_string_append (tmp, "\n");
+       g_string_append_printf (tmp, _("Information about %s, as well as options "
+                               "for how to get a codec that can play this format "
+                               "can be found on the website."), search);
+       gs_app_set_summary_missing (app, tmp->str);
+       gs_app_set_kind (app, GS_APP_KIND_MISSING);
+       gs_app_set_size (app, GS_APP_SIZE_MISSING);
+       gs_app_set_icon_name (app, "dialog-question-symbolic", NULL);
+       g_string_free (tmp, TRUE);
+}
+
+/**
+ * gs_plugin_loader_convert_unavailable:
+ **/
+static void
+gs_plugin_loader_convert_unavailable (GList *list, const gchar *search)
+{
+       GList *l;
+       GsApp *app;
+
+       for (l = list; l != NULL; l = l->next) {
+               app = GS_APP (l->data);
+               if (gs_app_get_kind (app) != GS_APP_KIND_UNKNOWN &&
+                   gs_app_get_kind (app) != GS_APP_KIND_MISSING)
+                       continue;
+               if (gs_app_get_state (app) != GS_APP_STATE_UNAVAILABLE)
+                       continue;
+               if (gs_app_get_id_kind (app) != GS_APP_ID_KIND_CODEC)
+                       continue;
+               if (gs_app_get_url (app, GS_APP_URL_KIND_MISSING) == NULL)
+                       continue;
+
+               /* only convert the first unavailable codec */
+               gs_plugin_loader_convert_unavailable_app (app, search);
+               break;
+       }
+}
+
+/**
  * gs_plugin_loader_search_thread_cb:
  **/
 static void
@@ -1228,6 +1287,9 @@ gs_plugin_loader_search_thread_cb (GSimpleAsyncResult *res,
                goto out;
        }
 
+       /* convert any unavailables */
+       gs_plugin_loader_convert_unavailable (state->list, state->value);
+
        /* filter package list */
        gs_plugin_list_filter_duplicates (&state->list);
        gs_plugin_list_filter (&state->list, gs_plugin_loader_app_is_valid, NULL);
diff --git a/src/gs-shell-details.c b/src/gs-shell-details.c
index 955c610..b76d2a0 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -105,6 +105,7 @@ gs_shell_details_refresh (GsShellDetails *shell_details)
        case GS_APP_STATE_INSTALLED:
        case GS_APP_STATE_REMOVING:
        case GS_APP_STATE_UPDATABLE:
+       case GS_APP_STATE_UNAVAILABLE:
                gtk_widget_set_visible (widget, FALSE);
                break;
        default:
@@ -136,6 +137,7 @@ gs_shell_details_refresh (GsShellDetails *shell_details)
                        break;
                case GS_APP_STATE_AVAILABLE:
                case GS_APP_STATE_INSTALLING:
+               case GS_APP_STATE_UNAVAILABLE:
                        gtk_widget_set_visible (widget, FALSE);
                        break;
                default:
@@ -155,6 +157,7 @@ gs_shell_details_refresh (GsShellDetails *shell_details)
                case GS_APP_STATE_INSTALLED:
                case GS_APP_STATE_AVAILABLE:
                case GS_APP_STATE_UPDATABLE:
+               case GS_APP_STATE_UNAVAILABLE:
                        gtk_widget_set_visible (widget, FALSE);
                        gtk_spinner_stop (GTK_SPINNER (widget));
                        break;
diff --git a/src/gs-shell-search.c b/src/gs-shell-search.c
index 982b170..2405959 100644
--- a/src/gs-shell-search.c
+++ b/src/gs-shell-search.c
@@ -182,6 +182,24 @@ gs_shell_search_app_install (GsShellSearch *shell_search, GsApp *app)
 }
 
 /**
+ * gs_shell_search_show_missing_url:
+ **/
+static void
+gs_shell_search_show_missing_url (GsApp *app)
+{
+       GError *error = NULL;
+       const gchar *url;
+       gboolean ret;
+
+       url = gs_app_get_url (app, GS_APP_URL_KIND_MISSING);
+       ret = gtk_show_uri (NULL, url, GDK_CURRENT_TIME, &error);
+       if (!ret) {
+               g_warning ("spawn of '%s' failed", url);
+               g_error_free (error);
+       }
+}
+
+/**
  * gs_shell_search_app_widget_clicked_cb:
  **/
 static void
@@ -194,6 +212,8 @@ gs_shell_search_app_widget_clicked_cb (GsAppWidget *app_widget,
                gs_shell_search_app_install (shell_search, app);
        else if (gs_app_get_state (app) == GS_APP_STATE_INSTALLED)
                gs_shell_search_app_remove (shell_search, app);
+       else if (gs_app_get_state (app) == GS_APP_STATE_UNAVAILABLE)
+               gs_shell_search_show_missing_url (app);
 }
 
 /**
@@ -330,6 +350,16 @@ gs_shell_search_get_app_sort_key (GsApp *app)
        /* sort installed, removing, other */
        key = g_string_sized_new (64);
 
+       /* sort missing codecs before applications */
+       switch (gs_app_get_kind (app)) {
+       case GS_APP_KIND_MISSING:
+               g_string_append (key, "9:");
+               break;
+       default:
+               g_string_append (key, "1:");
+               break;
+       }
+
        /* artificially cut the rating of applications with no description */
        desc = gs_app_get_description (app);
        g_string_append_printf (key, "%c:", desc != NULL ? '2' : '1');
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
index be83a4d..b6581c3 100644
--- a/src/plugins/gs-plugin-appstream.c
+++ b/src/plugins/gs-plugin-appstream.c
@@ -759,6 +759,8 @@ gs_plugin_add_categories (GsPlugin *plugin,
                                item = g_ptr_array_index (array, i);
                                if (appstream_app_get_id (item) == NULL)
                                        continue;
+                               if (appstream_app_get_priority (item) < 0)
+                                       continue;
                                if (!appstream_app_has_category (item, search_id1))
                                        continue;
                                if (search_id2 != NULL && !appstream_app_has_category (item, search_id2))
diff --git a/src/plugins/gs-plugin-packagekit-refine.c b/src/plugins/gs-plugin-packagekit-refine.c
index c53947f..b32db38 100644
--- a/src/plugins/gs-plugin-packagekit-refine.c
+++ b/src/plugins/gs-plugin-packagekit-refine.c
@@ -197,8 +197,11 @@ gs_plugin_packagekit_refine_packages (GsPlugin *plugin,
                        }
                }
                if (number_installed == 0 && number_available == 0) {
-                       g_warning ("Failed to find any package for %s, %s",
-                                  gs_app_get_id (app), pkgname);
+                       g_debug ("Failed to find any package for %s, "
+                                "marking %s unavailable.",
+                                pkgname, gs_app_get_id (app));
+                       gs_app_set_kind (app, GS_APP_KIND_UNKNOWN);
+                       gs_app_set_state (app, GS_APP_STATE_UNAVAILABLE);
                } else if (number_installed == 1 && number_available >= 1) {
                        gs_app_set_state (app, GS_APP_STATE_UNKNOWN);
                        gs_app_set_state (app, GS_APP_STATE_UPDATABLE);


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