[evolution] Add EProxySelector.



commit c44f909b52e3e206b41ab64dac00ac9ae7fa008d
Author: Matthew Barnes <mbarnes redhat com>
Date:   Mon Oct 14 11:48:52 2013 -0400

    Add EProxySelector.

 .../evolution-util/evolution-util-docs.sgml        |    1 +
 .../evolution-util/evolution-util-sections.txt     |   22 +
 doc/reference/evolution-util/evolution-util.types  |    1 +
 e-util/Makefile.am                                 |    2 +
 e-util/e-proxy-selector.c                          |  845 ++++++++++++++++++++
 e-util/e-proxy-selector.h                          |   82 ++
 e-util/e-util.h                                    |    1 +
 po/POTFILES.in                                     |    1 +
 8 files changed, 955 insertions(+), 0 deletions(-)
---
diff --git a/doc/reference/evolution-util/evolution-util-docs.sgml 
b/doc/reference/evolution-util/evolution-util-docs.sgml
index 92ecf1f..2eae89c 100644
--- a/doc/reference/evolution-util/evolution-util-docs.sgml
+++ b/doc/reference/evolution-util/evolution-util-docs.sgml
@@ -248,6 +248,7 @@
     <xi:include href="xml/e-preview-pane.xml"/>
     <xi:include href="xml/e-printable.xml"/>
     <xi:include href="xml/e-proxy-combo-box.xml"/>
+    <xi:include href="xml/e-proxy-selector.xml"/>
     <xi:include href="xml/e-search-bar.xml"/>
     <xi:include href="xml/e-selectable.xml"/>
     <xi:include href="xml/e-selection-model-array.xml"/>
diff --git a/doc/reference/evolution-util/evolution-util-sections.txt 
b/doc/reference/evolution-util/evolution-util-sections.txt
index bca6945..52471c5 100644
--- a/doc/reference/evolution-util/evolution-util-sections.txt
+++ b/doc/reference/evolution-util/evolution-util-sections.txt
@@ -2773,6 +2773,28 @@ EProxyComboBoxPrivate
 </SECTION>
 
 <SECTION>
+<FILE>e-proxy-selector</FILE>
+<TITLE>EProxySelector</TITLE>
+EProxySelector
+e_proxy_selector_new
+e_proxy_selector_refresh
+e_proxy_selector_get_registry
+e_proxy_selector_ref_selected
+e_proxy_selector_set_selected
+<SUBSECTION Standard>
+E_PROXY_SELECTOR
+E_IS_PROXY_SELECTOR
+E_TYPE_PROXY_SELECTOR
+E_PROXY_SELECTOR_CLASS
+E_IS_PROXY_SELECTOR_CLASS
+E_PROXY_SELECTOR_GET_CLASS
+EProxySelectorClass
+e_proxy_selector_get_type
+<SUBSECTION Private>
+EProxySelectorPrivate
+</SECTION>
+
+<SECTION>
 <FILE>e-reflow</FILE>
 <TITLE>EReflow</TITLE>
 EReflow
diff --git a/doc/reference/evolution-util/evolution-util.types 
b/doc/reference/evolution-util/evolution-util.types
index cd60631..166ea75 100644
--- a/doc/reference/evolution-util/evolution-util.types
+++ b/doc/reference/evolution-util/evolution-util.types
@@ -102,6 +102,7 @@ e_preferences_window_get_type
 e_preview_pane_get_type
 e_printable_get_type
 e_proxy_combo_box_get_type
+e_proxy_selector_get_type
 e_reflow_get_type
 e_reflow_model_get_type
 e_rule_context_get_type
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 22d1133..368f731 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -225,6 +225,7 @@ evolution_util_include_HEADERS =  \
        e-print.h \
        e-printable.h \
        e-proxy-combo-box.h \
+       e-proxy-selector.h \
        e-reflow-model.h \
        e-reflow.h \
        e-rule-context.h \
@@ -464,6 +465,7 @@ libevolution_util_la_SOURCES = \
        e-print.c \
        e-printable.c \
        e-proxy-combo-box.c \
+       e-proxy-selector.c \
        e-reflow-model.c \
        e-reflow.c \
        e-rule-context.c \
