[evolution] I#697 - Add tooltip to account/source connection icon



commit ccc9082a6a5ac4ff08221701e583886470b5d069
Author: Milan Crha <mcrha redhat com>
Date:   Thu Oct 1 15:54:09 2020 +0200

    I#697 - Add tooltip to account/source connection icon
    
    Closes https://gitlab.gnome.org/GNOME/evolution/-/issues/697

 .../evolution-util/evolution-util-docs.sgml.in     |   4 +
 po/POTFILES.in                                     |   1 +
 src/e-util/e-client-selector.c                     | 112 ++++++++++++-
 src/e-util/e-source-selector.c                     | 176 +++++++++++++--------
 src/e-util/e-source-selector.h                     |   7 +
 src/mail/em-folder-tree-model.c                    |  16 +-
 src/mail/em-folder-tree-model.h                    |  10 ++
 src/mail/em-folder-tree.c                          |  70 ++++++++
 8 files changed, 325 insertions(+), 71 deletions(-)
---
diff --git a/docs/reference/evolution-util/evolution-util-docs.sgml.in 
b/docs/reference/evolution-util/evolution-util-docs.sgml.in
index 24df1d465b..20623f090b 100644
--- a/docs/reference/evolution-util/evolution-util-docs.sgml.in
+++ b/docs/reference/evolution-util/evolution-util-docs.sgml.in
@@ -323,6 +323,10 @@
     <title>Index</title>
     <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
   </index>
+  <index id="api-index-3-40" role="3.40">
+    <title>Index of new symbols in 3.40</title>
+    <xi:include href="xml/api-index-3.40.xml"><xi:fallback /></xi:include>
+  </index>
   <index id="api-index-3-36" role="3.36">
     <title>Index of new symbols in 3.36</title>
     <xi:include href="xml/api-index-3.36.xml"><xi:fallback /></xi:include>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bf1aaa9071..ba48b258e3 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -191,6 +191,7 @@ src/e-util/e-cell-text.c
 src/e-util/e-charset.c
 src/e-util/e-charset-combo-box.c
 src/e-util/e-client-cache.c
+src/e-util/e-client-selector.c
 src/e-util/e-collection-account-wizard.c
 src/e-util/e-color-chooser-widget.c
 src/e-util/e-color-combo.c
diff --git a/src/e-util/e-client-selector.c b/src/e-util/e-client-selector.c
index 473e1474bb..382436a2da 100644
--- a/src/e-util/e-client-selector.c
+++ b/src/e-util/e-client-selector.c
@@ -27,6 +27,7 @@
  * backends associated with the displayed data sources.
  **/
 
+#include <glib/gi18n-lib.h>
 #include <libedataserver/libedataserver.h>
 
 #include "e-client-selector.h"
