[libpeas] Show a tooltip for unavailable plugins



commit a1bc5e801d539caf3c197cc68de934cd218f17ee
Author: Garrett Regier <alias301 gmail com>
Date:   Wed Feb 9 22:33:56 2011 -0800

    Show a tooltip for unavailable plugins
    
    https://bugzilla.gnome.org/show_bug.cgi?id=511672

 libpeas-gtk/peas-gtk-plugin-manager-store.c  |    2 +-
 libpeas-gtk/peas-gtk-plugin-manager-view.c   |   50 +++++++++++++++++++++++++-
 libpeas/peas-engine.c                        |   31 +++++++++++++---
 libpeas/peas-plugin-info-priv.h              |    2 +
 libpeas/peas-plugin-info.c                   |   25 ++++++++++++-
 libpeas/peas-plugin-info.h                   |   31 +++++++++++++++-
 tests/libpeas/engine.c                       |   29 +++++++++++++--
 tests/libpeas/plugin-info.c                  |    8 +++-
 tests/libpeas/plugins/Makefile.am            |    1 +
 tests/libpeas/plugins/nonexistent-dep.plugin |    9 +++++
 10 files changed, 174 insertions(+), 14 deletions(-)
---
diff --git a/libpeas-gtk/peas-gtk-plugin-manager-store.c b/libpeas-gtk/peas-gtk-plugin-manager-store.c
index 8109e43..6be2436 100644
--- a/libpeas-gtk/peas-gtk-plugin-manager-store.c
+++ b/libpeas-gtk/peas-gtk-plugin-manager-store.c
@@ -66,7 +66,7 @@ update_plugin (PeasGtkPluginManagerStore *store,
   GdkPixbuf *icon_pixbuf = NULL;
 
   loaded = peas_plugin_info_is_loaded (info);
-  available = peas_plugin_info_is_available (info);
+  available = peas_plugin_info_is_available (info, NULL);
   builtin = peas_plugin_info_is_builtin (info);
 
   if (peas_plugin_info_get_description (info) == NULL)
diff --git a/libpeas-gtk/peas-gtk-plugin-manager-view.c b/libpeas-gtk/peas-gtk-plugin-manager-view.c
index 6aa5d04..a7afa90 100644
--- a/libpeas-gtk/peas-gtk-plugin-manager-view.c
+++ b/libpeas-gtk/peas-gtk-plugin-manager-view.c
@@ -278,7 +278,7 @@ create_popup_menu (PeasGtkPluginManagerView *view)
   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
                                   peas_plugin_info_is_loaded (info));
   g_signal_connect (item, "toggled", G_CALLBACK (enabled_menu_cb), view);
-  gtk_widget_set_sensitive (item, peas_plugin_info_is_available (info) &&
+  gtk_widget_set_sensitive (item, peas_plugin_info_is_available (info, NULL) &&
                                   !peas_plugin_info_is_builtin (info));
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
 
@@ -454,6 +454,8 @@ peas_gtk_plugin_manager_view_init (PeasGtkPluginManagerView *view)
                     G_CALLBACK (plugin_list_changed_cb),
                     view);
 
+  gtk_widget_set_has_tooltip (GTK_WIDGET (view), TRUE);
+
   gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE);
   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
 
@@ -545,6 +547,51 @@ peas_gtk_plugin_manager_view_popup_menu (GtkWidget *widget)
   return TRUE;
 }
 