diff --git a/e-util/e-proxy-selector.c b/e-util/e-proxy-selector.c
new file mode 100644
index 0000000..66a353f
--- /dev/null
+++ b/e-util/e-proxy-selector.c
@@ -0,0 +1,845 @@
+/*
+ * e-proxy-selector.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/**
+ * SECTION: e-proxy-selector
+ * @include: e-util/e-util.h
+ * @short_description: Select and manage proxy profiles
+ *
+ * #EProxySelector displays a list of available proxy profiles, with inline
+ * toolbar controls for adding and removing profiles.
+ **/
+
+#include "e-proxy-selector.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#define E_PROXY_SELECTOR_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), E_TYPE_PROXY_SELECTOR, EProxySelectorPrivate))
+
+typedef struct _AsyncContext AsyncContext;
+
+struct _EProxySelectorPrivate {
+       ESourceRegistry *registry;
+       gulong source_added_handler_id;
+       gulong source_changed_handler_id;
+       gulong source_removed_handler_id;
+
+       GtkTreeSelection *selection;
+       gulong selection_changed_handler_id;
+
+       guint refresh_idle_id;
+};
+
+struct _AsyncContext {
+       EProxySelector *selector;
+       ESource *scratch_source;
+};
+
+enum {
+       PROP_0,
+       PROP_REGISTRY,
+       PROP_SELECTED
+};
+
+enum {
+       COLUMN_DISPLAY_NAME,
+       COLUMN_SOURCE
+};
+
+G_DEFINE_TYPE (
+       EProxySelector,
+       e_proxy_selector,
+       E_TYPE_TREE_VIEW_FRAME)
+
+static void
+async_context_free (AsyncContext *async_context)
+{
+       g_clear_object (&async_context->selector);
+       g_clear_object (&async_context->scratch_source);
+
+       g_slice_free (AsyncContext, async_context);
+}
+
+static gchar *
+proxy_selector_pick_display_name (EProxySelector *selector)
+{
+       ESourceRegistry *registry;
+       GList *list, *link;
+       const gchar *base_name = _("Custom Proxy");
+       const gchar *extension_name;
+       gchar *display_name;
+       guint ii = 0;
+
+       extension_name = E_SOURCE_EXTENSION_PROXY;
+       registry = e_proxy_selector_get_registry (selector);
+       list = e_source_registry_list_sources (registry, extension_name);
+
+       /* Convert the list of ESources to a list of display names. */
+       for (link = list; link != NULL; link = g_list_next (link)) {
+               ESource *source = E_SOURCE (link->data);
+               link->data = e_source_dup_display_name (source);
+               g_object_unref (source);
+       }
+
+       display_name = g_strdup (base_name);
+
+try_again:
+       link = g_list_find_custom (
+               list, display_name, (GCompareFunc) g_utf8_collate);
+
+       if (link != NULL) {
+               g_free (display_name);
+               display_name = g_strdup_printf ("%s (%u)", base_name, ++ii);
+               goto try_again;
+       }
+
+       g_list_free_full (list, (GDestroyNotify) g_free);
+
+       return display_name;
+}
+
+static void
+proxy_selector_commit_source_cb (GObject *object,
+                                 GAsyncResult *result,
+                                 gpointer user_data)
+{
+       AsyncContext *async_context;
+       GError *local_error = NULL;
+
+       async_context = (AsyncContext *) user_data;
+
+       e_source_registry_commit_source_finish (
+               E_SOURCE_REGISTRY (object), result, &local_error);
+
+       if (local_error == NULL) {
+               /* Refresh the tree model immediately. */
+               e_proxy_selector_refresh (async_context->selector);
+
+               /* Select the newly added proxy data source.  Note that
+                * e_proxy_selector_set_selected() uses e_source_equal()
+                * to match the input ESource to a tree model row, so it
+                * should match our scratch ESource to the newly-created
+                * ESource since they both have the same UID. */
+               e_proxy_selector_set_selected (
+                       async_context->selector,
+                       async_context->scratch_source);
+       } else {
+               /* FIXME Hand the error off to an EAlertSink. */
+               g_warning ("%s: %s", G_STRFUNC, local_error->message);
+               g_error_free (local_error);
+       }
+
+       gtk_widget_set_sensitive (GTK_WIDGET (async_context->selector), TRUE);
+
+       async_context_free (async_context);
+}
+
+static void
+proxy_selector_remove_source_cb (GObject *object,
+                                 GAsyncResult *result,
+                                 gpointer user_data)
+{
+       EProxySelector *selector;
+       GError *local_error = NULL;
+
+       selector = E_PROXY_SELECTOR (user_data);
+
+       e_source_remove_finish (E_SOURCE (object), result, &local_error);
+
+       if (local_error != NULL) {
+               /* FIXME Hand the error off to an EAlertSink. */
+               g_warning ("%s: %s", G_STRFUNC, local_error->message);
+               g_error_free (local_error);
+       }
+
+       gtk_widget_set_sensitive (GTK_WIDGET (selector), TRUE);
+
+       g_object_unref (selector);
+}
+
+static gboolean
+proxy_selector_action_add_cb (EProxySelector *selector,
+                              GtkAction *action)
+{
+       AsyncContext *async_context;
+       ESourceRegistry *registry;
+       ESourceProxy *extension;
+       ESource *scratch_source;
+       const gchar *extension_name;
+       gchar *display_name;
+
+       const gchar * const ignore_hosts[] = {
+               "localhost",
+               "127.0.0.0/8",
+               "::1",
+               NULL
+       };
+
+       scratch_source = e_source_new (NULL, NULL, NULL);
+
+       display_name = proxy_selector_pick_display_name (selector);
+       e_source_set_display_name (scratch_source, display_name);
+       g_free (display_name);
+
+       extension_name = E_SOURCE_EXTENSION_PROXY;
+       extension = e_source_get_extension (scratch_source, extension_name);
+       e_source_proxy_set_ignore_hosts (extension, ignore_hosts);
+
+       registry = e_proxy_selector_get_registry (selector);
+
+       /* Disable the selector until the commit operation completes. */
+       gtk_widget_set_sensitive (GTK_WIDGET (selector), FALSE);
+
+       async_context = g_slice_new0 (AsyncContext);
+       async_context->selector = g_object_ref (selector);
+       async_context->scratch_source = g_object_ref (scratch_source);
+
+       e_source_registry_commit_source (
+               registry, scratch_source, NULL,
+               proxy_selector_commit_source_cb,
+               async_context);
+
+       g_object_unref (scratch_source);
+
+       return TRUE;
+}
+
+static gboolean
+proxy_selector_action_remove_cb (EProxySelector *selector,
+                                 GtkAction *action)
+{
+       ESource *selected_source;
+
+       selected_source = e_proxy_selector_ref_selected (selector);
+       g_return_val_if_fail (selected_source != NULL, FALSE);
+
+       /* Disable the selector until the remove operation completes. */
+       gtk_widget_set_sensitive (GTK_WIDGET (selector), FALSE);
+
+       e_source_remove (
+               selected_source, NULL,
+               proxy_selector_remove_source_cb,
+               g_object_ref (selector));
+
+       g_object_unref (selected_source);
+
+       return TRUE;
+}
+
+static gboolean
+proxy_selector_refresh_idle_cb (gpointer user_data)
+{
+       EProxySelector *selector = user_data;
+
+       /* The refresh function will clear the idle ID. */
+       e_proxy_selector_refresh (selector);
+
+       return FALSE;
+}
+
+static void
+proxy_selector_schedule_refresh (EProxySelector *selector)
+{
+       /* Use an idle callback to limit how frequently we refresh
+        * the tree model in case the registry is emitting lots of
+        * signals at once. */
+
+       if (selector->priv->refresh_idle_id == 0) {
+               selector->priv->refresh_idle_id = g_idle_add (
+                       proxy_selector_refresh_idle_cb, selector);
+       }
+}
+
+static void
+proxy_selector_cell_edited_cb (GtkCellRendererText *renderer,
+                               const gchar *path_string,
+                               const gchar *new_name,
+                               EProxySelector *selector)
+{
+       ETreeViewFrame *tree_view_frame;
+       GtkTreeView *tree_view;
+       GtkTreeModel *model;
+       GtkTreePath *path;
+       GtkTreeIter iter;
+       ESource *source;
+
+       if (new_name == NULL || *new_name == '\0')
+               return;
+
+       tree_view_frame = E_TREE_VIEW_FRAME (selector);
+       tree_view = e_tree_view_frame_get_tree_view (tree_view_frame);
+       model = gtk_tree_view_get_model (tree_view);
+
+       path = gtk_tree_path_new_from_string (path_string);
+       gtk_tree_model_get_iter (model, &iter, path);
+       gtk_tree_model_get (model, &iter, COLUMN_SOURCE, &source, -1);
+       gtk_tree_path_free (path);
+
+       /* EProxyPreferences will detect the change and commit it. */
+       e_source_set_display_name (source, new_name);
+
+       e_proxy_selector_refresh (selector);
+
+       g_object_unref (source);
+}
+
+static void
+proxy_selector_source_added_cb (ESourceRegistry *registry,
+                                ESource *source,
+                                EProxySelector *selector)
+{
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_PROXY))
+               proxy_selector_schedule_refresh (selector);
+}
+
+static void
+proxy_selector_source_changed_cb (ESourceRegistry *registry,
+                                  ESource *source,
+                                  EProxySelector *selector)
+{
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_PROXY))
+               proxy_selector_schedule_refresh (selector);
+}
+
+static void
+proxy_selector_source_removed_cb (ESourceRegistry *registry,
+                                  ESource *source,
+                                  EProxySelector *selector)
+{
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_PROXY))
+               proxy_selector_schedule_refresh (selector);
+}
+
+static void
+proxy_selector_selection_changed_cb (GtkTreeSelection *selection,
+                                     EProxySelector *selector)
+{
+       g_object_notify (G_OBJECT (selector), "selected");
+}
+
+static void
+proxy_selector_set_registry (EProxySelector *selector,
+                             ESourceRegistry *registry)
+{
+       gulong handler_id;
+
+       g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+       g_return_if_fail (selector->priv->registry == NULL);
+
+       selector->priv->registry = g_object_ref (registry);
+
+       handler_id = g_signal_connect (
+               registry, "source-added",
+               G_CALLBACK (proxy_selector_source_added_cb), selector);
+       selector->priv->source_added_handler_id = handler_id;
+
+       handler_id = g_signal_connect (
+               registry, "source-changed",
+               G_CALLBACK (proxy_selector_source_changed_cb), selector);
+       selector->priv->source_changed_handler_id = handler_id;
+
+       handler_id = g_signal_connect (
+               registry, "source-removed",
+               G_CALLBACK (proxy_selector_source_removed_cb), selector);
+       selector->priv->source_removed_handler_id = handler_id;
+}
+
+static void
+proxy_selector_set_property (GObject *object,
+                             guint property_id,
+                             const GValue *value,
+                             GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_REGISTRY:
+                       proxy_selector_set_registry (
+                               E_PROXY_SELECTOR (object),
+                               g_value_get_object (value));
+                       return;
+
+               case PROP_SELECTED:
+                       e_proxy_selector_set_selected (
+                               E_PROXY_SELECTOR (object),
+                               g_value_get_object (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+proxy_selector_get_property (GObject *object,
+                             guint property_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_REGISTRY:
+                       g_value_set_object (
+                               value,
+                               e_proxy_selector_get_registry (
+                               E_PROXY_SELECTOR (object)));
+                       return;
+
+               case PROP_SELECTED:
+                       g_value_take_object (
+                               value,
+                               e_proxy_selector_ref_selected (
+                               E_PROXY_SELECTOR (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+proxy_selector_dispose (GObject *object)
+{
+       EProxySelectorPrivate *priv;
+
+       priv = E_PROXY_SELECTOR_GET_PRIVATE (object);
+
+       if (priv->source_added_handler_id > 0) {
+               g_signal_handler_disconnect (
+                       priv->registry,
+                       priv->source_added_handler_id);
+               priv->source_added_handler_id = 0;
+       }
+
+       if (priv->source_changed_handler_id > 0) {
+               g_signal_handler_disconnect (
+                       priv->registry,
+                       priv->source_changed_handler_id);
+               priv->source_changed_handler_id = 0;
+       }
+
+       if (priv->source_removed_handler_id > 0) {
+               g_signal_handler_disconnect (
+                       priv->registry,
+                       priv->source_removed_handler_id);
+               priv->source_removed_handler_id = 0;
+       }
+
+       if (priv->selection_changed_handler_id > 0) {
+               g_signal_handler_disconnect (
+                       priv->selection,
+                       priv->selection_changed_handler_id);
+               priv->selection_changed_handler_id = 0;
+       }
+
+       if (priv->refresh_idle_id > 0) {
+               g_source_remove (priv->refresh_idle_id);
+               priv->refresh_idle_id = 0;
+       }
+
+       g_clear_object (&priv->registry);
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_proxy_selector_parent_class)->dispose (object);
+}
+
+static void
+proxy_selector_constructed (GObject *object)
+{
+       EProxySelector *selector;
+       ETreeViewFrame *tree_view_frame;
+       GtkTreeView *tree_view;
+       GtkTreeViewColumn *column;
+       GtkCellRenderer *renderer;
+       GtkTreeSelection *selection;
+       GtkListStore *list_store;
+       GtkAction *action;
+       const gchar *tooltip;
+       gulong handler_id;
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_proxy_selector_parent_class)->constructed (object);
+
+       selector = E_PROXY_SELECTOR (object);
+
+       tree_view_frame = E_TREE_VIEW_FRAME (object);
+       tree_view = e_tree_view_frame_get_tree_view (tree_view_frame);
+
+       gtk_tree_view_set_reorderable (tree_view, FALSE);
+       gtk_tree_view_set_headers_visible (tree_view, FALSE);
+
+       /* Configure the toolbar actions. */
+
+       action = e_tree_view_frame_lookup_toolbar_action (
+               tree_view_frame, E_TREE_VIEW_FRAME_ACTION_ADD);
+       tooltip = _("Create a new proxy profile");
+       gtk_action_set_tooltip (action, tooltip);
+
+       action = e_tree_view_frame_lookup_toolbar_action (
+               tree_view_frame, E_TREE_VIEW_FRAME_ACTION_REMOVE);
+       tooltip = _("Delete the selected proxy profile");
+       gtk_action_set_tooltip (action, tooltip);
+
+       /* Configure the tree view column. */
+
+       column = gtk_tree_view_column_new ();
+       renderer = gtk_cell_renderer_text_new ();
+       g_object_set (
+               G_OBJECT (renderer),
+               "editable", TRUE,
+               "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+       g_signal_connect (
+               renderer, "edited",
+               G_CALLBACK (proxy_selector_cell_edited_cb), selector);
+       gtk_tree_view_column_pack_start (column, renderer, TRUE);
+       gtk_tree_view_column_add_attribute (
+               column, renderer, "text", COLUMN_DISPLAY_NAME);
+       gtk_tree_view_append_column (tree_view, column);
+
+       /* Listen for tree view selection changes. */
+
+       selection = gtk_tree_view_get_selection (tree_view);
+       selector->priv->selection = g_object_ref (selection);
+
+       handler_id = g_signal_connect (
+               selection, "changed",
+               G_CALLBACK (proxy_selector_selection_changed_cb), selector);
+       selector->priv->selection_changed_handler_id = handler_id;
+
+       /* Create and populate the tree model. */
+
+       list_store = gtk_list_store_new (2, G_TYPE_STRING, E_TYPE_SOURCE);
+       gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (list_store));
+       g_object_unref (list_store);
+
+       e_proxy_selector_refresh (E_PROXY_SELECTOR (object));
+}
+
+static void
+proxy_selector_update_toolbar_actions (ETreeViewFrame *tree_view_frame)
+{
+       EProxySelector *selector;
+       ESource *selected;
+       GtkAction *action;
+       gboolean sensitive;
+
+       selector = E_PROXY_SELECTOR (tree_view_frame);
+       selected = e_proxy_selector_ref_selected (selector);
+
+       action = e_tree_view_frame_lookup_toolbar_action (
+               tree_view_frame, E_TREE_VIEW_FRAME_ACTION_REMOVE);
+       sensitive = e_source_get_removable (selected);
+       gtk_action_set_sensitive (action, sensitive);
+
+       g_object_unref (selected);
+
+       /* Chain up to parent's update_toolbar_actions() method. */
+       E_TREE_VIEW_FRAME_CLASS (e_proxy_selector_parent_class)->
+               update_toolbar_actions (tree_view_frame);
+}
+
+static void
+e_proxy_selector_class_init (EProxySelectorClass *class)
+{
+       GObjectClass *object_class;
+       ETreeViewFrameClass *tree_view_frame_class;
+
+       g_type_class_add_private (class, sizeof (EProxySelectorPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = proxy_selector_set_property;
+       object_class->get_property = proxy_selector_get_property;
+       object_class->dispose = proxy_selector_dispose;
+       object_class->constructed = proxy_selector_constructed;
+
+       tree_view_frame_class = E_TREE_VIEW_FRAME_CLASS (class);
+       tree_view_frame_class->update_toolbar_actions =
+                               proxy_selector_update_toolbar_actions;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_REGISTRY,
+               g_param_spec_object (
+                       "registry",
+                       "Registry",
+                       "Data source registry",
+                       E_TYPE_SOURCE_REGISTRY,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_SELECTED,
+               g_param_spec_object (
+                       "selected",
+                       "Selected",
+                       "The selected data source",
+                       E_TYPE_SOURCE,
+                       G_PARAM_READWRITE |
+                       G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_proxy_selector_init (EProxySelector *selector)
+{
+       selector->priv = E_PROXY_SELECTOR_GET_PRIVATE (selector);
+
+       /* In this particular case, it's easier to connect handlers
+        * to detailed signal names than to override the class method. */
+
+       g_signal_connect (
+               selector,
+               "toolbar-action-activate::"
+               E_TREE_VIEW_FRAME_ACTION_ADD,
+               G_CALLBACK (proxy_selector_action_add_cb), NULL);
+
+       g_signal_connect (
+               selector,
+               "toolbar-action-activate::"
+               E_TREE_VIEW_FRAME_ACTION_REMOVE,
+               G_CALLBACK (proxy_selector_action_remove_cb), NULL);
+}
+
+/**
+ * e_proxy_selector_new:
+ * @registry: an #ESourceRegistry
+ *
+ * Creates a new #EProxySelector widget using #ESource instances in @registry.
+ *
+ * Returns: a new #EProxySelector
+ **/
+GtkWidget *
+e_proxy_selector_new (ESourceRegistry *registry)
+{
+       g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+       return g_object_new (
+               E_TYPE_PROXY_SELECTOR,
+               "registry", registry, NULL);
+}
+
+/**
+ * e_proxy_selector_refresh:
+ * @selector: an #EProxySelector
+ *
+ * Rebuilds the @selector's list store with an updated list of #ESource
+ * instances that describe a network proxy profile, without disrupting the
+ * previously selected item (if possible).
+ *
+ * This funtion is called automatically in response to #ESourceRegistry
+ * signals which are pertinent to the @selector.
+ **/
+void
+e_proxy_selector_refresh (EProxySelector *selector)
+{
+       ETreeViewFrame *tree_view_frame;
+       ESourceRegistry *registry;
+       GtkTreeView *tree_view;
+       GtkTreeModel *tree_model;
+       ESource *builtin_source;
+       ESource *selected;
+       GList *list, *link;
+       const gchar *extension_name;
+
+       g_return_if_fail (E_IS_PROXY_SELECTOR (selector));
+
+       if (selector->priv->refresh_idle_id > 0) {
+               g_source_remove (selector->priv->refresh_idle_id);
+               selector->priv->refresh_idle_id = 0;
+       }
+
+       tree_view_frame = E_TREE_VIEW_FRAME (selector);
+       tree_view = e_tree_view_frame_get_tree_view (tree_view_frame);
+       tree_model = gtk_tree_view_get_model (tree_view);
+
+       selected = e_proxy_selector_ref_selected (selector);
+
+       gtk_list_store_clear (GTK_LIST_STORE (tree_model));
+
+       extension_name = E_SOURCE_EXTENSION_PROXY;
+       registry = e_proxy_selector_get_registry (selector);
+       list = e_source_registry_list_enabled (registry, extension_name);
+
+       builtin_source = e_source_registry_ref_builtin_proxy (registry);
+       g_warn_if_fail (builtin_source != NULL);
+
+       /* Always list the built-in proxy profile first. */
+       link = g_list_find (list, builtin_source);
+       if (link != NULL && list != link) {
+               list = g_list_remove_link (list, link);
+               list = g_list_concat (link, list);
+       }
+
+       for (link = list; link != NULL; link = g_list_next (link)) {
+               ESource *source;
+               GtkTreeIter iter;
+               const gchar *display_name;
+
+               source = E_SOURCE (link->data);
+               display_name = e_source_get_display_name (source);
+
+               gtk_list_store_append (GTK_LIST_STORE (tree_model), &iter);
+
+               gtk_list_store_set (
+                       GTK_LIST_STORE (tree_model), &iter,
+                       COLUMN_DISPLAY_NAME, display_name,
+                       COLUMN_SOURCE, source, -1);
+       }
+
+       g_clear_object (&builtin_source);
+
+       g_list_free_full (list, (GDestroyNotify) g_object_unref);
+
+       /* Try and restore the previous selected source or else pick
+        * the built-in proxy profile, which is always listed first. */
+
+       e_proxy_selector_set_selected (selector, selected);
+
+       g_clear_object (&selected);
+}
+
+/**
+ * e_proxy_selector_get_registry:
+ * @selector: an #EProxySelector
+ *
+ * Returns the #ESourceRegistry passed to e_proxy_selector_get_registry().
+ *
+ * Returns: an #ESourceRegistry
+ **/
+ESourceRegistry *
+e_proxy_selector_get_registry (EProxySelector *selector)
+{
+       g_return_val_if_fail (E_IS_PROXY_SELECTOR (selector), NULL);
+
+       return selector->priv->registry;
+}
+
+/**
+ * e_proxy_selector_ref_selected:
+ * @selector: an #EProxySelector
+ *
+ * Returns the selected #ESource in @selector.
+ *
+ * The function tries to ensure a valid #ESource is always returned,
+ * falling back to e_source_registry_ref_builtin_proxy() if necessary.
+ *
+ * The returned #ESource is referenced for thread-safety and must be
+ * unreferenced with g_object_unref() when finished with it.
+ *
+ * Returns: an #ESource
+ **/
+ESource *
+e_proxy_selector_ref_selected (EProxySelector *selector)
+{
+       ETreeViewFrame *tree_view_frame;
+       GtkTreeView *tree_view;
+       GtkTreeModel *tree_model;
+       GtkTreeSelection *selection;
+       GtkTreeIter iter;
+       ESource *source = NULL;
+
+       g_return_val_if_fail (E_IS_PROXY_SELECTOR (selector), NULL);
+
+       tree_view_frame = E_TREE_VIEW_FRAME (selector);
+       tree_view = e_tree_view_frame_get_tree_view (tree_view_frame);
+       selection = gtk_tree_view_get_selection (tree_view);
+
+       if (gtk_tree_selection_get_selected (selection, &tree_model, &iter)) {
+               gtk_tree_model_get (
+                       tree_model, &iter,
+                       COLUMN_SOURCE, &source, -1);
+       }
+
+       /* The built-in proxy profile is implicitly selected when
+        * no proxy profile is actually selected in the tree view. */
+       if (source == NULL) {
+               ESourceRegistry *registry;
+
+               registry = e_proxy_selector_get_registry (selector);
+               source = e_source_registry_ref_builtin_proxy (registry);
+               g_return_val_if_fail (source != NULL, NULL);
+       }
+
+       return source;
+}
+
+/**
+ * e_proxy_selector_set_selected:
+ * @selector: an #EProxySelector
+ * @source: an #ESource, or %NULL for the built-in proxy profile
+ *
+ * Finds the corresponding tree model row for @source, selects the row,
+ * and returns %TRUE.  If no corresponding tree model row for @source is
+ * found, the selection remains unchanged and the function returns %FALSE.
+ *
+ * Returns: whether @source was selected
+ **/
+gboolean
+e_proxy_selector_set_selected (EProxySelector *selector,
+                               ESource *source)
+{
+       ETreeViewFrame *tree_view_frame;
+       GtkTreeView *tree_view;
+       GtkTreeModel *tree_model;
+       GtkTreeIter iter;
+       gboolean iter_valid;
+
+       g_return_val_if_fail (E_IS_PROXY_SELECTOR (selector), FALSE);
+       g_return_val_if_fail (source == NULL || E_IS_SOURCE (source), FALSE);
+
+       if (source == NULL) {
+               ESourceRegistry *registry;
+
+               registry = e_proxy_selector_get_registry (selector);
+               source = e_source_registry_ref_builtin_proxy (registry);
+               g_return_val_if_fail (source != NULL, FALSE);
+       }
+
+       tree_view_frame = E_TREE_VIEW_FRAME (selector);
+       tree_view = e_tree_view_frame_get_tree_view (tree_view_frame);
+       tree_model = gtk_tree_view_get_model (tree_view);
+
+       iter_valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+       while (iter_valid) {
+               ESource *candidate = NULL;
+               gboolean match;
+
+               gtk_tree_model_get (
+                       tree_model, &iter,
+                       COLUMN_SOURCE, &candidate, -1);
+
+               match = e_source_equal (source, candidate);
+
+               g_object_unref (candidate);
+
+               if (match)
+                       break;
+
+               iter_valid = gtk_tree_model_iter_next (tree_model, &iter);
+       }
+
+       if (iter_valid) {
+               GtkTreeSelection *selection;
+
+               selection = gtk_tree_view_get_selection (tree_view);
+               gtk_tree_selection_select_iter (selection, &iter);
+       }
+
+       return iter_valid;
+}
+
diff --git a/e-util/e-proxy-selector.h b/e-util/e-proxy-selector.h
new file mode 100644
index 0000000..32438d4
--- /dev/null
+++ b/e-util/e-proxy-selector.h
@@ -0,0 +1,82 @@
+/*
+ * e-proxy-selector.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_PROXY_SELECTOR_H
+#define E_PROXY_SELECTOR_H
+
+#include <libedataserver/libedataserver.h>
+
+#include <e-util/e-tree-view-frame.h>
+
+/* Standard GObject macros */
+#define E_TYPE_PROXY_SELECTOR \
+       (e_proxy_selector_get_type ())
+#define E_PROXY_SELECTOR(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_PROXY_SELECTOR, EProxySelector))
+#define E_PROXY_SELECTOR_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_PROXY_SELECTOR, EProxySelectorClass))
+#define E_IS_PROXY_SELECTOR(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_PROXY_SELECTOR))
+#define E_IS_PROXY_SELECTOR_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_PROXY_SELECTOR))
+#define E_PROXY_SELECTOR_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_PROXY_SELECTOR, EProxySelectorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EProxySelector EProxySelector;
+typedef struct _EProxySelectorClass EProxySelectorClass;
+typedef struct _EProxySelectorPrivate EProxySelectorPrivate;
+
+/**
+ * EProxySelector:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ **/
+struct _EProxySelector {
+       ETreeViewFrame parent;
+       EProxySelectorPrivate *priv;
+};
+
+struct _EProxySelectorClass {
+       ETreeViewFrameClass parent_class;
+};
+
+GType          e_proxy_selector_get_type       (void) G_GNUC_CONST;
+GtkWidget *    e_proxy_selector_new            (ESourceRegistry *registry);
+void           e_proxy_selector_refresh        (EProxySelector *selector);
+ESourceRegistry *
+               e_proxy_selector_get_registry   (EProxySelector *selector);
+ESource *      e_proxy_selector_ref_selected   (EProxySelector *selector);
+gboolean       e_proxy_selector_set_selected   (EProxySelector *selector,
+                                                ESource *source);
+
+G_END_DECLS
+
+#endif /* E_PROXY_SELECTOR_H */
+
diff --git a/e-util/e-util.h b/e-util/e-util.h
index 7fe92b0..3c55911 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -144,6 +144,7 @@
 #include <e-util/e-print.h>
 #include <e-util/e-printable.h>
 #include <e-util/e-proxy-combo-box.h>
+#include <e-util/e-proxy-selector.h>
 #include <e-util/e-reflow-model.h>
 #include <e-util/e-reflow.h>
 #include <e-util/e-rule-context.h>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bdee4c9..556bf0c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -243,6 +243,7 @@ e-util/e-plugin.c
 e-util/e-popup-action.c
 e-util/e-preferences-window.c
 e-util/e-print.c
+e-util/e-proxy-selector.c
 e-util/e-rule-context.c
 e-util/e-rule-editor.c
 e-util/e-search-bar.c


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