@@ -38,6 +39,7 @@
 typedef struct _AsyncContext AsyncContext;
 
 struct _EClientSelectorPrivate {
+       GtkTreeViewColumn *connection_column;
        EClientCache *client_cache;
        gulong backend_died_handler_id;
        gulong client_created_handler_id;
@@ -59,6 +61,14 @@ G_DEFINE_TYPE (
        e_client_selector,
        E_TYPE_SOURCE_SELECTOR)
 
+enum {
+       CONNECTION_STATUS_UNKNOWN       = 0,
+       CONNECTION_STATUS_DISCONNECTED  = 1,
+       CONNECTION_STATUS_CONNECTED     = 2,
+       CONNECTION_STATUS_NO_ROUTE      = 3,
+       CONNECTION_STATUS_OTHER_ERROR   = 4
+};
+
 static void
 async_context_free (AsyncContext *async_context)
 {
@@ -85,10 +95,17 @@ client_selector_update_status_icon_cb (GtkTreeViewColumn *column,
                E_CLIENT_SELECTOR (tree_view), iter);
 
        if (client != NULL) {
-               if (e_client_is_online (client))
+               guint connection_status = CONNECTION_STATUS_UNKNOWN;
+
+               if (e_client_is_online (client)) {
                        icon_name = "network-idle-symbolic";
-               else
+                       connection_status = CONNECTION_STATUS_CONNECTED;
+               } else {
                        icon_name = "network-offline-symbolic";
+                       connection_status = CONNECTION_STATUS_DISCONNECTED;
+               }
+
+               e_source_selector_set_source_connection_status (E_SOURCE_SELECTOR (tree_view), 
e_client_get_source (client), connection_status);
 
                g_object_unref (client);
 
@@ -106,6 +123,7 @@ client_selector_update_status_icon_cb (GtkTreeViewColumn *column,
                                E_CLIENT_SELECTOR (tree_view), source);
                        if (dead_backend) {
                                icon_name = "network-error-symbolic";
+                               e_source_selector_set_source_connection_status (E_SOURCE_SELECTOR 
(tree_view), source, CONNECTION_STATUS_OTHER_ERROR);
                        } else {
                                gpointer data;
 
@@ -132,6 +150,80 @@ client_selector_update_status_icon_cb (GtkTreeViewColumn *column,
        }
 }
 
+static gboolean
+client_selector_query_tooltip_cb (GtkTreeView *tree_view,
+                                 gint xx,
+                                 gint yy,
+                                 gboolean keyboard_mode,
+                                 GtkTooltip *tooltip,
+                                 gpointer user_data)
+{
+       EClientSelector *client_selector;
+       ESourceSelector *selector;
+       ESource *source;
+       GtkCellRenderer *renderer = user_data;
+       GtkTreeModel *model = NULL;
+       GtkTreePath *path = NULL;
+       gboolean has_tooltip = FALSE;
+       guint connection_status = CONNECTION_STATUS_UNKNOWN;
+
+       g_return_val_if_fail (E_IS_CLIENT_SELECTOR (tree_view), FALSE);
+       g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
+
+       if (!gtk_tree_view_get_tooltip_context (tree_view, &xx, &yy, keyboard_mode, &model, &path, NULL))
+               return FALSE;
+
+       selector = E_SOURCE_SELECTOR (tree_view);
+       client_selector = E_CLIENT_SELECTOR (tree_view);
+       source = e_source_selector_ref_source_by_path (selector, path);
+
+       if (source)
+               connection_status = e_source_selector_get_source_connection_status (selector, source);
+
+       if (connection_status != CONNECTION_STATUS_UNKNOWN) {
+               gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, 
client_selector->priv->connection_column, renderer);
+
+               has_tooltip = TRUE;
+
+               switch (connection_status) {
+               case CONNECTION_STATUS_DISCONNECTED:
+                       gtk_tooltip_set_text (tooltip, C_("Status", "Offline"));
+                       break;
+               case CONNECTION_STATUS_CONNECTED:
+                       gtk_tooltip_set_text (tooltip, C_("Status", "Online"));
+                       break;
+               case CONNECTION_STATUS_NO_ROUTE:
+                       gtk_tooltip_set_text (tooltip, C_("Status", "Unreachable"));
+                       break;
+               case CONNECTION_STATUS_OTHER_ERROR:
+                       gtk_tooltip_set_text (tooltip, C_("Status", "Failed to connect"));
+                       break;
+               default:
+                       has_tooltip = FALSE;
+                       break;
+               }
+       }
+
+       if (!has_tooltip && source) {
+               gchar *text;
+
+               text = e_source_selector_dup_source_tooltip (selector, source);
+
+               if (text && *text) {
+                       has_tooltip = TRUE;
+                       gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
+                       gtk_tooltip_set_text (tooltip, text);
+               }
+
+               g_free (text);
+       }
+
+       gtk_tree_path_free (path);
+       g_clear_object (&source);
+
+       return has_tooltip;
+}
+
 static void
 client_selector_update_row (EClientSelector *selector,
                             EClient *client)
@@ -190,18 +282,24 @@ client_selector_can_reach_cb (GObject *source_object,
        /* EClient's online state is authoritative.
         * Defer to it if an instance already exists. */
        if (client == NULL) {
+               guint connection_status;
                const gchar *icon_name;
 
-               if (reachable)
+               if (reachable) {
                        icon_name = "network-idle-symbolic";
-               else
+                       connection_status = CONNECTION_STATUS_CONNECTED;
+               } else {
                        icon_name = "network-offline-symbolic";
+                       connection_status = CONNECTION_STATUS_DISCONNECTED;
+               }
 
                /* XXX Hackish way to stash the initial icon name. */
                g_object_set_data (
                        G_OBJECT (async_context->source),
                        "initial-icon-name", (gpointer) icon_name);
 
+               e_source_selector_set_source_connection_status (E_SOURCE_SELECTOR (async_context->selector), 
async_context->source, connection_status);
+
                e_source_selector_update_row (
                        E_SOURCE_SELECTOR (async_context->selector),
                        async_context->source);
@@ -325,6 +423,12 @@ client_selector_constructed (GObject *object)
                client_selector_update_status_icon_cb,
                NULL, (GDestroyNotify) NULL);
 
+       selector->priv->connection_column = column;
+
+       g_signal_connect_object (tree_view, "query-tooltip",
+               G_CALLBACK (client_selector_query_tooltip_cb), renderer, 0);
+       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
+
        /* Listen for signals that may change the icon. */
 
        handler_id = g_signal_connect (
diff --git a/src/e-util/e-source-selector.c b/src/e-util/e-source-selector.c
index f32e2c9a7b..db3fd28872 100644
--- a/src/e-util/e-source-selector.c
+++ b/src/e-util/e-source-selector.c
@@ -101,6 +101,7 @@ enum {
        COLUMN_SOURCE,
        COLUMN_TOOLTIP,
        COLUMN_IS_BUSY,
+       COLUMN_CONNECTION_STATUS,
        NUM_COLUMNS
 };
 
@@ -1920,7 +1921,8 @@ e_source_selector_init (ESourceSelector *selector)
                G_TYPE_INT,             /* COLUMN_WEIGHT */
                E_TYPE_SOURCE,          /* COLUMN_SOURCE */
                G_TYPE_STRING,          /* COLUMN_TOOLTIP */
-               G_TYPE_BOOLEAN);        /* COLUMN_IS_BUSY */
+               G_TYPE_BOOLEAN,         /* COLUMN_IS_BUSY */
+               G_TYPE_UINT);           /* COLUMN_CONNECTION_STATUS */
 
        gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (tree_store));
 
@@ -2985,6 +2987,41 @@ e_source_selector_update_all_rows (ESourceSelector *selector)
        g_list_free_full (list, (GDestroyNotify) g_object_unref);
 }
 
