[evolution-data-server/account-mgmt: 32/38] Adapt ESourceSelector to the new ESource API.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/account-mgmt: 32/38] Adapt ESourceSelector to the new ESource API.
- Date: Wed, 28 Mar 2012 03:32:24 +0000 (UTC)
commit 1236a29b221ef10325593dff1612dcbd2e02159b
Author: Matthew Barnes <mbarnes redhat com>
Date: Sat Dec 4 16:59:53 2010 -0600
Adapt ESourceSelector to the new ESource API.
.../libedataserverui/libedataserverui-sections.txt | 11 +-
libedataserverui/e-source-selector.c | 1761 +++++++++++---------
libedataserverui/e-source-selector.h | 49 +-
tests/libedataserverui/test-source-selector.c | 88 +-
4 files changed, 1056 insertions(+), 853 deletions(-)
---
diff --git a/docs/reference/libedataserverui/libedataserverui-sections.txt b/docs/reference/libedataserverui/libedataserverui-sections.txt
index 454a5b5..b097e1e 100644
--- a/docs/reference/libedataserverui/libedataserverui-sections.txt
+++ b/docs/reference/libedataserverui/libedataserverui-sections.txt
@@ -398,20 +398,27 @@ ESourceSelector
e_source_selector_new
e_source_selector_get_registry
e_source_selector_get_extension_name
+e_source_selector_get_default_source
+e_source_selector_set_default_source
+e_source_selector_get_show_colors
+e_source_selector_set_show_colors
+e_source_selector_get_show_toggles
+e_source_selector_set_show_toggles
e_source_selector_select_source
e_source_selector_unselect_source
e_source_selector_select_exclusive
e_source_selector_source_is_selected
e_source_selector_get_selection
e_source_selector_free_selection
-e_source_selector_show_selection
-e_source_selector_selection_shown
e_source_selector_set_select_new
e_source_selector_edit_primary_selection
e_source_selector_get_primary_selection
e_source_selector_set_primary_selection
e_source_selector_peek_primary_selection
e_source_selector_get_source_by_path
+e_source_selector_selection_shown
+e_source_selector_show_selection
+e_source_selector_queue_write
<SUBSECTION Standard>
E_SOURCE_SELECTOR
E_IS_SOURCE_SELECTOR
diff --git a/libedataserverui/e-source-selector.c b/libedataserverui/e-source-selector.c
index 5948d25..9c029e3 100644
--- a/libedataserverui/e-source-selector.c
+++ b/libedataserverui/e-source-selector.c
@@ -27,6 +27,9 @@
#include <string.h>
+#include <libedataserver/e-source-selectable.h>
+
+#include "e-cell-renderer-color.h"
#include "e-data-server-ui-marshal.h"
#include "e-source-selector.h"
@@ -34,33 +37,39 @@
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_SOURCE_SELECTOR, ESourceSelectorPrivate))
+typedef struct _AsyncContext AsyncContext;
+
struct _ESourceSelectorPrivate {
- ESourceList *list;
+ ESourceRegistry *registry;
+ GHashTable *source_index;
+ ESource *default_source;
+ gchar *extension_name;
- GHashTable *selected_sources;
GtkTreeRowReference *saved_primary_selection;
- ESourceGroup *primary_source_group;
- gint rebuild_model_idle_id;
+ /* ESource -> GSource */
+ GHashTable *pending_writes;
+ GMainContext *main_context;
gboolean toggled_last;
- gboolean checkboxes_shown;
gboolean select_new;
+ gboolean show_colors;
+ gboolean show_toggles;
};
-typedef struct {
+struct _AsyncContext {
ESourceSelector *selector;
-
- GHashTable *remaining_uids;
- GSList *deleted_uids;
-
- gboolean selection_changed;
-} ESourceSelectorRebuildData;
+ ESource *source;
+};
enum {
PROP_0,
+ PROP_DEFAULT_SOURCE,
+ PROP_EXTENSION_NAME,
PROP_PRIMARY_SELECTION,
- PROP_SOURCE_LIST
+ PROP_REGISTRY,
+ PROP_SHOW_COLORS,
+ PROP_SHOW_TOGGLES
};
enum {
@@ -70,23 +79,35 @@ enum {
DATA_DROPPED,
NUM_SIGNALS
};
-static guint signals[NUM_SIGNALS] = { 0 };
-G_DEFINE_TYPE (ESourceSelector, e_source_selector, GTK_TYPE_TREE_VIEW)
+enum {
+ COLUMN_NAME,
+ COLUMN_COLOR,
+ COLUMN_ACTIVE,
+ COLUMN_SHOW_COLOR,
+ COLUMN_SHOW_TOGGLE,
+ COLUMN_WEIGHT,
+ COLUMN_SOURCE,
+ NUM_COLUMNS
+};
-/* safe-toggle-renderer definition - it'll not call 'toggled' signal on 'activate', when mouse is not over the toggle */
+static guint signals[NUM_SIGNALS];
-typedef struct _ECellRendererSafeToggle {
- GtkCellRendererToggle parent;
-} ECellRendererSafeToggle;
+G_DEFINE_TYPE (ESourceSelector, e_source_selector, GTK_TYPE_TREE_VIEW)
-typedef struct _ECellRendererSafeToggleClass {
- GtkCellRendererToggleClass parent_class;
-} ECellRendererSafeToggleClass;
+/* ESafeToggleRenderer does not emit 'toggled' signal
+ * on 'activate' when mouse is not over the toggle. */
+typedef GtkCellRendererToggle ECellRendererSafeToggle;
+typedef GtkCellRendererToggleClass ECellRendererSafeToggleClass;
+
+/* Forward Declarations */
GType e_cell_renderer_safe_toggle_get_type (void);
-G_DEFINE_TYPE (ECellRendererSafeToggle, e_cell_renderer_safe_toggle, GTK_TYPE_CELL_RENDERER_TOGGLE)
+G_DEFINE_TYPE (
+ ECellRendererSafeToggle,
+ e_cell_renderer_safe_toggle,
+ GTK_TYPE_CELL_RENDERER_TOGGLE)
static gboolean
safe_toggle_activate (GtkCellRenderer *cell,
@@ -97,34 +118,32 @@ safe_toggle_activate (GtkCellRenderer *cell,
const GdkRectangle *cell_area,
GtkCellRendererState flags)
{
- if (event->type == GDK_BUTTON_PRESS && cell_area) {
- cairo_region_t *region;
- gboolean contains_point;
+ gboolean point_in_cell_area = TRUE;
- if (cell_area->width > 0 && cell_area->height > 0)
- region = cairo_region_create_rectangle (cell_area);
- else
- region = cairo_region_create ();
+ if (event->type == GDK_BUTTON_PRESS && cell_area != NULL) {
+ cairo_region_t *region;
- contains_point = cairo_region_contains_point (
+ region = cairo_region_create_rectangle (cell_area);
+ point_in_cell_area = cairo_region_contains_point (
region, event->button.x, event->button.y);
-
cairo_region_destroy (region);
-
- if (!contains_point)
- return FALSE;
}
- return GTK_CELL_RENDERER_CLASS (e_cell_renderer_safe_toggle_parent_class)->activate (cell, event, widget, path, background_area, cell_area, flags);
+ if (!point_in_cell_area)
+ return FALSE;
+
+ return GTK_CELL_RENDERER_CLASS (
+ e_cell_renderer_safe_toggle_parent_class)->activate (
+ cell, event, widget, path, background_area, cell_area, flags);
}
static void
e_cell_renderer_safe_toggle_class_init (ECellRendererSafeToggleClass *class)
{
- GtkCellRendererClass *rndr_class;
+ GtkCellRendererClass *cell_renderer_class;
- rndr_class = GTK_CELL_RENDERER_CLASS (class);
- rndr_class->activate = safe_toggle_activate;
+ cell_renderer_class = GTK_CELL_RENDERER_CLASS (class);
+ cell_renderer_class->activate = safe_toggle_activate;
}
static void
@@ -138,36 +157,6 @@ e_cell_renderer_safe_toggle_new (void)
return g_object_new (e_cell_renderer_safe_toggle_get_type (), NULL);
}
-/* Selection management. */
-
-static ESourceSelectorRebuildData *
-create_rebuild_data (ESourceSelector *selector)
-{
- ESourceSelectorRebuildData *rebuild_data;
-
- rebuild_data = g_new0 (ESourceSelectorRebuildData, 1);
-
- rebuild_data->selector = selector;
- rebuild_data->remaining_uids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
- (GDestroyNotify) gtk_tree_row_reference_free);
- rebuild_data->deleted_uids = NULL;
-
- return rebuild_data;
-}
-
-static void
-free_rebuild_data (ESourceSelectorRebuildData *rebuild_data)
-{
- GSList *p;
-
- g_hash_table_destroy (rebuild_data->remaining_uids);
- for (p = rebuild_data->deleted_uids; p; p = p->next)
- gtk_tree_row_reference_free (p->data);
- g_slist_free (rebuild_data->deleted_uids);
-
- g_free (rebuild_data);
-}
-
static void
clear_saved_primary_selection (ESourceSelector *selector)
{
@@ -175,468 +164,311 @@ clear_saved_primary_selection (ESourceSelector *selector)
selector->priv->saved_primary_selection = NULL;
}
-static gboolean
-source_is_selected (ESourceSelector *selector,
- ESource *source)
+static void
+async_context_free (AsyncContext *async_context)
{
- GHashTable *hash_table;
+ if (async_context->selector != NULL)
+ g_object_unref (async_context->selector);
- hash_table = selector->priv->selected_sources;
+ if (async_context->source != NULL)
+ g_object_unref (async_context->source);
- return (g_hash_table_lookup (hash_table, source) != NULL);
+ g_slice_free (AsyncContext, async_context);
}
static void
-select_source (ESourceSelector *selector,
- ESource *source)
+pending_writes_destroy_source (GSource *source)
{
- if (source_is_selected (selector, source))
- return;
-
- g_hash_table_insert (
- selector->priv->selected_sources,
- source, g_object_ref (source));
+ g_source_destroy (source);
+ g_source_unref (source);
}
static void
-unselect_source (ESourceSelector *selector,
- ESource *source)
+source_selector_write_done_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- if (!source_is_selected (selector, source))
- return;
-
- /* (This will unref the source.) */
- g_hash_table_remove (selector->priv->selected_sources, source);
-}
-
-static gboolean
-find_source_iter (ESourceSelector *selector,
- ESource *source,
- GtkTreeIter *parent_iter,
- GtkTreeIter *source_iter)
-{
- GtkTreeModel *model;
-
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
-
- if (gtk_tree_model_get_iter_first (model, parent_iter)) {
- do {
- if (gtk_tree_model_iter_children (model, source_iter, parent_iter)) {
- do {
- gpointer data;
-
- gtk_tree_model_get (model, source_iter, 0, &data, -1);
- g_assert (E_IS_SOURCE (data));
+ ESource *source;
+ ESourceSelector *selector;
+ GError *error = NULL;
- if (E_SOURCE (data) == source) {
- g_object_unref (data);
+ source = E_SOURCE (source_object);
+ selector = E_SOURCE_SELECTOR (user_data);
- return TRUE;
- }
+ e_source_write_finish (source, result, &error);
- g_object_unref (data);
- } while (gtk_tree_model_iter_next (model, source_iter));
- }
- } while (gtk_tree_model_iter_next (model, parent_iter));
+ /* FIXME Display the error in the selector somehow? */
+ if (error != NULL) {
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_error_free (error);
}
- return FALSE;
+ g_object_unref (selector);
}
-/* Setting up the model. */
static gboolean
-rebuild_existing_cb (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
+source_selector_write_idle_cb (gpointer user_data)
{
- ESourceSelectorRebuildData *rebuild_data = data;
- ESourceList *source_list;
- GtkTreeRowReference *reference;
- gpointer node;
- const gchar *uid;
-
- gtk_tree_model_get (model, iter, 0, &node, -1);
-
- source_list = rebuild_data->selector->priv->list;
- reference = gtk_tree_row_reference_new (model, path);
+ AsyncContext *async_context = user_data;
+ GHashTable *pending_writes;
- if (E_IS_SOURCE_GROUP (node)) {
- uid = e_source_group_peek_uid (E_SOURCE_GROUP (node));
-
- if (e_source_list_peek_group_by_uid (source_list, uid))
- g_hash_table_insert (
- rebuild_data->remaining_uids,
- g_strdup (uid), reference);
- else
- rebuild_data->deleted_uids = g_slist_append (
- rebuild_data->deleted_uids, reference);
- } else {
- uid = e_source_peek_uid (E_SOURCE (node));
-
- if (e_source_list_peek_source_by_uid (source_list, uid)) {
- g_hash_table_insert (
- rebuild_data->remaining_uids,
- g_strdup (uid), reference);
- } else {
- rebuild_data->deleted_uids = g_slist_prepend (
- rebuild_data->deleted_uids, reference);
-
- if (g_hash_table_remove (rebuild_data->selector->priv->selected_sources, node))
- rebuild_data->selection_changed = TRUE;
- }
- }
+ /* XXX This operation is not cancellable. */
+ e_source_write (
+ async_context->source, NULL,
+ source_selector_write_done_cb,
+ g_object_ref (async_context->selector));
- g_object_unref (node);
+ pending_writes = async_context->selector->priv->pending_writes;
+ g_hash_table_remove (pending_writes, async_context->source);
return FALSE;
}
-static ESource *
-find_source (ESourceSelector *selector,
- ESource *source)
-{
- GSList *groups, *p;
-
- g_return_val_if_fail (selector != NULL, source);
- g_return_val_if_fail (E_IS_SOURCE (source), source);
-
- groups = e_source_list_peek_groups (selector->priv->list);
- for (p = groups; p != NULL; p = p->next) {
- ESourceGroup *group = E_SOURCE_GROUP (p->data);
- GSList *sources, *q;
-
- sources = e_source_group_peek_sources (group);
- for (q = sources; q != NULL; q = q->next) {
- ESource *s = E_SOURCE (q->data);
-
- if (e_source_equal (s, source))
- return s;
- }
- }
-
- return source;
-}
-
-/**
- * compare_source_names
- * Compares sources by name.
- **/
-static gint
-compare_source_names (gconstpointer a,
- gconstpointer b)
+static void
+source_selector_cancel_write (ESourceSelector *selector,
+ ESource *source)
{
- const gchar *name_a;
- const gchar *name_b;
+ GHashTable *pending_writes;
- g_return_val_if_fail (E_IS_SOURCE (a), -1);
- g_return_val_if_fail (E_IS_SOURCE (b), 1);
-
- name_a = e_source_peek_name (E_SOURCE (a));
- name_b = e_source_peek_name (E_SOURCE (b));
-
- return g_utf8_collate (name_a, name_b);
+ /* Cancel any pending writes for this ESource so as not
+ * to overwrite whatever change we're being notified of. */
+ pending_writes = selector->priv->pending_writes;
+ g_hash_table_remove (pending_writes, source);
}
static void
-rebuild_model (ESourceSelector *selector)
+source_selector_update_row (ESourceSelector *selector,
+ ESource *source)
{
- ESourceSelectorRebuildData *rebuild_data;
- ESource *source;
+ GHashTable *source_index;
+ ESourceSelectable *extension = NULL;
+ GtkTreeRowReference *reference;
GtkTreeModel *model;
- GtkTreeStore *store;
+ GtkTreePath *path;
GtkTreeIter iter;
- GSList *groups, *p;
- gboolean set_primary;
-
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
- store = GTK_TREE_STORE (model);
-
- rebuild_data = create_rebuild_data (selector);
- set_primary = e_source_selector_get_primary_selection (selector) != NULL;
-
- gtk_tree_model_foreach (model, rebuild_existing_cb, rebuild_data);
-
- /* Remove any delete sources or groups */
- for (p = rebuild_data->deleted_uids; p; p = p->next) {
- GtkTreeRowReference *row_ref = p->data;
- GtkTreePath *path;
- GtkTreeIter parent_iter;
- gboolean parent_exists = FALSE;
-
- path = gtk_tree_row_reference_get_path (row_ref);
- if (!path) {
- /* skip this, if the reference is not valid any more, like when
- * removing a group, which got removed in the previous iteration
- * because it had no children */
- continue;
- }
-
- gtk_tree_model_get_iter (model, &iter, path);
-
- /* If it is the last source in the group, delete the group from the tree */
- if (gtk_tree_model_iter_parent (model, &parent_iter, &iter))
- parent_exists = TRUE;
-
- gtk_tree_store_remove (store, &iter);
-
- if (parent_exists && !gtk_tree_model_iter_has_child (model, &parent_iter))
- gtk_tree_store_remove (store, &parent_iter);
-
- gtk_tree_path_free (path);
- }
-
- /* Add new sources/groups or call row_changed in case they were renamed */
- groups = e_source_list_peek_groups (selector->priv->list);
- for (p = groups; p != NULL; p = p->next) {
- ESourceGroup *group = E_SOURCE_GROUP (p->data);
- GtkTreeRowReference *reference;
- GSList *sources, *q;
- gint position;
-
- sources = e_source_group_peek_sources (group);
- if (sources == NULL)
- continue;
+ const gchar *ext_name;
+ const gchar *display_name;
+ gboolean selected;
- /* Copy the list and sort by name. */
- sources = g_slist_copy (sources);
- sources = g_slist_sort (sources, compare_source_names);
+ source_index = selector->priv->source_index;
+ reference = g_hash_table_lookup (source_index, source);
- reference = g_hash_table_lookup (
- rebuild_data->remaining_uids,
- e_source_group_peek_uid (group));
+ /* This function runs when ANY ESource in the registry changes.
+ * If the ESource is not in our tree model then return silently. */
+ if (reference == NULL)
+ return;
- if (reference == NULL) {
- gtk_tree_store_append (store, &iter, NULL);
- gtk_tree_store_set (store, &iter, 0, group, -1);
- } else {
- GtkTreePath *path;
+ /* If we do have a row reference, it should be valid. */
+ g_return_if_fail (gtk_tree_row_reference_valid (reference));
- path = gtk_tree_row_reference_get_path (reference);
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_model_row_changed (model, path, &iter);
- gtk_tree_path_free (path);
- }
+ 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);
- for (q = sources, position = 0; q != NULL; q = q->next, position++) {
- ESource *source = E_SOURCE (q->data);
- GtkTreeIter child_iter;
-
- reference = g_hash_table_lookup (
- rebuild_data->remaining_uids,
- e_source_peek_uid (source));
-
- if (reference == NULL) {
- if (selector->priv->select_new) {
- select_source (selector, source);
- rebuild_data->selection_changed = TRUE;
- }
-
- gtk_tree_store_insert (
- store, &child_iter, &iter, position);
- gtk_tree_store_set (
- store, &child_iter, 0, source, -1);
- } else {
- GtkTreePath *path;
-
- path = gtk_tree_row_reference_get_path (reference);
- gtk_tree_model_get_iter (model, &child_iter, path);
- gtk_tree_model_row_changed (model, path, &child_iter);
- gtk_tree_path_free (path);
- }
- }
+ display_name = e_source_get_display_name (source);
- g_slist_free (sources);
- }
+ ext_name = e_source_selector_get_extension_name (selector);
+ selected = e_source_selector_source_is_selected (selector, source);
- if (rebuild_data->selection_changed)
- g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
+ if (e_source_has_extension (source, ext_name))
+ extension = e_source_get_extension (source, ext_name);
- source = e_source_selector_get_primary_selection (selector);
- if (set_primary && source == NULL) {
- ESourceList *source_list = selector->priv->list;
- source = e_source_list_peek_source_any (source_list);
- e_source_selector_set_primary_selection (selector, source);
+ if (E_IS_SOURCE_SELECTABLE (extension)) {
+ GdkColor color;
+ const gchar *color_spec = NULL;
+ gboolean show_color = FALSE;
+ gboolean show_toggle;
+
+ if (e_source_selector_get_show_colors (selector))
+ color_spec = e_source_selectable_get_color (extension);
+
+ if (color_spec != NULL && *color_spec != '\0')
+ show_color = gdk_color_parse (color_spec, &color);
+
+ show_toggle = e_source_selector_get_show_toggles (selector);
+
+ gtk_tree_store_set (
+ GTK_TREE_STORE (model), &iter,
+ COLUMN_NAME, display_name,
+ COLUMN_COLOR, show_color ? &color : NULL,
+ COLUMN_ACTIVE, selected,
+ COLUMN_SHOW_COLOR, show_color,
+ COLUMN_SHOW_TOGGLE, show_toggle,
+ COLUMN_WEIGHT, PANGO_WEIGHT_NORMAL,
+ COLUMN_SOURCE, source,
+ -1);
+ } else {
+ gtk_tree_store_set (
+ GTK_TREE_STORE (model), &iter,
+ COLUMN_NAME, display_name,
+ COLUMN_COLOR, NULL,
+ COLUMN_ACTIVE, FALSE,
+ COLUMN_SHOW_COLOR, FALSE,
+ COLUMN_SHOW_TOGGLE, FALSE,
+ COLUMN_WEIGHT, PANGO_WEIGHT_BOLD,
+ COLUMN_SOURCE, source,
+ -1);
}
-
- free_rebuild_data (rebuild_data);
}
static gboolean
-same_source_name_exists (ESourceSelector *selector,
- const gchar *name)
+source_selector_traverse (GNode *node,
+ ESourceSelector *selector)
{
+ ESource *source;
+ GHashTable *source_index;
+ GtkTreeRowReference *reference = NULL;
GtkTreeModel *model;
- GtkTreeIter parent_iter, source_iter;
+ GtkTreePath *path;
+ GtkTreeIter iter;
- g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), FALSE);
- g_return_val_if_fail (name != NULL, FALSE);
+ /* Skip the root node. */
+ if (G_NODE_IS_ROOT (node))
+ return FALSE;
+
+ source_index = selector->priv->source_index;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
- if (gtk_tree_model_get_iter_first (model, &parent_iter)) {
- do {
- if (gtk_tree_model_iter_children (model, &source_iter, &parent_iter)) {
- do {
- gpointer data;
- const gchar *source_name;
+ if (node->parent != NULL && node->parent->data != NULL)
+ reference = g_hash_table_lookup (
+ source_index, node->parent->data);
- gtk_tree_model_get (model, &source_iter, 0, &data, -1);
- g_assert (E_IS_SOURCE (data));
+ if (gtk_tree_row_reference_valid (reference)) {
+ GtkTreeIter parent;
- source_name = e_source_peek_name (E_SOURCE (data));
- if (source_name && g_str_equal (name, source_name)) {
- g_object_unref (data);
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (model, &parent, path);
+ gtk_tree_path_free (path);
- return TRUE;
- }
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent);
+ } else
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
- g_object_unref (data);
- } while (gtk_tree_model_iter_next (model, &source_iter));
- }
- } while (gtk_tree_model_iter_next (model, &parent_iter));
- }
+ source = E_SOURCE (node->data);
- return FALSE;
-}
+ path = gtk_tree_model_get_path (model, &iter);
+ reference = gtk_tree_row_reference_new (model, path);
+ g_hash_table_insert (source_index, g_object_ref (source), reference);
+ gtk_tree_path_free (path);
-static gint
-on_idle_rebuild_model_callback (ESourceSelector *selector)
-{
- rebuild_model (selector);
- selector->priv->rebuild_model_idle_id = 0;
+ source_selector_update_row (selector, source);
return FALSE;
}
static void
-list_changed_callback (ESourceList *list,
- ESourceSelector *selector)
+source_selector_save_expanded (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GQueue *queue)
{
- ESourceSelectorPrivate *priv = selector->priv;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ ESource *source;
- if (priv->rebuild_model_idle_id == 0)
- priv->rebuild_model_idle_id = g_idle_add ((GSourceFunc) on_idle_rebuild_model_callback,
- selector);
+ model = gtk_tree_view_get_model (tree_view);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, COLUMN_SOURCE, &source, -1);
+ g_queue_push_tail (queue, source);
}
-/* Data functions for rendering the model. */
-
static void
-toggle_cell_data_func (GtkTreeViewColumn *column,
- GtkCellRenderer *renderer,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- ESourceSelector *selector)
+source_selector_build_model (ESourceSelector *selector)
{
- gpointer data;
+ ESourceRegistry *registry;
+ GQueue queue = G_QUEUE_INIT;
+ GHashTable *source_index;
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ ESource *selected;
+ const gchar *ext_name;
+ GNode *root;
- gtk_tree_model_get (model, iter, 0, &data, -1);
- if (data == NULL) {
- g_object_set (renderer, "visible", FALSE, NULL);
- return;
- }
+ tree_view = GTK_TREE_VIEW (selector);
- if (E_IS_SOURCE_GROUP (data)) {
- g_object_set (renderer, "visible", FALSE, NULL);
- } else {
- g_assert (E_IS_SOURCE (data));
+ registry = e_source_selector_get_registry (selector);
+ ext_name = e_source_selector_get_extension_name (selector);
- g_object_set (renderer, "visible", selector->priv->checkboxes_shown, NULL);
- if (source_is_selected (selector, E_SOURCE (data)))
- g_object_set (renderer, "active", TRUE, NULL);
- else
- g_object_set (renderer, "active", FALSE, NULL);
- }
+ /* Make sure we have what we need to build the model, since
+ * this can get called early in the initialization phase. */
+ if (registry == NULL || ext_name == NULL)
+ return;
- g_object_unref (data);
-}
+ source_index = selector->priv->source_index;
+ selected = e_source_selector_get_primary_selection (selector);
-static void
-text_cell_data_func (GtkTreeViewColumn *column,
- GtkCellRenderer *renderer,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- ESourceSelector *selector)
-{
- gpointer data;
+ if (selected != NULL)
+ g_object_ref (selected);
- gtk_tree_model_get (model, iter, 0, &data, -1);
- if (data == NULL) {
- g_object_set (renderer, "visible", FALSE, NULL);
- return;
- }
+ /* Save expanded sources to restore later. */
+ gtk_tree_view_map_expanded_rows (
+ tree_view, (GtkTreeViewMappingFunc)
+ source_selector_save_expanded, &queue);
- if (E_IS_SOURCE_GROUP (data)) {
- g_object_set (renderer,
- "text", e_source_group_peek_name (E_SOURCE_GROUP (data)),
- "weight", PANGO_WEIGHT_BOLD,
- "foreground_set", FALSE,
- NULL);
- } else {
- ESource *source;
+ model = gtk_tree_view_get_model (tree_view);
+ gtk_tree_store_clear (GTK_TREE_STORE (model));
- g_assert (E_IS_SOURCE (data));
- source = E_SOURCE (data);
+ g_hash_table_remove_all (source_index);
- g_object_set (renderer,
- "text", e_source_peek_name (source),
- "weight", PANGO_WEIGHT_NORMAL,
- "foreground_set", FALSE,
- NULL);
- }
+ root = e_source_registry_build_display_tree (registry, ext_name);
- g_object_unref (data);
-}
+ g_node_traverse (
+ root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+ (GNodeTraverseFunc) source_selector_traverse,
+ selector);
-static void
-pixbuf_cell_data_func (GtkTreeViewColumn *column,
- GtkCellRenderer *renderer,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- ESourceSelector *selector)
-{
- gpointer data;
+ g_node_destroy (root);
- gtk_tree_model_get (model, iter, 0, &data, -1);
- g_return_if_fail (G_IS_OBJECT (data));
+ /* Restore previously expanded sources. */
+ while (!g_queue_is_empty (&queue)) {
+ GtkTreeRowReference *reference;
+ ESource *source;
- if (E_IS_SOURCE_GROUP (data)) {
- g_object_set (renderer, "visible", FALSE, NULL);
+ source = g_queue_pop_head (&queue);
+ reference = g_hash_table_lookup (source_index, source);
- } else if (E_IS_SOURCE (data)) {
- ESource *source;
- GdkPixbuf *pixbuf = NULL;
- const gchar *color_spec;
- GdkColor color;
+ if (gtk_tree_row_reference_valid (reference)) {
+ GtkTreePath *path;
- source = E_SOURCE (data);
- color_spec = e_source_peek_color_spec (source);
- if (color_spec != NULL && gdk_color_parse (color_spec, &color)) {
- guint32 rgba;
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_view_expand_to_path (tree_view, path);
+ gtk_tree_path_free (path);
+ }
- pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 16, 16);
+ g_object_unref (source);
+ }
- rgba = (((color.red & 0xff00) << 8) |
- ((color.green & 0xff00)) |
- ((color.blue & 0xff00) >> 8)) << 8;
+ /* Restore the primary selection. */
+ if (selected != NULL) {
+ e_source_selector_set_primary_selection (selector, selected);
+ g_object_unref (selected);
+ }
+}
- gdk_pixbuf_fill (pixbuf, rgba);
- }
+static gboolean
+same_source_name_exists (ESourceSelector *selector,
+ const gchar *display_name)
+{
+ GHashTable *source_index;
+ GHashTableIter iter;
+ gpointer key;
+
+ source_index = selector->priv->source_index;
+ g_hash_table_iter_init (&iter, source_index);
- g_object_set (renderer,
- "visible", pixbuf != NULL,
- "pixbuf", pixbuf,
- NULL);
+ while (g_hash_table_iter_next (&iter, &key, NULL)) {
+ ESource *source = E_SOURCE (key);
+ const gchar *source_name;
- if (pixbuf)
- g_object_unref (pixbuf);
+ source_name = e_source_get_display_name (source);
+ if (g_strcmp0 (display_name, source_name) == 0)
+ return TRUE;
}
- g_object_unref (data);
+ return FALSE;
}
-/* Custom selection function to make groups non selectable. */
static gboolean
selection_func (GtkTreeSelection *selection,
GtkTreeModel *model,
@@ -644,12 +476,12 @@ selection_func (GtkTreeSelection *selection,
gboolean path_currently_selected,
ESourceSelector *selector)
{
+ ESource *source;
GtkTreeIter iter;
- gpointer data;
+ const gchar *ext_name;
if (selector->priv->toggled_last) {
selector->priv->toggled_last = FALSE;
-
return FALSE;
}
@@ -659,21 +491,21 @@ selection_func (GtkTreeSelection *selection,
if (!gtk_tree_model_get_iter (model, &iter, path))
return FALSE;
- gtk_tree_model_get (model, &iter, 0, &data, -1);
- if (E_IS_SOURCE_GROUP (data)) {
- g_object_unref (data);
+ ext_name = e_source_selector_get_extension_name (selector);
+ gtk_tree_model_get (model, &iter, COLUMN_SOURCE, &source, -1);
+ if (!e_source_has_extension (source, ext_name)) {
+ g_object_unref (source);
return FALSE;
}
clear_saved_primary_selection (selector);
- g_object_unref (data);
+
+ g_object_unref (source);
return TRUE;
}
-/* Callbacks. */
-
static void
text_cell_edited_cb (ESourceSelector *selector,
const gchar *path_string,
@@ -690,18 +522,18 @@ text_cell_edited_cb (ESourceSelector *selector,
path = gtk_tree_path_new_from_string (path_string);
gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_model_get (model, &iter, 0, &source, -1);
+ gtk_tree_model_get (model, &iter, COLUMN_SOURCE, &source, -1);
gtk_tree_path_free (path);
- g_return_if_fail (E_IS_SOURCE (source));
-
if (new_name == NULL || *new_name == '\0')
return;
if (same_source_name_exists (selector, new_name))
return;
- e_source_set_name (source, new_name);
+ e_source_set_display_name (source, new_name);
+
+ e_source_selector_queue_write (selector, source);
}
static void
@@ -709,11 +541,10 @@ cell_toggled_callback (GtkCellRendererToggle *renderer,
const gchar *path_string,
ESourceSelector *selector)
{
+ ESource *source;
GtkTreeModel *model;
GtkTreePath *path;
GtkTreeIter iter;
- ESource *source;
- gpointer data;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
path = gtk_tree_path_new_from_string (path_string);
@@ -723,24 +554,18 @@ cell_toggled_callback (GtkCellRendererToggle *renderer,
return;
}
- gtk_tree_model_get (model, &iter, 0, &data, -1);
- if (!E_IS_SOURCE_GROUP (data)) {
- source = E_SOURCE (data);
-
- if (source_is_selected (selector, source))
- unselect_source (selector, source);
- else
- select_source (selector, source);
+ gtk_tree_model_get (model, &iter, COLUMN_SOURCE, &source, -1);
- selector->priv->toggled_last = TRUE;
+ if (e_source_selector_source_is_selected (selector, source))
+ e_source_selector_unselect_source (selector, source);
+ else
+ e_source_selector_select_source (selector, source);
- gtk_tree_model_row_changed (model, path, &iter);
- g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
- }
+ selector->priv->toggled_last = TRUE;
gtk_tree_path_free (path);
- g_object_unref (data);
+ g_object_unref (source);
}
static void
@@ -751,52 +576,24 @@ selection_changed_callback (GtkTreeSelection *selection,
g_object_notify (G_OBJECT (selector), "primary-selection");
}
-static gboolean
-group_search_function (GtkTreeModel *model,
- gint column,
- const gchar *key,
- GtkTreeIter *iter,
- gpointer dummy)
+static void
+source_selector_set_extension_name (ESourceSelector *selector,
+ const gchar *extension_name)
{
- gpointer data;
- const gchar *name = NULL;
- gboolean status = TRUE;
-
- gtk_tree_model_get (model, iter, 0, &data, -1);
-
- if (E_IS_SOURCE_GROUP (data))
- name = e_source_group_peek_name (E_SOURCE_GROUP (data));
- else {
- g_assert (E_IS_SOURCE (data));
-
- name = e_source_peek_name (E_SOURCE (data));
- }
+ g_return_if_fail (extension_name != NULL);
+ g_return_if_fail (selector->priv->extension_name == NULL);
- if (name)
- status = g_ascii_strncasecmp (name, key, strlen (key)) != 0;
-
- g_object_unref (data);
-
- return status;
+ selector->priv->extension_name = g_strdup (extension_name);
}
static void
-source_selector_set_source_list (ESourceSelector *selector,
- ESourceList *source_list)
+source_selector_set_registry (ESourceSelector *selector,
+ ESourceRegistry *registry)
{
- g_return_if_fail (E_IS_SOURCE_LIST (source_list));
- g_return_if_fail (selector->priv->list == NULL);
-
- selector->priv->list = g_object_ref (source_list);
+ g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+ g_return_if_fail (selector->priv->registry == NULL);
- rebuild_model (selector);
-
- g_signal_connect_object (
- source_list, "changed",
- G_CALLBACK (list_changed_callback),
- G_OBJECT (selector), 0);
-
- gtk_tree_view_expand_all (GTK_TREE_VIEW (selector));
+ selector->priv->registry = g_object_ref (registry);
}
static void
@@ -806,17 +603,41 @@ source_selector_set_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
+ case PROP_DEFAULT_SOURCE:
+ e_source_selector_set_default_source (
+ E_SOURCE_SELECTOR (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_EXTENSION_NAME:
+ source_selector_set_extension_name (
+ E_SOURCE_SELECTOR (object),
+ g_value_get_string (value));
+ return;
+
case PROP_PRIMARY_SELECTION:
e_source_selector_set_primary_selection (
E_SOURCE_SELECTOR (object),
g_value_get_object (value));
return;
- case PROP_SOURCE_LIST:
- source_selector_set_source_list (
+ case PROP_REGISTRY:
+ source_selector_set_registry (
E_SOURCE_SELECTOR (object),
g_value_get_object (value));
return;
+
+ case PROP_SHOW_COLORS:
+ e_source_selector_set_show_colors (
+ E_SOURCE_SELECTOR (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SHOW_TOGGLES:
+ e_source_selector_set_show_toggles (
+ E_SOURCE_SELECTOR (object),
+ g_value_get_boolean (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -829,6 +650,20 @@ source_selector_get_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
+ case PROP_DEFAULT_SOURCE:
+ g_value_set_object (
+ value,
+ e_source_selector_get_default_source (
+ E_SOURCE_SELECTOR (object)));
+ return;
+
+ case PROP_EXTENSION_NAME:
+ g_value_set_string (
+ value,
+ e_source_selector_get_extension_name (
+ E_SOURCE_SELECTOR (object)));
+ return;
+
case PROP_PRIMARY_SELECTION:
g_value_set_object (
value,
@@ -836,10 +671,24 @@ source_selector_get_property (GObject *object,
E_SOURCE_SELECTOR (object)));
return;
- case PROP_SOURCE_LIST:
+ case PROP_REGISTRY:
g_value_set_object (
value,
- e_source_selector_get_source_list (
+ e_source_selector_get_registry (
+ E_SOURCE_SELECTOR (object)));
+ return;
+
+ case PROP_SHOW_COLORS:
+ g_value_set_boolean (
+ value,
+ e_source_selector_get_show_colors (
+ E_SOURCE_SELECTOR (object)));
+ return;
+
+ case PROP_SHOW_TOGGLES:
+ g_value_set_boolean (
+ value,
+ e_source_selector_get_show_toggles (
E_SOURCE_SELECTOR (object)));
return;
}
@@ -854,18 +703,23 @@ source_selector_dispose (GObject *object)
priv = E_SOURCE_SELECTOR_GET_PRIVATE (object);
- g_hash_table_remove_all (priv->selected_sources);
-
- if (priv->rebuild_model_idle_id != 0) {
- g_source_remove (priv->rebuild_model_idle_id);
- priv->rebuild_model_idle_id = 0;
+ if (priv->default_source != NULL) {
+ g_object_unref (priv->default_source);
+ priv->default_source = NULL;
}
- if (priv->list != NULL) {
- g_object_unref (priv->list);
- priv->list = NULL;
+ if (priv->registry != NULL) {
+ g_signal_handlers_disconnect_matched (
+ priv->registry,
+ G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, object);
+ g_object_unref (priv->registry);
+ priv->registry = NULL;
}
+ g_hash_table_remove_all (priv->source_index);
+ g_hash_table_remove_all (priv->pending_writes);
+
clear_saved_primary_selection (E_SOURCE_SELECTOR (object));
/* Chain up to parent's dispose() method. */
@@ -879,12 +733,55 @@ source_selector_finalize (GObject *object)
priv = E_SOURCE_SELECTOR_GET_PRIVATE (object);
- g_hash_table_destroy (priv->selected_sources);
+ g_hash_table_destroy (priv->source_index);
+ g_hash_table_destroy (priv->pending_writes);
+
+ g_free (priv->extension_name);
+
+ if (priv->main_context != NULL)
+ g_main_context_unref (priv->main_context);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_source_selector_parent_class)->finalize (object);
}
+static void
+source_selector_constructed (GObject *object)
+{
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ ESource *source;
+ const gchar *ext_name;
+
+ selector = E_SOURCE_SELECTOR (object);
+ registry = e_source_selector_get_registry (selector);
+ ext_name = e_source_selector_get_extension_name (selector);
+
+ /* Make sure the system source is included in the model. */
+ source = e_source_registry_lookup_by_uid (registry, "system");
+ e_source_get_extension (source, ext_name);
+
+ g_signal_connect_swapped (
+ registry, "source-added",
+ G_CALLBACK (source_selector_build_model), selector);
+
+ g_signal_connect_swapped (
+ registry, "source-removed",
+ G_CALLBACK (source_selector_build_model), selector);
+
+ g_signal_connect_swapped (
+ registry, "source-changed",
+ G_CALLBACK (source_selector_cancel_write), selector);
+
+ g_signal_connect_swapped (
+ registry, "source-changed",
+ G_CALLBACK (source_selector_update_row), selector);
+
+ source_selector_build_model (selector);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (selector));
+}
+
static gboolean
source_selector_button_press_event (GtkWidget *widget,
GdkEventButton *event)
@@ -919,25 +816,11 @@ source_selector_button_press_event (GtkWidget *widget,
if (row_exists) {
GtkTreeModel *model;
GtkTreeIter iter;
- gpointer data;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
- if (gtk_tree_model_get_iter (model, &iter, path)) {
- gtk_tree_model_get (model, &iter, 0, &data, -1);
-
- /* Do not emit popup since we will
- * not be able to get the ESource. */
- if (E_IS_SOURCE_GROUP (data)) {
- selector->priv->primary_source_group =
- g_object_ref (data);
- /* Data shuld be unreffed after
- * creating the new source. */
- goto chainup;
- }
-
- source = E_SOURCE (data);
- }
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, COLUMN_SOURCE, &source, -1);
}
if (source == NULL)
@@ -987,13 +870,13 @@ source_selector_drag_motion (GtkWidget *widget,
gint y,
guint time_)
{
+ ESource *source = NULL;
GtkTreeView *tree_view;
GtkTreeModel *model;
GtkTreePath *path = NULL;
GtkTreeIter iter;
GtkTreeViewDropPosition pos;
GdkDragAction action = 0;
- gpointer object = NULL;
tree_view = GTK_TREE_VIEW (widget);
model = gtk_tree_view_get_model (tree_view);
@@ -1004,9 +887,9 @@ source_selector_drag_motion (GtkWidget *widget,
if (!gtk_tree_model_get_iter (model, &iter, path))
goto exit;
- gtk_tree_model_get (model, &iter, 0, &object, -1);
+ gtk_tree_model_get (model, &iter, COLUMN_SOURCE, &source, -1);
- if (E_IS_SOURCE_GROUP (object) || e_source_get_readonly (object))
+ if (!e_source_get_writable (source))
goto exit;
pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
@@ -1021,8 +904,8 @@ exit:
if (path != NULL)
gtk_tree_path_free (path);
- if (object != NULL)
- g_object_unref (object);
+ if (source != NULL)
+ g_object_unref (source);
gdk_drag_status (context, action, time_);
@@ -1036,13 +919,15 @@ source_selector_drag_drop (GtkWidget *widget,
gint y,
guint time_)
{
+ ESource *source;
+ ESourceSelector *selector;
GtkTreeView *tree_view;
GtkTreeModel *model;
GtkTreePath *path;
GtkTreeIter iter;
+ const gchar *ext_name;
gboolean drop_zone;
gboolean valid;
- gpointer object;
tree_view = GTK_TREE_VIEW (widget);
model = gtk_tree_view_get_model (tree_view);
@@ -1055,9 +940,13 @@ source_selector_drag_drop (GtkWidget *widget,
gtk_tree_path_free (path);
g_return_val_if_fail (valid, FALSE);
- gtk_tree_model_get (model, &iter, 0, &object, -1);
- drop_zone = E_IS_SOURCE (object);
- g_object_unref (object);
+ gtk_tree_model_get (model, &iter, COLUMN_SOURCE, &source, -1);
+
+ selector = E_SOURCE_SELECTOR (widget);
+ ext_name = e_source_selector_get_extension_name (selector);
+ drop_zone = e_source_has_extension (source, ext_name);
+
+ g_object_unref (source);
return drop_zone;
}
@@ -1071,17 +960,20 @@ source_selector_drag_data_received (GtkWidget *widget,
guint info,
guint time_)
{
+ ESource *source = NULL;
GtkTreeView *tree_view;
GtkTreeModel *model;
GtkTreePath *path = NULL;
GtkTreeIter iter;
- gpointer object = NULL;
+ GdkDragAction action;
gboolean delete;
gboolean success = FALSE;
tree_view = GTK_TREE_VIEW (widget);
model = gtk_tree_view_get_model (tree_view);
- delete = (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE);
+
+ action = gdk_drag_context_get_selected_action (context);
+ delete = (action == GDK_ACTION_MOVE);
if (!gtk_tree_view_get_dest_row_at_pos (tree_view, x, y, &path, NULL))
goto exit;
@@ -1089,22 +981,22 @@ source_selector_drag_data_received (GtkWidget *widget,
if (!gtk_tree_model_get_iter (model, &iter, path))
goto exit;
- gtk_tree_model_get (model, &iter, 0, &object, -1);
+ gtk_tree_model_get (model, &iter, COLUMN_SOURCE, &source, -1);
- if (!E_IS_SOURCE (object) || e_source_get_readonly (object))
+ if (!e_source_get_writable (source))
goto exit;
g_signal_emit (
widget, signals[DATA_DROPPED], 0, selection_data,
- object, gdk_drag_context_get_selected_action (context),
+ source, gdk_drag_context_get_selected_action (context),
info, &success);
exit:
if (path != NULL)
gtk_tree_path_free (path);
- if (object != NULL)
- g_object_unref (object);
+ if (source != NULL)
+ g_object_unref (source);
gtk_drag_finish (context, success, delete, time_);
}
@@ -1180,30 +1072,70 @@ source_selector_row_expanded (GtkTreeView *tree_view,
priv->saved_primary_selection);
gtk_tree_model_get_iter (model, &child_iter, child_path);
- if (gtk_tree_store_is_ancestor (GTK_TREE_STORE (model), iter, &child_iter)) {
- GtkTreeSelection *selection;
+ if (gtk_tree_store_is_ancestor (GTK_TREE_STORE (model), iter, &child_iter)) {
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ gtk_tree_selection_select_iter (selection, &child_iter);
+
+ clear_saved_primary_selection (E_SOURCE_SELECTOR (tree_view));
+ }
+
+ gtk_tree_path_free (child_path);
+}
+
+static gboolean
+source_selector_get_source_selected (ESourceSelector *selector,
+ ESource *source)
+{
+ ESourceSelectable *extension;
+ const gchar *extension_name;
+
+ extension_name = e_source_selector_get_extension_name (selector);
+
+ if (!e_source_has_extension (source, extension_name))
+ return FALSE;
+
+ extension = e_source_get_extension (source, extension_name);
+ g_return_val_if_fail (E_IS_SOURCE_SELECTABLE (extension), FALSE);
+
+ return e_source_selectable_get_selected (extension);
+}
+
+static void
+source_selector_set_source_selected (ESourceSelector *selector,
+ ESource *source,
+ gboolean selected)
+{
+ ESourceSelectable *extension;
+ const gchar *extension_name;
+
+ extension_name = e_source_selector_get_extension_name (selector);
- selection = gtk_tree_view_get_selection (tree_view);
- gtk_tree_selection_select_iter (selection, &child_iter);
+ if (!e_source_has_extension (source, extension_name))
+ return;
- clear_saved_primary_selection (E_SOURCE_SELECTOR (tree_view));
- }
+ extension = e_source_get_extension (source, extension_name);
+ g_return_if_fail (E_IS_SOURCE_SELECTABLE (extension));
- gtk_tree_path_free (child_path);
+ e_source_selectable_set_selected (extension, selected);
+
+ /* Note, the "selected" property is not stored in data source
+ * key files, so no need to call e_source_selector_queue_write(). */
}
-/* Initialization. */
static gboolean
ess_bool_accumulator (GSignalInvocationHint *ihint,
GValue *out,
const GValue *in,
gpointer data)
{
- gboolean val = g_value_get_boolean (in);
+ gboolean v_boolean;
- g_value_set_boolean (out, val);
+ v_boolean = g_value_get_boolean (in);
+ g_value_set_boolean (out, v_boolean);
- return !val;
+ return !v_boolean;
}
static void
@@ -1220,6 +1152,7 @@ e_source_selector_class_init (ESourceSelectorClass *class)
object_class->get_property = source_selector_get_property;
object_class->dispose = source_selector_dispose;
object_class->finalize = source_selector_finalize;
+ object_class->constructed = source_selector_constructed;
widget_class = GTK_WIDGET_CLASS (class);
widget_class->button_press_event = source_selector_button_press_event;
@@ -1233,6 +1166,32 @@ e_source_selector_class_init (ESourceSelectorClass *class)
tree_view_class->test_collapse_row = source_selector_test_collapse_row;
tree_view_class->row_expanded = source_selector_row_expanded;
+ class->get_source_selected = source_selector_get_source_selected;
+ class->set_source_selected = source_selector_set_source_selected;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DEFAULT_SOURCE,
+ g_param_spec_object (
+ "default-source",
+ NULL,
+ NULL,
+ E_TYPE_SOURCE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_EXTENSION_NAME,
+ g_param_spec_string (
+ "extension-name",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
g_object_class_install_property (
object_class,
PROP_PRIMARY_SELECTION,
@@ -1241,18 +1200,42 @@ e_source_selector_class_init (ESourceSelectorClass *class)
NULL,
NULL,
E_TYPE_SOURCE,
- G_PARAM_READWRITE));
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
g_object_class_install_property (
object_class,
- PROP_SOURCE_LIST,
+ PROP_REGISTRY,
g_param_spec_object (
- "source-list",
+ "registry",
+ NULL,
+ NULL,
+ E_TYPE_SOURCE_REGISTRY,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_COLORS,
+ g_param_spec_boolean (
+ "show-colors",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_TOGGLES,
+ g_param_spec_boolean (
+ "show-toggles",
NULL,
NULL,
- E_TYPE_SOURCE_LIST,
+ TRUE,
G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY));
+ G_PARAM_STATIC_STRINGS));
signals[SELECTION_CHANGED] = g_signal_new (
"selection-changed",
@@ -1301,64 +1284,91 @@ e_source_selector_class_init (ESourceSelectorClass *class)
static void
e_source_selector_init (ESourceSelector *selector)
{
+ GHashTable *pending_writes;
GtkTreeViewColumn *column;
- GtkCellRenderer *cell_renderer;
GtkTreeSelection *selection;
+ GtkCellRenderer *renderer;
GtkTreeStore *tree_store;
GtkTreeView *tree_view;
+ pending_writes = g_hash_table_new_full (
+ (GHashFunc) g_direct_hash,
+ (GEqualFunc) g_direct_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) pending_writes_destroy_source);
+
selector->priv = E_SOURCE_SELECTOR_GET_PRIVATE (selector);
+ selector->priv->pending_writes = pending_writes;
+
+ selector->priv->main_context = g_main_context_get_thread_default ();
+ if (selector->priv->main_context != NULL)
+ g_main_context_ref (selector->priv->main_context);
+
tree_view = GTK_TREE_VIEW (selector);
- gtk_tree_view_set_search_column (tree_view, 0);
- gtk_tree_view_set_search_equal_func (tree_view, group_search_function, NULL, NULL);
+ gtk_tree_view_set_search_column (tree_view, COLUMN_SOURCE);
gtk_tree_view_set_enable_search (tree_view, TRUE);
selector->priv->toggled_last = FALSE;
- selector->priv->checkboxes_shown = TRUE;
selector->priv->select_new = FALSE;
+ selector->priv->show_colors = TRUE;
+ selector->priv->show_toggles = TRUE;
- selector->priv->selected_sources = g_hash_table_new_full (
- g_direct_hash, g_direct_equal,
+ selector->priv->source_index = g_hash_table_new_full (
+ (GHashFunc) e_source_hash,
+ (GEqualFunc) e_source_equal,
(GDestroyNotify) g_object_unref,
- (GDestroyNotify) NULL);
+ (GDestroyNotify) gtk_tree_row_reference_free);
+
+ tree_store = gtk_tree_store_new (
+ NUM_COLUMNS,
+ G_TYPE_STRING, /* COLUMN_NAME */
+ GDK_TYPE_COLOR, /* COLUMN_COLOR */
+ G_TYPE_BOOLEAN, /* COLUMN_ACTIVE */
+ G_TYPE_BOOLEAN, /* COLUMN_SHOW_COLOR */
+ G_TYPE_BOOLEAN, /* COLUMN_SHOW_TOGGLE */
+ G_TYPE_INT, /* COLUMN_WEIGHT */
+ E_TYPE_SOURCE); /* COLUMN_SOURCE */
- tree_store = gtk_tree_store_new (1, G_TYPE_OBJECT);
gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (tree_store));
column = gtk_tree_view_column_new ();
gtk_tree_view_append_column (tree_view, column);
- cell_renderer = gtk_cell_renderer_pixbuf_new ();
+ renderer = e_cell_renderer_color_new ();
g_object_set (
- G_OBJECT (cell_renderer),
- "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
- gtk_tree_view_column_pack_start (column, cell_renderer, FALSE);
- gtk_tree_view_column_set_cell_data_func (
- column, cell_renderer, (GtkTreeCellDataFunc)
- pixbuf_cell_data_func, selector, NULL);
-
- cell_renderer = e_cell_renderer_safe_toggle_new ();
- gtk_tree_view_column_pack_start (column, cell_renderer, FALSE);
- gtk_tree_view_column_set_cell_data_func (
- column, cell_renderer, (GtkTreeCellDataFunc)
- toggle_cell_data_func, selector, NULL);
+ G_OBJECT (renderer), "mode",
+ GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "color", COLUMN_COLOR);
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "visible", COLUMN_SHOW_COLOR);
+
+ renderer = e_cell_renderer_safe_toggle_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "active", COLUMN_ACTIVE);
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "visible", COLUMN_SHOW_TOGGLE);
g_signal_connect (
- cell_renderer, "toggled",
+ renderer, "toggled",
G_CALLBACK (cell_toggled_callback), selector);
- cell_renderer = gtk_cell_renderer_text_new ();
+ renderer = gtk_cell_renderer_text_new ();
g_object_set (
- G_OBJECT (cell_renderer),
+ G_OBJECT (renderer),
"ellipsize", PANGO_ELLIPSIZE_END, NULL);
g_signal_connect_swapped (
- cell_renderer, "edited",
+ renderer, "edited",
G_CALLBACK (text_cell_edited_cb), selector);
- gtk_tree_view_column_pack_start (column, cell_renderer, TRUE);
- gtk_tree_view_column_set_cell_data_func (
- column, cell_renderer, (GtkTreeCellDataFunc)
- text_cell_data_func, selector, NULL);
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (
+ column, renderer,
+ "text", COLUMN_NAME,
+ "weight", COLUMN_WEIGHT,
+ NULL);
selection = gtk_tree_view_get_selection (tree_view);
gtk_tree_selection_set_select_function (
@@ -1374,154 +1384,269 @@ e_source_selector_init (ESourceSelector *selector)
/**
* e_source_selector_new:
- * @list: A source list.
+ * @registry: an #ESourceRegistry
+ * @extension_name: the name of an #ESource extension
*
- * Create a new view for @list. The view will update automatically when @list
- * changes.
+ * Displays a list of sources from @registry having an extension named
+ * @extension_name. The sources are grouped by backend or groupware
+ * account, which are described by the parent source.
*
- * Returns: The newly created widget.
+ * Returns: a new #ESourceSelector
**/
GtkWidget *
-e_source_selector_new (ESourceList *list)
+e_source_selector_new (ESourceRegistry *registry,
+ const gchar *extension_name)
{
- g_return_val_if_fail (E_IS_SOURCE_LIST (list), NULL);
+ g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+ g_return_val_if_fail (extension_name != NULL, NULL);
return g_object_new (
- E_TYPE_SOURCE_SELECTOR, "source-list", list, NULL);
+ E_TYPE_SOURCE_SELECTOR, "registry", registry,
+ "extension-name", extension_name, NULL);
}
/**
- * e_source_selector_get_source_list:
+ * e_source_selector_get_registry:
* @selector: an #ESourceSelector
*
- * Returns the #ESourceList that @selector is rendering.
+ * Returns the #ESourceRegistry that @selector is getting sources from.
*
- * Returns: an #ESourceList
+ * Returns: an #ESourceRegistry
*
- * Since: 2.24
+ * Since: 3.4
**/
-ESourceList *
-e_source_selector_get_source_list (ESourceSelector *selector)
+ESourceRegistry *
+e_source_selector_get_registry (ESourceSelector *selector)
{
g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), NULL);
- return selector->priv->list;
+ return selector->priv->registry;
}
/**
- * e_source_selector_get_selection:
+ * e_source_selector_get_extension_name:
* @selector: an #ESourceSelector
*
- * Get the list of selected sources, i.e. those that were enabled through the
- * corresponding checkboxes in the tree.
+ * Returns the extension name used to filter which sources are displayed.
*
- * Returns: A list of the ESources currently selected. The sources will
- * be in the same order as they appear on the screen, and the list should be
- * freed using e_source_selector_free_selection().
+ * Returns: the #ESource extension name
+ *
+ * Since: 3.4
**/
-GSList *
-e_source_selector_get_selection (ESourceSelector *selector)
+const gchar *
+e_source_selector_get_extension_name (ESourceSelector *selector)
{
- GSList *selection_list;
- GSList *groups;
- GSList *p;
-
g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), NULL);
- selection_list = NULL;
+ return selector->priv->extension_name;
+}
+
+/**
+ * e_source_selector_get_default_source:
+ * @selector: an #ESourceSelector
+ *
+ * Returns the default #ESource set by e_source_selector_set_default(),
+ * or %NULL if no default #ESource has been set.
+ *
+ * Note that @selector does not define or use a default #ESource (yet),
+ * it's purely for convenience.
+ *
+ * Returns: the default #ESource, or %NULL
+ *
+ * Since: 3.4
+ **/
+ESource *
+e_source_selector_get_default_source (ESourceSelector *selector)
+{
+ g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), NULL);
- groups = e_source_list_peek_groups (selector->priv->list);
- for (p = groups; p != NULL; p = p->next) {
- ESourceGroup *group = E_SOURCE_GROUP (p->data);
- GSList *sources;
- GSList *q;
+ return selector->priv->default_source;
+}
- sources = e_source_group_peek_sources (group);
- for (q = sources; q != NULL; q = q->next) {
- ESource *source = E_SOURCE (q->data);
+/**
+ * e_source_selector_set_default_source:
+ * @selector: an #ESourceSelector
+ * @default_source: a default #ESource, or %NULL
+ *
+ * Stashes a reference to @default_source in @selector.
+ *
+ * Note that @selector does not define or use a default #ESource (yet),
+ * it's purely for convenience.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_selector_set_default_source (ESourceSelector *selector,
+ ESource *default_source)
+{
+ g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
- if (source_is_selected (selector, source)) {
- selection_list = g_slist_prepend (selection_list, source);
- g_object_ref (source);
- }
- }
+ if (default_source != NULL) {
+ g_return_if_fail (E_IS_SOURCE (default_source));
+ g_object_ref (default_source);
}
- return g_slist_reverse (selection_list);
+ if (selector->priv->default_source != NULL)
+ g_object_unref (selector->priv->default_source);
+
+ selector->priv->default_source = default_source;
+
+ g_object_notify (G_OBJECT (selector), "default-source");
}
/**
- * e_source_selector_get_primary_source_group:
+ * e_source_selector_get_show_colors:
* @selector: an #ESourceSelector
*
- * Gets the primary source group associated with the selector.
+ * Returns whether colors are shown next to data sources.
+ *
+ * Returns: %TRUE if colors are being shown
*
- * Returns: primary_source_group if selector is valid, NULL otherwise.
+ * Since: 3.4
**/
-ESourceGroup *
-e_source_selector_get_primary_source_group (ESourceSelector *selector)
+gboolean
+e_source_selector_get_show_colors (ESourceSelector *selector)
{
- g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), NULL);
-
- return selector->priv->primary_source_group;
+ g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), FALSE);
+ return selector->priv->show_colors;
}
/**
- * e_source_list_free_selection:
- * @list: A selection list returned by e_source_selector_get_selection().
+ * e_source_selector_set_show_colors:
+ * @selector: an #ESourceSelector
+ * @show_colors: whether to show colors
*
- * Free the selection list.
+ * Sets whether to show colors next to data sources.
+ *
+ * Since: 3.4
**/
void
-e_source_selector_free_selection (GSList *list)
+e_source_selector_set_show_colors (ESourceSelector *selector,
+ gboolean show_colors)
{
- g_slist_foreach (list, (GFunc) g_object_unref, NULL);
- g_slist_free (list);
+ g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+
+ if (show_colors == selector->priv->show_colors)
+ return;
+
+ selector->priv->show_colors = show_colors;
+
+ g_object_notify (G_OBJECT (selector), "show-colors");
+
+ source_selector_build_model (selector);
}
/**
- * e_source_selector_show_selection:
- * @selector: An ESourceSelector widget
+ * e_source_selector_get_show_toggles:
+ * @selector: an #ESourceSelector
+ *
+ * Returns whether toggles are shown next to data sources.
*
- * Specify whether the checkboxes in the ESourceSelector should be shown or
- * not.
+ * Returns: %TRUE if toggles are being shown
+ *
+ * Since: 3.4
**/
-void
-e_source_selector_show_selection (ESourceSelector *selector,
- gboolean show)
+gboolean
+e_source_selector_get_show_toggles (ESourceSelector *selector)
{
- GtkTreeModel *model;
+ g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), FALSE);
+
+ return selector->priv->show_toggles;
+}
+/**
+ * e_source_selector_set_show_toggles:
+ * @selector: an #ESourceSelector
+ * @show_toggles: whether to show toggles
+ *
+ * Sets whether to show toggles next to data sources.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_selector_set_show_toggles (ESourceSelector *selector,
+ gboolean show_toggles)
+{
g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
- show = !! show;
- if (show == selector->priv->checkboxes_shown)
+ if (show_toggles == selector->priv->show_toggles)
return;
- selector->priv->checkboxes_shown = show;
+ selector->priv->show_toggles = show_toggles;
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
+ g_object_notify (G_OBJECT (selector), "show-toggles");
- gtk_tree_model_foreach (
- model, (GtkTreeModelForeachFunc)
- gtk_tree_model_row_changed, NULL);
+ source_selector_build_model (selector);
+}
+
+/* Helper for e_source_selector_get_selection() */
+static gboolean
+source_selector_check_selected (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ ESource *source;
+
+ struct {
+ ESourceSelector *selector;
+ GSList *list;
+ } *closure = user_data;
+
+ gtk_tree_model_get (model, iter, COLUMN_SOURCE, &source, -1);
+
+ if (e_source_selector_source_is_selected (closure->selector, source))
+ closure->list = g_slist_prepend (closure->list, source);
+
+ g_object_unref (source);
+
+ return FALSE;
}
/**
- * e_source_selector_selection_shown:
+ * e_source_selector_get_selection:
* @selector: an #ESourceSelector
*
- * Check whether the checkboxes in the ESourceSelector are being shown or not.
+ * Get the list of selected sources, i.e. those that were enabled through the
+ * corresponding checkboxes in the tree.
*
- * Returns: %TRUE if the checkboxes are shown, %FALSE otherwise.
+ * Returns: A list of the ESources currently selected. The sources will
+ * be in the same order as they appear on the screen, and the list should be
+ * freed using e_source_selector_free_selection().
**/
-gboolean
-e_source_selector_selection_shown (ESourceSelector *selector)
+GSList *
+e_source_selector_get_selection (ESourceSelector *selector)
{
- g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), FALSE);
+ struct {
+ ESourceSelector *selector;
+ GSList *list;
+ } closure;
+
+ g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), NULL);
- return selector->priv->checkboxes_shown;
+ closure.selector = selector;
+ closure.list = NULL;
+
+ gtk_tree_model_foreach (
+ gtk_tree_view_get_model (GTK_TREE_VIEW (selector)),
+ (GtkTreeModelForeachFunc) source_selector_check_selected,
+ &closure);
+
+ return g_slist_reverse (closure.list);
+}
+
+/**
+ * e_source_list_free_selection:
+ * @list: A selection list returned by e_source_selector_get_selection().
+ *
+ * Free the selection list.
+ **/
+void
+e_source_selector_free_selection (GSList *list)
+{
+ g_slist_foreach (list, (GFunc) g_object_unref, NULL);
+ g_slist_free (list);
}
/**
@@ -1551,31 +1676,24 @@ void
e_source_selector_select_source (ESourceSelector *selector,
ESource *source)
{
- GtkTreeIter parent_iter, source_iter;
+ ESourceSelectorClass *class;
+ GtkTreeRowReference *reference;
+ GHashTable *source_index;
g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
g_return_if_fail (E_IS_SOURCE (source));
- source = find_source (selector, source);
- g_return_if_fail (source != NULL);
-
- if (source_is_selected (selector, source))
- return;
-
- select_source (selector, source);
+ /* Make sure the ESource is in our tree model. */
+ source_index = selector->priv->source_index;
+ reference = g_hash_table_lookup (source_index, source);
+ g_return_if_fail (gtk_tree_row_reference_valid (reference));
- if (find_source_iter (selector, source, &parent_iter, &source_iter)) {
- GtkTreeModel *model;
- GtkTreePath *path;
+ class = E_SOURCE_SELECTOR_GET_CLASS (selector);
+ g_return_if_fail (class->set_source_selected != NULL);
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
-
- path = gtk_tree_model_get_path (model, &source_iter);
- gtk_tree_model_row_changed (model, path, &source_iter);
- gtk_tree_path_free (path);
+ class->set_source_selected (selector, source, TRUE);
- g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
- }
+ g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
}
/**
@@ -1589,62 +1707,24 @@ void
e_source_selector_unselect_source (ESourceSelector *selector,
ESource *source)
{
- GtkTreeIter parent_iter, source_iter;
+ ESourceSelectorClass *class;
+ GtkTreeRowReference *reference;
+ GHashTable *source_index;
g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
g_return_if_fail (E_IS_SOURCE (source));
- source = find_source (selector, source);
- g_return_if_fail (source != NULL);
-
- if (!source_is_selected (selector, source))
- return;
-
- unselect_source (selector, source);
-
- if (find_source_iter (selector, source, &parent_iter, &source_iter)) {
- GtkTreeModel *model;
- GtkTreePath *path;
-
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
-
- path = gtk_tree_model_get_path (model, &source_iter);
- gtk_tree_model_row_changed (model, path, &source_iter);
- gtk_tree_path_free (path);
-
- g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
- }
-}
-
-/* Helper for e_source_selector_select_exclusive() */
-static gboolean
-source_selector_select_exclusive_foreach (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer user_data)
-{
- ESource *source;
-
- struct {
- ESourceSelector *selector;
- ESource *source_to_select;
- } *data = user_data;
-
- if (gtk_tree_path_get_depth (path) != 2)
- return FALSE;
-
- gtk_tree_model_get (model, iter, 0, &source, -1);
-
- if (source == data->source_to_select)
- select_source (data->selector, source);
- else
- unselect_source (data->selector, source);
+ /* Make sure the ESource is in our tree model. */
+ source_index = selector->priv->source_index;
+ reference = g_hash_table_lookup (source_index, source);
+ g_return_if_fail (gtk_tree_row_reference_valid (reference));
- gtk_tree_model_row_changed (model, path, iter);
+ class = E_SOURCE_SELECTOR_GET_CLASS (selector);
+ g_return_if_fail (class->set_source_selected != NULL);
- g_object_unref (source);
+ class->set_source_selected (selector, source, FALSE);
- return FALSE;
+ g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
}
/**
@@ -1660,27 +1740,24 @@ void
e_source_selector_select_exclusive (ESourceSelector *selector,
ESource *source)
{
- GtkTreeModel *model;
-
- struct {
- ESourceSelector *selector;
- ESource *source_to_select;
- } data;
+ ESourceSelectorClass *class;
+ GHashTable *source_index;
+ GHashTableIter iter;
+ gpointer key;
g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
g_return_if_fail (E_IS_SOURCE (source));
- source = find_source (selector, source);
- g_return_if_fail (source != NULL);
+ class = E_SOURCE_SELECTOR_GET_CLASS (selector);
+ g_return_if_fail (class->set_source_selected != NULL);
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
-
- data.selector = selector;
- data.source_to_select = source;
+ source_index = selector->priv->source_index;
+ g_hash_table_iter_init (&iter, source_index);
- gtk_tree_model_foreach (
- model, (GtkTreeModelForeachFunc)
- source_selector_select_exclusive_foreach, &data);
+ while (g_hash_table_iter_next (&iter, &key, NULL)) {
+ gboolean selected = e_source_equal (key, source);
+ class->set_source_selected (selector, source, selected);
+ }
g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
}
@@ -1698,13 +1775,22 @@ gboolean
e_source_selector_source_is_selected (ESourceSelector *selector,
ESource *source)
{
+ ESourceSelectorClass *class;
+ GtkTreeRowReference *reference;
+ GHashTable *source_index;
+
g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), FALSE);
g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
- source = find_source (selector, source);
- g_return_val_if_fail (source != NULL, FALSE);
+ /* Make sure the ESource is in our tree model. */
+ source_index = selector->priv->source_index;
+ reference = g_hash_table_lookup (source_index, source);
+ g_return_val_if_fail (gtk_tree_row_reference_valid (reference), FALSE);
- return source_is_selected (selector, source);
+ class = E_SOURCE_SELECTOR_GET_CLASS (selector);
+ g_return_val_if_fail (class->get_source_selected != NULL, FALSE);
+
+ return class->get_source_selected (selector, source);
}
/**
@@ -1782,13 +1868,14 @@ e_source_selector_edit_primary_selection (ESourceSelector *selector)
ESource *
e_source_selector_get_primary_selection (ESourceSelector *selector)
{
+ ESource *source;
GtkTreeRowReference *reference;
GtkTreeSelection *selection;
GtkTreeView *tree_view;
GtkTreeModel *model;
GtkTreeIter iter;
+ const gchar *ext_name;
gboolean have_iter = FALSE;
- gpointer data = NULL;
g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), NULL);
@@ -1813,19 +1900,18 @@ e_source_selector_get_primary_selection (ESourceSelector *selector)
if (!have_iter)
return NULL;
- gtk_tree_model_get (model, &iter, 0, &data, -1);
+ gtk_tree_model_get (model, &iter, COLUMN_SOURCE, &source, -1);
- if (data == NULL)
- return NULL;
+ ext_name = e_source_selector_get_extension_name (selector);
- if (!E_IS_SOURCE (data)) {
- g_object_unref (data);
+ if (!e_source_has_extension (source, ext_name)) {
+ g_object_unref (source);
return NULL;
}
- g_object_unref (data);
-
- return E_SOURCE (data);
+ /* Return a borrowed reference. */
+ g_object_unref (source);
+ return source;
}
/**
@@ -1839,64 +1925,66 @@ void
e_source_selector_set_primary_selection (ESourceSelector *selector,
ESource *source)
{
- ESourceSelectorPrivate *priv;
- GtkTreeIter parent_iter, source_iter;
+ GHashTable *source_index;
+ GtkTreeRowReference *reference;
+ GtkTreeSelection *selection;
+ GtkTreeView *tree_view;
+ GtkTreePath *child_path;
+ GtkTreePath *parent_path;
+ const gchar *extension_name;
- g_return_if_fail (selector != NULL);
g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
- g_return_if_fail (source != NULL);
g_return_if_fail (E_IS_SOURCE (source));
- priv = selector->priv;
+ tree_view = GTK_TREE_VIEW (selector);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ source_index = selector->priv->source_index;
+ reference = g_hash_table_lookup (source_index, source);
- source = find_source (selector, source);
- g_return_if_fail (source != NULL);
+ /* XXX Maybe we should return a success/fail boolean? */
+ if (!gtk_tree_row_reference_valid (reference))
+ return;
- if (find_source_iter (selector, source, &parent_iter, &source_iter)) {
- GtkTreeSelection *selection;
- GtkTreeView *tree_view;
- GtkTreeModel *model;
- GtkTreePath *path;
+ extension_name = e_source_selector_get_extension_name (selector);
+ g_return_if_fail (e_source_has_extension (source, extension_name));
- tree_view = GTK_TREE_VIEW (selector);
- model = gtk_tree_view_get_model (tree_view);
- selection = gtk_tree_view_get_selection (tree_view);
+ /* We block the signal because this all needs to be atomic */
+ g_signal_handlers_block_matched (
+ selection, G_SIGNAL_MATCH_FUNC,
+ 0, 0, NULL, selection_changed_callback, NULL);
+ gtk_tree_selection_unselect_all (selection);
+ g_signal_handlers_unblock_matched (
+ selection, G_SIGNAL_MATCH_FUNC,
+ 0, 0, NULL, selection_changed_callback, NULL);
- /* We block the signal because this all needs to be atomic */
- g_signal_handlers_block_matched (selection, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, selection_changed_callback, NULL);
- gtk_tree_selection_unselect_all (selection);
- g_signal_handlers_unblock_matched (selection, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, selection_changed_callback, NULL);
+ clear_saved_primary_selection (selector);
- clear_saved_primary_selection (selector);
+ child_path = gtk_tree_row_reference_get_path (reference);
- path = gtk_tree_model_get_path (model, &parent_iter);
+ parent_path = gtk_tree_path_copy (child_path);
+ gtk_tree_path_up (parent_path);
- if (gtk_tree_view_row_expanded (tree_view, path)) {
- gtk_tree_selection_select_iter (selection, &source_iter);
- } else {
- GtkTreePath *child_path;
+ if (gtk_tree_view_row_expanded (tree_view, parent_path)) {
+ gtk_tree_selection_select_path (selection, child_path);
+ } else {
+ ESourceSelectorClass *class;
- child_path = gtk_tree_model_get_path (model, &source_iter);
- priv->saved_primary_selection = gtk_tree_row_reference_new (model, child_path);
- gtk_tree_path_free (child_path);
+ class = E_SOURCE_SELECTOR_GET_CLASS (selector);
+ g_return_if_fail (class->set_source_selected != NULL);
- /* We do this by hand because we aren't changing the tree selection */
- if (!source_is_selected (selector, source)) {
- select_source (selector, source);
- gtk_tree_model_row_changed (model, path, &source_iter);
- g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
- }
+ selector->priv->saved_primary_selection =
+ gtk_tree_row_reference_copy (reference);
- g_signal_emit (selector, signals[PRIMARY_SELECTION_CHANGED], 0);
- g_object_notify (G_OBJECT (selector), "primary-selection");
- }
+ class->set_source_selected (selector, source, TRUE);
- gtk_tree_path_free (path);
- } else {
- g_warning (G_STRLOC ": Cannot find source %p (%s) in selector %p",
- (gpointer) source, e_source_peek_name (source),
- (gpointer) selector);
+ g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
+ g_signal_emit (selector, signals[PRIMARY_SELECTION_CHANGED], 0);
+ g_object_notify (G_OBJECT (selector), "primary-selection");
}
+
+ gtk_tree_path_free (child_path);
+ gtk_tree_path_free (parent_path);
}
/**
@@ -1924,7 +2012,7 @@ e_source_selector_get_source_by_path (ESourceSelector *selector,
model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
if (gtk_tree_model_get_iter (model, &iter, path))
- gtk_tree_model_get (model, &iter, 0, &source, -1);
+ gtk_tree_model_get (model, &iter, COLUMN_SOURCE, &source, -1);
/* Return a borrowed reference. */
if (source != NULL)
@@ -1932,3 +2020,60 @@ e_source_selector_get_source_by_path (ESourceSelector *selector,
return source;
}
+
+/**
+ * e_source_selector_queue_write:
+ * @selector: an #ESourceSelecetor
+ * @source: an #ESource with changes to be written
+ *
+ * Queues a main loop idle callback to write changes to @source back to
+ * the D-Bus registry service.
+ *
+ * Since: 3.6
+ **/
+void
+e_source_selector_queue_write (ESourceSelector *selector,
+ ESource *source)
+{
+ GSource *idle_source;
+ GHashTable *pending_writes;
+ GMainContext *main_context;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ main_context = selector->priv->main_context;
+ pending_writes = selector->priv->pending_writes;
+
+ idle_source = g_hash_table_lookup (pending_writes, source);
+ if (idle_source != NULL && !g_source_is_destroyed (idle_source))
+ return;
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->selector = g_object_ref (selector);
+ async_context->source = g_object_ref (source);
+
+ /* Set a higher priority so this idle source runs before our
+ * source_selector_cancel_write() signal handler, which will
+ * cancel this idle source. Cancellation is the right thing
+ * to do when receiving changes from OTHER registry clients,
+ * but we don't want to cancel our own changes.
+ *
+ * XXX This might be an argument for using etags.
+ */
+ idle_source = g_idle_source_new ();
+ g_hash_table_insert (
+ pending_writes,
+ g_object_ref (source),
+ g_source_ref (idle_source));
+ g_source_set_callback (
+ idle_source,
+ source_selector_write_idle_cb,
+ async_context,
+ (GDestroyNotify) async_context_free);
+ g_source_set_priority (idle_source, G_PRIORITY_HIGH_IDLE);
+ g_source_attach (idle_source, main_context);
+ g_source_unref (idle_source);
+}
+
diff --git a/libedataserverui/e-source-selector.h b/libedataserverui/e-source-selector.h
index fb1dc3e..9880cd3 100644
--- a/libedataserverui/e-source-selector.h
+++ b/libedataserverui/e-source-selector.h
@@ -25,7 +25,7 @@
#define E_SOURCE_SELECTOR_H
#include <gtk/gtk.h>
-#include <libedataserver/e-source-list.h>
+#include <libedataserver/e-source-registry.h>
/* Standard GObject macros */
#define E_TYPE_SOURCE_SELECTOR \
@@ -60,6 +60,14 @@ struct _ESourceSelector {
struct _ESourceSelectorClass {
GtkTreeViewClass parent_class;
+ /* Methods */
+ gboolean (*get_source_selected) (ESourceSelector *selector,
+ ESource *source);
+ void (*set_source_selected) (ESourceSelector *selector,
+ ESource *source,
+ gboolean selected);
+
+ /* Signals */
void (*selection_changed) (ESourceSelector *selector);
void (*primary_selection_changed)
(ESourceSelector *selector);
@@ -78,9 +86,27 @@ struct _ESourceSelectorClass {
};
GType e_source_selector_get_type (void);
-GtkWidget * e_source_selector_new (ESourceList *list);
-ESourceList * e_source_selector_get_source_list
+GtkWidget * e_source_selector_new (ESourceRegistry *registry,
+ const gchar *extension_name);
+ESourceRegistry *
+ e_source_selector_get_registry (ESourceSelector *selector);
+const gchar * e_source_selector_get_extension_name
+ (ESourceSelector *selector);
+ESource * e_source_selector_get_default_source
+ (ESourceSelector *selector);
+void e_source_selector_set_default_source
+ (ESourceSelector *selector,
+ ESource *default_source);
+gboolean e_source_selector_get_show_colors
+ (ESourceSelector *selector);
+void e_source_selector_set_show_colors
+ (ESourceSelector *selector,
+ gboolean show_colors);
+gboolean e_source_selector_get_show_toggles
(ESourceSelector *selector);
+void e_source_selector_set_show_toggles
+ (ESourceSelector *selector,
+ gboolean show_toggles);
void e_source_selector_select_source (ESourceSelector *selector,
ESource *source);
void e_source_selector_unselect_source
@@ -95,11 +121,6 @@ gboolean e_source_selector_source_is_selected
GSList * e_source_selector_get_selection (ESourceSelector *selector);
void e_source_selector_free_selection
(GSList *list);
-void e_source_selector_show_selection
- (ESourceSelector *selector,
- gboolean show);
-gboolean e_source_selector_selection_shown
- (ESourceSelector *selector);
void e_source_selector_set_select_new
(ESourceSelector *selector,
gboolean state);
@@ -110,16 +131,24 @@ ESource * e_source_selector_get_primary_selection
void e_source_selector_set_primary_selection
(ESourceSelector *selector,
ESource *source);
-ESourceGroup * e_source_selector_get_primary_source_group
- (ESourceSelector *selector);
ESource * e_source_selector_get_source_by_path
(ESourceSelector *selector,
GtkTreePath *path);
+void e_source_selector_queue_write (ESourceSelector *selector,
+ ESource *source);
/* For backward-compatibility */
#ifndef EDS_DISABLE_DEPRECATED
+
#define e_source_selector_peek_primary_selection \
e_source_selector_get_primary_selection
+
+#define e_source_selector_selection_shown \
+ e_source_selector_get_show_toggles
+
+#define e_source_selector_show_selection \
+ e_source_selector_set_show_toggles
+
#endif
G_END_DECLS
diff --git a/tests/libedataserverui/test-source-selector.c b/tests/libedataserverui/test-source-selector.c
index ae899c7..1a4ee49 100644
--- a/tests/libedataserverui/test-source-selector.c
+++ b/tests/libedataserverui/test-source-selector.c
@@ -21,8 +21,11 @@
* Author: Ettore Perazzoli <ettore ximian com>
*/
+#include <libedataserver/e-source-address-book.h>
#include <libedataserverui/e-source-selector.h>
+static const gchar *extension_name;
+
static void
dump_selection (ESourceSelector *selector)
{
@@ -36,10 +39,15 @@ dump_selection (ESourceSelector *selector)
for (p = selection; p != NULL; p = p->next) {
ESource *source = E_SOURCE (p->data);
+ ESourceBackend *extension;
+
+ extension = e_source_get_extension (
+ source, extension_name);
- g_print ("\tSource %s (group %s)\n",
- e_source_peek_name (source),
- e_source_group_peek_name (e_source_peek_group (source)));
+ g_print (
+ "\tSource %s (backend %s)\n",
+ e_source_get_display_name (source),
+ e_source_backend_get_backend_name (extension));
}
}
@@ -47,57 +55,61 @@ dump_selection (ESourceSelector *selector)
}
static void
-selection_changed_callback (ESourceSelector *selector,
- gpointer unused_data)
+selection_changed_callback (ESourceSelector *selector)
{
g_print ("Selection changed!\n");
dump_selection (selector);
}
-static void
-check_toggled_callback (GtkToggleButton *button,
- ESourceSelector *selector)
-{
- e_source_selector_show_selection (selector, gtk_toggle_button_get_active (button));
-}
-
static gint
-on_idle_create_widget (const gchar *gconf_path)
+on_idle_create_widget (ESourceRegistry *registry)
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *selector;
GtkWidget *scrolled_window;
GtkWidget *check;
- ESourceList *list;
- GConfClient *gconf_client;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 200, 300);
- vbox = gtk_vbox_new (FALSE, 3);
+ vbox = gtk_vbox_new (FALSE, 6);
gtk_container_add (GTK_CONTAINER (window), vbox);
- gconf_client = gconf_client_get_default ();
- list = e_source_list_new_for_gconf (gconf_client, gconf_path);
- selector = e_source_selector_new (list);
- g_signal_connect (selector, "selection_changed", G_CALLBACK (selection_changed_callback), NULL);
+ selector = e_source_selector_new (registry, extension_name);
+ g_signal_connect (
+ selector, "selection_changed",
+ G_CALLBACK (selection_changed_callback), NULL);
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (scrolled_window), selector);
- gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 3);
+ gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
+
+ check = gtk_check_button_new_with_label ("Show colors");
+ gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0);
- check = gtk_check_button_new_with_label ("Show checkboxes");
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check),
- e_source_selector_selection_shown (E_SOURCE_SELECTOR (selector)));
- g_signal_connect (check, "toggled", G_CALLBACK (check_toggled_callback), selector);
- gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 3);
+ g_object_bind_property (
+ selector, "show-colors",
+ check, "active",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ check = gtk_check_button_new_with_label ("Show toggles");
+ gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0);
+
+ g_object_bind_property (
+ selector, "show-toggles",
+ check, "active",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
gtk_widget_show_all (window);
- g_object_unref (gconf_client);
return FALSE;
}
@@ -105,15 +117,25 @@ gint
main (gint argc,
gchar **argv)
{
- const gchar *gconf_path;
+ ESourceRegistry *registry;
+ GError *error = NULL;
gtk_init (&argc, &argv);
+
if (argc < 2)
- gconf_path = "/apps/evolution/calendar/sources";
+ extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
else
- gconf_path = argv[1];
+ extension_name = argv[1];
+
+ registry = e_source_registry_new_sync (NULL, &error);
+
+ if (error != NULL) {
+ g_error ("Failed to load ESource registry: %s",
+ error->message);
+ g_assert_not_reached ();
+ }
- g_idle_add ((GSourceFunc) on_idle_create_widget, (gpointer) gconf_path);
+ g_idle_add ((GSourceFunc) on_idle_create_widget, registry);
gtk_main ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]