+static gboolean
+peas_gtk_plugin_manager_view_query_tooltip (GtkWidget  *widget,
+                                            gint        x,
+                                            gint        y,
+                                            gboolean    keyboard_mode,
+                                            GtkTooltip *tooltip)
+{
+  PeasGtkPluginManagerView *view = PEAS_GTK_PLUGIN_MANAGER_VIEW (widget);
+  gboolean is_row;
+  GtkTreeIter iter;
+  PeasPluginInfo *info;
+  GError *error = NULL;
+
+  is_row = gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
+                                              &x, &y, keyboard_mode,
+                                              NULL, NULL, &iter);
+
+  if (!is_row)
+    return FALSE;
+    
+  convert_iter_to_child_iter (view, &iter);
+
+  info = peas_gtk_plugin_manager_store_get_plugin (view->priv->store, &iter);
+
+  if (!peas_plugin_info_is_available (info, &error))
+    {
+      gchar *message;
+
+      message = g_strdup_printf (_("<b>The plugin '%s' could not be loaded</b>\n"
+                                   "An error occurred: %s"),
+                                 peas_plugin_info_get_name (info),
+                                 error->message);
+
+      gtk_tooltip_set_markup (tooltip, message);
+
+      g_free (message);
+      g_error_free (error);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+  
+
 static void
 peas_gtk_plugin_manager_view_row_activated (GtkTreeView       *tree_view,
                                             GtkTreePath       *path,
@@ -646,6 +693,7 @@ peas_gtk_plugin_manager_view_class_init (PeasGtkPluginManagerViewClass *klass)
 
   widget_class->button_press_event = peas_gtk_plugin_manager_view_button_press_event;
   widget_class->popup_menu = peas_gtk_plugin_manager_view_popup_menu;
+  widget_class->query_tooltip = peas_gtk_plugin_manager_view_query_tooltip;
 
   tree_view_class->row_activated = peas_gtk_plugin_manager_view_row_activated;
 
diff --git a/libpeas/peas-engine.c b/libpeas/peas-engine.c
index e59e8c8..af96bf8 100644
--- a/libpeas/peas-engine.c
+++ b/libpeas/peas-engine.c
@@ -768,7 +768,7 @@ load_plugin (PeasEngine     *engine,
   if (peas_plugin_info_is_loaded (info))
     return TRUE;
 
-  if (!peas_plugin_info_is_available (info))
+  if (!peas_plugin_info_is_available (info, NULL))
     return FALSE;
 
   /* We set the plugin info as loaded before trying to load the dependencies,
@@ -782,11 +782,23 @@ load_plugin (PeasEngine     *engine,
       if (!dep_info)
         {
           g_warning ("Plugin not found: %s", dependencies[i]);
+          g_set_error (&info->error,
+                       PEAS_PLUGIN_INFO_ERROR,
+                       PEAS_PLUGIN_INFO_ERROR_DEP_NOT_FOUND,
+                       _("Dependency '%s' was not found"),
+                       dependencies[i]);
           goto error;
         }
 
       if (!peas_engine_load_plugin (engine, dep_info))
-        goto error;
+        {
+          g_set_error (&info->error,
+                       PEAS_PLUGIN_INFO_ERROR,
+                       PEAS_PLUGIN_INFO_ERROR_LOADING_FAILED,
+                       _("Dependency '%s' failed to load"),
+                       dep_info->name);
+          goto error;
+        }
     }
 
   loader = get_plugin_loader (engine, info);
@@ -795,12 +807,21 @@ load_plugin (PeasEngine     *engine,
     {
       g_warning ("Could not find loader '%s' for plugin '%s'",
                  info->loader, info->name);
+      g_set_error (&info->error,
+                   PEAS_PLUGIN_INFO_ERROR,
+                   PEAS_PLUGIN_INFO_ERROR_LOADER_NOT_FOUND,
+                   _("Plugin loader '%s' was not found"),
+                   info->loader);
       goto error;
     }
 
   if (!peas_plugin_loader_load (loader, info))
     {
       g_warning ("Error loading plugin '%s'", info->name);
+      g_set_error (&info->error,
+                   PEAS_PLUGIN_INFO_ERROR,
+                   PEAS_PLUGIN_INFO_ERROR_LOADING_FAILED,
+                   _("Failed to load"));
       goto error;
     }
 
@@ -839,7 +860,7 @@ peas_engine_load_plugin (PeasEngine     *engine,
 {
   g_return_val_if_fail (info != NULL, FALSE);
 
-  if (!peas_plugin_info_is_available (info))
+  if (!peas_plugin_info_is_available (info, NULL))
     return FALSE;
 
   if (peas_plugin_info_is_loaded (info))
@@ -859,7 +880,7 @@ peas_engine_unload_plugin_real (PeasEngine     *engine,
   PeasPluginLoader *loader;
 
   if (!peas_plugin_info_is_loaded (info) ||
-      !peas_plugin_info_is_available (info))
+      !peas_plugin_info_is_available (info, NULL))
     return;
 
   /* We set the plugin info as unloaded before trying to unload the
@@ -1133,7 +1154,7 @@ peas_engine_set_loaded_plugins (PeasEngine   *engine,
       gboolean is_loaded;
       gboolean to_load;
 
-      if (!peas_plugin_info_is_available (info))
+      if (!peas_plugin_info_is_available (info, NULL))
         continue;
 
       module_name = peas_plugin_info_get_module_name (info);
diff --git a/libpeas/peas-plugin-info-priv.h b/libpeas/peas-plugin-info-priv.h
index 6240e59..b617b84 100644
--- a/libpeas/peas-plugin-info-priv.h
+++ b/libpeas/peas-plugin-info-priv.h
@@ -48,6 +48,8 @@ struct _PeasPluginInfo {
   guint iage;
   GHashTable *keys;
 
+  GError *error;
+
   gint loaded : 1;
   /* A plugin is unavailable if it is not possible to load it
      due to an error loading the plugin module (e.g. for Python plugins
diff --git a/libpeas/peas-plugin-info.c b/libpeas/peas-plugin-info.c
index 6dd94a7..478b60a 100644
--- a/libpeas/peas-plugin-info.c
+++ b/libpeas/peas-plugin-info.c
@@ -89,6 +89,8 @@ _peas_plugin_info_unref (PeasPluginInfo *info)
   g_free (info->version);
   g_free (info->help_uri);
   g_strfreev (info->authors);
+  if (info->error != NULL)
+    g_error_free (info->error);
 
   g_free (info);
 }
@@ -106,6 +108,18 @@ peas_plugin_info_get_type (void)
   return the_type;
 }
 
+GQuark
+peas_plugin_info_error_quark (void)
+{
+  static volatile gsize quark = 0;
+
+	if (g_once_init_enter (&quark))
+		g_once_init_leave (&quark,
+		                   g_quark_from_static_string ("peas-plugin-info-error"));
+
+	return quark;
+}
+
 static void
 value_free (GValue *value)
 {
@@ -361,19 +375,28 @@ peas_plugin_info_is_loaded (const PeasPluginInfo *info)
 /**
  * peas_plugin_info_is_available:
  * @info: A #PeasPluginInfo.
+ * @error: A #GError.
  *
  * Check if the plugin is available.
  *
  * A plugin is marked as not available when there is no loader available to
  * load it, or when there has been an error when trying to load it previously.
+ * If not available then @error will be set.
  *
  * Returns: %TRUE if the plugin is available.
  */
 gboolean
-peas_plugin_info_is_available (const PeasPluginInfo *info)
+peas_plugin_info_is_available (const PeasPluginInfo  *info,
+                               GError               **error)
 {
   g_return_val_if_fail (info != NULL, FALSE);
 
+  /* Uses g_propagate_error() so we get the right warning
+   * in the case that *error != NULL
+   */
+  if (error != NULL && info->error != NULL)
+    g_propagate_error (error, g_error_copy (info->error));
+
   return info->available != FALSE;
 }
 
diff --git a/libpeas/peas-plugin-info.h b/libpeas/peas-plugin-info.h
index 0dfe8ed..249d2d3 100644
--- a/libpeas/peas-plugin-info.h
+++ b/libpeas/peas-plugin-info.h
@@ -31,6 +31,33 @@ G_BEGIN_DECLS
 #define PEAS_PLUGIN_INFO(obj)   ((PeasPluginInfo *) (obj))
 
 /**
+ * PEAS_PLUGIN_INFO_ERROR:
+ *
+ * Error domain for PeasPluginInfo. Errors in this domain will
+ * be from the PeasPluginInfoError enumeration. See GError for
+ * more information on error domains.
+ */
+#define PEAS_PLUGIN_INFO_ERROR peas_plugin_info_error_quark ()
+
+/**
+ * PeasPluginInfoError:
+ * @PEAS_PLUGIN_INFO_ERROR_LOADING_FAILED:
+ *      The plugin failed to load.
+ * @PEAS_PLUGIN_INFO_ERROR_LOADER_NOT_FOUND:
+ *      The plugin's loader was not found.
+ * @PEAS_PLUGIN_INFO_ERROR_DEP_NOT_FOUND:
+ *      A dependancy of the plugin was not found.
+ * @PEAS_PLUGIN_INFO_ERROR_DEP_LOADING_FAILED:
+ *      A dependancy of the plugin failed to load.
+ */
+typedef enum {
+  PEAS_PLUGIN_INFO_ERROR_LOADING_FAILED,
+  PEAS_PLUGIN_INFO_ERROR_LOADER_NOT_FOUND,
+  PEAS_PLUGIN_INFO_ERROR_DEP_NOT_FOUND,
+  PEAS_PLUGIN_INFO_ERROR_DEP_LOADING_FAILED
+} PeasPluginInfoError;
+
+/**
  * PeasPluginInfo:
  *
  * The #PeasPluginInfo structure contains only private data and should only
@@ -39,9 +66,11 @@ G_BEGIN_DECLS
 typedef struct _PeasPluginInfo PeasPluginInfo;
 
 GType         peas_plugin_info_get_type         (void) G_GNUC_CONST;
+GQuark        peas_plugin_info_error_quark      (void);
 
 gboolean      peas_plugin_info_is_loaded        (const PeasPluginInfo *info);
-gboolean      peas_plugin_info_is_available     (const PeasPluginInfo *info);
+gboolean      peas_plugin_info_is_available     (const PeasPluginInfo *info,
+                                                 GError               **error);
 gboolean      peas_plugin_info_is_builtin       (const PeasPluginInfo *info);
 
 const gchar  *peas_plugin_info_get_module_name  (const PeasPluginInfo *info);
diff --git a/tests/libpeas/engine.c b/tests/libpeas/engine.c
index f7054d0..9b8e97d 100644
--- a/tests/libpeas/engine.c
+++ b/tests/libpeas/engine.c
@@ -130,6 +130,23 @@ test_engine_load_plugin_with_self_dep (PeasEngine *engine)
 }
 
 static void
+test_engine_load_plugin_with_nonexistent_dep (PeasEngine *engine)
+{
+  GError *error = NULL;
+  PeasPluginInfo *info;
+
+  info = peas_engine_get_plugin_info (engine, "nonexistent-dep");
+
+  g_assert (!peas_engine_load_plugin (engine, info));
+  g_assert (!peas_plugin_info_is_loaded (info));
+  g_assert (!peas_plugin_info_is_available (info, &error));
+  g_assert_error (error, PEAS_PLUGIN_INFO_ERROR,
+                  PEAS_PLUGIN_INFO_ERROR_DEP_NOT_FOUND);
+
+  g_error_free (error);
+}
+
+static void
 test_engine_unload_plugin (PeasEngine *engine)
 {
   PeasPluginInfo *info;
@@ -181,7 +198,7 @@ test_engine_unavailable_plugin (PeasEngine *engine)
 
   g_assert (!peas_engine_load_plugin (engine, info));
   g_assert (!peas_plugin_info_is_loaded (info));
-  g_assert (!peas_plugin_info_is_available (info));
+  g_assert (!peas_plugin_info_is_available (info, NULL));
 }
 
 static void
@@ -267,13 +284,18 @@ test_engine_loaded_plugins (PeasEngine *engine)
 static void
 test_engine_nonexistent_loader (PeasEngine *engine)
 {
+  GError *error = NULL;
   PeasPluginInfo *info;
 
   info = peas_engine_get_plugin_info (engine, "nonexistent-loader");
 
   g_assert (!peas_engine_load_plugin (engine, info));
   g_assert (!peas_plugin_info_is_loaded (info));
-  g_assert (!peas_plugin_info_is_available (info));
+  g_assert (!peas_plugin_info_is_available (info, &error));
+  g_assert_error (error, PEAS_PLUGIN_INFO_ERROR,
+                  PEAS_PLUGIN_INFO_ERROR_LOADER_NOT_FOUND);
+
+  g_error_free (error);
 }
 
 static void
@@ -291,7 +313,7 @@ test_engine_disable_loader (PeasEngine *engine)
 
   g_assert (!peas_engine_load_plugin (engine, info));
   g_assert (!peas_plugin_info_is_loaded (info));
-  g_assert (!peas_plugin_info_is_available (info));
+  g_assert (!peas_plugin_info_is_available (info, NULL));
 
 
   info = peas_engine_get_plugin_info (engine, "loadable");
@@ -370,6 +392,7 @@ main (int    argc,
   TEST ("load-plugin", load_plugin);
   TEST ("load-plugin-with-dep", load_plugin_with_dep);
   TEST ("load-plugin-with-self-dep", load_plugin_with_self_dep);
+  TEST ("load-plugin-with-nonexistent-dep", load_plugin_with_nonexistent_dep);
 
   TEST ("unload-plugin", unload_plugin);
   TEST ("unload-plugin-with-dep", unload_plugin_with_dep);
diff --git a/tests/libpeas/plugin-info.c b/tests/libpeas/plugin-info.c
index 88d6a2d..6992386 100644
--- a/tests/libpeas/plugin-info.c
+++ b/tests/libpeas/plugin-info.c
@@ -61,12 +61,14 @@ static void
 test_plugin_info_verify_full_info (PeasEngine *engine)
 {
   PeasPluginInfo *info;
+  GError *error = NULL;
   const gchar **authors;
 
   info = peas_engine_get_plugin_info (engine, "full-info");
 
   g_assert (!peas_plugin_info_is_loaded (info));
-  g_assert (peas_plugin_info_is_available (info));
+  g_assert (peas_plugin_info_is_available (info, &error));
+  g_assert_no_error (error);
   g_assert (peas_plugin_info_is_builtin (info));
 
   g_assert_cmpstr (peas_plugin_info_get_module_name (info), ==, "full-info");
@@ -95,11 +97,13 @@ static void
 test_plugin_info_verify_min_info (PeasEngine *engine)
 {
   PeasPluginInfo *info;
+  GError *error = NULL;
 
   info = peas_engine_get_plugin_info (engine, "min-info");
 
   g_assert (!peas_plugin_info_is_loaded (info));
-  g_assert (peas_plugin_info_is_available (info));
+  g_assert (peas_plugin_info_is_available (info, &error));
+  g_assert_no_error (error);
   g_assert (!peas_plugin_info_is_builtin (info));
 
   g_assert_cmpstr (peas_plugin_info_get_module_name (info), ==, "min-info");
diff --git a/tests/libpeas/plugins/Makefile.am b/tests/libpeas/plugins/Makefile.am
index 70f9066..8252c99 100644
--- a/tests/libpeas/plugins/Makefile.am
+++ b/tests/libpeas/plugins/Makefile.am
@@ -13,6 +13,7 @@ noinst_DATA = \
 	info-missing-module.plugin	\
 	info-missing-name.plugin	\
 	loader-disabled.plugin		\
+	nonexistent-dep.plugin		\
 	nonexistent-loader.plugin	\
 	os-dependant-help.plugin
 
diff --git a/tests/libpeas/plugins/nonexistent-dep.plugin b/tests/libpeas/plugins/nonexistent-dep.plugin
new file mode 100644
index 0000000..1cfc76e
--- /dev/null
+++ b/tests/libpeas/plugins/nonexistent-dep.plugin
@@ -0,0 +1,9 @@
+[Plugin]
+Module=nonexistent-dep
+Depends=does-not-exist
+IAge=2
+Name=Nonexistent Dependency
+Description=This plugin has a nonexistent dependency.
+Authors=Garrett Regier
+Copyright=Copyright © 2011 Garrett Regier
+Website=http://live.gnome.org/Libpeas



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