+static gboolean
+e_source_selector_get_source_iter (ESourceSelector *selector,
+                                  ESource *source,
+                                  GtkTreeIter *iter,
+                                  GtkTreeModel **out_model)
+{
+       GtkTreeRowReference *reference;
+       GtkTreeModel *model;
+       GtkTreePath *path;
+       gboolean found;
+
+       g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (iter, FALSE);
+
+       reference = g_hash_table_lookup (selector->priv->source_index, source);
+
+       /* If the ESource is not in our tree model then return silently. */
+       if (!reference)
+               return FALSE;
+
+       /* If we do have a row reference, it should be valid. */
+       g_return_val_if_fail (gtk_tree_row_reference_valid (reference), FALSE);
+
+       model = gtk_tree_row_reference_get_model (reference);
+       path = gtk_tree_row_reference_get_path (reference);
+       found = gtk_tree_model_get_iter (model, iter, path);
+       gtk_tree_path_free (path);
+
+       if (found && out_model)
+               *out_model = model;
+
+       return found;
+}
+
 /**
  * e_source_selector_set_source_tooltip:
  * @selector: an #ESourceSelector
@@ -2999,28 +3036,15 @@ e_source_selector_set_source_tooltip (ESourceSelector *selector,
                                      ESource *source,
                                      const gchar *tooltip)
 {
-       GtkTreeRowReference *reference;
-       GtkTreeModel *model;
-       GtkTreePath *path;
+       GtkTreeModel *model = NULL;
        GtkTreeIter iter;
 
        g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
        g_return_if_fail (E_IS_SOURCE (source));
 
-       reference = g_hash_table_lookup (selector->priv->source_index, source);
-
-       /* If the ESource is not in our tree model then return silently. */
-       if (reference == NULL)
+       if (!e_source_selector_get_source_iter (selector, source, &iter, &model))
                return;
 
