aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/misc
diff options
context:
space:
mode:
authorEttore Perazzoli <ettore@src.gnome.org>2003-10-22 02:28:34 +0800
committerEttore Perazzoli <ettore@src.gnome.org>2003-10-22 02:28:34 +0800
commit0fb08f3ff81575a4749d851404233f34252dd2f2 (patch)
tree7e03befedc3a76fd104921dbbc616810d87333be /widgets/misc
parent0e19f2c16de592607a341eb9974d31e4e47e02b5 (diff)
downloadgsoc2013-evolution-0fb08f3ff81575a4749d851404233f34252dd2f2.tar
gsoc2013-evolution-0fb08f3ff81575a4749d851404233f34252dd2f2.tar.gz
gsoc2013-evolution-0fb08f3ff81575a4749d851404233f34252dd2f2.tar.bz2
gsoc2013-evolution-0fb08f3ff81575a4749d851404233f34252dd2f2.tar.lz
gsoc2013-evolution-0fb08f3ff81575a4749d851404233f34252dd2f2.tar.xz
gsoc2013-evolution-0fb08f3ff81575a4749d851404233f34252dd2f2.tar.zst
gsoc2013-evolution-0fb08f3ff81575a4749d851404233f34252dd2f2.zip
Merge new-ui-branch to the trunk.
svn path=/trunk/; revision=22964
Diffstat (limited to 'widgets/misc')
-rw-r--r--widgets/misc/ChangeLog50
-rw-r--r--widgets/misc/Makefile.am14
-rw-r--r--widgets/misc/e-source-selector.c682
-rw-r--r--widgets/misc/e-source-selector.h80
-rw-r--r--widgets/misc/test-source-selector.c131
5 files changed, 957 insertions, 0 deletions
diff --git a/widgets/misc/ChangeLog b/widgets/misc/ChangeLog
index ddf64a7889..fe4bcd24fa 100644
--- a/widgets/misc/ChangeLog
+++ b/widgets/misc/ChangeLog
@@ -4,6 +4,56 @@
* e-combo-cell-editable.* : new, GtkCellEditable for combo cells
* Makefile.am : build the new files
+2003-08-18 Ettore Perazzoli <ettore@ximian.com>
+
+ * e-source-selector.c (e_source_selector_selection_shown)
+ (e_source_selector_show_selection): Add precondition.
+
+2003-08-18 Ettore Perazzoli <ettore@ximian.com>
+
+ * test-source-selector.c (on_idle_create_widget): Add a
+ checkbutton to the test window for toggling the checkboxes on and
+ off. Also, put the list in a scrolled window and set a default
+ size for the main window.
+ (check_toggled_callback): Callback for the checkbutton.
+
+ * e-source-selector.c: New member checkboxes_shown in struct
+ ESourceSelectorPrivate.
+ (init): Set to TRUE.
+ (e_source_selector_show_selection): New.
+ (e_source_selector_selection_shown): New.
+ (toggle_cell_data_func): Don't show the toggle if checkboxes_shown
+ is FALSE.
+
+2003-08-17 Ettore Perazzoli <ettore@ximian.com>
+
+ * e-source-selector.c: New signal "primary_selection_changed",
+ removed members list_changed_callback_id and
+ selection_changed_callback_id in ESourceSelectorPrivate.
+ (rebuild_model): If the new set of selected sources is smaller
+ than the old one, emit "selection_changed".
+ (e_source_selector_peek_primary_selection): New.
+ (e_source_selector_set_primary_selection): New.
+ (selection_changed_callback): New callback for the "changed"
+ signal on our associated GtkTreeSelection.
+ (init): Connect.
+ (impl_dispose): Disconnect.
+ (setup_model): Use signal_connect_object() instead of saving the
+ ID.
+
+2003-08-15 Ettore Perazzoli <ettore@ximian.com>
+
+ * e-source-selector.c (cell_toggled_callback): Call
+ gtk_tree_model_row_changed() to let the model know that we changed
+ the data.
+
+2003-08-15 Ettore Perazzoli <ettore@ximian.com>
+
+ * test-source-selector.c: New test program.
+
+ * e-source-selector.c: New file.
+ * e-source-selector.h: New file.
+
2003-07-23 Dan Winship <danw@ximian.com>
* Makefile.am: use EVO_MARSHAL_RULE
diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am
index 7efeebb86f..f4d2cac974 100644
--- a/widgets/misc/Makefile.am
+++ b/widgets/misc/Makefile.am
@@ -31,6 +31,7 @@ widgetsinclude_HEADERS = \
e-map.h \
e-multi-config-dialog.h \
e-search-bar.h \
+ e-source-selector.h \
e-title-bar.h \
e-url-entry.h
@@ -51,6 +52,7 @@ libemiscwidgets_la_SOURCES = \
e-map.c \
e-multi-config-dialog.c \
e-search-bar.c \
+ e-source-selector.c \
e-title-bar.c \
e-url-entry.c \
e-util-marshal.c
@@ -72,6 +74,7 @@ noinst_PROGRAMS = \
test-dateedit \
test-dropdown-button \
test-multi-config-dialog \
+ test-source-selector \
test-title-bar
# test-calendar
@@ -122,6 +125,17 @@ test_title_bar_LDADD = \
$(GNOME_FULL_LIBS)
+# test-source-list-selector
+
+test_source_selector_SOURCES = \
+ test-source-selector.c
+
+test_source_selector_LDADD = \
+ ../../e-util/libeutil.la \
+ ./libemiscwidgets.la \
+ $(GNOME_FULL_LIBS)
+
+
BUILT_SOURCES = $(MARSHAL_GENERATED)
CLEANFILES = $(BUILT_SOURCES)
diff --git a/widgets/misc/e-source-selector.c b/widgets/misc/e-source-selector.c
new file mode 100644
index 0000000000..5bc12bcd39
--- /dev/null
+++ b/widgets/misc/e-source-selector.c
@@ -0,0 +1,682 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-source-selector.c
+ *
+ * Copyright (C) 2003 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ettore Perazzoli <ettore@ximian.com>
+ */
+
+#include <config.h>
+
+#include "e-source-selector.h"
+
+#include "e-util-marshal.h"
+
+#include <gal/util/e-util.h>
+
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtktreestore.h>
+#include <gtk/gtkcellrenderertoggle.h>
+#include <gtk/gtkcellrenderertext.h>
+
+
+#define PARENT_TYPE gtk_tree_view_get_type ()
+static GtkTreeViewClass *parent_class = NULL;
+
+
+struct _ESourceSelectorPrivate {
+ ESourceList *list;
+
+ GtkTreeStore *tree_store;
+
+ GHashTable *selected_sources;
+
+ int rebuild_model_idle_id;
+
+ gboolean checkboxes_shown;
+};
+
+
+enum {
+ SELECTION_CHANGED,
+ PRIMARY_SELECTION_CHANGED,
+ NUM_SIGNALS
+};
+static unsigned int signals[NUM_SIGNALS] = { 0 };
+
+
+/* Selection management. */
+
+static GHashTable *
+create_selected_sources_hash (void)
+{
+ return g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ (GDestroyNotify) g_object_unref, NULL);
+}
+
+static gboolean
+source_is_selected (ESourceSelector *selector,
+ ESource *source)
+{
+ if (g_hash_table_lookup (selector->priv->selected_sources, source) == NULL)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+static void
+select_source (ESourceSelector *selector,
+ ESource *source)
+{
+ if (g_hash_table_lookup (selector->priv->selected_sources, source) != NULL)
+ return;
+
+ g_hash_table_insert (selector->priv->selected_sources, source, source);
+ g_object_ref (source);
+}
+
+static void
+unselect_source (ESourceSelector *selector,
+ ESource *source)
+{
+ if (g_hash_table_lookup (selector->priv->selected_sources, source) == NULL)
+ return;
+
+ /* (This will unref the source.) */
+ g_hash_table_remove (selector->priv->selected_sources, source);
+}
+
+
+/* Setting up the model. */
+
+static void
+rebuild_model (ESourceSelector *selector)
+{
+ GtkTreeStore *tree_store;
+ GtkTreeIter iter;
+ GSList *groups, *p;
+ GHashTable *new_selected_sources;
+
+ new_selected_sources = create_selected_sources_hash ();
+
+ tree_store = selector->priv->tree_store;
+ gtk_tree_store_clear (GTK_TREE_STORE (tree_store));
+
+ 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;
+
+ gtk_tree_store_append (GTK_TREE_STORE (tree_store), &iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (tree_store), &iter, 0, group, -1);
+
+ sources = e_source_group_peek_sources (group);
+ for (q = sources; q != NULL; q = q->next) {
+ ESource *source = E_SOURCE (q->data);
+ GtkTreeIter child_iter;
+
+ gtk_tree_store_append (GTK_TREE_STORE (tree_store), &child_iter, &iter);
+ gtk_tree_store_set (GTK_TREE_STORE (tree_store), &child_iter, 0, source, -1);
+
+ if (g_hash_table_lookup (selector->priv->selected_sources, source) != NULL) {
+ g_hash_table_insert (new_selected_sources, source, source);
+ g_object_ref (source);
+ }
+ }
+ }
+
+ /* Since new_selected_sources is a subset of selected_sources, we can tell whether the overall
+ selection has changed just by comparing the sizes of the hash tables. */
+ if (g_hash_table_size (selector->priv->selected_sources) != g_hash_table_size (new_selected_sources))
+ g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
+
+ g_hash_table_destroy (selector->priv->selected_sources);
+ selector->priv->selected_sources = new_selected_sources;
+}
+
+static int
+on_idle_rebuild_model_callback (ESourceSelector *selector)
+{
+ rebuild_model (selector);
+ selector->priv->rebuild_model_idle_id = 0;
+
+ return FALSE;
+}
+
+static void
+list_changed_callback (ESourceList *list,
+ ESourceSelector *selector)
+{
+ ESourceSelectorPrivate *priv = selector->priv;
+
+ if (priv->rebuild_model_idle_id == 0)
+ priv->rebuild_model_idle_id = g_idle_add ((GSourceFunc) on_idle_rebuild_model_callback,
+ selector);
+}
+
+static void
+setup_model (ESourceSelector *selector)
+{
+ rebuild_model (selector);
+
+ g_signal_connect_object (selector->priv->list, "changed", G_CALLBACK (list_changed_callback), G_OBJECT (selector), 0);
+}
+
+
+/* Data functions for rendering the model. */
+
+static void
+toggle_cell_data_func (GtkTreeViewColumn *column,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ ESourceSelector *selector)
+{
+ void *data;
+
+ gtk_tree_model_get (model, iter, 0, &data, -1);
+
+ if (E_IS_SOURCE_GROUP (data)) {
+ g_object_set (renderer, "visible", FALSE, NULL);
+ } else {
+ g_assert (E_IS_SOURCE (data));
+
+ 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);
+ }
+}
+
+static void
+text_cell_data_func (GtkTreeViewColumn *column,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ ESourceSelector *selector)
+{
+ void *data;
+
+ gtk_tree_model_get (model, iter, 0, &data, -1);
+
+ 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;
+ guint32 color;
+ gboolean has_color;
+
+ g_assert (E_IS_SOURCE (data));
+ source = E_SOURCE (data);
+
+ g_object_set (renderer,
+ "text", e_source_peek_name (source),
+ "weight", PANGO_WEIGHT_NORMAL,
+ NULL);
+
+ has_color = e_source_get_color (source, &color);
+ if (!has_color) {
+ g_object_set (renderer,
+ "foreground_set", FALSE,
+ NULL);
+ } else {
+ char *color_string = g_strdup_printf ("#%06x", color);
+ g_object_set (renderer,
+ "foreground_set", TRUE,
+ "foreground", color_string,
+ NULL);
+ g_free (color_string);
+ }
+ }
+}
+
+/* Custom selection function to make groups non selectable. */
+static gboolean
+selection_func (GtkTreeSelection *selection,
+ GtkTreeModel *model,
+ GtkTreePath *path,
+ gboolean path_currently_selected,
+ ESourceSelector *selector)
+{
+ GtkTreeIter iter;
+ void *data;
+
+ 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))
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+/* Callbacks. */
+
+static void
+cell_toggled_callback (GtkCellRendererToggle *renderer,
+ const char *path_string,
+ ESourceSelector *selector)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (selector->priv->tree_store);
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+ GtkTreeIter iter;
+ ESource *source;
+ void *data;
+
+ if (! gtk_tree_model_get_iter (model, &iter, path)) {
+ gtk_tree_path_free (path);
+ return;
+ }
+
+ gtk_tree_model_get (model, &iter, 0, &data, -1);
+ if (! E_IS_SOURCE (data)) {
+ gtk_tree_path_free (path);
+ return;
+ }
+
+ source = E_SOURCE (data);
+ if (source_is_selected (selector, source))
+ unselect_source (selector, source);
+ else
+ select_source (selector, source);
+
+ gtk_tree_model_row_changed (model, path, &iter);
+ g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+selection_changed_callback (GtkTreeSelection *selection,
+ ESourceSelector *selector)
+{
+ g_signal_emit (selector, signals[PRIMARY_SELECTION_CHANGED], 0);
+}
+
+
+/* GObject methods. */
+
+static void
+impl_dispose (GObject *object)
+{
+ ESourceSelectorPrivate *priv = E_SOURCE_SELECTOR (object)->priv;
+
+ if (priv->selected_sources != NULL) {
+ g_hash_table_destroy (priv->selected_sources);
+ priv->selected_sources = NULL;
+ }
+
+ if (priv->rebuild_model_idle_id != 0) {
+ g_source_remove (priv->rebuild_model_idle_id);
+ priv->rebuild_model_idle_id = 0;
+ }
+
+ if (priv->list != NULL) {
+ g_object_unref (priv->list);
+ priv->list = NULL;
+ }
+
+ if (priv->tree_store != NULL) {
+ g_object_unref (priv->tree_store);
+ priv->tree_store = NULL;
+ }
+
+ (* G_OBJECT_CLASS (parent_class)->dispose) (object);
+}
+
+static void
+impl_finalize (GObject *object)
+{
+ ESourceSelectorPrivate *priv = E_SOURCE_SELECTOR (object)->priv;
+
+ g_free (priv);
+
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+
+/* Initialization. */
+
+static void
+class_init (ESourceSelectorClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = impl_dispose;
+ object_class->finalize = impl_finalize;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ signals[SELECTION_CHANGED] =
+ g_signal_new ("selection_changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ESourceSelectorClass, selection_changed),
+ NULL, NULL,
+ e_util_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[PRIMARY_SELECTION_CHANGED] =
+ g_signal_new ("primary_selection_changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ESourceSelectorClass, primary_selection_changed),
+ NULL, NULL,
+ e_util_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+init (ESourceSelector *selector)
+{
+ ESourceSelectorPrivate *priv;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell_renderer;
+ GtkTreeSelection *selection;
+
+ priv = g_new0 (ESourceSelectorPrivate, 1);
+ selector->priv = priv;
+
+ priv->checkboxes_shown = TRUE;
+
+ priv->selected_sources = create_selected_sources_hash ();
+
+ priv->tree_store = gtk_tree_store_new (1, G_TYPE_POINTER);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (selector), GTK_TREE_MODEL (priv->tree_store));
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_append_column (GTK_TREE_VIEW (selector), column);
+
+ cell_renderer = gtk_cell_renderer_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_signal_connect (cell_renderer, "toggled", G_CALLBACK (cell_toggled_callback), selector);
+
+ cell_renderer = gtk_cell_renderer_text_new ();
+ 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);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selector));
+ gtk_tree_selection_set_select_function (selection, (GtkTreeSelectionFunc) selection_func, selector, NULL);
+ g_signal_connect_object (selection, "changed", G_CALLBACK (selection_changed_callback), G_OBJECT (selector), 0);
+
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (selector), FALSE);
+}
+
+
+/* Public API. */
+
+/**
+ * e_source_selector_new:
+ * @list: A source list.
+ *
+ * Create a new view for @list. The view will update automatically when @list
+ * changes.
+ *
+ * Return value: The newly created widget.
+ **/
+GtkWidget *
+e_source_selector_new (ESourceList *list)
+{
+ ESourceSelector *selector;
+
+ g_return_val_if_fail (E_IS_SOURCE_LIST (list), NULL);
+
+ selector = g_object_new (e_source_selector_get_type (), NULL);
+
+ selector->priv->list = list;
+ g_object_ref (list);
+
+ setup_model (selector);
+
+ return GTK_WIDGET (selector);
+}
+
+
+/**
+ * e_source_selector_get_selection:
+ * @selector:
+ *
+ * Get the list of selected sources, i.e. those that were enabled through the
+ * corresponding checkboxes in the tree.
+ *
+ * Return value: 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().
+ **/
+GSList *
+e_source_selector_get_selection (ESourceSelector *selector)
+{
+ GSList *selection_list;
+ GSList *groups;
+ GSList *p;
+
+ g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), NULL);
+
+ selection_list = 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;
+
+ sources = e_source_group_peek_sources (group);
+ for (q = sources; q != NULL; q = q->next) {
+ ESource *source = E_SOURCE (q->data);
+
+ if (source_is_selected (selector, source)) {
+ selection_list = g_slist_prepend (selection_list, source);
+ g_object_ref (source);
+ }
+ }
+ }
+
+ return g_slist_reverse (selection_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);
+}
+
+
+/**
+ * e_source_selector_show_selection:
+ * @selector: An ESourceSelector widget
+ *
+ * Specify whether the checkboxes in the ESourceSelector should be shown or
+ * not.
+ **/
+void
+e_source_selector_show_selection (ESourceSelector *selector,
+ gboolean show)
+{
+ g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+
+ show = !! show;
+ if (show == selector->priv->checkboxes_shown)
+ return;
+
+ selector->priv->checkboxes_shown = show;
+
+ gtk_tree_model_foreach (GTK_TREE_MODEL (selector->priv->tree_store),
+ (GtkTreeModelForeachFunc) gtk_tree_model_row_changed,
+ NULL);
+}
+
+/**
+ * e_source_selector_selection_shown:
+ * @selector:
+ *
+ * Check whether the checkboxes in the ESourceSelector are being shown or not.
+ *
+ * Return value: %TRUE if the checkboxes are shown, %FALSE otherwise.
+ **/
+gboolean
+e_source_selector_selection_shown (ESourceSelector *selector)
+{
+ g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+
+ return selector->priv->checkboxes_shown;
+}
+
+/**
+ * e_source_selector_select_source:
+ * @selector: An ESourceSelector widget
+ * @source: An ESource.
+ *
+ * Select @source in @selector.
+ **/
+void
+e_source_selector_select_source (ESourceSelector *selector,
+ ESource *source)
+{
+ g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ if (source_is_selected (selector, source))
+ return;
+
+ select_source (selector, source);
+ g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
+}
+
+/**
+ * e_source_selector_unselect_source:
+ * @selector: An ESourceSelector widget
+ * @source: An ESource.
+ *
+ * Unselect @source in @selector.
+ **/
+void
+e_source_selector_unselect_source (ESourceSelector *selector,
+ ESource *source)
+{
+ g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ if (! source_is_selected (selector, source))
+ return;
+
+ unselect_source (selector, source);
+ g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
+}
+
+/**
+ * e_source_selector_source_is_selected:
+ * @selector: An ESourceSelector widget
+ * @source: An ESource.
+ *
+ * Check whether @source is selected in @selector.
+ *
+ * Return value: %TRUE if @source is currently selected, %FALSE otherwise.
+ **/
+gboolean
+e_source_selector_source_is_selected (ESourceSelector *selector,
+ ESource *source)
+{
+ g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), FALSE);
+ g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+ return source_is_selected (selector, source);
+}
+
+/**
+ * e_source_selector_peek_primary_selection:
+ * @selector: An ESourceSelector widget
+ *
+ * Get the primary selected source. The primary selection is the one that is
+ * highlighted through the normal GtkTreeView selection mechanism (as opposed
+ * to the "normal" selection, which is the set of source whose checkboxes are
+ * checked).
+ *
+ * Return value: The selected source.
+ **/
+ESource *
+e_source_selector_peek_primary_selection (ESourceSelector *selector)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (selector->priv->tree_store);
+ GtkTreeIter iter;
+ void *data;
+
+ if (! gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (selector)), NULL, &iter))
+ return NULL;
+
+ gtk_tree_model_get (model, &iter, 0, &data, -1);
+ if (! E_IS_SOURCE (data))
+ return NULL;
+
+ return E_SOURCE (data);
+}
+
+/**
+ * e_source_selector_set_primary_selection:
+ * @selector: An ESourceSelector widget
+ * @source: Source to select
+ *
+ * Set the primary selected source.
+ **/
+void
+e_source_selector_set_primary_selection (ESourceSelector *selector,
+ ESource *source)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (selector->priv->tree_store);
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter_first (model, &iter)) {
+ do {
+ GtkTreeIter children_iter;
+
+ if (gtk_tree_model_iter_children (model, &children_iter, &iter)) {
+ do {
+ void *data;
+
+ gtk_tree_model_get (model, &iter, 0, &data, -1);
+ g_assert (E_IS_SOURCE (data));
+
+ if (E_SOURCE (data) == source) {
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (selection));
+ gtk_tree_selection_select_iter (selection, &children_iter);
+ return;
+ }
+ } while (gtk_tree_model_iter_next (model, &iter));
+ }
+ } while (gtk_tree_model_iter_next (model, &iter));
+ }
+
+ g_warning (G_GNUC_FUNCTION ": Cannot find source %p (%s) in selector %p", source, e_source_peek_name (source), selector);
+}
+
+
+E_MAKE_TYPE (e_source_selector, "ESourceSelector", ESourceSelector, class_init, init, PARENT_TYPE)
diff --git a/widgets/misc/e-source-selector.h b/widgets/misc/e-source-selector.h
new file mode 100644
index 0000000000..02b1356e08
--- /dev/null
+++ b/widgets/misc/e-source-selector.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-source-selector.h
+ *
+ * Copyright (C) 2003 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ettore Perazzoli <ettore@ximian.com>
+ */
+
+#ifndef _E_SOURCE_SELECTOR_H_
+#define _E_SOURCE_SELECTOR_H_
+
+#include "e-util/e-source-list.h"
+
+#include <gtk/gtktreeview.h>
+
+
+#define E_TYPE_SOURCE_SELECTOR (e_source_selector_get_type ())
+#define E_SOURCE_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_SOURCE_SELECTOR, ESourceSelector))
+#define E_SOURCE_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_SOURCE_SELECTOR, ESourceSelectorClass))
+#define E_IS_SOURCE_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_SOURCE_SELECTOR))
+#define E_IS_SOURCE_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_SOURCE_SELECTOR))
+
+
+typedef struct _ESourceSelector ESourceSelector;
+typedef struct _ESourceSelectorPrivate ESourceSelectorPrivate;
+typedef struct _ESourceSelectorClass ESourceSelectorClass;
+
+struct _ESourceSelector {
+ GtkTreeView parent;
+
+ ESourceSelectorPrivate *priv;
+};
+
+struct _ESourceSelectorClass {
+ GtkTreeViewClass parent_class;
+
+ void (* selection_changed) (ESourceSelector *selector);
+ void (* primary_selection_changed) (ESourceSelector *selector);
+};
+
+
+GType e_source_selector_get_type (void);
+
+GtkWidget *e_source_selector_new (ESourceList *list);
+
+void e_source_selector_select_source (ESourceSelector *selector,
+ ESource *source);
+void e_source_selector_unselect_source (ESourceSelector *selector,
+ ESource *source);
+gboolean e_source_selector_source_is_selected (ESourceSelector *selector,
+ ESource *source);
+
+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);
+
+ESource *e_source_selector_peek_primary_selection (ESourceSelector *selector);
+void e_source_selector_set_primary_selection (ESourceSelector *selector,
+ ESource *source);
+
+
+#endif /* _E_SOURCE_SELECTOR_H_ */
diff --git a/widgets/misc/test-source-selector.c b/widgets/misc/test-source-selector.c
new file mode 100644
index 0000000000..3120f0c948
--- /dev/null
+++ b/widgets/misc/test-source-selector.c
@@ -0,0 +1,131 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* test-source-list-selector.c - Test program for the ESourceListSelector
+ * widget.
+ *
+ * Copyright (C) 2002 Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ettore Perazzoli <ettore@ximian.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-source-selector.h"
+
+#include <gtk/gtkmain.h>
+#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtkwindow.h>
+
+#include <libgnomeui/gnome-ui-init.h>
+
+
+static void
+dump_selection (ESourceSelector *selector)
+{
+ GSList *selection = e_source_selector_get_selection (selector);
+
+ g_print ("Current selection:\n");
+ if (selection == NULL) {
+ g_print ("\t(None)\n");
+ } else {
+ GSList *p;
+
+ for (p = selection; p != NULL; p = p->next) {
+ ESource *source = E_SOURCE (p->data);
+
+ g_print ("\tSource %s (group %s)\n",
+ e_source_peek_name (source),
+ e_source_group_peek_name (e_source_peek_group (source)));
+ }
+ }
+
+ e_source_selector_free_selection (selection);
+}
+
+static void
+selection_changed_callback (ESourceSelector *selector,
+ void *unused_data)
+{
+ 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 int
+on_idle_create_widget (void *unused_data)
+{
+ 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);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ gconf_client = gconf_client_get_default ();
+ list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/test/source_list");
+ selector = e_source_selector_new (list);
+ 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_container_add (GTK_CONTAINER (scrolled_window), selector);
+ gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 3);
+
+ 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);
+
+ gtk_widget_show_all (window);
+
+ g_object_unref (gconf_client);
+ return FALSE;
+}
+
+
+int
+main (int argc, char **argv)
+{
+ GnomeProgram *program;
+
+ program = gnome_program_init ("test-source-list", "0.0",
+ LIBGNOMEUI_MODULE, argc, argv,
+ NULL);
+
+ g_idle_add (on_idle_create_widget, NULL);
+ gtk_main ();
+
+ return 0;
+}