-       /* If we do have a row reference, it should be valid. */
-       g_return_if_fail (gtk_tree_row_reference_valid (reference));
-
-       model = gtk_tree_row_reference_get_model (reference);
-       path = gtk_tree_row_reference_get_path (reference);
-       gtk_tree_model_get_iter (model, &iter, path);
-       gtk_tree_path_free (path);
-
        gtk_tree_store_set (
                GTK_TREE_STORE (model), &iter,
                COLUMN_TOOLTIP, tooltip && *tooltip ? tooltip : NULL,
@@ -3041,29 +3065,16 @@ gchar *
 e_source_selector_dup_source_tooltip (ESourceSelector *selector,
                                      ESource *source)
 {
-       GtkTreeRowReference *reference;
-       GtkTreeModel *model;
-       GtkTreePath *path;
+       GtkTreeModel *model = NULL;
        GtkTreeIter iter;
        gchar *tooltip = NULL;
 
        g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), NULL);
        g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-       reference = g_hash_table_lookup (selector->priv->source_index, source);
-
-       /* If the ESource is not in our tree model then return silently. */
-       if (reference == NULL)
+       if (!e_source_selector_get_source_iter (selector, source, &iter, &model))
                return NULL;
 
-       /* If we do have a row reference, it should be valid. */
-       g_return_val_if_fail (gtk_tree_row_reference_valid (reference), FALSE);
-
-       model = gtk_tree_row_reference_get_model (reference);
-       path = gtk_tree_row_reference_get_path (reference);
-       gtk_tree_model_get_iter (model, &iter, path);
-       gtk_tree_path_free (path);
-
        gtk_tree_model_get (
                model, &iter,
                COLUMN_TOOLTIP, &tooltip,
@@ -3086,31 +3097,17 @@ e_source_selector_set_source_is_busy (ESourceSelector *selector,
                                      ESource *source,
                                      gboolean is_busy)
 {
-       GtkTreeRowReference *reference;
-       GtkTreeModel *model;
-       GtkTreePath *path;
+       GtkTreeModel *model = NULL;
        GtkTreeIter iter;
        gboolean old_is_busy = FALSE;
 
        g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
        g_return_if_fail (E_IS_SOURCE (source));
 
-       reference = g_hash_table_lookup (selector->priv->source_index, source);
-
-       /* If the ESource is not in our tree model then return silently. */
-       if (reference == NULL)
+       if (!e_source_selector_get_source_iter (selector, source, &iter, &model))
                return;
 
-       /* If we do have a row reference, it should be valid. */
-       g_return_if_fail (gtk_tree_row_reference_valid (reference));
-
-       model = gtk_tree_row_reference_get_model (reference);
-       path = gtk_tree_row_reference_get_path (reference);
-       gtk_tree_model_get_iter (model, &iter, path);
-       gtk_tree_path_free (path);
-
-       gtk_tree_model_get (
-               GTK_TREE_MODEL (model), &iter,
+       gtk_tree_model_get (model, &iter,
                COLUMN_IS_BUSY, &old_is_busy,
                -1);
 
@@ -3141,29 +3138,16 @@ gboolean
 e_source_selector_get_source_is_busy (ESourceSelector *selector,
                                      ESource *source)
 {
-       GtkTreeRowReference *reference;
-       GtkTreeModel *model;
-       GtkTreePath *path;
+       GtkTreeModel *model = NULL;
        GtkTreeIter iter;
        gboolean is_busy = FALSE;
 
        g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), FALSE);
        g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
 
-       reference = g_hash_table_lookup (selector->priv->source_index, source);
-
-       /* If the ESource is not in our tree model then return silently. */
-       if (reference == NULL)
+       if (!e_source_selector_get_source_iter (selector, source, &iter, &model))
                return FALSE;
 
-       /* If we do have a row reference, it should be valid. */
-       g_return_val_if_fail (gtk_tree_row_reference_valid (reference), FALSE);
-
-       model = gtk_tree_row_reference_get_model (reference);
-       path = gtk_tree_row_reference_get_path (reference);
-       gtk_tree_model_get_iter (model, &iter, path);
-       gtk_tree_path_free (path);
-
        gtk_tree_model_get (
                model, &iter,
                COLUMN_IS_BUSY, &is_busy,
@@ -3172,6 +3156,72 @@ e_source_selector_get_source_is_busy (ESourceSelector *selector,
        return is_busy;
 }
 
+/**
+ * e_source_selector_set_source_connection_status:
+ * @selector: an #ESourceSelector
+ * @source: an #ESource for which to set the connection status
+ * @value: the value to set
+ *
+ * Sets connection status for the @source. It's not interpreted by the @selector,
+ * it only saves it into the model. Read it back with e_source_selector_get_source_connection_status().
+ *
+ * Since: 3.40
+ **/
+void
+e_source_selector_set_source_connection_status (ESourceSelector *selector,
+                                               ESource *source,
+                                               guint value)
+{
+       GtkTreeModel *model = NULL;
+       GtkTreeIter iter;
+
+       g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       if (!e_source_selector_get_source_iter (selector, source, &iter, &model))
+               return;
+
+       gtk_tree_store_set (
+               GTK_TREE_STORE (model), &iter,
+               COLUMN_CONNECTION_STATUS, value,
+               -1);
+}
+
+/**
+ * e_source_selector_get_source_connection_status:
+ * @selector: an #ESourceSelector
+ * @source: an #ESource for which to get the stored connection status
+ *
+ * Gets connection status for the @source. It's not interpreted by the @selector,
+ * it only returns what had been saved into the model with e_source_selector_set_source_connection_status().
+ *
+ * Returns: Value previously stored with e_source_selector_set_source_connection_status(),
+ *    or 0 when not set or when the @source was not found.
+ *
+ * Since: 3.40
+ **/
+guint
+e_source_selector_get_source_connection_status (ESourceSelector *selector,
+                                               ESource *source)
+{
+       GtkTreeModel *model = NULL;
+       GtkTreeIter iter;
+       guint value = 0;
+
+       g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), 0);
+       g_return_val_if_fail (E_IS_SOURCE (source), 0);
+
+       if (!e_source_selector_get_source_iter (selector, source, &iter, &model))
+               return 0;
+
+       gtk_tree_model_get (
+               model, &iter,
+               COLUMN_CONNECTION_STATUS, &value,
+               -1);
+
+       return value;
+}
+
 static gboolean
 source_selector_get_source_hidden (ESourceSelector *selector,
                                   ESource *source)
diff --git a/src/e-util/e-source-selector.h b/src/e-util/e-source-selector.h
index d1daa32207..1402d06347 100644
--- a/src/e-util/e-source-selector.h
+++ b/src/e-util/e-source-selector.h
@@ -162,6 +162,13 @@ void               e_source_selector_set_source_is_busy
 gboolean       e_source_selector_get_source_is_busy
                                                (ESourceSelector *selector,
                                                 ESource *source);
+void           e_source_selector_set_source_connection_status
+                                               (ESourceSelector *selector,
+                                                ESource *source,
+                                                guint value);
+guint          e_source_selector_get_source_connection_status
+                                               (ESourceSelector *selector,
+                                                ESource *source);
 gboolean       e_source_selector_manage_groups (ESourceSelector *selector);
 gboolean       e_source_selector_save_groups_setup
                                                (ESourceSelector *selector,
diff --git a/src/mail/em-folder-tree-model.c b/src/mail/em-folder-tree-model.c
index 0d3e50fedc..e2a3698065 100644
--- a/src/mail/em-folder-tree-model.c
+++ b/src/mail/em-folder-tree-model.c
@@ -1000,7 +1000,8 @@ folder_tree_model_constructed (GObject *object)
                G_TYPE_STRING,    /* COL_STRING_FOLDER_URI */
                G_TYPE_ICON,      /* COL_GICON_CUSTOM_ICON */
                GDK_TYPE_RGBA,    /* COL_RGBA_FOREGROUND_RGBA */
-               G_TYPE_UINT       /* COL_UINT_SORT_ORDER */
+               G_TYPE_UINT,      /* COL_UINT_SORT_ORDER */
+               G_TYPE_UINT       /* COL_UINT_STATUS_CODE */
        };
 
        g_warn_if_fail (G_N_ELEMENTS (col_types) == NUM_COLUMNS);
@@ -1785,6 +1786,7 @@ folder_tree_model_update_status_icon (StoreInfo *si)
        const gchar *icon_name = NULL;
        gboolean was_connecting;
        gboolean host_reachable;
+       guint status_code = EMFT_STATUS_CODE_UNKNOWN;
 
        g_return_if_fail (si != NULL);
 
@@ -1801,12 +1803,16 @@ folder_tree_model_update_status_icon (StoreInfo *si)
 
        switch (status) {
                case CAMEL_SERVICE_DISCONNECTED:
-                       if (!host_reachable)
+                       if (!host_reachable) {
                                icon_name = "network-no-route-symbolic";
-                       else if (was_connecting)
+                               status_code = EMFT_STATUS_CODE_NO_ROUTE;
+                       } else if (was_connecting) {
                                icon_name = "network-error-symbolic";
-                       else
+                               status_code = EMFT_STATUS_CODE_OTHER_ERROR;
+                       } else {
                                icon_name = "network-offline-symbolic";
+                               status_code = EMFT_STATUS_CODE_DISCONNECTED;
+                       }
                        break;
 
                case CAMEL_SERVICE_CONNECTING:
@@ -1815,6 +1821,7 @@ folder_tree_model_update_status_icon (StoreInfo *si)
 
                case CAMEL_SERVICE_CONNECTED:
                        icon_name = "network-idle-symbolic";
+                       status_code = EMFT_STATUS_CODE_CONNECTED;
                        break;
 
                case CAMEL_SERVICE_DISCONNECTING:
@@ -1851,6 +1858,7 @@ folder_tree_model_update_status_icon (StoreInfo *si)
                COL_STATUS_ICON, icon,
                COL_STATUS_ICON_VISIBLE, (icon_name != NULL),
                COL_STATUS_SPINNER_VISIBLE, (icon_name == NULL),
+               COL_UINT_STATUS_CODE, status_code,
                -1);
 
        g_clear_object (&icon);
diff --git a/src/mail/em-folder-tree-model.h b/src/mail/em-folder-tree-model.h
index 45784278be..0a6151850f 100644
--- a/src/mail/em-folder-tree-model.h
+++ b/src/mail/em-folder-tree-model.h
@@ -54,6 +54,14 @@ typedef struct _EMFolderTreeModel EMFolderTreeModel;
 typedef struct _EMFolderTreeModelClass EMFolderTreeModelClass;
 typedef struct _EMFolderTreeModelPrivate EMFolderTreeModelPrivate;
 
+enum {
+       EMFT_STATUS_CODE_UNKNOWN        = 0,
+       EMFT_STATUS_CODE_DISCONNECTED   = 1,
+       EMFT_STATUS_CODE_CONNECTED      = 2,
+       EMFT_STATUS_CODE_NO_ROUTE       = 3,
+       EMFT_STATUS_CODE_OTHER_ERROR    = 4
+};
+
 enum {
        COL_STRING_DISPLAY_NAME,        /* string that appears in the tree */
        COL_OBJECT_CAMEL_STORE,         /* CamelStore object */
@@ -82,6 +90,8 @@ enum {
        COL_RGBA_FOREGROUND_RGBA,       /* GdkRGBA for the foreground color; can be NULL */
        COL_UINT_SORT_ORDER,            /* 0 - use default; non-zero - define sort order on its level */
 
+       COL_UINT_STATUS_CODE,           /* Status code for the store - one of EMFT_STATUS_CODE_ constancts */
+
        NUM_COLUMNS
 };
 
diff --git a/src/mail/em-folder-tree.c b/src/mail/em-folder-tree.c
index 9677106712..eee04578ba 100644
--- a/src/mail/em-folder-tree.c
+++ b/src/mail/em-folder-tree.c
@@ -989,6 +989,72 @@ folder_tree_render_icon (GtkTreeViewColumn *column,
        g_free (icon_name);
 }
 
+static gboolean
+em_folder_tree_query_tooltip_cb (GtkTreeView *tree_view,
+                                gint xx,
+                                gint yy,
+                                gboolean keyboard_mode,
+                                GtkTooltip *tooltip,
+                                gpointer user_data)
+{
+       GtkCellRenderer *renderer = user_data;
+       GtkTreeModel *model = NULL;
+       GtkTreePath *path = NULL;
+       GtkTreeIter iter;
+       CamelService *service = NULL;
+       gboolean is_store = FALSE;
+       gboolean has_tooltip = FALSE;
+       guint status_code = EMFT_STATUS_CODE_UNKNOWN;
+
+       g_return_val_if_fail (EM_IS_FOLDER_TREE (tree_view), FALSE);
+       g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
+
+       if (keyboard_mode)
+               return FALSE;
+
+       if (!gtk_tree_view_get_tooltip_context (tree_view, &xx, &yy, keyboard_mode, &model, &path, &iter))
+               return FALSE;
+
+       gtk_tree_model_get (model, &iter,
+               COL_OBJECT_CAMEL_STORE, &service,
+               COL_BOOL_IS_STORE, &is_store,
+               COL_UINT_STATUS_CODE, &status_code,
+               -1);
+
+       if (is_store && service && status_code != EMFT_STATUS_CODE_UNKNOWN && CAMEL_IS_NETWORK_SERVICE 
(service)) {
+               GtkTreeViewColumn *column;
+
+               column = gtk_tree_view_get_column (tree_view, 1);
+
+               gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, column, renderer);
+
+               has_tooltip = TRUE;
+
+               switch (status_code) {
+               case EMFT_STATUS_CODE_DISCONNECTED:
+                       gtk_tooltip_set_text (tooltip, C_("Status", "Offline"));
+                       break;
+               case EMFT_STATUS_CODE_CONNECTED:
+                       gtk_tooltip_set_text (tooltip, C_("Status", "Online"));
+                       break;
+               case EMFT_STATUS_CODE_NO_ROUTE:
+                       gtk_tooltip_set_text (tooltip, C_("Status", "Unreachable"));
+                       break;
+               case EMFT_STATUS_CODE_OTHER_ERROR:
+                       gtk_tooltip_set_text (tooltip, C_("Status", "Failed to connect"));
+                       break;
+               default:
+                       has_tooltip = FALSE;
+                       break;
+               }
+       }
+
+       gtk_tree_path_free (path);
+       g_clear_object (&service);
+
+       return has_tooltip;
+}
+
 static void
 folder_tree_selection_changed_cb (EMFolderTree *folder_tree,
                                   GtkTreeSelection *selection)
@@ -1374,6 +1440,10 @@ folder_tree_constructed (GObject *object)
        gtk_tree_view_column_add_attribute (
                column, renderer, "visible", COL_STATUS_ICON_VISIBLE);
 
+       g_signal_connect_object (tree_view, "query-tooltip",
+               G_CALLBACK (em_folder_tree_query_tooltip_cb), renderer, 0);
+       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
+
        renderer = gtk_cell_renderer_spinner_new ();
        g_object_set (renderer, "xalign", 1.0, NULL);
        gtk_tree_view_column_pack_end (column, renderer, FALSE);


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